@koda-sl/baker-cli 0.526.0 → 0.527.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.
Files changed (98) hide show
  1. package/README.md +1 -0
  2. package/dist/{account-APMJVG2F.js → account-CQJFUII3.js} +3 -3
  3. package/dist/{account-APMJVG2F.js.map → account-CQJFUII3.js.map} +1 -1
  4. package/dist/{account-assets-TAUEBCY5.js → account-assets-IDVG4DGK.js} +12 -12
  5. package/dist/account-assets-IDVG4DGK.js.map +1 -0
  6. package/dist/{account-level-2MYDHOID.js → account-level-GK7M2MMQ.js} +14 -14
  7. package/dist/account-level-GK7M2MMQ.js.map +1 -0
  8. package/dist/{accounts-VIAQC3PA.js → accounts-KRW3JNCW.js} +2 -2
  9. package/dist/{activities-MJMAV3SI.js → activities-2RAJXP3J.js} +3 -3
  10. package/dist/{activities-MJMAV3SI.js.map → activities-2RAJXP3J.js.map} +1 -1
  11. package/dist/{ads-O4RL4JXD.js → ads-F2PURRHL.js} +2 -2
  12. package/dist/{ads-NNKUR4HG.js → ads-JVBLNTBF.js} +20 -15
  13. package/dist/ads-JVBLNTBF.js.map +1 -0
  14. package/dist/{adsets-VO5C7PDM.js → adsets-FN5ZWSYF.js} +11 -11
  15. package/dist/adsets-FN5ZWSYF.js.map +1 -0
  16. package/dist/{asset-writes-PQNENVYY.js → asset-writes-SSI3CO2A.js} +4 -4
  17. package/dist/{audience-writes-QDDADCYE.js → audience-writes-G64754LR.js} +6 -6
  18. package/dist/audience-writes-G64754LR.js.map +1 -0
  19. package/dist/{audiences-TQ5ZEWIR.js → audiences-JAVNJ5NC.js} +8 -8
  20. package/dist/audiences-JAVNJ5NC.js.map +1 -0
  21. package/dist/{businesses-CW4RB36R.js → businesses-DXRDQIFP.js} +2 -2
  22. package/dist/{campaigns-IQYYYD2S.js → campaigns-GQWFSKGC.js} +11 -11
  23. package/dist/campaigns-GQWFSKGC.js.map +1 -0
  24. package/dist/{catalogs-PLBY32BE.js → catalogs-TBRONC2D.js} +15 -15
  25. package/dist/catalogs-TBRONC2D.js.map +1 -0
  26. package/dist/{chunk-OEJNZSJG.js → chunk-4XXA4WCS.js} +4 -4
  27. package/dist/chunk-4XXA4WCS.js.map +1 -0
  28. package/dist/{chunk-HPAGYPAF.js → chunk-BN4TDL5L.js} +65 -23
  29. package/dist/chunk-BN4TDL5L.js.map +1 -0
  30. package/dist/{chunk-5LN7GWRE.js → chunk-GEFZVG4P.js} +10 -10
  31. package/dist/chunk-GEFZVG4P.js.map +1 -0
  32. package/dist/{chunk-XB2FODWU.js → chunk-TKDOVFO6.js} +2 -2
  33. package/dist/cli.js +1 -1
  34. package/dist/{copy-writes-GZ744FHU.js → copy-writes-EUFEVWDW.js} +5 -5
  35. package/dist/{copy-writes-GZ744FHU.js.map → copy-writes-EUFEVWDW.js.map} +1 -1
  36. package/dist/{creatives-GTRQAZSB.js → creatives-6VJDUHEY.js} +6 -6
  37. package/dist/creatives-6VJDUHEY.js.map +1 -0
  38. package/dist/{custom-conversions-VQ3LBWYV.js → custom-conversions-NDY5RHSM.js} +6 -6
  39. package/dist/{custom-conversions-VQ3LBWYV.js.map → custom-conversions-NDY5RHSM.js.map} +1 -1
  40. package/dist/{draft-ME4TNPO7.js → draft-G432FJ7N.js} +2 -2
  41. package/dist/{insights-INIFHYR7.js → insights-IVW6W5CP.js} +2 -2
  42. package/dist/{instant-experiences-NMJUWNP3.js → instant-experiences-6F6GXZ67.js} +5 -5
  43. package/dist/{instant-experiences-NMJUWNP3.js.map → instant-experiences-6F6GXZ67.js.map} +1 -1
  44. package/dist/{leads-QBWR7FKT.js → leads-CJKRKB2Q.js} +6 -6
  45. package/dist/{leads-QBWR7FKT.js.map → leads-CJKRKB2Q.js.map} +1 -1
  46. package/dist/{media-23IW442U.js → media-HDHZULQ7.js} +3 -3
  47. package/dist/{meta-H3KBPU33.js → meta-MOSJVYIE.js} +38 -38
  48. package/dist/{page-photos-SHIGXDYE.js → page-photos-4JTIKXAW.js} +5 -5
  49. package/dist/page-photos-4JTIKXAW.js.map +1 -0
  50. package/dist/{pages-XJF3FBOJ.js → pages-BAUS7LQM.js} +2 -2
  51. package/dist/{pixels-AZCIWWXK.js → pixels-QOSEYXCP.js} +3 -3
  52. package/dist/pixels-QOSEYXCP.js.map +1 -0
  53. package/dist/{preview-BIEVHIDJ.js → preview-X6EJGPAY.js} +2 -2
  54. package/dist/{rule-writes-QLZNJ7CT.js → rule-writes-A4BFYHPA.js} +7 -7
  55. package/dist/rule-writes-A4BFYHPA.js.map +1 -0
  56. package/dist/{rules-FJHYG4SJ.js → rules-HLREXY2M.js} +11 -11
  57. package/dist/rules-HLREXY2M.js.map +1 -0
  58. package/dist/{shared-HY2VP7PT.js → shared-I3SB77VH.js} +2 -2
  59. package/dist/{studies-Z2ZIWLTO.js → studies-IGOCWM7F.js} +7 -7
  60. package/dist/{studies-Z2ZIWLTO.js.map → studies-IGOCWM7F.js.map} +1 -1
  61. package/dist/{study-writes-V7BXLTQG.js → study-writes-Z5P2W7JH.js} +6 -6
  62. package/dist/study-writes-Z5P2W7JH.js.map +1 -0
  63. package/dist/{targeting-YBIWD27C.js → targeting-7HXKBXWY.js} +12 -12
  64. package/dist/targeting-7HXKBXWY.js.map +1 -0
  65. package/dist/{write-commands-R5SN6CVQ.js → write-commands-CY734U34.js} +22 -22
  66. package/dist/write-commands-CY734U34.js.map +1 -0
  67. package/package.json +1 -1
  68. package/dist/account-assets-TAUEBCY5.js.map +0 -1
  69. package/dist/account-level-2MYDHOID.js.map +0 -1
  70. package/dist/ads-NNKUR4HG.js.map +0 -1
  71. package/dist/adsets-VO5C7PDM.js.map +0 -1
  72. package/dist/audience-writes-QDDADCYE.js.map +0 -1
  73. package/dist/audiences-TQ5ZEWIR.js.map +0 -1
  74. package/dist/campaigns-IQYYYD2S.js.map +0 -1
  75. package/dist/catalogs-PLBY32BE.js.map +0 -1
  76. package/dist/chunk-5LN7GWRE.js.map +0 -1
  77. package/dist/chunk-HPAGYPAF.js.map +0 -1
  78. package/dist/chunk-OEJNZSJG.js.map +0 -1
  79. package/dist/creatives-GTRQAZSB.js.map +0 -1
  80. package/dist/page-photos-SHIGXDYE.js.map +0 -1
  81. package/dist/pixels-AZCIWWXK.js.map +0 -1
  82. package/dist/rule-writes-QLZNJ7CT.js.map +0 -1
  83. package/dist/rules-FJHYG4SJ.js.map +0 -1
  84. package/dist/study-writes-V7BXLTQG.js.map +0 -1
  85. package/dist/targeting-YBIWD27C.js.map +0 -1
  86. package/dist/write-commands-R5SN6CVQ.js.map +0 -1
  87. /package/dist/{accounts-VIAQC3PA.js.map → accounts-KRW3JNCW.js.map} +0 -0
  88. /package/dist/{ads-O4RL4JXD.js.map → ads-F2PURRHL.js.map} +0 -0
  89. /package/dist/{asset-writes-PQNENVYY.js.map → asset-writes-SSI3CO2A.js.map} +0 -0
  90. /package/dist/{businesses-CW4RB36R.js.map → businesses-DXRDQIFP.js.map} +0 -0
  91. /package/dist/{chunk-XB2FODWU.js.map → chunk-TKDOVFO6.js.map} +0 -0
  92. /package/dist/{draft-ME4TNPO7.js.map → draft-G432FJ7N.js.map} +0 -0
  93. /package/dist/{insights-INIFHYR7.js.map → insights-IVW6W5CP.js.map} +0 -0
  94. /package/dist/{media-23IW442U.js.map → media-HDHZULQ7.js.map} +0 -0
  95. /package/dist/{meta-H3KBPU33.js.map → meta-MOSJVYIE.js.map} +0 -0
  96. /package/dist/{pages-XJF3FBOJ.js.map → pages-BAUS7LQM.js.map} +0 -0
  97. /package/dist/{preview-BIEVHIDJ.js.map → preview-X6EJGPAY.js.map} +0 -0
  98. /package/dist/{shared-HY2VP7PT.js.map → shared-I3SB77VH.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/ads/meta/catalogs.ts"],"sourcesContent":["import { retailerIdFilter } from \"@baker/api/ads-meta/catalogs\";\nimport { defineCommand } from \"citty\";\nimport { NO_CACHE_ARG } from \"../../../cache-flag.ts\";\nimport { apiGet } from \"../../../client.ts\";\nimport { repeatedValues } from \"../../../lib/repeatedFlags.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { writeAdsJson, writeAdsOutput, writeJsonEnvelope } from \"../output.ts\";\nimport { csvOrJson, handleMetaError } from \"./shared.ts\";\nimport {\n bareAccountId,\n failWriteValidation,\n loadJsonFileArg,\n mergePayload,\n numberFlag,\n requireTarget,\n stageOp,\n upper,\n} from \"./write-shared.ts\";\n\n/**\n * Product catalogs and what is in them — products, product sets, feeds — read\n * live and changed through this chat's draft (applied at publish). Changing a\n * catalog needs the Catalog permission for Meta (a per-company switch); Baker\n * changes only catalogs the ad account's own Business owns.\n */\n\ntype Row = Record<string, unknown>;\ntype Args = Record<string, unknown>;\n\nconst STAGED_NOTE = \"Staged until publish — review with `baker ads meta draft`.\";\nconst outputArg = { type: \"string\", description: \"json|csv|jsonl|md\", default: \"json\" } as const;\nconst accountArg = {\n type: \"string\",\n description: \"Numeric account ID or act_N (whose Business owns the catalog)\",\n} as const;\nconst schemaAccount = { type: \"string\", description: \"Ad account the change is staged under\", required: false };\nconst schemaOutput = { type: \"string\", description: \"json|csv|jsonl|md\", required: false, default: \"json\" };\n\nfunction emit(rows: Row[], args: Args, hints: string[]): void {\n const fmt = csvOrJson(args);\n if (fmt !== \"json\") {\n writeAdsOutput(rows, fmt, undefined, hints);\n return;\n }\n writeJsonEnvelope(hints.length > 0 ? { ok: true, data: rows, hints } : { ok: true, data: rows });\n}\n\nfunction requireCatalogId(args: Args): string {\n const id = args[\"catalog-id\"];\n if (typeof id !== \"string\" || id.length === 0) {\n failWriteValidation(\"pass --catalog-id (from `baker ads meta catalogs --business-id <id>`, or a meta_temp_* ref)\");\n }\n return id;\n}\n\nfunction stringArg(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction jsonArg(value: unknown, flag: string): Record<string, unknown> | undefined {\n if (typeof value !== \"string\" || value.length === 0) return undefined;\n try {\n return JSON.parse(value) as Record<string, unknown>;\n } catch {\n failWriteValidation(`--${flag} takes JSON, e.g. '{\"brand\":{\"eq\":\"Acme\"}}'`);\n }\n}\n\nasync function contents(edge: \"products\" | \"feeds\" | \"diagnostics\", args: Args): Promise<Row[]> {\n const params: Record<string, string> = { \"catalog-id\": requireCatalogId(args), edge };\n if (args.full) params.full = \"true\";\n if (stringArg(args[\"retailer-id\"])) params[\"retailer-id\"] = String(args[\"retailer-id\"]);\n return await apiGet<Row[]>(\"/api/ads/meta/catalog-contents\", params);\n}\n\n// --- Catalogs (list, create, rename, delete) ---\n\nregisterSchema({\n command: \"ads.meta.catalogs\",\n description:\n \"Product catalogs a Business owns (for catalog / Advantage+ catalog ads), or one catalog's product sets with --catalog-id.\",\n args: {\n \"business-id\": { type: \"string\", description: \"Business ID (baker ads meta businesses)\", required: false },\n \"catalog-id\": { type: \"string\", description: \"List this catalog's product sets\", required: false },\n \"no-cache\": { type: \"boolean\", description: \"Bypass the cache\", required: false },\n output: schemaOutput,\n },\n});\n\nconst catalogsListCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"Product catalogs on a Business, or a catalog's product sets. Runs by default. Example: baker ads meta catalogs --business-id 601050769212882; --catalog-id <id> for its sets\",\n },\n args: {\n \"business-id\": { type: \"string\", description: \"Business ID — from `baker ads meta businesses`\" },\n \"catalog-id\": { type: \"string\", description: \"List the product sets of this catalog\" },\n \"no-cache\": NO_CACHE_ARG,\n output: outputArg,\n },\n run: async ({ args }) => {\n try {\n const cache: Record<string, string> = args[\"no-cache\"] ? { \"skip-cache\": \"true\" } : {};\n if (args[\"catalog-id\"]) {\n const rows = await apiGet<Row[]>(\"/api/ads/meta/product-sets\", {\n \"catalog-id\": args[\"catalog-id\"] as string,\n ...cache,\n });\n emit(rows, args, [\n 'A catalog ad set promotes one product set: promoted_object {\"product_set_id\":\"<id>\"}; product_count 0 means the set\\'s filter matches nothing yet. Read just after a publish with --no-cache.',\n ]);\n return;\n }\n if (!args[\"business-id\"]) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: \"pass --business-id (from `baker ads meta businesses`) or --catalog-id\",\n },\n });\n process.exit(1);\n }\n const rows = await apiGet<Row[]>(\"/api/ads/meta/catalogs\", {\n \"business-id\": args[\"business-id\"] as string,\n ...cache,\n });\n emit(\n rows,\n args,\n rows.length === 0\n ? [\n \"This Business owns no product catalogs. Stage one with `baker ads meta catalogs create --name …`, or — for a catalog another Business shares with it — ask for its id and read it with `catalogs --catalog-id <id>` (shared catalogs are read, never changed).\",\n ]\n : [\n \"`catalogs --catalog-id <id>` lists a catalog's product sets; `catalogs products --catalog-id <id>` its products.\",\n ],\n );\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.create\",\n description:\n \"Stage a new product catalog on the ad account's own Business, made at publish. Needs the Catalog permission for Meta.\",\n args: {\n \"account-id\": schemaAccount,\n name: { type: \"string\", description: \"Catalog name\", required: true },\n pixel: { type: \"string\", description: \"Pixel to connect (repeatable) — catalog ads need one\", required: false },\n },\n});\n\nconst catalogCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a new product catalog on the ad account's own Business. ${STAGED_NOTE}\nConnect the account's pixel with --pixel (\\`baker ads meta pixels\\`): Meta runs catalog ads only on a catalog with one.\nThen add products (\\`catalogs products create --catalog-id meta_temp_…\\`) and a product set to advertise.\nExample: baker ads meta catalogs create --account-id act_123 --name \"Spring shop\" --pixel 1275507706837548`,\n },\n args: {\n \"account-id\": accountArg,\n name: { type: \"string\", description: \"Catalog name\" },\n pixel: { type: \"string\", description: \"Pixel to connect once it exists (repeatable) — catalog ads need one\" },\n },\n run: async ({ args, rawArgs }) => {\n const pixels = repeatedValues(rawArgs, \"pixel\", args.pixel);\n await stageOp(\n {\n kind: \"productCatalog.create\",\n accountId: await bareAccountId(args as Args),\n payload: { name: args.name, event_sources: pixels.length > 0 ? pixels : undefined },\n },\n [\n \"Add products with `catalogs products create --catalog-id <ref>` and a set with `catalogs sets create --catalog-id <ref>`.\",\n ],\n );\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.update\",\n description:\n \"Stage a change to a product catalog the ad account's Business owns: a new name, pixels to connect (catalog ads need one) or disconnect.\",\n args: {\n id: { type: \"positional\", description: \"Catalog id\", required: true },\n \"account-id\": schemaAccount,\n name: { type: \"string\", description: \"New name\", required: false },\n pixel: { type: \"string\", description: \"Pixel to connect (repeatable)\", required: false },\n \"unlink-pixel\": { type: \"string\", description: \"Pixel to disconnect (repeatable)\", required: false },\n },\n});\n\nconst catalogUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Rename a product catalog, or connect / disconnect pixels. ${STAGED_NOTE}\nExample: baker ads meta catalogs update 1798573158016525 --account-id act_123 --pixel 1275507706837548`,\n },\n args: {\n id: { type: \"positional\", description: \"Catalog id\", required: true },\n \"account-id\": accountArg,\n name: { type: \"string\", description: \"New name\" },\n pixel: { type: \"string\", description: \"Pixel to connect (repeatable) — from `baker ads meta pixels`\" },\n \"unlink-pixel\": { type: \"string\", description: \"Pixel to disconnect (repeatable)\" },\n },\n run: async ({ args, rawArgs }) => {\n const pixels = repeatedValues(rawArgs, \"pixel\", args.pixel);\n const unlink = repeatedValues(rawArgs, \"unlink-pixel\", args[\"unlink-pixel\"]);\n await stageOp({\n kind: \"productCatalog.update\",\n accountId: await bareAccountId(args as Args),\n target: requireTarget(args as Args, \"catalog\"),\n payload: {\n name: args.name,\n event_sources: pixels.length > 0 ? pixels : undefined,\n unlink_event_sources: unlink.length > 0 ? unlink : undefined,\n },\n });\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.delete\",\n description:\n \"Stage deleting a product catalog with every product, product set and feed in it. Delete the ads, ad sets and campaigns that use it in the same chat.\",\n args: { id: { type: \"positional\", description: \"Catalog id\", required: true }, \"account-id\": schemaAccount },\n});\n\nconst catalogDeleteCommand = defineCommand({\n meta: {\n name: \"delete\",\n description: `Delete a product catalog and everything in it — runs after every other change in the publish. ${STAGED_NOTE}\nExample: baker ads meta catalogs delete 1798573158016525 --account-id act_123`,\n },\n args: { id: { type: \"positional\", description: \"Catalog id\", required: true }, \"account-id\": accountArg },\n run: async ({ args }) => {\n await stageOp({\n kind: \"productCatalog.update\",\n accountId: await bareAccountId(args as Args),\n target: requireTarget(args as Args, \"catalog\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\n// --- Products ---\n\nconst productFieldArgs = {\n name: { type: \"string\", description: \"Title shoppers see\" },\n description: { type: \"string\", description: \"Description\" },\n price: { type: \"string\", description: 'Price in major units, e.g. \"19.99\"' },\n \"sale-price\": { type: \"string\", description: \"Sale price in major units\" },\n currency: { type: \"string\", description: \"Three-letter currency code, e.g. EUR (needed with a price)\" },\n availability: {\n type: \"string\",\n description: '\"in stock\" (default), \"out of stock\", \"preorder\", \"available for order\", \"discontinued\"',\n },\n condition: { type: \"string\", description: \"new (default), refurbished, used\" },\n url: { type: \"string\", description: \"The product's own page (https) — where its ad sends people\" },\n \"image-url\": {\n type: \"string\",\n description: \"Public https picture Meta fetches (a library image's address works)\",\n },\n \"additional-image-url\": { type: \"string\", description: \"More pictures (repeatable)\" },\n brand: { type: \"string\", description: \"Brand\" },\n} as const;\n\nconst productFieldSchema = Object.fromEntries(\n Object.entries(productFieldArgs).map(([key, arg]) => [key, { ...arg, required: false }]),\n);\n\n/** The product fields given on the command line, in Meta's vocabulary. */\nexport function productFieldsFromArgs(args: Args, rawArgs: readonly string[] | undefined): Record<string, unknown> {\n const extra = repeatedValues(rawArgs, \"additional-image-url\", args[\"additional-image-url\"]);\n return {\n name: args.name,\n description: args.description,\n price: stringArg(args.price),\n sale_price: stringArg(args[\"sale-price\"]),\n currency: upper(args.currency),\n availability: stringArg(args.availability)?.toLowerCase(),\n condition: stringArg(args.condition)?.toLowerCase(),\n url: args.url,\n image_url: args[\"image-url\"],\n additional_image_urls: extra.length > 0 ? extra : undefined,\n brand: args.brand,\n };\n}\n\nregisterSchema({\n command: \"ads.meta.catalogs.products\",\n description:\n \"A catalog's products, compact (id, retailer id, name, price, availability, review status); --full for every field and Meta's errors on each.\",\n args: {\n \"catalog-id\": { type: \"string\", description: \"Catalog id\", required: true },\n \"retailer-id\": { type: \"string\", description: \"Only the product with this retailer id\", required: false },\n full: { type: \"boolean\", description: \"Every field, and Meta's errors on each product\", required: false },\n output: schemaOutput,\n },\n});\n\nconst productsListCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"A catalog's products (up to 500). Runs by default. Example: baker ads meta catalogs products --catalog-id 1798573158016525\",\n },\n args: {\n \"catalog-id\": { type: \"string\", description: \"Catalog id\" },\n \"retailer-id\": { type: \"string\", description: \"Only the product with this retailer id\" },\n full: { type: \"boolean\", description: \"Every field, and Meta's errors on each product\" },\n output: outputArg,\n },\n run: async ({ args }) => {\n try {\n const rows = await contents(\"products\", args as Args);\n const rejected = rows.filter((row) => row.review_status === \"rejected\").length;\n emit(rows, args as Args, [\n ...(rows.length === 0 ? [\"No products yet — stage some with `catalogs products create`.\"] : []),\n ...(rejected > 0\n ? [\n `${rejected} product(s) were rejected by Meta's review — \\`--full\\` shows why; a rejected product is never shown in an ad.`,\n ]\n : []),\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.products.create\",\n description:\n \"Stage a product in a catalog (or one this chat creates), added at publish. Fake or real, every product needs a retailer id, name, description, price + currency, page URL and picture URL.\",\n args: {\n \"account-id\": schemaAccount,\n \"catalog-id\": { type: \"string\", description: \"Catalog id or meta_temp_* ref\", required: true },\n \"retailer-id\": { type: \"string\", description: \"Your own id for the product (SKU)\", required: true },\n ...productFieldSchema,\n file: { type: \"string\", description: \"JSON file with the whole payload\", required: false },\n },\n});\n\nconst productCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a product in a catalog. ${STAGED_NOTE}\nExample: baker ads meta catalogs products create --account-id act_123 --catalog-id meta_temp_… --retailer-id SKU-1 --name \"Solar panel\" --description \"400 W panel\" --price 199.00 --currency EUR --url https://shop.example/panel --image-url https://shop.example/panel.jpg`,\n },\n args: {\n \"account-id\": accountArg,\n \"catalog-id\": { type: \"string\", description: \"Catalog id, or meta_temp_* of a catalog this chat creates\" },\n \"retailer-id\": { type: \"string\", description: \"Your own id for the product (SKU) — what product sets filter on\" },\n ...productFieldArgs,\n file: { type: \"string\", description: \"JSON file with the whole payload\" },\n },\n run: async ({ args, rawArgs }) => {\n const payload = mergePayload(loadJsonFileArg(args.file), {\n catalog_id: args[\"catalog-id\"],\n retailer_id: args[\"retailer-id\"],\n ...productFieldsFromArgs(args as Args, rawArgs),\n });\n await stageOp({ kind: \"product.create\", accountId: await bareAccountId(args as Args), payload }, [\n \"Group products for an ad with `catalogs sets create --catalog-id <id> --retailer-id <sku> …`.\",\n ]);\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.products.update\",\n description: \"Stage changes to a product's fields (a price names its currency).\",\n args: {\n id: { type: \"positional\", description: \"Product id\", required: true },\n \"account-id\": schemaAccount,\n ...productFieldSchema,\n },\n});\n\nconst productUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Change a product's fields. ${STAGED_NOTE}\nExample: baker ads meta catalogs products update 39108967418750368 --account-id act_123 --price 179.00 --currency EUR --availability \"out of stock\"`,\n },\n args: {\n id: { type: \"positional\", description: \"Product id\", required: true },\n \"account-id\": accountArg,\n ...productFieldArgs,\n },\n run: async ({ args, rawArgs }) => {\n await stageOp({\n kind: \"product.update\",\n accountId: await bareAccountId(args as Args),\n target: requireTarget(args as Args, \"product\"),\n payload: productFieldsFromArgs(args as Args, rawArgs),\n });\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.products.delete\",\n description: \"Stage deleting a product from its catalog.\",\n args: { id: { type: \"positional\", description: \"Product id\", required: true }, \"account-id\": schemaAccount },\n});\n\nconst productDeleteCommand = defineCommand({\n meta: {\n name: \"delete\",\n description: `Delete a product from its catalog. ${STAGED_NOTE}\nExample: baker ads meta catalogs products delete 39108967418750368 --account-id act_123`,\n },\n args: { id: { type: \"positional\", description: \"Product id\", required: true }, \"account-id\": accountArg },\n run: async ({ args }) => {\n await stageOp({\n kind: \"product.update\",\n accountId: await bareAccountId(args as Args),\n target: requireTarget(args as Args, \"product\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\nconst productsCommand = defineCommand({\n meta: {\n name: \"products\",\n description: `A catalog's products.\n baker ads meta catalogs products --catalog-id <id> [--full] — list\n baker ads meta catalogs products create --catalog-id <id> --retailer-id SKU-1 --name … --price 19.99 --currency EUR …\n baker ads meta catalogs products update <id> --price 17.99 --currency EUR\n baker ads meta catalogs products delete <id>`,\n },\n subCommands: {\n list: productsListCommand,\n create: productCreateCommand,\n update: productUpdateCommand,\n delete: productDeleteCommand,\n },\n args: {\n \"catalog-id\": { type: \"string\", description: \"Catalog id\" },\n \"retailer-id\": { type: \"string\", description: \"Only the product with this retailer id\" },\n full: { type: \"boolean\", description: \"Every field, and Meta's errors on each product\" },\n output: outputArg,\n },\n default: \"list\",\n});\n\n// --- Product sets ---\n\n/** A set's rule: --filter JSON, or the products by retailer id. */\nexport function productSetFilterFromArgs(args: Args, rawArgs: readonly string[] | undefined): unknown {\n const retailerIds = repeatedValues(rawArgs, \"retailer-id\", args[\"retailer-id\"])\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter(Boolean);\n const filter = jsonArg(args.filter, \"filter\");\n if (filter && retailerIds.length > 0) failWriteValidation(\"pass --filter or --retailer-id, not both\");\n return filter ?? (retailerIds.length > 0 ? retailerIdFilter(retailerIds) : undefined);\n}\n\nconst setRuleArgs = {\n \"retailer-id\": {\n type: \"string\",\n description: \"A product in the set, by retailer id (repeatable, or comma-separated)\",\n },\n filter: {\n type: \"string\",\n description:\n 'Meta\\'s rule as JSON, e.g. \\'{\"and\":[{\"brand\":{\"eq\":\"Acme\"}},{\"price\":{\"lt\":5000}}]}\\' — operators: is_any, is_not_any, eq, neq, contains, not_contains, i_contains, i_not_contains, starts_with, lt, lte, gt, gte (a price in minor units)',\n },\n} as const;\n\nregisterSchema({\n command: \"ads.meta.catalogs.sets\",\n description: \"A catalog's product sets, with how many products each matches.\",\n args: {\n \"catalog-id\": { type: \"string\", description: \"Catalog id\", required: true },\n \"no-cache\": { type: \"boolean\", description: \"Bypass the cache\", required: false },\n output: schemaOutput,\n },\n});\n\nconst setsListCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"A catalog's product sets. Runs by default. Example: baker ads meta catalogs sets --catalog-id 1798573158016525\",\n },\n args: { \"catalog-id\": { type: \"string\", description: \"Catalog id\" }, \"no-cache\": NO_CACHE_ARG, output: outputArg },\n run: async ({ args }) => {\n try {\n const params: Record<string, string> = { \"catalog-id\": requireCatalogId(args as Args) };\n if (args[\"no-cache\"]) params[\"skip-cache\"] = \"true\";\n const rows = await apiGet<Row[]>(\"/api/ads/meta/product-sets\", params);\n emit(rows, args as Args, [\n \"An ad set shows one set (`adsets create --product-set-id <id>`); a catalog creative names it too (`creatives create --type catalog --product-set-id <id>`).\",\n ]);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.sets.create\",\n description:\n \"Stage a product set — the products an Advantage+ catalog ad or a collection shows — by retailer id or Meta's filter rule. Without either it holds the whole catalog.\",\n args: {\n \"account-id\": schemaAccount,\n \"catalog-id\": { type: \"string\", description: \"Catalog id or meta_temp_* ref\", required: true },\n name: { type: \"string\", description: \"Set name\", required: true },\n \"retailer-id\": { type: \"string\", description: \"Retailer id of a product (repeatable)\", required: false },\n filter: { type: \"string\", description: \"Meta's filter rule as JSON\", required: false },\n },\n});\n\nconst setCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a product set. ${STAGED_NOTE}\nExample: baker ads meta catalogs sets create --account-id act_123 --catalog-id meta_temp_… --name \"Panels\" --retailer-id SKU-1 --retailer-id SKU-2\nRule: --filter '{\"brand\":{\"eq\":\"Acme\"}}'. Without --retailer-id or --filter the set holds the whole catalog.`,\n },\n args: {\n \"account-id\": accountArg,\n \"catalog-id\": { type: \"string\", description: \"Catalog id, or meta_temp_* of a catalog this chat creates\" },\n name: { type: \"string\", description: \"Set name\" },\n ...setRuleArgs,\n },\n run: async ({ args, rawArgs }) => {\n await stageOp(\n {\n kind: \"productSet.create\",\n accountId: await bareAccountId(args as Args),\n payload: {\n catalog_id: args[\"catalog-id\"],\n name: args.name,\n filter: productSetFilterFromArgs(args as Args, rawArgs),\n },\n },\n [\n \"Advertise it: `adsets create --product-set-id <ref>` under a campaign with `--catalog-id`, then `creatives create --type catalog --product-set-id <ref>`.\",\n ],\n );\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.sets.update\",\n description: \"Stage a new name or a new rule for a product set (the whole rule is replaced).\",\n args: {\n id: { type: \"positional\", description: \"Product set id\", required: true },\n \"account-id\": schemaAccount,\n name: { type: \"string\", description: \"New name\", required: false },\n \"retailer-id\": { type: \"string\", description: \"Retailer id of a product (repeatable)\", required: false },\n filter: { type: \"string\", description: \"Meta's filter rule as JSON\", required: false },\n },\n});\n\nconst setUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Rename a product set or replace its rule. ${STAGED_NOTE}\nExample: baker ads meta catalogs sets update 1748674113031942 --account-id act_123 --retailer-id SKU-1 --retailer-id SKU-3`,\n },\n args: {\n id: { type: \"positional\", description: \"Product set id\", required: true },\n \"account-id\": accountArg,\n name: { type: \"string\", description: \"New name\" },\n ...setRuleArgs,\n },\n run: async ({ args, rawArgs }) => {\n await stageOp({\n kind: \"productSet.update\",\n accountId: await bareAccountId(args as Args),\n target: requireTarget(args as Args, \"product set\"),\n payload: { name: args.name, filter: productSetFilterFromArgs(args as Args, rawArgs) },\n });\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.sets.delete\",\n description:\n \"Stage deleting a product set. Delete or repoint the ad sets and creatives that show it in the same chat.\",\n args: { id: { type: \"positional\", description: \"Product set id\", required: true }, \"account-id\": schemaAccount },\n});\n\nconst setDeleteCommand = defineCommand({\n meta: {\n name: \"delete\",\n description: `Delete a product set — after the ads, ad sets and creatives this chat deletes. ${STAGED_NOTE}\nExample: baker ads meta catalogs sets delete 1748674113031942 --account-id act_123`,\n },\n args: { id: { type: \"positional\", description: \"Product set id\", required: true }, \"account-id\": accountArg },\n run: async ({ args }) => {\n await stageOp({\n kind: \"productSet.update\",\n accountId: await bareAccountId(args as Args),\n target: requireTarget(args as Args, \"product set\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\nconst setsCommand = defineCommand({\n meta: {\n name: \"sets\",\n description: `A catalog's product sets.\n baker ads meta catalogs sets --catalog-id <id> — list\n baker ads meta catalogs sets create --catalog-id <id> --name … --retailer-id SKU-1 [--filter '<json>']\n baker ads meta catalogs sets update <id> --name …\n baker ads meta catalogs sets delete <id>`,\n },\n subCommands: { list: setsListCommand, create: setCreateCommand, update: setUpdateCommand, delete: setDeleteCommand },\n args: { \"catalog-id\": { type: \"string\", description: \"Catalog id\" }, \"no-cache\": NO_CACHE_ARG, output: outputArg },\n default: \"list\",\n});\n\n// --- Feeds ---\n\nconst scheduleArgs = {\n url: { type: \"string\", description: \"https address of the feed file (CSV, TSV, XML) Meta fetches\" },\n interval: { type: \"string\", description: \"HOURLY, DAILY or WEEKLY\" },\n hour: { type: \"string\", description: \"Hour of day 0–23\" },\n day: { type: \"string\", description: \"Day for a WEEKLY schedule, e.g. MONDAY\" },\n} as const;\n\n/** A feed schedule from the flags, or nothing when no flag names one. */\nexport function feedScheduleFromArgs(args: Args): Record<string, unknown> | undefined {\n if (args.url === undefined && args.interval === undefined && args.hour === undefined && args.day === undefined) {\n return undefined;\n }\n return {\n url: args.url,\n interval: upper(args.interval) ?? \"DAILY\",\n hour: numberFlag(args.hour, \"--hour\"),\n day_of_week: upper(args.day),\n };\n}\n\nregisterSchema({\n command: \"ads.meta.catalogs.feeds\",\n description: \"A catalog's data feeds: each one's schedule and its last upload's errors and warnings.\",\n args: { \"catalog-id\": { type: \"string\", description: \"Catalog id\", required: true }, output: schemaOutput },\n});\n\nconst feedsListCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"A catalog's feeds. Runs by default. Example: baker ads meta catalogs feeds --catalog-id 1798573158016525\",\n },\n args: { \"catalog-id\": { type: \"string\", description: \"Catalog id\" }, output: outputArg },\n run: async ({ args }) => {\n try {\n emit(await contents(\"feeds\", args as Args), args as Args, []);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.feeds.create\",\n description:\n \"Stage a data feed in a catalog: a file Meta fetches on a schedule and replaces the catalog's products from. Without --url it waits for uploads.\",\n args: {\n \"account-id\": schemaAccount,\n \"catalog-id\": { type: \"string\", description: \"Catalog id or meta_temp_* ref\", required: true },\n name: { type: \"string\", description: \"Feed name\", required: true },\n url: { type: \"string\", description: \"Feed file address (https)\", required: false },\n interval: { type: \"string\", description: \"HOURLY, DAILY (default) or WEEKLY\", required: false },\n hour: { type: \"string\", description: \"Hour 0–23\", required: false },\n day: { type: \"string\", description: \"Day for WEEKLY\", required: false },\n },\n});\n\nconst feedCreateCommand = defineCommand({\n meta: {\n name: \"create\",\n description: `Stage a scheduled data feed in a catalog. ${STAGED_NOTE}\nExample: baker ads meta catalogs feeds create --account-id act_123 --catalog-id 1798573158016525 --name \"Daily feed\" --url https://shop.example/feed.csv --interval DAILY --hour 3`,\n },\n args: {\n \"account-id\": accountArg,\n \"catalog-id\": { type: \"string\", description: \"Catalog id, or meta_temp_* of a catalog this chat creates\" },\n name: { type: \"string\", description: \"Feed name\" },\n ...scheduleArgs,\n },\n run: async ({ args }) => {\n await stageOp({\n kind: \"productFeed.create\",\n accountId: await bareAccountId(args as Args),\n payload: { catalog_id: args[\"catalog-id\"], name: args.name, schedule: feedScheduleFromArgs(args as Args) },\n });\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.feeds.update\",\n description: \"Stage a new name or schedule for a feed (the whole schedule is replaced).\",\n args: {\n id: { type: \"positional\", description: \"Feed id\", required: true },\n \"account-id\": schemaAccount,\n name: { type: \"string\", description: \"New name\", required: false },\n url: { type: \"string\", description: \"Feed file address (https)\", required: false },\n interval: { type: \"string\", description: \"HOURLY, DAILY or WEEKLY\", required: false },\n hour: { type: \"string\", description: \"Hour 0–23\", required: false },\n day: { type: \"string\", description: \"Day for WEEKLY\", required: false },\n },\n});\n\nconst feedUpdateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: `Rename a feed or replace its schedule. ${STAGED_NOTE}\nExample: baker ads meta catalogs feeds update 1157910959893469 --account-id act_123 --url https://shop.example/feed.csv --interval WEEKLY --day MONDAY --hour 4`,\n },\n args: {\n id: { type: \"positional\", description: \"Feed id\", required: true },\n \"account-id\": accountArg,\n name: { type: \"string\", description: \"New name\" },\n ...scheduleArgs,\n },\n run: async ({ args }) => {\n await stageOp({\n kind: \"productFeed.update\",\n accountId: await bareAccountId(args as Args),\n target: requireTarget(args as Args, \"feed\"),\n payload: { name: args.name, schedule: feedScheduleFromArgs(args as Args) },\n });\n },\n});\n\nregisterSchema({\n command: \"ads.meta.catalogs.feeds.delete\",\n description: \"Stage deleting a feed. Its products stay in the catalog.\",\n args: { id: { type: \"positional\", description: \"Feed id\", required: true }, \"account-id\": schemaAccount },\n});\n\nconst feedDeleteCommand = defineCommand({\n meta: {\n name: \"delete\",\n description: `Delete a data feed; its products stay in the catalog. ${STAGED_NOTE}\nExample: baker ads meta catalogs feeds delete 1157910959893469 --account-id act_123`,\n },\n args: { id: { type: \"positional\", description: \"Feed id\", required: true }, \"account-id\": accountArg },\n run: async ({ args }) => {\n await stageOp({\n kind: \"productFeed.update\",\n accountId: await bareAccountId(args as Args),\n target: requireTarget(args as Args, \"feed\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\nconst feedsCommand = defineCommand({\n meta: {\n name: \"feeds\",\n description: `A catalog's data feeds.\n baker ads meta catalogs feeds --catalog-id <id> — list, with the last upload's errors\n baker ads meta catalogs feeds create --catalog-id <id> --name … --url https://… --interval DAILY\n baker ads meta catalogs feeds update <id> --interval WEEKLY --day MONDAY --url https://…\n baker ads meta catalogs feeds delete <id>`,\n },\n subCommands: {\n list: feedsListCommand,\n create: feedCreateCommand,\n update: feedUpdateCommand,\n delete: feedDeleteCommand,\n },\n args: { \"catalog-id\": { type: \"string\", description: \"Catalog id\" }, output: outputArg },\n default: \"list\",\n});\n\n// --- Diagnostics ---\n\nregisterSchema({\n command: \"ads.meta.catalogs.diagnostics\",\n description:\n \"Meta's diagnostics for a catalog — product problems (missing fields, rejected pictures) and event-matching issues, grouped by type.\",\n args: { \"catalog-id\": { type: \"string\", description: \"Catalog id\", required: true }, output: schemaOutput },\n});\n\nconst diagnosticsCommand = defineCommand({\n meta: {\n name: \"diagnostics\",\n description:\n \"What Meta says is wrong with a catalog. Example: baker ads meta catalogs diagnostics --catalog-id 1798573158016525\",\n },\n args: { \"catalog-id\": { type: \"string\", description: \"Catalog id\" }, output: outputArg },\n run: async ({ args }) => {\n try {\n const rows = await contents(\"diagnostics\", args as Args);\n emit(rows, args as Args, rows.length === 0 ? [\"Meta reports no problems with this catalog.\"] : []);\n } catch (err) {\n handleMetaError(err);\n }\n },\n});\n\nexport const catalogsCommand = defineCommand({\n meta: {\n name: \"catalogs\",\n description: `Product catalogs — what Advantage+ catalog and collection ads show. Reading is open; changing needs the Catalog permission for Meta, and Baker changes only catalogs the ad account's own Business owns.\n baker ads meta catalogs --business-id <id> — catalogs; --catalog-id <id> for its product sets\n baker ads meta catalogs create --name … --pixel <id> | update <id> --name … --pixel <id> | delete <id>\n baker ads meta catalogs products … | sets … | feeds … | diagnostics --catalog-id <id>`,\n },\n subCommands: {\n list: catalogsListCommand,\n create: catalogCreateCommand,\n update: catalogUpdateCommand,\n delete: catalogDeleteCommand,\n products: productsCommand,\n sets: setsCommand,\n feeds: feedsCommand,\n diagnostics: diagnosticsCommand,\n },\n args: {\n \"business-id\": { type: \"string\", description: \"Business ID\" },\n \"catalog-id\": { type: \"string\", description: \"Catalog id\" },\n \"no-cache\": NO_CACHE_ARG,\n output: outputArg,\n },\n default: \"list\",\n});\n"],"mappings":"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","names":["rows"]}
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  handleMetaError,
6
6
  resolveAccountIdArg
