@koda-sl/baker-cli 0.384.0-dev.4699b7308 → 0.385.0-dev.ec7b0e42b
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 +16 -7
- package/dist/{chunk-CHJOTJTZ.js → chunk-JHKW6IDX.js} +4 -4
- package/dist/{chunk-CHJOTJTZ.js.map → chunk-JHKW6IDX.js.map} +1 -1
- package/dist/{chunk-VLUGGVJL.js → chunk-WLDM2TRF.js} +9 -1
- package/dist/chunk-WLDM2TRF.js.map +1 -0
- package/dist/cli.js +180 -105
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/dist/{shared-J7DQZ2ED.js → shared-6762QE6R.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-VLUGGVJL.js.map +0 -1
- /package/dist/{shared-J7DQZ2ED.js.map → shared-6762QE6R.js.map} +0 -0
|
@@ -13,6 +13,14 @@ import {
|
|
|
13
13
|
// src/commands/ads/meta/shared.ts
|
|
14
14
|
var DAY_MS = 864e5;
|
|
15
15
|
function metaForbiddenFix(message) {
|
|
16
|
+
if (message.includes("has not accepted Meta's Lead Generation Terms")) {
|
|
17
|
+
return {
|
|
18
|
+
action: "reject",
|
|
19
|
+
explanation: `${message}
|
|
20
|
+
|
|
21
|
+
Meta confirmed the Page's terms status using its Page access. Give the Page owner the terms link in the error and ask them to accept it before trying the form or lead ad set again. Do not suggest reconnecting Meta for this refusal; continue with other work that does not require the form or ad set.`
|
|
22
|
+
};
|
|
23
|
+
}
|
|
16
24
|
return {
|
|
17
25
|
action: "reject",
|
|
18
26
|
explanation: [
|
|
@@ -125,4 +133,4 @@ export {
|
|
|
125
133
|
resolveEffectiveStatus,
|
|
126
134
|
statusFilterHints
|
|
127
135
|
};
|
|
128
|
-
//# sourceMappingURL=chunk-
|
|
136
|
+
//# sourceMappingURL=chunk-WLDM2TRF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/ads/meta/shared.ts"],"sourcesContent":["import { ApiError } from \"../../../client.ts\";\nimport { getEnv } from \"../../../env.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../../error-handler.ts\";\nimport { writeAdsJson } from \"../output.ts\";\nimport type { AdsErrorEnvelope, QueryFix } from \"../types.ts\";\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Meta answers a permission refusal (Graph codes 200/10/294) with a bare\n * \"Permissions error\" that covers two causes needing opposite remedies: a\n * consent grant the connection never got — nothing validates Meta's granted\n * scopes after connect, unlike HubSpot's `requireCapability` — or a role the\n * user lacks on one asset, since a Pixel/Dataset, Page or catalog lives in a\n * Business and is assigned separately from the ad account. Only the blast radius\n * separates them, so hand the agent that test rather than a verdict: guessing\n * \"reconnect\" wastes the user's time on an unassigned asset, and ruling it out\n * strands a connection that really is short a scope.\n */\nexport function metaForbiddenFix(message: string): QueryFix {\n if (message.includes(\"has not accepted Meta's Lead Generation Terms\")) {\n return {\n action: \"reject\",\n explanation: `${message}\\n\\nMeta confirmed the Page's terms status using its Page access. Give the Page owner the terms link in the error and ask them to accept it before trying the form or lead ad set again. Do not suggest reconnecting Meta for this refusal; continue with other work that does not require the form or ad set.`,\n };\n }\n return {\n action: \"reject\",\n explanation: [\n message,\n \"This is a permission refusal, not a dead connection, and Meta returns the same code for two causes with opposite remedies. Tell them apart by how much else works before you answer.\",\n \"If other reads on this account are ALSO refused (campaigns, ad sets, insights), the connection is short a permission it was never granted. Only the user can widen it, by reconnecting Meta from the dashboard.\",\n \"If those reads work and only this object is refused, the asset (pixel/dataset, Page, or catalog) belongs to a Business the connected user holds no role in. Ad-account access does not carry asset access and reconnecting cannot grant it — the client assigns that asset to the connected user or partner in Meta Business settings, under the asset's own section (Data sources → Datasets for a pixel).\",\n \"Either way do not retry the same call, and do not abort the wider job. Continue with what you can read, and state in your answer that this specific check could not run and why — never present the task as verified when this step was skipped.\",\n ].join(\"\\n\\n\"),\n };\n}\n\nexport function handleMetaError(err: unknown): never {\n if (err instanceof ApiError) {\n if (needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"meta_ads\", err.message);\n }\n const envelope: AdsErrorEnvelope = {\n ok: false,\n error: {\n code: err.code,\n message: err.message,\n fix: err.code === \"FORBIDDEN\" ? metaForbiddenFix(err.message) : { action: \"reject\", explanation: err.message },\n retryable: err.code === \"RATE_LIMITED\" || err.code === \"UNAVAILABLE\" || err.code === \"INTERNAL_ERROR\",\n },\n };\n writeAdsJson(envelope);\n process.exit(1);\n }\n const message = err instanceof Error ? err.message : \"Unexpected error\";\n writeAdsJson({ ok: false, error: { code: \"NETWORK_ERROR\", message } });\n process.exit(1);\n}\n\nconst ACCOUNT_ID_RE = /^(act_)?[0-9]+$/;\n\n/** Pull the default Meta ad account ID from `--account-id` arg or `BAKER_META_AD_ACCOUNT_ID` env. */\nexport function resolveAccountIdArg(args: Record<string, unknown>): string {\n const fromArgs = args[\"account-id\"] as string | undefined;\n const id = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;\n if (!id) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"MISSING_ACCOUNT_ID\",\n message: \"Pass --account-id or set BAKER_META_AD_ACCOUNT_ID. Run `baker ads meta accounts` to find IDs.\",\n },\n });\n process.exit(1);\n }\n if (!ACCOUNT_ID_RE.test(id)) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"INVALID_ACCOUNT_ID\",\n message: `Invalid account ID \"${id}\". Expected numeric ID, optionally prefixed with \"act_\".`,\n },\n });\n process.exit(1);\n }\n return id.startsWith(\"act_\") ? id : `act_${id}`;\n}\n\nexport function getDateRange(args: Record<string, unknown>): { datePreset?: string; since?: string; until?: string } {\n const datePreset = args[\"date-preset\"] as string | undefined;\n const since = args.since as string | undefined;\n const until = args.until as string | undefined;\n if (since && until) return { since, until };\n return { datePreset: datePreset ?? \"last_7d\" };\n}\n\nexport function todayIso(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport function daysAgoIso(days: number): string {\n return new Date(Date.now() - days * DAY_MS).toISOString().slice(0, 10);\n}\n\nexport function csvOrJson(args: Record<string, unknown>): string {\n return (args.output as string | undefined) ?? \"json\";\n}\n\n/**\n * Matched by Meta itself, so finding one entity by name reads only the rows that\n * match instead of the whole account.\n */\nexport const NAME_CONTAINS_ARG = {\n type: \"string\",\n description:\n \"Only rows whose name contains this text, matched by Meta before anything is returned. Start here to find one entity by name: --name-contains octubre --all-statuses\",\n} as const;\n\n/**\n * Default to ACTIVE-only on listings — that's almost always what an AI agent or\n * a human glance wants. Pass `--effective-status ACTIVE,PAUSED` to override, or\n * `--all-statuses` to drop the filter entirely.\n */\nexport function resolveEffectiveStatus(args: Record<string, unknown>): string | undefined {\n if (args[\"all-statuses\"]) {\n return undefined;\n }\n const explicit = args[\"effective-status\"] as string | undefined;\n if (explicit) {\n return explicit;\n }\n return \"ACTIVE\";\n}\n\n/**\n * An empty listing under a status filter reads exactly like \"nothing exists\":\n * a paused campaign's ad sets are CAMPAIGN_PAUSED, so the ACTIVE default hides\n * every one of them. Say which filter produced the empty list and how to widen it.\n */\nexport function statusFilterHints(\n rows: ReadonlyArray<unknown>,\n effectiveStatus: string | undefined,\n noun: string,\n): string[] {\n if (rows.length > 0 || effectiveStatus === undefined) return [];\n if (effectiveStatus === \"ACTIVE\") {\n return [\n `No ACTIVE ${noun}. The ACTIVE filter hides paused, archived and in-review ones (under a paused campaign or ad set that is all of them), so this does NOT mean none exist. Re-run with --all-statuses before concluding there are none.`,\n ];\n }\n return [\n `No ${noun} with effective_status ${effectiveStatus}. Re-run with --all-statuses to see every status before concluding there are none.`,\n ];\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
validateCanvasDeep,
|
|
71
71
|
withoutCastName,
|
|
72
72
|
ytDlpBlockSignal
|
|
73
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-JHKW6IDX.js";
|
|
74
74
|
import {
|
|
75
75
|
NAME_CONTAINS_ARG,
|
|
76
76
|
csvOrJson,
|
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
resolveEffectiveStatus,
|
|
82
82
|
statusFilterHints,
|
|
83
83
|
todayIso
|
|
84
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-WLDM2TRF.js";
|
|
85
85
|
import {
|
|
86
86
|
buildQueryCacheKey,
|
|
87
87
|
cacheGet,
|
|
@@ -299,6 +299,7 @@ var chatActionDraftOpViewSchema = z.object({
|
|
|
299
299
|
targetActionId: z.string().optional(),
|
|
300
300
|
tempId: z.string().optional(),
|
|
301
301
|
tags: z.array(z.string()).optional(),
|
|
302
|
+
priority: actionPrioritySchema.nullable().optional(),
|
|
302
303
|
reason: z.string().optional(),
|
|
303
304
|
note: z.string().optional(),
|
|
304
305
|
name: z.string().optional(),
|
|
@@ -20571,9 +20572,8 @@ function requireTargets(args5, entity) {
|
|
|
20571
20572
|
var CHAT_READ_ARG_DESCRIPTION = CHAT_READ_ARG.description;
|
|
20572
20573
|
registerSchema({
|
|
20573
20574
|
command: "ads.linkedin.accounts",
|
|
20574
|
-
description: "List LinkedIn ad accounts in the company's connected scope.
|
|
20575
|
+
description: "List LinkedIn ad accounts in the company's connected scope.",
|
|
20575
20576
|
args: {
|
|
20576
|
-
"include-all": { type: "boolean", description: "Ignore picker scope", required: false },
|
|
20577
20577
|
"no-cache": NO_CACHE_ARG,
|
|
20578
20578
|
output: { type: "string", description: "json|csv|jsonl|md", required: false, default: "json" }
|
|
20579
20579
|
}
|
|
@@ -22284,11 +22284,7 @@ Examples:
|
|
|
22284
22284
|
|
|
22285
22285
|
// src/commands/ads/linkedin/accounts.ts
|
|
22286
22286
|
import { defineCommand as defineCommand35 } from "citty";
|
|
22287
|
-
|
|
22288
|
-
function accountHints2(accounts, includeAll) {
|
|
22289
|
-
if (includeAll) {
|
|
22290
|
-
return [];
|
|
22291
|
-
}
|
|
22287
|
+
function accountHints2(accounts) {
|
|
22292
22288
|
return connectedResourceHints({
|
|
22293
22289
|
plural: "LinkedIn ad accounts",
|
|
22294
22290
|
singular: "LinkedIn ad account",
|
|
@@ -22303,44 +22299,23 @@ var accountsCommand2 = defineCommand35({
|
|
|
22303
22299
|
|
|
22304
22300
|
Examples:
|
|
22305
22301
|
baker ads linkedin accounts
|
|
22306
|
-
baker ads linkedin accounts --include-all # ignore picker scope, list every account the token can see
|
|
22307
22302
|
baker ads linkedin accounts --output csv`
|
|
22308
22303
|
},
|
|
22309
22304
|
args: {
|
|
22310
|
-
"include-all": { type: "boolean", description: "List all accessible accounts, ignoring picker scope" },
|
|
22311
22305
|
"no-cache": NO_CACHE_ARG,
|
|
22312
22306
|
output: { type: "string", description: "Output format: json|csv|jsonl|md", default: "json" }
|
|
22313
22307
|
},
|
|
22314
22308
|
run: async ({ args: args5 }) => {
|
|
22315
|
-
const includeAll = args5["include-all"] === true;
|
|
22316
|
-
const useCache = !args5["no-cache"];
|
|
22317
|
-
const cacheKey = `accounts:${includeAll ? "all" : "scoped"}`;
|
|
22318
|
-
if (useCache) {
|
|
22319
|
-
const cached = cacheGet("linkedin-accounts", cacheKey);
|
|
22320
|
-
if (cached) {
|
|
22321
|
-
writeJsonEnvelope({
|
|
22322
|
-
ok: true,
|
|
22323
|
-
data: cached.data,
|
|
22324
|
-
cached: true,
|
|
22325
|
-
hints: accountHints2(cached.data, includeAll)
|
|
22326
|
-
});
|
|
22327
|
-
return;
|
|
22328
|
-
}
|
|
22329
|
-
}
|
|
22330
22309
|
try {
|
|
22331
22310
|
const params = {};
|
|
22332
|
-
if (
|
|
22333
|
-
if (!useCache) params["skip-cache"] = "true";
|
|
22311
|
+
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
22334
22312
|
const data = await apiGet("/api/ads/linkedin/accounts", params);
|
|
22335
|
-
if (useCache) {
|
|
22336
|
-
cacheSet("linkedin-accounts", cacheKey, data, ACCOUNTS_TTL_MS);
|
|
22337
|
-
}
|
|
22338
22313
|
const fmt = csvOrJson2(args5);
|
|
22339
22314
|
if (fmt !== "json") {
|
|
22340
22315
|
writeAdsOutput(data, fmt);
|
|
22341
22316
|
return;
|
|
22342
22317
|
}
|
|
22343
|
-
writeJsonEnvelope({ ok: true, data, hints: accountHints2(data
|
|
22318
|
+
writeJsonEnvelope({ ok: true, data, hints: accountHints2(data) });
|
|
22344
22319
|
} catch (err) {
|
|
22345
22320
|
handleLinkedinError(err);
|
|
22346
22321
|
}
|
|
@@ -24339,7 +24314,6 @@ var linkedinCommand = defineCommand53({
|
|
|
24339
24314
|
|
|
24340
24315
|
Discovery:
|
|
24341
24316
|
baker ads linkedin accounts \u2014 accounts in this company's connected scope
|
|
24342
|
-
baker ads linkedin accounts --include-all \u2014 every account the token can see
|
|
24343
24317
|
baker ads linkedin account --account-id 503001492 \u2014 single-account detail (currency, type, status)
|
|
24344
24318
|
baker ads linkedin url-params [--ad-sets] \u2014 UTMs in effect today, and keys set at two levels
|
|
24345
24319
|
|
|
@@ -24434,10 +24408,7 @@ Examples:
|
|
|
24434
24408
|
|
|
24435
24409
|
// src/commands/ads/meta/accounts.ts
|
|
24436
24410
|
import { defineCommand as defineCommand55 } from "citty";
|
|
24437
|
-
function accountHints3(accounts
|
|
24438
|
-
if (includeAll) {
|
|
24439
|
-
return [];
|
|
24440
|
-
}
|
|
24411
|
+
function accountHints3(accounts) {
|
|
24441
24412
|
return connectedResourceHints({
|
|
24442
24413
|
plural: "Meta ad accounts",
|
|
24443
24414
|
singular: "Meta ad account",
|
|
@@ -24455,44 +24426,23 @@ var accountsCommand3 = defineCommand55({
|
|
|
24455
24426
|
|
|
24456
24427
|
Examples:
|
|
24457
24428
|
baker ads meta accounts
|
|
24458
|
-
baker ads meta accounts --include-all # ignore picker scope and list every account the token can see
|
|
24459
24429
|
baker ads meta accounts --output csv`
|
|
24460
24430
|
},
|
|
24461
24431
|
args: {
|
|
24462
|
-
"include-all": { type: "boolean", description: "List all accessible accounts, ignoring picker scope" },
|
|
24463
24432
|
"no-cache": NO_CACHE_ARG,
|
|
24464
24433
|
output: { type: "string", description: "Output format: json|csv|jsonl|md", default: "json" }
|
|
24465
24434
|
},
|
|
24466
24435
|
run: async ({ args: args5 }) => {
|
|
24467
|
-
const includeAll = args5["include-all"] === true;
|
|
24468
|
-
const useCache = !args5["no-cache"];
|
|
24469
|
-
const cacheKey = `accounts:${includeAll ? "all" : "scoped"}`;
|
|
24470
|
-
if (useCache) {
|
|
24471
|
-
const cached = cacheGet("meta-accounts", cacheKey);
|
|
24472
|
-
if (cached) {
|
|
24473
|
-
writeJsonEnvelope({
|
|
24474
|
-
ok: true,
|
|
24475
|
-
data: cached.data,
|
|
24476
|
-
cached: true,
|
|
24477
|
-
hints: accountHints3(cached.data, includeAll)
|
|
24478
|
-
});
|
|
24479
|
-
return;
|
|
24480
|
-
}
|
|
24481
|
-
}
|
|
24482
24436
|
try {
|
|
24483
24437
|
const params = {};
|
|
24484
|
-
if (
|
|
24485
|
-
if (!useCache) params["skip-cache"] = "true";
|
|
24438
|
+
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
24486
24439
|
const data = await apiGet("/api/ads/meta/accounts", params);
|
|
24487
|
-
if (useCache) {
|
|
24488
|
-
cacheSet("meta-accounts", cacheKey, data, 60 * 60 * 1e3);
|
|
24489
|
-
}
|
|
24490
24440
|
const fmt = csvOrJson(args5);
|
|
24491
24441
|
if (fmt !== "json") {
|
|
24492
24442
|
writeAdsOutput(data, fmt);
|
|
24493
24443
|
return;
|
|
24494
24444
|
}
|
|
24495
|
-
writeJsonEnvelope({ ok: true, data, hints: accountHints3(data
|
|
24445
|
+
writeJsonEnvelope({ ok: true, data, hints: accountHints3(data) });
|
|
24496
24446
|
} catch (err) {
|
|
24497
24447
|
handleMetaError(err);
|
|
24498
24448
|
}
|
|
@@ -24793,7 +24743,7 @@ function leafRefusal(field, condition, path48) {
|
|
|
24793
24743
|
}
|
|
24794
24744
|
|
|
24795
24745
|
// ../api/src/ads-meta/leadAds.ts
|
|
24796
|
-
var META_LEAD_ADS_NOT_ENABLED_MESSAGE = "
|
|
24746
|
+
var META_LEAD_ADS_NOT_ENABLED_MESSAGE = "Using Meta instant forms and their leads is not switched on for this company. Everything else on Meta keeps working. Tell the user this needs switching on by the Baker team, and carry on with the rest of the job.";
|
|
24797
24747
|
var META_LEAD_ADS_RECONNECT_MESSAGE = "This Meta connection was made before lead ads were switched on for this company, so it cannot work with instant forms or read their leads. Ask the user to reconnect Meta in the dashboard \u2014 that grants the extra permissions \u2014 then ask for this again. Everything else on Meta keeps working meanwhile.";
|
|
24798
24748
|
function isMetaLeadAdsRefusal(message) {
|
|
24799
24749
|
return message === META_LEAD_ADS_NOT_ENABLED_MESSAGE || message === META_LEAD_ADS_RECONNECT_MESSAGE;
|
|
@@ -25879,7 +25829,7 @@ var callToActionSchema = z37.strictObject({
|
|
|
25879
25829
|
* Without it Meta refuses every ad in that ad set with subcode 3390001,
|
|
25880
25830
|
* "Choose or create an instant form for your leads campaign".
|
|
25881
25831
|
*/
|
|
25882
|
-
lead_gen_form_id:
|
|
25832
|
+
lead_gen_form_id: parentRefSchema3.optional()
|
|
25883
25833
|
}).superRefine((p, ctx) => {
|
|
25884
25834
|
if (p.lead_gen_form_id && !LEAD_FORM_CTA_TYPES.some((allowed) => allowed === p.type)) {
|
|
25885
25835
|
ctx.addIssue({
|
|
@@ -26202,6 +26152,50 @@ var mediaUploadSchema = z37.strictObject({
|
|
|
26202
26152
|
ctx.addIssue({ code: "custom", path: ["bakerVideoId"], message: "video uploads need a bakerVideoId" });
|
|
26203
26153
|
}
|
|
26204
26154
|
});
|
|
26155
|
+
var leadFormCreateSchema2 = z37.strictObject({
|
|
26156
|
+
page_id: z37.string().regex(NUMERIC_ID_REGEX3),
|
|
26157
|
+
name: z37.string().min(1).max(255),
|
|
26158
|
+
locale: z37.enum(["EN_US", "EN_GB", "ES_ES", "ES_LA", "FR_FR", "DE_DE", "PT_BR", "PT_PT"]).default("EN_US"),
|
|
26159
|
+
questionPageHeadline: z37.string().min(1).max(255).optional(),
|
|
26160
|
+
questions: z37.array(
|
|
26161
|
+
z37.strictObject({
|
|
26162
|
+
type: z37.enum([
|
|
26163
|
+
"FULL_NAME",
|
|
26164
|
+
"FIRST_NAME",
|
|
26165
|
+
"LAST_NAME",
|
|
26166
|
+
"EMAIL",
|
|
26167
|
+
"PHONE",
|
|
26168
|
+
"CITY",
|
|
26169
|
+
"STATE",
|
|
26170
|
+
"COUNTRY",
|
|
26171
|
+
"ZIP_CODE",
|
|
26172
|
+
"COMPANY_NAME",
|
|
26173
|
+
"JOB_TITLE",
|
|
26174
|
+
"CUSTOM"
|
|
26175
|
+
]),
|
|
26176
|
+
label: z37.string().min(1).max(255).optional()
|
|
26177
|
+
})
|
|
26178
|
+
).min(1).max(15),
|
|
26179
|
+
privacyPolicyUrl: httpsUrlSchema3,
|
|
26180
|
+
privacyPolicyLinkText: z37.string().min(1).max(70).default("Privacy Policy"),
|
|
26181
|
+
followUpActionUrl: httpsUrlSchema3,
|
|
26182
|
+
optimizedForQuality: z37.boolean().default(false),
|
|
26183
|
+
thankYou: z37.strictObject({
|
|
26184
|
+
title: z37.string().min(1).max(255),
|
|
26185
|
+
body: z37.string().min(1).max(1e3),
|
|
26186
|
+
buttonText: z37.string().min(1).max(70).default("View website")
|
|
26187
|
+
}).optional()
|
|
26188
|
+
}).superRefine((form, ctx) => {
|
|
26189
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26190
|
+
for (const [index, question] of form.questions.entries()) {
|
|
26191
|
+
if (question.type === "CUSTOM" && !question.label) {
|
|
26192
|
+
ctx.addIssue({ code: "custom", path: ["questions", index, "label"], message: "custom questions need a label" });
|
|
26193
|
+
}
|
|
26194
|
+
const key = `${question.type}:${question.label ?? ""}`;
|
|
26195
|
+
if (seen.has(key)) ctx.addIssue({ code: "custom", path: ["questions", index], message: "duplicate question" });
|
|
26196
|
+
seen.add(key);
|
|
26197
|
+
}
|
|
26198
|
+
});
|
|
26205
26199
|
var META_DRAFT_OP_KINDS = [
|
|
26206
26200
|
"campaign.create",
|
|
26207
26201
|
"campaign.update",
|
|
@@ -26214,6 +26208,7 @@ var META_DRAFT_OP_KINDS = [
|
|
|
26214
26208
|
"customAudience.create",
|
|
26215
26209
|
"customAudience.update",
|
|
26216
26210
|
"customConversion.create",
|
|
26211
|
+
"leadForm.create",
|
|
26217
26212
|
"media.upload"
|
|
26218
26213
|
];
|
|
26219
26214
|
var metaDraftOpKindSchema = z37.enum(META_DRAFT_OP_KINDS);
|
|
@@ -26237,6 +26232,7 @@ var metaDraftOpInputSchema = z37.discriminatedUnion("kind", [
|
|
|
26237
26232
|
createOp4("customAudience.create", customAudienceCreateSchema),
|
|
26238
26233
|
updateOp4("customAudience.update", customAudienceUpdateSchema),
|
|
26239
26234
|
createOp4("customConversion.create", customConversionCreateSchema),
|
|
26235
|
+
createOp4("leadForm.create", leadFormCreateSchema2),
|
|
26240
26236
|
createOp4("media.upload", mediaUploadSchema)
|
|
26241
26237
|
]);
|
|
26242
26238
|
|
|
@@ -26827,7 +26823,7 @@ Example: baker ads meta creatives create --page 555 --message "Save now" --link
|
|
|
26827
26823
|
cta: { type: "string", description: "Call-to-action type (SHOP_NOW|LEARN_MORE|SIGN_UP|\u2026)" },
|
|
26828
26824
|
"lead-form": {
|
|
26829
26825
|
type: "string",
|
|
26830
|
-
description: "Instant form id
|
|
26826
|
+
description: "Instant form id or meta_temp_* ref from `baker ads meta lead-forms create` \u2014 REQUIRED for an ad set that collects leads on the ad. With a form, --cta must be APPLY_NOW|DOWNLOAD|GET_QUOTE|LEARN_MORE|SIGN_UP|SUBSCRIBE"
|
|
26831
26827
|
},
|
|
26832
26828
|
"image-hash": { type: "string", description: "Meta ad-image hash (already uploaded)" },
|
|
26833
26829
|
"image-ref": { type: "string", description: "meta_temp_* ref of a staged media upload" },
|
|
@@ -26971,7 +26967,7 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
26971
26967
|
const { apiPost: apiPost2 } = await import("./client-GR6YL3YX.js");
|
|
26972
26968
|
const { requireChatId: requireChatId2 } = await import("./env-4P5HOGNA.js");
|
|
26973
26969
|
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-NMQXZF3Z.js");
|
|
26974
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
26970
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-6762QE6R.js");
|
|
26975
26971
|
try {
|
|
26976
26972
|
const accountId = bareAccountId2(args5);
|
|
26977
26973
|
const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
|
|
@@ -27125,7 +27121,7 @@ function duplicateCommand2(entity, label) {
|
|
|
27125
27121
|
const { apiPost: apiPost2 } = await import("./client-GR6YL3YX.js");
|
|
27126
27122
|
const { requireChatId: requireChatId2 } = await import("./env-4P5HOGNA.js");
|
|
27127
27123
|
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-NMQXZF3Z.js");
|
|
27128
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
27124
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-6762QE6R.js");
|
|
27129
27125
|
try {
|
|
27130
27126
|
const accountId = bareAccountId2(args5);
|
|
27131
27127
|
const chatId = requireChatId2();
|
|
@@ -27378,7 +27374,7 @@ import { defineCommand as defineCommand61 } from "citty";
|
|
|
27378
27374
|
var businessesCommand = defineCommand61({
|
|
27379
27375
|
meta: {
|
|
27380
27376
|
name: "businesses",
|
|
27381
|
-
description: `List Meta Business Manager accounts
|
|
27377
|
+
description: `List Meta Business Manager accounts linked to this company's selected ad accounts. Required for ad-studies and product-catalogs commands.
|
|
27382
27378
|
|
|
27383
27379
|
Examples:
|
|
27384
27380
|
baker ads meta businesses`
|
|
@@ -28248,13 +28244,47 @@ Async is automatic for heavy queries; pass --async to force it, or --no-async to
|
|
|
28248
28244
|
import { defineCommand as defineCommand67 } from "citty";
|
|
28249
28245
|
registerSchema({
|
|
28250
28246
|
command: "ads.meta.lead-forms",
|
|
28251
|
-
description: "List the instant (lead) forms on a Facebook Page, with how many leads each has collected. Start here: a lead is fetched by form id
|
|
28247
|
+
description: "List the instant (lead) forms on a Facebook Page, with how many leads each has collected. Start here: a lead is fetched by form id. Use a Page from `baker ads meta pages` with hasPageAccessToken: true.",
|
|
28252
28248
|
args: {
|
|
28253
|
-
"page-id": {
|
|
28249
|
+
"page-id": {
|
|
28250
|
+
type: "string",
|
|
28251
|
+
description: "Facebook Page ID \u2014 from `baker ads meta pages` with hasPageAccessToken: true",
|
|
28252
|
+
required: true
|
|
28253
|
+
},
|
|
28254
28254
|
full: { type: "boolean", description: "Include each form's questions", required: false },
|
|
28255
28255
|
output: { type: "string", description: "json|csv", required: false, default: "json" }
|
|
28256
28256
|
}
|
|
28257
28257
|
});
|
|
28258
|
+
registerSchema({
|
|
28259
|
+
command: "ads.meta.lead-forms.create",
|
|
28260
|
+
description: "Start here to stage a Page-owned Meta Instant Form. The form is created only when this Session publishes. Use the returned meta_temp_* ref as --lead-form on a creative in the same Session.",
|
|
28261
|
+
args: {
|
|
28262
|
+
"account-id": { type: "string", description: "Selected Meta ad account, act_<id>", required: true },
|
|
28263
|
+
"page-id": {
|
|
28264
|
+
type: "string",
|
|
28265
|
+
description: "Facebook Page that owns the form \u2014 choose one with this account in promotingAccountIds and hasPageAccessToken: true from `baker ads meta pages`",
|
|
28266
|
+
required: true
|
|
28267
|
+
},
|
|
28268
|
+
name: { type: "string", description: "Form name", required: true },
|
|
28269
|
+
questions: {
|
|
28270
|
+
type: "string",
|
|
28271
|
+
description: "Comma-separated Meta fields, e.g. FULL_NAME,EMAIL,PHONE",
|
|
28272
|
+
required: true
|
|
28273
|
+
},
|
|
28274
|
+
"privacy-policy-url": { type: "string", description: "Public HTTPS privacy policy", required: true },
|
|
28275
|
+
"follow-up-url": { type: "string", description: "Public HTTPS link after submission", required: true },
|
|
28276
|
+
"optimized-for-quality": {
|
|
28277
|
+
type: "boolean",
|
|
28278
|
+
description: "Ask Meta to optimize form leads for quality",
|
|
28279
|
+
required: false
|
|
28280
|
+
},
|
|
28281
|
+
file: {
|
|
28282
|
+
type: "string",
|
|
28283
|
+
description: "JSON file with full form payload, including thankYou and custom questions",
|
|
28284
|
+
required: false
|
|
28285
|
+
}
|
|
28286
|
+
}
|
|
28287
|
+
});
|
|
28258
28288
|
registerSchema({
|
|
28259
28289
|
command: "ads.meta.leads",
|
|
28260
28290
|
description: "Read the leads an instant form collected. Contact details (email, phone) come back masked; pass --full only when the raw values are genuinely needed, e.g. handing them to a CRM.",
|
|
@@ -28320,25 +28350,56 @@ function leadPageHints(page, full) {
|
|
|
28320
28350
|
}
|
|
28321
28351
|
return hints2;
|
|
28322
28352
|
}
|
|
28323
|
-
var
|
|
28353
|
+
var leadFormsCreateCommand2 = defineCommand67({
|
|
28324
28354
|
meta: {
|
|
28325
|
-
name: "
|
|
28326
|
-
description: `
|
|
28327
|
-
|
|
28328
|
-
|
|
28329
|
-
baker ads meta lead-forms --page-id 100635183117758
|
|
28330
|
-
baker ads meta lead-forms --page-id 100635183117758 --full # also lists each form's questions`
|
|
28355
|
+
name: "create",
|
|
28356
|
+
description: `Stage a Meta Instant Form on a Facebook Page. The form appears in review and is created only when the Session publishes.
|
|
28357
|
+
Choose a Page with this account in promotingAccountIds and hasPageAccessToken: true from \`baker ads meta pages\`.
|
|
28358
|
+
Example: baker ads meta lead-forms create --account-id act_123 --page-id 456 --name "Free audit" --questions FULL_NAME,EMAIL,PHONE --privacy-policy-url https://example.com/privacy --follow-up-url https://example.com`
|
|
28331
28359
|
},
|
|
28332
28360
|
args: {
|
|
28361
|
+
"account-id": { type: "string", description: "Selected Meta ad account" },
|
|
28333
28362
|
"page-id": { type: "string", description: "Facebook Page ID" },
|
|
28334
|
-
|
|
28335
|
-
|
|
28363
|
+
name: { type: "string", description: "Form name" },
|
|
28364
|
+
questions: { type: "string", description: "FULL_NAME,EMAIL,PHONE or other Meta fields" },
|
|
28365
|
+
"privacy-policy-url": { type: "string", description: "HTTPS privacy policy" },
|
|
28366
|
+
"follow-up-url": { type: "string", description: "HTTPS thank-you link" },
|
|
28367
|
+
"optimized-for-quality": { type: "boolean", description: "Optimize form leads for quality" },
|
|
28368
|
+
file: { type: "string", description: "JSON form payload; flags override file keys" }
|
|
28336
28369
|
},
|
|
28370
|
+
run: async ({ args: args5 }) => {
|
|
28371
|
+
const accountId = bareAccountId2(args5);
|
|
28372
|
+
const payload = mergePayload3(loadJsonFileArg3(args5.file), {
|
|
28373
|
+
page_id: args5["page-id"],
|
|
28374
|
+
name: args5.name,
|
|
28375
|
+
questions: typeof args5.questions === "string" ? args5.questions.split(",").map((type) => ({ type: type.trim().toUpperCase() })) : void 0,
|
|
28376
|
+
privacyPolicyUrl: args5["privacy-policy-url"],
|
|
28377
|
+
followUpActionUrl: args5["follow-up-url"],
|
|
28378
|
+
optimizedForQuality: args5["optimized-for-quality"]
|
|
28379
|
+
});
|
|
28380
|
+
await stageOp2({ kind: "leadForm.create", accountId, payload });
|
|
28381
|
+
}
|
|
28382
|
+
});
|
|
28383
|
+
var leadFormsListArgs = {
|
|
28384
|
+
"page-id": { type: "string", description: "Facebook Page ID" },
|
|
28385
|
+
full: { type: "boolean", description: "Include each form's questions" },
|
|
28386
|
+
output: { type: "string", description: "Output format", default: "json" }
|
|
28387
|
+
};
|
|
28388
|
+
var leadFormsListCommand = defineCommand67({
|
|
28389
|
+
meta: {
|
|
28390
|
+
name: "list",
|
|
28391
|
+
description: "List the Instant Forms on a Facebook Page, with lead counts. Choose a Page with hasPageAccessToken: true from `baker ads meta pages`. Pass --full to include questions."
|
|
28392
|
+
},
|
|
28393
|
+
args: leadFormsListArgs,
|
|
28337
28394
|
run: async ({ args: args5 }) => {
|
|
28338
28395
|
try {
|
|
28339
28396
|
const pageId = args5["page-id"];
|
|
28340
28397
|
if (!pageId) {
|
|
28341
|
-
handleLeadsError(
|
|
28398
|
+
handleLeadsError(
|
|
28399
|
+
new Error(
|
|
28400
|
+
"--page-id is required. Run `baker ads meta pages` and choose a Page with hasPageAccessToken: true."
|
|
28401
|
+
)
|
|
28402
|
+
);
|
|
28342
28403
|
}
|
|
28343
28404
|
const params = { "page-id": pageId };
|
|
28344
28405
|
if (args5.full) params.full = "true";
|
|
@@ -28355,6 +28416,19 @@ Examples:
|
|
|
28355
28416
|
}
|
|
28356
28417
|
}
|
|
28357
28418
|
});
|
|
28419
|
+
var leadFormsCommand2 = defineCommand67({
|
|
28420
|
+
meta: {
|
|
28421
|
+
name: "lead-forms",
|
|
28422
|
+
description: `List Instant Forms on a Facebook Page or stage a new one.
|
|
28423
|
+
Examples:
|
|
28424
|
+
baker ads meta lead-forms --page-id 100635183117758
|
|
28425
|
+
baker ads meta lead-forms --page-id 100635183117758 --full
|
|
28426
|
+
baker ads meta lead-forms create --account-id act_123 --page-id 555 --file form.json`
|
|
28427
|
+
},
|
|
28428
|
+
args: leadFormsListArgs,
|
|
28429
|
+
subCommands: { list: leadFormsListCommand, create: leadFormsCreateCommand2 },
|
|
28430
|
+
default: "list"
|
|
28431
|
+
});
|
|
28358
28432
|
var leadsCommand2 = defineCommand67({
|
|
28359
28433
|
meta: {
|
|
28360
28434
|
name: "leads",
|
|
@@ -28424,27 +28498,21 @@ var metaMediaCommand = defineCommand68({
|
|
|
28424
28498
|
|
|
28425
28499
|
// src/commands/ads/meta/pages.ts
|
|
28426
28500
|
import { defineCommand as defineCommand69 } from "citty";
|
|
28427
|
-
function advertisablePages(data) {
|
|
28428
|
-
return data.filter((p) => Array.isArray(p.tasks) && p.tasks.includes("ADVERTISE"));
|
|
28429
|
-
}
|
|
28430
28501
|
function pageSelectionHints(data) {
|
|
28431
|
-
|
|
28432
|
-
|
|
28433
|
-
|
|
28434
|
-
"MULTIPLE Pages can run ads \u2014 do NOT guess. Confirm with the user which Page an ad should run from before passing --page to `creatives create`; a wrong Page publishes the ad under the wrong brand identity and staging will not catch it."
|
|
28435
|
-
];
|
|
28436
|
-
}
|
|
28437
|
-
if (data.length > 0 && advertisable.length === 0) {
|
|
28502
|
+
if (data.length === 0) return [];
|
|
28503
|
+
const accountHint = "Use a Page only with an ad account listed in its promotingAccountIds. hasPageAccessToken must be true to read instant forms; null means Meta could not check it. Form reads also require the company's lead-ads permissions.";
|
|
28504
|
+
if (data.length > 1) {
|
|
28438
28505
|
return [
|
|
28439
|
-
|
|
28506
|
+
accountHint,
|
|
28507
|
+
"MULTIPLE Pages can run ads from the selected Meta ad accounts \u2014 do NOT guess. Confirm with the user which Page an ad should run from before passing --page to `creatives create`; a wrong Page publishes the ad under the wrong brand identity and staging will not catch it."
|
|
28440
28508
|
];
|
|
28441
28509
|
}
|
|
28442
|
-
return [];
|
|
28510
|
+
return [accountHint];
|
|
28443
28511
|
}
|
|
28444
28512
|
var pagesCommand = defineCommand69({
|
|
28445
28513
|
meta: {
|
|
28446
28514
|
name: "pages",
|
|
28447
|
-
description: `List the Facebook Pages the
|
|
28515
|
+
description: `List the Facebook Pages that the selected Meta ad accounts can promote, showing which accounts can promote each Page. Every Meta ad publishes from a Page, so match its promotingAccountIds to the target account. hasPageAccessToken shows whether the connected person can also read that Page's instant forms. If more than one Page is listed, confirm the brand with the user.
|
|
28448
28516
|
|
|
28449
28517
|
Examples:
|
|
28450
28518
|
baker ads meta pages`
|
|
@@ -28703,10 +28771,10 @@ var metaCommand = defineCommand72({
|
|
|
28703
28771
|
|
|
28704
28772
|
Discovery:
|
|
28705
28773
|
baker ads meta accounts \u2014 accounts in this company's connected scope
|
|
28706
|
-
baker ads meta accounts --include-all \u2014 every account the token can see
|
|
28707
28774
|
baker ads meta businesses \u2014 Business Manager IDs
|
|
28708
|
-
baker ads meta pages \u2014 Facebook Pages the
|
|
28775
|
+
baker ads meta pages \u2014 Facebook Pages the selected ad accounts can promote (an ad's identity)
|
|
28709
28776
|
baker ads meta lead-forms --page-id 100635183117758 \u2014 instant (lead) forms on a Page, with lead counts
|
|
28777
|
+
baker ads meta lead-forms create --account-id act_123 --page-id 555 --file form.json \u2014 stage a new form
|
|
28710
28778
|
baker ads meta leads --form-id 987654321 \u2014 the leads one form collected (contact details masked)
|
|
28711
28779
|
|
|
28712
28780
|
Snapshot a running account (default = ACTIVE only):
|
|
@@ -66999,7 +67067,7 @@ var draftCommand5 = defineCommand218({
|
|
|
66999
67067
|
import { defineCommand as defineCommand219 } from "citty";
|
|
67000
67068
|
registerSchema({
|
|
67001
67069
|
command: "tagManager.containers",
|
|
67002
|
-
description: "List the Google Tag Manager containers this company
|
|
67070
|
+
description: "List the Google Tag Manager containers this company selected. There can be several, and Baker may read and change all of them. Start here to confirm which containers you are managing.",
|
|
67003
67071
|
args: {}
|
|
67004
67072
|
});
|
|
67005
67073
|
registerSchema({
|
|
@@ -67020,27 +67088,34 @@ registerSchema({
|
|
|
67020
67088
|
full: { type: "boolean", description: "Include the raw Tag Manager object for each entity", required: false }
|
|
67021
67089
|
}
|
|
67022
67090
|
});
|
|
67023
|
-
function containersHints(containers) {
|
|
67024
|
-
const
|
|
67025
|
-
if (connected.length === 0) {
|
|
67026
|
-
return [
|
|
67027
|
-
"None of the containers this company connected came back from Tag Manager. The connected Google account may have lost access to them \u2014 ask the user to reconnect or pick a container again."
|
|
67028
|
-
];
|
|
67029
|
-
}
|
|
67030
|
-
return connectedResourceHints({
|
|
67091
|
+
function containersHints(containers, unavailableContainers = []) {
|
|
67092
|
+
const hints2 = connectedResourceHints({
|
|
67031
67093
|
plural: "Tag Manager containers",
|
|
67032
67094
|
singular: "Tag Manager container",
|
|
67033
67095
|
flag: "--container",
|
|
67034
|
-
resources:
|
|
67096
|
+
resources: containers.map((container) => ({
|
|
67035
67097
|
id: container.containerId,
|
|
67036
67098
|
label: `${container.publicId} \xB7 ${container.name}`
|
|
67037
67099
|
}))
|
|
67038
67100
|
});
|
|
67101
|
+
if (unavailableContainers.length > 0) {
|
|
67102
|
+
const [available] = containers;
|
|
67103
|
+
if (containers.length === 1 && available) {
|
|
67104
|
+
hints2.length = 0;
|
|
67105
|
+
hints2.push(
|
|
67106
|
+
`Use --container ${available.containerId} for ${available.publicId} (${available.name}); another selected container cannot be opened.`
|
|
67107
|
+
);
|
|
67108
|
+
}
|
|
67109
|
+
hints2.push(
|
|
67110
|
+
`Tag Manager cannot open ${unavailableContainers.map((container) => `${container.publicId} (${container.name})`).join(", ")}. Ask the user to reconnect with a Google account that has access to these containers.`
|
|
67111
|
+
);
|
|
67112
|
+
}
|
|
67113
|
+
return hints2;
|
|
67039
67114
|
}
|
|
67040
67115
|
var containersCommand = defineCommand219({
|
|
67041
67116
|
meta: {
|
|
67042
67117
|
name: "containers",
|
|
67043
|
-
description: `List Tag Manager containers
|
|
67118
|
+
description: `List Tag Manager containers selected by this company.
|
|
67044
67119
|
|
|
67045
67120
|
Start here:
|
|
67046
67121
|
baker tag-manager containers`
|
|
@@ -67048,7 +67123,7 @@ Start here:
|
|
|
67048
67123
|
run: async () => {
|
|
67049
67124
|
try {
|
|
67050
67125
|
const data = await apiGet("/api/tag-manager/containers");
|
|
67051
|
-
writeJsonEnvelope({ ok: true, data, hints: containersHints(data.containers) });
|
|
67126
|
+
writeJsonEnvelope({ ok: true, data, hints: containersHints(data.containers, data.unavailableContainers) });
|
|
67052
67127
|
} catch (err) {
|
|
67053
67128
|
handleError8(err);
|
|
67054
67129
|
}
|