@koda-sl/baker-cli 0.445.0-dev.a2eb3621e → 0.445.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/{account-4H7QVBRK.js → account-F6MHQ64I.js} +3 -3
- package/dist/{account-RDRK7NOE.js → account-S2PX5JOR.js} +5 -5
- package/dist/{account-writes-AK42HGRM.js → account-writes-ISE4U2FQ.js} +3 -3
- package/dist/{accounts-4TYIUVWY.js → accounts-2D6D4MTX.js} +4 -4
- package/dist/{accounts-6COLJJHM.js → accounts-TC3LBWNF.js} +6 -6
- package/dist/{actions-PEI6ZQAG.js → actions-WEZT4Z6N.js} +18 -18
- package/dist/{ad-group-writes-QQS4223F.js → ad-group-writes-UU5NNKSO.js} +3 -3
- package/dist/{ad-groups-WGPDPUI2.js → ad-groups-CGFXZNIA.js} +7 -7
- package/dist/{ad-writes-XE2IE4DS.js → ad-writes-NALDYWOR.js} +3 -3
- package/dist/{add-XDOQQCHS.js → add-IJ6DDZFU.js} +3 -3
- package/dist/{add-XEDSBYLM.js → add-N7SAQT4W.js} +4 -4
- package/dist/{ads-BCOSQALY.js → ads-PV7GZXPR.js} +8 -8
- package/dist/{ads-TJ7ACFHG.js → ads-R4VOYYCQ.js} +5 -5
- package/dist/{advertisers-WSNHNCBQ.js → advertisers-OVPF7MPT.js} +4 -4
- package/dist/{analytics-PT2GKCFU.js → analytics-AIT5OTZU.js} +7 -7
- package/dist/{analytics-ZVWUY66X.js → analytics-UQZHJ73K.js} +4 -4
- package/dist/{animate-3Z7HXOLE.js → animate-37ZVC3Q5.js} +4 -4
- package/dist/{assign-B26AJLGN.js → assign-HTM32ZU7.js} +4 -4
- package/dist/{audience-size-ZX565D5P.js → audience-size-34FBOXDD.js} +4 -4
- package/dist/{audiences-TGD5US2M.js → audiences-VEKGLWBG.js} +3 -3
- package/dist/{audit-SAXVPGWS.js → audit-VLOHMKZS.js} +4 -4
- package/dist/{autocomplete-6PYFCOMX.js → autocomplete-COT2XIF2.js} +4 -4
- package/dist/{avatars-2UQJXHPV.js → avatars-3OFDMP7K.js} +4 -4
- package/dist/{bid-pricing-WSHACGX4.js → bid-pricing-5RJI4XRY.js} +4 -4
- package/dist/{brand-XBABUT52.js → brand-HEG34BBE.js} +2 -2
- package/dist/{brief-KKNC32TA.js → brief-X3DWOXZB.js} +10 -10
- package/dist/{campaign-groups-G35366AW.js → campaign-groups-VSPY3PGK.js} +9 -9
- package/dist/{campaign-writes-SXLZFYF6.js → campaign-writes-SX52CJYW.js} +3 -3
- package/dist/{campaign-writes-ZQGN7FQ3.js → campaign-writes-UXSPJHNL.js} +4 -4
- package/dist/{campaigns-WECN54WV.js → campaigns-K4MWUORA.js} +5 -5
- package/dist/{campaigns-GXUCHQ2S.js → campaigns-UB7QCJUT.js} +12 -12
- package/dist/{campaigns-YS3OGQXO.js → campaigns-X3DPCCSN.js} +7 -7
- package/dist/{canvas-DNIREYCF.js → canvas-WBQKGYOB.js} +14 -14
- package/dist/{capabilities-74I5AQ36.js → capabilities-3W5CZZFQ.js} +4 -4
- package/dist/{catalog-IQEQ5TGQ.js → catalog-E62VZ4QC.js} +6 -6
- package/dist/{catalogs-BRXEDE56.js → catalogs-G3YEVG6S.js} +3 -3
- package/dist/{changes-6QBJMGJC.js → changes-TP7ZZHB3.js} +4 -4
- package/dist/{chatgpt-7W75X3ER.js → chatgpt-QNUN63YS.js} +13 -13
- package/dist/{chats-DWHF64IU.js → chats-5JUHCYQ7.js} +4 -4
- package/dist/{chunk-JM73NDCM.js → chunk-2HZN4CJD.js} +2 -2
- package/dist/{chunk-OC5IJSIW.js → chunk-2LY4RW5O.js} +3 -3
- package/dist/{chunk-7J6EHOH6.js → chunk-35XWJEWH.js} +2 -2
- package/dist/{chunk-7QJVPMVB.js → chunk-3EEOCPPI.js} +3 -3
- package/dist/{chunk-7GPDUS3P.js → chunk-5XQEA7RP.js} +2 -2
- package/dist/{chunk-RSW6QJPH.js → chunk-6VAAU2DJ.js} +2 -2
- package/dist/{chunk-LL2CD5WU.js → chunk-6W37TO6U.js} +2 -2
- package/dist/{chunk-CLMM6P6B.js → chunk-76KTC7RD.js} +2 -2
- package/dist/{chunk-OKG6GX2F.js → chunk-AQ7UIRZ3.js} +2 -2
- package/dist/{chunk-HMEFD2CG.js → chunk-AQYRPO4R.js} +5 -5
- package/dist/{chunk-NPE7EWBE.js → chunk-CC7IKR36.js} +2 -2
- package/dist/{chunk-QJE6ZYGI.js → chunk-CWX4PPOK.js} +2 -2
- package/dist/{chunk-SBMIQDCX.js → chunk-ER322F6V.js} +2 -2
- package/dist/{chunk-5CGZ54YS.js → chunk-ERFFZYCK.js} +3 -3
- package/dist/{chunk-VWCELTQE.js → chunk-FQOBCTMF.js} +2 -2
- package/dist/{chunk-4SJDDGPV.js → chunk-GTRZUWT2.js} +2 -2
- package/dist/{chunk-73QKIIIR.js → chunk-GWZCWUUQ.js} +2 -2
- package/dist/{chunk-KWAOTV7F.js → chunk-GX6VAHY7.js} +2 -2
- package/dist/{chunk-XG3XCHN6.js → chunk-HA5D6US2.js} +2 -2
- package/dist/{chunk-ZNBDKK4Y.js → chunk-HWB5DN32.js} +2 -2
- package/dist/{chunk-UKJNLP4A.js → chunk-I2Z3Q436.js} +3 -3
- package/dist/{chunk-HSTEQ3RF.js → chunk-J6QVRNHE.js} +7 -7
- package/dist/{chunk-XWH7CCBL.js → chunk-KFKZHKGZ.js} +23 -8
- package/dist/chunk-KFKZHKGZ.js.map +1 -0
- package/dist/{chunk-IXKEWS7X.js → chunk-KIAD2YRA.js} +2 -2
- package/dist/{chunk-FTWJFDIN.js → chunk-KLBTXETO.js} +169 -169
- package/dist/chunk-KLBTXETO.js.map +1 -0
- package/dist/{chunk-FEXDI4NM.js → chunk-KSTGP67A.js} +2 -2
- package/dist/{chunk-OBDAYP2P.js → chunk-KY4MPR6R.js} +4 -4
- package/dist/chunk-KY4MPR6R.js.map +1 -0
- package/dist/{chunk-2SCPDSFN.js → chunk-LIQ4SQ2T.js} +2 -2
- package/dist/{chunk-AN447DQB.js → chunk-LTGKIBVX.js} +3 -3
- package/dist/{chunk-RRUJQVWA.js → chunk-MF5WL2MP.js} +4 -4
- package/dist/{chunk-HXTGYOQC.js → chunk-MO7XF4HR.js} +3 -3
- package/dist/{chunk-XML7AJM3.js → chunk-NE4F3FHN.js} +1 -1
- package/dist/chunk-NE4F3FHN.js.map +1 -0
- package/dist/{chunk-MRLT6YQM.js → chunk-NX6U2JSE.js} +13 -13
- package/dist/{chunk-FHXIEMCG.js → chunk-O7NR6OPL.js} +2 -2
- package/dist/{chunk-DIY6QR3E.js → chunk-OTDS56OQ.js} +4 -4
- package/dist/{chunk-SJDPHVGE.js → chunk-PQEPGP2M.js} +2 -2
- package/dist/{chunk-QXZYAIWS.js → chunk-Q4XTRXJV.js} +5 -5
- package/dist/{chunk-BYDF22T4.js → chunk-QEGHWJXC.js} +3 -3
- package/dist/{chunk-XYMPS526.js → chunk-QKBO6QD2.js} +2 -2
- package/dist/{chunk-3RJ3VGJP.js → chunk-R3OD5PVZ.js} +2 -2
- package/dist/{chunk-ZJ47BR6X.js → chunk-RNNIKAR7.js} +2 -2
- package/dist/{chunk-HYCIBVDW.js → chunk-RWPQW73R.js} +2 -2
- package/dist/{chunk-LO72ZSRR.js → chunk-STIQPSLZ.js} +3 -3
- package/dist/{chunk-EIP4PYCL.js → chunk-TIOQ7ZFQ.js} +2 -2
- package/dist/{chunk-VBHDZSI5.js → chunk-UQFAYC2Y.js} +2 -2
- package/dist/{chunk-OKJYCCHY.js → chunk-V47L5CNH.js} +7 -7
- package/dist/{chunk-IPAETHU2.js → chunk-VTGEGDKW.js} +2 -2
- package/dist/{chunk-EVYXTT7V.js → chunk-XCM6XWOB.js} +2 -2
- package/dist/{chunk-EZUG6WE2.js → chunk-YDJMV7BC.js} +2 -2
- package/dist/{chunk-KXRXS6BZ.js → chunk-YPKSJRSF.js} +6 -6
- package/dist/{chunk-75VNSKS3.js → chunk-Z65HNXZ2.js} +2 -2
- package/dist/{chunk-LO6GEJ4Z.js → chunk-ZFKL7UYS.js} +3 -3
- package/dist/{claim-EIL4ZBSN.js → claim-GPKFFPWC.js} +4 -4
- package/dist/cli.js +28 -28
- package/dist/{companies-2UG7RDYN.js → companies-2PQ2BXQO.js} +4 -4
- package/dist/{complete-I4KRFYMD.js → complete-LT6PYTQA.js} +4 -4
- package/dist/{connect-TA5W6YGW.js → connect-6LR75R2A.js} +7 -7
- package/dist/{conversation-BJI54MI6.js → conversation-4DI5N62Z.js} +4 -4
- package/dist/{conversion-report-XQBJ6LG4.js → conversion-report-N4HANYOB.js} +2 -2
- package/dist/{conversion-upload-command-JULHGVIR.js → conversion-upload-command-TZTHU2CD.js} +4 -4
- package/dist/{conversion-writes-UBCVXP2E.js → conversion-writes-LW4HQKK5.js} +3 -3
- package/dist/{conversions-VJOJ5S4U.js → conversions-3I2L4J5V.js} +8 -8
- package/dist/{conversions-D236RTUK.js → conversions-TS723AZV.js} +5 -5
- package/dist/{create-VY3RQXOY.js → create-CDEXO5TQ.js} +4 -4
- package/dist/{create-JLQCXAT2.js → create-DCFRBBRW.js} +3 -3
- package/dist/{create-E7BIZNUC.js → create-JOJ7PTHG.js} +4 -4
- package/dist/{create-HKOO7O5L.js → create-JUSUZ6AH.js} +4 -4
- package/dist/{creatives-KM2XH4G7.js → creatives-HFG6KSLV.js} +10 -10
- package/dist/{creatives-VXQQUH2F.js → creatives-ODCZ3C2H.js} +9 -9
- package/dist/{credentials-G5BJK7OR.js → credentials-AYMSKYFV.js} +17 -17
- package/dist/credentials-AYMSKYFV.js.map +1 -0
- package/dist/{critique-CMLAPVUB.js → critique-4BFUFNZQ.js} +4 -4
- package/dist/{critique-6MIZLNCN.js → critique-X5N53OCQ.js} +10 -10
- package/dist/{crm-CL7R67FT.js → crm-GGKMNFLI.js} +5 -5
- package/dist/{crm-GJCAM3DI.js → crm-GXLDR5RP.js} +5 -5
- package/dist/{currency-DJDVIR3C.js → currency-XCGKQ7FE.js} +4 -4
- package/dist/{customers-4RJGRR2Y.js → customers-4D6MXGCQ.js} +6 -6
- package/dist/{delete-IJNJTAGW.js → delete-2SBGGQDG.js} +4 -4
- package/dist/{delete-4QXLTL24.js → delete-7RI3657I.js} +4 -4
- package/dist/{delete-R57JFJ3A.js → delete-L2I54O3F.js} +3 -3
- package/dist/{demographics-VMARSTTE.js → demographics-SXCT2YZA.js} +4 -4
- package/dist/{discard-Y2BKPW4Z.js → discard-5DCAWO7J.js} +4 -4
- package/dist/{discover-M3ZKKFEL.js → discover-BJPZNXUQ.js} +4 -4
- package/dist/{domain-YTHDTRWN.js → domain-XD5HZMA3.js} +4 -4
- package/dist/{draft-ABGQYDHP.js → draft-B44SVA7P.js} +4 -4
- package/dist/{draft-U6CT6LCC.js → draft-BV2QRPZ4.js} +4 -4
- package/dist/{draft-MNFJ4G3C.js → draft-THPZFASM.js} +3 -3
- package/dist/{draft-KOLU5BRR.js → draft-XNUD2ZX3.js} +4 -4
- package/dist/{draft-ZVVUAMMQ.js → draft-XZ2UXMUK.js} +5 -5
- package/dist/engine/index.js +5 -5
- package/dist/{facets-UXN4MYPO.js → facets-FGRPLNHJ.js} +4 -4
- package/dist/{feedback-C4VDRNUM.js → feedback-NZDBN3MD.js} +3 -3
- package/dist/feedback-NZDBN3MD.js.map +1 -0
- package/dist/{feedback-record-KNIYAUTC.js → feedback-record-3ZLSSBOI.js} +13 -13
- package/dist/feedback-record-3ZLSSBOI.js.map +1 -0
- package/dist/{fit-KXHYKIA4.js → fit-275H7ETA.js} +4 -4
- package/dist/{flows-PB4K66NJ.js → flows-DTJHR2HD.js} +11 -11
- package/dist/{fonts-NTOQS2KU.js → fonts-SEC67SFN.js} +6 -6
- package/dist/{forecast-RWDIDDWP.js → forecast-ZZ7FWJST.js} +4 -4
- package/dist/{funnel-XCKPRYTV.js → funnel-ILNHRWXJ.js} +5 -5
- package/dist/{generate-DMQUS665.js → generate-6DDI42Y2.js} +3 -3
- package/dist/{get-67IG7SZI.js → get-6MJRBEGP.js} +4 -4
- package/dist/{get-WO22OCMZ.js → get-CQFJWZSM.js} +4 -4
- package/dist/{google-KIBLORXX.js → google-35GDU3G3.js} +18 -18
- package/dist/{google-KIBLORXX.js.map → google-35GDU3G3.js.map} +1 -1
- package/dist/{history-Q3QCT64S.js → history-DBIEYQHY.js} +3 -3
- package/dist/{history-PBFRKLU6.js → history-DBR2D4DC.js} +4 -4
- package/dist/{hubspot-PMOZST7W.js → hubspot-YPG2W5UP.js} +8 -8
- package/dist/{ideas-PU7IAX6F.js → ideas-AV7CYETD.js} +3 -3
- package/dist/{images-QI2HTX6B.js → images-F54P6D3N.js} +4 -4
- package/dist/{ingest-ZQM47NVZ.js → ingest-G5OVGZUO.js} +3 -3
- package/dist/{ingest-BYJNFOOT.js → ingest-RUC3EPHJ.js} +4 -4
- package/dist/{insights-LNAXV2CG.js → insights-ZIU6FJMS.js} +2 -2
- package/dist/{inspect-CQH55Q6G.js → inspect-6PCX234P.js} +4 -4
- package/dist/{intent-ICKFJRT2.js → intent-HG637ISN.js} +4 -4
- package/dist/{keyword-gap-NGPH32FN.js → keyword-gap-MBZ4T6PS.js} +4 -4
- package/dist/{keyword-metrics-E3NJUSEQ.js → keyword-metrics-C7TN7WVV.js} +5 -5
- package/dist/{keywords-for-site-RH47P4GJ.js → keywords-for-site-RXYG74EH.js} +4 -4
- package/dist/{landing-4PA7GCPM.js → landing-EPYJ2TYC.js} +2 -2
- package/dist/{languages-JDYL2N5F.js → languages-HORKPDNH.js} +4 -4
- package/dist/{leads-I7BO5V7P.js → leads-5E3MULCF.js} +4 -4
- package/dist/{learn-HZU3QWNN.js → learn-EC73LWRX.js} +8 -8
- package/dist/{line-item-writes-JSR53MID.js → line-item-writes-OWDX5TF4.js} +4 -4
- package/dist/{line-items-2WFLKOOR.js → line-items-LF4IZCVD.js} +5 -5
- package/dist/{link-AYXOJQDV.js → link-D2ZPRSGD.js} +4 -4
- package/dist/{linkedin-M2PVZYLV.js → linkedin-3LUIRE76.js} +27 -27
- package/dist/{list-3OKEMUFD.js → list-5LXT3MMM.js} +3 -3
- package/dist/{list-4MQC23JH.js → list-PYRY2HPB.js} +4 -4
- package/dist/{list-QGLIL7J6.js → list-QTFE6CJ2.js} +4 -4
- package/dist/{locations-2NKBJKBT.js → locations-74TPQWAT.js} +2 -2
- package/dist/{locations-S4U6IJIS.js → locations-J4G5RNPH.js} +4 -4
- package/dist/{log-QHR2JNKW.js → log-YOEMOLDG.js} +4 -4
- package/dist/{make-HRCWP2C6.js → make-2EK4E4BB.js} +18 -18
- package/dist/{map-3BVFAP33.js → map-XMWYNJZI.js} +5 -5
- package/dist/{mcp-LH5KR6RO.js → mcp-6HL4CR5E.js} +3 -3
- package/dist/{media-sources-3D246I3O.js → media-sources-WFTHXYMZ.js} +2 -2
- package/dist/{members-4DUQHLZH.js → members-6FKD5KZ2.js} +4 -4
- package/dist/{metrics-AY4RP54F.js → metrics-SQDJ5NQO.js} +4 -4
- package/dist/{models-5NTC7A5G.js → models-6T2XV2KB.js} +2 -2
- package/dist/{normalize-CD4PQRYY.js → normalize-3JLFCOWS.js} +4 -4
- package/dist/{options-6TE5E34Z.js → options-RAHLATMR.js} +7 -7
- package/dist/{performance-7LQQCEAW.js → performance-FKL2KHHX.js} +5 -5
- package/dist/{pixels-TZPF746S.js → pixels-45A55MOP.js} +3 -3
- package/dist/{promoted-tweet-writes-F76YIMB6.js → promoted-tweet-writes-DMFVG63W.js} +4 -4
- package/dist/{promoted-tweets-EJL37P7K.js → promoted-tweets-KJYCL6J5.js} +3 -3
- package/dist/{publish-H5S2IKZP.js → publish-Y5PALSEY.js} +4 -4
- package/dist/{query-CPZZNMDY.js → query-IEZRY6HV.js} +4 -4
- package/dist/{reddit-INGPFGP4.js → reddit-CIJFBT32.js} +4 -4
- package/dist/{refresh-MKSKISPX.js → refresh-SWW23DAQ.js} +3 -3
- package/dist/{release-J5LIAIZT.js → release-FOBIO5QG.js} +4 -4
- package/dist/{relevant-pages-MTMFMBPD.js → relevant-pages-MFJEPBR4.js} +4 -4
- package/dist/{remove-LYEK7VFV.js → remove-OXAH3ZKL.js} +3 -3
- package/dist/{reopen-FR4UBOG7.js → reopen-JFRI6ZR6.js} +4 -4
- package/dist/{rerun-XPWGIVTT.js → rerun-73NGMIM7.js} +19 -19
- package/dist/{research-RPJSOWPT.js → research-7N67CM2T.js} +56 -20
- package/dist/research-7N67CM2T.js.map +1 -0
- package/dist/{research-PA53M335.js → research-SNMF4JOY.js} +10 -10
- package/dist/{reset-RCYRE5WO.js → reset-222UFTF6.js} +3 -3
- package/dist/{reset-H3ES4WV5.js → reset-B6JRVIIH.js} +3 -3
- package/dist/{resolve-QIDQJCE6.js → resolve-XQCGZYTD.js} +4 -4
- package/dist/{retry-WLVMR7XP.js → retry-O6BBBGXP.js} +3 -3
- package/dist/{retry-PLLCFOJW.js → retry-TQHVMUU4.js} +3 -3
- package/dist/{run-WMJPDX6U.js → run-6L3QS4PP.js} +19 -19
- package/dist/{run-4D7ZCLMF.js → run-FDSII53R.js} +4 -4
- package/dist/{scaffold-ad-VYYZIEQ2.js → scaffold-ad-WRPLC3JR.js} +17 -17
- package/dist/{scaffold-static-ad-B3SZ2HLW.js → scaffold-static-ad-HRLKY5WF.js} +23 -23
- package/dist/{scaffold-video-2QISC5CW.js → scaffold-video-LSOSZCVF.js} +15 -15
- package/dist/{schedule-RXUUCNNI.js → schedule-KNRJAYCK.js} +3 -3
- package/dist/{scheduled-agents-2NCGSD76.js → scheduled-agents-IPZ5QA6C.js} +11 -11
- package/dist/{schema-SFODURN7.js → schema-H43I3TR4.js} +5 -5
- package/dist/{search-7QVZOWSI.js → search-7CMRZNWL.js} +3 -3
- package/dist/{select-C6CFCOEM.js → select-OKF5SLAO.js} +12 -12
- package/dist/{set-prompt-MIMQYMGM.js → set-prompt-N54XKRGK.js} +11 -11
- package/dist/{setup-links-XW4A6L2I.js → setup-links-2MOYMVEY.js} +4 -4
- package/dist/{site-6UTQSYIK.js → site-BDTMN6VB.js} +5 -5
- package/dist/{sources-QQNWQLUM.js → sources-4XCN3STL.js} +7 -7
- package/dist/{sources-UGMZFZ2E.js → sources-TCEHZ5RV.js} +6 -6
- package/dist/{stale-NOSV6ONW.js → stale-J5PKAEBW.js} +11 -11
- package/dist/{status-NXGKJGH7.js → status-6AN44KXK.js} +4 -4
- package/dist/{studio-HUEBE6DS.js → studio-TM3MAAUW.js} +4 -4
- package/dist/{sync-RXS6BPLM.js → sync-TPOVAGPK.js} +3 -3
- package/dist/{sync-definition-2DQN2KN3.js → sync-definition-A4SIK5VW.js} +14 -14
- package/dist/{tags-CMBKEXIZ.js → tags-CN6I22A5.js} +4 -4
- package/dist/{tags-C65JB762.js → tags-N6SF24MU.js} +3 -3
- package/dist/{tags-R3K35KTL.js → tags-QITCY5QO.js} +4 -4
- package/dist/{tags-GFFQLLG2.js → tags-TMUNXXYN.js} +4 -4
- package/dist/{tags-IJN2SPSM.js → tags-U4JDAVUH.js} +4 -4
- package/dist/{targeting-criteria-IHBPLHSX.js → targeting-criteria-DRA5JGCZ.js} +3 -3
- package/dist/{targets-JH37NVJF.js → targets-B3HWHREZ.js} +4 -4
- package/dist/{templates-HXSHQ23T.js → templates-53VD5PEV.js} +4 -4
- package/dist/{testimonials-5QGCPZ6K.js → testimonials-NOTV6AON.js} +6 -6
- package/dist/{top-companies-FJEFKVI7.js → top-companies-NIG3PBD3.js} +4 -4
- package/dist/{translate-XQDRDI6P.js → translate-QYBPQSAP.js} +171 -50
- package/dist/translate-QYBPQSAP.js.map +1 -0
- package/dist/{triggers-SEOAAJSS.js → triggers-IIUPW5LU.js} +4 -4
- package/dist/{unlink-UZDVSHBO.js → unlink-WRF3E3AL.js} +4 -4
- package/dist/{unstage-CE5RRGM5.js → unstage-GXHKDXA5.js} +4 -4
- package/dist/{update-JZ4I6WW7.js → update-4KUD5OH4.js} +4 -4
- package/dist/{update-ZXOG2V34.js → update-6CHXJFMF.js} +3 -3
- package/dist/{update-DGZKEP6T.js → update-FGTKHBEG.js} +4 -4
- package/dist/{update-JOS4ITAV.js → update-R47RJ5NM.js} +4 -4
- package/dist/{upload-SSOPA7ZT.js → upload-3IDNWUH7.js} +4 -4
- package/dist/{url-options-QEWKRKZ3.js → url-options-GGXAL3J4.js} +4 -4
- package/dist/{url-params-OR5N5EWT.js → url-params-EYHAK4TR.js} +4 -4
- package/dist/{validate-4YXSJA4S.js → validate-S3S52QNH.js} +12 -12
- package/dist/{videos-GIYDCCKR.js → videos-FH4XUXWR.js} +5 -5
- package/dist/{viewer-check-VN2JK2LW.js → viewer-check-5TJ7UGMV.js} +4 -4
- package/dist/{winning-ads-7QWEIMRU.js → winning-ads-QMTRP7DI.js} +3 -3
- package/dist/{write-commands-SVJ43D7G.js → write-commands-N6ZN3B4E.js} +5 -5
- package/dist/{x-OEAKQBB7.js → x-W6GJ63OZ.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-FTWJFDIN.js.map +0 -1
- package/dist/chunk-OBDAYP2P.js.map +0 -1
- package/dist/chunk-XML7AJM3.js.map +0 -1
- package/dist/chunk-XWH7CCBL.js.map +0 -1
- package/dist/credentials-G5BJK7OR.js.map +0 -1
- package/dist/feedback-C4VDRNUM.js.map +0 -1
- package/dist/feedback-record-KNIYAUTC.js.map +0 -1
- package/dist/research-RPJSOWPT.js.map +0 -1
- package/dist/translate-XQDRDI6P.js.map +0 -1
- /package/dist/{account-4H7QVBRK.js.map → account-F6MHQ64I.js.map} +0 -0
- /package/dist/{account-RDRK7NOE.js.map → account-S2PX5JOR.js.map} +0 -0
- /package/dist/{account-writes-AK42HGRM.js.map → account-writes-ISE4U2FQ.js.map} +0 -0
- /package/dist/{accounts-4TYIUVWY.js.map → accounts-2D6D4MTX.js.map} +0 -0
- /package/dist/{accounts-6COLJJHM.js.map → accounts-TC3LBWNF.js.map} +0 -0
- /package/dist/{actions-PEI6ZQAG.js.map → actions-WEZT4Z6N.js.map} +0 -0
- /package/dist/{ad-group-writes-QQS4223F.js.map → ad-group-writes-UU5NNKSO.js.map} +0 -0
- /package/dist/{ad-groups-WGPDPUI2.js.map → ad-groups-CGFXZNIA.js.map} +0 -0
- /package/dist/{ad-writes-XE2IE4DS.js.map → ad-writes-NALDYWOR.js.map} +0 -0
- /package/dist/{add-XDOQQCHS.js.map → add-IJ6DDZFU.js.map} +0 -0
- /package/dist/{add-XEDSBYLM.js.map → add-N7SAQT4W.js.map} +0 -0
- /package/dist/{ads-BCOSQALY.js.map → ads-PV7GZXPR.js.map} +0 -0
- /package/dist/{ads-TJ7ACFHG.js.map → ads-R4VOYYCQ.js.map} +0 -0
- /package/dist/{advertisers-WSNHNCBQ.js.map → advertisers-OVPF7MPT.js.map} +0 -0
- /package/dist/{analytics-PT2GKCFU.js.map → analytics-AIT5OTZU.js.map} +0 -0
- /package/dist/{analytics-ZVWUY66X.js.map → analytics-UQZHJ73K.js.map} +0 -0
- /package/dist/{animate-3Z7HXOLE.js.map → animate-37ZVC3Q5.js.map} +0 -0
- /package/dist/{assign-B26AJLGN.js.map → assign-HTM32ZU7.js.map} +0 -0
- /package/dist/{audience-size-ZX565D5P.js.map → audience-size-34FBOXDD.js.map} +0 -0
- /package/dist/{audiences-TGD5US2M.js.map → audiences-VEKGLWBG.js.map} +0 -0
- /package/dist/{audit-SAXVPGWS.js.map → audit-VLOHMKZS.js.map} +0 -0
- /package/dist/{autocomplete-6PYFCOMX.js.map → autocomplete-COT2XIF2.js.map} +0 -0
- /package/dist/{avatars-2UQJXHPV.js.map → avatars-3OFDMP7K.js.map} +0 -0
- /package/dist/{bid-pricing-WSHACGX4.js.map → bid-pricing-5RJI4XRY.js.map} +0 -0
- /package/dist/{brand-XBABUT52.js.map → brand-HEG34BBE.js.map} +0 -0
- /package/dist/{brief-KKNC32TA.js.map → brief-X3DWOXZB.js.map} +0 -0
- /package/dist/{campaign-groups-G35366AW.js.map → campaign-groups-VSPY3PGK.js.map} +0 -0
- /package/dist/{campaign-writes-SXLZFYF6.js.map → campaign-writes-SX52CJYW.js.map} +0 -0
- /package/dist/{campaign-writes-ZQGN7FQ3.js.map → campaign-writes-UXSPJHNL.js.map} +0 -0
- /package/dist/{campaigns-WECN54WV.js.map → campaigns-K4MWUORA.js.map} +0 -0
- /package/dist/{campaigns-GXUCHQ2S.js.map → campaigns-UB7QCJUT.js.map} +0 -0
- /package/dist/{campaigns-YS3OGQXO.js.map → campaigns-X3DPCCSN.js.map} +0 -0
- /package/dist/{canvas-DNIREYCF.js.map → canvas-WBQKGYOB.js.map} +0 -0
- /package/dist/{capabilities-74I5AQ36.js.map → capabilities-3W5CZZFQ.js.map} +0 -0
- /package/dist/{catalog-IQEQ5TGQ.js.map → catalog-E62VZ4QC.js.map} +0 -0
- /package/dist/{catalogs-BRXEDE56.js.map → catalogs-G3YEVG6S.js.map} +0 -0
- /package/dist/{changes-6QBJMGJC.js.map → changes-TP7ZZHB3.js.map} +0 -0
- /package/dist/{chatgpt-7W75X3ER.js.map → chatgpt-QNUN63YS.js.map} +0 -0
- /package/dist/{chats-DWHF64IU.js.map → chats-5JUHCYQ7.js.map} +0 -0
- /package/dist/{chunk-JM73NDCM.js.map → chunk-2HZN4CJD.js.map} +0 -0
- /package/dist/{chunk-OC5IJSIW.js.map → chunk-2LY4RW5O.js.map} +0 -0
- /package/dist/{chunk-7J6EHOH6.js.map → chunk-35XWJEWH.js.map} +0 -0
- /package/dist/{chunk-7QJVPMVB.js.map → chunk-3EEOCPPI.js.map} +0 -0
- /package/dist/{chunk-7GPDUS3P.js.map → chunk-5XQEA7RP.js.map} +0 -0
- /package/dist/{chunk-RSW6QJPH.js.map → chunk-6VAAU2DJ.js.map} +0 -0
- /package/dist/{chunk-LL2CD5WU.js.map → chunk-6W37TO6U.js.map} +0 -0
- /package/dist/{chunk-CLMM6P6B.js.map → chunk-76KTC7RD.js.map} +0 -0
- /package/dist/{chunk-OKG6GX2F.js.map → chunk-AQ7UIRZ3.js.map} +0 -0
- /package/dist/{chunk-HMEFD2CG.js.map → chunk-AQYRPO4R.js.map} +0 -0
- /package/dist/{chunk-NPE7EWBE.js.map → chunk-CC7IKR36.js.map} +0 -0
- /package/dist/{chunk-QJE6ZYGI.js.map → chunk-CWX4PPOK.js.map} +0 -0
- /package/dist/{chunk-SBMIQDCX.js.map → chunk-ER322F6V.js.map} +0 -0
- /package/dist/{chunk-5CGZ54YS.js.map → chunk-ERFFZYCK.js.map} +0 -0
- /package/dist/{chunk-VWCELTQE.js.map → chunk-FQOBCTMF.js.map} +0 -0
- /package/dist/{chunk-4SJDDGPV.js.map → chunk-GTRZUWT2.js.map} +0 -0
- /package/dist/{chunk-73QKIIIR.js.map → chunk-GWZCWUUQ.js.map} +0 -0
- /package/dist/{chunk-KWAOTV7F.js.map → chunk-GX6VAHY7.js.map} +0 -0
- /package/dist/{chunk-XG3XCHN6.js.map → chunk-HA5D6US2.js.map} +0 -0
- /package/dist/{chunk-ZNBDKK4Y.js.map → chunk-HWB5DN32.js.map} +0 -0
- /package/dist/{chunk-UKJNLP4A.js.map → chunk-I2Z3Q436.js.map} +0 -0
- /package/dist/{chunk-HSTEQ3RF.js.map → chunk-J6QVRNHE.js.map} +0 -0
- /package/dist/{chunk-IXKEWS7X.js.map → chunk-KIAD2YRA.js.map} +0 -0
- /package/dist/{chunk-FEXDI4NM.js.map → chunk-KSTGP67A.js.map} +0 -0
- /package/dist/{chunk-2SCPDSFN.js.map → chunk-LIQ4SQ2T.js.map} +0 -0
- /package/dist/{chunk-AN447DQB.js.map → chunk-LTGKIBVX.js.map} +0 -0
- /package/dist/{chunk-RRUJQVWA.js.map → chunk-MF5WL2MP.js.map} +0 -0
- /package/dist/{chunk-HXTGYOQC.js.map → chunk-MO7XF4HR.js.map} +0 -0
- /package/dist/{chunk-MRLT6YQM.js.map → chunk-NX6U2JSE.js.map} +0 -0
- /package/dist/{chunk-FHXIEMCG.js.map → chunk-O7NR6OPL.js.map} +0 -0
- /package/dist/{chunk-DIY6QR3E.js.map → chunk-OTDS56OQ.js.map} +0 -0
- /package/dist/{chunk-SJDPHVGE.js.map → chunk-PQEPGP2M.js.map} +0 -0
- /package/dist/{chunk-QXZYAIWS.js.map → chunk-Q4XTRXJV.js.map} +0 -0
- /package/dist/{chunk-BYDF22T4.js.map → chunk-QEGHWJXC.js.map} +0 -0
- /package/dist/{chunk-XYMPS526.js.map → chunk-QKBO6QD2.js.map} +0 -0
- /package/dist/{chunk-3RJ3VGJP.js.map → chunk-R3OD5PVZ.js.map} +0 -0
- /package/dist/{chunk-ZJ47BR6X.js.map → chunk-RNNIKAR7.js.map} +0 -0
- /package/dist/{chunk-HYCIBVDW.js.map → chunk-RWPQW73R.js.map} +0 -0
- /package/dist/{chunk-LO72ZSRR.js.map → chunk-STIQPSLZ.js.map} +0 -0
- /package/dist/{chunk-EIP4PYCL.js.map → chunk-TIOQ7ZFQ.js.map} +0 -0
- /package/dist/{chunk-VBHDZSI5.js.map → chunk-UQFAYC2Y.js.map} +0 -0
- /package/dist/{chunk-OKJYCCHY.js.map → chunk-V47L5CNH.js.map} +0 -0
- /package/dist/{chunk-IPAETHU2.js.map → chunk-VTGEGDKW.js.map} +0 -0
- /package/dist/{chunk-EVYXTT7V.js.map → chunk-XCM6XWOB.js.map} +0 -0
- /package/dist/{chunk-EZUG6WE2.js.map → chunk-YDJMV7BC.js.map} +0 -0
- /package/dist/{chunk-KXRXS6BZ.js.map → chunk-YPKSJRSF.js.map} +0 -0
- /package/dist/{chunk-75VNSKS3.js.map → chunk-Z65HNXZ2.js.map} +0 -0
- /package/dist/{chunk-LO6GEJ4Z.js.map → chunk-ZFKL7UYS.js.map} +0 -0
- /package/dist/{claim-EIL4ZBSN.js.map → claim-GPKFFPWC.js.map} +0 -0
- /package/dist/{companies-2UG7RDYN.js.map → companies-2PQ2BXQO.js.map} +0 -0
- /package/dist/{complete-I4KRFYMD.js.map → complete-LT6PYTQA.js.map} +0 -0
- /package/dist/{connect-TA5W6YGW.js.map → connect-6LR75R2A.js.map} +0 -0
- /package/dist/{conversation-BJI54MI6.js.map → conversation-4DI5N62Z.js.map} +0 -0
- /package/dist/{conversion-report-XQBJ6LG4.js.map → conversion-report-N4HANYOB.js.map} +0 -0
- /package/dist/{conversion-upload-command-JULHGVIR.js.map → conversion-upload-command-TZTHU2CD.js.map} +0 -0
- /package/dist/{conversion-writes-UBCVXP2E.js.map → conversion-writes-LW4HQKK5.js.map} +0 -0
- /package/dist/{conversions-VJOJ5S4U.js.map → conversions-3I2L4J5V.js.map} +0 -0
- /package/dist/{conversions-D236RTUK.js.map → conversions-TS723AZV.js.map} +0 -0
- /package/dist/{create-VY3RQXOY.js.map → create-CDEXO5TQ.js.map} +0 -0
- /package/dist/{create-JLQCXAT2.js.map → create-DCFRBBRW.js.map} +0 -0
- /package/dist/{create-E7BIZNUC.js.map → create-JOJ7PTHG.js.map} +0 -0
- /package/dist/{create-HKOO7O5L.js.map → create-JUSUZ6AH.js.map} +0 -0
- /package/dist/{creatives-KM2XH4G7.js.map → creatives-HFG6KSLV.js.map} +0 -0
- /package/dist/{creatives-VXQQUH2F.js.map → creatives-ODCZ3C2H.js.map} +0 -0
- /package/dist/{critique-CMLAPVUB.js.map → critique-4BFUFNZQ.js.map} +0 -0
- /package/dist/{critique-6MIZLNCN.js.map → critique-X5N53OCQ.js.map} +0 -0
- /package/dist/{crm-CL7R67FT.js.map → crm-GGKMNFLI.js.map} +0 -0
- /package/dist/{crm-GJCAM3DI.js.map → crm-GXLDR5RP.js.map} +0 -0
- /package/dist/{currency-DJDVIR3C.js.map → currency-XCGKQ7FE.js.map} +0 -0
- /package/dist/{customers-4RJGRR2Y.js.map → customers-4D6MXGCQ.js.map} +0 -0
- /package/dist/{delete-IJNJTAGW.js.map → delete-2SBGGQDG.js.map} +0 -0
- /package/dist/{delete-4QXLTL24.js.map → delete-7RI3657I.js.map} +0 -0
- /package/dist/{delete-R57JFJ3A.js.map → delete-L2I54O3F.js.map} +0 -0
- /package/dist/{demographics-VMARSTTE.js.map → demographics-SXCT2YZA.js.map} +0 -0
- /package/dist/{discard-Y2BKPW4Z.js.map → discard-5DCAWO7J.js.map} +0 -0
- /package/dist/{discover-M3ZKKFEL.js.map → discover-BJPZNXUQ.js.map} +0 -0
- /package/dist/{domain-YTHDTRWN.js.map → domain-XD5HZMA3.js.map} +0 -0
- /package/dist/{draft-ABGQYDHP.js.map → draft-B44SVA7P.js.map} +0 -0
- /package/dist/{draft-U6CT6LCC.js.map → draft-BV2QRPZ4.js.map} +0 -0
- /package/dist/{draft-MNFJ4G3C.js.map → draft-THPZFASM.js.map} +0 -0
- /package/dist/{draft-KOLU5BRR.js.map → draft-XNUD2ZX3.js.map} +0 -0
- /package/dist/{draft-ZVVUAMMQ.js.map → draft-XZ2UXMUK.js.map} +0 -0
- /package/dist/{facets-UXN4MYPO.js.map → facets-FGRPLNHJ.js.map} +0 -0
- /package/dist/{fit-KXHYKIA4.js.map → fit-275H7ETA.js.map} +0 -0
- /package/dist/{flows-PB4K66NJ.js.map → flows-DTJHR2HD.js.map} +0 -0
- /package/dist/{fonts-NTOQS2KU.js.map → fonts-SEC67SFN.js.map} +0 -0
- /package/dist/{forecast-RWDIDDWP.js.map → forecast-ZZ7FWJST.js.map} +0 -0
- /package/dist/{funnel-XCKPRYTV.js.map → funnel-ILNHRWXJ.js.map} +0 -0
- /package/dist/{generate-DMQUS665.js.map → generate-6DDI42Y2.js.map} +0 -0
- /package/dist/{get-67IG7SZI.js.map → get-6MJRBEGP.js.map} +0 -0
- /package/dist/{get-WO22OCMZ.js.map → get-CQFJWZSM.js.map} +0 -0
- /package/dist/{history-Q3QCT64S.js.map → history-DBIEYQHY.js.map} +0 -0
- /package/dist/{history-PBFRKLU6.js.map → history-DBR2D4DC.js.map} +0 -0
- /package/dist/{hubspot-PMOZST7W.js.map → hubspot-YPG2W5UP.js.map} +0 -0
- /package/dist/{ideas-PU7IAX6F.js.map → ideas-AV7CYETD.js.map} +0 -0
- /package/dist/{images-QI2HTX6B.js.map → images-F54P6D3N.js.map} +0 -0
- /package/dist/{ingest-ZQM47NVZ.js.map → ingest-G5OVGZUO.js.map} +0 -0
- /package/dist/{ingest-BYJNFOOT.js.map → ingest-RUC3EPHJ.js.map} +0 -0
- /package/dist/{insights-LNAXV2CG.js.map → insights-ZIU6FJMS.js.map} +0 -0
- /package/dist/{inspect-CQH55Q6G.js.map → inspect-6PCX234P.js.map} +0 -0
- /package/dist/{intent-ICKFJRT2.js.map → intent-HG637ISN.js.map} +0 -0
- /package/dist/{keyword-gap-NGPH32FN.js.map → keyword-gap-MBZ4T6PS.js.map} +0 -0
- /package/dist/{keyword-metrics-E3NJUSEQ.js.map → keyword-metrics-C7TN7WVV.js.map} +0 -0
- /package/dist/{keywords-for-site-RH47P4GJ.js.map → keywords-for-site-RXYG74EH.js.map} +0 -0
- /package/dist/{landing-4PA7GCPM.js.map → landing-EPYJ2TYC.js.map} +0 -0
- /package/dist/{languages-JDYL2N5F.js.map → languages-HORKPDNH.js.map} +0 -0
- /package/dist/{leads-I7BO5V7P.js.map → leads-5E3MULCF.js.map} +0 -0
- /package/dist/{learn-HZU3QWNN.js.map → learn-EC73LWRX.js.map} +0 -0
- /package/dist/{line-item-writes-JSR53MID.js.map → line-item-writes-OWDX5TF4.js.map} +0 -0
- /package/dist/{line-items-2WFLKOOR.js.map → line-items-LF4IZCVD.js.map} +0 -0
- /package/dist/{link-AYXOJQDV.js.map → link-D2ZPRSGD.js.map} +0 -0
- /package/dist/{linkedin-M2PVZYLV.js.map → linkedin-3LUIRE76.js.map} +0 -0
- /package/dist/{list-3OKEMUFD.js.map → list-5LXT3MMM.js.map} +0 -0
- /package/dist/{list-4MQC23JH.js.map → list-PYRY2HPB.js.map} +0 -0
- /package/dist/{list-QGLIL7J6.js.map → list-QTFE6CJ2.js.map} +0 -0
- /package/dist/{locations-2NKBJKBT.js.map → locations-74TPQWAT.js.map} +0 -0
- /package/dist/{locations-S4U6IJIS.js.map → locations-J4G5RNPH.js.map} +0 -0
- /package/dist/{log-QHR2JNKW.js.map → log-YOEMOLDG.js.map} +0 -0
- /package/dist/{make-HRCWP2C6.js.map → make-2EK4E4BB.js.map} +0 -0
- /package/dist/{map-3BVFAP33.js.map → map-XMWYNJZI.js.map} +0 -0
- /package/dist/{mcp-LH5KR6RO.js.map → mcp-6HL4CR5E.js.map} +0 -0
- /package/dist/{media-sources-3D246I3O.js.map → media-sources-WFTHXYMZ.js.map} +0 -0
- /package/dist/{members-4DUQHLZH.js.map → members-6FKD5KZ2.js.map} +0 -0
- /package/dist/{metrics-AY4RP54F.js.map → metrics-SQDJ5NQO.js.map} +0 -0
- /package/dist/{models-5NTC7A5G.js.map → models-6T2XV2KB.js.map} +0 -0
- /package/dist/{normalize-CD4PQRYY.js.map → normalize-3JLFCOWS.js.map} +0 -0
- /package/dist/{options-6TE5E34Z.js.map → options-RAHLATMR.js.map} +0 -0
- /package/dist/{performance-7LQQCEAW.js.map → performance-FKL2KHHX.js.map} +0 -0
- /package/dist/{pixels-TZPF746S.js.map → pixels-45A55MOP.js.map} +0 -0
- /package/dist/{promoted-tweet-writes-F76YIMB6.js.map → promoted-tweet-writes-DMFVG63W.js.map} +0 -0
- /package/dist/{promoted-tweets-EJL37P7K.js.map → promoted-tweets-KJYCL6J5.js.map} +0 -0
- /package/dist/{publish-H5S2IKZP.js.map → publish-Y5PALSEY.js.map} +0 -0
- /package/dist/{query-CPZZNMDY.js.map → query-IEZRY6HV.js.map} +0 -0
- /package/dist/{reddit-INGPFGP4.js.map → reddit-CIJFBT32.js.map} +0 -0
- /package/dist/{refresh-MKSKISPX.js.map → refresh-SWW23DAQ.js.map} +0 -0
- /package/dist/{release-J5LIAIZT.js.map → release-FOBIO5QG.js.map} +0 -0
- /package/dist/{relevant-pages-MTMFMBPD.js.map → relevant-pages-MFJEPBR4.js.map} +0 -0
- /package/dist/{remove-LYEK7VFV.js.map → remove-OXAH3ZKL.js.map} +0 -0
- /package/dist/{reopen-FR4UBOG7.js.map → reopen-JFRI6ZR6.js.map} +0 -0
- /package/dist/{rerun-XPWGIVTT.js.map → rerun-73NGMIM7.js.map} +0 -0
- /package/dist/{research-PA53M335.js.map → research-SNMF4JOY.js.map} +0 -0
- /package/dist/{reset-RCYRE5WO.js.map → reset-222UFTF6.js.map} +0 -0
- /package/dist/{reset-H3ES4WV5.js.map → reset-B6JRVIIH.js.map} +0 -0
- /package/dist/{resolve-QIDQJCE6.js.map → resolve-XQCGZYTD.js.map} +0 -0
- /package/dist/{retry-WLVMR7XP.js.map → retry-O6BBBGXP.js.map} +0 -0
- /package/dist/{retry-PLLCFOJW.js.map → retry-TQHVMUU4.js.map} +0 -0
- /package/dist/{run-WMJPDX6U.js.map → run-6L3QS4PP.js.map} +0 -0
- /package/dist/{run-4D7ZCLMF.js.map → run-FDSII53R.js.map} +0 -0
- /package/dist/{scaffold-ad-VYYZIEQ2.js.map → scaffold-ad-WRPLC3JR.js.map} +0 -0
- /package/dist/{scaffold-static-ad-B3SZ2HLW.js.map → scaffold-static-ad-HRLKY5WF.js.map} +0 -0
- /package/dist/{scaffold-video-2QISC5CW.js.map → scaffold-video-LSOSZCVF.js.map} +0 -0
- /package/dist/{schedule-RXUUCNNI.js.map → schedule-KNRJAYCK.js.map} +0 -0
- /package/dist/{scheduled-agents-2NCGSD76.js.map → scheduled-agents-IPZ5QA6C.js.map} +0 -0
- /package/dist/{schema-SFODURN7.js.map → schema-H43I3TR4.js.map} +0 -0
- /package/dist/{search-7QVZOWSI.js.map → search-7CMRZNWL.js.map} +0 -0
- /package/dist/{select-C6CFCOEM.js.map → select-OKF5SLAO.js.map} +0 -0
- /package/dist/{set-prompt-MIMQYMGM.js.map → set-prompt-N54XKRGK.js.map} +0 -0
- /package/dist/{setup-links-XW4A6L2I.js.map → setup-links-2MOYMVEY.js.map} +0 -0
- /package/dist/{site-6UTQSYIK.js.map → site-BDTMN6VB.js.map} +0 -0
- /package/dist/{sources-QQNWQLUM.js.map → sources-4XCN3STL.js.map} +0 -0
- /package/dist/{sources-UGMZFZ2E.js.map → sources-TCEHZ5RV.js.map} +0 -0
- /package/dist/{stale-NOSV6ONW.js.map → stale-J5PKAEBW.js.map} +0 -0
- /package/dist/{status-NXGKJGH7.js.map → status-6AN44KXK.js.map} +0 -0
- /package/dist/{studio-HUEBE6DS.js.map → studio-TM3MAAUW.js.map} +0 -0
- /package/dist/{sync-RXS6BPLM.js.map → sync-TPOVAGPK.js.map} +0 -0
- /package/dist/{sync-definition-2DQN2KN3.js.map → sync-definition-A4SIK5VW.js.map} +0 -0
- /package/dist/{tags-CMBKEXIZ.js.map → tags-CN6I22A5.js.map} +0 -0
- /package/dist/{tags-C65JB762.js.map → tags-N6SF24MU.js.map} +0 -0
- /package/dist/{tags-R3K35KTL.js.map → tags-QITCY5QO.js.map} +0 -0
- /package/dist/{tags-GFFQLLG2.js.map → tags-TMUNXXYN.js.map} +0 -0
- /package/dist/{tags-IJN2SPSM.js.map → tags-U4JDAVUH.js.map} +0 -0
- /package/dist/{targeting-criteria-IHBPLHSX.js.map → targeting-criteria-DRA5JGCZ.js.map} +0 -0
- /package/dist/{targets-JH37NVJF.js.map → targets-B3HWHREZ.js.map} +0 -0
- /package/dist/{templates-HXSHQ23T.js.map → templates-53VD5PEV.js.map} +0 -0
- /package/dist/{testimonials-5QGCPZ6K.js.map → testimonials-NOTV6AON.js.map} +0 -0
- /package/dist/{top-companies-FJEFKVI7.js.map → top-companies-NIG3PBD3.js.map} +0 -0
- /package/dist/{triggers-SEOAAJSS.js.map → triggers-IIUPW5LU.js.map} +0 -0
- /package/dist/{unlink-UZDVSHBO.js.map → unlink-WRF3E3AL.js.map} +0 -0
- /package/dist/{unstage-CE5RRGM5.js.map → unstage-GXHKDXA5.js.map} +0 -0
- /package/dist/{update-JZ4I6WW7.js.map → update-4KUD5OH4.js.map} +0 -0
- /package/dist/{update-ZXOG2V34.js.map → update-6CHXJFMF.js.map} +0 -0
- /package/dist/{update-DGZKEP6T.js.map → update-FGTKHBEG.js.map} +0 -0
- /package/dist/{update-JOS4ITAV.js.map → update-R47RJ5NM.js.map} +0 -0
- /package/dist/{upload-SSOPA7ZT.js.map → upload-3IDNWUH7.js.map} +0 -0
- /package/dist/{url-options-QEWKRKZ3.js.map → url-options-GGXAL3J4.js.map} +0 -0
- /package/dist/{url-params-OR5N5EWT.js.map → url-params-EYHAK4TR.js.map} +0 -0
- /package/dist/{validate-4YXSJA4S.js.map → validate-S3S52QNH.js.map} +0 -0
- /package/dist/{videos-GIYDCCKR.js.map → videos-FH4XUXWR.js.map} +0 -0
- /package/dist/{viewer-check-VN2JK2LW.js.map → viewer-check-5TJ7UGMV.js.map} +0 -0
- /package/dist/{winning-ads-7QWEIMRU.js.map → winning-ads-QMTRP7DI.js.map} +0 -0
- /package/dist/{write-commands-SVJ43D7G.js.map → write-commands-N6ZN3B4E.js.map} +0 -0
- /package/dist/{x-OEAKQBB7.js.map → x-W6GJ63OZ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../api/src/ads-google/limits.ts","../../api/src/ads-google/conversion-upload.ts","../../api/src/ads-google/structured-snippet-headers.ts","../../api/src/ads-google/ops.ts","../../api/src/ads-google/wire.ts"],"sourcesContent":["/**\n * Single source of truth for Google Ads API write constraints (v23). Every zod\n * schema in `ops.ts` reads from here — no scattered literals. Money is in\n * micros (major currency × 1,000,000) everywhere the API expects it.\n */\n\nexport const GOOGLE_ADS_LIMITS = {\n budget: {\n nameMax: 255,\n amountMicrosMin: 1,\n },\n campaign: {\n nameMax: 255,\n /** `campaign.final_url_suffix` — the query string appended to every final URL under the campaign. */\n finalUrlSuffixMax: 2048,\n /** `campaign.tracking_url_template` — the click-measurement URL every ad routes through. */\n trackingUrlTemplateMax: 2048,\n /** `campaign.url_custom_parameters` — Google caps a single entity at 8 `{_name}` parameters. */\n urlCustomParametersMax: 8,\n urlCustomParameterKeyMax: 16,\n urlCustomParameterValueMax: 250,\n /** `campaign.text_guidelines.term_exclusions` — words AI Max and Performance Max must never write. */\n termExclusionsMax: 25,\n termExclusionMax: 30,\n /** `campaign.text_guidelines.messaging_restrictions` — freeform rules for generated text. */\n messagingRestrictionsMax: 40,\n messagingRestrictionMax: 300,\n },\n adGroup: {\n nameMax: 255,\n },\n keyword: {\n textMax: 80,\n wordsMax: 10,\n },\n responsiveSearchAd: {\n headlinesMin: 3,\n headlinesMax: 15,\n headlineTextMax: 30,\n descriptionsMin: 2,\n descriptionsMax: 4,\n descriptionTextMax: 90,\n pathMax: 15,\n },\n responsiveDisplayAd: {\n headlinesMin: 1,\n headlinesMax: 5,\n headlineTextMax: 30,\n longHeadlineTextMax: 90,\n descriptionsMin: 1,\n descriptionsMax: 5,\n descriptionTextMax: 90,\n businessNameMax: 25,\n },\n appAd: {\n headlinesMin: 1,\n headlinesMax: 5,\n headlineTextMax: 30,\n descriptionsMin: 1,\n descriptionsMax: 5,\n descriptionTextMax: 90,\n imagesMax: 20,\n youtubeVideosMax: 20,\n },\n /** `DemandGenMultiAssetAdInfo` — the image-carrying Demand Gen ad. No long headline exists on it. */\n demandGenAd: {\n adNameMax: 255,\n headlinesMin: 1,\n headlinesMax: 5,\n headlineTextMax: 40,\n descriptionsMin: 1,\n descriptionsMax: 5,\n descriptionTextMax: 90,\n businessNameMax: 25,\n },\n /**\n * `DemandGenVideoResponsiveAdInfo` — the Demand Gen ad that runs a YouTube video. It is the only\n * ad format with BOTH a headline list and a long-headline list, which is why its copy has no home\n * in `demandGenAd`: every content schema is strict, so a payload naming `longHeadlines` there is\n * refused, and before this format existed a served Demand Gen video ad could not be edited at all.\n */\n demandGenVideoAd: {\n adNameMax: 255,\n headlinesMin: 1,\n headlinesMax: 5,\n headlineTextMax: 40,\n longHeadlinesMin: 1,\n longHeadlinesMax: 5,\n longHeadlineTextMax: 90,\n descriptionsMin: 1,\n descriptionsMax: 5,\n descriptionTextMax: 90,\n businessNameMax: 25,\n },\n sharedSet: {\n nameMax: 255,\n },\n asset: {\n sitelinkLinkTextMax: 25,\n sitelinkDescriptionMax: 35,\n calloutTextMax: 25,\n // A snippet's HEADER has no length limit of its own — it has to be one of\n // Google's published headers (`structured-snippet-headers.ts`), the longest\n // of which is 29 characters. Only the values are capped.\n structuredSnippetValuesMin: 3,\n structuredSnippetValuesMax: 10,\n /**\n * Per VALUE, not per asset. Google rejects a 26-character value with a bare \"Too long.\" at\n * `structured_snippet_asset.values[i]` — one red row inside an otherwise clean publish, plus\n * every link that depends on the asset. Confirmed live on v23: \"Bases de datos vectoriales\"\n * (26) rejected, its four neighbours accepted.\n */\n structuredSnippetValueMax: 25,\n },\n conversionAction: {\n nameMax: 255,\n },\n audience: {\n nameMax: 255,\n },\n biddingStrategy: {\n nameMax: 255,\n },\n label: {\n nameMax: 255,\n },\n assetGroup: {\n nameMax: 255,\n headlinesMin: 3,\n headlinesMax: 15,\n headlineTextMax: 30,\n longHeadlinesMin: 1,\n longHeadlinesMax: 5,\n longHeadlineTextMax: 90,\n descriptionsMin: 2,\n descriptionsMax: 5,\n descriptionTextMax: 90,\n businessNameMax: 25,\n },\n} as const;\n\n/**\n * Most rows one `/api/ads/google/query` read returns — the route refuses a larger `pageSize`, the CLI a\n * larger `--limit` or statement LIMIT. Google pages at 10000, but a Convex function returns at most 8192\n * array items, so a larger page fails the route as a bare internal error.\n */\nexport const GOOGLE_ADS_QUERY_MAX_PAGE_SIZE = 8192;\n\nexport const KEYWORD_MATCH_TYPES = [\"EXACT\", \"PHRASE\", \"BROAD\"] as const;\nexport type GoogleKeywordMatchType = (typeof KEYWORD_MATCH_TYPES)[number];\n\nexport const ADVERTISING_CHANNEL_TYPES = [\n \"SEARCH\",\n \"DISPLAY\",\n \"SHOPPING\",\n \"VIDEO\",\n \"PERFORMANCE_MAX\",\n \"DEMAND_GEN\",\n \"MULTI_CHANNEL\",\n \"LOCAL\",\n \"SMART\",\n \"TRAVEL\",\n \"HOTEL\",\n // This constant has ONE consumer — `campaignCreateSchema.channelType` — so it is a write-side\n // allowlist, not a vocabulary. A value belongs here only if Baker can legitimately create a\n // campaign of that type. GAQL reads never pass through it (`listSizeRequirement` takes the raw\n // string straight off the row, deliberately), so adding a channel here buys no read coverage.\n //\n // Two omissions are therefore deliberate. DISCOVERY used to sit here: Google renamed it\n // DEMAND_GEN and dropped the old name from the v23 enum, so a campaign staged as DISCOVERY could\n // only ever fail at publish — inside an atomic batch, taking every co-staged op down with it.\n // LOCAL_SERVICES is a real v23 channel but is not creatable through the API; Google's own LSA\n // migration produces those campaigns. Accepting either one would stage a campaign that passes\n // validation, reaches a review card a user approves, and then fails the whole publish.\n] as const;\nexport type GoogleAdvertisingChannelType = (typeof ADVERTISING_CHANNEL_TYPES)[number];\n\nexport const ADVERTISING_CHANNEL_SUB_TYPES = [\n \"SEARCH_MOBILE_APP\",\n \"DISPLAY_MOBILE_APP\",\n \"SEARCH_EXPRESS\",\n \"DISPLAY_EXPRESS\",\n \"SHOPPING_SMART_ADS\",\n \"DISPLAY_GMAIL_AD\",\n \"DISPLAY_SMART_CAMPAIGN\",\n \"VIDEO_OUTSTREAM\",\n \"VIDEO_ACTION\",\n \"VIDEO_NON_SKIPPABLE\",\n \"APP_CAMPAIGN\",\n \"APP_CAMPAIGN_FOR_ENGAGEMENT\",\n \"LOCAL_CAMPAIGN\",\n \"SHOPPING_COMPARISON_LISTING_ADS\",\n \"SEARCH_MOBILE_APP_ENGAGEMENT\",\n \"TRAVEL_ACTIVITIES\",\n] as const;\nexport type GoogleAdvertisingChannelSubType = (typeof ADVERTISING_CHANNEL_SUB_TYPES)[number];\n\nexport const BIDDING_STRATEGY_TYPES = [\n \"MANUAL_CPC\",\n \"MAXIMIZE_CONVERSIONS\",\n \"MAXIMIZE_CONVERSION_VALUE\",\n \"TARGET_SPEND\",\n \"TARGET_CPA\",\n \"TARGET_ROAS\",\n \"TARGET_IMPRESSION_SHARE\",\n \"MANUAL_CPM\",\n \"MANUAL_CPV\",\n \"PERCENT_CPC\",\n // Demand Gen's \"maximize clicks at a target CPC\" — `Campaign.target_cpc`, overridable per ad\n // group via `AdGroup.target_cpc_micros`. Confirmed present in v23.\n // It is one of the target-driven strategies governed by the August 2026 budget-limited\n // change, so modelling it as a strategy without a target would leave a Demand Gen\n // campaign's exposure invisible to `biddingTargetWarnings`.\n \"TARGET_CPC\",\n] as const;\nexport type GoogleBiddingStrategyType = (typeof BIDDING_STRATEGY_TYPES)[number];\n\n/**\n * Channels where Google folded the standalone Target CPA / Target ROAS strategies into Maximize\n * conversions / Maximize conversion value (2021). On one of these, the target lives at\n * `campaign.maximize_conversions.target_cpa_micros`, and writing the legacy `campaign.target_cpa`\n * comes back `ContextError.OPERATION_NOT_PERMITTED_FOR_CONTEXT` — confirmed live on v23 against a\n * Search campaign (request GphdG5HKabzlUWQqjGne9w, at\n * `mutate_operations[109].campaign_operation.update.target_cpa`).\n *\n * `SEARCH` alone, deliberately. Google's own announcement of the merge covers Search campaigns, and\n * the field is still the live one on App, Display and Video, where a blanket refusal would block a\n * legitimate edit. The June 2026 relabel that brings \"Target CPA\" back as its own option in the UI\n * is cosmetic — it renames the same Maximize-conversions-with-a-target strategy and does not make\n * `campaign.target_cpa` settable again. Widen this set only against a live rejection, the way this\n * entry was earned.\n */\nconst MERGED_TARGET_STRATEGY_CHANNELS = new Set([\"SEARCH\"]);\n\n/**\n * Shared by the CLI-boundary refusal on a campaign create, the stage-time refusal on a campaign\n * update, and the publish-time humanizer — so all three tell the user the same thing.\n *\n * Names the route, because the strategy the user asked for is not gone: it is the same bidding under\n * the name Google now files it under, one flag away. Saying only \"not allowed\" would send a marketer\n * looking for a setting that no longer exists.\n */\nexport const MERGED_TARGET_CPA_MESSAGE =\n \"Google doesn't accept Target CPA as a bidding strategy of its own on a Search campaign — the target sits inside Maximize conversions. Choose Maximize conversions and give it the same target CPA; it bids exactly the same.\";\n\n/** The Target ROAS half of {@link MERGED_TARGET_CPA_MESSAGE}. */\nexport const MERGED_TARGET_ROAS_MESSAGE =\n \"Google doesn't accept Target ROAS as a bidding strategy of its own on a Search campaign — the target sits inside Maximize conversion value. Choose Maximize conversion value and give it the same target ROAS; it bids exactly the same.\";\n\n/**\n * Why this inline bidding strategy can't be set on this campaign, or undefined to let it through.\n *\n * Only a positively-read channel refuses: an unknown channel (a stage-time read that missed, an\n * op that never carried one) falls through to publish, where the partial-failure isolation and the\n * humanized message are the backstop. Blocking a legitimate change is worse than failing one.\n *\n * Portfolio strategies are not covered on purpose — `BiddingStrategy` still takes a standalone\n * `target_cpa` / `target_roas`, and a Search campaign may point at one.\n */\nexport function mergedTargetStrategyRefusal(\n channelType: string | undefined,\n biddingType: string | undefined,\n): string | undefined {\n if (channelType === undefined || !MERGED_TARGET_STRATEGY_CHANNELS.has(channelType)) {\n return undefined;\n }\n if (biddingType === \"TARGET_CPA\") {\n return MERGED_TARGET_CPA_MESSAGE;\n }\n return biddingType === \"TARGET_ROAS\" ? MERGED_TARGET_ROAS_MESSAGE : undefined;\n}\n\n/**\n * The route out of {@link EMBEDDED_TARGET_CPA_DEMAND_GEN_MESSAGE} — named, not just refused, because\n * the bidding the user asked for is available here, under the other spelling.\n */\nexport const EMBEDDED_TARGET_CPA_DEMAND_GEN_MESSAGE =\n \"Google doesn't accept a target CPA inside Maximize conversions on a Demand Gen campaign — there the target is its own bidding strategy. Choose Target CPA and give it the same target; it bids exactly the same.\";\n\n/**\n * The exact inverse of {@link mergedTargetStrategyRefusal}, and the reason both have to exist.\n *\n * On Search, Google merged Target CPA into Maximize conversions, so the target rides inside that\n * strategy and a standalone `TARGET_CPA` is refused. On Demand Gen the opposite holds: the target is\n * its own strategy, and `maximize_conversions.target_cpa_micros` is refused. So the single rule\n * \"put the target inside Maximize conversions\" — correct on Search, and the one the CLI's own\n * `--target-cpa` help teaches — publishes a rejected op the moment it is applied to a Demand Gen\n * campaign. That is not hypothetical: two campaigns on one account, both\n * `{\"maximizeConversions\":{\"targetCpaMicros\":…}}` with `updateMask` `maximizeConversions.targetCpaMicros`,\n * both answered `OPERATION_NOT_PERMITTED_FOR_CONTEXT` (\"The operation is not allowed for the given\n * context.\") after the Session had already merged and gone live.\n *\n * `DEMAND_GEN` alone, and Target CPA alone, deliberately — the same discipline the Search entry\n * documents. Google's Maximize conversion value carries `target_roas` in the same embedded shape and\n * it may well be refused here too, but nothing has rejected one yet, and a refusal invented ahead of\n * its evidence blocks a change that would have worked. Widen this against a live rejection, not a\n * hunch.\n */\nexport function embeddedTargetOnDemandGenRefusal(\n channelType: string | undefined,\n bidding: { type?: string; targetCpaMicros?: number } | undefined,\n): string | undefined {\n if (channelType !== \"DEMAND_GEN\" || bidding?.type !== \"MAXIMIZE_CONVERSIONS\") {\n return undefined;\n }\n return bidding.targetCpaMicros === undefined ? undefined : EMBEDDED_TARGET_CPA_DEMAND_GEN_MESSAGE;\n}\n\n/** The route out of {@link manualCpcOnDemandGenRefusal}, naming bidding that has been published on this channel. */\nexport const MANUAL_CPC_DEMAND_GEN_MESSAGE =\n \"Google doesn't accept Manual CPC on a Demand Gen campaign. Choose Maximize conversions (with a Target CPA as its own strategy if you have a target), or Target CPC, which exists on this channel alone.\";\n\n/**\n * Manual CPC on Demand Gen, the third per-channel bidding rule and the one that was being actively\n * taught: the Demand Gen playbook that ships in every sandbox said to use `MANUAL_CPC` \"as the click\n * proxy\" for prospecting. Google answers the create with `OPERATION_NOT_PERMITTED_FOR_CONTEXT` at\n * `campaign_operation.create.manual_cpc`, and because a campaign create is one operation inside an\n * atomic batch, the ad group, the ad and every asset staged with it fail too. Confirmed live on v23,\n * then confirmed the other way by publishing the same campaign with `MAXIMIZE_CONVERSIONS`.\n *\n * Same discipline as its siblings: `DEMAND_GEN` alone, `MANUAL_CPC` alone, and an unread channel\n * falls through to publish.\n */\nexport function manualCpcOnDemandGenRefusal(\n channelType: string | undefined,\n biddingType: string | undefined,\n): string | undefined {\n return channelType === \"DEMAND_GEN\" && biddingType === \"MANUAL_CPC\" ? MANUAL_CPC_DEMAND_GEN_MESSAGE : undefined;\n}\n\n/** The Demand-Gen-only half of {@link MERGED_TARGET_CPA_MESSAGE}, and named the same way: route, not verdict. */\nexport const TARGET_CPC_DEMAND_GEN_MESSAGE =\n \"Google only accepts Target CPC on a Demand Gen campaign — no other campaign type has a target CPC. Pick the bidding this campaign's type supports (Maximize conversions with a target CPA on Search), or set the target CPC on the Demand Gen campaign that should carry it.\";\n\n/**\n * The mirror image of {@link mergedTargetStrategyRefusal}: that one names the channels a strategy is\n * refused ON, this one names the only channel a strategy is accepted on. `Campaign.target_cpc` exists\n * on Demand Gen alone, so the same op staged against Search, Display or Video passes every payload\n * check and then fails the whole atomic publish batch.\n *\n * Same conservatism, for the same reason: an unknown channel falls through to publish rather than\n * blocking a change that may well be legitimate.\n */\nexport function demandGenOnlyStrategyRefusal(\n channelType: string | undefined,\n biddingType: string | undefined,\n): string | undefined {\n if (biddingType !== \"TARGET_CPC\" || channelType === undefined || channelType === \"DEMAND_GEN\") {\n return undefined;\n }\n return TARGET_CPC_DEMAND_GEN_MESSAGE;\n}\n\n/**\n * `campaign.geo_target_type_setting` — Google's \"Location options\": who a location targets.\n *\n * `PRESENCE_OR_INTEREST` is what Google applies when the setting is omitted on a create, so a\n * campaign staged without it goes live reaching people merely *interested* in the location.\n * `SEARCH_INTEREST` is in the proto but no longer settable (Google retired it in 2023), so it is\n * deliberately absent — offering it would stage an op that fails the whole atomic publish batch.\n */\nexport const POSITIVE_GEO_TARGET_TYPES = [\"PRESENCE_OR_INTEREST\", \"PRESENCE\"] as const;\nexport type GooglePositiveGeoTargetType = (typeof POSITIVE_GEO_TARGET_TYPES)[number];\n\n/** Exclusions: `PRESENCE` (Google's default) excludes only people in the location. */\nexport const NEGATIVE_GEO_TARGET_TYPES = [\"PRESENCE_OR_INTEREST\", \"PRESENCE\"] as const;\nexport type GoogleNegativeGeoTargetType = (typeof NEGATIVE_GEO_TARGET_TYPES)[number];\n\nexport const BUDGET_DELIVERY_METHODS = [\"STANDARD\", \"ACCELERATED\"] as const;\nexport type GoogleBudgetDeliveryMethod = (typeof BUDGET_DELIVERY_METHODS)[number];\n\n/**\n * Mirrors v23's `AdGroupTypeEnum.AdGroupType`. Two values that were here are not in it:\n * `DEMAND_GEN_AD` and `VIDEO_OUTSTREAM`.\n *\n * `DEMAND_GEN_AD` was rejected live while publishing a Demand Gen video ad, with a request-level\n * `Invalid value at '…ad_group_operation.create.type'` — not a partial failure: it takes the WHOLE\n * mutate batch down, so the budget, campaign, asset and ad staged alongside it all failed with the\n * ad group's error. `VIDEO_OUTSTREAM` was never published, so it was confirmed the cheap way\n * instead — the API refuses a query filtering `ad_group.type = 'VIDEO_OUTSTREAM'` where\n * `'VIDEO_RESPONSIVE'` answers, and neither the name nor its old enum number is in v23.\n * `VIDEO_RESPONSIVE` and `VIDEO_EFFICIENT_REACH` are two v23 values Baker never offered.\n *\n * **A Demand Gen ad group has no type of its own**: the enum has no value for it, and Google derives\n * it from the campaign's channel when `type` is left unset — which is why `type` is now optional\n * rather than defaulted (see `adGroupCreateSchema`).\n */\nexport const AD_GROUP_TYPES = [\n \"SEARCH_STANDARD\",\n \"DISPLAY_STANDARD\",\n \"SHOPPING_PRODUCT_ADS\",\n \"VIDEO_BUMPER\",\n \"VIDEO_TRUE_VIEW_IN_STREAM\",\n \"VIDEO_TRUE_VIEW_IN_DISPLAY\",\n \"VIDEO_NON_SKIPPABLE_IN_STREAM\",\n \"VIDEO_RESPONSIVE\",\n \"VIDEO_EFFICIENT_REACH\",\n] as const;\nexport type GoogleAdGroupType = (typeof AD_GROUP_TYPES)[number];\n\nexport const SHARED_SET_TYPES = [\n \"NEGATIVE_KEYWORDS\",\n \"NEGATIVE_PLACEMENTS\",\n \"ACCOUNT_LEVEL_NEGATIVE_KEYWORDS\",\n] as const;\nexport type GoogleSharedSetType = (typeof SHARED_SET_TYPES)[number];\n\nexport const AD_FORMATS = [\n \"responsiveSearch\",\n \"responsiveDisplay\",\n \"performanceMaxAssetGroup\",\n \"demandGen\",\n \"call\",\n \"app\",\n \"video\",\n] as const;\nexport type GoogleAdFormat = (typeof AD_FORMATS)[number];\n\nexport const ENTITY_STATUSES = [\"ENABLED\", \"PAUSED\", \"REMOVED\"] as const;\nexport type GoogleEntityStatus = (typeof ENTITY_STATUSES)[number];\n\n/** Statuses a create op may carry — a create can't be born REMOVED. */\nexport const STAGEABLE_CREATE_STATUSES = [\"ENABLED\", \"PAUSED\"] as const;\n\nexport const PINNED_FIELDS = [\"HEADLINE_1\", \"HEADLINE_2\", \"HEADLINE_3\", \"DESCRIPTION_1\", \"DESCRIPTION_2\"] as const;\nexport type GooglePinnedField = (typeof PINNED_FIELDS)[number];\n\nexport const CONVERSION_ACTION_CATEGORIES = [\n \"DEFAULT\",\n \"PAGE_VIEW\",\n \"PURCHASE\",\n \"SIGNUP\",\n \"LEAD\",\n \"DOWNLOAD\",\n \"ADD_TO_CART\",\n \"BEGIN_CHECKOUT\",\n \"SUBSCRIBE_PAID\",\n \"PHONE_CALL_LEAD\",\n \"SUBMIT_LEAD_FORM\",\n \"BOOK_APPOINTMENT\",\n \"REQUEST_QUOTE\",\n \"CONTACT\",\n] as const;\n\nexport const CONVERSION_ACTION_TYPES = [\n \"WEBPAGE\",\n \"UPLOAD_CLICKS\",\n \"UPLOAD_CALLS\",\n \"WEBSITE_CALL\",\n \"GOOGLE_ANALYTICS_4_CUSTOM\",\n] as const;\n\nexport const CONVERSION_COUNTING_TYPES = [\"ONE_PER_CLICK\", \"MANY_PER_CLICK\"] as const;\n\n/**\n * Google's `ConversionOrigin` — WHERE a conversion happens. Together with a `ConversionActionCategory`\n * it is the whole key of a `CustomerConversionGoal`, the account-level switch that decides whether a\n * conversion category counts toward automated bidding at all.\n *\n * `UNSPECIFIED` and `UNKNOWN` are deliberately absent. Google returns them, but never keys a real goal\n * on one, so an op carrying either could only address a goal that does not exist — and it would spend\n * a publish to find that out.\n */\nexport const CONVERSION_ORIGINS = [\n \"WEBSITE\",\n \"GOOGLE_HOSTED\",\n \"APP\",\n \"CALL_FROM_ADS\",\n \"STORE\",\n \"YOUTUBE_HOSTED\",\n] as const;\nexport type GoogleConversionOrigin = (typeof CONVERSION_ORIGINS)[number];\n\nexport const USER_LIST_TYPES = [\"CRM_BASED\", \"RULE_BASED\", \"LOGICAL\", \"BASIC\", \"LOOKALIKE\"] as const;\n\n/**\n * The targeting dimensions a `TargetingSetting.target_restrictions` row can name. Baker only ever\n * SETS the AUDIENCE one; the rest are here because a write replaces the whole repeated field, so\n * every dimension already on the account has to be readable in order to be sent back untouched.\n */\nexport const TARGETING_DIMENSIONS = [\n \"KEYWORD\",\n \"AUDIENCE\",\n \"TOPIC\",\n \"GENDER\",\n \"AGE_RANGE\",\n \"PLACEMENT\",\n \"PARENTAL_STATUS\",\n \"INCOME_RANGE\",\n] as const;\nexport type GoogleTargetingDimension = (typeof TARGETING_DIMENSIONS)[number];\n\nexport const ASSET_TYPES = [\n \"text\",\n \"image\",\n \"youtubeVideo\",\n \"sitelink\",\n \"callout\",\n \"structuredSnippet\",\n \"callToAction\",\n] as const;\nexport type GoogleAssetType = (typeof ASSET_TYPES)[number];\n\nexport const ASSET_FIELD_TYPES = [\n \"SITELINK\",\n \"CALLOUT\",\n \"STRUCTURED_SNIPPET\",\n \"CALL\",\n \"PRICE\",\n \"PROMOTION\",\n \"MOBILE_APP\",\n \"HEADLINE\",\n \"DESCRIPTION\",\n \"LOGO\",\n /**\n * Kept because a draft staged before {@link IMAGE_ASSET_LINK_MESSAGE} shipped may still carry one,\n * and because it is the field type an asset-group image occupies. It is refused on an\n * `assetLink.attach` — see that message for what Google actually does with it.\n */\n \"MARKETING_IMAGE\",\n \"BUSINESS_NAME\",\n /**\n * The one image link a Search campaign takes. It carries the advertiser's logo beside the ad and\n * is the only image field type that survives Google's field-type check at all — swept live on v23\n * and v25, campaign and customer level both answer `CUSTOMER_NOT_VERIFIED` (an account fact,\n * fixed by advertiser verification) rather than a field-type refusal. Ad group level is not a\n * level Google links it at — see {@link BUSINESS_LOGO_LEVEL_MESSAGE}.\n */\n \"BUSINESS_LOGO\",\n] as const;\n\n/** The levels Google links a `BUSINESS_LOGO` at: campaign and customer, never ad group. */\nexport const BUSINESS_LOGO_LEVELS = [\"campaign\", \"customer\"] as const;\n\nexport const BUSINESS_LOGO_LEVEL_MESSAGE =\n \"Google links a BUSINESS_LOGO at campaign or customer level only — an ad group link comes back \" +\n \"UNSUPPORTED_FIELD_TYPE. Attach it to the campaign instead.\";\n\n/**\n * The image field types an `assetLink.attach` can name. `AD_IMAGE` is the Search image extension and\n * is decided per account at stage time; the marketing-image ones are Performance Max asset-group\n * slots that no Search link takes.\n */\nconst IMAGE_ASSET_LINK_FIELD_TYPES = new Set([\n \"MARKETING_IMAGE\",\n \"SQUARE_MARKETING_IMAGE\",\n \"PORTRAIT_MARKETING_IMAGE\",\n \"AD_IMAGE\",\n]);\n\n/**\n * Google opens `AD_IMAGE` links (image extensions on Search) per advertiser account, and says so\n * nowhere a read can see. Checked live with `validate_only` on v25, Oct 2026:\n *\n * - Our harness account 3865083115 (no Search spend) answers `UNSUPPORTED_FIELD_TYPE` — \"not\n * supported to be added directly through asset links\" — at campaign, ad group and customer level,\n * on every campaign, on v23–v25. Google's v12 notes ship the field type \"for allowlisted\n * customers\"; the Help Center opens Search images to accounts with 60+ days of history and recent\n * Search spend.\n * - A client account with Search spend validates the very same six-image campaign link clean (200).\n *\n * So the stage asks Google (`adImageLinkAccepted`, `ads/google/writes/stage.ts`): accepted → the link\n * stages and applies at publish like a sitelink; refused → it is skipped with this message and Baker\n * stages the handover Task. `MARKETING_IMAGE` on a Search campaign is always refused\n * (`FIELD_TYPE_INCOMPATIBLE_WITH_CAMPAIGN_TYPE` — the six red rows of the production publish that\n * started this) and is sent back to `AD_IMAGE` with {@link SEARCH_IMAGE_FIELD_TYPE_MESSAGE}.\n *\n * **The upload half is never blocked, and saying otherwise costs the user real work.** In that\n * production publish all six uploads applied and only the links failed, while Baker told the\n * advertiser to upload the images. So a refusal ends in a handover, not a dead end.\n */\nexport const IMAGE_ASSET_LINK_MESSAGE =\n \"Google refuses the LINK, not the upload — so do not stop at this refusal, finish the handover. \" +\n \"Google opens image extensions on Search per advertiser account, and it answered that this account \" +\n \"does not take them through Baker. So stage the image assets anyway: `assets create` with an image \" +\n \"still publishes, and the image lands in the advertiser's Google Ads asset library. This link is skipped rather than \" +\n \"stored, so it costs nothing, and it is what records which images go on which campaign: Baker has \" +\n \"staged the handover Task from it, so do not stage a second one with `baker actions`. Tell the user \" +\n \"the images are already in their Google Ads account and only need adding to the campaign under \" +\n \"Assets — name them. Never tell them to upload the images; they are uploaded. The other image a \" +\n \"Search campaign takes through a link is the advertiser's logo — BUSINESS_LOGO at campaign or \" +\n \"customer level, on a verified account.\";\n\n/**\n * The `AD_IMAGE` link was not confirmed either way: Google's check failed for a reason that is not the\n * account gate, or could not be asked. The handover Task is still staged — a minute in Google Ads\n * beats images left off the campaign — but the agent is not told Google refuses, because it may not.\n */\nexport const IMAGE_LINK_UNCONFIRMED_MESSAGE =\n \"Not staged: Baker could not confirm with Google that this account takes image links on Search \" +\n \"(the check failed for a reason other than the account's own setting), so it staged the handover Task \" +\n \"instead — do not stage a second one with `baker actions`. The images are already in the advertiser's \" +\n \"Google Ads account; tell the user they only need adding to the campaign under Assets, and name them. \" +\n \"Do not tell them Google refuses images on their account — that was not established.\";\n\n/** A marketing-image field type on a campaign/ad group/customer link, which no Search campaign takes. */\nexport const SEARCH_IMAGE_FIELD_TYPE_MESSAGE =\n 'Not staged: a Search image extension links as AD_IMAGE — restage this link with \"fieldType\":\"AD_IMAGE\" in its --file payload. ' +\n \"MARKETING_IMAGE, SQUARE_MARKETING_IMAGE and PORTRAIT_MARKETING_IMAGE are Performance Max asset-group \" +\n \"slots (`asset-groups attach`); Google refuses them on a Search campaign.\";\n\n/** Whether this asset-link field type is an image slot Google refuses through an asset link. */\nexport function isImageAssetLinkFieldType(fieldType: string): boolean {\n return IMAGE_ASSET_LINK_FIELD_TYPES.has(fieldType);\n}\n\n/**\n * `AssetGroupAsset.AssetFieldType` — the field types an asset can occupy inside a Performance Max\n * asset group. A different enum from `ASSET_FIELD_TYPES` above, which types campaign/adGroup/customer\n * `AssetLink`s: this one carries the PMax-only ratios and LONG_HEADLINE, and drops the extension\n * field types (SITELINK/CALLOUT/PRICE/…) that cannot live on an asset group.\n */\nexport const ASSET_GROUP_ASSET_FIELD_TYPES = [\n \"MARKETING_IMAGE\",\n \"SQUARE_MARKETING_IMAGE\",\n \"PORTRAIT_MARKETING_IMAGE\",\n \"LOGO\",\n \"LANDSCAPE_LOGO\",\n \"YOUTUBE_VIDEO\",\n \"HEADLINE\",\n \"LONG_HEADLINE\",\n \"DESCRIPTION\",\n \"BUSINESS_NAME\",\n \"CALL_TO_ACTION_SELECTION\",\n] as const;\nexport type GoogleAssetGroupAssetFieldType = (typeof ASSET_GROUP_ASSET_FIELD_TYPES)[number];\n\nexport const DEVICE_TYPES = [\"MOBILE\", \"TABLET\", \"DESKTOP\", \"CONNECTED_TV\", \"OTHER\"] as const;\nexport const DAYS_OF_WEEK = [\"MONDAY\", \"TUESDAY\", \"WEDNESDAY\", \"THURSDAY\", \"FRIDAY\", \"SATURDAY\", \"SUNDAY\"] as const;\n\n/** Google Ads UI objective — advisory only (drives warnings, not an API field). */\nexport const CAMPAIGN_OBJECTIVES = [\n \"SALES\",\n \"LEADS\",\n \"WEBSITE_TRAFFIC\",\n \"PRODUCT_BRAND_CONSIDERATION\",\n \"BRAND_AWARENESS_REACH\",\n \"APP_PROMOTION\",\n \"LOCAL_STORE_VISITS\",\n] as const;\nexport type GoogleCampaignObjective = (typeof CAMPAIGN_OBJECTIVES)[number];\n\nexport const MICROS_PER_UNIT = 1_000_000;\n\nexport function toMicros(amount: number): number {\n return Math.round(amount * MICROS_PER_UNIT);\n}\n\nexport function fromMicros(micros: number): number {\n return micros / MICROS_PER_UNIT;\n}\n\n/** Indicative daily-budget floor (advisory warning; Google enforces real minimums at apply). */\nexport const PLAYBOOK_DAILY_BUDGET_FLOOR_MICROS = 10 * MICROS_PER_UNIT;\n\nexport const TEMP_REF_PREFIX = \"g_temp_\";\nexport const TEMP_REF_REGEX = /^g_temp_[A-Za-z0-9_-]{2,}$/;\nexport const NUMERIC_ID_REGEX = /^\\d+$/;\n/** A Google Ads resource name, e.g. customers/123/campaigns/456. */\nexport const RESOURCE_NAME_REGEX = /^customers\\/\\d+\\/[A-Za-z]+\\/[-\\w~]+$/;\nexport const GEO_TARGET_CONSTANT_REGEX = /^geoTargetConstants\\/\\d+$/;\nexport const LANGUAGE_CONSTANT_REGEX = /^languageConstants\\/\\d+$/;\n\nexport const SIMULATED_RESOURCE_PREFIX = \"simulated-\";\n\n/**\n * The only image shapes an App campaign ad accepts (`AppAdInfo.images`): landscape 1.91:1,\n * square 1:1, portrait 4:5. A 16:9 image is NOT a landscape App image — it is 7% off 1.91:1\n * and Google rejects the whole ad mutate with \"The aspect ratio of the image does not match\n * the expected aspect ratios provided in the asset spec\", naming nothing.\n */\nexport const APP_AD_IMAGE_ASPECT_RATIOS = [\n { label: \"1.91:1\", ratio: 1.91 },\n { label: \"1:1\", ratio: 1 },\n { label: \"4:5\", ratio: 0.8 },\n] as const;\n\n/**\n * The shapes an `AD_IMAGE` link (a Search image extension) takes: landscape and square. Narrower than\n * the App-ad set on purpose — a shape Google might also take costs a handover Task, a shape it refuses\n * costs a publish failure with the Task already withdrawn.\n */\nexport const SEARCH_IMAGE_ASPECT_RATIOS = [\n { label: \"1.91:1\", ratio: 1.91 },\n { label: \"1:1\", ratio: 1 },\n] as const;\n\n/** Relative tolerance Google allows around each accepted ratio — wide enough for rounding, narrow enough to reject 16:9. */\nexport const APP_AD_IMAGE_ASPECT_TOLERANCE = 0.02;\n","/**\n * Manual conversion upload — the contract for re-sending conversions Google never received.\n *\n * Every other staged Google op describes a change to the ACCOUNT's configuration and applies as a\n * `GoogleAdsService.Mutate` operation. This one describes measurement that already happened and\n * applies through Data Manager `events:ingest` — the same endpoint the server-side tag\n * (`sideEffects/googleAdsCapi`) posts to on every live conversion. It exists for the case that\n * endpoint failed: a connection that had lost the `datamanager` scope, an outage, a tag that was\n * misconfigured for a week. The conversions are real, the account simply never heard about them.\n *\n * Because a conversion is only ever uploaded to REPAIR a gap, the row's `orderId` is required and is\n * the same order id the original submission carried. Google recognises an upload it has already\n * recorded by that id, so a re-send of something that did land is a correction rather than a second\n * conversion — which is what makes a backfill safe to run when nobody is sure how much was lost.\n *\n * Identifiers are hashed before anything is stored: the staged draft, the publish request and the\n * write log all hold SHA-256 hex, never an address. See `writes/conversionUpload.ts`.\n */\nimport { z } from \"zod\";\nimport { NUMERIC_ID_REGEX, RESOURCE_NAME_REGEX } from \"./limits\";\n\n/**\n * Rows per staged op. Well under what `events:ingest` accepts in one request — the ceiling that\n * matters here is the review: a draft card nobody can read is not a change anybody approved, and a\n * backfill larger than this is several days' repair that should stage (and fail) day by day.\n */\nexport const CONVERSION_UPLOAD_MAX_ROWS = 200;\n\n/** A SHA-256 hex digest — what a hashed identifier looks like once `stageConversionUpload` is done with it. */\nexport const SHA256_HEX_REGEX = /^[0-9a-f]{64}$/i;\n\n/** The conversion action the rows are recorded against: a bare numeric id or its full resource name. */\nexport const conversionUploadActionSchema = z.union([\n z.string().regex(NUMERIC_ID_REGEX, \"expected the numeric conversion action id\"),\n z.string().regex(RESOURCE_NAME_REGEX, \"expected a customers/…/conversionActions/… resource name\"),\n]);\n\n/**\n * Google's click identifiers are URL-safe tokens. Validated by shape rather than by provider —\n * a `gclid` copied out of a spreadsheet routinely arrives wrapped in quotes or with a stray `?gclid=`\n * still attached, and both reach Google as an id it has never issued, where the upload is accepted\n * and attributed to nothing.\n */\nconst clickIdSchema = z\n .string()\n .min(1)\n .max(512)\n .regex(/^[A-Za-z0-9_.-]+$/, \"a click id is letters, digits, '-', '_' and '.' only — paste the id, not the URL\");\n\n/**\n * An instant, with its offset stated. A bare `2026-08-01T10:00:00` is refused on purpose: it reads as\n * local time to the person who typed it and as UTC to everything downstream, and a conversion filed\n * two hours from where it happened lands in the wrong day's reporting with nothing to show for it.\n */\nconst conversionDateTimeSchema = z\n .string()\n .regex(\n /^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$/,\n \"expected an ISO-8601 instant WITH a timezone, e.g. 2026-08-01T10:00:00Z or 2026-08-01T12:00:00+02:00\",\n )\n .refine((value) => Number.isFinite(Date.parse(value)), \"not a real date\");\n\n/** An email address, or the SHA-256 hex it is stored as once staged. */\nconst emailSchema = z\n .string()\n .min(3)\n .max(320)\n .refine(\n (value) => SHA256_HEX_REGEX.test(value) || /^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(value),\n \"expected an email address\",\n );\n\n/**\n * A phone number in E.164, or the SHA-256 hex it is stored as once staged.\n *\n * The leading `+` and country code are required, not tidied up. A number stored the way a client's\n * CRM holds it — `600111222`, no country code — hashes to a different digest from the one Google\n * holds for that person, so the upload is accepted, reports as applied, and matches nobody. There is\n * no way to detect that afterwards from either end, and no way to guess the country from the digits.\n */\nconst phoneSchema = z\n .string()\n .min(4)\n .max(64)\n .refine(\n (value) => SHA256_HEX_REGEX.test(value) || /^\\+\\d[\\d\\s().-]{6,}$/.test(value),\n \"expected a phone number in E.164 with its country code, e.g. +34600111222 — a local number hashes to something Google cannot match\",\n );\n\n/**\n * A name, or the SHA-256 hex it is stored as. Google hashes given/family name after lowercasing and\n * stripping punctuation and whitespace, so what a CRM exports is normalized on the way in — the\n * caller sends \"Van Der Berg\" and Baker sends the digest of `vanderberg`.\n */\nconst nameSchema = z.string().min(1).max(120);\n\n/**\n * Google's address identifier requires all four of givenName, familyName, regionCode and postalCode\n * together — a partial address is not a weaker match, it is not a match at all, and Google rejects\n * the identifier rather than degrading it. City, region and street are optional refinements on top.\n */\nconst addressSchema = z\n .strictObject({\n givenName: nameSchema,\n familyName: nameSchema,\n /** ISO-3166-1 alpha-2, sent in the clear — it is not identifying on its own. */\n regionCode: z.string().regex(/^[A-Z]{2}$/, \"expected a 2-letter country code, e.g. ES\"),\n /** Sent in the clear, like the country: Google matches on it as a plain string. */\n postalCode: z.string().min(2).max(16),\n addressLine: z.string().min(1).max(200).optional(),\n city: z.string().min(1).max(100).optional(),\n /** State / province / region, whatever the country calls it. */\n administrativeArea: z.string().min(1).max(100).optional(),\n })\n .describe(\"advanced matching by name and address\");\n\n/**\n * How many conversions this one row stands for.\n *\n * Only meaningful on a conversion action whose counting type is EVERY — a lead action counts one per\n * click whatever is sent. Left unset it is one, which is what a repaired Form submission is; a\n * backfilled basket of three items sold in one order is three.\n */\nconst conversionCountSchema = z.number().int().positive().max(10_000);\n\n/**\n * Where the conversion happened. Defaults to WEB, which is what a repaired tag gap always is — the\n * others exist because a backfill of phone or in-store conversions arrives the same way and reads\n * wrong filed as web traffic.\n */\nexport const CONVERSION_EVENT_SOURCES = [\"WEB\", \"APP\", \"IN_STORE\", \"PHONE\", \"OTHER\"] as const;\n\nexport const conversionUploadRowSchema = z\n .strictObject({\n /**\n * The order id the original conversion carried — Baker's server-side tag sends the Form\n * submission id here, so a repair reuses that. Required: without it Google has no way to tell a\n * re-send from a new conversion, and the only way to find out is to double-count.\n */\n orderId: z.string().min(1).max(64),\n conversionDateTime: conversionDateTimeSchema,\n gclid: clickIdSchema.optional(),\n gbraid: clickIdSchema.optional(),\n wbraid: clickIdSchema.optional(),\n email: emailSchema.optional(),\n phone: phoneSchema.optional(),\n address: addressSchema.optional(),\n conversionCount: conversionCountSchema.optional(),\n eventSource: z.enum(CONVERSION_EVENT_SOURCES).optional(),\n value: z.number().nonnegative().optional(),\n currency: z\n .string()\n .regex(/^[A-Z]{3}$/, \"expected a 3-letter currency code, e.g. EUR\")\n .optional(),\n })\n .refine(\n (row) => Boolean(row.gclid ?? row.gbraid ?? row.wbraid ?? row.email ?? row.phone ?? row.address),\n \"every conversion needs something to match on: a click id (gclid / gbraid / wbraid), or a customer's email, phone or name+address\",\n )\n .refine(\n (row) => [row.gclid, row.gbraid, row.wbraid].filter(Boolean).length <= 1,\n \"pass at most one click id per conversion — gclid, gbraid and wbraid are three ways of naming the same click\",\n )\n // Currency is not optional next to a value: Google reads a value with no currency in the ACCOUNT's\n // currency, so a EUR order uploaded from a USD account silently changes what the campaign is worth.\n .refine(\n (row) => row.value === undefined || row.currency !== undefined,\n \"a conversion with a value needs its currency too\",\n )\n .refine((row) => row.currency === undefined || row.value !== undefined, \"currency was given with no value\");\nexport type ConversionUploadRow = z.infer<typeof conversionUploadRowSchema>;\n\nexport const conversionUploadSchema = z\n .strictObject({\n conversionAction: conversionUploadActionSchema,\n conversions: z.array(conversionUploadRowSchema).min(1).max(CONVERSION_UPLOAD_MAX_ROWS),\n })\n // Two rows with one order id are one conversion described twice — Google keeps one of them and\n // never says which, so the count the upload reports and the count the account records diverge.\n .refine((payload) => {\n const ids = payload.conversions.map((row) => row.orderId);\n return new Set(ids).size === ids.length;\n }, \"two conversions share an order id — each order id can appear once per upload\");\nexport type ConversionUpload = z.infer<typeof conversionUploadSchema>;\n\n/** The conversion action id an upload records against, whichever way it was named. */\nexport function conversionUploadActionId(payload: ConversionUpload): string {\n return payload.conversionAction.split(\"/\").pop() ?? payload.conversionAction;\n}\n\nexport interface ConversionUploadTotals {\n count: number;\n /** How many rows carry a value at all — the rest upload as a conversion with no revenue. */\n valued: number;\n /** Summed value, present only when every valued row agrees on one currency. */\n total?: { amount: number; currency: string };\n currencies: string[];\n}\n\n/**\n * Add money in minor units, then come back.\n *\n * Both call sites interpolate this straight into a label a reviewer reads as money, and a plain\n * float sum does not survive that: 12.10 + 3.30 is 15.399999999999999 in binary, and with up to\n * 200 decimal rows a set that sums exactly is the exception.\n */\nfunction sumMoney(values: number[]): number {\n return values.reduce((sum, value) => sum + Math.round(value * 100), 0) / 100;\n}\n\n/** What an upload adds up to, for the summary line and the review card. */\nexport function conversionUploadTotals(payload: ConversionUpload): ConversionUploadTotals {\n const valuedRows = payload.conversions.filter((row) => row.value !== undefined);\n const currencies = [...new Set(valuedRows.map((row) => row.currency ?? \"\"))].filter(Boolean).sort();\n const only = currencies.length === 1 ? currencies[0] : undefined;\n return {\n count: payload.conversions.length,\n valued: valuedRows.length,\n // Mixed currencies deliberately produce no total: adding EUR to USD gives a number that is wrong\n // in both, and this line is read as money.\n ...(only ? { total: { amount: sumMoney(valuedRows.map((row) => row.value ?? 0)), currency: only } } : {}),\n currencies,\n };\n}\n\n/** Order ids dated in the future — a conversion that has not happened yet is a typo, not a backfill. */\nexport function futureConversionRows(payload: ConversionUpload, nowMs: number): string[] {\n return payload.conversions.filter((row) => Date.parse(row.conversionDateTime) > nowMs).map((row) => row.orderId);\n}\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n/**\n * Order ids older than the conversion action's own click-through window. Google attributes an upload\n * to the click it names only while that click is still inside the window the action is configured\n * for, so anything past it is accepted and then counted against nothing. The number comes off the\n * account, never off a constant here — the window is a per-action setting the client can change.\n */\nexport function staleConversionRows(payload: ConversionUpload, lookbackDays: number, nowMs: number): string[] {\n const cutoff = nowMs - lookbackDays * MS_PER_DAY;\n return payload.conversions.filter((row) => Date.parse(row.conversionDateTime) < cutoff).map((row) => row.orderId);\n}\n\n/** How many rows match on a click id versus on a hashed customer identifier — stated on the review card. */\nexport function conversionUploadMatchCounts(payload: ConversionUpload): { byClick: number; byCustomer: number } {\n let byClick = 0;\n let byCustomer = 0;\n for (const row of payload.conversions) {\n if (row.gclid ?? row.gbraid ?? row.wbraid) {\n byClick += 1;\n } else {\n // Email, phone and name+address all reach Google as customer details under the same terms, so\n // they count as one kind here — the per-row table is where WHICH of them is stated.\n byCustomer += 1;\n }\n }\n return { byClick, byCustomer };\n}\n\nconst MONTHS = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"] as const;\n\n/**\n * One instant as a date a marketer reads. Hand-rolled rather than `Intl`, because this string is\n * built once at stage time and then stored on the draft and shown back unchanged — a value that\n * varied with the runtime's locale would make the same upload read differently in the chat, in\n * History and in a test.\n *\n * UTC, and the clock time is dropped: an upload covers a period, and \"2026-08-20T10:14:00Z\" tells\n * the person approving it nothing that \"20 Aug 2026\" does not.\n */\nfunction conversionUploadDay(instant: string): string {\n const date = new Date(instant);\n if (Number.isNaN(date.getTime())) {\n return instant;\n }\n return `${date.getUTCDate()} ${MONTHS[date.getUTCMonth()]} ${date.getUTCFullYear()}`;\n}\n\n/**\n * One instant as a date and time a person reads, in UTC.\n *\n * UTC and said so at the column header, rather than each row's own offset: a backfill routinely\n * mixes `Z` rows exported from one system with `+02:00` rows typed by hand, and a table that renders\n * each in its own zone cannot be scanned for the out-of-order row that is the whole point of reading\n * it. Same hand-rolled formatting as the range label, for the same reason.\n */\nexport function conversionUploadInstantLabel(instant: string): string {\n const date = new Date(instant);\n if (Number.isNaN(date.getTime())) {\n return instant;\n }\n const hh = String(date.getUTCHours()).padStart(2, \"0\");\n const mm = String(date.getUTCMinutes()).padStart(2, \"0\");\n return `${date.getUTCDate()} ${MONTHS[date.getUTCMonth()]} ${date.getUTCFullYear()}, ${hh}:${mm}`;\n}\n\n/**\n * The two days the upload runs between, as the label renders them.\n *\n * One definition of \"which day is this row on\", shared by the label and by the multi-day check, so\n * the phrase and the decision to show it cannot disagree: a warning that says \"Covers conversions\n * dated 1 Sep 2026\" is one that decided a one-day window spans several.\n */\nfunction conversionUploadDayEnds(payload: ConversionUpload): { start: string; end: string } {\n const { from, to } = conversionUploadRange(payload);\n return { start: conversionUploadDay(from), end: conversionUploadDay(to) };\n}\n\n/** The window an upload covers, as one phrase: \"20 Aug 2026 – 28 Aug 2026\", or one date if it is all one day. */\nexport function conversionUploadRangeLabel(payload: ConversionUpload): string {\n const { start, end } = conversionUploadDayEnds(payload);\n return start === end ? start : `${start} – ${end}`;\n}\n\n/**\n * Whether the upload really covers more than one day.\n *\n * The days, never the instants. Comparing the two ends of the range as timestamps answers \"are these\n * two rows the same moment\", which is a different question and is false for almost every upload —\n * a single afternoon's repair has rows at 10:00 and 15:45. Read that way, the multi-day heads-up\n * fired on everything with two rows in it and said \"Covers conversions dated 1 Sep 2026\", warning\n * about a window that is one day wide.\n */\nexport function conversionUploadSpansSeveralDays(payload: ConversionUpload): boolean {\n const { start, end } = conversionUploadDayEnds(payload);\n return start !== end;\n}\n\n/**\n * A conversion's value as money, with its cents kept: \"89.90 EUR\", never \"89.9 EUR\".\n *\n * These numbers are read straight off the client's own export and checked against it row by row, so\n * a trailing zero that JavaScript drops turns €89.90 into something that does not match the line the\n * reviewer is comparing it to. Two decimals for every currency: a zero-decimal one (JPY) reads a\n * little odd, which is a much smaller cost than a euro amount that looks like a different number.\n */\nexport function conversionValueLabel(amount: number, currency: string | undefined): string {\n return currency ? `${amount.toFixed(2)} ${currency}` : amount.toFixed(2);\n}\n\n/** The window an upload covers, as the earliest and latest instant in it. */\nexport function conversionUploadRange(payload: ConversionUpload): { from: string; to: string } {\n const sorted = [...payload.conversions].sort(\n (a, b) => Date.parse(a.conversionDateTime) - Date.parse(b.conversionDateTime),\n );\n const from = sorted[0]?.conversionDateTime ?? \"\";\n const to = sorted[sorted.length - 1]?.conversionDateTime ?? \"\";\n return { from, to };\n}\n\n/** Which identifiers a row actually carries, in the order Google prefers them. Never their values. */\nexport function conversionRowIdentifiers(row: ConversionUploadRow): string[] {\n const carried: string[] = [];\n if (row.gclid) carried.push(\"gclid\");\n if (row.gbraid) carried.push(\"gbraid\");\n if (row.wbraid) carried.push(\"wbraid\");\n if (row.email) carried.push(\"email\");\n if (row.phone) carried.push(\"phone\");\n if (row.address) carried.push(\"name + address\");\n return carried;\n}\n","/**\n * The structured snippet headers Google Ads accepts.\n *\n * `StructuredSnippetAsset.header` looks like free text and is not: Google\n * rejects anything outside its own published list with \"The input string value\n * is invalid for the associated field.\", which names neither the field nor the\n * list. A campaign launch lost two snippet assets — and, with them, the asset\n * links that depended on them — to the header \"Features\", which is not on it.\n *\n * The list below is Google's, verbatim: the thirteen English headers plus every\n * translation it publishes, so a Portuguese campaign can stage \"Tipos\" and a\n * French one \"Émissions\". A header is matched case-insensitively and rewritten\n * to Google's exact spelling, because a snippet that only differs in casing is\n * a valid intent Google would otherwise refuse.\n *\n * Source: https://developers.google.com/google-ads/api/data/structured-snippet-headers\n */\n\n/** The English headers, in Google's own order — what an error message offers back. */\nexport const STRUCTURED_SNIPPET_HEADERS_EN = [\n \"Brands\",\n \"Amenities\",\n \"Styles\",\n \"Types\",\n \"Destinations\",\n \"Services\",\n \"Courses\",\n \"Neighborhoods\",\n \"Shows\",\n \"Insurance coverage\",\n \"Degree programs\",\n \"Featured hotels\",\n \"Models\",\n] as const;\n\n/** Google's translations of those thirteen headers, across every locale it publishes. */\nconst STRUCTURED_SNIPPET_HEADERS_LOCALIZED: readonly string[] = [\n \"Aanbevolen hotels\",\n \"Acara\",\n \"Apdrošināšana\",\n \"Apkaimes\",\n \"Arredores\",\n \"Asigurare\",\n \"Assegurança\",\n \"Ausstattung\",\n \"Automerkit\",\n \"Bairros\",\n \"Barrios\",\n \"Barris\",\n \"Bestemmingen\",\n \"Biztosítási módozat\",\n \"Blagovne znamke\",\n \"Brand\",\n \"Brändid\",\n \"Brändit\",\n \"Buurten\",\n \"Cakupan asuransi\",\n \"Carreras universitarias\",\n \"Cartiere\",\n \"Chương trình\",\n \"Cilji\",\n \"Cobertura de seguro\",\n \"Cobertura do seguro\",\n \"Comodidades\",\n \"Coperture assicurativa\",\n \"Corsi\",\n \"Corsi di laurea\",\n \"Cours\",\n \"Couverture d'assurance\",\n \"Cursos\",\n \"Cursuri\",\n \"Cursussen\",\n \"Cíle\",\n \"Cấp bằng\",\n \"Degree programmes\",\n \"Dekking\",\n \"Design\",\n \"Destinacions\",\n \"Destinasi\",\n \"Destinasjoner\",\n \"Destinationer\",\n \"Destinazioni\",\n \"Destinații\",\n \"Destinos\",\n \"Destinácie\",\n \"Dienstleistungen\",\n \"Diplomaprogramok\",\n \"Dotări\",\n \"Draudimo aprėptis\",\n \"Dzielnice\",\n \"Dịch vụ\",\n \"Emisije\",\n \"Emisiuni\",\n \"Espectáculos\",\n \"Estilos\",\n \"Estils\",\n \"Faciliteter\",\n \"Fasilitas\",\n \"Fasiliteter\",\n \"Forsikringsdekning\",\n \"Forsikringsdækning\",\n \"Försäkringstyper\",\n \"Galamērķi\",\n \"Gaya\",\n \"Hizmetler\",\n \"Hotel consigliati\",\n \"Hotel ditampilkan\",\n \"Hotel pilihan\",\n \"Hoteles destacados\",\n \"Hotels destacats\",\n \"Hoteluri prezentate\",\n \"Hotéis em destaque\",\n \"Istaknuti hoteli\",\n \"Itinatampok na hotel\",\n \"Jenama\",\n \"Jenis\",\n \"Kaupunginosat\",\n \"Kawasan\",\n \"Kejiranan\",\n \"Kemudahan\",\n \"Khách sạn nổi bật\",\n \"Khóa học\",\n \"Kiemelt szállodák\",\n \"Kierunki studiów\",\n \"Kindlustuskaitse\",\n \"Kiểu\",\n \"Kohteet\",\n \"Kraadiõppeprogrammid\",\n \"Kritje zavarovanj\",\n \"Kurs\",\n \"Kursai\",\n \"Kurse\",\n \"Kurser\",\n \"Kursi\",\n \"Kurslar\",\n \"Kurssit\",\n \"Kursus\",\n \"Kursused\",\n \"Kursy\",\n \"Kurzy\",\n \"Laidos\",\n \"Layanan\",\n \"Licenciaturas\",\n \"Liputan insurans\",\n \"Lisans programları\",\n \"Lisäpalvelut\",\n \"Lokalområder\",\n \"Loại\",\n \"Mahalleler\",\n \"Marcas\",\n \"Markalar\",\n \"Marken\",\n \"Marki\",\n \"Marques\",\n \"Mata pelajaran\",\n \"Merek\",\n \"Merken\",\n \"Merkevarer\",\n \"Mga Amenity\",\n \"Mga Brand\",\n \"Mga Destinasyon\",\n \"Mga Istilo\",\n \"Mga Komunidad\",\n \"Mga Kurso\",\n \"Mga Modelo\",\n \"Mga Palabas\",\n \"Mga Serbisyo\",\n \"Mga Uri\",\n \"Mga degree program\",\n \"Miejsca\",\n \"Model\",\n \"Modele\",\n \"Modeli\",\n \"Modeliai\",\n \"Modelle\",\n \"Modellek\",\n \"Modellen\",\n \"Modeller\",\n \"Modelli\",\n \"Modelos\",\n \"Modely\",\n \"Modeļi\",\n \"Modèles\",\n \"Moksliniai laipsniai\",\n \"Mudelid\",\n \"Mugavusteenused\",\n \"Márkák\",\n \"Mărci\",\n \"Műsorok\",\n \"Nabolag\",\n \"Namų apylinkės\",\n \"Neighbourhoods\",\n \"Oddaje\",\n \"Odporúčané hotely\",\n \"Odredišta\",\n \"Oppiaineet\",\n \"Osiguranje\",\n \"Pakalpojumi\",\n \"Palvelut\",\n \"Paskirties vietos\",\n \"Paslaugos\",\n \"Patogumai\",\n \"Perkhidmatan\",\n \"Phạm vi bảo hiểm\",\n \"Piedāvātās viesnīcas\",\n \"Poistenie\",\n \"Pojištění\",\n \"Polecane hotele\",\n \"Ponudba\",\n \"Pořady\",\n \"Predstavljeni hoteli\",\n \"Prekių ženklai\",\n \"Program\",\n \"Program ijazah\",\n \"Program sarjana\",\n \"Programas\",\n \"Programas de graduação\",\n \"Programe de studiu\",\n \"Programes\",\n \"Programlar\",\n \"Programmer\",\n \"Programmes d'études\",\n \"Programmi\",\n \"Programy\",\n \"Pārraides\",\n \"Quartieri\",\n \"Quartiers\",\n \"Rancangan\",\n \"Relácie\",\n \"Resmål\",\n \"Robne marke\",\n \"Saated ja etendused\",\n \"Sadržaji\",\n \"Sakop ng insurance\",\n \"Serien\",\n \"Serier\",\n \"Serveis\",\n \"Serveis addicionals\",\n \"Servicii\",\n \"Servicios\",\n \"Servicios adicionales\",\n \"Servizi\",\n \"Serviços\",\n \"Show't\",\n \"Sigorta kapsamı\",\n \"Sihtkohad\",\n \"Siūlomi viešbučiai\",\n \"Slogi\",\n \"Služby\",\n \"Soovitatud hotellid\",\n \"Soseske\",\n \"Stiilid\",\n \"Stijlen\",\n \"Stilar\",\n \"Stile\",\n \"Stiler\",\n \"Stili\",\n \"Stiliai\",\n \"Stiller\",\n \"Stilovi\",\n \"Stiluri\",\n \"Storitve\",\n \"Studiengänge\",\n \"Studieprogramma's\",\n \"Studijní programy\",\n \"Studijski programi\",\n \"Studiju programmas\",\n \"Style\",\n \"Styly\",\n \"Stílusok\",\n \"Sunulan olanaklar\",\n \"Suositellut hotellit\",\n \"Szolgáltatások\",\n \"Sélection d'hôtels\",\n \"Tanfolyamok\",\n \"Teenused\",\n \"Tečajevi\",\n \"Tečaji\",\n \"Thương hiệu\",\n \"Tipai\",\n \"Tipi\",\n \"Tipos\",\n \"Tipuri\",\n \"Tipus\",\n \"Titulacions\",\n \"Tiện nghi\",\n \"Tjenester\",\n \"Tjänster\",\n \"Typen\",\n \"Typer\",\n \"Typy\",\n \"Tyylit\",\n \"Tyypit\",\n \"Típusok\",\n \"Türler\",\n \"Tüübid\",\n \"Ubezpieczenia\",\n \"Uddannelser\",\n \"Udogodnienia\",\n \"Udvalgte hoteller\",\n \"Usluge\",\n \"Usługi\",\n \"Utbildningsprogram\",\n \"Utdanningsprogrammer\",\n \"Utvalda hotell\",\n \"Utvalgte hoteller\",\n \"Vakuutukset\",\n \"Varumärken\",\n \"Veidi\",\n \"Versicherungsleistung\",\n \"Viertel\",\n \"Voorzieningen\",\n \"Vorgestellte Hotels\",\n \"Vrste\",\n \"Vybavenie\",\n \"Vybavení\",\n \"Vybrané hotely\",\n \"Vzdelávacie programy\",\n \"Városrészek\",\n \"Vùng lân cận\",\n \"Ziele\",\n \"Značky\",\n \"Známé oblasti\",\n \"Zīmoli\",\n \"destinasyonlar\",\n \"Émissions\",\n \"Équipements\",\n \"Öne çıkan oteller\",\n \"Úti célok\",\n \"Ümbruskonnad\",\n \"Četvrti\",\n \"Điểm đến\",\n \"Ērtības\",\n \"Študijski programi\",\n \"Štvrte\",\n \"Štýly\",\n \"Ασφαλιστική κάλυψη\",\n \"Γειτονιές\",\n \"Εκπομπές\",\n \"Επωνυμίες\",\n \"Μαθήματα\",\n \"Μοντέλα\",\n \"Ξενοδοχεία\",\n \"Παροχές\",\n \"Προγράμματα πτυχίων\",\n \"Προορισμοί\",\n \"Στυλ\",\n \"Τύποι\",\n \"Υπηρεσίες\",\n \"Бренди\",\n \"Бренды\",\n \"Дестинации\",\n \"Застраховка\",\n \"Зручності\",\n \"Квартали\",\n \"Курси\",\n \"Курсове\",\n \"Курсы\",\n \"Марки\",\n \"Места\",\n \"Модели\",\n \"Моделі\",\n \"Місця\",\n \"Освітні програми\",\n \"Послуги\",\n \"Предавания\",\n \"Представени хотели\",\n \"Программы высшего образования\",\n \"Районы\",\n \"Рекомендовані готелі\",\n \"Рекомендуемые отели\",\n \"Специалности\",\n \"Стили\",\n \"Стилове\",\n \"Стилі\",\n \"Страховая защита\",\n \"Страховий захист\",\n \"Типи\",\n \"Типове\",\n \"Типы\",\n \"Удобства\",\n \"Услуги\",\n \"Шоу\",\n \"брендови\",\n \"делови града\",\n \"дестинације\",\n \"дипломе\",\n \"емисије\",\n \"истакнути хотели\",\n \"курсеви\",\n \"модели\",\n \"осигурање\",\n \"садржаји\",\n \"стилови\",\n \"типови\",\n \"услуге\",\n \"דגמים\",\n \"הופעות ותוכניות\",\n \"יעדים גיאוגרפיים\",\n \"כיסוי ביטוחי\",\n \"מותגים\",\n \"מלונות מומלצים\",\n \"סגנונות\",\n \"סוגים\",\n \"קורסים\",\n \"שירותי המקום\",\n \"שירותים\",\n \"שכונות\",\n \"תוכניות ללימודי תואר\",\n \"الأحياء\",\n \"الأنماط\",\n \"الأنواع\",\n \"التغطية التأمينية\",\n \"الخدمات\",\n \"الدورات التدريبية\",\n \"العروض\",\n \"العلامات التجارية\",\n \"الفنادق المميّزة\",\n \"النماذج\",\n \"الوجهات\",\n \"برامج الشهادات\",\n \"وسائل الراحة\",\n \"आस-पड़ोस\",\n \"गंतव्य\",\n \"डिग्री कार्यक्रम\",\n \"पाठ्यक्रम\",\n \"प्रकार\",\n \"प्रदर्शित होटल\",\n \"बीमा कवरेज\",\n \"ब्रांड\",\n \"मॉडल\",\n \"शैलियां\",\n \"शो\",\n \"सुविधाएं\",\n \"सेवाएं\",\n \"ความคุ้มครองในประกัน\",\n \"บริการ\",\n \"ประเภท\",\n \"ปลายทาง\",\n \"ย่านใกล้เคียง\",\n \"รุ่น\",\n \"สิ่งอำนวยความสะดวก\",\n \"สไตล์\",\n \"หลักสูตร\",\n \"หลักสูตรปริญญา\",\n \"แบรนด์\",\n \"โชว์\",\n \"โรงแรมเด่น\",\n \"おすすめのホテル\",\n \"コース\",\n \"サービス\",\n \"スタイル\",\n \"タイプ\",\n \"ブランド\",\n \"モデル\",\n \"保険の保障\",\n \"保障範圍\",\n \"到着地\",\n \"周辺地域\",\n \"品牌\",\n \"型号\",\n \"型號\",\n \"学位プログラム\",\n \"学位课程\",\n \"學位課程\",\n \"承保範圍\",\n \"服务\",\n \"服務\",\n \"款式\",\n \"特色酒店\",\n \"番組\",\n \"目的地\",\n \"社区\",\n \"社區\",\n \"節目\",\n \"类型\",\n \"精选酒店\",\n \"精選飯店\",\n \"节目\",\n \"設備\",\n \"設施\",\n \"課程\",\n \"设施\",\n \"课程\",\n \"险种\",\n \"類型\",\n \"과정\",\n \"모델\",\n \"목적지\",\n \"보험 보상 범위\",\n \"브랜드\",\n \"서비스\",\n \"스타일\",\n \"유형\",\n \"인근 지역\",\n \"추천 호텔\",\n \"편의 시설\",\n \"프로그램\",\n \"학위 취득 프로그램\",\n];\n\n/**\n * Headers Google renamed but still documents under the old name, so a marketer\n * reading an older help page does not lose an asset to it.\n *\n * A `Map`, not an object literal: an object answers `\"constructor\"` with a\n * function off `Object.prototype`, and the schema downstream would take that as\n * a valid header and stage a snippet whose header vanishes on serialization —\n * the exact failure this module exists to stop, from a lookup that never\n * touched the list.\n */\nconst HEADER_ALIASES = new Map<string, string>([[\"service catalog\", \"Services\"]]);\n\nconst ACCEPTED = new Set<string>([...STRUCTURED_SNIPPET_HEADERS_EN, ...STRUCTURED_SNIPPET_HEADERS_LOCALIZED]);\n\n/**\n * One case-folded entry per accepted header. Two locales disagree on the casing\n * of the same word, so an exact match is always answered before this map — the\n * fold is a fallback for the caller's casing, not a canonicalization of\n * Google's.\n */\nconst BY_FOLDED_CASE = new Map<string, string>([...ACCEPTED].map((header) => [header.toLowerCase(), header] as const));\n\n/**\n * Google's own spelling of `header`, or `undefined` if Google does not accept\n * any spelling of it. Callers stage the returned string, never the input.\n */\nexport function canonicalStructuredSnippetHeader(header: string): string | undefined {\n const trimmed = header.trim();\n if (ACCEPTED.has(trimmed)) {\n return trimmed;\n }\n const folded = trimmed.toLowerCase();\n return HEADER_ALIASES.get(folded) ?? BY_FOLDED_CASE.get(folded);\n}\n","/**\n * Staged Google Ads write operations — the wire + storage payload contract.\n *\n * Ops are staged per chat and applied only when the chat publishes as a single\n * atomic `GoogleAdsService.Mutate` batch. Every payload here is exhaustively\n * validated at stage time (lengths, enums, micros, match types, resource-name\n * shapes, cross-field constraints); referential checks (customer scope, parent\n * existence, asset readiness) happen in the backend stage action on top of\n * these schemas.\n *\n * Money is in micros (major currency × 1,000,000) — the CLI converts before\n * staging so the contract, builders, and audit log all speak the API's units.\n */\nimport { z } from \"zod\";\nimport { conversionUploadSchema } from \"./conversion-upload\";\nimport {\n AD_GROUP_TYPES,\n ADVERTISING_CHANNEL_SUB_TYPES,\n ADVERTISING_CHANNEL_TYPES,\n ASSET_FIELD_TYPES,\n ASSET_GROUP_ASSET_FIELD_TYPES,\n BIDDING_STRATEGY_TYPES,\n BUDGET_DELIVERY_METHODS,\n BUSINESS_LOGO_LEVEL_MESSAGE,\n CAMPAIGN_OBJECTIVES,\n CONVERSION_ACTION_CATEGORIES,\n CONVERSION_ACTION_TYPES,\n CONVERSION_COUNTING_TYPES,\n CONVERSION_ORIGINS,\n DAYS_OF_WEEK,\n DEVICE_TYPES,\n demandGenOnlyStrategyRefusal,\n embeddedTargetOnDemandGenRefusal,\n GEO_TARGET_CONSTANT_REGEX,\n GOOGLE_ADS_LIMITS,\n type GoogleBiddingStrategyType,\n isImageAssetLinkFieldType,\n KEYWORD_MATCH_TYPES,\n LANGUAGE_CONSTANT_REGEX,\n manualCpcOnDemandGenRefusal,\n mergedTargetStrategyRefusal,\n NEGATIVE_GEO_TARGET_TYPES,\n NUMERIC_ID_REGEX,\n PINNED_FIELDS,\n PLAYBOOK_DAILY_BUDGET_FLOOR_MICROS,\n POSITIVE_GEO_TARGET_TYPES,\n RESOURCE_NAME_REGEX,\n SHARED_SET_TYPES,\n STAGEABLE_CREATE_STATUSES,\n TARGETING_DIMENSIONS,\n TEMP_REF_REGEX,\n USER_LIST_TYPES,\n} from \"./limits\";\nimport { canonicalStructuredSnippetHeader, STRUCTURED_SNIPPET_HEADERS_EN } from \"./structured-snippet-headers\";\n\n// --- Shared primitives ---\n\nexport const tempRefSchema = z.string().regex(TEMP_REF_REGEX, \"expected a g_temp_* reference\");\n\n/** A reference to another entity: a full resource name, a bare numeric id, or a g_temp_* ref staged earlier. */\nexport const refSchema = z.union([\n z.string().regex(RESOURCE_NAME_REGEX, \"expected a customers/…/…/… resource name\"),\n z.string().regex(NUMERIC_ID_REGEX, \"expected a numeric id\"),\n tempRefSchema,\n]);\n\n/** Update/status/remove targets: a real resource name or bare id, or a g_temp_* ref (AMENDS the staged create). */\nexport const targetRefSchema = refSchema;\n\nconst microsSchema = z.number().int().positive(\"expected a positive micros amount\");\nconst httpsUrlSchema = z\n .string()\n .url()\n .refine((u) => u.startsWith(\"https://\"), \"final URLs must be https\");\n\nconst customerIdSchema = z.string().regex(NUMERIC_ID_REGEX, \"customerId must be the bare numeric customer id\");\n\nconst stageableStatusSchema = z.enum(STAGEABLE_CREATE_STATUSES);\nconst matchTypeSchema = z.enum(KEYWORD_MATCH_TYPES);\n\n/**\n * `final_url_suffix` — bare query parameters appended to every final URL under the entity\n * (`utm_source=google&utm_agency=baker`). Not a URL and not a tracking template: a leading `?`\n * or `&` and a `{lpurl}` placeholder are both rejected by Google, so they are rejected here\n * before they can fail the whole atomic publish batch. The empty string clears the suffix.\n */\nexport const finalUrlSuffixSchema = z\n .string()\n .max(GOOGLE_ADS_LIMITS.campaign.finalUrlSuffixMax)\n .refine((s) => !/^[?&]/.test(s), \"drop the leading ? or & — a final URL suffix is bare query parameters\")\n .refine((s) => !s.includes(\"{lpurl}\"), \"{lpurl} belongs in a tracking template, not in a final URL suffix\")\n .refine((s) => !/\\s/.test(s), \"a final URL suffix cannot contain whitespace\")\n .refine((s) => s === \"\" || s.includes(\"=\"), 'expected key=value pairs, e.g. \"utm_source=google&utm_agency=baker\"');\n\n/** The ValueTrack tags that carry the landing page into a tracking template. */\nconst LANDING_PAGE_TAGS = [\"{lpurl}\", \"{unescapedlpurl}\", \"{escapedlpurl}\", \"{lpurl+2}\", \"{lpurl+3}\"];\n\n/**\n * `tracking_url_template` — the click-measurement URL every ad under the entity routes through.\n *\n * A template without a landing-page tag sends the click to the tracker and nowhere after it, which\n * Google rejects (and which would strand traffic if it didn't), so the tag is required here rather\n * than at publish where the rejection fails the whole atomic batch. The empty string clears the\n * template back to the account-level one.\n */\nexport const trackingUrlTemplateSchema = z\n .string()\n .max(GOOGLE_ADS_LIMITS.campaign.trackingUrlTemplateMax)\n .refine((t) => !/\\s/.test(t), \"a tracking template cannot contain whitespace\")\n .refine(\n (t) => t === \"\" || LANDING_PAGE_TAGS.some((tag) => t.includes(tag)),\n `a tracking template must carry the landing page through one of ${LANDING_PAGE_TAGS.join(\", \")}, e.g. \"https://tracker.example/?url={lpurl}\"`,\n )\n .refine(\n (t) => t === \"\" || /^(https?:\\/\\/|\\{)/.test(t),\n \"a tracking template must start with http://, https:// or a {lpurl} tag\",\n );\n\n/**\n * `url_custom_parameters` — the `{_name}` placeholders a tracking template or final URL can\n * reference. Google REPLACES the whole set on update, so an empty array clears them.\n */\nexport const urlCustomParametersSchema = z\n .array(\n z.strictObject({\n key: z\n .string()\n .min(1)\n .max(GOOGLE_ADS_LIMITS.campaign.urlCustomParameterKeyMax)\n .regex(/^[A-Za-z0-9_]+$/, \"a custom parameter key is letters, digits and underscores only\"),\n value: z.string().max(GOOGLE_ADS_LIMITS.campaign.urlCustomParameterValueMax),\n }),\n )\n .max(GOOGLE_ADS_LIMITS.campaign.urlCustomParametersMax)\n .refine(\n (params) => new Set(params.map((p) => p.key)).size === params.length,\n \"each custom parameter key can appear only once\",\n );\n\nconst keywordTextSchema = z\n .string()\n .min(1)\n .max(GOOGLE_ADS_LIMITS.keyword.textMax)\n .refine((t) => t.trim().split(/\\s+/).length <= GOOGLE_ADS_LIMITS.keyword.wordsMax, \"keyword exceeds 10 words\");\n\n// --- Campaign budget ---\n\nexport const budgetCreateSchema = z.strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.budget.nameMax),\n amountMicros: microsSchema,\n deliveryMethod: z.enum(BUDGET_DELIVERY_METHODS).default(\"STANDARD\"),\n explicitlyShared: z.boolean().default(false),\n});\nexport type BudgetCreate = z.infer<typeof budgetCreateSchema>;\n\nexport const budgetUpdateSchema = z\n .strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.budget.nameMax).optional(),\n amountMicros: microsSchema.optional(),\n deliveryMethod: z.enum(BUDGET_DELIVERY_METHODS).optional(),\n })\n .refine((p) => Object.values(p).some((v) => v !== undefined), \"update needs at least one field\");\nexport type BudgetUpdate = z.infer<typeof budgetUpdateSchema>;\n\n// --- Bidding (inline standard strategy on a campaign) ---\n\n/**\n * Strict for the same reason as `networkSettings`: Target Impression Share goal keys\n * (`location`, `locationFractionMicros`) were stripped by a non-strict object, so the update\n * staged with no warning and published a campaign whose goal never changed.\n */\nexport const biddingConfigSchema = z\n .strictObject({\n type: z.enum(BIDDING_STRATEGY_TYPES),\n targetCpaMicros: microsSchema.optional(),\n targetRoas: z.number().positive().optional(),\n /** Demand Gen only — `Campaign.target_cpc.target_cpc_micros`. */\n targetCpcMicros: microsSchema.optional(),\n cpcBidCeilingMicros: microsSchema.optional(),\n enhancedCpcEnabled: z.boolean().optional(),\n })\n .superRefine((p, ctx) => {\n if (p.type === \"TARGET_CPA\" && p.targetCpaMicros === undefined) {\n ctx.addIssue({ code: \"custom\", path: [\"targetCpaMicros\"], message: \"TARGET_CPA needs targetCpaMicros\" });\n }\n if (p.type === \"TARGET_ROAS\" && p.targetRoas === undefined) {\n ctx.addIssue({ code: \"custom\", path: [\"targetRoas\"], message: \"TARGET_ROAS needs targetRoas\" });\n }\n if (p.type === \"TARGET_CPC\" && p.targetCpcMicros === undefined) {\n ctx.addIssue({ code: \"custom\", path: [\"targetCpcMicros\"], message: \"TARGET_CPC needs targetCpcMicros\" });\n }\n });\nexport type BiddingConfig = z.infer<typeof biddingConfigSchema>;\n\n// --- Campaign ---\n\n/**\n * `campaign.network_settings` — which networks the campaign serves on. Strict for the same reason\n * as `geoTargetTypeSetting`: a typo'd key inside a non-strict object was stripped silently, so the\n * command reported success and the campaign published on Google's networks instead of the staged ones.\n */\nconst networkSettingsSchema = z.strictObject({\n targetGoogleSearch: z.boolean().optional(),\n targetSearchNetwork: z.boolean().optional(),\n targetContentNetwork: z.boolean().optional(),\n targetPartnerSearchNetwork: z.boolean().optional(),\n});\nexport type NetworkSettings = z.infer<typeof networkSettingsSchema>;\n\n/**\n * What Baker sends for a SEARCH campaign create that states no networks. Google's own default turns\n * Search partners AND the Display network on, which is spend on surfaces nobody chose and an audit\n * finding on the next Session — so the unstated case means Google Search only, and widening is an\n * explicit `networkSettings` in the payload.\n *\n * SEARCH only: Display campaigns need `targetContentNetwork` on, and Performance Max does not take\n * network settings at all, so there is no single safe default to apply across channel types.\n * Applied on the way OUT — at publish and on the review card — never on the way in, so the draft\n * keeps recording what the agent actually asked for (same convention as CONVERSION_ACTION_CREATE_DEFAULTS).\n */\nexport const SEARCH_CAMPAIGN_NETWORK_DEFAULTS = {\n targetGoogleSearch: true,\n targetSearchNetwork: false,\n targetContentNetwork: false,\n targetPartnerSearchNetwork: false,\n} as const satisfies NetworkSettings;\n\n/** The network settings that actually reach Google for a campaign create; undefined leaves it unset. */\nexport function resolveCampaignNetworkSettings(\n channelType: string | undefined,\n staged: NetworkSettings | undefined,\n): NetworkSettings | undefined {\n if (staged) {\n return staged;\n }\n return channelType === \"SEARCH\" ? SEARCH_CAMPAIGN_NETWORK_DEFAULTS : undefined;\n}\n\nconst dateSchema = z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"expected a YYYY-MM-DD date\");\n\n/**\n * `campaign.geo_target_type_setting` — how the campaign's location criteria are interpreted.\n * Strict, because the whole point of staging this is that a typo'd key used to vanish silently\n * and the campaign published on Google's default (`PRESENCE_OR_INTEREST`) instead.\n */\nconst geoTargetTypeSettingSchema = z\n .strictObject({\n positiveGeoTargetType: z.enum(POSITIVE_GEO_TARGET_TYPES).optional(),\n negativeGeoTargetType: z.enum(NEGATIVE_GEO_TARGET_TYPES).optional(),\n })\n .refine(\n (p) => p.positiveGeoTargetType !== undefined || p.negativeGeoTargetType !== undefined,\n \"geoTargetTypeSetting needs positiveGeoTargetType and/or negativeGeoTargetType\",\n );\nexport type GeoTargetTypeSetting = z.infer<typeof geoTargetTypeSettingSchema>;\n\n/**\n * Text guidelines: what the text Google writes for an AI Max or Performance Max campaign must avoid.\n * Each list REPLACES the campaign's whole list on publish; `[]` clears it, an omitted list is left\n * alone. A messaging restriction is sent as Google's only restriction type, `RESTRICTION_BASED_EXCLUSION`.\n */\nconst textGuidelinesSchema = z\n .strictObject({\n termExclusions: z\n .array(z.string().trim().min(1).max(GOOGLE_ADS_LIMITS.campaign.termExclusionMax))\n .max(GOOGLE_ADS_LIMITS.campaign.termExclusionsMax)\n .optional(),\n messagingRestrictions: z\n .array(z.string().trim().min(1).max(GOOGLE_ADS_LIMITS.campaign.messagingRestrictionMax))\n .max(GOOGLE_ADS_LIMITS.campaign.messagingRestrictionsMax)\n .refine(\n (rules) => new Set(rules.map((rule) => rule.toLowerCase())).size === rules.length,\n \"each messaging restriction must be unique\",\n )\n .optional(),\n })\n .refine(\n (p) => p.termExclusions !== undefined || p.messagingRestrictions !== undefined,\n \"textGuidelines needs termExclusions and/or messagingRestrictions\",\n );\nexport type TextGuidelines = z.infer<typeof textGuidelinesSchema>;\n\nexport const AI_MAX_TEXT_NEEDS_AI_MAX_MESSAGE =\n \"AI Max text customization only works with AI Max on: also turn AI Max on, or leave text customization off.\";\nexport const AI_MAX_URL_NEEDS_TEXT_MESSAGE =\n \"AI Max final URL expansion only works with text customization on: also turn text customization on, or leave URL expansion off.\";\n\n/**\n * AI Max on a Search campaign: the switch itself (`ai_max_setting.enable_ai_max`) and its two\n * opt-in features, text customization (`TEXT_ASSET_AUTOMATION`) and final URL expansion\n * (`FINAL_URL_EXPANSION_TEXT_ASSET_AUTOMATION`). An omitted field keeps the campaign's value.\n * Google refuses text customization without AI Max and URL expansion without text customization,\n * so a payload that states both halves of either pair contradictorily is refused here; a half the\n * payload leaves out is checked against the live campaign at stage time.\n */\nconst aiMaxSchema = z\n .strictObject({\n enabled: z.boolean().optional(),\n textCustomization: z.boolean().optional(),\n finalUrlExpansion: z.boolean().optional(),\n })\n .superRefine((p, ctx) => {\n if (p.enabled === undefined && p.textCustomization === undefined && p.finalUrlExpansion === undefined) {\n ctx.addIssue({ code: \"custom\", message: \"aiMax needs enabled, textCustomization and/or finalUrlExpansion\" });\n }\n if (p.enabled === false && p.textCustomization === true) {\n ctx.addIssue({ code: \"custom\", path: [\"textCustomization\"], message: AI_MAX_TEXT_NEEDS_AI_MAX_MESSAGE });\n }\n if (p.textCustomization === false && p.finalUrlExpansion === true) {\n ctx.addIssue({ code: \"custom\", path: [\"finalUrlExpansion\"], message: AI_MAX_URL_NEEDS_TEXT_MESSAGE });\n }\n });\nexport type AiMax = z.infer<typeof aiMaxSchema>;\n\nexport const AI_MAX_SEARCH_ONLY_MESSAGE = \"AI Max exists only on Search campaigns.\";\n\n/** Why a new campaign's AI Max can't be created as staged. A new campaign starts with AI Max and both features off. */\nfunction aiMaxCreateRefusal(channelType: string, aiMax: AiMax | undefined): string | undefined {\n if (!aiMax) {\n return undefined;\n }\n if (channelType !== \"SEARCH\") {\n return AI_MAX_SEARCH_ONLY_MESSAGE;\n }\n if (aiMax.enabled !== true && aiMax.textCustomization === true) {\n return AI_MAX_TEXT_NEEDS_AI_MAX_MESSAGE;\n }\n if (aiMax.textCustomization !== true && aiMax.finalUrlExpansion === true) {\n return AI_MAX_URL_NEEDS_TEXT_MESSAGE;\n }\n return undefined;\n}\n\n/**\n * Strict: an unknown key on a campaign payload is a hard stage-time error, never a silent drop.\n * A `--file` payload that named a field this contract does not carry (`geoTargetTypeSetting`\n * before it existed here) used to be stripped by zod, so the command reported success and the\n * campaign went live on Google's defaults. Failing loudly is what lets the agent correct itself.\n */\nexport const campaignCreateSchema = z\n .strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.campaign.nameMax),\n channelType: z.enum(ADVERTISING_CHANNEL_TYPES),\n channelSubType: z.enum(ADVERTISING_CHANNEL_SUB_TYPES).optional(),\n budget: refSchema,\n /** Inline standard bidding, or a portfolio strategy ref via biddingStrategy. */\n bidding: biddingConfigSchema.optional(),\n biddingStrategy: refSchema.optional(),\n networkSettings: networkSettingsSchema.optional(),\n /**\n * \"Location options\". Omitted stages Google's own default — reach people *in or interested in*\n * the targeted locations — so pass `PRESENCE` explicitly when only people physically there count.\n */\n geoTargetTypeSetting: geoTargetTypeSettingSchema.optional(),\n startDate: dateSchema.optional(),\n endDate: dateSchema.optional(),\n /** Campaign-level override of the account's final URL suffix — REPLACES it, never merges. */\n finalUrlSuffix: finalUrlSuffixSchema.optional(),\n /** Campaign-level override of the account's tracking template — REPLACES it, never merges. */\n trackingUrlTemplate: trackingUrlTemplateSchema.optional(),\n /** The `{_name}` parameters this campaign's tracking template and final URLs can reference. */\n urlCustomParameters: urlCustomParametersSchema.optional(),\n /** Advisory Google Ads UI objective — drives warnings, not sent to the API. */\n objective: z.enum(CAMPAIGN_OBJECTIVES).optional(),\n /**\n * Whether the campaign contains EU political advertising. Google requires the declaration on\n * every campaign create (FieldError.REQUIRED without it); omitted means it does not.\n */\n euPoliticalAds: z.boolean().optional(),\n /** AI Max for Search. A new campaign has it off unless this turns it on. */\n aiMax: aiMaxSchema.optional(),\n status: stageableStatusSchema.default(\"PAUSED\"),\n })\n .superRefine((p, ctx) => {\n if (!p.bidding && !p.biddingStrategy) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"bidding\"],\n message: \"set an inline bidding strategy or reference a portfolio biddingStrategy\",\n });\n }\n if (p.bidding && p.biddingStrategy) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"bidding\"],\n message: \"use inline bidding OR a portfolio biddingStrategy, not both\",\n });\n }\n if (p.channelType === \"PERFORMANCE_MAX\" && p.bidding && p.bidding.type === \"MANUAL_CPC\") {\n ctx.addIssue({ code: \"custom\", path: [\"bidding\"], message: \"Performance Max does not support Manual CPC\" });\n }\n // A create carries its own channel, so this one is answerable here — an update has to wait for\n // the stage-time snapshot to say what channel it is editing.\n const channelRefusal =\n mergedTargetStrategyRefusal(p.channelType, p.bidding?.type) ??\n demandGenOnlyStrategyRefusal(p.channelType, p.bidding?.type) ??\n manualCpcOnDemandGenRefusal(p.channelType, p.bidding?.type) ??\n embeddedTargetOnDemandGenRefusal(p.channelType, p.bidding);\n if (channelRefusal) {\n ctx.addIssue({ code: \"custom\", path: [\"bidding\"], message: channelRefusal });\n }\n if (p.startDate && p.endDate && p.endDate <= p.startDate) {\n ctx.addIssue({ code: \"custom\", path: [\"endDate\"], message: \"endDate must be after startDate\" });\n }\n const aiMaxRefusal = aiMaxCreateRefusal(p.channelType, p.aiMax);\n if (aiMaxRefusal) {\n ctx.addIssue({ code: \"custom\", path: [\"aiMax\"], message: aiMaxRefusal });\n }\n });\nexport type CampaignCreate = z.infer<typeof campaignCreateSchema>;\n\nexport const campaignUpdateSchema = z\n .strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.campaign.nameMax).optional(),\n budget: refSchema.optional(),\n bidding: biddingConfigSchema.optional(),\n networkSettings: networkSettingsSchema.optional(),\n /** Switches an existing campaign between \"Presence or interest\" and \"Presence\". */\n geoTargetTypeSetting: geoTargetTypeSettingSchema.optional(),\n startDate: dateSchema.optional(),\n endDate: dateSchema.optional(),\n /** Campaign-level override of the account's final URL suffix. `\"\"` clears it back to the account value. */\n finalUrlSuffix: finalUrlSuffixSchema.optional(),\n /** Campaign-level tracking template. `\"\"` clears it back to the account value. */\n trackingUrlTemplate: trackingUrlTemplateSchema.optional(),\n /** Replaces the campaign's custom parameters wholesale; `[]` removes them all. */\n urlCustomParameters: urlCustomParametersSchema.optional(),\n /** Corrects the campaign's EU political advertising declaration (true = contains, false = does not). */\n euPoliticalAds: z.boolean().optional(),\n /** AI Max / Performance Max text guidelines. Google refuses them on a Search campaign without AI Max. */\n textGuidelines: textGuidelinesSchema.optional(),\n /** Turns AI Max or its features on or off. Search campaigns only (checked against the live channel). */\n aiMax: aiMaxSchema.optional(),\n status: z.enum([\"ENABLED\", \"PAUSED\", \"REMOVED\"]).optional(),\n })\n .refine((p) => Object.values(p).some((v) => v !== undefined), \"update needs at least one field\");\nexport type CampaignUpdate = z.infer<typeof campaignUpdateSchema>;\n\n// --- Ad group ---\n\nexport const adGroupCreateSchema = z.strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.adGroup.nameMax),\n campaign: refSchema,\n /**\n * Optional, and NOT defaulted: Google derives an ad group's type from its campaign's channel when\n * it is unset, and for a Demand Gen campaign that is the only way to say it — the v23 enum has no\n * Demand Gen value at all. A default of `SEARCH_STANDARD` would state a type nobody chose on every\n * ad group Baker stages, which on a Demand Gen campaign is a whole-batch publish failure.\n */\n type: z.enum(AD_GROUP_TYPES).optional(),\n cpcBidMicros: microsSchema.optional(),\n status: stageableStatusSchema.default(\"PAUSED\"),\n});\nexport type AdGroupCreate = z.infer<typeof adGroupCreateSchema>;\n\n/** Strict for the same reason as `campaignUpdateSchema`: an unknown key here used to be dropped in silence. */\nexport const adGroupUpdateSchema = z\n .strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.adGroup.nameMax).optional(),\n cpcBidMicros: microsSchema.optional(),\n status: z.enum([\"ENABLED\", \"PAUSED\", \"REMOVED\"]).optional(),\n })\n .refine((p) => Object.values(p).some((v) => v !== undefined), \"update needs at least one field\");\nexport type AdGroupUpdate = z.infer<typeof adGroupUpdateSchema>;\n\n// --- Keywords (ad-group criteria) ---\n\nexport const keywordAddSchema = z.strictObject({\n adGroup: refSchema,\n text: keywordTextSchema,\n matchType: matchTypeSchema,\n cpcBidMicros: microsSchema.optional(),\n finalUrls: z.array(httpsUrlSchema).optional(),\n status: stageableStatusSchema.default(\"ENABLED\"),\n});\nexport type KeywordAdd = z.infer<typeof keywordAddSchema>;\n\nexport const keywordUpdateSchema = z\n .strictObject({\n cpcBidMicros: microsSchema.optional(),\n finalUrls: z.array(httpsUrlSchema).optional(),\n status: z.enum([\"ENABLED\", \"PAUSED\", \"REMOVED\"]).optional(),\n })\n .refine((p) => Object.values(p).some((v) => v !== undefined), \"update needs at least one field\");\nexport type KeywordUpdate = z.infer<typeof keywordUpdateSchema>;\n\nexport const negativeKeywordAddSchema = z.strictObject({\n level: z.enum([\"adGroup\", \"campaign\"]),\n parent: refSchema,\n text: keywordTextSchema,\n matchType: matchTypeSchema,\n});\nexport type NegativeKeywordAdd = z.infer<typeof negativeKeywordAddSchema>;\n\n// --- Shared sets (keyword lists) ---\n\nexport const sharedSetCreateSchema = z.strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.sharedSet.nameMax),\n type: z.enum(SHARED_SET_TYPES).default(\"NEGATIVE_KEYWORDS\"),\n});\nexport type SharedSetCreate = z.infer<typeof sharedSetCreateSchema>;\n\nexport const sharedSetMemberAddSchema = z.strictObject({\n sharedSet: refSchema,\n text: keywordTextSchema,\n matchType: matchTypeSchema,\n});\nexport type SharedSetMemberAdd = z.infer<typeof sharedSetMemberAddSchema>;\n\nexport const campaignSharedSetAttachSchema = z.strictObject({\n campaign: refSchema,\n sharedSet: refSchema,\n});\nexport type CampaignSharedSetAttach = z.infer<typeof campaignSharedSetAttachSchema>;\n\n// --- Ads (asset-based, discriminated on format) ---\n\nconst adTextAssetSchema = z.strictObject({\n text: z.string().min(1),\n pinnedField: z.enum(PINNED_FIELDS).optional(),\n});\n\n/**\n * Every ad-content format is STRICT. An ad's creative lives in format-specific fields\n * (`images` on an App ad, `marketingImageAssets` on a Display ad, …), so a payload that names the\n * wrong one used to parse clean — zod dropped the unknown key, the derived updateMask never\n * mentioned the image field, and publish shipped headlines only while every staged image was\n * created in the account and attached to nothing. Rejecting the unknown key is the only place that\n * failure is visible; by publish the agent is long gone.\n */\nconst responsiveSearchAdSchema = z.strictObject({\n format: z.literal(\"responsiveSearch\"),\n headlines: z\n .array(\n adTextAssetSchema.refine(\n (a) => a.text.length <= GOOGLE_ADS_LIMITS.responsiveSearchAd.headlineTextMax,\n \"headline exceeds 30 chars\",\n ),\n )\n .min(GOOGLE_ADS_LIMITS.responsiveSearchAd.headlinesMin)\n .max(GOOGLE_ADS_LIMITS.responsiveSearchAd.headlinesMax),\n descriptions: z\n .array(\n adTextAssetSchema.refine(\n (a) => a.text.length <= GOOGLE_ADS_LIMITS.responsiveSearchAd.descriptionTextMax,\n \"description exceeds 90 chars\",\n ),\n )\n .min(GOOGLE_ADS_LIMITS.responsiveSearchAd.descriptionsMin)\n .max(GOOGLE_ADS_LIMITS.responsiveSearchAd.descriptionsMax),\n path1: z.string().max(GOOGLE_ADS_LIMITS.responsiveSearchAd.pathMax).optional(),\n path2: z.string().max(GOOGLE_ADS_LIMITS.responsiveSearchAd.pathMax).optional(),\n finalUrls: z.array(httpsUrlSchema).min(1),\n});\n\nconst responsiveDisplayAdSchema = z.strictObject({\n format: z.literal(\"responsiveDisplay\"),\n headlines: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.responsiveDisplayAd.headlineTextMax) }))\n .min(1)\n .max(5),\n longHeadline: z.strictObject({\n text: z.string().min(1).max(GOOGLE_ADS_LIMITS.responsiveDisplayAd.longHeadlineTextMax),\n }),\n descriptions: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.responsiveDisplayAd.descriptionTextMax) }))\n .min(1)\n .max(5),\n businessName: z.string().min(1).max(GOOGLE_ADS_LIMITS.responsiveDisplayAd.businessNameMax),\n // A Responsive Display Ad's images are fields on the ad's own content (never campaign-level\n // asset links). Google requires ≥1 landscape marketing image (1.91:1) AND ≥1 square marketing\n // image (1:1) to serve; the logo images are optional.\n marketingImageAssets: z.array(refSchema).optional(),\n squareMarketingImageAssets: z.array(refSchema).optional(),\n logoImageAssets: z.array(refSchema).optional(),\n finalUrls: z.array(httpsUrlSchema).min(1),\n});\n\nconst callAdSchema = z.strictObject({\n format: z.literal(\"call\"),\n countryCode: z.string().length(2),\n phoneNumber: z.string().min(3),\n headline1: z.string().min(1).max(30),\n headline2: z.string().min(1).max(30),\n description1: z.string().min(1).max(90),\n description2: z.string().min(1).max(90),\n businessName: z.string().min(1).max(25),\n finalUrls: z.array(httpsUrlSchema).min(1),\n});\n\n/**\n * An App ad's counts were unbounded here until a publish carrying 6 descriptions came back as the\n * bare word \"Too many.\" — Google's whole-batch rejection names no field, no count, and no limit, and\n * by then every image asset in the same draft had already been created in the account. The caps are\n * cheap to enforce at stage time and unreadable at publish.\n */\nconst appAdSchema = z.strictObject({\n format: z.literal(\"app\"),\n headlines: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.appAd.headlineTextMax) }))\n .min(GOOGLE_ADS_LIMITS.appAd.headlinesMin)\n .max(GOOGLE_ADS_LIMITS.appAd.headlinesMax),\n descriptions: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.appAd.descriptionTextMax) }))\n .min(GOOGLE_ADS_LIMITS.appAd.descriptionsMin)\n .max(GOOGLE_ADS_LIMITS.appAd.descriptionsMax),\n // An App campaign ad carries its images on its own content (`AppAdInfo.images`), not as\n // campaign-level asset links — same shape as a responsive display ad's marketing images.\n images: z.array(refSchema).max(GOOGLE_ADS_LIMITS.appAd.imagesMax).optional(),\n // `AppAdInfo.youtube_videos` — an App ad's videos live on its content too. Without this field\n // there is no way to express \"keep these videos on the ad\", so a content update that only\n // restated headlines silently left the ad's videos to whatever the mask happened to omit.\n youtubeVideos: z.array(refSchema).max(GOOGLE_ADS_LIMITS.appAd.youtubeVideosMax).optional(),\n});\n\nconst videoAdSchema = z.strictObject({\n format: z.literal(\"video\"),\n // A raw YouTube id is not a publishable Google Ads reference — the video must be staged as\n // its own `google.asset.create` (type: youtubeVideo) first, then referenced here by asset ref.\n videoAssets: z.array(refSchema).min(1),\n finalUrls: z.array(httpsUrlSchema).min(1),\n});\n\nconst demandGenAdSchema = z.strictObject({\n format: z.literal(\"demandGen\"),\n /**\n * `Ad.name`. Accepted here but NOT required: a multi-asset Demand Gen ad published against a live\n * account with no name was created, and reads back with none. Only the video format requires one.\n */\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenAd.adNameMax).optional(),\n headlines: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenAd.headlineTextMax) }))\n .min(GOOGLE_ADS_LIMITS.demandGenAd.headlinesMin)\n .max(GOOGLE_ADS_LIMITS.demandGenAd.headlinesMax),\n descriptions: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenAd.descriptionTextMax) }))\n .min(GOOGLE_ADS_LIMITS.demandGenAd.descriptionsMin)\n .max(GOOGLE_ADS_LIMITS.demandGenAd.descriptionsMax),\n businessName: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenAd.businessNameMax),\n finalUrls: z.array(httpsUrlSchema).min(1),\n imageAssets: z.array(refSchema).optional(),\n squareImageAssets: z.array(refSchema).optional(),\n logoImageAssets: z.array(refSchema).optional(),\n});\n\n/**\n * The Demand Gen ad that runs a video (`DEMAND_GEN_VIDEO_RESPONSIVE_AD`). It is its own format\n * rather than a few optional fields on `demandGen` because Google gives it a different message\n * (`demandGenVideoResponsiveAd`), a `longHeadlines` list no other Demand Gen ad has, and a\n * `businessName` that is a text ASSET rather than a bare string. Folding the two together would put\n * `longHeadlines` on a payload that publishes into a message with no such field.\n *\n * `videoAssets` / `logoImageAssets` / `callToActionAssets` are optional so a copy-only edit can omit\n * them: an ad update masks only the fields it sends, so an omitted media list is left as it is on\n * the ad (the same contract as an App ad's `images`). A CREATE needs at least one video — Google\n * refuses it otherwise, and `demandGenVideoNeedsVideoRefusal` says so before a publish does.\n */\nconst demandGenVideoAdSchema = z.strictObject({\n format: z.literal(\"demandGenVideo\"),\n /**\n * `Ad.name` — the ad's own name, which Google REQUIRES on this format and asks for in its\n * interface as \"Ad name\". No other format Baker writes needs one (the multi-asset Demand Gen ad\n * was published without one and accepted), so nothing carried it: a create without it comes back\n * as `REQUIRED … at mutate_operations[n].ad_group_ad_operation.create.ad.name`, after every asset\n * in the same batch has already been created. Optional in the schema because `Ad.name` is\n * IMMUTABLE — an update must be able to restate the whole content without renaming the ad.\n */\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenVideoAd.adNameMax).optional(),\n headlines: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenVideoAd.headlineTextMax) }))\n .min(GOOGLE_ADS_LIMITS.demandGenVideoAd.headlinesMin)\n .max(GOOGLE_ADS_LIMITS.demandGenVideoAd.headlinesMax),\n longHeadlines: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenVideoAd.longHeadlineTextMax) }))\n .min(GOOGLE_ADS_LIMITS.demandGenVideoAd.longHeadlinesMin)\n .max(GOOGLE_ADS_LIMITS.demandGenVideoAd.longHeadlinesMax),\n descriptions: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenVideoAd.descriptionTextMax) }))\n .min(GOOGLE_ADS_LIMITS.demandGenVideoAd.descriptionsMin)\n .max(GOOGLE_ADS_LIMITS.demandGenVideoAd.descriptionsMax),\n businessName: z.string().min(1).max(GOOGLE_ADS_LIMITS.demandGenVideoAd.businessNameMax),\n finalUrls: z.array(httpsUrlSchema).min(1),\n videoAssets: z.array(refSchema).optional(),\n logoImageAssets: z.array(refSchema).optional(),\n callToActionAssets: z.array(refSchema).optional(),\n});\n\nexport const adContentSchema = z.discriminatedUnion(\"format\", [\n responsiveSearchAdSchema,\n responsiveDisplayAdSchema,\n callAdSchema,\n appAdSchema,\n videoAdSchema,\n demandGenAdSchema,\n demandGenVideoAdSchema,\n]);\nexport type AdContent = z.infer<typeof adContentSchema>;\nexport type AdFormat = AdContent[\"format\"];\n\nexport const adCreateSchema = z.strictObject({\n adGroup: refSchema,\n status: stageableStatusSchema.default(\"PAUSED\"),\n content: adContentSchema,\n});\nexport type AdCreate = z.infer<typeof adCreateSchema>;\n\nexport const adUpdateSchema = z\n .strictObject({\n status: z.enum([\"ENABLED\", \"PAUSED\", \"REMOVED\"]).optional(),\n /** Whole-content replacement for RSA-like formats; re-validated against adContentSchema. */\n content: z.record(z.string(), z.unknown()).optional(),\n })\n .refine((p) => Object.values(p).some((v) => v !== undefined), \"update needs at least one field\");\nexport type AdUpdate = z.infer<typeof adUpdateSchema>;\n\n// --- Assets & extensions ---\n\nconst textAssetSchema = z.strictObject({ type: z.literal(\"text\"), text: z.string().min(1) });\nconst imageAssetSchema = z.strictObject({\n type: z.literal(\"image\"),\n imageId: z.string().min(1),\n name: z.string().optional(),\n});\nconst youtubeVideoAssetSchema = z.strictObject({\n type: z.literal(\"youtubeVideo\"),\n youtubeVideoId: z.string().min(1),\n name: z.string().optional(),\n});\nconst sitelinkAssetSchema = z.strictObject({\n type: z.literal(\"sitelink\"),\n linkText: z.string().min(1).max(GOOGLE_ADS_LIMITS.asset.sitelinkLinkTextMax),\n description1: z.string().max(GOOGLE_ADS_LIMITS.asset.sitelinkDescriptionMax).optional(),\n description2: z.string().max(GOOGLE_ADS_LIMITS.asset.sitelinkDescriptionMax).optional(),\n finalUrls: z.array(httpsUrlSchema).min(1),\n});\nconst calloutAssetSchema = z.strictObject({\n type: z.literal(\"callout\"),\n calloutText: z.string().min(1).max(GOOGLE_ADS_LIMITS.asset.calloutTextMax),\n});\n/**\n * A structured snippet header is not free text: Google accepts only its own\n * published headers (or their translations) and rejects anything else at publish\n * with an error naming neither the field nor the list. Checked here so an\n * invented header can never be staged, and rewritten to Google's spelling so a\n * casing difference is not a lost asset.\n *\n * The list IS the length limit, so there is no `max()` in front of it. There was\n * one, borrowed from the 25-character cap on a snippet's VALUES, and it made the\n * Russian \"Degree programs\" (29 characters) the one published header Baker could\n * not stage. A cap in front of a closed vocabulary can only reject things the\n * vocabulary already accepts.\n */\nconst structuredSnippetHeaderSchema = z\n .string()\n .min(1)\n .transform((header, ctx) => {\n const canonical = canonicalStructuredSnippetHeader(header);\n if (!canonical) {\n ctx.addIssue({\n code: \"custom\",\n message:\n `Google Ads does not accept \"${header}\" as a structured snippet header. Use one of: ` +\n `${STRUCTURED_SNIPPET_HEADERS_EN.join(\", \")} — or that header in the campaign's language.`,\n });\n return z.NEVER;\n }\n return canonical;\n });\n\nconst structuredSnippetAssetSchema = z.strictObject({\n type: z.literal(\"structuredSnippet\"),\n header: structuredSnippetHeaderSchema,\n values: z\n .array(z.string().min(1).max(GOOGLE_ADS_LIMITS.asset.structuredSnippetValueMax))\n .min(GOOGLE_ADS_LIMITS.asset.structuredSnippetValuesMin)\n .max(GOOGLE_ADS_LIMITS.asset.structuredSnippetValuesMax),\n});\nconst callToActionAssetSchema = z.strictObject({ type: z.literal(\"callToAction\"), callToAction: z.string().min(1) });\n\nexport const assetCreateSchema = z.discriminatedUnion(\"type\", [\n textAssetSchema,\n imageAssetSchema,\n youtubeVideoAssetSchema,\n sitelinkAssetSchema,\n calloutAssetSchema,\n structuredSnippetAssetSchema,\n callToActionAssetSchema,\n]);\nexport type AssetCreate = z.infer<typeof assetCreateSchema>;\n\n/**\n * Flat partial of the mutable fields across every asset type — the caller doesn't repeat the\n * asset's `type` discriminant to amend it. Live publish maps fields to their sub-message via an\n * updateMask (`sitelinkAsset.linkText`, `calloutAsset.calloutText`, …); Google mutates any asset\n * subtype through the same `AssetOperation.update`, and only the fields actually set are masked.\n */\nexport const assetUpdateSchema = z\n .strictObject({\n name: z.string().min(1).optional(),\n linkText: z.string().min(1).max(GOOGLE_ADS_LIMITS.asset.sitelinkLinkTextMax).optional(),\n description1: z.string().max(GOOGLE_ADS_LIMITS.asset.sitelinkDescriptionMax).optional(),\n description2: z.string().max(GOOGLE_ADS_LIMITS.asset.sitelinkDescriptionMax).optional(),\n finalUrls: z.array(httpsUrlSchema).min(1).optional(),\n calloutText: z.string().min(1).max(GOOGLE_ADS_LIMITS.asset.calloutTextMax).optional(),\n header: structuredSnippetHeaderSchema.optional(),\n values: z\n .array(z.string().min(1).max(GOOGLE_ADS_LIMITS.asset.structuredSnippetValueMax))\n .min(GOOGLE_ADS_LIMITS.asset.structuredSnippetValuesMin)\n .max(GOOGLE_ADS_LIMITS.asset.structuredSnippetValuesMax)\n .optional(),\n callToAction: z.string().min(1).optional(),\n text: z.string().min(1).optional(),\n })\n .refine((p) => Object.values(p).some((v) => v !== undefined), \"update needs at least one field\");\nexport type AssetUpdate = z.infer<typeof assetUpdateSchema>;\n\nexport const assetLinkAttachSchema = z\n .strictObject({\n level: z.enum([\"campaign\", \"adGroup\", \"customer\"]),\n parent: refSchema.optional(),\n asset: refSchema,\n // A plain string, not `z.enum(ASSET_FIELD_TYPES)`, so the image refusal below can answer with\n // the reason instead of an enum listing. An agent reaching for AD_IMAGE is following Google's\n // own documentation; \"Invalid option: expected one of …\" sends it to guess another field type,\n // which is the failure this whole refusal exists to end.\n fieldType: z.string().min(1),\n })\n .superRefine((value, ctx) => {\n // Customer-level links attach account-wide; campaign/adGroup links without a parent\n // build a mutate operation missing its required campaign/adGroup and fail at publish.\n if (value.level !== \"customer\" && !value.parent) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"parent\"],\n message: `parent is required for a ${value.level}-level asset link (--parent-ref)`,\n });\n }\n if (value.fieldType === \"BUSINESS_LOGO\" && value.level === \"adGroup\") {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: [\"fieldType\"], message: BUSINESS_LOGO_LEVEL_MESSAGE });\n } else if (isImageAssetLinkFieldType(value.fieldType)) {\n // Parses, and is decided at stage time: AD_IMAGE is asked of Google per account and stages or\n // hands over; a marketing-image type is sent back to AD_IMAGE. Refusing it HERE cost the user the\n // handover: a schema refusal leaves no chat to record against, and a batch carrying sitelinks\n // alongside the image failed whole. See `ads/google/writes/stage.ts`.\n } else if (!(ASSET_FIELD_TYPES as readonly string[]).includes(value.fieldType)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"fieldType\"],\n message: `expected one of ${ASSET_FIELD_TYPES.join(\" | \")}`,\n });\n }\n });\nexport type AssetLinkAttach = z.infer<typeof assetLinkAttachSchema>;\n\n// --- Performance Max asset groups ---\n\n/**\n * A Performance Max asset group — its own entity, not an ad format. Publish synthesizes a text\n * asset per headline/longHeadline/description/businessName plus one `AssetGroupAsset` link per\n * asset (see the publish builder); staging here only carries the group's copy + image refs.\n */\nexport const assetGroupCreateSchema = z.strictObject({\n campaign: refSchema,\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.assetGroup.nameMax),\n finalUrls: z.array(httpsUrlSchema).min(1),\n headlines: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.assetGroup.headlineTextMax) }))\n .min(GOOGLE_ADS_LIMITS.assetGroup.headlinesMin)\n .max(GOOGLE_ADS_LIMITS.assetGroup.headlinesMax),\n longHeadlines: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.assetGroup.longHeadlineTextMax) }))\n .min(GOOGLE_ADS_LIMITS.assetGroup.longHeadlinesMin)\n .max(GOOGLE_ADS_LIMITS.assetGroup.longHeadlinesMax),\n descriptions: z\n .array(z.strictObject({ text: z.string().min(1).max(GOOGLE_ADS_LIMITS.assetGroup.descriptionTextMax) }))\n .min(GOOGLE_ADS_LIMITS.assetGroup.descriptionsMin)\n .max(GOOGLE_ADS_LIMITS.assetGroup.descriptionsMax),\n businessName: z.string().min(1).max(GOOGLE_ADS_LIMITS.assetGroup.businessNameMax),\n imageAssets: z.array(refSchema).optional(),\n squareImageAssets: z.array(refSchema).optional(),\n portraitImageAssets: z.array(refSchema).optional(),\n logoAssets: z.array(refSchema).optional(),\n status: z.enum([\"ENABLED\", \"PAUSED\"]).default(\"PAUSED\"),\n});\nexport type AssetGroupCreate = z.infer<typeof assetGroupCreateSchema>;\n\n/**\n * Link one already-existing asset into an already-existing asset group. `assetGroup.create` links a\n * group's opening set of assets inline, and `assetLink.attach` covers campaign/adGroup/customer\n * links — neither can touch the assets of a group that is already live, which is what a creative\n * refresh actually is. Detach is the plain target-only twin (`google.assetGroupAsset.detach`), whose\n * target is the composite `customers/{cid}/assetGroupAssets/{group}~{asset}~{FIELD_TYPE}`.\n *\n * Swapping a creative is attach-then-detach, and the order they are STAGED in is the order they\n * publish in — `planBatchWindows` sorts by stage index and Google Ads removals carry no dependency\n * edge (docs/publishing.md → Known gap). Detach staged first therefore reaches Google first, and if\n * it was the last asset of that field type the group drops below its per-ratio minimum and the\n * operation is rejected. The attach has to be staged first; nothing reorders it for you.\n */\nexport const assetGroupAssetAttachSchema = z.strictObject({\n assetGroup: refSchema,\n asset: refSchema,\n fieldType: z.enum(ASSET_GROUP_ASSET_FIELD_TYPES),\n});\nexport type AssetGroupAssetAttach = z.infer<typeof assetGroupAssetAttachSchema>;\n\nexport const assetGroupUpdateSchema = z\n .strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.assetGroup.nameMax).optional(),\n finalUrls: z.array(httpsUrlSchema).min(1).optional(),\n status: z.enum([\"ENABLED\", \"PAUSED\", \"REMOVED\"]).optional(),\n })\n .refine((p) => Object.values(p).some((v) => v !== undefined), \"update needs at least one field\");\nexport type AssetGroupUpdate = z.infer<typeof assetGroupUpdateSchema>;\n\n// --- Audiences (user lists) & audience criteria ---\n\nexport const audienceCreateSchema = z.strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.audience.nameMax),\n type: z.enum(USER_LIST_TYPES).default(\"BASIC\"),\n description: z.string().optional(),\n /** Customer-match members (crm-based) — file-first for large lists. */\n members: z.array(z.record(z.string(), z.string())).optional(),\n sourceFileRef: z.string().optional(),\n});\nexport type AudienceCreate = z.infer<typeof audienceCreateSchema>;\n\n/**\n * Strict, for the same reason `geoTargetTypeSetting` is: a key this schema does not know used to\n * vanish between the command line and the stored payload, and the op published on Google's default.\n * Here that default is the expensive one — an audience criterion whose dimension has no\n * `bid_only: true` restriction RESTRICTS the parent's reach to the list (Google's API default is\n * Targeting mode, unlike the interface, which offers Observation). `bidOnly` and `targetingSetting`\n * were both tried against this op in production and both were silently dropped; the campaign was\n * one publish away from serving only to a 6,700-person remarketing list. Whether the parent\n * restricts is not a property of the criterion at all — it lives on the campaign/ad group, so it is\n * set by `google.targetingSetting.set` and refused here rather than quietly ignored.\n */\nexport const audienceCriterionAttachSchema = z.strictObject({\n level: z.enum([\"campaign\", \"adGroup\"]),\n parent: refSchema,\n userList: refSchema,\n negative: z.boolean().default(false),\n});\nexport type AudienceCriterionAttach = z.infer<typeof audienceCriterionAttachSchema>;\n\n/**\n * One `TargetingSetting.target_restrictions` row: a targeting dimension plus whether criteria in it\n * only move bids (`bidOnly: true`, the interface's \"Observation\") or also restrict who sees the ads\n * (`bidOnly: false`, \"Targeting\").\n */\nconst targetRestrictionSchema = z.strictObject({\n targetingDimension: z.enum(TARGETING_DIMENSIONS),\n bidOnly: z.boolean(),\n});\nexport type GoogleTargetRestriction = z.infer<typeof targetRestrictionSchema>;\n\n/**\n * Switch the AUDIENCE dimension of a campaign's or ad group's targeting setting between Observation\n * and Targeting — the selector the Google Ads interface shows next to an audience, which the API\n * does not default the same way (see `audienceCriterionAttachSchema`).\n *\n * Two things are load-bearing:\n *\n * - **The parent is in the payload, not in `target`.** It has to resolve a `g_temp_*` ref, because\n * the case that costs money most is an ad group created in this same draft: it starts with no\n * AUDIENCE restriction at all, so an audience attached to it publishes in Targeting mode.\n * - **`preserved` is resolved at stage time from the live setting and never supplied by the\n * caller.** `target_restrictions` is a repeated field, and Google replaces it wholesale on write,\n * so the AGE_RANGE / GENDER / PARENTAL_STATUS / INCOME_RANGE rows an account already carries have\n * to be re-sent verbatim or they are wiped along with any bid adjustment behind them. It stays\n * `.optional()` here because that is the truth of the input shape — the request builder refuses\n * to build without it rather than send a write that silently drops the other dimensions.\n */\nexport const targetingSettingSetSchema = z.strictObject({\n level: z.enum([\"campaign\", \"adGroup\"]),\n parent: refSchema,\n audience: z.enum([\"OBSERVATION\", \"TARGETING\"]),\n preserved: z.array(targetRestrictionSchema).optional(),\n});\nexport type TargetingSettingSet = z.infer<typeof targetingSettingSetSchema>;\n\n// --- Conversion actions ---\n\n/**\n * Every field below that Baker fills in when the payload is silent is `.optional()` here and\n * defaulted by `resolveConversionActionCreate` instead — never by `z.default()`.\n *\n * A `.default()` is invisible after the fact: the parsed payload cannot tell \"the agent chose\n * ONE_PER_CLICK\" from \"the agent said nothing\", and that payload is what gets stored, re-read on\n * every amend, and rendered on the review card. Keeping the omission in the stored payload is what\n * lets `collectOpWarnings` surface a filled-in business decision as a reviewable one — and it keeps\n * surviving an amend, which re-parses the STORED payload and would otherwise see five explicit\n * choices the agent never made.\n */\nexport const conversionActionCreateSchema = z.strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.conversionAction.nameMax),\n type: z.enum(CONVERSION_ACTION_TYPES).optional(),\n category: z.enum(CONVERSION_ACTION_CATEGORIES).optional(),\n countingType: z.enum(CONVERSION_COUNTING_TYPES).optional(),\n defaultValueMicros: microsSchema.optional(),\n defaultCurrencyCode: z.string().length(3).optional(),\n clickThroughLookbackWindowDays: z.number().int().positive().optional(),\n viewThroughLookbackWindowDays: z.number().int().positive().optional(),\n status: z.enum([\"ENABLED\", \"PAUSED\"]).optional(),\n /**\n * Primary = Google bids toward this conversion; secondary = it is only reported (\"Primary action\n * used for bidding optimization\" / \"Secondary action not used for bidding optimization\" in the UI).\n * Resolves to SECONDARY on create, deliberately: left unset ON THE WIRE, Google picks — and in a\n * live account some actions were born primary and some secondary, so a new action could silently\n * join the bidding target of every Maximize-Conversions campaign and redirect real spend. Nothing\n * exists yet to flip on a create, so a fixed resolved value is safe here in a way it would never be\n * on an update: joining bidding becomes an explicit `primaryForGoal: true`, never an accident.\n */\n primaryForGoal: z.boolean().optional(),\n});\nexport type ConversionActionCreate = z.infer<typeof conversionActionCreateSchema>;\n\n/**\n * What Baker sends for a conversion-action create field the payload left out. Applied on the way OUT\n * — at publish, on the review card, and in the op summary — never on the way in (see the schema\n * above). `primaryForGoal` in particular must always be sent: omitting it on the wire lets Google\n * decide the new action's bidding role.\n */\nexport const CONVERSION_ACTION_CREATE_DEFAULTS = {\n type: \"WEBPAGE\",\n category: \"DEFAULT\",\n countingType: \"ONE_PER_CLICK\",\n status: \"ENABLED\",\n primaryForGoal: false,\n} as const satisfies Partial<ConversionActionCreate>;\n\nexport type ResolvedConversionActionCreate = ConversionActionCreate &\n Required<Pick<ConversionActionCreate, \"type\" | \"category\" | \"countingType\" | \"status\" | \"primaryForGoal\">>;\n\n/** A create payload with every unstated field filled in — what actually reaches Google. */\nexport function resolveConversionActionCreate(payload: ConversionActionCreate): ResolvedConversionActionCreate {\n return {\n ...payload,\n type: payload.type ?? CONVERSION_ACTION_CREATE_DEFAULTS.type,\n category: payload.category ?? CONVERSION_ACTION_CREATE_DEFAULTS.category,\n countingType: payload.countingType ?? CONVERSION_ACTION_CREATE_DEFAULTS.countingType,\n status: payload.status ?? CONVERSION_ACTION_CREATE_DEFAULTS.status,\n primaryForGoal: payload.primaryForGoal ?? CONVERSION_ACTION_CREATE_DEFAULTS.primaryForGoal,\n };\n}\n\n/**\n * An agent reaching for `HIDDEN` wants \"stop counting this without deleting it\", so saying only\n * \"not a valid value\" sends it to `REMOVED` on an action it never meant to retire. Name both real\n * routes instead: demote to secondary keeps the measurement and takes it out of bidding, `REMOVED`\n * stops the measurement.\n */\nconst HIDDEN_CONVERSION_STATUS_ERROR =\n 'Google rejects status HIDDEN on every conversion action write (\"the field\\'s value is on a deny-list\"), so it is not part of this contract. ' +\n \"To stop automated bidding optimizing toward a conversion while it keeps measuring, demote it instead: `baker ads google conversions update --target <id> --no-primary`. \" +\n 'To stop it counting altogether, use `status: \"REMOVED\"`. Pick one of those and carry on with the rest of the job.';\n\nexport const conversionActionUpdateSchema = z\n .strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.conversionAction.nameMax).optional(),\n category: z.enum(CONVERSION_ACTION_CATEGORIES).optional(),\n countingType: z.enum(CONVERSION_COUNTING_TYPES).optional(),\n defaultValueMicros: microsSchema.optional(),\n defaultCurrencyCode: z.string().length(3).optional(),\n clickThroughLookbackWindowDays: z.number().int().positive().optional(),\n viewThroughLookbackWindowDays: z.number().int().positive().optional(),\n /**\n * `HIDDEN` is deliberately not writable. Google returns it — an action hidden long ago reads\n * back as HIDDEN, and every read path keeps it — but it is on the API's deny-list for a write:\n * `conversion_action.status = HIDDEN` fails with \"The field's value is on a deny-list for this\n * field\" even on an ordinary WEBPAGE action with nothing else wrong. Offering it made it the\n * obvious pick for an agent told to retire an action gently, and the whole cleanup published\n * nothing.\n */\n status: z\n .enum([\"ENABLED\", \"REMOVED\"], {\n error: (issue) => (issue.input === \"HIDDEN\" ? HIDDEN_CONVERSION_STATUS_ERROR : undefined),\n })\n .optional(),\n /** Promote to primary (bid toward it) or demote to secondary (report only). No default — an\n * update must never change an existing action's bidding role unless it was asked to. */\n primaryForGoal: z.boolean().optional(),\n })\n .refine((p) => Object.values(p).some((v) => v !== undefined), \"update needs at least one field\")\n .refine(\n (p) => p.status !== \"REMOVED\" || Object.entries(p).every(([k, v]) => k === \"status\" || v === undefined),\n 'removing a conversion action cannot be combined with other edits — `status: \"REMOVED\"` deletes it, so a name or category sent alongside would be silently discarded. Stage the removal on its own.',\n );\nexport type ConversionActionUpdate = z.infer<typeof conversionActionUpdateSchema>;\n\n// --- Account-level conversion goals ---\n\n/**\n * `CustomerConversionGoal` — the account-level half of \"does this conversion drive bidding\".\n *\n * A conversion action steers automated bidding only when BOTH halves agree: the action is\n * `primaryForGoal`, AND the account-level goal for its (category, origin) pair is `biddable`. Google\n * creates one goal row per pair automatically as conversion actions appear, so this op never creates\n * or removes anything — it flips the one writable field on a row that already exists.\n *\n * ONE op per (category, origin), never a bag of pairs. Google's own samples mutate several goals in a\n * single request to make exactly one biddable, but atomicity is not what that buys here: a whole draft\n * already publishes as one `GoogleAdsService.Mutate` batch, so N staged ops land in N operations of the\n * SAME request and get exactly Google's semantics. What a multi-pair payload would cost is everything\n * the surface keys off one-op-one-change — a review card the user reads as a single decision, per-op\n * amend, per-op no-op detection, and per-op error attribution at publish.\n *\n * Both key halves are immutable on the resource, so they are the address, not an edit: only `biddable`\n * ever changes, and it is never defaulted — this op moves what the account bids toward in both\n * directions, and an op that forgot to say which way must fail rather than pick one.\n */\nexport const conversionGoalSetSchema = z.strictObject({\n category: z.enum(CONVERSION_ACTION_CATEGORIES),\n origin: z.enum(CONVERSION_ORIGINS),\n /** True = conversions of this category/origin count toward automated bidding; false = reported only. */\n biddable: z.boolean(),\n});\nexport type ConversionGoalSet = z.infer<typeof conversionGoalSetSchema>;\n\n/** `customers/{cid}/customerConversionGoals/{CATEGORY}~{ORIGIN}` — the goal's resource name is its key. */\nexport function conversionGoalResourceName(customerId: string, category: string, origin: string): string {\n return `customers/${customerId}/customerConversionGoals/${category}~${origin}`;\n}\n\n/** \"PURCHASE\" + \"WEBSITE\" → `Purchase (website)` — how the Goals table names the pair. */\nexport function conversionGoalLabel(category: string, origin: string): string {\n const words = (value: string) => value.toLowerCase().replace(/_/g, \" \");\n const category_ = words(category);\n return `${category_.charAt(0).toUpperCase()}${category_.slice(1)} (${words(origin)})`;\n}\n\n// --- Portfolio bidding strategies ---\n\n/**\n * Google's BiddingStrategy resource carries no target_cpc scheme — Demand Gen's target CPC is\n * campaign-level only. Accepting it on either verb would stage an op that can only fail at publish,\n * inside an atomic batch, taking every co-staged op down with it — so the create and the update\n * refuse it with the same sentence.\n */\nconst PORTFOLIO_TARGET_CPC_MESSAGE =\n \"portfolio strategies cannot be Target CPC — it is set on the Demand Gen campaign itself\";\n\nexport const biddingStrategyCreateSchema = z\n .strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.biddingStrategy.nameMax),\n config: biddingConfigSchema,\n })\n .superRefine((p, ctx) => {\n if (p.config.type === \"MANUAL_CPC\") {\n ctx.addIssue({ code: \"custom\", path: [\"config\", \"type\"], message: \"portfolio strategies cannot be Manual CPC\" });\n }\n if (p.config.type === \"TARGET_CPC\") {\n ctx.addIssue({ code: \"custom\", path: [\"config\", \"type\"], message: PORTFOLIO_TARGET_CPC_MESSAGE });\n }\n });\nexport type BiddingStrategyCreate = z.infer<typeof biddingStrategyCreateSchema>;\n\nexport const biddingStrategyUpdateSchema = z\n .strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.biddingStrategy.nameMax).optional(),\n config: biddingConfigSchema.optional(),\n })\n .superRefine((p, ctx) => {\n if (Object.values(p).every((v) => v === undefined)) {\n ctx.addIssue({ code: \"custom\", message: \"update needs at least one field\" });\n }\n if (p.config?.type === \"TARGET_CPC\") {\n ctx.addIssue({ code: \"custom\", path: [\"config\", \"type\"], message: PORTFOLIO_TARGET_CPC_MESSAGE });\n }\n });\nexport type BiddingStrategyUpdate = z.infer<typeof biddingStrategyUpdateSchema>;\n\n// --- Labels ---\n\nexport const labelCreateSchema = z.strictObject({\n name: z.string().min(1).max(GOOGLE_ADS_LIMITS.label.nameMax),\n backgroundColor: z\n .string()\n .regex(/^#[0-9A-Fa-f]{6}$/)\n .optional(),\n description: z.string().optional(),\n});\nexport type LabelCreate = z.infer<typeof labelCreateSchema>;\n\nexport const labelAttachSchema = z.strictObject({\n level: z.enum([\"campaign\", \"adGroup\", \"ad\"]),\n parent: refSchema,\n label: refSchema,\n});\nexport type LabelAttach = z.infer<typeof labelAttachSchema>;\n\n// --- Campaign criteria (location/language/adSchedule/device) ---\n\nconst locationCriterionSchema = z.strictObject({\n criterionType: z.literal(\"location\"),\n geoTargetConstant: z.union([z.string().regex(GEO_TARGET_CONSTANT_REGEX), z.string().regex(NUMERIC_ID_REGEX)]),\n});\nconst languageCriterionSchema = z.strictObject({\n criterionType: z.literal(\"language\"),\n languageConstant: z.union([z.string().regex(LANGUAGE_CONSTANT_REGEX), z.string().regex(NUMERIC_ID_REGEX)]),\n});\nconst adScheduleCriterionSchema = z.strictObject({\n criterionType: z.literal(\"adSchedule\"),\n dayOfWeek: z.enum(DAYS_OF_WEEK),\n startHour: z.number().int().min(0).max(23),\n startMinute: z.enum([\"ZERO\", \"FIFTEEN\", \"THIRTY\", \"FORTY_FIVE\"]).default(\"ZERO\"),\n endHour: z.number().int().min(0).max(24),\n endMinute: z.enum([\"ZERO\", \"FIFTEEN\", \"THIRTY\", \"FORTY_FIVE\"]).default(\"ZERO\"),\n});\n// Google's `CampaignCriterion.bid_modifier`: \"The modifier must be in the range 0.1 - 10.0. Use 0\n// to opt out of a Device type.\" So 0 (exclude the device) and 0.1–10.0 are valid; the (0, 0.1) gap is not.\nconst bidModifierSchema = z\n .number()\n .min(0)\n .max(10)\n .refine((v) => v === 0 || v >= 0.1, {\n message: \"bid modifier must be 0 (exclude the device) or between 0.1 and 10.0\",\n });\n\nconst deviceCriterionSchema = z.strictObject({\n criterionType: z.literal(\"device\"),\n device: z.enum(DEVICE_TYPES),\n bidModifier: bidModifierSchema.optional(),\n});\n\nexport const campaignCriterionAddSchema = z\n .strictObject({\n campaign: refSchema,\n negative: z.boolean().default(false),\n criterion: z.discriminatedUnion(\"criterionType\", [\n locationCriterionSchema,\n languageCriterionSchema,\n adScheduleCriterionSchema,\n deviceCriterionSchema,\n ]),\n })\n // Cross-field on the ad-schedule criterion: endHour 24 is midnight, which has no partial-hour\n // component — Google rejects a non-zero endMinute with it, so fail fast at stage time instead.\n // Lives here (not on the criterion option) because a discriminated-union option must stay a plain\n // object; a `.refine()` there would turn it into a ZodEffects the union can't accept.\n .superRefine((val, ctx) => {\n const c = val.criterion;\n if (c.criterionType === \"adSchedule\" && c.endHour === 24 && c.endMinute !== \"ZERO\") {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"endHour 24 (midnight) cannot have a non-zero endMinute\",\n path: [\"criterion\", \"endMinute\"],\n });\n }\n });\nexport type CampaignCriterionAdd = z.infer<typeof campaignCriterionAddSchema>;\n\n/**\n * The one thing a live campaign criterion lets you change.\n *\n * A device criterion can be added and re-bid, but never removed — Google rejects the removal even\n * of one the same account created itself. So \"stop bidding up on desktop\" is an UPDATE of\n * `bid_modifier` back to 1.0 and \"don't serve on desktop\" is an update to 0, where a removal is\n * rejected outright; this op exists to give the agent that route.\n * Everything else on the resource (which geo, which language, negative or not) is create-only:\n * changing what a criterion targets means removing it and adding the replacement.\n */\nexport const campaignCriterionUpdateSchema = z.strictObject({\n bidModifier: bidModifierSchema,\n});\nexport type CampaignCriterionUpdate = z.infer<typeof campaignCriterionUpdateSchema>;\n\n// --- The op union ---\n\nexport const GOOGLE_DRAFT_OP_KINDS = [\n \"google.budget.create\",\n \"google.budget.update\",\n \"google.campaign.create\",\n \"google.campaign.update\",\n \"google.campaign.pause\",\n \"google.campaign.resume\",\n \"google.campaign.remove\",\n \"google.adGroup.create\",\n \"google.adGroup.update\",\n \"google.adGroup.pause\",\n \"google.adGroup.resume\",\n \"google.adGroup.remove\",\n \"google.keyword.add\",\n \"google.keyword.update\",\n \"google.keyword.remove\",\n \"google.negativeKeyword.add\",\n \"google.negativeKeyword.remove\",\n \"google.sharedSet.create\",\n \"google.sharedSetMember.add\",\n \"google.sharedSetMember.remove\",\n \"google.campaignSharedSet.attach\",\n \"google.campaignSharedSet.detach\",\n \"google.ad.create\",\n \"google.ad.update\",\n \"google.ad.pause\",\n \"google.ad.resume\",\n \"google.ad.remove\",\n \"google.asset.create\",\n \"google.asset.update\",\n \"google.assetLink.attach\",\n \"google.assetLink.detach\",\n \"google.assetGroup.create\",\n \"google.assetGroup.update\",\n \"google.assetGroupAsset.attach\",\n \"google.assetGroupAsset.detach\",\n \"google.audience.create\",\n \"google.audienceCriterion.attach\",\n \"google.audienceCriterion.detach\",\n \"google.targetingSetting.set\",\n \"google.conversionAction.create\",\n \"google.conversionAction.update\",\n \"google.conversionAction.goal\",\n \"google.conversion.upload\",\n \"google.biddingStrategy.create\",\n \"google.biddingStrategy.update\",\n \"google.label.create\",\n \"google.label.attach\",\n \"google.campaignCriterion.add\",\n \"google.campaignCriterion.update\",\n \"google.campaignCriterion.remove\",\n] as const;\nexport const googleDraftOpKindSchema = z.enum(GOOGLE_DRAFT_OP_KINDS);\nexport type GoogleDraftOpKind = z.infer<typeof googleDraftOpKindSchema>;\n\nfunction createOp<K extends GoogleDraftOpKind, P extends z.ZodTypeAny>(kind: K, payload: P) {\n return z.object({ kind: z.literal(kind), customerId: customerIdSchema, payload });\n}\nfunction updateOp<K extends GoogleDraftOpKind, P extends z.ZodTypeAny>(kind: K, payload: P) {\n return z.object({ kind: z.literal(kind), customerId: customerIdSchema, target: targetRefSchema, payload });\n}\n/** Pause/resume/remove/detach ops carry only a target — no payload. */\nfunction targetOp<K extends GoogleDraftOpKind>(kind: K) {\n return z.object({ kind: z.literal(kind), customerId: customerIdSchema, target: targetRefSchema });\n}\n\nexport const googleDraftOpInputSchema = z.discriminatedUnion(\"kind\", [\n createOp(\"google.budget.create\", budgetCreateSchema),\n updateOp(\"google.budget.update\", budgetUpdateSchema),\n createOp(\"google.campaign.create\", campaignCreateSchema),\n updateOp(\"google.campaign.update\", campaignUpdateSchema),\n targetOp(\"google.campaign.pause\"),\n targetOp(\"google.campaign.resume\"),\n targetOp(\"google.campaign.remove\"),\n createOp(\"google.adGroup.create\", adGroupCreateSchema),\n updateOp(\"google.adGroup.update\", adGroupUpdateSchema),\n targetOp(\"google.adGroup.pause\"),\n targetOp(\"google.adGroup.resume\"),\n targetOp(\"google.adGroup.remove\"),\n createOp(\"google.keyword.add\", keywordAddSchema),\n updateOp(\"google.keyword.update\", keywordUpdateSchema),\n targetOp(\"google.keyword.remove\"),\n createOp(\"google.negativeKeyword.add\", negativeKeywordAddSchema),\n targetOp(\"google.negativeKeyword.remove\"),\n createOp(\"google.sharedSet.create\", sharedSetCreateSchema),\n createOp(\"google.sharedSetMember.add\", sharedSetMemberAddSchema),\n targetOp(\"google.sharedSetMember.remove\"),\n createOp(\"google.campaignSharedSet.attach\", campaignSharedSetAttachSchema),\n targetOp(\"google.campaignSharedSet.detach\"),\n createOp(\"google.ad.create\", adCreateSchema),\n updateOp(\"google.ad.update\", adUpdateSchema),\n targetOp(\"google.ad.pause\"),\n targetOp(\"google.ad.resume\"),\n targetOp(\"google.ad.remove\"),\n createOp(\"google.asset.create\", assetCreateSchema),\n updateOp(\"google.asset.update\", assetUpdateSchema),\n createOp(\"google.assetLink.attach\", assetLinkAttachSchema),\n targetOp(\"google.assetLink.detach\"),\n createOp(\"google.assetGroup.create\", assetGroupCreateSchema),\n updateOp(\"google.assetGroup.update\", assetGroupUpdateSchema),\n createOp(\"google.assetGroupAsset.attach\", assetGroupAssetAttachSchema),\n targetOp(\"google.assetGroupAsset.detach\"),\n createOp(\"google.audience.create\", audienceCreateSchema),\n createOp(\"google.audienceCriterion.attach\", audienceCriterionAttachSchema),\n targetOp(\"google.audienceCriterion.detach\"),\n createOp(\"google.targetingSetting.set\", targetingSettingSetSchema),\n createOp(\"google.conversionAction.create\", conversionActionCreateSchema),\n updateOp(\"google.conversionAction.update\", conversionActionUpdateSchema),\n createOp(\"google.conversionAction.goal\", conversionGoalSetSchema),\n createOp(\"google.conversion.upload\", conversionUploadSchema),\n createOp(\"google.biddingStrategy.create\", biddingStrategyCreateSchema),\n updateOp(\"google.biddingStrategy.update\", biddingStrategyUpdateSchema),\n createOp(\"google.label.create\", labelCreateSchema),\n createOp(\"google.label.attach\", labelAttachSchema),\n createOp(\"google.campaignCriterion.add\", campaignCriterionAddSchema),\n updateOp(\"google.campaignCriterion.update\", campaignCriterionUpdateSchema),\n targetOp(\"google.campaignCriterion.remove\"),\n]);\nexport type GoogleDraftOpInput = z.infer<typeof googleDraftOpInputSchema>;\n\nexport type GoogleDraftEntity =\n | \"budget\"\n | \"campaign\"\n | \"adGroup\"\n | \"keyword\"\n | \"negativeKeyword\"\n | \"sharedSet\"\n | \"sharedSetMember\"\n | \"campaignSharedSet\"\n | \"ad\"\n | \"asset\"\n | \"assetLink\"\n | \"assetGroup\"\n | \"assetGroupAsset\"\n | \"audience\"\n | \"audienceCriterion\"\n | \"targetingSetting\"\n | \"conversionAction\"\n | \"conversion\"\n | \"biddingStrategy\"\n | \"label\"\n | \"campaignCriterion\";\n\nexport function entityOfKind(kind: GoogleDraftOpKind): GoogleDraftEntity {\n return kind.split(\".\")[1] as GoogleDraftEntity;\n}\n\nexport function verbOfKind(kind: GoogleDraftOpKind): string {\n return kind.split(\".\")[2] ?? \"\";\n}\n\nexport function isCreateKind(kind: GoogleDraftOpKind): boolean {\n const verb = verbOfKind(kind);\n return verb === \"create\" || verb === \"add\" || verb === \"attach\";\n}\n\nexport function isTargetOnlyKind(kind: GoogleDraftOpKind): boolean {\n const verb = verbOfKind(kind);\n return verb === \"pause\" || verb === \"resume\" || verb === \"remove\" || verb === \"detach\";\n}\n\n/**\n * The status a `pause`/`resume` will set, or undefined for every other verb. These kinds\n * carry no payload, so their intent lives only in the kind — both the before/after diff\n * and stage-time no-op detection have to read it from here to know what the op will do.\n */\nexport function impliedStatusOfKind(kind: GoogleDraftOpKind): \"ENABLED\" | \"PAUSED\" | undefined {\n const verb = verbOfKind(kind);\n if (verb === \"pause\") {\n return \"PAUSED\";\n }\n return verb === \"resume\" ? \"ENABLED\" : undefined;\n}\n\n// --- Temp-ref dependency collection ---\n\ntype TempRefDep = { ref: string; entity: GoogleDraftEntity };\n\nfunction isTempRef(value: unknown): value is string {\n return typeof value === \"string\" && TEMP_REF_REGEX.test(value);\n}\n\n/** The image/logo/video asset refs an ad's own content references, keyed by the format. Empty for formats with none. */\nfunction contentAssetRefs(content: AdContent): string[] {\n switch (content.format) {\n case \"responsiveDisplay\":\n return [\n ...(content.marketingImageAssets ?? []),\n ...(content.squareMarketingImageAssets ?? []),\n ...(content.logoImageAssets ?? []),\n ];\n case \"video\":\n return [...content.videoAssets];\n case \"demandGen\":\n return [...(content.imageAssets ?? []), ...(content.squareImageAssets ?? []), ...(content.logoImageAssets ?? [])];\n case \"demandGenVideo\":\n return [\n ...(content.videoAssets ?? []),\n ...(content.logoImageAssets ?? []),\n ...(content.callToActionAssets ?? []),\n ];\n case \"app\":\n return [...(content.images ?? []), ...(content.youtubeVideos ?? [])];\n default:\n return [];\n }\n}\n\n/**\n * The image refs an ad op puts on an App ad's `AppAdInfo.images`, or `[]` for any other op or\n * format. Google validates each one's shape and rejects the WHOLE ad mutate if any is wrong, so\n * the stage-time shape check needs exactly this list — no other format's images are affected.\n */\nexport function appAdImageRefs(op: GoogleDraftOpInput): string[] {\n if (op.kind === \"google.ad.create\") {\n return op.payload.content.format === \"app\" ? [...(op.payload.content.images ?? [])] : [];\n }\n if (op.kind !== \"google.ad.update\" || op.payload.content === undefined) {\n return [];\n }\n const parsed = adContentSchema.safeParse(op.payload.content);\n return parsed.success && parsed.data.format === \"app\" ? [...(parsed.data.images ?? [])] : [];\n}\n\n/**\n * Asset refs inside an ad.update's LOOSE content bag. `adUpdateSchema.content` is a `Record` so a\n * partial patch can merge into a staged op, which means the typed `contentAssetRefs` can't read it —\n * scan its array fields for refs instead. Undercounting here would stage an ad update that consumes\n * a `g_temp_*` asset with an empty `dependsOn`: the reference passes unchecked, discarding the asset\n * create leaves the ad pointing at nothing, and publish order is left to luck.\n */\nfunction looseContentAssetRefs(content: unknown): string[] {\n if (content === null || typeof content !== \"object\" || Array.isArray(content)) {\n return [];\n }\n return Object.values(content as Record<string, unknown>)\n .filter((value): value is unknown[] => Array.isArray(value))\n .flat()\n .filter((value): value is string => typeof value === \"string\");\n}\n\n/** The image/square-image/portrait-image/logo asset refs an asset group's own payload references. */\nfunction assetGroupImageRefs(payload: AssetGroupCreate): string[] {\n return [\n ...(payload.imageAssets ?? []),\n ...(payload.squareImageAssets ?? []),\n ...(payload.portraitImageAssets ?? []),\n ...(payload.logoAssets ?? []),\n ];\n}\n\n/** The entity a `level` names — campaign or ad group — for the ops that hang off either. */\nfunction levelEntity(level: string): GoogleDraftEntity {\n return level === \"adGroup\" ? \"adGroup\" : \"campaign\";\n}\n\n/** Temp refs an op consumes, keyed by the entity kind each ref must resolve to. */\nexport function collectTempRefDeps(op: GoogleDraftOpInput): TempRefDep[] {\n const deps: TempRefDep[] = [];\n const add = (value: unknown, entity: GoogleDraftEntity) => {\n if (isTempRef(value)) {\n deps.push({ ref: value, entity });\n }\n };\n switch (op.kind) {\n case \"google.campaign.create\":\n add(op.payload.budget, \"budget\");\n add(op.payload.biddingStrategy, \"biddingStrategy\");\n break;\n case \"google.campaign.update\":\n add(op.payload.budget, \"budget\");\n break;\n case \"google.adGroup.create\":\n add(op.payload.campaign, \"campaign\");\n break;\n case \"google.keyword.add\":\n add(op.payload.adGroup, \"adGroup\");\n break;\n case \"google.negativeKeyword.add\":\n add(op.payload.parent, levelEntity(op.payload.level));\n break;\n case \"google.sharedSetMember.add\":\n add(op.payload.sharedSet, \"sharedSet\");\n break;\n case \"google.targetingSetting.set\":\n add(op.payload.parent, levelEntity(op.payload.level));\n break;\n case \"google.campaignSharedSet.attach\":\n add(op.payload.campaign, \"campaign\");\n add(op.payload.sharedSet, \"sharedSet\");\n break;\n case \"google.ad.create\":\n add(op.payload.adGroup, \"adGroup\");\n // A responsive display / video / demand gen ad references its assets by ref on its own\n // content — a staged `asset.create` must land before the ad, so its temp refs are real deps.\n for (const ref of contentAssetRefs(op.payload.content)) {\n add(ref, \"asset\");\n }\n break;\n case \"google.ad.update\":\n // A content update replaces the ad's assets too, so the same asset creates are real deps.\n for (const ref of looseContentAssetRefs(op.payload.content)) {\n add(ref, \"asset\");\n }\n break;\n case \"google.assetLink.attach\":\n add(op.payload.parent, op.payload.level === \"adGroup\" ? \"adGroup\" : \"campaign\");\n add(op.payload.asset, \"asset\");\n break;\n case \"google.assetGroup.create\":\n add(op.payload.campaign, \"campaign\");\n for (const ref of assetGroupImageRefs(op.payload)) {\n add(ref, \"asset\");\n }\n break;\n case \"google.assetGroupAsset.attach\":\n add(op.payload.assetGroup, \"assetGroup\");\n add(op.payload.asset, \"asset\");\n break;\n case \"google.audienceCriterion.attach\":\n add(op.payload.parent, op.payload.level === \"adGroup\" ? \"adGroup\" : \"campaign\");\n add(op.payload.userList, \"audience\");\n break;\n case \"google.label.attach\":\n add(op.payload.parent, op.payload.level === \"adGroup\" ? \"adGroup\" : \"campaign\");\n add(op.payload.label, \"label\");\n break;\n case \"google.campaignCriterion.add\":\n add(op.payload.campaign, \"campaign\");\n break;\n default:\n break;\n }\n return deps;\n}\n\n// --- Whole-content replacement gate (blocking) ---\n\n/**\n * Why an `ad.update` content payload can't be persisted as-is, or undefined when it's fine.\n *\n * `adUpdateSchema.content` is a loose bag ON PURPOSE: a partial patch has to be able to merge into a\n * staged create or a staged update. But whatever is finally STORED as a `google.ad.update` is sent to\n * Google as a whole-content replacement, so at that point it must be a complete `AdContent` — the\n * `format` discriminator included. Every persist point runs this, so a half-content update is\n * rejected the moment it's staged instead of surfacing as an unpublishable draft much later.\n */\nexport function incompleteAdContentReason(op: GoogleDraftOpInput): string | undefined {\n if (op.kind !== \"google.ad.update\" || op.payload.content === undefined) {\n return undefined;\n }\n const parsed = adContentSchema.safeParse(op.payload.content);\n if (parsed.success) {\n return undefined;\n }\n const unknownFields = unrecognizedContentKeys(parsed.error.issues);\n if (unknownFields.length > 0) {\n const format = readFormat(op.payload.content);\n const accepted = format ? AD_CONTENT_ASSET_FIELDS[format] : undefined;\n // A format with no creative fields at all (responsiveSearch, call) has an EMPTY list, which is\n // truthy — falling through to the field-naming branch built \"carries its creative on .\" Send\n // those to the schema instead, which is where the answer actually is.\n const where =\n accepted && accepted.length > 0\n ? `a ${format} ad carries its creative on ${accepted.map((f) => `\\`${f}\\``).join(\" / \")}`\n : \"check the format's fields with `baker schema ads.google.ads.update`\";\n return `${unknownFields.map((f) => `\\`${f}\\``).join(\", \")} ${unknownFields.length === 1 ? \"is not a field\" : \"are not fields\"} of this ad's content — ${where}. Unknown fields are dropped, so publishing would have shipped the copy without the assets.`;\n }\n const detail = parsed.error.issues\n .slice(0, 4)\n .map((issue) => (issue.path.length > 0 ? `content.${issue.path.join(\".\")}: ${issue.message}` : issue.message))\n .join(\"; \");\n return `an ad content update replaces the ad's whole content — send every field of the format (starting with \\`format\\`), not only the ones you are changing: ${detail}`;\n}\n\n/** Each content format in the words a user reads — one map, so a card and a summary cannot disagree. */\nexport const AD_FORMAT_LABELS: Readonly<Record<AdFormat, string>> = {\n responsiveSearch: \"Responsive search ad\",\n responsiveDisplay: \"Responsive display ad\",\n call: \"Call ad\",\n app: \"App ad\",\n video: \"Video ad\",\n demandGen: \"Demand Gen ad\",\n demandGenVideo: \"Demand Gen video ad\",\n};\n\n/**\n * Google's live `ad_group_ad.ad.type` → the content format that writes it. An ad's format is chosen\n * by whoever stages the update, and nothing else compares it to the ad on the account: naming the\n * wrong one builds a mutate against a DIFFERENT ad message, which Google refuses at publish, long\n * after the Session moved on. Every writable type is here, so a type that is absent is either one\n * Baker cannot write ({@link UNWRITABLE_AD_TYPES}) or one it has never seen.\n */\nexport const AD_FORMAT_BY_AD_TYPE: Readonly<Record<string, AdFormat>> = {\n RESPONSIVE_SEARCH_AD: \"responsiveSearch\",\n RESPONSIVE_DISPLAY_AD: \"responsiveDisplay\",\n CALL_AD: \"call\",\n APP_AD: \"app\",\n VIDEO_RESPONSIVE_AD: \"video\",\n DEMAND_GEN_MULTI_ASSET_AD: \"demandGen\",\n DEMAND_GEN_VIDEO_RESPONSIVE_AD: \"demandGenVideo\",\n};\n\n/**\n * Live ad types Baker has no content format for, in the words a refusal uses. Named rather than left\n * to fall through, because \"Baker cannot edit this ad\" is an answer the agent can act on — reporting\n * the copy as a finding, or replacing the ad — and a publish failure is not.\n */\nexport const UNWRITABLE_AD_TYPES: Readonly<Record<string, string>> = {\n DEMAND_GEN_CAROUSEL_AD: \"Demand Gen carousel ad\",\n DEMAND_GEN_PRODUCT_AD: \"Demand Gen product ad\",\n EXPANDED_TEXT_AD: \"expanded text ad\",\n IMAGE_AD: \"image ad\",\n VIDEO_AD: \"video ad (the legacy format)\",\n LEGACY_RESPONSIVE_DISPLAY_AD: \"legacy responsive display ad\",\n SHOPPING_PRODUCT_AD: \"Shopping product ad\",\n SMART_CAMPAIGN_AD: \"Smart campaign ad\",\n};\n\n/**\n * Why a staged ad-content format cannot be the content of the ad it targets, or undefined when it\n * can (or when the live type was never read — a missing read is never an accusation).\n */\nexport function adContentFormatRefusal(liveAdType: string | undefined, format: AdFormat): string | undefined {\n if (!liveAdType) {\n return undefined;\n }\n const unwritable = UNWRITABLE_AD_TYPES[liveAdType];\n if (unwritable) {\n return (\n `This ad is a ${unwritable} (${liveAdType}), and Baker has no content format that writes one — ` +\n \"publishing this would be refused by Google. Change this ad in the Google Ads interface, or replace it \" +\n \"with an ad in a format Baker writes, and report the copy as a finding either way.\"\n );\n }\n const expected = AD_FORMAT_BY_AD_TYPE[liveAdType];\n if (!expected || expected === format) {\n return undefined;\n }\n return (\n `This ad is a ${liveAdType}, whose content is \\`format: \"${expected}\"\\` — this update carries ` +\n `\\`format: \"${format}\"\\`, which builds a different ad message and would be refused at publish. ` +\n `Re-stage it with --format ${expected} and that format's own fields (\\`baker schema ads.google.ads.update\\`).`\n );\n}\n\n/** The creative fields each ad format accepts, so an unknown-field error can name the right one. */\nconst AD_CONTENT_ASSET_FIELDS: Record<AdFormat, string[]> = {\n responsiveSearch: [],\n responsiveDisplay: [\"marketingImageAssets\", \"squareMarketingImageAssets\", \"logoImageAssets\"],\n call: [],\n app: [\"images\", \"youtubeVideos\"],\n video: [\"videoAssets\"],\n demandGen: [\"imageAssets\", \"squareImageAssets\", \"logoImageAssets\"],\n demandGenVideo: [\"videoAssets\", \"logoImageAssets\", \"callToActionAssets\"],\n};\n\nfunction readFormat(content: unknown): AdFormat | undefined {\n if (content === null || typeof content !== \"object\") {\n return undefined;\n }\n const format = (content as Record<string, unknown>).format;\n return typeof format === \"string\" && format in AD_CONTENT_ASSET_FIELDS ? (format as AdFormat) : undefined;\n}\n\n/** Field names the strict content schemas rejected, deduped in payload order. */\nfunction unrecognizedContentKeys(issues: readonly z.core.$ZodIssue[]): string[] {\n const keys = new Set<string>();\n for (const issue of issues) {\n if (issue.code === \"unrecognized_keys\") {\n for (const key of issue.keys) {\n keys.add(key);\n }\n }\n }\n return [...keys];\n}\n\n// --- Stage-time warnings (non-blocking) ---\n\n/**\n * `{_source}` in a tracking template resolves from the custom parameters defined on the campaign,\n * ad group or ad. Baker can only see what this op stages, so an undefined tag is a warning, not a\n * rejection — it may legitimately be defined further down. Left unwarned it publishes an empty\n * value into every tracked click.\n */\nfunction urlCustomParameterWarnings(\n template: string | undefined,\n params: ReadonlyArray<{ key: string }> | undefined,\n): string[] {\n if (!template) {\n return [];\n }\n const defined = new Set((params ?? []).map((p) => p.key));\n const referenced = [...template.matchAll(/\\{_([A-Za-z0-9_]+)\\}/g)].map((m) => m[1] ?? \"\");\n const missing = [...new Set(referenced.filter((key) => !defined.has(key)))];\n return missing.length === 0\n ? []\n : [\n `tracking template references {_${missing.join(\"}, {_\")}} but this campaign defines no such custom parameter — define it here (--custom-param ${missing[0]}=…) or make sure the ad group or ad does, or it resolves empty`,\n ];\n}\n\nfunction campaignUpdateWarnings(p: CampaignUpdate): string[] {\n return [\n ...urlCustomParameterWarnings(p.trackingUrlTemplate, p.urlCustomParameters),\n ...biddingTargetWarnings(p.bidding),\n ];\n}\n\nfunction campaignCreateWarnings(p: CampaignCreate): string[] {\n const warnings: string[] = urlCustomParameterWarnings(p.trackingUrlTemplate, p.urlCustomParameters);\n if (p.bidding && (p.bidding.type === \"MAXIMIZE_CONVERSIONS\" || p.bidding.type === \"MAXIMIZE_CONVERSION_VALUE\")) {\n warnings.push(\"automated bidding needs conversion tracking live before it can optimize\");\n }\n if (p.channelType === \"PERFORMANCE_MAX\") {\n warnings.push(\"Performance Max needs an asset group (stage one with `asset-groups create`) before it can serve\");\n }\n warnings.push(...biddingTargetWarnings(p.bidding));\n return warnings;\n}\n\nfunction budgetCreateWarnings(p: BudgetCreate): string[] {\n if (p.amountMicros < PLAYBOOK_DAILY_BUDGET_FLOOR_MICROS) {\n return [`budget ${p.amountMicros / 1_000_000} is very low — campaigns rarely exit learning below ~10/day`];\n }\n return [];\n}\n\n/**\n * Bidding strategies whose delivery is driven by a target the advertiser sets.\n *\n * Since 17 August 2026 a campaign limited by its budget delivers toward that TARGET rather than\n * toward the cost per conversion it has recently been achieving (Google Ads Help 17061251: a $10\n * Target CPA on a campaign running at $5 moves toward $10). A generous target used to be capped in\n * practice by the budget and is not any more.\n *\n * Deliberately excludes MANUAL_CPC, TARGET_IMPRESSION_SHARE, TARGET_CPM and TARGET_SPEND: Google's\n * note scopes the change to target CPA / target ROAS / target CPC, so warning on the others would\n * be noise on a change the release never touched.\n */\nconst TARGET_DRIVEN_BIDDING_TYPES: ReadonlySet<GoogleBiddingStrategyType> = new Set<GoogleBiddingStrategyType>([\n \"TARGET_CPA\",\n \"TARGET_ROAS\",\n \"TARGET_CPC\",\n \"MAXIMIZE_CONVERSIONS\",\n \"MAXIMIZE_CONVERSION_VALUE\",\n]);\n\n/**\n * Exported so the stage layer can drop it when it has the campaign's live target and can say the\n * same thing with both numbers in it — the dashboard renders only the first warning on an op, so\n * two near-identical sentences means the vague one hides the exact one.\n */\nexport const LOOSE_TARGET_WARNING =\n \"a campaign limited by its budget now delivers close to this target instead of to the cost per conversion it has been achieving, so a target set above what this campaign actually does today raises that cost rather than leaving it alone. Set the target from the campaign's own recent performance, and check whether it is limited by budget first: `baker ads google query --preset budget-limited`.\";\n\nfunction biddingTargetWarnings(bidding: BiddingConfig | undefined): string[] {\n if (!bidding || !TARGET_DRIVEN_BIDDING_TYPES.has(bidding.type)) {\n return [];\n }\n if (\n bidding.targetCpaMicros === undefined &&\n bidding.targetRoas === undefined &&\n bidding.targetCpcMicros === undefined\n ) {\n return [];\n }\n return [LOOSE_TARGET_WARNING];\n}\n\n/**\n * A budget update carries no bidding config and no live budget, so the only thing decidable from\n * the payload alone is the same floor `budget.create` warns about. The August 2026 interaction —\n * raising a budget on a campaign whose target sits above its actual performance — needs the live\n * amount to know a raise from a cut, so it lives in `writes/biddingTarget.ts` where the owning\n * campaign's snapshot is already read. Warning here unconditionally would have fired on every\n * decrease too, and called it a raise.\n */\nfunction budgetUpdateWarnings(p: BudgetUpdate): string[] {\n if (p.amountMicros !== undefined && p.amountMicros < PLAYBOOK_DAILY_BUDGET_FLOOR_MICROS) {\n return [`budget ${p.amountMicros / 1_000_000} is very low — campaigns rarely exit learning below ~10/day`];\n }\n return [];\n}\n\nfunction responsiveSearchAdWarnings(content: AdContent): string[] {\n if (content.format !== \"responsiveSearch\") {\n return [];\n }\n const warnings: string[] = [];\n if (content.headlines.length < 8) {\n warnings.push(`only ${content.headlines.length} headlines — Google recommends 8-15 for best Ad Strength`);\n }\n const pins = content.headlines.filter((h) => h.pinnedField).length;\n if (pins > content.headlines.length / 2) {\n warnings.push(\"pinning most headlines limits Google's optimization — pin sparingly\");\n }\n return warnings;\n}\n\n/**\n * The two conversion-action fields Baker fills in that the person approving the change would want a\n * say in. Both fire on the payload being SILENT, never on the value — an agent that chose\n * `ONE_PER_CLICK` on purpose made the decision this warning exists to surface.\n *\n * Only two of the five filled-in fields warn. `type` is plumbing (a website conversion is a website\n * conversion — the other types come with a whole different setup the agent has to ask for anyway),\n * `status` has nothing to decide (an action is created in order to measure), and `primaryForGoal`\n * already says itself on every card: the summary line always ends \"· secondary\" and the card carries\n * an \"Action optimization\" row. Warning on all five would put four notices on every conversion card\n * and teach the reader to skip them.\n */\nfunction conversionActionCreateWarnings(p: ConversionActionCreate): string[] {\n const warnings: string[] = [];\n if (p.category === undefined) {\n warnings.push(\n 'no conversion category was chosen, so this is filed as \"Default\" — the category decides which account-level goal the conversion belongs to, and so whether automated bidding ever optimizes toward it. Set the one that matches what the customer did (purchase, lead, sign-up, phone call, booking…) if \"Default\" is not where it belongs.',\n );\n }\n if (p.countingType === undefined) {\n warnings.push(\n \"nothing said how often this should count, so one conversion is counted per click — right for a lead or a sign-up, wrong for sales, where a customer who buys twice from the same click should count twice. Ask for every conversion to be counted if repeat purchases should each count.\",\n );\n }\n return warnings;\n}\n\nexport function collectOpWarnings(op: GoogleDraftOpInput): string[] {\n switch (op.kind) {\n case \"google.budget.create\":\n return budgetCreateWarnings(op.payload);\n case \"google.budget.update\":\n return budgetUpdateWarnings(op.payload);\n case \"google.campaign.create\":\n return campaignCreateWarnings(op.payload);\n case \"google.campaign.update\":\n return campaignUpdateWarnings(op.payload);\n case \"google.biddingStrategy.create\":\n return biddingTargetWarnings(op.payload.config);\n case \"google.biddingStrategy.update\":\n return biddingTargetWarnings(op.payload.config);\n case \"google.ad.create\":\n return responsiveSearchAdWarnings(op.payload.content);\n case \"google.conversionAction.create\":\n return conversionActionCreateWarnings(op.payload);\n default:\n return [];\n }\n}\n","/**\n * Wire contract for `/api/ads/google/draft*` — staging, listing, and removing\n * draft Google Ads write ops. Ops stage per chat and apply only when the chat\n * publishes as a single atomic `GoogleAdsService.Mutate` batch;\n * `mode: \"simulated\"` means publish completes the full lifecycle without\n * calling Google (feature flag off).\n */\nimport { z } from \"zod\";\nimport { googleDraftOpInputSchema, googleDraftOpKindSchema } from \"./ops\";\n\nexport const googleWriteModeSchema = z.enum([\"live\", \"simulated\"]);\nexport type GoogleWriteMode = z.infer<typeof googleWriteModeSchema>;\n\n/**\n * Read-back check run AFTER the publish finalized: the entity is re-read from\n * the platform and compared against what the op declared. It never contradicts\n * `status` — a change that applied stays applied. `unconfirmed` means Baker\n * could not see the change, which on an eventually consistent platform is not\n * the same as it not having happened.\n */\nexport const publishVerificationSchema = z.object({\n status: z.enum([\"confirmed\", \"unconfirmed\", \"drifted\"]),\n note: z.string().optional(),\n checkedAt: z.number(),\n});\nexport type PublishVerification = z.infer<typeof publishVerificationSchema>;\n\nexport const googleDraftOpResultSchema = z.object({\n status: z.enum([\"applied\", \"simulated\", \"failed\", \"skipped\"]),\n resourceName: z.string().optional(),\n error: z.string().optional(),\n skippedBecause: z.string().optional(),\n executedAt: z.number().optional(),\n verification: publishVerificationSchema.optional(),\n});\nexport type GoogleDraftOpResult = z.infer<typeof googleDraftOpResultSchema>;\n\n// --- POST /api/ads/google/draft/stage ---\n\nexport const googleDraftStageRequestSchema = z.object({\n chatId: z.string(),\n op: googleDraftOpInputSchema,\n});\nexport type GoogleDraftStageRequest = z.infer<typeof googleDraftStageRequestSchema>;\n\n/**\n * `staged: false` is a NO-OP, not a failure: every field the op asks for already\n * holds that value on the live account, so nothing was appended to the draft and\n * publish has nothing to send. `reason` says which state it already had.\n */\nexport const googleDraftStageResponseSchema = z.discriminatedUnion(\"staged\", [\n z.object({\n staged: z.literal(true),\n ref: z.string(),\n kind: googleDraftOpKindSchema,\n mode: googleWriteModeSchema,\n dependsOn: z.array(z.string()),\n summary: z.string(),\n warnings: z.array(z.string()),\n /** True when the op amended an already-staged op in place instead of appending a new one. */\n amended: z.boolean().optional(),\n }),\n z.object({\n staged: z.literal(false),\n noop: z.literal(true),\n kind: googleDraftOpKindSchema,\n mode: googleWriteModeSchema,\n summary: z.string(),\n reason: z.string(),\n }),\n]);\nexport type GoogleDraftStageResponse = z.infer<typeof googleDraftStageResponseSchema>;\n\n// --- POST /api/ads/google/draft/amend ---\n\n/**\n * Generic in-place amend: `patch` RFC-7386-merges into the staged op's payload (plain objects\n * deep-merge, `null` deletes the key, arrays/scalars replace), the merged payload re-validates\n * against the op's own kind, and `dependsOn` recomputes fresh from the merge (a re-parent drops\n * the old parent dep instead of unioning). `ref` matches the staged op's ref or, for staged\n * updates, its target — same lookup `findAmendTarget` uses.\n */\nexport const googleDraftAmendRequestSchema = z.object({\n chatId: z.string(),\n ref: z.string(),\n patch: z.record(z.string(), z.unknown()),\n});\nexport type GoogleDraftAmendRequest = z.infer<typeof googleDraftAmendRequestSchema>;\n\n// --- POST /api/ads/google/draft/show ---\n\nexport const googleDraftShowRequestSchema = z.object({\n chatId: z.string(),\n ref: z.string(),\n});\nexport type GoogleDraftShowRequest = z.infer<typeof googleDraftShowRequestSchema>;\n\n// --- POST /api/ads/google/draft/stage-batch ---\n\n/** Batch ceiling — negative lists routinely carry hundreds of keywords; one request stages them all. */\nexport const GOOGLE_DRAFT_BATCH_MAX = 500;\n\nexport const googleDraftStageBatchRequestSchema = z.object({\n chatId: z.string(),\n ops: z.array(googleDraftOpInputSchema).min(1).max(GOOGLE_DRAFT_BATCH_MAX),\n});\nexport type GoogleDraftStageBatchRequest = z.infer<typeof googleDraftStageBatchRequestSchema>;\n\n/**\n * All-or-nothing on validity: every valid op staged, or the whole batch rejected — no\n * partial drafts to reason about. `skipped` is separate from that contract: those ops\n * were valid but already hold the requested value on the live account, so they were\n * dropped rather than staged. `count` is what actually entered the draft.\n */\nexport const googleDraftStageBatchResponseSchema = z.object({\n staged: z.literal(true),\n mode: googleWriteModeSchema,\n count: z.number(),\n ops: z.array(\n z.object({\n ref: z.string(),\n kind: googleDraftOpKindSchema,\n dependsOn: z.array(z.string()),\n summary: z.string(),\n warnings: z.array(z.string()),\n }),\n ),\n skipped: z.array(z.object({ kind: googleDraftOpKindSchema, summary: z.string(), reason: z.string() })).optional(),\n});\nexport type GoogleDraftStageBatchResponse = z.infer<typeof googleDraftStageBatchResponseSchema>;\n\n// --- POST /api/ads/google/draft (list) ---\n\nexport const googleDraftOpViewSchema = z.object({\n ref: z.string(),\n kind: googleDraftOpKindSchema,\n customerId: z.string(),\n target: z.string().optional(),\n dependsOn: z.array(z.string()),\n summary: z.string(),\n stagedAt: z.number(),\n result: googleDraftOpResultSchema.optional(),\n});\nexport type GoogleDraftOpView = z.infer<typeof googleDraftOpViewSchema>;\n\n// --- POST /api/ads/google/draft/show (response) ---\n\n/** The staged op's full payload as its \"receipt\" — verify a change looks right before publish. */\nexport const googleDraftShowResponseSchema = z.object({\n op: googleDraftOpViewSchema.extend({\n payload: z.unknown().optional(),\n warnings: z.array(z.string()).optional(),\n annotations: z.unknown().optional(),\n }),\n});\nexport type GoogleDraftShowResponse = z.infer<typeof googleDraftShowResponseSchema>;\n\nexport const googleDraftListRequestSchema = z.object({\n chatId: z.string(),\n});\nexport type GoogleDraftListRequest = z.infer<typeof googleDraftListRequestSchema>;\n\n/** A non-blocking completeness nudge for the staged draft (mirrors DraftAdvisory in completeness.ts). */\nexport const googleDraftAdvisorySchema = z.object({\n scope: z.enum([\"campaign\", \"adGroup\"]),\n message: z.string(),\n});\nexport type GoogleDraftAdvisory = z.infer<typeof googleDraftAdvisorySchema>;\n\n/** One member-collection rollup on a status node (e.g. \"Keywords in list\", \"Sitelinks\"). */\nexport const googleDraftStatusCollectionSchema = z.object({\n label: z.string(),\n added: z.number(),\n removed: z.number(),\n /** Members that stay in the set with a changed value — a device's bid adjustment. Optional: a\n * status tree built by an older backend carries no such count. */\n updated: z.number().optional(),\n existing: z.number(),\n});\nexport type GoogleDraftStatusCollection = z.infer<typeof googleDraftStatusCollectionSchema>;\n\n/** A node in the CLI status tree — the same campaign ▸ ad group ▸ ad grouping the dashboard renders. */\nexport interface GoogleDraftStatusNode {\n entity: string;\n name: string;\n /** The ad account this node lives in — one draft may span several. */\n customerId: string;\n operation?: GoogleDraftChangeOperationValue;\n existing: boolean;\n collections: GoogleDraftStatusCollection[];\n children: GoogleDraftStatusNode[];\n /** Non-blocking warnings on this node's heading op (e.g. \"target not found on the account\"). */\n warnings?: string[];\n}\nconst googleDraftChangeOperationSchema = z.enum([\"create\", \"update\", \"pause\", \"resume\", \"remove\", \"upload\"]);\ntype GoogleDraftChangeOperationValue = z.infer<typeof googleDraftChangeOperationSchema>;\nexport const googleDraftStatusNodeSchema: z.ZodType<GoogleDraftStatusNode> = z.lazy(() =>\n z.object({\n entity: z.string(),\n name: z.string(),\n customerId: z.string(),\n operation: googleDraftChangeOperationSchema.optional(),\n existing: z.boolean(),\n collections: z.array(googleDraftStatusCollectionSchema),\n children: z.array(googleDraftStatusNodeSchema),\n warnings: z.array(z.string()).optional(),\n }),\n);\n\nexport const googleDraftListResponseSchema = z.object({\n status: z.enum([\"active\", \"publishing\", \"applied\", \"discarded\", \"none\"]),\n mode: googleWriteModeSchema,\n count: z.number(),\n ops: z.array(googleDraftOpViewSchema),\n /** Grouped campaign ▸ ad group ▸ ad tree for the readable CLI status view. */\n tree: z.array(googleDraftStatusNodeSchema).optional(),\n /** Non-blocking completeness advisories for the whole draft. */\n advisories: z.array(googleDraftAdvisorySchema).optional(),\n});\nexport type GoogleDraftListResponse = z.infer<typeof googleDraftListResponseSchema>;\n\n// --- POST /api/ads/google/draft/remove ---\n\nexport const googleDraftRemoveRequestSchema = z.object({\n chatId: z.string(),\n ref: z.string(),\n});\nexport type GoogleDraftRemoveRequest = z.infer<typeof googleDraftRemoveRequestSchema>;\n\nexport const googleDraftRemoveResponseSchema = z.object({\n /** The requested ref plus any dependents removed by cascade. */\n removed: z.array(z.string()),\n});\nexport type GoogleDraftRemoveResponse = z.infer<typeof googleDraftRemoveResponseSchema>;\n\n// --- POST /api/ads/google/draft/clear ---\n\nexport const googleDraftClearRequestSchema = z.object({\n chatId: z.string(),\n});\nexport type GoogleDraftClearRequest = z.infer<typeof googleDraftClearRequestSchema>;\n\nexport const googleDraftClearResponseSchema = z.object({\n cleared: z.number(),\n});\nexport type GoogleDraftClearResponse = z.infer<typeof googleDraftClearResponseSchema>;\n\n// --- Structured validation errors (400) ---\n\nexport const googleFieldErrorSchema = z.object({\n path: z.string(),\n message: z.string(),\n});\nexport type GoogleFieldError = z.infer<typeof googleFieldErrorSchema>;\n\nexport const googleDraftErrorResponseSchema = z.object({\n code: z.string(),\n error: z.string(),\n fields: z.array(googleFieldErrorSchema).optional(),\n});\nexport type GoogleDraftErrorResponse = z.infer<typeof googleDraftErrorResponseSchema>;\n"],"mappings":"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CA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,uCAA0D;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAYA,IAAM,iBAAiB,oBAAI,IAAoB,CAAC,CAAC,mBAAmB,UAA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","names":["z","z","z","z","z","z","z"]}
|