7
- } from "./chunk-HPAGYPAF.js";
7
+ } from "./chunk-BN4TDL5L.js";
8
8
  import {
9
9
  repeatedValues
10
10
  } from "./chunk-ERSX3MKH.js";
@@ -28,8 +28,8 @@ import {
28
28
 
29
29
  // src/commands/ads/meta/write-shared.ts
30
30
  import { readFileSync } from "fs";
31
- function bareAccountId(args) {
32
- return resolveAccountIdArg(args).replace(/^act_/, "");
31
+ async function bareAccountId(args) {
32
+ return (await resolveAccountIdArg(args)).replace(/^act_/, "");
33
33
  }
34
34
  function failWriteValidation(message) {
35
35
  writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
@@ -204,4 +204,4 @@ export {
204
204
  stageOps,
205
205
  stageStatusChange
206
206
  };
207
- //# sourceMappingURL=chunk-OEJNZSJG.js.map
207
+ //# sourceMappingURL=chunk-4XXA4WCS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/ads/meta/write-shared.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { type MetaDraftStageResponse, metaDraftOpInputSchema } from \"@baker/api/ads-meta\";\nimport { apiPost } from \"../../../client.ts\";\nimport { requireChatId } from \"../../../env.ts\";\nimport { repeatedValues } from \"../../../lib/repeatedFlags.ts\";\nimport { capabilityFix } from \"../../capabilities/fix.ts\";\nimport { booleanWordPositionalError } from \"../boolean-word-positional.ts\";\nimport { adCopyHints } from \"../copy-hints.ts\";\nimport { withHints } from \"../hints.ts\";\nimport { writeJsonEnvelope } from \"../output.ts\";\nimport { handleMetaError, resolveAccountIdArg } from \"./shared.ts\";\n\n/**\n * Shared plumbing for the staged Meta write commands. Writes NEVER hit Meta\n * directly: every command stages an op against this chat's draft\n * (`/api/ads/meta/draft/stage`), the dashboard shows it as a pending Meta\n * change, and it applies when the chat is published.\n */\n\n/** Backend account ids are bare numeric — strip the `act_` prefix resolveAccountIdArg adds. */\nexport async function bareAccountId(args: Record<string, unknown>): Promise<string> {\n return (await resolveAccountIdArg(args)).replace(/^act_/, \"\");\n}\n\nexport function failWriteValidation(message: string): never {\n writeJsonEnvelope({ ok: false, error: { code: \"VALIDATION_ERROR\", message } });\n process.exit(1);\n}\n\n/** Deleting is permanent, so it only stages through `delete`, whose description carries that warning. */\nexport function refuseDeleteByUpdate(payload: Record<string, unknown>, group: \"campaigns\" | \"adsets\" | \"ads\"): void {\n if (payload.status === \"DELETED\") {\n failWriteValidation(\n `update does not delete — deleting is permanent. Use \\`baker ads meta ${group} delete <id>\\` if the user asked to delete; otherwise pause or archive.`,\n );\n }\n}\n\n/**\n * `--file`: a JSON file path, or the JSON itself when it starts with `{` — the shape Google's\n * `--file` already takes and the one an agent writes first for a short payload (a customer list of\n * a few people).\n */\nexport function loadJsonFileArg(path: unknown): Record<string, unknown> {\n if (typeof path !== \"string\" || path.length === 0) {\n return {};\n }\n const inline = /^\\s*\\{/.test(path);\n const source = inline ? \"inline JSON\" : path;\n try {\n const parsed = JSON.parse(inline ? path : readFileSync(path, \"utf8\")) as unknown;\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n failWriteValidation(`${source} must contain a JSON object`);\n }\n return parsed as Record<string, unknown>;\n } catch (err) {\n if (err instanceof SyntaxError) {\n failWriteValidation(`${source} is not valid JSON: ${err.message}`);\n }\n throw err;\n }\n}\n\n/** Flags override file keys — the file is the base, flags are the overrides. */\nexport function mergePayload(file: Record<string, unknown>, flags: Record<string, unknown>): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...file };\n for (const [key, value] of Object.entries(flags)) {\n if (value !== undefined) {\n merged[key] = value;\n }\n }\n return merged;\n}\n\nexport function parseMoneyFlag(\n amount: unknown,\n currency: unknown,\n flag: string,\n): { amount: string; currencyCode?: string } | undefined {\n if (amount === undefined || amount === null || amount === \"\") {\n return undefined;\n }\n if (currency === undefined || currency === null || currency === \"\") {\n // Meta ad accounts are single-currency — the backend fills it in.\n return { amount: String(amount) };\n }\n if (typeof currency !== \"string\" || currency.length !== 3) {\n failWriteValidation(`${flag} got an invalid --currency (expected a 3-letter code like USD)`);\n }\n return { amount: String(amount), currencyCode: currency.toUpperCase() };\n}\n\n/** Accepts ISO dates (2026-07-10), ISO datetimes, or epoch millis. */\nexport function parseDateFlag(value: unknown, flag: string): number | undefined {\n if (value === undefined || value === null || value === \"\") {\n return undefined;\n }\n const raw = String(value);\n if (/^\\d{10,}$/.test(raw)) {\n return Number(raw);\n }\n const parsed = Date.parse(raw);\n if (Number.isNaN(parsed)) {\n failWriteValidation(`${flag} must be an ISO date (2026-07-10) or epoch milliseconds`);\n }\n return parsed;\n}\n\n/** Split a comma-separated flag into a trimmed, non-empty array. */\nexport function listFlag(value: unknown): string[] | undefined {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n return undefined;\n }\n const items = value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n return items.length > 0 ? items : undefined;\n}\n\n/**\n * A list flag that may be repeated as well as comma-separated\n * (`--countries ES,FR --countries DE`). citty keeps only a repeated flag's last\n * value, so the values are read from the command line (`repeatedValues`).\n */\nexport function repeatedListFlag(\n rawArgs: readonly string[] | undefined,\n flag: string,\n parsed: unknown,\n): string[] | undefined {\n const items = repeatedValues(rawArgs, flag, parsed)\n .flatMap((value) => value.split(\",\"))\n .map((item) => item.trim())\n .filter(Boolean);\n return items.length > 0 ? items : undefined;\n}\n\nexport function upper(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value.toUpperCase() : undefined;\n}\n\nexport function numberFlag(value: unknown, flag: string): number | undefined {\n if (value === undefined || value === null || value === \"\") {\n return undefined;\n }\n const n = Number(value);\n if (!Number.isFinite(n)) {\n failWriteValidation(`${flag} must be a number`);\n }\n return n;\n}\n\n/**\n * Accepts whichever positional the command declared (`id`, `target`, `ref`) or the raw positional.\n *\n * `--flag false` is refused first: citty turns it into the flag set to TRUE plus a stray positional,\n * so on `campaigns duplicate 6123 --replace false` the copy stages AND the live original is staged\n * for pause — the opposite of what was typed, with an \"ok\" receipt. This is the only place on this\n * surface that reads positionals, and every target-taking command goes through it.\n */\nexport function requireTarget(args: Record<string, unknown>, entity: string): string {\n const inverted = booleanWordPositionalError(args, entity);\n if (inverted !== undefined) {\n failWriteValidation(inverted);\n }\n const positional = Array.isArray(args._) ? args._[0] : undefined;\n const target = args.id ?? args.target ?? args.ref ?? positional;\n if (typeof target !== \"string\" || target.length === 0) {\n failWriteValidation(`pass the ${entity} id as the positional argument`);\n }\n return target;\n}\n\ninterface StageEnvelope extends Record<string, unknown> {\n ok: true;\n data: MetaDraftStageResponse;\n}\n\n/**\n * Preflight-validates the op against the shared `@baker/api/ads-meta` contract\n * (same schema the backend enforces), then stages it. Prints the staged\n * envelope — ref, mode (always `live`: publishing reaches the real ad account),\n * summary, warnings.\n */\n/** The op parsed against the shared contract, or the validation envelope printed and the process ended. */\nfunction preflightOp(raw: Record<string, unknown>) {\n const preflight = metaDraftOpInputSchema.safeParse(raw);\n if (!preflight.success) {\n const fields = preflight.error.issues.map((issue) => ({ path: issue.path.join(\".\"), message: issue.message }));\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: fields.map((field) => (field.path ? `${field.path}: ${field.message}` : field.message)).join(\"; \"),\n fields,\n fix: capabilityFix(\"meta-ads\"),\n },\n });\n process.exit(1);\n }\n return preflight.data;\n}\n\nexport async function stageOp(raw: Record<string, unknown>, extraHints: readonly string[] = []): Promise<void> {\n const op = preflightOp(raw);\n try {\n const chatId = requireChatId();\n const response = await apiPost<StageEnvelope>(\"/api/ads/meta/draft/stage\", { chatId, op });\n const copyHints = await adCopyHints(op);\n writeJsonEnvelope(withHints(response, [...copyHints, ...extraHints]));\n } catch (err) {\n handleMetaError(err);\n }\n}\n\n/**\n * Stage several ops as one command and print one envelope: each staged op's\n * receipt, in order. Stops at the first refusal, which names the op it was —\n * the ones before it stay staged, and the envelope says which.\n */\nexport async function stageOps(raws: readonly Record<string, unknown>[]): Promise<void> {\n const ops = raws.map(preflightOp);\n const chatId = requireChatId();\n const staged: MetaDraftStageResponse[] = [];\n for (const op of ops) {\n try {\n const response = await apiPost<StageEnvelope>(\"/api/ads/meta/draft/stage\", { chatId, op });\n staged.push(response.data);\n } catch (err) {\n if (staged.length > 0) {\n process.stderr.write(`staged before the refusal: ${staged.map((entry) => entry.ref).join(\", \")}\\n`);\n }\n handleMetaError(err);\n }\n }\n writeJsonEnvelope({ ok: true, data: staged });\n}\n\nexport async function stageStatusChange(input: {\n kind: \"campaign.update\" | \"adSet.update\" | \"adCreative.update\" | \"ad.update\" | \"customAudience.update\";\n accountId: string;\n target: string;\n status: \"ACTIVE\" | \"PAUSED\" | \"ARCHIVED\" | \"DELETED\";\n}): Promise<void> {\n await stageOp({\n kind: input.kind,\n accountId: input.accountId,\n target: input.target,\n payload: { status: input.status },\n });\n}\n"],"mappings":"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","names":[]}
@@ -2,6 +2,8 @@ import {
2
2
  termsRefusalFix
3
3
  } from "./chunk-QALAJNBG.js";
4
4
  import {
5
+ cacheGet,
6
+ cacheSet,
5
7
  handleConnectionError,
6
8
  isOrganizationReadRefusal,
7
9
  needsConnectionFix,
@@ -9,7 +11,8 @@ import {
9
11
  writeJsonEnvelope
10
12
  } from "./chunk-HPDGVK6R.js";
11
13
  import {
12
- ApiError
14
+ ApiError,
15
+ apiGet
13
16
  } from "./chunk-B4UVJCJ4.js";
14
17
  import {
15
18
  getEnv
@@ -93,30 +96,69 @@ function handleMetaError(err) {
93
96
  process.exit(1);
94
97
  }
95
98
  var ACCOUNT_ID_RE = /^(act_)?[0-9]+$/;
96
- function resolveAccountIdArg(args) {
99
+ var CONNECTED_ACCOUNTS_TTL_MS = 60 * 60 * 1e3;
100
+ function invalidAccountId(id) {
101
+ writeAdsJson({
102
+ ok: false,
103
+ error: {
104
+ code: "INVALID_ACCOUNT_ID",
105
+ message: `Invalid account ID "${id}". Expected numeric ID, optionally prefixed with "act_".`
106
+ }
107
+ });
108
+ process.exit(1);
109
+ }
110
+ function actId(id) {
111
+ return id.startsWith("act_") ? id : `act_${id}`;
112
+ }
113
+ async function connectedMetaAccounts(useCache) {
114
+ if (useCache) {
115
+ const cached = cacheGet("meta-accounts", "list");
116
+ if (cached) return cached.data;
117
+ }
118
+ const accounts = await apiGet(
119
+ "/api/ads/meta/accounts",
120
+ useCache ? void 0 : { "skip-cache": "true" }
121
+ );
122
+ if (useCache && accounts.length > 0) cacheSet("meta-accounts", "list", accounts, CONNECTED_ACCOUNTS_TTL_MS);
123
+ return accounts;
124
+ }
125
+ async function resolveAccountIdArg(args) {
97
126
  const fromArgs = args["account-id"];
98
- const id = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;
99
- if (!id) {
100
- writeAdsJson({
101
- ok: false,
102
- error: {
103
- code: "MISSING_ACCOUNT_ID",
104
- message: "Pass --account-id or set BAKER_META_AD_ACCOUNT_ID. Run `baker ads meta accounts` to find IDs."
105
- }
106
- });
107
- process.exit(1);
127
+ const explicit = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;
128
+ if (explicit) {
129
+ if (!ACCOUNT_ID_RE.test(explicit)) invalidAccountId(explicit);
130
+ return actId(explicit);
108
131
  }
109
- if (!ACCOUNT_ID_RE.test(id)) {
110
- writeAdsJson({
111
- ok: false,
112
- error: {
113
- code: "INVALID_ACCOUNT_ID",
114
- message: `Invalid account ID "${id}". Expected numeric ID, optionally prefixed with "act_".`
115
- }
116
- });
117
- process.exit(1);
132
+ let accounts;
133
+ try {
134
+ accounts = await connectedMetaAccounts(!args["no-cache"]);
135
+ } catch (err) {
136
+ handleMetaError(err);
118
137
  }
119
- return id.startsWith("act_") ? id : `act_${id}`;
138
+ const ids = accounts.flatMap((account) => {
139
+ const id = account.externalId ?? account.id;
140
+ return id && ACCOUNT_ID_RE.test(id) ? [{ id: actId(id), name: account.name }] : [];
141
+ });
142
+ const [single] = ids;
143
+ if (ids.length === 1 && single) {
144
+ process.stderr.write(`Using account "${single.name ?? single.id}" (${single.id})
145
+ `);
146
+ return single.id;
147
+ }
148
+ const listed = ids.map((account) => account.name ? `${account.id} (${account.name})` : account.id).join("; ");
149
+ writeAdsJson({
150
+ ok: false,
151
+ error: {
152
+ code: "MISSING_ACCOUNT_ID",
153
+ message: ids.length === 0 ? "This company has no Meta ad account selected, so there is no account to default to." : `This company connected ${ids.length} Meta ad accounts, so pass --account-id to name one: ${listed}.`,
154
+ fix: {
155
+ action: "reject",
156
+ explanation: ids.length === 0 ? "Ask the user to select a Meta ad account for this company in Baker's Meta connection, or pass --account-id act_<id> for one the login reaches (`baker ads meta accounts --available`)." : `Re-run with --account-id set to one of: ${listed}. A question about the whole business covers all ${ids.length}.`
157
+ },
158
+ retryable: false
159
+ }
160
+ });
161
+ process.exit(1);
120
162
  }
121
163
  function getDateRange(args) {
122
164
  const datePreset = args["date-preset"];
@@ -172,4 +214,4 @@ export {
172
214
  resolveEffectiveStatus,
173
215
  statusFilterHints
174
216
  };
175
- //# sourceMappingURL=chunk-HPAGYPAF.js.map
217
+ //# sourceMappingURL=chunk-BN4TDL5L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../api/src/ads-meta/permissionGates.ts","../src/commands/ads/meta/shared.ts"],"sourcesContent":["/**\n * The refusals Baker writes for Meta work that needs a permission the baseline\n * connection does not ask for — managing catalogs (`catalog_management`) and\n * posting to a Facebook Page (`pages_manage_posts`). Shared verbatim by the\n * backend that throws them and the CLI that explains them, for the same reason\n * as `leadAds.ts`: these name their own cause and remedy, so the CLI must not\n * append Meta's ambiguous \"maybe reconnect, maybe an unassigned asset\" advice.\n */\n\nexport type MetaPermissionGate = \"catalog\" | \"pagePosts\";\n\n/** Everything a person or the agent can see about one per-company Meta permission. */\nexport interface MetaPermissionState {\n /** A Baker admin switched it on for this company, so the consent screen asks for it. */\n enabled: boolean;\n /** The current Meta connection holds it. */\n granted: boolean;\n /** Switched on, but the connection predates it — reconnecting Meta is the fix. */\n reconnectNeeded: boolean;\n}\n\nexport type MetaPermissionStates = Record<\"leadAds\" | MetaPermissionGate, MetaPermissionState>;\n\nexport const META_PERMISSION_NOT_ENABLED_MESSAGE: Record<MetaPermissionGate, string> = {\n catalog:\n \"Catalog changes need the Catalog permission for Meta — ask a Baker admin to turn it on, then reconnect Meta. \" +\n \"Everything else on Meta keeps working: tell the user, and carry on with the rest of the job.\",\n pagePosts:\n \"Facebook Page posts need the Page posts permission for Meta — ask a Baker admin to turn it on, then reconnect \" +\n \"Meta. Everything else on Meta keeps working: tell the user, and carry on with the rest of the job.\",\n};\n\nexport const META_PERMISSION_RECONNECT_MESSAGE: Record<MetaPermissionGate, string> = {\n catalog:\n \"Catalog changes need the Catalog permission for Meta. It is turned on for this company, but this Meta \" +\n \"connection was made before, so it does not hold it — ask the user to reconnect Meta in the dashboard, then \" +\n \"try again. Everything else on Meta keeps working meanwhile.\",\n pagePosts:\n \"Facebook Page posts need the Page posts permission for Meta. It is turned on for this company, but this Meta \" +\n \"connection was made before, so it does not hold it — ask the user to reconnect Meta in the dashboard, then \" +\n \"try again. Everything else on Meta keeps working meanwhile.\",\n};\n\n/**\n * Work that needs a Meta permission Baker's connection does not ask for at all\n * (no switch turns it on): reading and moderating comments on ads\n * (`pages_read_user_content`, `pages_manage_engagement`) and listing an\n * Instagram account's posts (`instagram_basic`). Live on v26.0 (2026-10-15)\n * Meta refused both with code 10.\n */\nexport const META_UNREQUESTED_PERMISSION_MESSAGE = {\n comments:\n \"Reading and moderating comments on ads needs Meta permissions Baker's Meta connection does not ask for yet \" +\n \"(reading people's comments and managing them on the Page). Tell the user that comment moderation happens in \" +\n \"Meta Business Suite for now, and carry on with the rest of the job.\",\n instagramMedia:\n \"Listing an Instagram account's posts needs a Meta permission Baker's Meta connection does not ask for yet. \" +\n \"Ask the user for the post's link or id instead, or boost it from Meta Business Suite, and carry on.\",\n} as const;\n\nconst META_PAGE_ADS_PERMISSION_REMEDY =\n \"A Baker admin turns it on with the lead ads switch for this company; then the user reconnects Meta in the dashboard. \" +\n \"Tell the user, and carry on with the rest of the job.\";\n\n/**\n * Click-to-message ads and Instant Experiences need Meta's Page ads permission\n * (`pages_manage_ads`), which only the lead ads switch adds to the consent\n * screen. `work` names what was refused (\"Click-to-message ads\").\n */\nexport function metaPageAdsPermissionMessage(work: string): string {\n return `${work} need Meta's Page ads permission, and this Meta connection does not have it. ${META_PAGE_ADS_PERMISSION_REMEDY}`;\n}\n\n/**\n * Whether a `FORBIDDEN` message carries one of these refusals. `includes`, not\n * equality: a stage-time refusal may lead with what the op was trying to do.\n */\nexport function isMetaPermissionGateRefusal(message: string): boolean {\n return [\n ...Object.values(META_PERMISSION_NOT_ENABLED_MESSAGE),\n ...Object.values(META_PERMISSION_RECONNECT_MESSAGE),\n ...Object.values(META_UNREQUESTED_PERMISSION_MESSAGE),\n META_PAGE_ADS_PERMISSION_REMEDY,\n ].some((refusal) => message.includes(refusal));\n}\n","import { isMetaPermissionGateRefusal } from \"@baker/api/ads-meta/permissionGates\";\nimport { ApiError, apiGet } from \"../../../client.ts\";\nimport { getEnv } from \"../../../env.ts\";\nimport { handleConnectionError, isOrganizationReadRefusal, needsConnectionFix } from \"../../../error-handler.ts\";\nimport { cacheGet, cacheSet } from \"../cache.ts\";\nimport { writeAdsJson, writeJsonEnvelope } from \"../output.ts\";\nimport { termsRefusalFix } from \"../terms-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 // Baker's own refusal already names the switch or the reconnect; Meta's\n // two-cause advice under it would contradict it.\n if (isMetaPermissionGateRefusal(message)) {\n return { action: \"reject\", explanation: message };\n }\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 terms = termsRefusalFix(err.code, err.message);\n if (terms) {\n writeJsonEnvelope({\n ok: false,\n error: { code: terms.code, message: err.message, fix: terms.fix, retryable: false },\n });\n process.exit(1);\n }\n const envelope: AdsErrorEnvelope = {\n ok: false,\n error: {\n code: err.code,\n message: err.message,\n fix:\n err.code === \"FORBIDDEN\" && !isOrganizationReadRefusal(err.message)\n ? metaForbiddenFix(err.message)\n : { 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]+$/;\nconst CONNECTED_ACCOUNTS_TTL_MS = 60 * 60 * 1000;\n\ninterface ConnectedMetaAccount {\n externalId?: string;\n id?: string;\n name?: string;\n}\n\nfunction invalidAccountId(id: string): never {\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\nfunction actId(id: string): string {\n return id.startsWith(\"act_\") ? id : `act_${id}`;\n}\n\nasync function connectedMetaAccounts(useCache: boolean): Promise<ConnectedMetaAccount[]> {\n if (useCache) {\n const cached = cacheGet<ConnectedMetaAccount[]>(\"meta-accounts\", \"list\");\n if (cached) return cached.data;\n }\n const accounts = await apiGet<ConnectedMetaAccount[]>(\n \"/api/ads/meta/accounts\",\n useCache ? undefined : { \"skip-cache\": \"true\" },\n );\n // An empty list is never kept: the refusal asks the user to select an account, and the retry must see it.\n if (useCache && accounts.length > 0) cacheSet(\"meta-accounts\", \"list\", accounts, CONNECTED_ACCOUNTS_TTL_MS);\n return accounts;\n}\n\n/**\n * The Meta ad account a command works on: `--account-id`, then\n * `BAKER_META_AD_ACCOUNT_ID`, then the company's only connected account — the\n * default `baker ads meta accounts` promises. With several connected, nothing is\n * picked: the refusal lists them so the next call can name one.\n */\nexport async function resolveAccountIdArg(args: Record<string, unknown>): Promise<string> {\n const fromArgs = args[\"account-id\"] as string | undefined;\n const explicit = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;\n if (explicit) {\n if (!ACCOUNT_ID_RE.test(explicit)) invalidAccountId(explicit);\n return actId(explicit);\n }\n let accounts: ConnectedMetaAccount[];\n try {\n accounts = await connectedMetaAccounts(!args[\"no-cache\"]);\n } catch (err) {\n handleMetaError(err);\n }\n const ids = accounts.flatMap((account) => {\n const id = account.externalId ?? account.id;\n return id && ACCOUNT_ID_RE.test(id) ? [{ id: actId(id), name: account.name }] : [];\n });\n const [single] = ids;\n if (ids.length === 1 && single) {\n process.stderr.write(`Using account \"${single.name ?? single.id}\" (${single.id})\\n`);\n return single.id;\n }\n const listed = ids.map((account) => (account.name ? `${account.id} (${account.name})` : account.id)).join(\"; \");\n writeAdsJson({\n ok: false,\n error: {\n code: \"MISSING_ACCOUNT_ID\",\n message:\n ids.length === 0\n ? \"This company has no Meta ad account selected, so there is no account to default to.\"\n : `This company connected ${ids.length} Meta ad accounts, so pass --account-id to name one: ${listed}.`,\n fix: {\n action: \"reject\",\n explanation:\n ids.length === 0\n ? \"Ask the user to select a Meta ad account for this company in Baker's Meta connection, or pass --account-id act_<id> for one the login reaches (`baker ads meta accounts --available`).\"\n : `Re-run with --account-id set to one of: ${listed}. A question about the whole business covers all ${ids.length}.`,\n },\n retryable: false,\n },\n });\n process.exit(1);\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":[]}
@@ -5,7 +5,7 @@ import {
5
5
  requireTarget,
6
6
  stageOp,
7
7
  stageOps
8
- } from "./chunk-OEJNZSJG.js";
8
+ } from "./chunk-4XXA4WCS.js";
9
9
  import {
10
10
  repeatedValues
11
11
  } from "./chunk-ERSX3MKH.js";
@@ -46,7 +46,7 @@ var creativesDeleteCommand = command({
46
46
  run: async (args) => {
47
47
  await stageOp({
48
48
  kind: "adCreative.update",
49
- accountId: bareAccountId(args),
49
+ accountId: await bareAccountId(args),
50
50
  target: requireTarget(args, "creative"),
51
51
  payload: { status: "DELETED" }
52
52
  });
@@ -68,7 +68,7 @@ var mediaDeleteCommand = command({
68
68
  if (imageHash === void 0 === (videoId === void 0)) {
69
69
  failWriteValidation("pass --image-hash (from `baker ads meta images`) or --video-id \u2014 one of them");
70
70
  }
71
- await stageOp({ kind: "media.delete", accountId: bareAccountId(args), payload: { imageHash, videoId } });
71
+ await stageOp({ kind: "media.delete", accountId: await bareAccountId(args), payload: { imageHash, videoId } });
72
72
  }
73
73
  });
74
74
  var customConversionsUpdateCommand = command({
@@ -93,7 +93,7 @@ var customConversionsUpdateCommand = command({
93
93
  );
94
94
  await stageOp({
95
95
  kind: "customConversion.update",
96
- accountId: bareAccountId(args),
96
+ accountId: await bareAccountId(args),
97
97
  target: requireTarget(args, "custom conversion"),
98
98
  payload
99
99
  });
@@ -108,7 +108,7 @@ var customConversionsDeleteCommand = command({
108
108
  run: async (args) => {
109
109
  await stageOp({
110
110
  kind: "customConversion.update",
111
- accountId: bareAccountId(args),
111
+ accountId: await bareAccountId(args),
112
112
  target: requireTarget(args, "custom conversion"),
113
113
  payload: { status: "DELETED" }
114
114
  });
@@ -121,7 +121,7 @@ var labelsCreateCommand = command({
121
121
  schemaDescription: "Stage a new Meta ad label (created at publish). Returns a meta_temp_* ref `labels attach` takes.",
122
122
  args: { "account-id": accountArg, name: { type: "string", description: "Label name" } },
123
123
  run: async (args) => {
124
- await stageOp({ kind: "adLabel.create", accountId: bareAccountId(args), payload: { name: args.name } });
124
+ await stageOp({ kind: "adLabel.create", accountId: await bareAccountId(args), payload: { name: args.name } });
125
125
  }
126
126
  });
127
127
  var labelsRenameCommand = command({
@@ -133,7 +133,7 @@ var labelsRenameCommand = command({
133
133
  run: async (args) => {
134
134
  await stageOp({
135
135
  kind: "adLabel.update",
136
- accountId: bareAccountId(args),
136
+ accountId: await bareAccountId(args),
137
137
  target: requireTarget(args, "label"),
138
138
  payload: { name: args.name }
139
139
  });
@@ -148,7 +148,7 @@ var labelsDeleteCommand = command({
148
148
  run: async (args) => {
149
149
  await stageOp({
150
150
  kind: "adLabel.update",
151
- accountId: bareAccountId(args),
151
+ accountId: await bareAccountId(args),
152
152
  target: requireTarget(args, "label"),
153
153
  payload: { status: "DELETED" }
154
154
  });
@@ -173,7 +173,7 @@ function idsOf(rawArgs, flag, parsed) {
173
173
  return repeatedValues(rawArgs, flag, parsed).flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
174
174
  }
175
175
  async function stageLabelChange(verb, args, rawArgs) {
176
- const accountId = bareAccountId(args);
176
+ const accountId = await bareAccountId(args);
177
177
  const label = requireTarget(args, "label");
178
178
  const targets = LABELLED.flatMap(([flag, kind]) => idsOf(rawArgs, flag, args[flag]).map((id) => ({ kind, id })));
179
179
  if (targets.length === 0) {
@@ -216,4 +216,4 @@ export {
216
216
  labelsAttachCommand,
217
217
  labelsDetachCommand
218
218
  };
219
- //# sourceMappingURL=chunk-5LN7GWRE.js.map
219
+ //# sourceMappingURL=chunk-GEFZVG4P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/ads/meta/asset-writes.ts"],"sourcesContent":["import { type ArgsDef, type CommandDef, defineCommand } from \"citty\";\nimport { repeatedValues } from \"../../../lib/repeatedFlags.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { bareAccountId, failWriteValidation, numberFlag, requireTarget, stageOp, stageOps } from \"./write-shared.ts\";\n\n/**\n * Staged writes on the account's own assets: deleting a creative or an image,\n * changing or deleting a Custom Conversion, and ad labels — creating, renaming,\n * deleting them, and filing campaigns, ad sets, ads and creatives under them.\n * Nothing reaches Meta until the chat publishes.\n */\n\nconst STAGED_NOTE = \"Staged until publish — review with `baker ads meta draft`.\";\nconst accountArg = { type: \"string\", description: \"Meta ad account ID (act_123)\" } as const;\nconst schemaId = (what: string) => ({ type: \"positional\", description: what, required: true });\n\nexport function command(input: {\n schema: string;\n name: string;\n description: string;\n schemaDescription: string;\n args: Record<string, { type: string; description: string; required?: boolean }>;\n run: (args: Record<string, unknown>, rawArgs: readonly string[] | undefined) => Promise<void>;\n}): CommandDef<ArgsDef> {\n registerSchema({\n command: input.schema,\n description: input.schemaDescription,\n args: Object.fromEntries(\n Object.entries(input.args).map(([key, arg]) => [\n key,\n { type: arg.type, description: arg.description, required: arg.required === true },\n ]),\n ),\n });\n return defineCommand<ArgsDef>({\n meta: { name: input.name, description: `${input.description} ${STAGED_NOTE}` },\n args: input.args as ArgsDef,\n run: async ({ args, rawArgs }) => {\n await input.run(args as Record<string, unknown>, rawArgs);\n },\n });\n}\n\n// --- Creatives ---\n\nexport const creativesDeleteCommand = command({\n schema: \"ads.meta.creatives.delete\",\n name: \"delete\",\n description:\n \"Stage deleting an ad creative. Meta deletes only a creative no ad runs — repoint or delete the ad first. Permanent.\",\n schemaDescription:\n \"Stage deleting a Meta ad creative (status DELETED) — applied at publish, permanent. Meta refuses a creative an ad still runs.\",\n args: { id: { type: \"positional\", description: \"Creative id\", required: true }, \"account-id\": accountArg },\n run: async (args) => {\n await stageOp({\n kind: \"adCreative.update\",\n accountId: await bareAccountId(args),\n target: requireTarget(args, \"creative\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\n// --- Images ---\n\nexport const mediaDeleteCommand = command({\n schema: \"ads.meta.media.delete\",\n name: \"delete\",\n description:\n \"Stage taking an image out of the ad account's image library, by its hash (`baker ads meta images`), or one of its videos by id (`--video-id`, from `baker ads meta media`). Meta refuses an image a creative still uses.\",\n schemaDescription:\n \"Stage deleting an image from a Meta ad account's image library by hash, or a video from its video library by id — applied at publish. Meta refuses an image a creative uses.\",\n args: {\n \"account-id\": accountArg,\n \"image-hash\": { type: \"string\", description: \"The image's hash\" },\n \"video-id\": { type: \"string\", description: \"Or a video of the ad account, by id\" },\n },\n run: async (args) => {\n const imageHash = typeof args[\"image-hash\"] === \"string\" ? args[\"image-hash\"] : undefined;\n const videoId = typeof args[\"video-id\"] === \"string\" ? args[\"video-id\"] : undefined;\n if ((imageHash === undefined) === (videoId === undefined)) {\n failWriteValidation(\"pass --image-hash (from `baker ads meta images`) or --video-id — one of them\");\n }\n await stageOp({ kind: \"media.delete\", accountId: await bareAccountId(args), payload: { imageHash, videoId } });\n },\n});\n\n// --- Custom conversions ---\n\nexport const customConversionsUpdateCommand = command({\n schema: \"ads.meta.custom-conversions.update\",\n name: \"update\",\n description:\n \"Stage renaming a Custom Conversion, its description or its value per conversion. Meta keeps a conversion's rule and event category for good — a conversion that counts something else is a new one.\",\n schemaDescription:\n \"Stage a change to a Meta Custom Conversion: --name, --description, --value (value per conversion, account currency). The rule and event category cannot change (Meta accepts and ignores them).\",\n args: {\n id: { type: \"positional\", description: \"Custom conversion id\", required: true },\n \"account-id\": accountArg,\n name: { type: \"string\", description: \"New name\" },\n description: { type: \"string\", description: \"New description\" },\n value: { type: \"string\", description: \"Value of one conversion, in the account currency\" },\n },\n run: async (args) => {\n const payload = Object.fromEntries(\n Object.entries({\n name: args.name,\n description: args.description,\n default_conversion_value: numberFlag(args.value, \"--value\"),\n }).filter(([, value]) => value !== undefined),\n );\n await stageOp({\n kind: \"customConversion.update\",\n accountId: await bareAccountId(args),\n target: requireTarget(args, \"custom conversion\"),\n payload,\n });\n },\n});\n\nexport const customConversionsDeleteCommand = command({\n schema: \"ads.meta.custom-conversions.delete\",\n name: \"delete\",\n description:\n \"Stage deleting a Custom Conversion. Meta archives it: it stops counting and leaves the active list, and still uses one of the account's slots. Ad sets optimizing toward it stop finding conversions.\",\n schemaDescription:\n \"Stage deleting (archiving) a Meta Custom Conversion — applied at publish. Not reversible; it keeps its slot in the account's cap.\",\n args: { id: schemaId(\"Custom conversion id\"), \"account-id\": accountArg },\n run: async (args) => {\n await stageOp({\n kind: \"customConversion.update\",\n accountId: await bareAccountId(args),\n target: requireTarget(args, \"custom conversion\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\n// --- Labels ---\n\nexport const labelsCreateCommand = command({\n schema: \"ads.meta.labels.create\",\n name: \"create\",\n description:\n 'Stage a new ad label. File things under it with `labels attach <ref> --campaigns …` in the same chat. Example: baker ads meta labels create --name \"Q4 launch\"',\n schemaDescription: \"Stage a new Meta ad label (created at publish). Returns a meta_temp_* ref `labels attach` takes.\",\n args: { \"account-id\": accountArg, name: { type: \"string\", description: \"Label name\" } },\n run: async (args) => {\n await stageOp({ kind: \"adLabel.create\", accountId: await bareAccountId(args), payload: { name: args.name } });\n },\n});\n\nexport const labelsRenameCommand = command({\n schema: \"ads.meta.labels.rename\",\n name: \"rename\",\n description: \"Stage renaming an ad label.\",\n schemaDescription: \"Stage renaming a Meta ad label.\",\n args: { id: schemaId(\"Label id\"), \"account-id\": accountArg, name: { type: \"string\", description: \"New name\" } },\n run: async (args) => {\n await stageOp({\n kind: \"adLabel.update\",\n accountId: await bareAccountId(args),\n target: requireTarget(args, \"label\"),\n payload: { name: args.name },\n });\n },\n});\n\nexport const labelsDeleteCommand = command({\n schema: \"ads.meta.labels.delete\",\n name: \"delete\",\n description: \"Stage deleting an ad label. Everything filed under it keeps running, unlabelled.\",\n schemaDescription: \"Stage deleting a Meta ad label — applied at publish; labelled objects keep running.\",\n args: { id: schemaId(\"Label id\"), \"account-id\": accountArg },\n run: async (args) => {\n await stageOp({\n kind: \"adLabel.update\",\n accountId: await bareAccountId(args),\n target: requireTarget(args, \"label\"),\n payload: { status: \"DELETED\" },\n });\n },\n});\n\nconst LABELLED = [\n [\"campaigns\", \"campaign.update\"],\n [\"adsets\", \"adSet.update\"],\n [\"ads\", \"ad.update\"],\n [\"creatives\", \"adCreative.update\"],\n] as const;\n\nconst targetArgs = {\n campaigns: { type: \"string\", description: \"Campaign ids (comma-separated or repeated)\" },\n adsets: { type: \"string\", description: \"Ad set ids\" },\n ads: { type: \"string\", description: \"Ad ids\" },\n creatives: {\n type: \"string\",\n description: \"Creative ids (live ones — a creative created in this chat is labelled later)\",\n },\n} as const;\n\nfunction idsOf(rawArgs: readonly string[] | undefined, flag: string, parsed: unknown): string[] {\n return repeatedValues(rawArgs, flag, parsed)\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter(Boolean);\n}\n\n/**\n * One staged update per object. Each names only the label to add or take\n * away; staging reads the labels the object has now and stages the whole set,\n * because Meta replaces an object's labels with the set it is sent.\n */\nasync function stageLabelChange(\n verb: \"addLabels\" | \"removeLabels\",\n args: Record<string, unknown>,\n rawArgs: readonly string[] | undefined,\n): Promise<void> {\n const accountId = await bareAccountId(args);\n const label = requireTarget(args, \"label\");\n const targets = LABELLED.flatMap(([flag, kind]) => idsOf(rawArgs, flag, args[flag]).map((id) => ({ kind, id })));\n if (targets.length === 0) {\n failWriteValidation(\"name what to label: --campaigns, --adsets, --ads or --creatives\");\n }\n await stageOps(\n targets.map((target) => ({ kind: target.kind, accountId, target: target.id, payload: { [verb]: [label] } })),\n );\n}\n\nexport const labelsAttachCommand = command({\n schema: \"ads.meta.labels.attach\",\n name: \"attach\",\n description:\n \"Stage filing campaigns, ad sets, ads or creatives under a label (a label id, or a meta_temp_* ref from `labels create`). Their other labels stay. Example: baker ads meta labels attach 120249 --campaigns 6123,6124\",\n schemaDescription:\n \"Stage adding a Meta ad label to campaigns/ad sets/ads/creatives (--campaigns, --adsets, --ads, --creatives; comma-separated). One staged change per object; other labels kept.\",\n args: { id: schemaId(\"Label id or meta_temp_* ref\"), \"account-id\": accountArg, ...targetArgs },\n run: async (args, rawArgs) => {\n await stageLabelChange(\"addLabels\", args, rawArgs);\n },\n});\n\nexport const labelsDetachCommand = command({\n schema: \"ads.meta.labels.detach\",\n name: \"detach\",\n description: \"Stage taking a label off campaigns, ad sets, ads or creatives. Their other labels stay.\",\n schemaDescription:\n \"Stage removing a Meta ad label from campaigns/ad sets/ads/creatives (--campaigns, --adsets, --ads, --creatives). Other labels kept.\",\n args: { id: schemaId(\"Label id\"), \"account-id\": accountArg, ...targetArgs },\n run: async (args, rawArgs) => {\n await stageLabelChange(\"removeLabels\", args, rawArgs);\n },\n});\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@ import {
2
2
  failWriteValidation,
3
3
  parseDateFlag,
4
4
  parseMoneyFlag
5
- } from "./chunk-OEJNZSJG.js";
5
+ } from "./chunk-4XXA4WCS.js";
6
6
  import {
7
7
  repeatedValues
8
8
  } from "./chunk-ERSX3MKH.js";
@@ -284,4 +284,4 @@ export {
284
284
  clearFromFlags,
285
285
  clearArg
286
286
  };
287
- //# sourceMappingURL=chunk-XB2FODWU.js.map
287
+ //# sourceMappingURL=chunk-TKDOVFO6.js.map
package/dist/cli.js CHANGED
@@ -170,7 +170,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
170
170
  capabilities: () => import("./capabilities-BEZXR2FZ.js").then((m) => m.capabilitiesCommand),
171
171
  actions: () => import("./actions-33IZOT5C.js").then((m) => m.actionsCommand),
172
172
  "scheduled-agents": () => import("./scheduled-agents-EPPP4SCZ.js").then((m) => m.scheduledAgentsCommand),
173
- ads: () => import("./ads-O4RL4JXD.js").then((m) => m.adsCommand),
173
+ ads: () => import("./ads-F2PURRHL.js").then((m) => m.adsCommand),
174
174
  brand: () => import("./brand-GBP4OEJI.js").then((m) => m.brandCommand),
175
175
  analytics: () => import("./analytics-OUNKG2FW.js").then((m) => m.analyticsCommand),
176
176
  experiment: () => import("./experiment-MO6MT6OJ.js").then((m) => m.experimentCommand),
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  command
3
- } from "./chunk-5LN7GWRE.js";
3
+ } from "./chunk-GEFZVG4P.js";
4
4
  import {
5
5
  bareAccountId,
6
6
  failWriteValidation,
@@ -8,10 +8,10 @@ import {
8
8
  requireTarget,
9
9
  stageOp,
10
10
  upper
11
- } from "./chunk-OEJNZSJG.js";
11
+ } from "./chunk-4XXA4WCS.js";
12
12
  import "./chunk-GC5P4KWY.js";
13
13
  import "./chunk-GDFJOCDO.js";
14
- import "./chunk-HPAGYPAF.js";
14
+ import "./chunk-BN4TDL5L.js";
15
15
  import "./chunk-ERSX3MKH.js";
16
16
  import "./chunk-WPAW6EVY.js";
17
17
  import "./chunk-4NZ47VXO.js";
@@ -140,7 +140,7 @@ Example: ${input.extra}`,
140
140
  requireTarget(args, input.label);
141
141
  await stageOp({
142
142
  kind: `${level}.copy`,
143
- accountId: bareAccountId(args),
143
+ accountId: await bareAccountId(args),
144
144
  payload: copyPayloadFromFlags(level, args)
145
145
  });
146
146
  }
@@ -167,4 +167,4 @@ export {
167
167
  campaignsCopyCommand,
168
168
  copyPayloadFromFlags
169
169
  };
170
- //# sourceMappingURL=copy-writes-GZ744FHU.js.map
170
+ //# sourceMappingURL=copy-writes-EUFEVWDW.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/ads/meta/copy-writes.ts"],"sourcesContent":["import type { ArgsDef, CommandDef } from \"citty\";\nimport { command } from \"./asset-writes.ts\";\nimport { bareAccountId, failWriteValidation, parseDateFlag, requireTarget, stageOp, upper } from \"./write-shared.ts\";\n\n/**\n * `campaigns|adsets|ads copy` — Meta's own copy (`POST /{id}/copies`), staged\n * until publish. Meta builds the copy from everything it holds, so it keeps\n * what Baker cannot read back or write; `duplicate` is the other tool, for a\n * copy whose fields change in the same step.\n */\n\ntype Level = \"campaign\" | \"adSet\" | \"ad\";\n\nconst STATUS_WORDS: Record<string, string> = {\n PAUSED: \"PAUSED\",\n ACTIVE: \"ACTIVE\",\n INHERITED: \"INHERITED_FROM_SOURCE\",\n INHERITED_FROM_SOURCE: \"INHERITED_FROM_SOURCE\",\n SAME: \"INHERITED_FROM_SOURCE\",\n};\n\nconst RENAME_WORDS: Record<string, string> = {\n TOP: \"ONLY_TOP_LEVEL_RENAME\",\n ONLY_TOP_LEVEL_RENAME: \"ONLY_TOP_LEVEL_RENAME\",\n DEEP: \"DEEP_RENAME\",\n ALL: \"DEEP_RENAME\",\n DEEP_RENAME: \"DEEP_RENAME\",\n NONE: \"NO_RENAME\",\n NO_RENAME: \"NO_RENAME\",\n};\n\nfunction mapped(words: Record<string, string>, value: unknown, flag: string, allowed: string): string | undefined {\n const key = upper(value);\n if (key === undefined) {\n return undefined;\n }\n const word = words[key];\n if (!word) {\n failWriteValidation(`${flag} takes ${allowed}`);\n }\n return word;\n}\n\n/** The staged copy payload from the command's flags. */\nexport function copyPayloadFromFlags(level: Level, args: Record<string, unknown>): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n source_id: args.id,\n status_option: mapped(STATUS_WORDS, args.status, \"--status\", \"PAUSED, ACTIVE or INHERITED\"),\n rename_strategy: mapped(RENAME_WORDS, args.rename, \"--rename\", \"top, deep or none\"),\n rename_prefix: args[\"rename-prefix\"],\n rename_suffix: args[\"rename-suffix\"],\n };\n if (level !== \"ad\") {\n payload.deep_copy = args.deep === true ? true : undefined;\n payload.start_time = parseDateFlag(args.start, \"--start\");\n payload.end_time = parseDateFlag(args.end, \"--end\");\n }\n if (level === \"adSet\") {\n payload.campaign_id = args[\"to-campaign\"];\n }\n if (level === \"ad\") {\n payload.adset_id = args[\"to-adset\"];\n }\n return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));\n}\n\nconst accountArg = { type: \"string\", description: \"Meta ad account ID (act_123)\" } as const;\nconst naming = {\n status: {\n type: \"string\",\n description: \"PAUSED (default) | ACTIVE — the copy delivers and spends once published | INHERITED — the original's\",\n },\n rename: {\n type: \"string\",\n description: \"top (default: only the copied object is renamed) | deep (its ad sets and ads too) | none\",\n },\n \"rename-prefix\": { type: \"string\", description: \"Put this before each renamed name\" },\n \"rename-suffix\": {\n type: \"string\",\n description: \"Put this after each renamed name instead of Meta's \\\" - Copy\\\" (in the account's language)\",\n },\n} as const;\nconst schedule = {\n start: { type: \"string\", description: \"When the copied ad sets start (ISO date or datetime); else the original's\" },\n end: { type: \"string\", description: \"When the copied ad sets end; else the original's\" },\n} as const;\n\nconst WHEN_TO_COPY = `copy is Meta's own copy: it keeps everything Meta holds — creatives, placements, every setting Baker cannot read back — and, with --deep, everything underneath. Use \\`duplicate\\` instead when the copy must differ in the same step (a new name, budget or targeting); or copy, then change the copy by its ref (\\`adsets update <ref> --daily-budget 30\\`), which applies once Meta has made it.`;\n\ntype ArgSpec = { type: string; description: string; required?: boolean };\n\nfunction copyArgs(level: Level, label: string): Record<string, ArgSpec> {\n const args: Record<string, ArgSpec> = {\n id: { type: \"positional\", description: `${label} id to copy (a published one)`, required: true },\n \"account-id\": accountArg,\n };\n if (level !== \"ad\") {\n const children = level === \"campaign\" ? \"ad sets and ads\" : \"ads\";\n args.deep = { type: \"boolean\", description: `Copy its ${children} too (Meta copies at most 51 ads in one go)` };\n }\n if (level === \"adSet\") {\n args[\"to-campaign\"] = {\n type: \"string\",\n description: \"Campaign id or meta_temp_* ref to put the copy in; else beside the original\",\n };\n }\n if (level === \"ad\") {\n args[\"to-adset\"] = {\n type: \"string\",\n description: \"Ad set id or meta_temp_* ref to put the copy in; else beside the original\",\n };\n }\n Object.assign(args, naming, level === \"ad\" ? {} : schedule);\n return args;\n}\n\nfunction copyCommand(level: Level, input: { family: string; label: string; extra: string }): CommandDef<ArgsDef> {\n return command({\n schema: `ads.meta.${input.family}.copy`,\n name: \"copy\",\n description: `Stage Meta's own copy of a ${input.label}${level === \"ad\" ? \"\" : \" (with --deep, of everything under it)\"}, paused unless --status. Prints a meta_temp_* ref for the copy that later changes in this chat can name. ${WHEN_TO_COPY}\nExample: ${input.extra}`,\n schemaDescription: `Stage a copy of a Meta ${input.label} through Meta's copies edge — applied at publish; the copy's ref resolves to its new id.`,\n args: copyArgs(level, input.label),\n run: async (args) => {\n requireTarget(args, input.label);\n await stageOp({\n kind: `${level}.copy`,\n accountId: bareAccountId(args),\n payload: copyPayloadFromFlags(level, args),\n });\n },\n });\n}\n\nexport const campaignsCopyCommand = copyCommand(\"campaign\", {\n family: \"campaigns\",\n label: \"campaign\",\n extra: 'baker ads meta campaigns copy 6123 --deep --rename-suffix \" – Q4\" --start 2026-11-01',\n});\nexport const adSetsCopyCommand = copyCommand(\"adSet\", {\n family: \"adsets\",\n label: \"ad set\",\n extra: \"baker ads meta adsets copy 6124 --deep --to-campaign meta_temp_ab12\",\n});\nexport const adsCopyCommand = copyCommand(\"ad\", {\n family: \"ads\",\n label: \"ad\",\n extra: \"baker ads meta ads copy 6125 --to-adset 6130\",\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/ads/meta/copy-writes.ts"],"sourcesContent":["import type { ArgsDef, CommandDef } from \"citty\";\nimport { command } from \"./asset-writes.ts\";\nimport { bareAccountId, failWriteValidation, parseDateFlag, requireTarget, stageOp, upper } from \"./write-shared.ts\";\n\n/**\n * `campaigns|adsets|ads copy` — Meta's own copy (`POST /{id}/copies`), staged\n * until publish. Meta builds the copy from everything it holds, so it keeps\n * what Baker cannot read back or write; `duplicate` is the other tool, for a\n * copy whose fields change in the same step.\n */\n\ntype Level = \"campaign\" | \"adSet\" | \"ad\";\n\nconst STATUS_WORDS: Record<string, string> = {\n PAUSED: \"PAUSED\",\n ACTIVE: \"ACTIVE\",\n INHERITED: \"INHERITED_FROM_SOURCE\",\n INHERITED_FROM_SOURCE: \"INHERITED_FROM_SOURCE\",\n SAME: \"INHERITED_FROM_SOURCE\",\n};\n\nconst RENAME_WORDS: Record<string, string> = {\n TOP: \"ONLY_TOP_LEVEL_RENAME\",\n ONLY_TOP_LEVEL_RENAME: \"ONLY_TOP_LEVEL_RENAME\",\n DEEP: \"DEEP_RENAME\",\n ALL: \"DEEP_RENAME\",\n DEEP_RENAME: \"DEEP_RENAME\",\n NONE: \"NO_RENAME\",\n NO_RENAME: \"NO_RENAME\",\n};\n\nfunction mapped(words: Record<string, string>, value: unknown, flag: string, allowed: string): string | undefined {\n const key = upper(value);\n if (key === undefined) {\n return undefined;\n }\n const word = words[key];\n if (!word) {\n failWriteValidation(`${flag} takes ${allowed}`);\n }\n return word;\n}\n\n/** The staged copy payload from the command's flags. */\nexport function copyPayloadFromFlags(level: Level, args: Record<string, unknown>): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n source_id: args.id,\n status_option: mapped(STATUS_WORDS, args.status, \"--status\", \"PAUSED, ACTIVE or INHERITED\"),\n rename_strategy: mapped(RENAME_WORDS, args.rename, \"--rename\", \"top, deep or none\"),\n rename_prefix: args[\"rename-prefix\"],\n rename_suffix: args[\"rename-suffix\"],\n };\n if (level !== \"ad\") {\n payload.deep_copy = args.deep === true ? true : undefined;\n payload.start_time = parseDateFlag(args.start, \"--start\");\n payload.end_time = parseDateFlag(args.end, \"--end\");\n }\n if (level === \"adSet\") {\n payload.campaign_id = args[\"to-campaign\"];\n }\n if (level === \"ad\") {\n payload.adset_id = args[\"to-adset\"];\n }\n return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));\n}\n\nconst accountArg = { type: \"string\", description: \"Meta ad account ID (act_123)\" } as const;\nconst naming = {\n status: {\n type: \"string\",\n description: \"PAUSED (default) | ACTIVE — the copy delivers and spends once published | INHERITED — the original's\",\n },\n rename: {\n type: \"string\",\n description: \"top (default: only the copied object is renamed) | deep (its ad sets and ads too) | none\",\n },\n \"rename-prefix\": { type: \"string\", description: \"Put this before each renamed name\" },\n \"rename-suffix\": {\n type: \"string\",\n description: \"Put this after each renamed name instead of Meta's \\\" - Copy\\\" (in the account's language)\",\n },\n} as const;\nconst schedule = {\n start: { type: \"string\", description: \"When the copied ad sets start (ISO date or datetime); else the original's\" },\n end: { type: \"string\", description: \"When the copied ad sets end; else the original's\" },\n} as const;\n\nconst WHEN_TO_COPY = `copy is Meta's own copy: it keeps everything Meta holds — creatives, placements, every setting Baker cannot read back — and, with --deep, everything underneath. Use \\`duplicate\\` instead when the copy must differ in the same step (a new name, budget or targeting); or copy, then change the copy by its ref (\\`adsets update <ref> --daily-budget 30\\`), which applies once Meta has made it.`;\n\ntype ArgSpec = { type: string; description: string; required?: boolean };\n\nfunction copyArgs(level: Level, label: string): Record<string, ArgSpec> {\n const args: Record<string, ArgSpec> = {\n id: { type: \"positional\", description: `${label} id to copy (a published one)`, required: true },\n \"account-id\": accountArg,\n };\n if (level !== \"ad\") {\n const children = level === \"campaign\" ? \"ad sets and ads\" : \"ads\";\n args.deep = { type: \"boolean\", description: `Copy its ${children} too (Meta copies at most 51 ads in one go)` };\n }\n if (level === \"adSet\") {\n args[\"to-campaign\"] = {\n type: \"string\",\n description: \"Campaign id or meta_temp_* ref to put the copy in; else beside the original\",\n };\n }\n if (level === \"ad\") {\n args[\"to-adset\"] = {\n type: \"string\",\n description: \"Ad set id or meta_temp_* ref to put the copy in; else beside the original\",\n };\n }\n Object.assign(args, naming, level === \"ad\" ? {} : schedule);\n return args;\n}\n\nfunction copyCommand(level: Level, input: { family: string; label: string; extra: string }): CommandDef<ArgsDef> {\n return command({\n schema: `ads.meta.${input.family}.copy`,\n name: \"copy\",\n description: `Stage Meta's own copy of a ${input.label}${level === \"ad\" ? \"\" : \" (with --deep, of everything under it)\"}, paused unless --status. Prints a meta_temp_* ref for the copy that later changes in this chat can name. ${WHEN_TO_COPY}\nExample: ${input.extra}`,\n schemaDescription: `Stage a copy of a Meta ${input.label} through Meta's copies edge — applied at publish; the copy's ref resolves to its new id.`,\n args: copyArgs(level, input.label),\n run: async (args) => {\n requireTarget(args, input.label);\n await stageOp({\n kind: `${level}.copy`,\n accountId: await bareAccountId(args),\n payload: copyPayloadFromFlags(level, args),\n });\n },\n });\n}\n\nexport const campaignsCopyCommand = copyCommand(\"campaign\", {\n family: \"campaigns\",\n label: \"campaign\",\n extra: 'baker ads meta campaigns copy 6123 --deep --rename-suffix \" – Q4\" --start 2026-11-01',\n});\nexport const adSetsCopyCommand = copyCommand(\"adSet\", {\n family: \"adsets\",\n label: \"ad set\",\n extra: \"baker ads meta adsets copy 6124 --deep --to-campaign meta_temp_ab12\",\n});\nexport const adsCopyCommand = copyCommand(\"ad\", {\n family: \"ads\",\n label: \"ad\",\n extra: \"baker ads meta ads copy 6125 --to-adset 6130\",\n});\n"],"mappings":"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","names":[]}