@koda-sl/baker-cli 0.565.0 → 0.567.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 +4 -3
- package/dist/{account-R3GWLAQD.js → account-UE6DOQXK.js} +5 -5
- package/dist/{account-reads-X35O4MCA.js → account-reads-WPKD2LPB.js} +4 -4
- package/dist/{account-users-AQSRZXEM.js → account-users-USGCCE6I.js} +5 -5
- package/dist/{accounts-HGCR3WFZ.js → accounts-3DS67RX7.js} +4 -4
- package/dist/{accounts-RIYQZZQD.js → accounts-FZCQNX3B.js} +8 -8
- package/dist/{accounts-FS6YGLOR.js → accounts-PVMTLDJU.js} +4 -4
- package/dist/{actions-RUCWCCWN.js → actions-EG23YFYB.js} +18 -18
- package/dist/{activecampaign-HP4WKQOG.js → activecampaign-GPT5R647.js} +4 -4
- package/dist/{add-BBKIUDIO.js → add-IH6GAMK4.js} +3 -3
- package/dist/{add-LYIMFKFR.js → add-UWTWG4VO.js} +4 -4
- package/dist/{ads-MNHPQA4T.js → ads-F3VUMSEV.js} +5 -5
- package/dist/{advertisers-KKZRGHZL.js → advertisers-AJNDC3AX.js} +6 -6
- package/dist/{analytics-MVVSPVAB.js → analytics-PEGA46W5.js} +4 -4
- package/dist/{analytics-WLPHLFT7.js → analytics-XCQ3G5PM.js} +9 -9
- package/dist/{assign-3HOA5LOV.js → assign-2CZ5C43W.js} +4 -4
- package/dist/{audience-size-ZPRWRWTV.js → audience-size-FUHDVYLN.js} +4 -4
- package/dist/{audit-XIEU7MDY.js → audit-DECB5PP5.js} +4 -4
- package/dist/{autocomplete-6FHHTJLF.js → autocomplete-6XSIFXDA.js} +6 -6
- package/dist/{avatars-GZI5KOQN.js → avatars-LTV2TSO2.js} +4 -4
- package/dist/{bid-pricing-Y2DRXIBQ.js → bid-pricing-GC6YU3LW.js} +5 -5
- package/dist/{brand-KC5LQUK6.js → brand-B4QKPCEC.js} +2 -2
- package/dist/{brief-T7YTJI3B.js → brief-RYNGM4GX.js} +13 -13
- package/dist/{campaign-groups-Z3G6REGC.js → campaign-groups-FHV5A3EC.js} +10 -10
- package/dist/{campaign-writes-B4WOMLIE.js → campaign-writes-4B7DCAP2.js} +4 -4
- package/dist/{campaigns-LLJTH6WP.js → campaigns-TL37AY5Y.js} +13 -13
- package/dist/{campaigns-KMHUJNZX.js → campaigns-VNBJV5QD.js} +5 -5
- package/dist/{canvas-Y4QY5XGG.js → canvas-6XSA3VZE.js} +13 -13
- package/dist/{capabilities-GK7SIQF4.js → capabilities-6MOMJZFW.js} +4 -4
- package/dist/{changes-6CL42LG3.js → changes-WWZYTLC6.js} +4 -4
- package/dist/{chats-RGYP5GIA.js → chats-GRS6RCDL.js} +7 -7
- package/dist/{chats-RGYP5GIA.js.map → chats-GRS6RCDL.js.map} +1 -1
- package/dist/{check-3HWKXL4O.js → check-VIRAMFKC.js} +6 -6
- package/dist/{chunk-4S5ZAG4S.js → chunk-22RM3UOO.js} +2 -2
- package/dist/{chunk-6RDVZRK2.js → chunk-2GFJN2TR.js} +3 -3
- package/dist/{chunk-SIQMOZNP.js → chunk-3D5ABNNW.js} +2 -2
- package/dist/{chunk-7DKJF3Y5.js → chunk-3GKAVXR3.js} +2 -2
- package/dist/{chunk-QML3FCJC.js → chunk-5T6DUP7V.js} +2 -2
- package/dist/{chunk-RM6ZIQHH.js → chunk-6IRB3MHG.js} +2 -2
- package/dist/{chunk-I4VURNFW.js → chunk-6MX37ZQZ.js} +2 -2
- package/dist/{chunk-FZJALNM6.js → chunk-7M6GZI5B.js} +2 -2
- package/dist/{chunk-MXGXVYF3.js → chunk-AE5S5B2S.js} +2 -2
- package/dist/{chunk-GFMSRP5Q.js → chunk-ARPT74DG.js} +56 -19
- package/dist/chunk-ARPT74DG.js.map +1 -0
- package/dist/{chunk-ORFYWLJP.js → chunk-B42CHCXX.js} +54 -2
- package/dist/chunk-B42CHCXX.js.map +1 -0
- package/dist/{chunk-TJHEMCST.js → chunk-B47TRSMB.js} +5 -5
- package/dist/{chunk-LVDYB7RO.js → chunk-BHEOF2MF.js} +8 -8
- package/dist/{chunk-Q2JDS6WL.js → chunk-BMMXYR7A.js} +2 -2
- package/dist/{chunk-UIEVJ2HR.js → chunk-BRPSY35A.js} +3 -3
- package/dist/{chunk-N3P5BGPD.js → chunk-CDPM6OE6.js} +2 -2
- package/dist/{chunk-PNA7GXBR.js → chunk-D6YLVDVN.js} +2 -2
- package/dist/{chunk-LWYTFXJG.js → chunk-FHWYQSMY.js} +4 -4
- package/dist/{chunk-D67TRX67.js → chunk-GNTI4KST.js} +2 -2
- package/dist/{chunk-KPXURSDF.js → chunk-GR2BPVLX.js} +3 -3
- package/dist/{chunk-SKW7CDXE.js → chunk-GXAI3EII.js} +3 -3
- package/dist/{chunk-TSFHW2W4.js → chunk-H3PD2KOF.js} +2 -2
- package/dist/{chunk-FVDC6AKZ.js → chunk-IGCS3X4F.js} +2 -2
- package/dist/{chunk-T6RZ7ZOM.js → chunk-IXVVTPG6.js} +3 -3
- package/dist/{chunk-SGEI7HNU.js → chunk-JBABLH5C.js} +5 -5
- package/dist/{chunk-OWEON2S7.js → chunk-JHS5PE5Y.js} +3 -3
- package/dist/{chunk-DJCG3C2K.js → chunk-KICGV4JB.js} +2 -2
- package/dist/{chunk-Y4B7RLIE.js → chunk-LDYI7BIQ.js} +2 -2
- package/dist/{chunk-7BV5QN2P.js → chunk-LXOTNL65.js} +30 -5
- package/dist/chunk-LXOTNL65.js.map +1 -0
- package/dist/{chunk-S456S5VM.js → chunk-M45SOKI5.js} +2 -2
- package/dist/{chunk-RQSZDYEH.js → chunk-ME3K6XIS.js} +2 -2
- package/dist/{chunk-EOMY5SUJ.js → chunk-MKG57P2E.js} +2 -2
- package/dist/{chunk-E5V5HPYO.js → chunk-MU2TTM6Z.js} +2 -2
- package/dist/{chunk-ERQZNOKZ.js → chunk-N2MGR7HT.js} +6 -6
- package/dist/{chunk-TCR6KI6P.js → chunk-N2TXADL7.js} +2 -2
- package/dist/{chunk-ULKMNQ4I.js → chunk-O43QFUOG.js} +3 -3
- package/dist/{chunk-2NWVSWGS.js → chunk-P6KTCPJG.js} +3 -3
- package/dist/{chunk-QDCU26CB.js → chunk-RBB3UUYP.js} +3 -3
- package/dist/{chunk-HDL6MTZG.js → chunk-RJIFEHEG.js} +2 -2
- package/dist/{chunk-J35R2D6B.js → chunk-RYYRGQMM.js} +3 -3
- package/dist/{chunk-KGAYDZM2.js → chunk-S3ZW3KTX.js} +2 -2
- package/dist/{chunk-5W2FXAMY.js → chunk-SZET6NTF.js} +2 -2
- package/dist/{chunk-2YGUNIQJ.js → chunk-T4YD5W33.js} +3 -3
- package/dist/{chunk-DFDV42NY.js → chunk-TPGFX47R.js} +2 -2
- package/dist/{chunk-UHWGXVYT.js → chunk-U5LSGCT3.js} +2 -2
- package/dist/{chunk-5W3PAQTH.js → chunk-URKOGN5B.js} +2 -2
- package/dist/{chunk-YXEUUGUJ.js → chunk-V6TZRCAS.js} +2 -2
- package/dist/{chunk-MSMTG6OC.js → chunk-XHWHBGKX.js} +9 -1
- package/dist/{chunk-MSMTG6OC.js.map → chunk-XHWHBGKX.js.map} +1 -1
- package/dist/{chunk-XOC5F52C.js → chunk-XRR5NN2V.js} +2 -2
- package/dist/{chunk-7JBDVH7L.js → chunk-YXZV6YKH.js} +2 -2
- package/dist/{chunk-RNS5MVHS.js → chunk-ZREKNWIE.js} +2 -2
- package/dist/{claim-23PPIKS4.js → claim-YCK2XQUL.js} +4 -4
- package/dist/cli.js +32 -32
- package/dist/{companies-F5WNG6SA.js → companies-SWGL3MQT.js} +4 -4
- package/dist/{company-LXEKV5YA.js → company-XKEQKWPO.js} +4 -4
- package/dist/{complete-G3GRNRMY.js → complete-CHEZWF5R.js} +4 -4
- package/dist/{connect-NEUYLAWT.js → connect-GWLVOOU7.js} +7 -7
- package/dist/{conversation-CRNAMONB.js → conversation-QD4UJZ7S.js} +4 -4
- package/dist/{conversion-upload-command-WNHVNVMW.js → conversion-upload-command-5OILW65U.js} +4 -4
- package/dist/{conversions-G5ISEE5Z.js → conversions-BECU3XD2.js} +9 -9
- package/dist/{create-P72PSLV7.js → create-4OA5DOSO.js} +4 -4
- package/dist/{create-46WB2E3A.js → create-5QPEESSZ.js} +4 -4
- package/dist/{create-MZHQ422P.js → create-ET3VCGQT.js} +4 -4
- package/dist/{create-63IX52HC.js → create-IJSH2LHP.js} +3 -3
- package/dist/{creatives-OUAFL46L.js → creatives-AIRQ3FGH.js} +10 -10
- package/dist/{creatives-URDL6XUQ.js → creatives-L3XSN34M.js} +12 -12
- package/dist/{credentials-PN4YOTED.js → credentials-Q2FM4DP3.js} +4 -4
- package/dist/{critique-IDUJYXRT.js → critique-A5FVPC5K.js} +4 -4
- package/dist/{critique-6PZWQ6GE.js → critique-RSU7N2NV.js} +9 -9
- package/dist/{crm-UA5QNDY4.js → crm-7GTTSEHH.js} +5 -5
- package/dist/{crm-DC7BXQBS.js → crm-PQREUPOU.js} +6 -6
- package/dist/{currency-VQMZZXSS.js → currency-BZUNQ4XJ.js} +4 -4
- package/dist/{customers-F6FZ4BYS.js → customers-BYNADWKU.js} +6 -6
- package/dist/{delete-ZHGITRWJ.js → delete-2RAKL577.js} +3 -3
- package/dist/{delete-TAGNP5FJ.js → delete-EZ525EJV.js} +4 -4
- package/dist/{delete-PUX6AGGG.js → delete-ZBYPC5AL.js} +4 -4
- package/dist/{demographics-265MC2Y5.js → demographics-5XMZ2TBB.js} +4 -4
- package/dist/{discard-RAYUL25N.js → discard-Q7R5VJ7I.js} +4 -4
- package/dist/{discover-4F4USNHE.js → discover-PDSEJR2P.js} +4 -4
- package/dist/{domain-GSQX4Z2V.js → domain-MS3BKUYW.js} +4 -4
- package/dist/{download-CP3Y2K54.js → download-F56SAC2G.js} +3 -3
- package/dist/{draft-LJJ7K45J.js → draft-4EM4TL25.js} +5 -5
- package/dist/{draft-NNLOJEEV.js → draft-JBLWUO3J.js} +4 -4
- package/dist/{draft-3HRGCNWA.js → draft-L6XXU2I6.js} +4 -4
- package/dist/{draft-VIZTQ6W4.js → draft-XOPS4EZW.js} +16 -4
- package/dist/draft-XOPS4EZW.js.map +1 -0
- package/dist/{experiment-EFLKDQ3C.js → experiment-AZUKJ7ZO.js} +4 -4
- package/dist/{experiments-SSXYFZRC.js → experiments-34NEL75V.js} +5 -5
- package/dist/{extract-JNKU6ANI.js → extract-2PG5JB2C.js} +3 -3
- package/dist/{facets-67DUHP7G.js → facets-5CGKHFDQ.js} +4 -4
- package/dist/{feedback-FGOUIPFM.js → feedback-C7THFXTE.js} +4 -4
- package/dist/{feedback-3W3F3YUN.js → feedback-SWNIEXMA.js} +13 -13
- package/dist/{feedback-record-I3XMUJOX.js → feedback-record-BNDFZRYJ.js} +14 -14
- package/dist/{fetch-I74KDC2I.js → fetch-LMEYFSM5.js} +4 -4
- package/dist/{fit-DEY4SJ3Z.js → fit-DBA7FD3M.js} +6 -6
- package/dist/{flows-3OVUMHEN.js → flows-TQASOYQP.js} +109 -19
- package/dist/flows-TQASOYQP.js.map +1 -0
- package/dist/{fonts-WPI3P562.js → fonts-MPDK2DXR.js} +6 -6
- package/dist/{forecast-E2HJSD6E.js → forecast-3KMAJJWJ.js} +4 -4
- package/dist/{forecast-B4PXDUUF.js → forecast-OP2ECNM2.js} +5 -5
- package/dist/{funnel-QGMJBM23.js → funnel-BLRQAZ65.js} +5 -5
- package/dist/{get-FS5JCUJ6.js → get-DEELBPMG.js} +4 -4
- package/dist/{get-4QQDVHFA.js → get-YATZI6GN.js} +4 -4
- package/dist/{google-ZRZGM2XI.js → google-REFD3W2R.js} +23 -23
- package/dist/{google-UVRF4POY.js → google-ULLPGAXN.js} +3 -3
- package/dist/{google-ads-HLE2JZKC.js → google-ads-IEQJEICD.js} +4 -4
- package/dist/{history-TTTAC775.js → history-2LE4ELLB.js} +4 -4
- package/dist/{history-NULATRWC.js → history-FPXZOUHT.js} +4 -4
- package/dist/{hubspot-J7ZLBL6R.js → hubspot-MNREQEVI.js} +8 -8
- package/dist/{ideas-PDIJ3I2H.js → ideas-4N7WMX3P.js} +5 -5
- package/dist/{images-7WZM4I6K.js → images-KVMFKQX5.js} +7 -7
- package/dist/{ingest-M47H5CT7.js → ingest-GUJNPD6S.js} +4 -4
- package/dist/{ingest-4FLTGD2G.js → ingest-VG4YGXB2.js} +3 -3
- package/dist/{inspect-HDC263MS.js → inspect-VODWKUQY.js} +4 -4
- package/dist/{intent-ZKLT4DAW.js → intent-HXRSLFIO.js} +4 -4
- package/dist/{keyword-gap-QC3ITLNG.js → keyword-gap-WUHMSTNR.js} +4 -4
- package/dist/{keyword-metrics-QZKWO3BX.js → keyword-metrics-LOLNR24U.js} +6 -6
- package/dist/{keywords-for-site-EEIRZ77L.js → keywords-for-site-PLTJBXVN.js} +6 -6
- package/dist/{landing-TTKIW7CQ.js → landing-JMH3WIK2.js} +2 -2
- package/dist/{languages-QMLC4QWZ.js → languages-SVTYYYOC.js} +4 -4
- package/dist/{leads-DGOFIQMH.js → leads-XPIBMZI7.js} +4 -4
- package/dist/{learn-56DN2S6B.js → learn-MOHK6DHI.js} +5 -5
- package/dist/{line-item-writes-BHYFH4AZ.js → line-item-writes-5RVCYHHH.js} +4 -4
- package/dist/{line-items-PUWPYZOV.js → line-items-OESD2IJ6.js} +5 -5
- package/dist/{link-AED2A2ML.js → link-PURCDO7A.js} +4 -4
- package/dist/{linkedin-WB73GQ7E.js → linkedin-YWLXEPLB.js} +31 -31
- package/dist/{linkedin-person-EPSR7OIR.js → linkedin-person-L22XA5LG.js} +4 -4
- package/dist/{list-LLLEF6YM.js → list-KE6PQV2U.js} +3 -3
- package/dist/{list-O5RQLGQO.js → list-L5VZ35AO.js} +4 -4
- package/dist/{list-2YE5JWYG.js → list-T5ZVVC4L.js} +4 -4
- package/dist/{locations-DNRK7DY4.js → locations-7EBZ6KRH.js} +4 -4
- package/dist/{log-FRQ2XD7O.js → log-D3WU36FX.js} +4 -4
- package/dist/{make-ALUBF2U7.js → make-QPE6H3NT.js} +16 -16
- package/dist/{map-6FIEOF2C.js → map-PT7JJYQR.js} +17 -8
- package/dist/map-PT7JJYQR.js.map +1 -0
- package/dist/{mcp-AGZL4CA3.js → mcp-62MSONPH.js} +3 -3
- package/dist/{media-sources-5ECRCDXJ.js → media-sources-DGVR3YPL.js} +2 -2
- package/dist/{members-CH5TDNEZ.js → members-DAHPS3MB.js} +4 -4
- package/dist/{metrics-P4QDFCVB.js → metrics-WRERNMRK.js} +4 -4
- package/dist/{normalize-AEJP2AEI.js → normalize-ZOJ4YROH.js} +4 -4
- package/dist/{options-VENBF5ES.js → options-DTB2NYBL.js} +7 -7
- package/dist/{organization-USVPE43J.js → organization-5JHFNUOD.js} +4 -4
- package/dist/{performance-2V2O5QIB.js → performance-VFDK5PHT.js} +4 -4
- package/dist/{performance-GEALWLJF.js → performance-W6CJEUHR.js} +5 -5
- package/dist/{preview-Q3N6NMQ5.js → preview-PUF62HJU.js} +4 -4
- package/dist/{promoted-tweet-writes-DB6U5OIJ.js → promoted-tweet-writes-FW4BAA5O.js} +4 -4
- package/dist/{promoted-tweets-ATKIVR2F.js → promoted-tweets-LYHKCVNV.js} +3 -3
- package/dist/{publish-R7RFAVGE.js → publish-S2KD5PCN.js} +4 -4
- package/dist/{query-AQ6HNKW7.js → query-3QFT42PG.js} +5 -5
- package/dist/{reddit-2FEGFGU7.js → reddit-AF2PPR3K.js} +5 -5
- package/dist/{refresh-BDEAUQEB.js → refresh-UC7OTPXS.js} +3 -3
- package/dist/{release-CA7H6KLD.js → release-FQOJ2FJ5.js} +4 -4
- package/dist/{relevant-pages-NZKXWMNA.js → relevant-pages-OFKZYWR3.js} +4 -4
- package/dist/{remove-GVLJDVSB.js → remove-H3SU4GJK.js} +3 -3
- package/dist/{reopen-5UVQ5EXY.js → reopen-M2PZEHKF.js} +4 -4
- package/dist/{rerun-4SVR7QGC.js → rerun-M63ZAYAV.js} +15 -15
- package/dist/{research-VPONEQYW.js → research-2N5HAFSB.js} +16 -16
- package/dist/{research-63R4XYM6.js → research-ILZZTO6Q.js} +3 -3
- package/dist/{reset-75QSSW7G.js → reset-JN437DOZ.js} +3 -3
- package/dist/{reset-RKW5GJAX.js → reset-XAKAEDPH.js} +3 -3
- package/dist/{resolve-GZPY2HSF.js → resolve-WVE6D7CP.js} +4 -4
- package/dist/{retry-QXKDF4VY.js → retry-ILL2ZATG.js} +3 -3
- package/dist/{retry-ZZM63KIG.js → retry-PMJ22IN4.js} +3 -3
- package/dist/{revenue-QJIUOCIR.js → revenue-UWU3ACGP.js} +5 -5
- package/dist/{rules-MTOM5TXU.js → rules-BOOFGKJA.js} +6 -6
- package/dist/{rules-add-P7QMIJ47.js → rules-add-7K5ESEZQ.js} +6 -6
- package/dist/{run-5XN3VZTK.js → run-2AIXS3KE.js} +15 -15
- package/dist/{run-UXLXTYI4.js → run-OCCY7JHY.js} +4 -4
- package/dist/{scaffold-ad-WGNIHTWJ.js → scaffold-ad-JQIOCLDU.js} +11 -11
- package/dist/{scaffold-static-ad-5AWGI5QC.js → scaffold-static-ad-BW56MVIV.js} +19 -19
- package/dist/{scaffold-video-UUHRYZFC.js → scaffold-video-OGPMQO5D.js} +10 -10
- package/dist/{schedule-HVLI4YDP.js → schedule-WV6NZ4CK.js} +3 -3
- package/dist/{scheduled-agents-DHKDQSOS.js → scheduled-agents-MZZMHN3T.js} +11 -11
- package/dist/{schema-CCM76NWZ.js → schema-ADRFE3AV.js} +5 -5
- package/dist/{search-563LZ4JQ.js → search-GGWTLVG7.js} +3 -3
- package/dist/{select-EBBZB4I7.js → select-HYZ5JYO7.js} +12 -12
- package/dist/{set-prompt-DIWUIE6L.js → set-prompt-FMJ32YNG.js} +9 -9
- package/dist/{setup-links-BTG7AOMH.js → setup-links-76AJJR5Z.js} +4 -4
- package/dist/{shopify-XOZ6H5WN.js → shopify-Q3XMCPHI.js} +4 -4
- package/dist/{site-BUJSVT4Y.js → site-I4HFMTE5.js} +5 -5
- package/dist/{sources-FZZRJTQV.js → sources-GGLP5NQU.js} +6 -6
- package/dist/{sources-6IU6U3CQ.js → sources-ORL5AEH5.js} +7 -7
- package/dist/{stale-MZCPHFMS.js → stale-GVPIUPBX.js} +11 -11
- package/dist/{status-OHMKGRZ6.js → status-LSHCACMZ.js} +4 -4
- package/dist/{stock-WEY6RYKP.js → stock-RZH4SEGS.js} +3 -3
- package/dist/{sync-EVJR4GY6.js → sync-MK7JTH3U.js} +3 -3
- package/dist/{sync-definition-PESPTSAQ.js → sync-definition-EFAJ744M.js} +10 -10
- package/dist/{tags-OZUQMA2G.js → tags-5HX7TDJN.js} +4 -4
- package/dist/{tags-T4QZEQIR.js → tags-BE6L5NLG.js} +4 -4
- package/dist/{tags-PF4TBBEX.js → tags-EOIC4EQK.js} +4 -4
- package/dist/{tags-HN67SXIG.js → tags-G4HMOLZF.js} +4 -4
- package/dist/{tags-YTZ6ZPQQ.js → tags-PF6UJWCF.js} +3 -3
- package/dist/{targeting-criteria-JTY4OUQV.js → targeting-criteria-DOHSND62.js} +3 -3
- package/dist/{targets-RG3NONXL.js → targets-7AL4HPAW.js} +4 -4
- package/dist/{testimonials-M4GVNUI7.js → testimonials-BNYHKXD2.js} +6 -6
- package/dist/{themes-WMZJWXFT.js → themes-5HKRO5RR.js} +4 -4
- package/dist/{top-companies-VNFPTJBI.js → top-companies-ASSEFHI3.js} +4 -4
- package/dist/{transcript-F5XLS33R.js → transcript-OTAKTTSA.js} +4 -4
- package/dist/{translate-ETC6UFI6.js → translate-ATGQD733.js} +14 -14
- package/dist/{triggers-3GJOP4QN.js → triggers-JQYC4JLT.js} +4 -4
- package/dist/{unlink-636FAP6D.js → unlink-FVHHULLC.js} +4 -4
- package/dist/{unstage-445BCA7J.js → unstage-FIRVPNRC.js} +4 -4
- package/dist/{update-U4UVU7LC.js → update-EO5LVV34.js} +4 -4
- package/dist/{update-V5WN6HAR.js → update-G7RMT4OC.js} +3 -3
- package/dist/{update-64M3KSXE.js → update-OD75FSPH.js} +4 -4
- package/dist/{update-J357GPUA.js → update-RA6TX5NV.js} +4 -4
- package/dist/{upload-PCXMVTGL.js → upload-X33VIDOB.js} +4 -4
- package/dist/{url-options-QLDSJ7QJ.js → url-options-4J3FRXHO.js} +4 -4
- package/dist/{url-params-NEVV6NED.js → url-params-IBE4HUKK.js} +4 -4
- package/dist/{validate-73GLPP7O.js → validate-ZKQN55FV.js} +12 -12
- package/dist/{videos-HBQGC3G6.js → videos-RGCF3EAE.js} +6 -6
- package/dist/{viewer-check-7YL3WXQK.js → viewer-check-AKVX3XFW.js} +7 -7
- package/dist/{web-JUSF75RR.js → web-QVR2EQ7X.js} +4 -4
- package/dist/{winning-ads-RIZANJER.js → winning-ads-3R4RU3FL.js} +3 -3
- package/dist/{write-commands-2TODH3QX.js → write-commands-QQFBJBYD.js} +5 -5
- package/dist/{x-WNZNCXG3.js → x-747NTJKH.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-7BV5QN2P.js.map +0 -1
- package/dist/chunk-GFMSRP5Q.js.map +0 -1
- package/dist/chunk-ORFYWLJP.js.map +0 -1
- package/dist/draft-VIZTQ6W4.js.map +0 -1
- package/dist/flows-3OVUMHEN.js.map +0 -1
- package/dist/map-6FIEOF2C.js.map +0 -1
- /package/dist/{account-R3GWLAQD.js.map → account-UE6DOQXK.js.map} +0 -0
- /package/dist/{account-reads-X35O4MCA.js.map → account-reads-WPKD2LPB.js.map} +0 -0
- /package/dist/{account-users-AQSRZXEM.js.map → account-users-USGCCE6I.js.map} +0 -0
- /package/dist/{accounts-HGCR3WFZ.js.map → accounts-3DS67RX7.js.map} +0 -0
- /package/dist/{accounts-RIYQZZQD.js.map → accounts-FZCQNX3B.js.map} +0 -0
- /package/dist/{accounts-FS6YGLOR.js.map → accounts-PVMTLDJU.js.map} +0 -0
- /package/dist/{actions-RUCWCCWN.js.map → actions-EG23YFYB.js.map} +0 -0
- /package/dist/{activecampaign-HP4WKQOG.js.map → activecampaign-GPT5R647.js.map} +0 -0
- /package/dist/{add-BBKIUDIO.js.map → add-IH6GAMK4.js.map} +0 -0
- /package/dist/{add-LYIMFKFR.js.map → add-UWTWG4VO.js.map} +0 -0
- /package/dist/{ads-MNHPQA4T.js.map → ads-F3VUMSEV.js.map} +0 -0
- /package/dist/{advertisers-KKZRGHZL.js.map → advertisers-AJNDC3AX.js.map} +0 -0
- /package/dist/{analytics-MVVSPVAB.js.map → analytics-PEGA46W5.js.map} +0 -0
- /package/dist/{analytics-WLPHLFT7.js.map → analytics-XCQ3G5PM.js.map} +0 -0
- /package/dist/{assign-3HOA5LOV.js.map → assign-2CZ5C43W.js.map} +0 -0
- /package/dist/{audience-size-ZPRWRWTV.js.map → audience-size-FUHDVYLN.js.map} +0 -0
- /package/dist/{audit-XIEU7MDY.js.map → audit-DECB5PP5.js.map} +0 -0
- /package/dist/{autocomplete-6FHHTJLF.js.map → autocomplete-6XSIFXDA.js.map} +0 -0
- /package/dist/{avatars-GZI5KOQN.js.map → avatars-LTV2TSO2.js.map} +0 -0
- /package/dist/{bid-pricing-Y2DRXIBQ.js.map → bid-pricing-GC6YU3LW.js.map} +0 -0
- /package/dist/{brand-KC5LQUK6.js.map → brand-B4QKPCEC.js.map} +0 -0
- /package/dist/{brief-T7YTJI3B.js.map → brief-RYNGM4GX.js.map} +0 -0
- /package/dist/{campaign-groups-Z3G6REGC.js.map → campaign-groups-FHV5A3EC.js.map} +0 -0
- /package/dist/{campaign-writes-B4WOMLIE.js.map → campaign-writes-4B7DCAP2.js.map} +0 -0
- /package/dist/{campaigns-LLJTH6WP.js.map → campaigns-TL37AY5Y.js.map} +0 -0
- /package/dist/{campaigns-KMHUJNZX.js.map → campaigns-VNBJV5QD.js.map} +0 -0
- /package/dist/{canvas-Y4QY5XGG.js.map → canvas-6XSA3VZE.js.map} +0 -0
- /package/dist/{capabilities-GK7SIQF4.js.map → capabilities-6MOMJZFW.js.map} +0 -0
- /package/dist/{changes-6CL42LG3.js.map → changes-WWZYTLC6.js.map} +0 -0
- /package/dist/{check-3HWKXL4O.js.map → check-VIRAMFKC.js.map} +0 -0
- /package/dist/{chunk-4S5ZAG4S.js.map → chunk-22RM3UOO.js.map} +0 -0
- /package/dist/{chunk-6RDVZRK2.js.map → chunk-2GFJN2TR.js.map} +0 -0
- /package/dist/{chunk-SIQMOZNP.js.map → chunk-3D5ABNNW.js.map} +0 -0
- /package/dist/{chunk-7DKJF3Y5.js.map → chunk-3GKAVXR3.js.map} +0 -0
- /package/dist/{chunk-QML3FCJC.js.map → chunk-5T6DUP7V.js.map} +0 -0
- /package/dist/{chunk-RM6ZIQHH.js.map → chunk-6IRB3MHG.js.map} +0 -0
- /package/dist/{chunk-I4VURNFW.js.map → chunk-6MX37ZQZ.js.map} +0 -0
- /package/dist/{chunk-FZJALNM6.js.map → chunk-7M6GZI5B.js.map} +0 -0
- /package/dist/{chunk-MXGXVYF3.js.map → chunk-AE5S5B2S.js.map} +0 -0
- /package/dist/{chunk-TJHEMCST.js.map → chunk-B47TRSMB.js.map} +0 -0
- /package/dist/{chunk-LVDYB7RO.js.map → chunk-BHEOF2MF.js.map} +0 -0
- /package/dist/{chunk-Q2JDS6WL.js.map → chunk-BMMXYR7A.js.map} +0 -0
- /package/dist/{chunk-UIEVJ2HR.js.map → chunk-BRPSY35A.js.map} +0 -0
- /package/dist/{chunk-N3P5BGPD.js.map → chunk-CDPM6OE6.js.map} +0 -0
- /package/dist/{chunk-PNA7GXBR.js.map → chunk-D6YLVDVN.js.map} +0 -0
- /package/dist/{chunk-LWYTFXJG.js.map → chunk-FHWYQSMY.js.map} +0 -0
- /package/dist/{chunk-D67TRX67.js.map → chunk-GNTI4KST.js.map} +0 -0
- /package/dist/{chunk-KPXURSDF.js.map → chunk-GR2BPVLX.js.map} +0 -0
- /package/dist/{chunk-SKW7CDXE.js.map → chunk-GXAI3EII.js.map} +0 -0
- /package/dist/{chunk-TSFHW2W4.js.map → chunk-H3PD2KOF.js.map} +0 -0
- /package/dist/{chunk-FVDC6AKZ.js.map → chunk-IGCS3X4F.js.map} +0 -0
- /package/dist/{chunk-T6RZ7ZOM.js.map → chunk-IXVVTPG6.js.map} +0 -0
- /package/dist/{chunk-SGEI7HNU.js.map → chunk-JBABLH5C.js.map} +0 -0
- /package/dist/{chunk-OWEON2S7.js.map → chunk-JHS5PE5Y.js.map} +0 -0
- /package/dist/{chunk-DJCG3C2K.js.map → chunk-KICGV4JB.js.map} +0 -0
- /package/dist/{chunk-Y4B7RLIE.js.map → chunk-LDYI7BIQ.js.map} +0 -0
- /package/dist/{chunk-S456S5VM.js.map → chunk-M45SOKI5.js.map} +0 -0
- /package/dist/{chunk-RQSZDYEH.js.map → chunk-ME3K6XIS.js.map} +0 -0
- /package/dist/{chunk-EOMY5SUJ.js.map → chunk-MKG57P2E.js.map} +0 -0
- /package/dist/{chunk-E5V5HPYO.js.map → chunk-MU2TTM6Z.js.map} +0 -0
- /package/dist/{chunk-ERQZNOKZ.js.map → chunk-N2MGR7HT.js.map} +0 -0
- /package/dist/{chunk-TCR6KI6P.js.map → chunk-N2TXADL7.js.map} +0 -0
- /package/dist/{chunk-ULKMNQ4I.js.map → chunk-O43QFUOG.js.map} +0 -0
- /package/dist/{chunk-2NWVSWGS.js.map → chunk-P6KTCPJG.js.map} +0 -0
- /package/dist/{chunk-QDCU26CB.js.map → chunk-RBB3UUYP.js.map} +0 -0
- /package/dist/{chunk-HDL6MTZG.js.map → chunk-RJIFEHEG.js.map} +0 -0
- /package/dist/{chunk-J35R2D6B.js.map → chunk-RYYRGQMM.js.map} +0 -0
- /package/dist/{chunk-KGAYDZM2.js.map → chunk-S3ZW3KTX.js.map} +0 -0
- /package/dist/{chunk-5W2FXAMY.js.map → chunk-SZET6NTF.js.map} +0 -0
- /package/dist/{chunk-2YGUNIQJ.js.map → chunk-T4YD5W33.js.map} +0 -0
- /package/dist/{chunk-DFDV42NY.js.map → chunk-TPGFX47R.js.map} +0 -0
- /package/dist/{chunk-UHWGXVYT.js.map → chunk-U5LSGCT3.js.map} +0 -0
- /package/dist/{chunk-5W3PAQTH.js.map → chunk-URKOGN5B.js.map} +0 -0
- /package/dist/{chunk-YXEUUGUJ.js.map → chunk-V6TZRCAS.js.map} +0 -0
- /package/dist/{chunk-XOC5F52C.js.map → chunk-XRR5NN2V.js.map} +0 -0
- /package/dist/{chunk-7JBDVH7L.js.map → chunk-YXZV6YKH.js.map} +0 -0
- /package/dist/{chunk-RNS5MVHS.js.map → chunk-ZREKNWIE.js.map} +0 -0
- /package/dist/{claim-23PPIKS4.js.map → claim-YCK2XQUL.js.map} +0 -0
- /package/dist/{companies-F5WNG6SA.js.map → companies-SWGL3MQT.js.map} +0 -0
- /package/dist/{company-LXEKV5YA.js.map → company-XKEQKWPO.js.map} +0 -0
- /package/dist/{complete-G3GRNRMY.js.map → complete-CHEZWF5R.js.map} +0 -0
- /package/dist/{connect-NEUYLAWT.js.map → connect-GWLVOOU7.js.map} +0 -0
- /package/dist/{conversation-CRNAMONB.js.map → conversation-QD4UJZ7S.js.map} +0 -0
- /package/dist/{conversion-upload-command-WNHVNVMW.js.map → conversion-upload-command-5OILW65U.js.map} +0 -0
- /package/dist/{conversions-G5ISEE5Z.js.map → conversions-BECU3XD2.js.map} +0 -0
- /package/dist/{create-P72PSLV7.js.map → create-4OA5DOSO.js.map} +0 -0
- /package/dist/{create-46WB2E3A.js.map → create-5QPEESSZ.js.map} +0 -0
- /package/dist/{create-MZHQ422P.js.map → create-ET3VCGQT.js.map} +0 -0
- /package/dist/{create-63IX52HC.js.map → create-IJSH2LHP.js.map} +0 -0
- /package/dist/{creatives-OUAFL46L.js.map → creatives-AIRQ3FGH.js.map} +0 -0
- /package/dist/{creatives-URDL6XUQ.js.map → creatives-L3XSN34M.js.map} +0 -0
- /package/dist/{credentials-PN4YOTED.js.map → credentials-Q2FM4DP3.js.map} +0 -0
- /package/dist/{critique-IDUJYXRT.js.map → critique-A5FVPC5K.js.map} +0 -0
- /package/dist/{critique-6PZWQ6GE.js.map → critique-RSU7N2NV.js.map} +0 -0
- /package/dist/{crm-UA5QNDY4.js.map → crm-7GTTSEHH.js.map} +0 -0
- /package/dist/{crm-DC7BXQBS.js.map → crm-PQREUPOU.js.map} +0 -0
- /package/dist/{currency-VQMZZXSS.js.map → currency-BZUNQ4XJ.js.map} +0 -0
- /package/dist/{customers-F6FZ4BYS.js.map → customers-BYNADWKU.js.map} +0 -0
- /package/dist/{delete-ZHGITRWJ.js.map → delete-2RAKL577.js.map} +0 -0
- /package/dist/{delete-TAGNP5FJ.js.map → delete-EZ525EJV.js.map} +0 -0
- /package/dist/{delete-PUX6AGGG.js.map → delete-ZBYPC5AL.js.map} +0 -0
- /package/dist/{demographics-265MC2Y5.js.map → demographics-5XMZ2TBB.js.map} +0 -0
- /package/dist/{discard-RAYUL25N.js.map → discard-Q7R5VJ7I.js.map} +0 -0
- /package/dist/{discover-4F4USNHE.js.map → discover-PDSEJR2P.js.map} +0 -0
- /package/dist/{domain-GSQX4Z2V.js.map → domain-MS3BKUYW.js.map} +0 -0
- /package/dist/{download-CP3Y2K54.js.map → download-F56SAC2G.js.map} +0 -0
- /package/dist/{draft-LJJ7K45J.js.map → draft-4EM4TL25.js.map} +0 -0
- /package/dist/{draft-NNLOJEEV.js.map → draft-JBLWUO3J.js.map} +0 -0
- /package/dist/{draft-3HRGCNWA.js.map → draft-L6XXU2I6.js.map} +0 -0
- /package/dist/{experiment-EFLKDQ3C.js.map → experiment-AZUKJ7ZO.js.map} +0 -0
- /package/dist/{experiments-SSXYFZRC.js.map → experiments-34NEL75V.js.map} +0 -0
- /package/dist/{extract-JNKU6ANI.js.map → extract-2PG5JB2C.js.map} +0 -0
- /package/dist/{facets-67DUHP7G.js.map → facets-5CGKHFDQ.js.map} +0 -0
- /package/dist/{feedback-FGOUIPFM.js.map → feedback-C7THFXTE.js.map} +0 -0
- /package/dist/{feedback-3W3F3YUN.js.map → feedback-SWNIEXMA.js.map} +0 -0
- /package/dist/{feedback-record-I3XMUJOX.js.map → feedback-record-BNDFZRYJ.js.map} +0 -0
- /package/dist/{fetch-I74KDC2I.js.map → fetch-LMEYFSM5.js.map} +0 -0
- /package/dist/{fit-DEY4SJ3Z.js.map → fit-DBA7FD3M.js.map} +0 -0
- /package/dist/{fonts-WPI3P562.js.map → fonts-MPDK2DXR.js.map} +0 -0
- /package/dist/{forecast-E2HJSD6E.js.map → forecast-3KMAJJWJ.js.map} +0 -0
- /package/dist/{forecast-B4PXDUUF.js.map → forecast-OP2ECNM2.js.map} +0 -0
- /package/dist/{funnel-QGMJBM23.js.map → funnel-BLRQAZ65.js.map} +0 -0
- /package/dist/{get-FS5JCUJ6.js.map → get-DEELBPMG.js.map} +0 -0
- /package/dist/{get-4QQDVHFA.js.map → get-YATZI6GN.js.map} +0 -0
- /package/dist/{google-ZRZGM2XI.js.map → google-REFD3W2R.js.map} +0 -0
- /package/dist/{google-UVRF4POY.js.map → google-ULLPGAXN.js.map} +0 -0
- /package/dist/{google-ads-HLE2JZKC.js.map → google-ads-IEQJEICD.js.map} +0 -0
- /package/dist/{history-TTTAC775.js.map → history-2LE4ELLB.js.map} +0 -0
- /package/dist/{history-NULATRWC.js.map → history-FPXZOUHT.js.map} +0 -0
- /package/dist/{hubspot-J7ZLBL6R.js.map → hubspot-MNREQEVI.js.map} +0 -0
- /package/dist/{ideas-PDIJ3I2H.js.map → ideas-4N7WMX3P.js.map} +0 -0
- /package/dist/{images-7WZM4I6K.js.map → images-KVMFKQX5.js.map} +0 -0
- /package/dist/{ingest-M47H5CT7.js.map → ingest-GUJNPD6S.js.map} +0 -0
- /package/dist/{ingest-4FLTGD2G.js.map → ingest-VG4YGXB2.js.map} +0 -0
- /package/dist/{inspect-HDC263MS.js.map → inspect-VODWKUQY.js.map} +0 -0
- /package/dist/{intent-ZKLT4DAW.js.map → intent-HXRSLFIO.js.map} +0 -0
- /package/dist/{keyword-gap-QC3ITLNG.js.map → keyword-gap-WUHMSTNR.js.map} +0 -0
- /package/dist/{keyword-metrics-QZKWO3BX.js.map → keyword-metrics-LOLNR24U.js.map} +0 -0
- /package/dist/{keywords-for-site-EEIRZ77L.js.map → keywords-for-site-PLTJBXVN.js.map} +0 -0
- /package/dist/{landing-TTKIW7CQ.js.map → landing-JMH3WIK2.js.map} +0 -0
- /package/dist/{languages-QMLC4QWZ.js.map → languages-SVTYYYOC.js.map} +0 -0
- /package/dist/{leads-DGOFIQMH.js.map → leads-XPIBMZI7.js.map} +0 -0
- /package/dist/{learn-56DN2S6B.js.map → learn-MOHK6DHI.js.map} +0 -0
- /package/dist/{line-item-writes-BHYFH4AZ.js.map → line-item-writes-5RVCYHHH.js.map} +0 -0
- /package/dist/{line-items-PUWPYZOV.js.map → line-items-OESD2IJ6.js.map} +0 -0
- /package/dist/{link-AED2A2ML.js.map → link-PURCDO7A.js.map} +0 -0
- /package/dist/{linkedin-WB73GQ7E.js.map → linkedin-YWLXEPLB.js.map} +0 -0
- /package/dist/{linkedin-person-EPSR7OIR.js.map → linkedin-person-L22XA5LG.js.map} +0 -0
- /package/dist/{list-LLLEF6YM.js.map → list-KE6PQV2U.js.map} +0 -0
- /package/dist/{list-O5RQLGQO.js.map → list-L5VZ35AO.js.map} +0 -0
- /package/dist/{list-2YE5JWYG.js.map → list-T5ZVVC4L.js.map} +0 -0
- /package/dist/{locations-DNRK7DY4.js.map → locations-7EBZ6KRH.js.map} +0 -0
- /package/dist/{log-FRQ2XD7O.js.map → log-D3WU36FX.js.map} +0 -0
- /package/dist/{make-ALUBF2U7.js.map → make-QPE6H3NT.js.map} +0 -0
- /package/dist/{mcp-AGZL4CA3.js.map → mcp-62MSONPH.js.map} +0 -0
- /package/dist/{media-sources-5ECRCDXJ.js.map → media-sources-DGVR3YPL.js.map} +0 -0
- /package/dist/{members-CH5TDNEZ.js.map → members-DAHPS3MB.js.map} +0 -0
- /package/dist/{metrics-P4QDFCVB.js.map → metrics-WRERNMRK.js.map} +0 -0
- /package/dist/{normalize-AEJP2AEI.js.map → normalize-ZOJ4YROH.js.map} +0 -0
- /package/dist/{options-VENBF5ES.js.map → options-DTB2NYBL.js.map} +0 -0
- /package/dist/{organization-USVPE43J.js.map → organization-5JHFNUOD.js.map} +0 -0
- /package/dist/{performance-2V2O5QIB.js.map → performance-VFDK5PHT.js.map} +0 -0
- /package/dist/{performance-GEALWLJF.js.map → performance-W6CJEUHR.js.map} +0 -0
- /package/dist/{preview-Q3N6NMQ5.js.map → preview-PUF62HJU.js.map} +0 -0
- /package/dist/{promoted-tweet-writes-DB6U5OIJ.js.map → promoted-tweet-writes-FW4BAA5O.js.map} +0 -0
- /package/dist/{promoted-tweets-ATKIVR2F.js.map → promoted-tweets-LYHKCVNV.js.map} +0 -0
- /package/dist/{publish-R7RFAVGE.js.map → publish-S2KD5PCN.js.map} +0 -0
- /package/dist/{query-AQ6HNKW7.js.map → query-3QFT42PG.js.map} +0 -0
- /package/dist/{reddit-2FEGFGU7.js.map → reddit-AF2PPR3K.js.map} +0 -0
- /package/dist/{refresh-BDEAUQEB.js.map → refresh-UC7OTPXS.js.map} +0 -0
- /package/dist/{release-CA7H6KLD.js.map → release-FQOJ2FJ5.js.map} +0 -0
- /package/dist/{relevant-pages-NZKXWMNA.js.map → relevant-pages-OFKZYWR3.js.map} +0 -0
- /package/dist/{remove-GVLJDVSB.js.map → remove-H3SU4GJK.js.map} +0 -0
- /package/dist/{reopen-5UVQ5EXY.js.map → reopen-M2PZEHKF.js.map} +0 -0
- /package/dist/{rerun-4SVR7QGC.js.map → rerun-M63ZAYAV.js.map} +0 -0
- /package/dist/{research-VPONEQYW.js.map → research-2N5HAFSB.js.map} +0 -0
- /package/dist/{research-63R4XYM6.js.map → research-ILZZTO6Q.js.map} +0 -0
- /package/dist/{reset-75QSSW7G.js.map → reset-JN437DOZ.js.map} +0 -0
- /package/dist/{reset-RKW5GJAX.js.map → reset-XAKAEDPH.js.map} +0 -0
- /package/dist/{resolve-GZPY2HSF.js.map → resolve-WVE6D7CP.js.map} +0 -0
- /package/dist/{retry-QXKDF4VY.js.map → retry-ILL2ZATG.js.map} +0 -0
- /package/dist/{retry-ZZM63KIG.js.map → retry-PMJ22IN4.js.map} +0 -0
- /package/dist/{revenue-QJIUOCIR.js.map → revenue-UWU3ACGP.js.map} +0 -0
- /package/dist/{rules-MTOM5TXU.js.map → rules-BOOFGKJA.js.map} +0 -0
- /package/dist/{rules-add-P7QMIJ47.js.map → rules-add-7K5ESEZQ.js.map} +0 -0
- /package/dist/{run-5XN3VZTK.js.map → run-2AIXS3KE.js.map} +0 -0
- /package/dist/{run-UXLXTYI4.js.map → run-OCCY7JHY.js.map} +0 -0
- /package/dist/{scaffold-ad-WGNIHTWJ.js.map → scaffold-ad-JQIOCLDU.js.map} +0 -0
- /package/dist/{scaffold-static-ad-5AWGI5QC.js.map → scaffold-static-ad-BW56MVIV.js.map} +0 -0
- /package/dist/{scaffold-video-UUHRYZFC.js.map → scaffold-video-OGPMQO5D.js.map} +0 -0
- /package/dist/{schedule-HVLI4YDP.js.map → schedule-WV6NZ4CK.js.map} +0 -0
- /package/dist/{scheduled-agents-DHKDQSOS.js.map → scheduled-agents-MZZMHN3T.js.map} +0 -0
- /package/dist/{schema-CCM76NWZ.js.map → schema-ADRFE3AV.js.map} +0 -0
- /package/dist/{search-563LZ4JQ.js.map → search-GGWTLVG7.js.map} +0 -0
- /package/dist/{select-EBBZB4I7.js.map → select-HYZ5JYO7.js.map} +0 -0
- /package/dist/{set-prompt-DIWUIE6L.js.map → set-prompt-FMJ32YNG.js.map} +0 -0
- /package/dist/{setup-links-BTG7AOMH.js.map → setup-links-76AJJR5Z.js.map} +0 -0
- /package/dist/{shopify-XOZ6H5WN.js.map → shopify-Q3XMCPHI.js.map} +0 -0
- /package/dist/{site-BUJSVT4Y.js.map → site-I4HFMTE5.js.map} +0 -0
- /package/dist/{sources-FZZRJTQV.js.map → sources-GGLP5NQU.js.map} +0 -0
- /package/dist/{sources-6IU6U3CQ.js.map → sources-ORL5AEH5.js.map} +0 -0
- /package/dist/{stale-MZCPHFMS.js.map → stale-GVPIUPBX.js.map} +0 -0
- /package/dist/{status-OHMKGRZ6.js.map → status-LSHCACMZ.js.map} +0 -0
- /package/dist/{stock-WEY6RYKP.js.map → stock-RZH4SEGS.js.map} +0 -0
- /package/dist/{sync-EVJR4GY6.js.map → sync-MK7JTH3U.js.map} +0 -0
- /package/dist/{sync-definition-PESPTSAQ.js.map → sync-definition-EFAJ744M.js.map} +0 -0
- /package/dist/{tags-OZUQMA2G.js.map → tags-5HX7TDJN.js.map} +0 -0
- /package/dist/{tags-T4QZEQIR.js.map → tags-BE6L5NLG.js.map} +0 -0
- /package/dist/{tags-PF4TBBEX.js.map → tags-EOIC4EQK.js.map} +0 -0
- /package/dist/{tags-HN67SXIG.js.map → tags-G4HMOLZF.js.map} +0 -0
- /package/dist/{tags-YTZ6ZPQQ.js.map → tags-PF6UJWCF.js.map} +0 -0
- /package/dist/{targeting-criteria-JTY4OUQV.js.map → targeting-criteria-DOHSND62.js.map} +0 -0
- /package/dist/{targets-RG3NONXL.js.map → targets-7AL4HPAW.js.map} +0 -0
- /package/dist/{testimonials-M4GVNUI7.js.map → testimonials-BNYHKXD2.js.map} +0 -0
- /package/dist/{themes-WMZJWXFT.js.map → themes-5HKRO5RR.js.map} +0 -0
- /package/dist/{top-companies-VNFPTJBI.js.map → top-companies-ASSEFHI3.js.map} +0 -0
- /package/dist/{transcript-F5XLS33R.js.map → transcript-OTAKTTSA.js.map} +0 -0
- /package/dist/{translate-ETC6UFI6.js.map → translate-ATGQD733.js.map} +0 -0
- /package/dist/{triggers-3GJOP4QN.js.map → triggers-JQYC4JLT.js.map} +0 -0
- /package/dist/{unlink-636FAP6D.js.map → unlink-FVHHULLC.js.map} +0 -0
- /package/dist/{unstage-445BCA7J.js.map → unstage-FIRVPNRC.js.map} +0 -0
- /package/dist/{update-U4UVU7LC.js.map → update-EO5LVV34.js.map} +0 -0
- /package/dist/{update-V5WN6HAR.js.map → update-G7RMT4OC.js.map} +0 -0
- /package/dist/{update-64M3KSXE.js.map → update-OD75FSPH.js.map} +0 -0
- /package/dist/{update-J357GPUA.js.map → update-RA6TX5NV.js.map} +0 -0
- /package/dist/{upload-PCXMVTGL.js.map → upload-X33VIDOB.js.map} +0 -0
- /package/dist/{url-options-QLDSJ7QJ.js.map → url-options-4J3FRXHO.js.map} +0 -0
- /package/dist/{url-params-NEVV6NED.js.map → url-params-IBE4HUKK.js.map} +0 -0
- /package/dist/{validate-73GLPP7O.js.map → validate-ZKQN55FV.js.map} +0 -0
- /package/dist/{videos-HBQGC3G6.js.map → videos-RGCF3EAE.js.map} +0 -0
- /package/dist/{viewer-check-7YL3WXQK.js.map → viewer-check-AKVX3XFW.js.map} +0 -0
- /package/dist/{web-JUSF75RR.js.map → web-QVR2EQ7X.js.map} +0 -0
- /package/dist/{winning-ads-RIZANJER.js.map → winning-ads-3R4RU3FL.js.map} +0 -0
- /package/dist/{write-commands-2TODH3QX.js.map → write-commands-QQFBJBYD.js.map} +0 -0
- /package/dist/{x-WNZNCXG3.js.map → x-747NTJKH.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/flows/shared.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n FLOW_ACCOUNT_ONLY_KINDS,\n FLOW_AGENT_DESTINATION_KINDS,\n FLOW_DELIVERY_SIDE_EFFECT_TYPES,\n FLOW_RESOURCE_NODE_TYPES,\n FLOW_SECRET_FIELDS,\n type FlowConfigStatus,\n type FlowSideEffectType,\n type FlowsRevealResponse,\n flowCatalogEntry,\n isFlowOauthSideEffect,\n} from \"@baker/api\";\nimport { apiPost } from \"../../client.ts\";\nimport { writeJson } from \"../../output.ts\";\n\nconst FLOWS_DIR = \"src/lib/flow-engine/flows\";\n\n/** Resolve the flows directory from cwd (walk up a few levels to find the repo root). */\nexport function flowsDir(): string {\n let dir = process.cwd();\n for (let i = 0; i < 6; i++) {\n const candidate = join(dir, FLOWS_DIR);\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = join(dir, \"..\");\n if (parent === dir) {\n break;\n }\n dir = parent;\n }\n return join(process.cwd(), FLOWS_DIR);\n}\n\nexport function failLocal(message: string): never {\n writeJson({ ok: false, error: { code: \"NOT_FOUND\", message } });\n process.exit(1);\n}\n\nexport function listFlowSlugs(): string[] {\n const dir = flowsDir();\n if (!existsSync(dir)) {\n return [];\n }\n return readdirSync(dir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory() && !entry.name.startsWith(\"_\") && entry.name !== \".gitkeep\")\n .map((entry) => entry.name)\n .sort();\n}\n\ntype AnyRecord = Record<string, unknown>;\n\n/** Absolute path to a form's `_data.json` — the one file the agent may edit. */\nexport function flowDataPath(slug: string): string {\n return join(flowsDir(), slug, \"_data.json\");\n}\n\n/**\n * Write a form tree back. Two-space JSON with a trailing newline, matching what\n * the scaffolder and the repo's markdown/JSON formatting already produce — a\n * write in any other shape turns a one-field edit into a whole-file diff.\n */\nexport function writeFlowTree(slug: string, tree: AnyRecord): void {\n writeFileSync(flowDataPath(slug), `${JSON.stringify(tree, null, 2)}\\n`, \"utf-8\");\n}\n\n/**\n * Every node in the tree, depth-first, parents before children.\n *\n * `Array.isArray`, not `?? []`: `_data.json` is hand-authored, so `children`\n * can be an object or a string, and `??` only guards null. These walkers are\n * what `flows show` and the pre-commit `normalize` run over, which are the two\n * things reached for when a form file is already wrong — throwing there would\n * take out the diagnosis along with the form.\n */\nexport function walkNodes(node: AnyRecord, acc: AnyRecord[] = []): AnyRecord[] {\n if (!node || typeof node !== \"object\") return acc;\n acc.push(node);\n if (Array.isArray(node.children)) {\n for (const child of node.children as AnyRecord[]) walkNodes(child, acc);\n }\n return acc;\n}\n\n/**\n * Every side effect in the tree, with the node that owns it.\n *\n * Walked rather than read off the root: side effects hang off whichever node\n * fires them, so a multi-step form keeps them on a child step. Reading\n * `tree.sideEffects` alone reports \"no side effects\" for a form that plainly\n * has one.\n */\nexport function collectSideEffects(tree: AnyRecord): Array<{ node: AnyRecord; sideEffect: AnyRecord }> {\n return walkNodes(tree).flatMap((node) =>\n Array.isArray(node.sideEffects)\n ? (node.sideEffects as AnyRecord[])\n .filter((sideEffect): sideEffect is AnyRecord => Boolean(sideEffect) && typeof sideEffect === \"object\")\n .map((sideEffect) => ({ node, sideEffect }))\n : [],\n );\n}\n\n/** A destination with something sealed in it, as `/api/flows/destinations/reveal` takes it. */\nexport type SealedSideEffect = { sideEffectId: string; type: FlowSideEffectType; encryptedConfig: string };\n\nexport function sealedSideEffects(tree: AnyRecord): SealedSideEffect[] {\n return collectSideEffects(tree).flatMap(({ sideEffect }) => {\n const { id, type, encryptedConfig } = sideEffect;\n const sealed =\n typeof id === \"string\" &&\n typeof type === \"string\" &&\n (FLOW_DELIVERY_SIDE_EFFECT_TYPES as readonly string[]).includes(type) &&\n typeof encryptedConfig === \"string\" &&\n encryptedConfig.length > 0;\n return sealed\n ? [{ sideEffectId: id as string, type: type as FlowSideEffectType, encryptedConfig: encryptedConfig as string }]\n : [];\n });\n}\n\nfunction describeSettings(settings: Record<string, unknown>): string {\n if (typeof settings.email === \"string\") {\n return `to ${settings.email}${typeof settings.subject === \"string\" ? ` · subject \"${settings.subject}\"` : \"\"}`;\n }\n return Object.entries(settings)\n .filter(([, value]) => typeof value === \"string\" || typeof value === \"number\")\n .map(([key, value]) => `${key}: ${String(value)}`)\n .join(\" · \");\n}\n\n/** Each sealed destination's row, saying where it sends — credentials never included (the backend strips them). */\nexport function withSettings(\n rows: FlowConfigStatus[],\n settingsById: Record<string, Record<string, unknown> | null>,\n): FlowConfigStatus[] {\n return rows.map((row) => {\n const settings = row.sideEffectId ? settingsById[row.sideEffectId] : undefined;\n const described = settings ? describeSettings(settings) : \"\";\n return described ? { ...row, status: `${row.status} → ${described}` } : row;\n });\n}\n\n/** Whether this workspace holds a Form by that slug. Never exits. */\nexport function flowExists(slug: string): boolean {\n return existsSync(join(flowsDir(), slug, \"_data.json\"));\n}\n\nexport function readFlowTree(slug: string): AnyRecord {\n const path = join(flowsDir(), slug, \"_data.json\");\n if (!existsSync(path)) {\n failLocal(`No form \"${slug}\". Run \"baker flows list\" to see the forms in this workspace.`);\n }\n try {\n return JSON.parse(readFileSync(path, \"utf-8\")) as AnyRecord;\n } catch (error) {\n failLocal(`Could not read form \"${slug}\": ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\nfunction isConfigured(value: unknown): boolean {\n return typeof value === \"string\" && value.length > 0;\n}\n\ntype NodeMeta = { nodeId: string; nodeName?: string };\n\nfunction nodeMeta(record: AnyRecord): NodeMeta {\n const nodeId = typeof record.id === \"string\" ? record.id : \"\";\n const nodeName = typeof record.name === \"string\" ? record.name : undefined;\n return { nodeId, ...(nodeName ? { nodeName } : {}) };\n}\n\nfunction widgetNodeStatus(record: AnyRecord, meta: NodeMeta): FlowConfigStatus | null {\n const nodeData = record.nodeData as AnyRecord | undefined;\n const nodeType = nodeData?.type;\n if (typeof nodeType !== \"string\" || !(FLOW_RESOURCE_NODE_TYPES as readonly string[]).includes(nodeType)) {\n return null;\n }\n const external = (nodeData?.form as AnyRecord | undefined)?.external;\n const selected = external != null && typeof external === \"object\";\n const name = selected ? (external as AnyRecord).name : undefined;\n return {\n ...meta,\n target: \"node\",\n kind: nodeType,\n status: selected\n ? `${nodeType} — selected${typeof name === \"string\" ? ` \"${name}\"` : \"\"}`\n : `${nodeType} — not selected`,\n needsInput: !selected,\n };\n}\n\n/**\n * Whether this side effect still needs something only the user can give.\n *\n * `false` for a type that has no confidential half at all (a pixel takes a tag\n * ref and nothing else), so a caller can ask the question of any side effect\n * without first checking whether the question applies.\n */\nexport function sideEffectNeedsInput(raw: unknown): boolean {\n const effect = raw as AnyRecord | null;\n const type = effect?.type;\n if (typeof type !== \"string\" || !(FLOW_DELIVERY_SIDE_EFFECT_TYPES as readonly string[]).includes(type)) {\n return false;\n }\n const configured = isConfigured(effect?.encryptedConfig);\n if (!isFlowOauthSideEffect(type as FlowSideEffectType)) return !configured;\n return !isConfigured(effect?.oauthProviderId) || !configured;\n}\n\n/** A pixel has no confidential half; it is listed so a form's tracking is visible before anyone adds to it. */\nfunction trackingStatus(effect: AnyRecord, type: string, meta: NodeMeta): FlowConfigStatus | null {\n if (flowCatalogEntry(\"side-effect\", type)?.owners?.tagIds !== \"tags\") return null;\n const tags = Array.isArray(effect.tagIds) ? effect.tagIds.length : 0;\n const event = typeof effect.eventName === \"string\" ? ` \"${effect.eventName}\"` : \"\";\n return {\n ...meta,\n target: \"sideEffect\",\n ...(typeof effect.id === \"string\" ? { sideEffectId: effect.id } : {}),\n kind: type,\n status: `${type}${event} — ${tags > 0 ? `[${tags} tag${tags === 1 ? \"\" : \"s\"}]` : \"[no tag]\"}`,\n needsInput: false,\n };\n}\n\nfunction sideEffectStatus(raw: unknown, meta: NodeMeta): FlowConfigStatus | null {\n const effect = raw as AnyRecord | null;\n const type = effect?.type;\n if (typeof type !== \"string\") return null;\n if (!(FLOW_DELIVERY_SIDE_EFFECT_TYPES as readonly string[]).includes(type)) {\n return effect ? trackingStatus(effect, type, meta) : null;\n }\n const configured = isConfigured(effect?.encryptedConfig);\n const oauth = isFlowOauthSideEffect(type as FlowSideEffectType);\n const connected = isConfigured(effect?.oauthProviderId);\n const needs = FLOW_SECRET_FIELDS[type as FlowSideEffectType];\n const status = oauth\n ? `${type} — connection ${connected ? \"[connected]\" : \"[needs connection]\"}, config ${configured ? \"[set]\" : \"[missing]\"}`\n : configured\n ? `${type} — [configured]`\n : `${type} — [missing]${needs.length > 0 ? ` (needs: ${needs.join(\", \")})` : \"\"}`;\n return {\n ...meta,\n target: \"sideEffect\",\n ...(typeof effect?.id === \"string\" ? { sideEffectId: effect.id } : {}),\n kind: type,\n status,\n needsInput: sideEffectNeedsInput(effect),\n };\n}\n\n/**\n * The exact call that fills a still-unconfigured item — `baker flows connect`\n * for anything the agent can wire itself, `request_flow_input` for the rest\n * and as the fallback.\n *\n * Emitted as a ready-to-issue call rather than a reminder that one exists. The\n * argument set is not guessable — it needs the node id, and for a side effect\n * the side-effect id too — so a hint that only named the tool would still cost\n * the agent a `flows show --full` to assemble.\n */\nexport function requestFlowInputCall(slug: string, status: FlowConfigStatus): string {\n const args =\n status.target === \"node\"\n ? `{ target: \"node\", flowSlug: \"${slug}\", nodeId: \"${status.nodeId}\", nodeType: \"${status.kind}\" }`\n : `{ target: \"sideEffect\", flowSlug: \"${slug}\", nodeId: \"${status.nodeId}\", sideEffectId: \"${status.sideEffectId}\", sideEffectType: \"${status.kind}\" }`;\n const card = `request_flow_input with ${args}`;\n const target = status.target === \"node\" ? `--node ${status.nodeId}` : `--side-effect ${status.sideEffectId}`;\n const fallback = \"only if nothing is connected or several could be meant\";\n // Nothing in an email is confidential: you state it, and the user is never handed a card for it.\n if (status.kind === \"email\") {\n return `baker flows connect ${slug} ${target} --email \"<who receives each lead, comma-separated>\" --subject \"<New lead — the Form's name>\"`;\n }\n if (status.kind === \"httpWebhook\") {\n return `baker flows connect ${slug} ${target} --url <https address> — only a webhook that needs a token or password goes to the user: ${card}`;\n }\n if (status.kind === \"hubspotForm\") {\n return `baker flows connect ${slug} ${target} --hubspot-form <formId from baker hubspot forms list> — ${fallback}: ${card}`;\n }\n if (status.kind === \"hubspot\" || status.kind === \"hubspotMeeting\") {\n const list = status.kind === \"hubspot\" ? \"forms view <id>\" : \"meetings view <slug>\";\n return `write \\`baker hubspot ${list} --as-node\\` into the step's form.external — ${fallback}: ${card}`;\n }\n if ((FLOW_ACCOUNT_ONLY_KINDS as readonly string[]).includes(status.kind)) {\n return `baker flows connect ${slug} ${target} — ${fallback}: ${card}`;\n }\n if ((FLOW_AGENT_DESTINATION_KINDS as readonly string[]).includes(status.kind)) {\n const sheet = status.kind === \"googleSpreadsheet\" ? ' (or --new-sheet \"<title>\" --columns \"…\")' : \"\";\n return `baker flows connect ${slug} ${target} --resource <id from baker flows options ${status.kind}>${sheet} — ${fallback}: ${card}`;\n }\n return card;\n}\n\n/**\n * Walk a local flow tree collecting the configuration status of every\n * confidential field — WITHOUT decrypting anything. A present `encryptedConfig`\n * string / `oauthProviderId` / `form.external` object means \"configured\"; null /\n * absent means the agent still needs to run `request_flow_input` for it.\n */\nexport function collectConfigStatus(node: unknown, acc: FlowConfigStatus[]): void {\n if (!node || typeof node !== \"object\") {\n return;\n }\n const record = node as AnyRecord;\n const meta = nodeMeta(record);\n\n const widget = widgetNodeStatus(record, meta);\n if (widget) {\n acc.push(widget);\n }\n if (Array.isArray(record.sideEffects)) {\n for (const raw of record.sideEffects) {\n const status = sideEffectStatus(raw, meta);\n if (status) {\n acc.push(status);\n }\n }\n }\n if (Array.isArray(record.children)) {\n for (const child of record.children) {\n collectConfigStatus(child, acc);\n }\n }\n}\n\n/** Replace opaque ciphertext with a status marker so `--full` stays readable and never leaks noise. */\nexport function redactTree(node: unknown): unknown {\n if (Array.isArray(node)) {\n return node.map(redactTree);\n }\n if (!node || typeof node !== \"object\") {\n return node;\n }\n const out: AnyRecord = {};\n for (const [key, value] of Object.entries(node as AnyRecord)) {\n if (key === \"encryptedConfig\") {\n out[key] = isConfigured(value) ? \"[configured]\" : value;\n } else {\n out[key] = redactTree(value);\n }\n }\n return out;\n}\n\n/**\n * The constant a step's name becomes in the generated `_query.ts`.\n *\n * Byte-for-byte the scaffold's own `toScreamingSnake`\n * (`__tooling__/checks/base/flow-typed/flow-typed.mjs`), which is the only implementation\n * that decides anything: the watcher writes `export const <key> = \"<node id>\";`\n * for every step and throws `Duplicate flow node name` when two steps produce\n * the same one. `flows-step-name-key.test.ts` pins the two together.\n *\n * It is copied rather than imported because the CLI ships as a binary into a\n * Session Runtime and the scaffold ships as files — there is no module boundary\n * they share. The copy that was here before was NOT this rule: it uppercased and\n * squashed every non-alphanumeric run, which agrees on `Contact Info` and\n * disagrees on `contactInfo` (`CONTACTINFO` here, `CONTACT_INFO` there). So\n * `add-node` waved through a name that collided in the generator, the watcher\n * then threw, and `_query.ts` stopped regenerating for the whole form.\n */\nexport function stepNameKey(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, \"$1_$2\")\n .replace(/[-\\s]+/g, \"_\")\n .toUpperCase();\n}\n\n/**\n * Whether that constant is one TypeScript will accept.\n *\n * `flow-typed.mjs` interpolates the key straight into `export const <key> = …`\n * without checking, so a step called \"1. Your details\" or \"Thanks!\" writes a\n * `_query.ts` that is a syntax error, and the whole workspace stops building —\n * a failure whose message names the generated file rather than the step that\n * caused it. `add-node` is where a name is minted, so it is where this is worth\n * catching.\n *\n * The real identifier grammar, not `[A-Z0-9_]`: this product is Spanish-first\n * and `INFORMACIÓN_DE_CONTACTO` is both a legal identifier and an ordinary step\n * name. Rejecting it would be the check being wrong, not the name.\n */\nexport function isUsableStepNameKey(key: string): boolean {\n return /^[\\p{ID_Start}$_][\\p{ID_Continue}$]*$/u.test(key);\n}\n\n/**\n * What each sealed destination holds, minus credentials — so \"add Fran to the\n * leads email\" starts from who gets it today instead of a card for the user.\n * A destination Baker would not open for this company (sealed for another,\n * or saved before destinations recorded whose they are) maps to null; the whole call failing\n * returns null. `flows show` leaves those rows as they were, and `connect`\n * refuses to overwrite what it cannot see.\n */\nexport async function readSettings(\n tree: Record<string, unknown>,\n): Promise<Record<string, Record<string, unknown> | null> | null> {\n const sealed = sealedSideEffects(tree);\n if (sealed.length === 0) return {};\n try {\n const { data } = await apiPost<FlowsRevealResponse>(\"/api/flows/destinations/reveal\", {\n items: sealed.map(({ type, encryptedConfig }) => ({ type, encryptedConfig })),\n });\n return Object.fromEntries(sealed.map((item, index) => [item.sideEffectId, data.items[index] ?? null]));\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY,aAAa,cAAc,qBAAqB;AACrE,SAAS,YAAY;AAgBrB,IAAM,YAAY;AAGX,SAAS,WAAmB;AACjC,MAAI,MAAM,QAAQ,IAAI;AACtB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,YAAY,KAAK,KAAK,SAAS;AACrC,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO;AAAA,IACT;AACA,UAAM,SAAS,KAAK,KAAK,IAAI;AAC7B,QAAI,WAAW,KAAK;AAClB;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACA,SAAO,KAAK,QAAQ,IAAI,GAAG,SAAS;AACtC;AAEO,SAAS,UAAU,SAAwB;AAChD,YAAU,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,aAAa,QAAQ,EAAE,CAAC;AAC9D,UAAQ,KAAK,CAAC;AAChB;AAEO,SAAS,gBAA0B;AACxC,QAAM,MAAM,SAAS;AACrB,MAAI,CAAC,WAAW,GAAG,GAAG;AACpB,WAAO,CAAC;AAAA,EACV;AACA,SAAO,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,EAC5C,OAAO,CAAC,UAAU,MAAM,YAAY,KAAK,CAAC,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,SAAS,UAAU,EACjG,IAAI,CAAC,UAAU,MAAM,IAAI,EACzB,KAAK;AACV;AAKO,SAAS,aAAa,MAAsB;AACjD,SAAO,KAAK,SAAS,GAAG,MAAM,YAAY;AAC5C;AAOO,SAAS,cAAc,MAAc,MAAuB;AACjE,gBAAc,aAAa,IAAI,GAAG,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,GAAM,OAAO;AACjF;AAWO,SAAS,UAAU,MAAiB,MAAmB,CAAC,GAAgB;AAC7E,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,MAAI,KAAK,IAAI;AACb,MAAI,MAAM,QAAQ,KAAK,QAAQ,GAAG;AAChC,eAAW,SAAS,KAAK,SAAyB,WAAU,OAAO,GAAG;AAAA,EACxE;AACA,SAAO;AACT;AAUO,SAAS,mBAAmB,MAAoE;AACrG,SAAO,UAAU,IAAI,EAAE;AAAA,IAAQ,CAAC,SAC9B,MAAM,QAAQ,KAAK,WAAW,IACzB,KAAK,YACH,OAAO,CAAC,eAAwC,QAAQ,UAAU,KAAK,OAAO,eAAe,QAAQ,EACrG,IAAI,CAAC,gBAAgB,EAAE,MAAM,WAAW,EAAE,IAC7C,CAAC;AAAA,EACP;AACF;AAKO,SAAS,kBAAkB,MAAqC;AACrE,SAAO,mBAAmB,IAAI,EAAE,QAAQ,CAAC,EAAE,WAAW,MAAM;AAC1D,UAAM,EAAE,IAAI,MAAM,gBAAgB,IAAI;AACtC,UAAM,SACJ,OAAO,OAAO,YACd,OAAO,SAAS,YACf,gCAAsD,SAAS,IAAI,KACpE,OAAO,oBAAoB,YAC3B,gBAAgB,SAAS;AAC3B,WAAO,SACH,CAAC,EAAE,cAAc,IAAc,MAAkC,gBAA2C,CAAC,IAC7G,CAAC;AAAA,EACP,CAAC;AACH;AAEA,SAAS,iBAAiB,UAA2C;AACnE,MAAI,OAAO,SAAS,UAAU,UAAU;AACtC,WAAO,MAAM,SAAS,KAAK,GAAG,OAAO,SAAS,YAAY,WAAW,kBAAe,SAAS,OAAO,MAAM,EAAE;AAAA,EAC9G;AACA,SAAO,OAAO,QAAQ,QAAQ,EAC3B,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,OAAO,UAAU,YAAY,OAAO,UAAU,QAAQ,EAC5E,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,KAAK,OAAO,KAAK,CAAC,EAAE,EAChD,KAAK,QAAK;AACf;AAGO,SAAS,aACd,MACA,cACoB;AACpB,SAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,UAAM,WAAW,IAAI,eAAe,aAAa,IAAI,YAAY,IAAI;AACrE,UAAM,YAAY,WAAW,iBAAiB,QAAQ,IAAI;AAC1D,WAAO,YAAY,EAAE,GAAG,KAAK,QAAQ,GAAG,IAAI,MAAM,WAAM,SAAS,GAAG,IAAI;AAAA,EAC1E,CAAC;AACH;AAGO,SAAS,WAAW,MAAuB;AAChD,SAAO,WAAW,KAAK,SAAS,GAAG,MAAM,YAAY,CAAC;AACxD;AAEO,SAAS,aAAa,MAAyB;AACpD,QAAM,OAAO,KAAK,SAAS,GAAG,MAAM,YAAY;AAChD,MAAI,CAAC,WAAW,IAAI,GAAG;AACrB,cAAU,YAAY,IAAI,+DAA+D;AAAA,EAC3F;AACA,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,MAAM,OAAO,CAAC;AAAA,EAC/C,SAAS,OAAO;AACd,cAAU,wBAAwB,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,EACtG;AACF;AAEA,SAAS,aAAa,OAAyB;AAC7C,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS;AACrD;AAIA,SAAS,SAAS,QAA6B;AAC7C,QAAM,SAAS,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK;AAC3D,QAAM,WAAW,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AACjE,SAAO,EAAE,QAAQ,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC,EAAG;AACrD;AAEA,SAAS,iBAAiB,QAAmB,MAAyC;AACpF,QAAM,WAAW,OAAO;AACxB,QAAM,WAAW,UAAU;AAC3B,MAAI,OAAO,aAAa,YAAY,CAAE,yBAA+C,SAAS,QAAQ,GAAG;AACvG,WAAO;AAAA,EACT;AACA,QAAM,WAAY,UAAU,MAAgC;AAC5D,QAAM,WAAW,YAAY,QAAQ,OAAO,aAAa;AACzD,QAAM,OAAO,WAAY,SAAuB,OAAO;AACvD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ,WACJ,GAAG,QAAQ,mBAAc,OAAO,SAAS,WAAW,KAAK,IAAI,MAAM,EAAE,KACrE,GAAG,QAAQ;AAAA,IACf,YAAY,CAAC;AAAA,EACf;AACF;AASO,SAAS,qBAAqB,KAAuB;AAC1D,QAAM,SAAS;AACf,QAAM,OAAO,QAAQ;AACrB,MAAI,OAAO,SAAS,YAAY,CAAE,gCAAsD,SAAS,IAAI,GAAG;AACtG,WAAO;AAAA,EACT;AACA,QAAM,aAAa,aAAa,QAAQ,eAAe;AACvD,MAAI,CAAC,sBAAsB,IAA0B,EAAG,QAAO,CAAC;AAChE,SAAO,CAAC,aAAa,QAAQ,eAAe,KAAK,CAAC;AACpD;AAGA,SAAS,eAAe,QAAmB,MAAc,MAAyC;AAChG,MAAI,iBAAiB,eAAe,IAAI,GAAG,QAAQ,WAAW,OAAQ,QAAO;AAC7E,QAAM,OAAO,MAAM,QAAQ,OAAO,MAAM,IAAI,OAAO,OAAO,SAAS;AACnE,QAAM,QAAQ,OAAO,OAAO,cAAc,WAAW,KAAK,OAAO,SAAS,MAAM;AAChF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,GAAI,OAAO,OAAO,OAAO,WAAW,EAAE,cAAc,OAAO,GAAG,IAAI,CAAC;AAAA,IACnE,MAAM;AAAA,IACN,QAAQ,GAAG,IAAI,GAAG,KAAK,WAAM,OAAO,IAAI,IAAI,IAAI,OAAO,SAAS,IAAI,KAAK,GAAG,MAAM,UAAU;AAAA,IAC5F,YAAY;AAAA,EACd;AACF;AAEA,SAAS,iBAAiB,KAAc,MAAyC;AAC/E,QAAM,SAAS;AACf,QAAM,OAAO,QAAQ;AACrB,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,MAAI,CAAE,gCAAsD,SAAS,IAAI,GAAG;AAC1E,WAAO,SAAS,eAAe,QAAQ,MAAM,IAAI,IAAI;AAAA,EACvD;AACA,QAAM,aAAa,aAAa,QAAQ,eAAe;AACvD,QAAM,QAAQ,sBAAsB,IAA0B;AAC9D,QAAM,YAAY,aAAa,QAAQ,eAAe;AACtD,QAAM,QAAQ,mBAAmB,IAA0B;AAC3D,QAAM,SAAS,QACX,GAAG,IAAI,sBAAiB,YAAY,gBAAgB,oBAAoB,YAAY,aAAa,UAAU,WAAW,KACtH,aACE,GAAG,IAAI,yBACP,GAAG,IAAI,oBAAe,MAAM,SAAS,IAAI,YAAY,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE;AACnF,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ;AAAA,IACR,GAAI,OAAO,QAAQ,OAAO,WAAW,EAAE,cAAc,OAAO,GAAG,IAAI,CAAC;AAAA,IACpE,MAAM;AAAA,IACN;AAAA,IACA,YAAY,qBAAqB,MAAM;AAAA,EACzC;AACF;AAYO,SAAS,qBAAqB,MAAc,QAAkC;AACnF,QAAM,OACJ,OAAO,WAAW,SACd,gCAAgC,IAAI,eAAe,OAAO,MAAM,iBAAiB,OAAO,IAAI,QAC5F,sCAAsC,IAAI,eAAe,OAAO,MAAM,qBAAqB,OAAO,YAAY,uBAAuB,OAAO,IAAI;AACtJ,QAAM,OAAO,2BAA2B,IAAI;AAC5C,QAAM,SAAS,OAAO,WAAW,SAAS,UAAU,OAAO,MAAM,KAAK,iBAAiB,OAAO,YAAY;AAC1G,QAAM,WAAW;AAEjB,MAAI,OAAO,SAAS,SAAS;AAC3B,WAAO,uBAAuB,IAAI,IAAI,MAAM;AAAA,EAC9C;AACA,MAAI,OAAO,SAAS,eAAe;AACjC,WAAO,uBAAuB,IAAI,IAAI,MAAM,iGAA4F,IAAI;AAAA,EAC9I;AACA,MAAI,OAAO,SAAS,eAAe;AACjC,WAAO,uBAAuB,IAAI,IAAI,MAAM,iEAA4D,QAAQ,KAAK,IAAI;AAAA,EAC3H;AACA,MAAI,OAAO,SAAS,aAAa,OAAO,SAAS,kBAAkB;AACjE,UAAM,OAAO,OAAO,SAAS,YAAY,oBAAoB;AAC7D,WAAO,yBAAyB,IAAI,qDAAgD,QAAQ,KAAK,IAAI;AAAA,EACvG;AACA,MAAK,wBAA8C,SAAS,OAAO,IAAI,GAAG;AACxE,WAAO,uBAAuB,IAAI,IAAI,MAAM,WAAM,QAAQ,KAAK,IAAI;AAAA,EACrE;AACA,MAAK,6BAAmD,SAAS,OAAO,IAAI,GAAG;AAC7E,UAAM,QAAQ,OAAO,SAAS,sBAAsB,mDAA8C;AAClG,WAAO,uBAAuB,IAAI,IAAI,MAAM,4CAA4C,OAAO,IAAI,IAAI,KAAK,WAAM,QAAQ,KAAK,IAAI;AAAA,EACrI;AACA,SAAO;AACT;AAQO,SAAS,oBAAoB,MAAe,KAA+B;AAChF,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC;AAAA,EACF;AACA,QAAM,SAAS;AACf,QAAM,OAAO,SAAS,MAAM;AAE5B,QAAM,SAAS,iBAAiB,QAAQ,IAAI;AAC5C,MAAI,QAAQ;AACV,QAAI,KAAK,MAAM;AAAA,EACjB;AACA,MAAI,MAAM,QAAQ,OAAO,WAAW,GAAG;AACrC,eAAW,OAAO,OAAO,aAAa;AACpC,YAAM,SAAS,iBAAiB,KAAK,IAAI;AACzC,UAAI,QAAQ;AACV,YAAI,KAAK,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,QAAQ,OAAO,QAAQ,GAAG;AAClC,eAAW,SAAS,OAAO,UAAU;AACnC,0BAAoB,OAAO,GAAG;AAAA,IAChC;AAAA,EACF;AACF;AAGO,SAAS,WAAW,MAAwB;AACjD,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,IAAI,UAAU;AAAA,EAC5B;AACA,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AACA,QAAM,MAAiB,CAAC;AACxB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAiB,GAAG;AAC5D,QAAI,QAAQ,mBAAmB;AAC7B,UAAI,GAAG,IAAI,aAAa,KAAK,IAAI,iBAAiB;AAAA,IACpD,OAAO;AACL,UAAI,GAAG,IAAI,WAAW,KAAK;AAAA,IAC7B;AAAA,EACF;AACA,SAAO;AACT;AAmBO,SAAS,YAAY,MAAsB;AAChD,SAAO,KACJ,QAAQ,mBAAmB,OAAO,EAClC,QAAQ,WAAW,GAAG,EACtB,YAAY;AACjB;AAgBO,SAAS,oBAAoB,KAAsB;AACxD,SAAO,2CAA2C,KAAK,GAAG;AAC5D;AAUA,eAAsB,aACpB,MACgE;AAChE,QAAM,SAAS,kBAAkB,IAAI;AACrC,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AACjC,MAAI;AACF,UAAM,EAAE,KAAK,IAAI,MAAM,QAA6B,kCAAkC;AAAA,MACpF,OAAO,OAAO,IAAI,CAAC,EAAE,MAAM,gBAAgB,OAAO,EAAE,MAAM,gBAAgB,EAAE;AAAA,IAC9E,CAAC;AACD,WAAO,OAAO,YAAY,OAAO,IAAI,CAAC,MAAM,UAAU,CAAC,KAAK,cAAc,KAAK,MAAM,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,EACvG,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../api/src/activecampaign.ts","../src/commands/flows/value-expression.ts","../src/commands/flows/mapping.ts"],"sourcesContent":["/**\n * ActiveCampaign as a Form destination: the contract the CLI, the dashboard and\n * the backend share.\n *\n * A Form's `activeCampaignContact` side effect maps answers onto these kinds of\n * destination field, each stored as one `fieldMapping` entry:\n *\n * standard a field every contact has (`email`, `firstName`, `lastName`, `phone`)\n * custom one of the account's own custom contact fields, addressed by its id —\n * or by its personalization tag (`UTM_SOURCE`), resolved to the id at\n * delivery, so a field that is only staged so far can already be mapped\n * tags the one entry whose value is a comma-separated list of tag names\n * lists comma-separated list ids or names the contact is subscribed to\n * automations comma-separated automation ids or names the contact is enrolled in\n * deal a deal tied to the contact (`title`, `value`, `pipeline`, `stage`, …)\n * account the B2B company the contact works at (`name`, `url`), found or created\n * note a note left on the contact\n * event a custom event recorded against the contact (`name`, `data`)\n *\n * The page sends each mapped value under `<fieldType>.<fieldKey>` and the\n * backend reads it back with {@link parseActiveCampaignPropertyKey}.\n */\nimport { z } from \"zod\";\n\nexport const ACTIVECAMPAIGN_FIELD_TYPES = [\n \"standard\",\n \"custom\",\n \"tags\",\n \"lists\",\n \"automations\",\n \"deal\",\n \"account\",\n \"note\",\n \"event\",\n] as const;\nexport type ActiveCampaignFieldType = (typeof ACTIVECAMPAIGN_FIELD_TYPES)[number];\n\n/** Contact fields ActiveCampaign defines on every account, with the label it shows them under. */\nexport const ACTIVECAMPAIGN_STANDARD_FIELDS = [\n { key: \"email\", label: \"Email\" },\n { key: \"firstName\", label: \"First name\" },\n { key: \"lastName\", label: \"Last name\" },\n { key: \"phone\", label: \"Phone\" },\n] as const;\n\n/** The `fieldKey` of the one mapping that carries tags. */\nexport const ACTIVECAMPAIGN_TAGS_KEY = \"tags\";\n\n/** A deal's parts. `pipeline`, `stage` and `owner` take an id or a name; `value` is in major units. */\nexport const ACTIVECAMPAIGN_DEAL_FIELDS = [\n { key: \"title\", label: \"Deal title\" },\n { key: \"value\", label: \"Deal value\" },\n { key: \"currency\", label: \"Deal currency\" },\n { key: \"pipeline\", label: \"Pipeline\" },\n { key: \"stage\", label: \"Stage\" },\n { key: \"owner\", label: \"Deal owner\" },\n { key: \"description\", label: \"Deal description\" },\n] as const;\nexport type ActiveCampaignDealKey = (typeof ACTIVECAMPAIGN_DEAL_FIELDS)[number][\"key\"];\n\n/** The company (ActiveCampaign \"Account\") a contact works at. */\nexport const ACTIVECAMPAIGN_ACCOUNT_FIELDS = [\n { key: \"name\", label: \"Account name\" },\n { key: \"url\", label: \"Account website\" },\n] as const;\n\n/** A custom event; ActiveCampaign records it against the contact by email. */\nexport const ACTIVECAMPAIGN_EVENT_FIELDS = [\n { key: \"name\", label: \"Event name\" },\n { key: \"data\", label: \"Event details\" },\n] as const;\n\n/** The property key a mapped value travels under, from the page to the backend. */\nexport function activeCampaignPropertyKey(fieldType: ActiveCampaignFieldType, fieldKey: string): string {\n return `${fieldType}.${fieldKey}`;\n}\n\n/** The mapping a property key names, or null when it is not one this destination reads. */\nexport function parseActiveCampaignPropertyKey(\n key: string,\n): { fieldType: ActiveCampaignFieldType; fieldKey: string } | null {\n const dot = key.indexOf(\".\");\n if (dot <= 0) return null;\n const fieldType = key.slice(0, dot);\n const fieldKey = key.slice(dot + 1);\n if (!fieldKey || !(ACTIVECAMPAIGN_FIELD_TYPES as readonly string[]).includes(fieldType)) return null;\n return { fieldType: fieldType as ActiveCampaignFieldType, fieldKey };\n}\n\n/**\n * The names one resolved comma-separated value names (tags, lists,\n * automations): split on commas, trimmed, blanks and repeats dropped.\n * ActiveCampaign caps a name at 255 characters.\n */\nexport function splitActiveCampaignNames(value: string): string[] {\n const seen = new Set<string>();\n for (const raw of value.split(\",\")) {\n const name = raw.trim().slice(0, 255);\n if (name) seen.add(name);\n }\n return [...seen];\n}\n\n/** The tag names one resolved `tags` value names. */\nexport const splitActiveCampaignTags = splitActiveCampaignNames;\n\n/** One thing in the account a mapping can name: a list, an automation, a pipeline, a stage, a user. */\nexport interface ActiveCampaignOption {\n id: string;\n name: string;\n}\n\n/** The option a mapping names, by its id or — case-insensitively — its name. */\nexport function findActiveCampaignOption<T extends ActiveCampaignOption>(\n options: readonly T[],\n named: string,\n): T | undefined {\n const wanted = named.trim();\n if (!wanted) return undefined;\n return (\n options.find((option) => option.id === wanted) ??\n options.find((option) => option.name.trim().toLowerCase() === wanted.toLowerCase())\n );\n}\n\n/** `text` (digits and separators only) as a plain decimal number string. */\nfunction plainDecimal(text: string): string {\n const lastDot = text.lastIndexOf(\".\");\n const lastComma = text.lastIndexOf(\",\");\n if (lastDot !== -1 && lastComma !== -1) {\n const decimal = lastDot > lastComma ? \".\" : \",\";\n return text.replaceAll(decimal === \".\" ? \",\" : \".\", \"\").replace(decimal, \".\");\n }\n const separator = lastDot !== -1 ? \".\" : \",\";\n const parts = text.split(separator);\n if (parts.length === 1) return text;\n const last = parts[parts.length - 1] ?? \"\";\n const isThousands = parts.length > 2 || last.length === 3;\n return isThousands ? parts.join(\"\") : `${parts.slice(0, -1).join(\"\")}.${last}`;\n}\n\n/**\n * A typed amount in major units (`1,500.50`, `1.500,50 €`, `$99`) as the cents\n * ActiveCampaign stores a deal's value in, or null when it is not a positive\n * number. A lone separator followed by exactly three digits is a thousands\n * separator (`10.000`); otherwise the last separator is the decimal point.\n */\nexport function activeCampaignAmountToCents(raw: string): number | null {\n if (raw.includes(\"-\")) return null;\n const text = raw.replace(/[^\\d.,]/g, \"\");\n if (!/\\d/.test(text)) return null;\n const amount = Number(plainDecimal(text));\n return Number.isFinite(amount) ? Math.round(amount * 100) : null;\n}\n\n/**\n * The account's API address, normalised to its origin, or null when it is not\n * an ActiveCampaign API host.\n *\n * Every request carries the account's key to this host, so it is held to\n * ActiveCampaign's own domains: anything else would let a pasted address send\n * the key — and every lead — somewhere else. Accepts what Settings → Developer\n * shows (`https://acme.api-us1.com`), with or without `/api/3` or a trailing slash.\n */\nexport function normalizeActiveCampaignApiUrl(raw: string): string | null {\n const trimmed = raw.trim();\n if (!trimmed) return null;\n let url: URL;\n try {\n url = new URL(/^https?:\\/\\//i.test(trimmed) ? trimmed : `https://${trimmed}`);\n } catch {\n return null;\n }\n const host = url.hostname.toLowerCase();\n const allowed = /^[a-z0-9][a-z0-9-]*\\.(api-[a-z]{2}\\d+\\.com|activehosted\\.com)$/;\n if (!allowed.test(host) || url.port !== \"\") return null;\n return `https://${host}`;\n}\n\n/** One field a Form's answer can be mapped onto, as `baker flows map` and the editor list it. */\nexport const activeCampaignFieldSchema = z.object({\n fieldType: z.enum(ACTIVECAMPAIGN_FIELD_TYPES),\n /** What the mapping stores: the standard field's name, a custom field's id, `tags`, a deal part, …. */\n fieldKey: z.string(),\n label: z.string(),\n /** ActiveCampaign's own type for a custom field (`text`, `date`, `dropdown`, …); null otherwise. */\n dataType: z.string().nullable(),\n /** A custom field's personalization tag (`%SECTOR%`), which people recognise it by. */\n perstag: z.string().nullable(),\n});\nexport type ActiveCampaignField = z.infer<typeof activeCampaignFieldSchema>;\n\nfunction fixedField(\n fieldType: ActiveCampaignFieldType,\n fieldKey: string,\n label: string,\n dataType: string | null = null,\n): ActiveCampaignField {\n return { fieldType, fieldKey, label, dataType, perstag: null };\n}\n\n/**\n * Every destination entry that is the same on every account — everything but\n * the contact's own fields — in the order the editor and `flows map` offer them.\n */\nexport const ACTIVECAMPAIGN_FIXED_FIELDS: readonly ActiveCampaignField[] = [\n fixedField(\"tags\", ACTIVECAMPAIGN_TAGS_KEY, \"Tags\"),\n fixedField(\"lists\", \"lists\", \"Lists\"),\n fixedField(\"automations\", \"automations\", \"Automations\"),\n ...ACTIVECAMPAIGN_DEAL_FIELDS.map((field) =>\n fixedField(\"deal\", field.key, field.label, field.key === \"value\" ? \"currency\" : null),\n ),\n ...ACTIVECAMPAIGN_ACCOUNT_FIELDS.map((field) => fixedField(\"account\", field.key, field.label)),\n fixedField(\"note\", \"note\", \"Note\"),\n ...ACTIVECAMPAIGN_EVENT_FIELDS.map((field) => fixedField(\"event\", field.key, field.label)),\n];\n\nexport const activeCampaignOptionSchema = z.object({ id: z.string(), name: z.string() });\n\n/** A deal pipeline and its stages, first stage first — the one a deal lands in by default. */\nexport const activeCampaignPipelineSchema = activeCampaignOptionSchema.extend({\n stages: z.array(activeCampaignOptionSchema),\n});\nexport type ActiveCampaignPipeline = z.infer<typeof activeCampaignPipelineSchema>;\n\n/** An automation, and the tags whose adding starts it (\"tag is added\" starts) — empty when it starts some other way. */\nexport const activeCampaignAutomationSchema = activeCampaignOptionSchema.extend({\n startTags: z.array(z.string()).default([]),\n});\nexport type ActiveCampaignAutomation = z.infer<typeof activeCampaignAutomationSchema>;\n\n/** What a connected account offers a Form: its fields, and the things the other mappings can name. */\nexport const activeCampaignCatalogSchema = z.object({\n fields: z.array(activeCampaignFieldSchema),\n lists: z.array(activeCampaignOptionSchema).default([]),\n automations: z.array(activeCampaignAutomationSchema).default([]),\n pipelines: z.array(activeCampaignPipelineSchema).default([]),\n users: z.array(activeCampaignOptionSchema).default([]),\n /** Whether events can be sent: an event key is pasted on the connection, or ActiveCampaign reports one (event tracking is on). */\n eventKeySaved: z.boolean().default(false),\n});\nexport type ActiveCampaignCatalog = z.infer<typeof activeCampaignCatalogSchema>;\n\nexport const activeCampaignFieldsRequestSchema = z.object({\n /** Connection id; optional when the company has exactly one ActiveCampaign account. */\n account: z.string().optional(),\n});\nexport type ActiveCampaignFieldsRequest = z.infer<typeof activeCampaignFieldsRequestSchema>;\n\nexport const activeCampaignFieldsResponseSchema = z.object({\n ok: z.literal(true),\n data: activeCampaignCatalogSchema.extend({ account: z.string() }),\n});\nexport type ActiveCampaignFieldsResponse = z.infer<typeof activeCampaignFieldsResponseSchema>;\n","/**\n * What goes on the RIGHT of a `--map`, and how it becomes an AutofillDoc.\n *\n * The first version of this command could only map a plain form field, which\n * left out most of what a real CRM mapping is made of. `lead_source` almost\n * always wants `tracking.utm_source`; a \"full name\" column wants two fields and\n * a space between them; a Pipedrive owner field wants a literal. None of that\n * was expressible, so the command that exists to stop the agent hand-writing\n * ProseMirror sent it straight back to hand-writing ProseMirror for the most\n * common mapping in paid marketing.\n *\n * The grammar is four prefixes, a quoted literal, and `+`:\n *\n * nombre a form field (shorthand for field:nombre)\n * field:nombre …the same, explicit\n * field:Contact Info.nombre …disambiguated when two steps share a name\n * tracking:utm_source a built-in tracking variable\n * global:UserEmail a global variable, by the name it was given\n * code:total_score a codeExecution exposed value\n * \"Paid Search\" literal text\n * field:first + \" \" + field:last concatenation\n * {{<stepId>.customForm.nombre}} a mention as the flow file stores it\n * (also .codeExecution., tracking., global.)\n *\n * A value never runs code: `.split(\" \")[0]` and the like are refused, because\n * the engine substitutes a mention and nothing evaluates what follows it.\n *\n * Every reference is resolved against the flow's own tree — a name that is not\n * there is refused with the names that are. That is the whole point: `attrs.id`\n * is not checked by anything downstream, so a mapping with a subtly wrong id is\n * valid, ships, and sends an empty value forever.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { MappingError } from \"./mapping.ts\";\nimport { flowsDir, walkNodes } from \"./shared.ts\";\n\ntype AnyRecord = Record<string, unknown>;\n\nexport type ValuePart =\n | { kind: \"text\"; text: string }\n | { kind: \"field\"; ref: string }\n | { kind: \"tracking\"; name: string }\n | { kind: \"global\"; name: string }\n | { kind: \"code\"; ref: string };\n\nconst PREFIXES = [\"field\", \"tracking\", \"global\", \"code\"] as const;\n\n/**\n * Split on `+` at the top level, keeping quoted segments intact.\n *\n * Hand-rolled rather than a regex because a literal may contain `+` — a mapping\n * that emits `\"A + B\"` as text is legitimate, and a regex split would tear it in\n * half silently.\n */\nfunction splitParts(raw: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let inQuotes = false;\n for (let i = 0; i < raw.length; i++) {\n const char = raw[i];\n if (char === '\"') {\n inQuotes = !inQuotes;\n current += char;\n } else if (char === \"+\" && !inQuotes) {\n parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n parts.push(current);\n if (inQuotes) {\n throw new MappingError(`Unclosed quote in value \\`${raw}\\`.`, 'A literal is written \"like this\".');\n }\n return parts.map((part) => part.trim()).filter((part) => part.length > 0);\n}\n\nconst TRANSFORM_REFUSAL =\n \"A value cannot run code. Map the field as it is (firstname=full_name), or split it in the step with a codeExecution that exposes first_name and last_name and map code:first_name.\";\n\n/** `.split(`, `.slice(`, `.toUpperCase()` — a method call, which no mapping can run. */\nconst METHOD_CALL = /\\.\\s*[A-Za-z_$][\\w$]*\\s*\\(/;\n/** `[0]` on the end of a reference — an index, which no mapping can run either. */\nconst TRAILING_INDEX = /\\[[^\\]]*\\]$/;\n\n/**\n * A reference in the spelling the flow file itself stores it in —\n * `{{<stepId>.customForm.<field>}}` — and the one every refusal's inventory\n * prints the step id for. Refusing it sent the agent back to hand-writing the\n * ProseMirror doc for a field the command had just listed.\n */\nfunction mentionPart(inner: string): ValuePart {\n if (inner.startsWith(\"tracking.\")) return { kind: \"tracking\", name: inner.slice(\"tracking.\".length) };\n if (inner.startsWith(\"global.\")) return { kind: \"global\", name: inner.slice(\"global.\".length) };\n return referencePart(inner);\n}\n\n/** A bare reference: `<stepId>.codeExecution.<name>` is an exposed value, anything else a form field. */\nfunction referencePart(ref: string): ValuePart {\n return /\\.codeExecution\\.[^.]+$/.test(ref) ? { kind: \"code\", ref } : { kind: \"field\", ref };\n}\n\n/** One `+`-separated segment: a quoted literal, a prefixed reference, or a bare field name. */\nfunction parsePart(part: string): ValuePart {\n if (part.startsWith('\"') && part.endsWith('\"') && part.length >= 2) {\n return { kind: \"text\", text: part.slice(1, -1) };\n }\n if (METHOD_CALL.test(part) || TRAILING_INDEX.test(part)) {\n throw new MappingError(TRANSFORM_REFUSAL);\n }\n\n if (part.startsWith(\"{{\")) {\n const close = part.indexOf(\"}}\");\n if (close < 0) {\n throw new MappingError(\n `Unclosed \\`{{\\` in value \\`${part}\\`.`,\n \"A mention is written {{<stepId>.customForm.<field>}}.\",\n );\n }\n if (part.slice(close + 2).trim()) throw new MappingError(TRANSFORM_REFUSAL);\n return mentionPart(part.slice(2, close).trim());\n }\n\n const colon = part.indexOf(\":\");\n if (colon <= 0) return referencePart(part);\n\n const prefix = part.slice(0, colon);\n const rest = part.slice(colon + 1).trim();\n if (!(PREFIXES as readonly string[]).includes(prefix)) {\n throw new MappingError(\n `\\`${prefix}:\\` is not a value kind.`,\n `Use one of ${PREFIXES.map((candidate) => `${candidate}:`).join(\" \")}, a bare form field name, or a \"quoted literal\".`,\n );\n }\n if (!rest) throw new MappingError(`\\`${part}\\` names no ${prefix}.`);\n\n switch (prefix) {\n case \"tracking\":\n return { kind: \"tracking\", name: rest.replace(/^tracking\\./, \"\") };\n case \"global\":\n return { kind: \"global\", name: rest };\n case \"code\":\n return { kind: \"code\", ref: rest };\n default:\n return { kind: \"field\", ref: rest };\n }\n}\n\nexport function parseValueExpression(raw: string): ValuePart[] {\n const parts = splitParts(raw);\n if (parts.length === 0) {\n throw new MappingError(\"A --map needs a value on the right of the `=`.\");\n }\n return parts.map(parsePart);\n}\n\n/**\n * The tracking vocabulary, read out of the workspace the command is running in\n * rather than copied here. `TRACKING_FIELD_IDS` is the engine's own list, so\n * reading it is the only way this cannot drift — and there are already four\n * hand-copies of the flow taxonomy in this repo without adding a fifth.\n *\n * Returns null when the file is not there (the CLI run outside a client repo),\n * which skips validation rather than refusing a mapping that is probably fine.\n */\nexport function trackingFieldIds(): Set<string> | null {\n const path = join(flowsDir(), \"..\", \"tracking.ts\");\n if (!existsSync(path)) return null;\n try {\n const source = readFileSync(path, \"utf-8\");\n const block = source.match(/TRACKING_FIELD_IDS\\s*=\\s*\\[([\\s\\S]*?)\\]\\s*as const/)?.[1];\n if (!block) return null;\n const ids = [...block.matchAll(/\"(tracking\\.[a-z0-9_]+)\"/g)].map((match) => match[1] as string);\n return ids.length > 0 ? new Set(ids) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * A step's `nodeData.form.external` — the one place the engine keeps both a\n * step's fields and its `codeExecution`.\n *\n * Read through here rather than off `nodeData` directly. `codeExecution` is\n * nested one level deeper than it looks (`CustomFormData` in `types.ts`, and\n * both readers — `store.ts` `applyCodeExecution` and `code-normalize.ts`\n * `pushCustomFormExposedNames` — go through `form.external`), and reading it\n * from the wrong level is invisible: the lookup simply finds nothing and every\n * `code:` reference is refused as if the form exposed no values at all.\n */\nfunction externalOf(node: AnyRecord): AnyRecord {\n const nodeData = (node.nodeData ?? {}) as AnyRecord;\n return ((nodeData.form as AnyRecord | undefined)?.external ?? {}) as AnyRecord;\n}\n\ntype FieldOwner = { id: string; name: string; fields: string[] };\n\n/** Steps that collect data, with the fields each one owns. */\nfunction fieldOwners(tree: AnyRecord): FieldOwner[] {\n return walkNodes(tree).flatMap((node) => {\n const external = externalOf(node);\n if (!Array.isArray(external.fields)) return [];\n return [\n {\n id: String(node.id ?? \"\"),\n name: typeof node.name === \"string\" && node.name ? node.name : \"Form\",\n fields: (external.fields as AnyRecord[])\n .map((field) => field?.fieldName)\n .filter((name): name is string => typeof name === \"string\"),\n },\n ];\n });\n}\n\n/**\n * `Contact Info.email` → the step called \"Contact Info\"; `email` → whichever step\n * owns it; `<stepId>.customForm.email` → that step, spelled as the flow file\n * stores the mention (`segment` is `customForm` for a field, `codeExecution`\n * for an exposed value).\n */\nfunction splitRef(ref: string, segment: \"customForm\" | \"codeExecution\"): { step?: string; name: string } {\n const marker = `.${segment}.`;\n const at = ref.lastIndexOf(marker);\n if (at > 0 && !ref.slice(at + marker.length).includes(\".\")) {\n return { step: ref.slice(0, at), name: ref.slice(at + marker.length) };\n }\n const dot = ref.lastIndexOf(\".\");\n if (dot <= 0) return { name: ref };\n return { step: ref.slice(0, dot), name: ref.slice(dot + 1) };\n}\n\nfunction mention(id: string, label: string): AnyRecord {\n return { type: \"VariablesMention\", attrs: { id, label, mentionSuggestionChar: \"{{\" } };\n}\n\n/** \"servicio_deseado\" → \"Servicio Deseado\" — the dashboard's display convention. */\nfunction titleize(value: string): string {\n return value\n .split(/[_-]+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\nfunction resolveField(tree: AnyRecord, ref: string): AnyRecord {\n const { step, name } = splitRef(ref, \"customForm\");\n const owners = fieldOwners(tree);\n const inventory = owners\n .map((owner) => ` ${owner.name} (${owner.id}): ${owner.fields.join(\", \") || \"(no fields)\"}`)\n .join(\"\\n\");\n\n const candidates = owners.filter(\n (owner) => owner.fields.includes(name) && (!step || owner.name === step || owner.id === step),\n );\n if (candidates.length === 0) {\n throw new MappingError(`Form field \"${ref}\" does not exist in this form.`, inventory);\n }\n // Two steps can legitimately own a field with the same name. Picking one would\n // wire the mapping to whichever happened to come first in the tree.\n if (candidates.length > 1) {\n throw new MappingError(\n `Form field \"${name}\" exists on ${candidates.length} steps — say which: field:<step>.${name}`,\n candidates.map((owner) => ` field:${owner.name}.${name}`).join(\"\\n\"),\n );\n }\n const owner = candidates[0] as FieldOwner;\n // The engine stores every node type's submission under `.customForm.`\n // (`controller.ts`, `wire.ts`), so this prefix is not the node's type.\n return mention(`${owner.id}.customForm.${name}`, `${owner.name} => ${titleize(name)}`);\n}\n\nfunction resolveTracking(name: string): AnyRecord {\n const id = `tracking.${name}`;\n const known = trackingFieldIds();\n if (known && !known.has(id)) {\n const near = [...known].filter((candidate) => candidate.includes(name.split(\"_\")[0] ?? name)).slice(0, 8);\n throw new MappingError(\n `\\`${id}\\` is not a tracking variable.`,\n near.length > 0\n ? `Close matches: ${near.join(\", \")}`\n : \"See references/autofill-and-variables.md § Built-in Tracking Variables.\",\n );\n }\n // Tracking and global mentions carry the id as their own label — that is what\n // the dashboard editor writes, and what the renderer displays.\n return mention(id, id);\n}\n\nfunction resolveGlobal(tree: AnyRecord, name: string): AnyRecord {\n const globals = (tree.globalVariables as AnyRecord[] | undefined) ?? [];\n const match = globals.find((variable) => variable?.name === name || variable?.id === name);\n if (!match) {\n throw new MappingError(\n `No global variable named \"${name}\" on this form.`,\n globals.length > 0\n ? `Defined: ${globals.map((variable) => String(variable.name)).join(\", \")}`\n : \"This form defines none. Globals live on the first node only — see references/autofill-and-variables.md § Global Variables.\",\n );\n }\n const id = `global.${String(match.id)}`;\n return mention(id, id);\n}\n\nfunction resolveCode(tree: AnyRecord, ref: string): AnyRecord {\n const { step, name } = splitRef(ref, \"codeExecution\");\n const owners = walkNodes(tree).flatMap((node) => {\n const exposed = ((externalOf(node).codeExecution as AnyRecord | undefined)?.exposedValues ?? []) as AnyRecord[];\n const names = exposed.map((value) => value?.name).filter((value): value is string => typeof value === \"string\");\n return names.length > 0 ? [{ id: String(node.id ?? \"\"), name: String(node.name ?? \"step\"), names }] : [];\n });\n\n const candidates = owners.filter(\n (owner) => owner.names.includes(name) && (!step || owner.name === step || owner.id === step),\n );\n if (candidates.length !== 1) {\n throw new MappingError(\n candidates.length === 0\n ? `No codeExecution exposes \"${ref}\" on this form.`\n : `\"${name}\" is exposed by ${candidates.length} steps — say which: code:<step>.${name}`,\n owners.length > 0\n ? owners.map((owner) => ` ${owner.name} (${owner.id}): ${owner.names.join(\", \")}`).join(\"\\n\")\n : \"No step on this form exposes any codeExecution value.\",\n );\n }\n const owner = candidates[0] as { id: string; name: string };\n // Exposed values live under `.codeExecution.`, NOT `.customForm.` — the same\n // id under the wrong segment resolves to empty in every CRM payload.\n return mention(`${owner.id}.codeExecution.${name}`, `${owner.name} => ${titleize(name)}`);\n}\n\n/**\n * Build the AutofillDoc a mapping's `value` holds.\n *\n * A single mention keeps its trailing space: that is byte-for-byte what the\n * dashboard's editor produces, and matching it means a mapping written here and\n * one written there are indistinguishable. A multi-part expression emits exactly\n * the parts given, because an injected space would corrupt `first + last`.\n */\nexport function buildValueDoc(tree: AnyRecord, expression: string): AnyRecord {\n const parts = parseValueExpression(expression);\n const content = parts.map((part) => {\n switch (part.kind) {\n case \"text\":\n return { type: \"text\", text: part.text };\n case \"tracking\":\n return resolveTracking(part.name);\n case \"global\":\n return resolveGlobal(tree, part.name);\n case \"code\":\n return resolveCode(tree, part.ref);\n default:\n return resolveField(tree, part.ref);\n }\n });\n\n const single = content.length === 1 && parts[0]?.kind !== \"text\";\n return {\n type: \"doc\",\n content: [{ type: \"paragraph\", content: single ? [...content, { type: \"text\", text: \" \" }] : content }],\n };\n}\n","/**\n * Build a side effect's `fieldMapping` / `columnMapping` from a short spec.\n *\n * Why this exists. A single mapped field is a ~28-line ProseMirror document:\n *\n * { \"objectTypeId\": \"0-1\", \"fieldType\": \"email\", \"fieldName\": \"email\",\n * \"value\": { \"type\": \"doc\", \"content\": [ { \"type\": \"paragraph\", \"content\": [\n * { \"type\": \"VariablesMention\", \"attrs\": {\n * \"id\": \"<nodeId>.customForm.<formField>\",\n * \"label\": \"<Node Name> => <Form Field>\",\n * \"mentionSuggestionChar\": \"{{\" } },\n * { \"type\": \"text\", \"text\": \" \" } ] } ] } }\n *\n * An eight-field CRM mapping is ~230 lines of hand-emitted JSON per form, in\n * which the only information is eight pairs of names. In one real session two\n * forms cost ~460 lines — written once, lost, and written again by hand.\n *\n * It also removes the failure mode those lines invite. `attrs.id` is\n * `<owning node's id>.customForm.<field>`: get the node wrong, or the field name\n * subtly wrong, and the mapping is structurally valid, ships, and silently sends\n * an empty value forever. This resolves the node id from the tree and refuses a\n * form field that does not exist.\n *\n * What it deliberately does NOT do: choose the destination. The CRM-side names\n * (`firstname`, a sheet column) describe an account only `request_flow_input`\n * can see. Configure the side effect first, read the real names back off that\n * call's own result, then map.\n *\n * This file owns the DESTINATION half — which record shape each side-effect type\n * reads, and what it refuses to guess. What goes in `value` is the other half,\n * and it lives in `value-expression.ts`.\n *\n * ## A mapping accumulates, so a write merges\n *\n * Every slot merges with what is already in it, addressed by destination name:\n * re-mapping a name overwrites it in place, a new name is appended, and a name\n * this call did not mention is left alone. `MapOptions.replace` is the opt-in\n * for the other reading, and it is the only way to remove a mapping.\n *\n * Merging is the default because building a mapping is not one act. The\n * documented order is configure the destination, read the real field names back,\n * then map — and in practice that means several calls, because the names arrive\n * in batches and some of them need a field type the first call did not have.\n * Replacing on every call turned \"add the ninth field\" into \"delete the other\n * eight\", with nothing said. That is this file's own failure mode, one level up:\n * a mapping that is structurally valid, ships, and delivers nothing.\n *\n * ## Destination metadata is derived, never defaulted\n *\n * A CRM mapping carries more than a pair of names: `fieldType`, `objectTypeId`,\n * `entityType`, `isCustomField`. Every one of them is a fact about the connected\n * account, and every one is required by the record the engine reads — so there\n * are exactly two honest ways to fill them, and inventing a plausible value is\n * not one. Either the caller hands over the destination's own field catalog\n * (`MapOptions.destinationFields`, which `map.ts` reads off the account) and\n * they are DERIVED, or the mapping states them and they are declared. Anything\n * else is refused.\n *\n * That order matters for how much work the agent does. Deriving is both less\n * work and more accurate than being told, so a caller that can read the\n * destination should: the agent then writes `firstname=nombre` and the types\n * take care of themselves.\n *\n * Pure — every function here takes a decoded tree and returns data, so the\n * refusals are unit-tested without a filesystem. Reading a destination's\n * catalog is I/O and therefore lives in `map.ts`.\n */\n\nimport {\n ACTIVECAMPAIGN_FIELD_TYPES,\n type ActiveCampaignCatalog,\n type ActiveCampaignField,\n type ActiveCampaignOption,\n findActiveCampaignOption,\n splitActiveCampaignNames,\n} from \"@baker/api/activecampaign\";\nimport { buildValueDoc } from \"./value-expression.ts\";\n\ntype AnyRecord = Record<string, unknown>;\n\n/** A refusal the caller turns into a `{ ok: false }` envelope with a `fix`. */\nexport class MappingError extends Error {\n readonly fix: string | undefined;\n constructor(message: string, fix?: string) {\n super(message);\n this.name = \"MappingError\";\n this.fix = fix;\n }\n}\n\n/**\n * A destination addressed by a list of records: one entry per mapped field.\n *\n * Two families share it. The CRM/sheet family (`fieldMapping`, `columnMapping`)\n * carries destination metadata alongside the value; the `PayloadKey` family\n * (`payloadKeys`, `eventParams`, `eventProperties`, `dataLayerParams`,\n * `goalParams`) is just `{ key, value }`.\n */\ntype ListShape = {\n kind: \"list\";\n key: string;\n /**\n * The object the list hangs off, when it is not the side effect itself.\n *\n * Only `email` needs it — its keys live at `body.fields`, and only while\n * `body.format` is `\"json\"`. That one level of nesting is why this command\n * used to refuse `email` outright, which left the single most common\n * notification side effect as the one place an agent still hand-wrote a\n * ProseMirror document per field.\n */\n under?: string;\n addressedBy: string;\n entities?: readonly string[];\n needsFieldType?: boolean;\n needsIsCustom?: boolean;\n /** Where the per-mapping field types come from, for the refusal that asks for one. */\n fieldTypeSource?: string;\n /** The closed set a stated field type must belong to, when the destination defines one. */\n fieldTypes?: readonly string[];\n /**\n * An entry is named by `<fieldType>.<address>` rather than its address alone,\n * when one address means different things under different types — an\n * ActiveCampaign `account.name` and `event.name` are two destinations.\n */\n qualifiedByFieldType?: boolean;\n};\n\n/**\n * A destination addressed by a fixed set of named slots, each an AutofillDoc.\n *\n * Meta advanced matching, Google Ads enhanced conversions, TikTok identify,\n * LinkedIn/X user matching, Pinterest enhanced matching. The key set is closed\n * and defined by the platform, so a name outside it is a typo, not a field.\n */\ntype RecordShape = { kind: \"record\"; key: string; allowed: readonly string[] };\n\n/** A single AutofillDoc sitting directly on the side effect (`value`, `currency`, …). */\ntype ScalarShape = { kind: \"scalar\"; keys: readonly string[] };\n\ntype MappingShape = ListShape | RecordShape | ScalarShape;\n\nconst PAYLOAD = (key: string): ListShape => ({ kind: \"list\", key, addressedBy: \"key\" });\n\nconst META_MATCHING = [\"em\", \"fn\", \"ln\", \"ph\", \"external_id\", \"ge\", \"db\", \"ct\", \"st\", \"zp\", \"country\"] as const;\nconst ADS_MATCHING = [\n \"email\",\n \"phone_number\",\n \"first_name\",\n \"last_name\",\n \"street\",\n \"city\",\n \"region\",\n \"postal_code\",\n \"country\",\n] as const;\n\n/**\n * Every slot each side-effect type can have a value mapped into, in the order\n * `--map` defaults to.\n *\n * This started as five CRM entries, which meant `baker flows map` refused\n * eleven of the sixteen mappable types — including the two most common things\n * in a real workspace: a webhook body and a Meta pixel's parameters. Its\n * refusal also said, in as many words, that `httpWebhook` and `zapier` \"carry\n * the whole submission and do not address individual destination fields\", which\n * is not true of either: both have `payloadKeys`, and a real form was already\n * using fourteen of them.\n *\n * A type with more than one slot takes `--into <key>` to pick; without it the\n * first is used, and the response names the others.\n */\nexport const MAPPING_SLOTS: Record<string, readonly MappingShape[]> = {\n shopifyCustomer: [\n {\n kind: \"record\",\n key: \"customer\",\n allowed: [\"email\", \"phone\", \"firstName\", \"lastName\", \"acceptsEmailMarketing\", \"acceptsSmsMarketing\"],\n },\n ],\n googleSpreadsheet: [{ kind: \"list\", key: \"columnMapping\", addressedBy: \"column\" }],\n hubspotForm: [\n {\n kind: \"list\",\n key: \"fieldMapping\",\n addressedBy: \"fieldName\",\n needsFieldType: true,\n fieldTypeSource:\n \"Pass --hubspot-form <formGuid> and this command reads every property's type off the form itself — the guid is the `formGuid` in the `destination` request_flow_input returned. `baker hubspot forms view <formGuid>` prints the same list if you want to see it.\",\n },\n ],\n pipedrive: [\n {\n kind: \"list\",\n key: \"fieldMapping\",\n addressedBy: \"fieldKey\",\n entities: [\"person\", \"organization\", \"lead\"],\n needsFieldType: true,\n needsIsCustom: true,\n },\n ],\n goHighlevelContact: [\n {\n kind: \"list\",\n key: \"fieldMapping\",\n addressedBy: \"fieldKey\",\n entities: [\"business\", \"contact\", \"opportunity\"],\n needsFieldType: true,\n needsIsCustom: true,\n },\n ],\n crmble: [\n { kind: \"list\", key: \"fieldMapping\", addressedBy: \"fieldId\", entities: [\"contact\", \"lead\"], needsFieldType: true },\n ],\n activeCampaignContact: [\n {\n kind: \"list\",\n key: \"fieldMapping\",\n addressedBy: \"fieldKey\",\n needsFieldType: true,\n fieldTypes: ACTIVECAMPAIGN_FIELD_TYPES,\n qualifiedByFieldType: true,\n fieldTypeSource:\n 'None to write: this command reads the connected ActiveCampaign account\\'s field list itself. Write `email=email`, `firstName=nombre`, a custom field by its id, personalization tag or label (`SECTOR=sector`; `custom.UTM_SOURCE=…` for one only staged so far), `tags=\"withbaker-\"+tracking:page_path`, `lists=\"Newsletter\"`, `automations=\"Welcome\"`, `deal.title=…` / `deal.pipeline=\"Sales\"` / `deal.value=budget`, `account.name=company`, `note=…`, `event.name=\"demo_requested\"`.',\n },\n ],\n\n email: [{ ...PAYLOAD(\"fields\"), under: \"body\" }],\n zapier: [PAYLOAD(\"payloadKeys\")],\n httpWebhook: [PAYLOAD(\"payloadKeys\")],\n googleTagManager: [PAYLOAD(\"dataLayerParams\")],\n googleAnalytics: [PAYLOAD(\"eventParams\")],\n posthog: [PAYLOAD(\"eventParams\")],\n amplitude: [PAYLOAD(\"eventProperties\")],\n hubspot: [PAYLOAD(\"eventProperties\")],\n vwo: [PAYLOAD(\"eventProperties\")],\n code: [PAYLOAD(\"eventProperties\")],\n datafast: [PAYLOAD(\"goalParams\")],\n\n meta: [PAYLOAD(\"eventParams\"), { kind: \"record\", key: \"advancedMatching\", allowed: META_MATCHING }],\n chatgptAds: [\n PAYLOAD(\"eventParams\"),\n {\n kind: \"record\",\n key: \"advancedMatching\",\n allowed: [\"em\", \"ph\", \"fn\", \"ln\", \"external_id\", \"ct\", \"st\", \"zp\", \"country\"],\n },\n ],\n tiktok: [\n PAYLOAD(\"eventParams\"),\n { kind: \"record\", key: \"identify\", allowed: [\"email\", \"phone_number\", \"external_id\"] },\n ],\n pinterest: [PAYLOAD(\"eventParams\"), { kind: \"record\", key: \"enhancedMatching\", allowed: [\"em\", \"hashed_maids\"] }],\n googleAds: [\n { kind: \"record\", key: \"enhancedConversions\", allowed: ADS_MATCHING },\n { kind: \"scalar\", keys: [\"value\", \"currency\", \"transactionId\"] },\n ],\n linkedinInsightTag: [\n { kind: \"record\", key: \"userMatching\", allowed: [\"em\", \"fn\", \"ln\", \"title\", \"companyName\", \"country\"] },\n { kind: \"scalar\", keys: [\"value\", \"currency\"] },\n ],\n twitterAds: [\n { kind: \"record\", key: \"userMatching\", allowed: [\"em\", \"ph\"] },\n { kind: \"scalar\", keys: [\"value\", \"currency\"] },\n ],\n};\n\n/**\n * The types that genuinely address nothing, and why — so the refusal can say it.\n *\n * Exported for `flow-catalog-coverage.test.ts`, which asserts that this and\n * `MAPPING_SLOTS` between them classify EVERY side-effect type the catalog\n * defines, exactly once. That gate is the reason a claim about this file can be\n * trusted: `email` used to live here, moved to `MAPPING_SLOTS` when `body.fields`\n * became mappable, and left behind prose elsewhere still describing it as\n * unmappable. A type in neither list refuses with \"not a side-effect type this\n * workspace's flow engine defines\" — which is false, and unanswerable.\n */\nexport const UNMAPPABLE: Record<string, string> = {\n hotjar: \"A Hotjar event carries only its name.\",\n clarity: \"A Clarity custom tag carries only its name.\",\n};\n\n/** How a slot is named everywhere the agent sees it — qualified when it is nested. */\nfunction slotName(shape: MappingShape): string {\n if (shape.kind === \"scalar\") return shape.keys.join(\"/\");\n if (shape.kind === \"list\" && shape.under) return `${shape.under}.${shape.key}`;\n return shape.key;\n}\n\n/**\n * The slot to map into: the one named by `--into`, or the first.\n * Refuses rather than guessing between a real slot and a name that is not one.\n */\nexport function shapeFor(type: string, into?: string): MappingShape {\n const slots = MAPPING_SLOTS[type];\n if (!slots) {\n const why = UNMAPPABLE[type];\n throw new MappingError(\n `Side effect \"${type}\" has no mappable field.`,\n why ?? `\"${type}\" is not a side-effect type this workspace's flow engine defines.`,\n );\n }\n if (!into) return slots[0] as MappingShape;\n const chosen = slots.find((slot) =>\n slot.kind === \"scalar\"\n ? slot.keys.includes(into) || into === \"scalar\"\n : slot.key === into || slotName(slot) === into,\n );\n if (!chosen) {\n throw new MappingError(\n `\"${into}\" is not a mappable slot on a ${type} side effect.`,\n `Slots on ${type}: ${slots.map(slotName).join(\", \")}`,\n );\n }\n return chosen;\n}\n\n/**\n * Whether this slot's names come from the connected account, or from the agent.\n *\n * The distinction decides what an unconfigured destination means. A sheet\n * column, a HubSpot property, a Pipedrive field key — those exist only in an\n * account the agent cannot see, so writing them before `request_flow_input` has\n * run means inventing them, and an invented destination is valid JSON that\n * ships and drops every submission. A webhook's `payloadKeys` and a pixel's\n * `eventParams` are the opposite: the agent picks those names (or the platform\n * fixes them), so they are perfectly authorable before the endpoint is set.\n */\nexport function namesComeFromAccount(shape: MappingShape): boolean {\n return shape.kind === \"list\" && shape.addressedBy !== \"key\";\n}\n\n/**\n * What can be mapped into a side effect, and — the part that is not guessable —\n * where the legal keys on the LEFT of each mapping come from.\n *\n * There are three different answers, and reading the wrong one produces a\n * mapping that is valid JSON and silently delivers nothing:\n *\n * closed the platform fixes the names (`em`, `ph`, `postal_code`). Anything\n * else is a typo, and they are listed here in full.\n * yours the keys are whatever the receiving system expects — a Make\n * scenario's field names, a GA4 parameter. Nobody but the user knows\n * them, but nothing validates them either, so you write what you were told.\n * account a sheet column, a HubSpot property, a Pipedrive field key. These\n * exist only in the connected account, so they come back from\n * `request_flow_input` and cannot be known before it runs.\n *\n * Exposed so the discovery path is a plain read rather than a wrong guess: the\n * agent used to learn a closed set only by naming a key outside it.\n */\nexport type SlotDescription = {\n slot: string;\n addressedBy: string;\n keysFrom: \"closed\" | \"yours\" | \"account\";\n keys?: readonly string[];\n note: string;\n /** How to get the per-mapping field types, for a slot that stores one. */\n fieldTypes?: string;\n};\n\nexport function describeSlots(type: string): SlotDescription[] {\n return (MAPPING_SLOTS[type] ?? []).map((shape) => {\n if (shape.kind === \"record\") {\n return {\n slot: shape.key,\n addressedBy: \"one of a closed set\",\n keysFrom: \"closed\" as const,\n keys: shape.allowed,\n note: `${type} defines these names; any other is refused.`,\n };\n }\n if (shape.kind === \"scalar\") {\n return {\n slot: shape.keys.join(\"/\"),\n addressedBy: \"the field's own name\",\n keysFrom: \"closed\" as const,\n keys: shape.keys,\n note: \"Each is a single value on the side effect, mapped like any other.\",\n };\n }\n if (shape.addressedBy === \"key\") {\n return {\n slot: slotName(shape),\n addressedBy: \"key\",\n keysFrom: \"yours\" as const,\n note: \"You name these — they are what the receiving system expects. Ask the user if you do not know them.\",\n };\n }\n return {\n slot: slotName(shape),\n addressedBy: shape.addressedBy,\n keysFrom: \"account\" as const,\n note: \"These live in the connected account. Read them off the request_flow_input result; they cannot be guessed.\",\n ...(shape.needsFieldType ? { fieldTypes: shape.fieldTypeSource ?? FIELD_TYPE_FROM_INPUT } : {}),\n };\n });\n}\n\n/** Where a per-mapping field type comes from when the shape names no better source. */\nconst FIELD_TYPE_FROM_INPUT =\n \"Each mapping stores a field type. They come back from request_flow_input with the field list — write one on the LEFT: <field>:<fieldType>=<value>.\";\n\n/** Every slot a type offers, for the hint that tells the agent what else it could map. */\nexport function otherSlots(type: string, used: MappingShape): string[] {\n return (MAPPING_SLOTS[type] ?? []).filter((slot) => slot !== used).map(slotName);\n}\n\n/**\n * One destination property as the connected account describes it.\n *\n * The point of carrying this is that `fieldType` stops being something the agent\n * has to know. It is a destination-side fact — HubSpot's own answer for that\n * property — so the only two honest ways to fill it are to read it off the\n * account or to be told it explicitly. Guessing a plausible-looking one is the\n * third option, and it is the one that ships: the key the engine builds is\n * `<objectTypeId>.<fieldType>.<fieldName>`, and a wrong `fieldType` on a date\n * property silently skips the YYYY-MM-DD coercion HubSpot requires.\n */\nexport type DestinationField = {\n fieldType: string;\n objectTypeId?: string;\n /**\n * The name the mapping is stored under, when the catalog also answers to\n * other names for it (an ActiveCampaign custom field is stored by id but known\n * by its personalization tag and label). Absent ⇒ the name looked up is the\n * one stored, and it must match exactly.\n */\n fieldKey?: string;\n /** How people know the field, for the refusal that lists what the destination has. */\n label?: string;\n /** The name to write it by, when that is not `fieldKey` alone (`deal.title`). */\n listedAs?: string;\n};\n\n/** Kinds whose one entry is also reachable by the bare word (`tags`, `lists`, `note`). */\nconst ACTIVECAMPAIGN_BARE_KINDS = new Set([\"standard\", \"custom\", \"tags\", \"lists\", \"automations\", \"note\"]);\n\n/**\n * An ActiveCampaign account's field list, as `buildFieldMapping` reads it.\n *\n * Every field is reachable as `<fieldType>.<fieldKey>` (`deal.title`,\n * `account.name`, `event.name`), the name the mapping is merged and pruned by.\n * Contact fields and the single-entry kinds also answer to the bare key\n * (`email`, `tags`, `lists`, `note`). A custom field is stored by its id (\"12\"),\n * which nobody recognises, so it also answers to its personalization tag (with\n * or without the `%`) and to its label, case-insensitively — and each of those\n * is normalised back to the id, because the id is what the backend sends.\n */\n/** A custom field's personalization tag and label as further names for it, never shadowing a field's own key. */\nfunction addCustomAliases(catalog: Map<string, DestinationField>, field: ActiveCampaignField): void {\n const entry = catalog.get(`custom.${field.fieldKey}`);\n if (!entry) return;\n const tag = field.perstag?.replaceAll(\"%\", \"\");\n if (tag) catalog.set(`custom.${tag.toUpperCase()}`, entry);\n const aliases = [field.perstag, tag, field.label].filter((alias): alias is string => !!alias);\n for (const alias of aliases) {\n const key = alias.trim().toLowerCase();\n if (key && !catalog.has(key)) catalog.set(key, entry);\n }\n}\n\nexport function activeCampaignDestinationFields(\n fields: readonly ActiveCampaignField[],\n): ReadonlyMap<string, DestinationField> {\n const catalog = new Map<string, DestinationField>();\n for (const field of fields) {\n const qualified = `${field.fieldType}.${field.fieldKey}`;\n const bare = ACTIVECAMPAIGN_BARE_KINDS.has(field.fieldType);\n const entry: DestinationField = {\n fieldType: field.fieldType,\n fieldKey: field.fieldKey,\n label: field.label,\n ...(bare ? {} : { listedAs: qualified }),\n };\n catalog.set(qualified, entry);\n if (bare && !catalog.has(field.fieldKey)) {\n catalog.set(field.fieldKey, entry);\n }\n }\n for (const field of fields) {\n if (field.fieldType === \"custom\") addCustomAliases(catalog, field);\n }\n return catalog;\n}\n\n/**\n * A custom field named by a personalization tag the account does not have yet\n * (`custom.UTM_SOURCE`) — typically one staged in this Session, created at\n * Publish. Stored by the tag and resolved to the field's id when a lead is sent;\n * until the field exists that value is left empty and the delivery says so.\n */\nexport function activeCampaignUnlistedField(destField: string): DestinationField | undefined {\n const match = /^custom\\.%?([A-Za-z][A-Za-z0-9_]*)%?$/.exec(destField.trim());\n if (!match?.[1]) return undefined;\n const tag = match[1].toUpperCase();\n return { fieldType: \"custom\", fieldKey: tag, label: `%${tag}%` };\n}\n\n/** A mapped value's text when it is only text — no variable, so it can be checked now. */\nfunction literalText(value: unknown): string | null {\n const paragraphs = ((value ?? {}) as { content?: { content?: { type?: string; text?: string }[] }[] }).content;\n if (!Array.isArray(paragraphs)) return null;\n const inline = paragraphs.flatMap((paragraph) => paragraph.content ?? []);\n if (inline.length === 0 || inline.some((node) => node.type !== \"text\")) return null;\n return inline.map((node) => node.text ?? \"\").join(\"\");\n}\n\nfunction optionListing(options: readonly ActiveCampaignOption[]): string {\n return options.length > 0 ? options.map((option) => `${option.name} (${option.id})`).join(\", \") : \"none\";\n}\n\n/** Each literal name in a comma-separated value the account has no option for. */\nfunction unknownNames(value: unknown, options: readonly ActiveCampaignOption[]): string[] {\n const text = literalText(value);\n if (text === null) return [];\n return splitActiveCampaignNames(text).filter((name) => !findActiveCampaignOption(options, name));\n}\n\ntype Mapped = (type: string, key: string) => AnyRecord | undefined;\n\nfunction namedOptionHints(mapped: Mapped, catalog: ActiveCampaignCatalog): string[] {\n const hints: string[] = [];\n const unknown = (type: string, key: string, options: readonly ActiveCampaignOption[], noun: string) => {\n for (const name of unknownNames(mapped(type, key)?.value, options)) {\n hints.push(\n `ActiveCampaign has no ${noun} called \"${name}\", so that part will be skipped. It has: ${optionListing(options)}.`,\n );\n }\n };\n unknown(\"lists\", \"lists\", catalog.lists, \"list\");\n unknown(\"automations\", \"automations\", catalog.automations, \"automation\");\n if (mapped(\"automations\", \"automations\") && catalog.automations.length === 0) {\n hints.push(\n \"This ActiveCampaign account has no automations. They can only be built in ActiveCampaign — ask the user to create one.\",\n );\n }\n unknown(\"deal\", \"pipeline\", catalog.pipelines, \"pipeline\");\n unknown(\"deal\", \"owner\", catalog.users, \"user\");\n return hints;\n}\n\n/**\n * The tags a value adds for certain: each comma-separated piece of its text\n * that no variable touches (`\"quote-request, withbaker-\"+page_path` adds\n * `quote-request` for sure; `withbaker-` is only the start of a tag).\n */\nfunction literalTags(value: unknown): string[] {\n const paragraphs = ((value ?? {}) as { content?: { content?: { type?: string; text?: string }[] }[] }).content;\n if (!Array.isArray(paragraphs)) return [];\n const inline = paragraphs.flatMap((paragraph) => paragraph.content ?? []);\n return inline.flatMap((node, index) => {\n if (node.type !== \"text\") return [];\n const pieces = (node.text ?? \"\").split(\",\");\n const touchesBefore = index > 0 && inline[index - 1]?.type !== \"text\";\n const touchesAfter = index < inline.length - 1 && inline[index + 1]?.type !== \"text\";\n return pieces\n .filter((_, piece) => !(piece === 0 && touchesBefore) && !(piece === pieces.length - 1 && touchesAfter))\n .map((piece) => piece.trim())\n .filter((piece) => piece !== \"\");\n });\n}\n\n/** An automation the Form enrolls a lead in AND starts by tagging them: the lead runs it twice. */\nfunction doubleEnrollmentHints(mapped: Mapped, catalog: ActiveCampaignCatalog): string[] {\n const enrolled = literalText(mapped(\"automations\", \"automations\")?.value);\n if (enrolled === null) return [];\n const tags = new Set(literalTags(mapped(\"tags\", \"tags\")?.value).map((tag) => tag.toLowerCase()));\n return splitActiveCampaignNames(enrolled).flatMap((name) => {\n const automation = catalog.automations.find((option) => findActiveCampaignOption([option], name));\n const tag = automation?.startTags.find((start) => tags.has(start.toLowerCase()));\n return automation && tag\n ? [\n `\"${automation.name}\" starts when the tag \"${tag}\" is added, and this Form adds that tag AND enrolls the lead in it — every lead would run it twice (ActiveCampaign's \"runs once\" does not stop a direct enrollment). Keep one: drop \"${automation.name}\" from automations, or drop the tag.`,\n ]\n : [];\n });\n}\n\nfunction dealHints(fieldMapping: readonly AnyRecord[], mapped: Mapped, catalog: ActiveCampaignCatalog): string[] {\n if (!fieldMapping.some((entry) => entry.fieldType === \"deal\")) return [];\n const hints: string[] = [];\n if (!mapped(\"deal\", \"title\") && !mapped(\"deal\", \"pipeline\")) {\n hints.push(\"No deal is created without deal.title or deal.pipeline — map one of them too.\");\n }\n if (catalog.pipelines.length === 0) {\n hints.push(\"This ActiveCampaign account has no deal pipeline, so no deal can be created until one exists.\");\n }\n const pipelineText = literalText(mapped(\"deal\", \"pipeline\")?.value);\n const pipeline = pipelineText ? findActiveCampaignOption(catalog.pipelines, pipelineText) : catalog.pipelines[0];\n if (!pipeline) return hints;\n for (const name of unknownNames(mapped(\"deal\", \"stage\")?.value, pipeline.stages)) {\n hints.push(\n `The pipeline \"${pipeline.name}\" has no stage called \"${name}\", so deals land in its first stage. Its stages: ${optionListing(pipeline.stages)}.`,\n );\n }\n return hints;\n}\n\nfunction attachmentHints(mapped: Mapped, catalog: ActiveCampaignCatalog): string[] {\n const hints: string[] = [];\n if (mapped(\"account\", \"url\") && !mapped(\"account\", \"name\")) {\n hints.push(\"account.url is only sent with account.name — map the company name too.\");\n }\n if (mapped(\"event\", \"data\") && !mapped(\"event\", \"name\")) hints.push(\"event.data is only sent with event.name.\");\n if (mapped(\"event\", \"name\") && !catalog.eventKeySaved) {\n hints.push(\n \"Event tracking is off on this ActiveCampaign account, so the event will be skipped: ask the user to switch event tracking on in ActiveCampaign (Settings → Tracking → Event Tracking). There is nothing to paste — Baker reads the account's event key itself once it is on. Until then only the event is skipped; the contact and the rest still arrive.\",\n );\n }\n return hints;\n}\n\nfunction unlistedCustomHints(fieldMapping: readonly AnyRecord[], catalog: ActiveCampaignCatalog): string[] {\n const listedIds = new Set(catalog.fields.flatMap((field) => (field.fieldType === \"custom\" ? [field.fieldKey] : [])));\n return fieldMapping.flatMap((entry) => {\n const key = typeof entry.fieldKey === \"string\" ? entry.fieldKey : \"\";\n if (entry.fieldType !== \"custom\" || /^\\d+$/.test(key) || listedIds.has(key)) return [];\n return [\n `custom.${key} is not on the ActiveCampaign account yet. Stage the field (\\`baker activecampaign stage field\\`) so it exists at Publish; until it does, that value is left empty on each contact.`,\n ];\n });\n}\n\n/**\n * What an ActiveCampaign mapping would fail to deliver, said while it can still\n * be fixed: a list, automation, pipeline, stage or owner the account does not\n * have (checked when the value is plain text), a deal nothing creates, an\n * account website or event details with nothing to attach to, an event with no\n * event key on the connection, and custom fields known only by a tag that is\n * not on the account yet. Warnings, not refusals: each one costs only its own\n * step — the contact still arrives.\n */\nexport function activeCampaignMappingHints(\n fieldMapping: readonly AnyRecord[],\n catalog: ActiveCampaignCatalog,\n): string[] {\n const mapped: Mapped = (type, key) =>\n fieldMapping.find((entry) => entry.fieldType === type && entry.fieldKey === key);\n return [\n ...namedOptionHints(mapped, catalog),\n ...doubleEnrollmentHints(mapped, catalog),\n ...dealHints(fieldMapping, mapped, catalog),\n ...attachmentHints(mapped, catalog),\n ...unlistedCustomHints(fieldMapping, catalog),\n ];\n}\n\nexport type MapOptions = {\n /** Which slot to map into, when the type has more than one. */\n into?: string | undefined;\n entity?: string | undefined;\n isCustomField?: boolean | undefined;\n objectType?: string | undefined;\n /**\n * The destination's own field catalog, keyed by destination field name, when\n * the caller was able to read it. Present ⇒ a per-mapping field type is\n * derived rather than demanded, and a name that is not on the destination is\n * refused with the ones that are.\n */\n destinationFields?: ReadonlyMap<string, DestinationField> | undefined;\n /**\n * A destination field `destinationFields` does not list but the destination\n * still accepts by that name, or undefined to refuse it as unknown.\n */\n unlistedField?: ((destField: string) => DestinationField | undefined) | undefined;\n /**\n * Drop the mappings whose destination field is no longer on the account.\n *\n * The repair for a deleted CRM property, and the reason it is not `--replace`:\n * HubSpot refuses the WHOLE submission when it names a field it does not\n * have, so a Form with one dead mapping delivers nothing — and the only tool\n * for removing one was `--replace`, which drops everything the call does not\n * name. Repairing seven dead mappings that way meant first reconstructing the\n * other twenty correctly, from a file the agent had to read and re-emit, or\n * silently deleting them.\n *\n * This removes exactly the entries the destination cannot accept and touches\n * nothing else, so the safe move and the small move are the same move.\n * Requires `destinationFields`: without the account's own catalog \"missing\n * from the destination\" has no answer, and the available wrong answer is\n * \"drop them all\".\n */\n pruneMissing?: boolean | undefined;\n /**\n * Write the slot exactly as given, dropping every mapping already in it.\n *\n * Off by default, because the default has to be the one that cannot lose\n * work. A mapping accumulates — read a destination, map what you can name,\n * come back for the rest — and a call that quietly replaced the slot turned\n * \"add a ninth field\" into \"delete eight\". The reverse mistake is visible\n * the moment you look: an entry you meant to remove is still listed.\n *\n * `--from` is the one place replacing is the natural reading, since a\n * mapping file states the whole mapping — so it can set `\"replace\": true`.\n */\n replace?: boolean | undefined;\n};\n\ntype Spec = { raw: string; destField: string; fieldType?: string | undefined; expression: string };\n\n/**\n * `<destField>[:<fieldType>]=<value expression>`\n *\n * The field type sits with the destination rather than the value, for two\n * reasons: it IS a destination-side property (a HubSpot `single_line_text`, a\n * Pipedrive `varchar`), and on the right it would collide with the value\n * grammar's `field:` / `tracking:` / `global:` / `code:` prefixes.\n */\nexport function parseMapSpec(raw: string): Spec {\n const eq = raw.indexOf(\"=\");\n if (eq <= 0 || eq === raw.length - 1) {\n throw new MappingError(\n `--map \"${raw}\" must be <destField>[:<fieldType>]=<value>`,\n 'Value: a form field (`nombre`), `tracking:utm_source`, `global:Name`, `code:name`, a \"literal\", or those joined with `+`.',\n );\n }\n const left = raw.slice(0, eq).trim();\n const expression = raw.slice(eq + 1).trim();\n const colon = left.indexOf(\":\");\n const destField = (colon > 0 ? left.slice(0, colon) : left).trim();\n const fieldType = colon > 0 ? left.slice(colon + 1).trim() : \"\";\n if (!destField) throw new MappingError(`--map \"${raw}\" names no destination field.`);\n return { raw, destField, fieldType: fieldType || undefined, expression };\n}\n\nfunction sheetEntry(spec: Spec, value: AnyRecord): AnyRecord {\n if (!/^[A-Z]{1,3}$/.test(spec.destField)) {\n throw new MappingError(\n `--map \"${spec.raw}\": a Google Sheet is addressed by COLUMN, so the left side must be a column letter (A, B, … AA), got \"${spec.destField}\".`,\n \"Read the real destination back from the configured side effect first — a column letter is a guess until a spreadsheet is picked.\",\n );\n }\n return { column: spec.destField, value };\n}\n\n/**\n * The destination property this mapping addresses, when the caller read the\n * destination's own catalog.\n *\n * Refusing an unknown name is the whole reason to carry the catalog at all. A\n * destination field nothing validates is the same failure as a wrong `attrs.id`\n * on the value side: structurally valid, ships, delivers nothing forever.\n */\nfunction destinationField(spec: Spec, options: MapOptions): DestinationField | undefined {\n const catalog = options.destinationFields;\n if (!catalog) return undefined;\n const match = catalog.get(spec.destField);\n if (match) return match;\n // A case-insensitive alias only reaches an entry that names the key it is\n // stored under, so the stored name is still the destination's own spelling.\n const alias = catalog.get(spec.destField.trim().toLowerCase());\n if (alias?.fieldKey) return alias;\n const unlisted = options.unlistedField?.(spec.destField);\n if (unlisted) return unlisted;\n throw new MappingError(\n `--map \"${spec.raw}\": the destination has no field called \"${spec.destField}\".`,\n `Fields on it: ${catalogListing(catalog) || \"(none)\"}`,\n );\n}\n\n/** Each destination field once, under the name it is stored by, with its label when that says more. */\nfunction catalogListing(catalog: ReadonlyMap<string, DestinationField>): string {\n const seen = new Set<DestinationField>();\n const names: string[] = [];\n for (const [name, field] of catalog) {\n if (seen.has(field)) continue;\n seen.add(field);\n const key = field.listedAs ?? field.fieldKey ?? name;\n names.push(field.label && field.label.toLowerCase() !== key.toLowerCase() ? `${key} (${field.label})` : key);\n }\n return names.join(\", \");\n}\n\n/**\n * The per-mapping field type: taken from the destination when we can read it,\n * from the spec when we were told, and refused when neither.\n *\n * Derived first, on purpose. The type is a destination-side fact, so reading it\n * off the account is both less work for the caller and MORE accurate than being\n * told — an explicit `:type` is kept as the override for a destination this\n * command cannot reach.\n */\nfunction fieldTypeFor(type: string, shape: ListShape, spec: Spec, known: DestinationField | undefined): string {\n const resolved = spec.fieldType ?? known?.fieldType;\n if (resolved && shape.fieldTypes && !shape.fieldTypes.includes(resolved)) {\n throw new MappingError(\n `--map \"${spec.raw}\": \"${resolved}\" is not a ${type} field type — expected one of: ${shape.fieldTypes.join(\", \")}.`,\n shape.fieldTypeSource,\n );\n }\n if (resolved) return resolved;\n throw new MappingError(\n `--map \"${spec.raw}\": ${type} stores a field type per mapping, and \"${spec.destField}\" has none — write it on the left: <field>:<fieldType>=<value>.`,\n shape.fieldTypeSource ?? FIELD_TYPE_FROM_INPUT,\n );\n}\n\n/**\n * The two answers a CRM shape needs beyond the field type, and will not default.\n *\n * Each decides whether the write lands or is accepted and dropped: which object\n * it lands on, and whether the key is looked up as a custom field. Both are\n * destination-side facts that come back from `request_flow_input`, so refusing\n * is the only honest response to their absence.\n *\n * The entity check is skipped for a shape that declares no `entities` —\n * `hubspotForm` addresses its object through `objectTypeId`, which rides on each\n * mapping rather than on the call.\n */\nfunction assertCrmOptions(type: string, shape: ListShape, options: MapOptions): void {\n const entities = shape.entities;\n if (entities) {\n if (!options.entity) {\n throw new MappingError(\n `${type} addresses a specific object, so --entity is required (one of: ${entities.join(\", \")}).`,\n \"Which object a value lands on is a destination-side fact — read it back from the configured side effect, do not assume.\",\n );\n }\n if (!entities.includes(options.entity)) {\n throw new MappingError(\n `--entity \"${options.entity}\" is not valid for ${type} — expected one of: ${entities.join(\", \")}.`,\n );\n }\n }\n if (shape.needsIsCustom && options.isCustomField === undefined) {\n throw new MappingError(\n `${type} looks a key up differently for custom and standard fields, so pass --custom or --standard.`,\n \"Mapping a custom field as standard (or the reverse) is accepted and then dropped. The field list from request_flow_input says which each one is.\",\n );\n }\n}\n\nfunction buildEntry(type: string, shape: ListShape, spec: Spec, value: AnyRecord, options: MapOptions): AnyRecord {\n if (shape.key === \"columnMapping\") {\n return sheetEntry(spec, value);\n }\n\n // The PayloadKey family is the plain shape: a name and a value, nothing else\n // to get wrong. Refuse the CRM flags here rather than writing a record with\n // keys the engine does not read.\n if (shape.addressedBy === \"key\") {\n if (spec.fieldType) {\n throw new MappingError(\n `--map \"${spec.raw}\": a ${type} ${shape.key} entry is just a name and a value — it takes no field type.`,\n `Write it as ${spec.destField}=${spec.expression}`,\n );\n }\n return { key: spec.destField, value };\n }\n\n const known = destinationField(spec, options);\n\n if (type === \"hubspotForm\") {\n // `objectTypeId` and `fieldType` are both HubSpot's answer, not ours. The\n // engine concatenates them into `<objectTypeId>.<fieldType>.<fieldName>`,\n // which is the key the dashboard's own picker writes — so a mapping built\n // here and one built there have to be indistinguishable, or HubSpot's\n // \"add the required fields\" list offers a field that is already mapped.\n // `0-1` (contact) is the fallback the engine itself uses for a key it\n // cannot split, so it is the one default that changes no behaviour.\n return {\n objectTypeId: options.objectType ?? known?.objectTypeId ?? \"0-1\",\n fieldType: fieldTypeFor(type, shape, spec, known),\n fieldName: spec.destField,\n value,\n };\n }\n\n // Everything left is the CRM `fieldMapping` family, and every one of those\n // records types `fieldType` as required — so it is resolved, never optional.\n assertCrmOptions(type, shape, options);\n return {\n ...(shape.entities ? { entityType: options.entity } : {}),\n fieldType: fieldTypeFor(type, shape, spec, known),\n ...(shape.needsIsCustom ? { isCustomField: options.isCustomField } : {}),\n [shape.addressedBy]: known?.fieldKey ?? spec.destField,\n value,\n };\n}\n\n/**\n * What a built mapping is, and where it goes.\n *\n * `patch` is spliced onto the side effect as-is, so a list slot yields\n * `{ payloadKeys: [...] }` and a record slot yields the whole record with the\n * mapped slots filled and the rest left `null`. Merging rather than replacing\n * matters for a record: every key is required by the engine, so writing only\n * the mapped ones would produce a side effect that no longer typechecks.\n *\n * `kept` is how many mappings were already in the slot and survive this call.\n * It exists so the response can say so out loud — a number that moves without\n * being named is the shape of every silent-loss bug this file is about.\n */\nexport type BuiltMapping = {\n key: string;\n count: number;\n kept: number;\n /** Destination names removed by `pruneMissing`, named so the caller can print each. */\n dropped: string[];\n patch: AnyRecord;\n};\n\n/**\n * Splice a list into the object that owns it, keeping that object's other keys.\n *\n * `email` is the one nested case, and the key it must not lose is `body.format`:\n * the engine reads `{ format: \"json\", fields }` as a discriminated union, so a\n * patch that replaced `body` wholesale would drop the discriminator and the\n * side effect would stop typechecking.\n */\nfunction listPatch(shape: ListShape, sideEffect: AnyRecord, entries: AnyRecord[]): AnyRecord {\n if (!shape.under) return { [shape.key]: entries };\n const owner = (sideEffect[shape.under] ?? {}) as AnyRecord;\n return { [shape.under]: { ...owner, [shape.key]: entries } };\n}\n\n/** The list already in a slot, skipping anything that is not a record to merge with. */\nfunction existingEntries(shape: ListShape, sideEffect: AnyRecord): AnyRecord[] {\n const owner = shape.under ? sideEffect[shape.under] : sideEffect;\n if (!owner || typeof owner !== \"object\") return [];\n const list = (owner as AnyRecord)[shape.key];\n if (!Array.isArray(list)) return [];\n return list.filter((entry): entry is AnyRecord => Boolean(entry) && typeof entry === \"object\");\n}\n\n/**\n * Merge new mappings into the ones already in the slot, addressed by name.\n *\n * A mapping is built up over several calls in practice — you configure the\n * destination, map the fields you can name, read the rest back, map those —\n * so replacing the slot on every call deleted the earlier ones with nothing\n * said. That is the same failure the whole command exists to prevent\n * (a mapping that is valid, ships, and delivers nothing), one level up.\n *\n * Address, not position: `shape.addressedBy` is the key that names the\n * destination (`key`, `column`, `fieldName`, `fieldKey`, `fieldId`), so\n * re-mapping the same destination overwrites it IN PLACE and a new one is\n * appended. Order therefore stays stable across calls, which matters for a\n * Google Sheet, where the column order is the row the client reads.\n *\n * An existing entry with no address at all is kept as-is: it is not something\n * this call can be addressing, and dropping it would be the silent loss again.\n *\n * `kept` counts the entries that were already there and this call did not touch,\n * so it is derived from what happened rather than from the spec count — two\n * `--map` flags naming one destination are one written mapping, not two.\n */\n/** The name an entry is merged and pruned by — see {@link ListShape.qualifiedByFieldType}. */\nfunction entryAddress(shape: ListShape, entry: AnyRecord): string | null {\n const value = entry[shape.addressedBy];\n if (typeof value !== \"string\") return null;\n return shape.qualifiedByFieldType && typeof entry.fieldType === \"string\" ? `${entry.fieldType}.${value}` : value;\n}\n\nfunction mergeEntries(\n shape: ListShape,\n existing: AnyRecord[],\n incoming: AnyRecord[],\n): { entries: AnyRecord[]; written: number; kept: number } {\n const address = (entry: AnyRecord) => entryAddress(shape, entry);\n const entries = [...existing];\n const overwritten = new Set<number>();\n for (const entry of incoming) {\n const name = address(entry);\n const at = name === null ? -1 : entries.findIndex((candidate) => address(candidate) === name);\n if (at === -1) {\n entries.push(entry);\n continue;\n }\n entries[at] = entry;\n if (at < existing.length) overwritten.add(at);\n }\n const kept = existing.length - overwritten.size;\n return { entries, written: entries.length - kept, kept };\n}\n\n/**\n * An email's mapped keys exist only in its JSON body shape.\n *\n * `{ format: \"body\", content: <AutofillDoc> }` is one written message, not named\n * keys — mapping into it would produce a `fields` array the engine never reads.\n * Refuse rather than switch the format: which of the two an email sends is the\n * agent's decision about the notification, not this command's to make.\n */\nfunction assertMappableOwner(type: string, shape: ListShape, sideEffect: AnyRecord): void {\n if (shape.under !== \"body\") return;\n const format = ((sideEffect.body ?? {}) as AnyRecord).format;\n if (format !== undefined && format !== \"json\") {\n throw new MappingError(\n `This ${type} side effect sends \\`body.format: \"${String(format)}\"\\`, which is one written message rather than named keys.`,\n 'Set `body` to `{ \"format\": \"json\", \"fields\": [] }` first if you want mapped keys, or write the message in `body.content` and map nothing.',\n );\n }\n}\n\nfunction buildList(\n tree: AnyRecord,\n type: string,\n shape: ListShape,\n sideEffect: AnyRecord,\n specs: string[],\n options: MapOptions,\n): BuiltMapping {\n assertMappableOwner(type, shape, sideEffect);\n const incoming = specs.map((raw) => {\n const spec = parseMapSpec(raw);\n return buildEntry(type, shape, spec, buildValueDoc(tree, spec.expression), options);\n });\n const present = options.replace === true ? [] : existingEntries(shape, sideEffect);\n const { kept: existing, dropped } = pruneAbsent(shape, present, options);\n const { entries, written, kept } = mergeEntries(shape, existing, incoming);\n return { key: slotName(shape), count: written, kept, dropped, patch: listPatch(shape, sideEffect, entries) };\n}\n\n/**\n * Split the mappings already in the slot into the ones the destination still\n * has and the ones it does not.\n *\n * An entry with no address at all is kept, for the same reason `mergeEntries`\n * keeps it: it is not something this call can be addressing, and dropping it\n * would be the silent loss the whole module exists to prevent.\n */\nfunction pruneAbsent(\n shape: ListShape,\n existing: AnyRecord[],\n options: MapOptions,\n): { kept: AnyRecord[]; dropped: string[] } {\n if (options.pruneMissing !== true) return { kept: existing, dropped: [] };\n\n const catalog = options.destinationFields;\n if (!catalog) {\n throw new MappingError(\n \"--prune-missing needs the destination's own field list, and it could not be read.\",\n \"Name the destination so its fields can be read — --hubspot-form <formGuid> for HubSpot (an ActiveCampaign side effect is read automatically). `baker flows show <slug>` names the side effect and returns the request_flow_input call that carries the guid.\",\n );\n }\n\n const kept: AnyRecord[] = [];\n const dropped: string[] = [];\n for (const entry of existing) {\n const name = entryAddress(shape, entry);\n if (name === null || catalog.has(name)) {\n kept.push(entry);\n continue;\n }\n dropped.push(name);\n }\n return { kept, dropped };\n}\n\nfunction buildRecord(\n tree: AnyRecord,\n type: string,\n shape: RecordShape,\n sideEffect: AnyRecord,\n specs: string[],\n options: MapOptions,\n): BuiltMapping {\n const existing = (options.replace === true ? {} : (sideEffect[shape.key] ?? {})) as AnyRecord;\n const record: AnyRecord = Object.fromEntries(shape.allowed.map((slot) => [slot, existing[slot] ?? null]));\n const filledBefore = shape.allowed.filter((slot) => record[slot] != null);\n const written = new Set<string>();\n for (const raw of specs) {\n const spec = parseMapSpec(raw);\n if (!shape.allowed.includes(spec.destField)) {\n throw new MappingError(\n `\"${spec.destField}\" is not a slot in ${shape.key} on a ${type} side effect.`,\n `${shape.key} slots: ${shape.allowed.join(\", \")}`,\n );\n }\n if (spec.fieldType) {\n throw new MappingError(`--map \"${spec.raw}\": a ${shape.key} slot takes no field type.`);\n }\n record[spec.destField] = buildValueDoc(tree, spec.expression);\n written.add(spec.destField);\n }\n return {\n key: shape.key,\n count: written.size,\n kept: filledBefore.filter((slot) => !written.has(slot)).length,\n dropped: [],\n patch: { [shape.key]: record },\n };\n}\n\nfunction buildScalar(\n tree: AnyRecord,\n type: string,\n shape: ScalarShape,\n sideEffect: AnyRecord,\n specs: string[],\n options: MapOptions,\n): BuiltMapping {\n // `--replace` means the same thing here as everywhere else: the slot ends up\n // exactly what was passed. Each key is typed `AutofillDoc | null`, so the\n // ones this call did not name are cleared rather than left standing.\n const patch: AnyRecord = options.replace === true ? Object.fromEntries(shape.keys.map((key) => [key, null])) : {};\n const written = new Set<string>();\n for (const raw of specs) {\n const spec = parseMapSpec(raw);\n if (!shape.keys.includes(spec.destField)) {\n throw new MappingError(\n `\"${spec.destField}\" is not a mappable field on a ${type} side effect.`,\n `Mappable directly: ${shape.keys.join(\", \")}`,\n );\n }\n if (spec.fieldType) {\n throw new MappingError(`--map \"${spec.raw}\": ${spec.destField} takes no field type.`);\n }\n patch[spec.destField] = buildValueDoc(tree, spec.expression);\n written.add(spec.destField);\n }\n const kept =\n options.replace === true ? 0 : shape.keys.filter((key) => !written.has(key) && sideEffect[key] != null).length;\n return { key: shape.keys.join(\"/\"), count: written.size, kept, dropped: [], patch };\n}\n\n/**\n * Build the mapping a side effect reads, from the form's own tree.\n * Throws `MappingError` for every refusal — nothing is guessed.\n */\nexport function buildFieldMapping(\n tree: AnyRecord,\n sideEffect: AnyRecord,\n specs: string[],\n options: MapOptions = {},\n): BuiltMapping {\n const type = String(sideEffect.type ?? \"\");\n const shape = shapeFor(type, options.into);\n if (shape.kind === \"record\") return buildRecord(tree, type, shape, sideEffect, specs, options);\n if (shape.kind === \"scalar\") return buildScalar(tree, type, shape, sideEffect, specs, options);\n return buildList(tree, type, shape, sideEffect, specs, options);\n}\n"],"mappings":"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","names":["owner"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/ads/google/draft.ts","../src/commands/ads/google/draft-batch.ts","../src/commands/ads/google/draft-validate.ts","../src/commands/ads/google/draft-where.ts"],"sourcesContent":["import type { GoogleDraftListResponse, GoogleDraftValidateResponse } from \"@baker/api/ads-google\";\nimport type { GoogleDraftImportResponse } from \"@baker/api/ads-google/wire\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../../client.ts\";\nimport { requireChatId } from \"../../../env.ts\";\nimport { registerSchema } from \"../../../schemas.ts\";\nimport { CHAT_READ_ARG, DRAFT_FULL_ARG } from \"../../chat-arg.ts\";\nimport { draftRefs, removeDraftRefs } from \"../../draft-refs.ts\";\nimport { writeJsonEnvelope } from \"../output.ts\";\nimport { amendBatchEntries, stageFileOps } from \"./draft-batch.ts\";\nimport { validationEnvelope } from \"./draft-validate.ts\";\nimport { parseDraftWhere, selectDraftRefs } from \"./draft-where.ts\";\nimport {\n draftAction,\n draftListAction,\n failWriteValidation,\n handleGoogleError,\n loadJsonPayloads,\n loadPatchArg,\n requireTarget,\n stageGoogleOps,\n} from \"./write-shared.ts\";\n\nconst VALIDATE_DESCRIPTION = `Ask Google whether the whole staged draft would publish — without applying anything.\n\nStart here, after the last staged change and before telling the user the draft is ready:\n baker ads google draft validate\n\nEvery staged op is built, batched and sent exactly as publish sends it, with Google's validateOnly\nflag, so each verdict is the answer publish would get: accepted | refused | blocked (a change it\ndepends on was refused) | unchecked (only publish can check it) | applied (an earlier publish did).\nCompact by default — counts, plus only the ops that need attention, each with Google's reason.\nFix refused ops with \\`draft amend <ref>\\` and validate again.\n\nExamples:\n baker ads google draft validate\n baker ads google draft validate --full # every op, with its built request and Google's raw answer`;\n\nregisterSchema({\n command: \"ads.google.draft.validate\",\n description: VALIDATE_DESCRIPTION,\n args: {\n full: {\n type: \"boolean\",\n description: \"List every op with its built request and Google's raw answer\",\n required: false,\n },\n },\n});\n\nconst STAGE_DESCRIPTION = `Stage many Google Ads changes from ONE file, in one call — any mix of kinds, up to 500 ops.\n\nStart here whenever a change touches more than a few rows (a keyword cleanup, bid changes, pausing\nads, a list of negatives): write the ops to a file and stage them together instead of running one\ncommand per row.\n baker ads google draft stage --file changes.json --customer-id 1234567890\n\nThe file is a JSON array (or JSON Lines, one op per line). Each op is what the single commands\nbuild — kind, customerId (or --customer-id for all), target for a change to something that exists,\npayload. Read the shape for a kind with \\`baker capabilities google-ads\\`.\n [\n {\"kind\":\"google.keyword.add\",\"payload\":{\"adGroup\":\"customers/1234567890/adGroups/111\",\"text\":\"solar panels\",\"matchType\":\"PHRASE\"}},\n {\"kind\":\"google.keyword.update\",\"target\":\"customers/1234567890/adGroupCriteria/111~222\",\"payload\":{\"status\":\"PAUSED\"}},\n {\"kind\":\"google.negativeKeyword.add\",\"payload\":{\"level\":\"campaign\",\"parent\":\"222333\",\"text\":\"free\",\"matchType\":\"BROAD\"}}\n ]\nAn op may name a g_temp_* ref an EARLIER call returned (a campaign or ad group staged before), but\nnot another op in the same file — a ref exists only once its op is staged, so stage new parents first.\nAll-or-nothing: one invalid op stages nothing. Ops already in effect come back as skipped.\nThen: baker ads google draft validate`;\n\nregisterSchema({\n command: \"ads.google.draft.stage\",\n description: STAGE_DESCRIPTION,\n args: {\n file: {\n type: \"string\",\n description: \"JSON array or JSON Lines of ops ({kind, customerId?, target?, payload?}), path or inline\",\n required: true,\n },\n \"customer-id\": {\n type: \"string\",\n description: \"10-digit customer id for every op that does not name its own\",\n required: false,\n },\n },\n});\n\nconst IMPORT_DESCRIPTION = `Move another open chat's staged Google Ads changes into this chat, in one call — and out of that chat, so the two can never publish the same change twice.\n\nStart here when the user wants another chat's changes brought into this one (\"bring over\", \"merge\",\n\"include what the other chat prepared\", \"all of them except …\"):\n baker ads google draft import --from-chat <chat-id>\n baker ads google draft import --from-chat <chat-id> --exclude g_temp_a,customers/123/adGroupAds/4~5\n baker ads google draft import --from-chat <chat-id> --refs g_temp_b\n\nEvery op moves exactly as it was staged — same ref, same payload, nothing retyped — so never copy\nanother chat's changes with \\`draft show --chat\\` and re-stage them. An op moves with the creates it\ndepends on and the ops that depend on it (an asset and the link that attaches it go together).\nThe other chat must still be open; its other work (Knowledge, Tasks) stays where it is. Find chat ids\nwith \\`baker chats list\\`, and refs with \\`baker ads google draft list --chat <chat-id> --json\\`.\nThen: baker ads google draft validate`;\n\nregisterSchema({\n command: \"ads.google.draft.import\",\n description: IMPORT_DESCRIPTION,\n args: {\n \"from-chat\": { type: \"string\", description: \"The other open chat whose staged changes move here\", required: true },\n refs: {\n type: \"string\",\n description: \"Comma-separated refs to move (default: all); what they depend on comes too\",\n required: false,\n },\n exclude: {\n type: \"string\",\n description: \"Comma-separated refs to leave in the other chat, with the ops that depend on them\",\n required: false,\n },\n },\n});\n\nconst LIST_DESCRIPTION =\n \"Review everything staged as a campaign ▸ ad group ▸ ad tree (--json for the raw envelope, --full for every op's payload too)\";\n\nregisterSchema({\n command: \"ads.google.draft.list\",\n description: LIST_DESCRIPTION,\n args: {\n json: { type: \"boolean\", description: \"Print the raw JSON envelope instead of the readable tree\", required: false },\n full: { type: \"boolean\", description: DRAFT_FULL_ARG.description, required: false },\n chat: { type: \"string\", description: CHAT_READ_ARG.description, required: false },\n },\n});\n\nconst WHERE_ARGS = {\n where: {\n type: \"string\",\n description:\n \"Select staged ops instead of naming refs: comma-separated key=value — kind (op kind), under (a campaign/ad group ref or resource name the op sits under), or any payload field (matchType, text, level, parent…); `|` for alternatives\",\n required: false,\n },\n \"dry-run\": { type: \"boolean\", description: \"Print the refs that would change, and change nothing\", required: false },\n} as const;\n\nconst REMOVE_DESCRIPTION = `Remove staged ops — one, many, or every op a selector matches, in one call. Each removal cascades to the ops that depend on it.\n\n baker ads google draft remove g_temp_a\n baker ads google draft remove g_temp_a g_temp_b g_temp_c # or g_temp_a,g_temp_b,g_temp_c\n baker ads google draft remove --where 'kind=google.negativeKeyword.add,text=twilio|baileys'\n baker ads google draft remove --where kind=google.keyword.add,under=g_temp_c1 --dry-run\n\nPrints one summary: every op removed (cascades listed once), and any ref the draft did not hold.`;\n\nconst REMOVE_ARGS = {\n ref: {\n type: \"positional\",\n description: \"Staged op ref(s) (g_temp_* or target) — several, space- or comma-separated\",\n required: false,\n },\n ...WHERE_ARGS,\n} as const;\n\nregisterSchema({ command: \"ads.google.draft.remove\", description: REMOVE_DESCRIPTION, args: REMOVE_ARGS });\n\nconst AMEND_DESCRIPTION = `Update staged ops in place — merges a JSON patch into each payload (RFC-7386: objects deep-merge, null deletes a key, arrays/scalars replace) and re-validates. Use this instead of remove + re-create.\n\n baker ads google draft amend g_temp_a --patch '{\"cpcBidMicros\":1500000}'\n baker ads google draft amend g_temp_a g_temp_b --patch '{\"status\":\"ENABLED\"}' # same patch, many refs\n baker ads google draft amend --where kind=google.keyword.add,under=g_temp_c1,matchType=EXACT --patch '{\"matchType\":\"BROAD\"}'\n baker ads google draft amend --file amends.json # [{\"ref\":\"g_temp_…\",\"patch\":{…}}, …] — a patch per ref\n\nMany refs are amended in one call, all or none: one refused amend changes nothing.`;\n\nconst AMEND_ARGS = {\n ref: {\n type: \"positional\",\n description:\n \"Staged op ref(s) (g_temp_*) or target id/resource name — several, space- or comma-separated, take the same patch; leave out to amend many from --file\",\n required: false,\n },\n file: {\n type: \"string\",\n description: 'JSON file with the patch object — or, with no ref, a JSON array of {\"ref\",\"patch\"} amends',\n required: false,\n },\n patch: { type: \"string\", description: \"Inline JSON patch object\", required: false },\n ...WHERE_ARGS,\n} as const;\n\nregisterSchema({ command: \"ads.google.draft.amend\", description: AMEND_DESCRIPTION, args: AMEND_ARGS });\n\n/**\n * The refs `--where` selects from the staged draft, or undefined without it. Exits with the reason\n * when it cannot select: a malformed selector, refs passed too, or nothing staged that matches.\n */\nasync function refsWhere(args: Record<string, unknown>): Promise<string[] | undefined> {\n if (typeof args.where !== \"string\") return undefined;\n const where = parseDraftWhere(args.where);\n if (\"error\" in where) failWriteValidation(where.error);\n if (draftRefs(args._).length > 0) failWriteValidation(\"pass refs or --where, not both\");\n let ops: GoogleDraftListResponse[\"ops\"] = [];\n try {\n const response = await apiPost<{ ok: boolean; data?: GoogleDraftListResponse }>(\"/api/ads/google/draft\", {\n chatId: requireChatId(),\n full: true,\n });\n ops = response.data?.ops ?? [];\n } catch (err) {\n handleGoogleError(err);\n }\n const refs = selectDraftRefs(ops, where);\n if (refs.length === 0) {\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"NOT_FOUND\",\n message: `--where ${args.where} matches no staged op`,\n fix: \"Read the staged ops' kinds and payload fields with `baker ads google draft list --full`, then adjust the selector.\",\n },\n });\n process.exit(1);\n }\n return refs;\n}\n\n/** `--dry-run`: the refs the command would change, printed instead of changing them. */\nfunction printDryRun(refs: string[]): void {\n writeJsonEnvelope({\n ok: true,\n data: { matched: refs.length, refs },\n hints: [\"Nothing changed. Run it again without --dry-run to apply it.\"],\n });\n}\n\n/** The refs a comma-separated flag names: undefined when the flag is absent, null when it names none. */\nfunction refList(value: unknown): string[] | undefined | null {\n if (typeof value !== \"string\") return undefined;\n const refs = value\n .split(\",\")\n .map((ref) => ref.trim())\n .filter((ref) => ref.length > 0);\n return refs.length > 0 ? refs : null;\n}\n\n/** What the agent needs after a move: the next step, and what the other chat now holds. */\nexport function importHints(fromChatId: string, data: GoogleDraftImportResponse): string[] {\n const source =\n data.sourceRemaining > 0\n ? `Chat ${fromChatId} still has ${data.sourceRemaining} Google Ads change(s) staged, which publish with that chat.`\n : `Chat ${fromChatId} has no Google Ads changes staged any more, so publishing it cannot apply these twice. Its other work stays there — never tell the user to discard it for this.`;\n return [source, \"Run `baker ads google draft validate` next.\"];\n}\n\n/** After a bulk stage: what to do next, and the reminder that the file — not a loop — is the tool. */\nexport const BULK_STAGE_HINTS = [\n \"Run `baker ads google draft validate` next: it asks Google about every staged op at once and lists only the ones it would refuse.\",\n 'To fix several staged ops, amend them together: `baker ads google draft amend --file amends.json` with [{\"ref\":\"…\",\"patch\":{…}}, …].',\n];\n\n/** Review and undo staged Google Ads ops on this chat's draft; `list`/`show` can also read another chat's. */\nexport const draftCommand = defineCommand({\n meta: {\n name: \"draft\",\n description:\n \"Stage many ops from one file, or list, validate, remove, clear, amend, or show staged Google Ads write ops for this chat. `list` and `show` take --chat <id> to read an earlier chat's changes instead; `import --from-chat <id>` moves another open chat's staged changes here.\",\n },\n subCommands: {\n stage: defineCommand({\n meta: { name: \"stage\", description: STAGE_DESCRIPTION },\n args: {\n file: {\n type: \"string\",\n description: \"JSON array or JSON Lines of ops ({kind, customerId?, target?, payload?}), path or inline\",\n },\n \"customer-id\": { type: \"string\", description: \"10-digit customer id for every op that does not name its own\" },\n },\n run: async ({ args }) => {\n const customerId = typeof args[\"customer-id\"] === \"string\" ? args[\"customer-id\"] : undefined;\n await stageGoogleOps(stageFileOps(loadJsonPayloads(args.file), customerId), BULK_STAGE_HINTS);\n },\n }),\n import: defineCommand({\n meta: { name: \"import\", description: IMPORT_DESCRIPTION },\n args: {\n \"from-chat\": { type: \"string\", description: \"The other open chat whose staged changes move here\" },\n refs: { type: \"string\", description: \"Comma-separated refs to move (default: all)\" },\n exclude: { type: \"string\", description: \"Comma-separated refs to leave in the other chat\" },\n },\n run: async ({ args }) => {\n const fromChatId = typeof args[\"from-chat\"] === \"string\" ? args[\"from-chat\"].trim() : \"\";\n if (!fromChatId) {\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: \"--from-chat is required\",\n fix: \"Name the other chat: baker ads google draft import --from-chat <chat-id> (ids from `baker chats list`).\",\n },\n });\n process.exit(1);\n }\n const refs = refList(args.refs);\n const exclude = refList(args.exclude);\n const empty = refs === null ? \"--refs\" : exclude === null ? \"--exclude\" : undefined;\n if (empty) {\n // An empty selection must never widen to \"every change\": the move takes them out of the other chat.\n writeJsonEnvelope({\n ok: false,\n error: {\n code: \"VALIDATION_ERROR\",\n message: `${empty} names no change`,\n fix: `Pass the refs, comma-separated (from \\`baker ads google draft list --chat ${fromChatId} --json\\`), or leave ${empty} off to move every change.`,\n },\n });\n process.exit(1);\n }\n try {\n const response = await apiPost<{ ok: boolean; data?: GoogleDraftImportResponse }>(\n \"/api/ads/google/draft/import\",\n { chatId: requireChatId(), fromChatId, refs: refs ?? undefined, exclude: exclude ?? undefined },\n );\n writeJsonEnvelope(\n response.ok && response.data ? { ...response, hints: importHints(fromChatId, response.data) } : response,\n );\n } catch (err) {\n handleGoogleError(err);\n }\n },\n }),\n list: defineCommand({\n meta: {\n name: \"list\",\n description: LIST_DESCRIPTION,\n },\n args: {\n json: { type: \"boolean\", description: \"Print the raw JSON envelope instead of the readable tree\" },\n full: DRAFT_FULL_ARG,\n chat: CHAT_READ_ARG,\n },\n run: async ({ args }) => {\n await draftListAction(args.json === true, args.chat, args.full === true);\n },\n }),\n remove: defineCommand({\n meta: { name: \"remove\", description: REMOVE_DESCRIPTION },\n args: REMOVE_ARGS,\n run: async ({ args }) => {\n const selected = await refsWhere(args);\n const refs = selected ?? draftRefs(args._);\n if (args[\"dry-run\"] === true) {\n printDryRun(refs);\n return;\n }\n if (selected || refs.length > 1) {\n await removeDraftRefs(\"/api/ads/google/draft/remove\", refs);\n return;\n }\n await draftAction(\"/api/ads/google/draft/remove\", { ref: requireTarget(args, \"op\") });\n },\n }),\n clear: defineCommand({\n meta: { name: \"clear\", description: \"Discard all staged ops on this chat\" },\n run: async () => {\n await draftAction(\"/api/ads/google/draft/clear\", {});\n },\n }),\n amend: defineCommand({\n meta: { name: \"amend\", description: AMEND_DESCRIPTION },\n args: AMEND_ARGS,\n run: async ({ args }) => {\n const selected = await refsWhere(args);\n const positional = Array.isArray(args._) ? args._[0] : undefined;\n if (!selected && !(args.ref ?? positional) && typeof args.file === \"string\" && args.file.length > 0) {\n const amends = amendBatchEntries(loadJsonPayloads(args.file));\n if (args[\"dry-run\"] === true) {\n printDryRun(amends.map((amend) => amend.ref));\n return;\n }\n await draftAction(\"/api/ads/google/draft/amend-batch\", { amends });\n return;\n }\n const refs = selected ?? draftRefs(args._);\n if (args[\"dry-run\"] === true) {\n printDryRun(refs);\n return;\n }\n if (selected || refs.length > 1) {\n const patch = loadPatchArg(args);\n await draftAction(\"/api/ads/google/draft/amend-batch\", { amends: refs.map((ref) => ({ ref, patch })) });\n return;\n }\n const ref = requireTarget(args, \"op\");\n const patch = loadPatchArg(args);\n await draftAction(\"/api/ads/google/draft/amend\", { ref, patch });\n },\n }),\n validate: defineCommand({\n meta: { name: \"validate\", description: VALIDATE_DESCRIPTION },\n args: {\n full: { type: \"boolean\", description: \"List every op with its built request and Google's raw answer\" },\n },\n run: async ({ args }) => {\n try {\n const full = args.full === true;\n const response = await apiPost<{ ok: boolean; data?: GoogleDraftValidateResponse }>(\n \"/api/ads/google/draft/validate\",\n { chatId: requireChatId(), full },\n );\n writeJsonEnvelope(response.ok && response.data ? validationEnvelope(response.data, full) : response);\n } catch (err) {\n handleGoogleError(err);\n }\n },\n }),\n show: defineCommand({\n meta: {\n name: \"show\",\n description:\n \"Print the full staged payload for one op — the receipt to verify a change looks right before publish (never truncated).\",\n },\n args: {\n ref: {\n type: \"positional\",\n description: \"Staged op ref (g_temp_*) or target id/resource name\",\n required: false,\n },\n chat: CHAT_READ_ARG,\n },\n run: async ({ args }) => {\n await draftAction(\"/api/ads/google/draft/show\", { ref: requireTarget(args, \"op\") }, args.chat);\n },\n }),\n },\n});\n","import { GOOGLE_DRAFT_BATCH_MAX } from \"@baker/api/ads-google\";\nimport { failWriteValidation } from \"./write-shared.ts\";\n\n/**\n * The bulk halves of `draft`: one file of many changes, staged or amended in ONE request. A bulk\n * change done as a loop of single commands is one request, one rate-limit hit and one tool call per\n * row — production saw 1,284 such calls — while a file is one of each for up to 500 rows.\n */\n\nfunction refuseOversized(count: number, what: string): void {\n if (count > GOOGLE_DRAFT_BATCH_MAX) {\n failWriteValidation(\n `${count} ${what} exceeds the batch limit of ${GOOGLE_DRAFT_BATCH_MAX} — split the file and run the command once per part`,\n );\n }\n}\n\n/**\n * `draft stage --file` items → ops: each item is a whole op (`kind`, `customerId`, `target` for a\n * change to something that exists, `payload`); `--customer-id` fills the account on items that leave\n * it out, so a one-account file need not repeat it. The ops are preflighted by `stageGoogleOps`.\n */\nexport function stageFileOps(\n items: ReadonlyArray<Record<string, unknown>>,\n customerId: string | undefined,\n): Array<Record<string, unknown>> {\n if (items.length === 0) {\n failWriteValidation(\n 'pass --file with the ops to stage: a JSON array (or JSON Lines) of {\"kind\",\"customerId\",\"target\"?,\"payload\"?}',\n );\n }\n refuseOversized(items.length, \"ops\");\n return items.map((item, index) => {\n if (typeof item.kind !== \"string\") {\n failWriteValidation(\n `item ${index} has no \"kind\" — every item is a whole op, e.g. {\"kind\":\"google.keyword.add\",…}`,\n );\n }\n return item.customerId === undefined && customerId ? { ...item, customerId } : item;\n });\n}\n\n/** `draft amend --file` items → the amend batch: each `{ ref, patch }` exactly as `draft amend <ref>` takes it. */\nexport function amendBatchEntries(\n items: ReadonlyArray<Record<string, unknown>>,\n): Array<{ ref: string; patch: Record<string, unknown> }> {\n refuseOversized(items.length, \"amends\");\n return items.map((item, index) => {\n const { ref, patch } = item;\n if (typeof ref !== \"string\" || ref.length === 0) {\n failWriteValidation(`item ${index} has no \"ref\" — name the staged op (g_temp_* or its target) to amend`);\n }\n if (patch === null || typeof patch !== \"object\" || Array.isArray(patch)) {\n failWriteValidation(`item ${index} has no \"patch\" object — {\"ref\":\"…\",\"patch\":{…fields to change…}}`);\n }\n return { ref, patch: patch as Record<string, unknown> };\n });\n}\n","import type { GoogleDraftOpVerdict, GoogleDraftValidateResponse } from \"@baker/api/ads-google\";\n\n/** Verdicts that need nothing from the agent — counted, never listed in the compact view. */\nconst QUIET: ReadonlySet<GoogleDraftOpVerdict[\"verdict\"]> = new Set([\"accepted\", \"applied\"]);\n\nfunction changes(n: number): string {\n return n === 1 ? \"1 change\" : `${n} changes`;\n}\n\n/** What to do next, read off the counts — the agent decides from these without re-reading every op. */\nfunction validationHints(data: GoogleDraftValidateResponse): string[] {\n const { refused, blocked, unchecked } = data.counts;\n const hints: string[] = [];\n if (refused > 0) {\n hints.push(\n `${changes(refused)} would fail at publish. Fix each refused op in place with \\`draft amend <ref>\\` (or \\`draft remove <ref>\\` if it should not exist), then run \\`draft validate\\` again before asking the user to publish. Never tell the user a refused change will go live.`,\n );\n }\n if (blocked > 0) {\n hints.push(\n `${changes(blocked)} would not apply only because a refused change they depend on fails — fixing the refused one clears them.`,\n );\n }\n if (data.publishHeld) {\n hints.push(\n \"Baker would hold this whole publish: a refused change stops a first publish from sending anything. Fix it first.\",\n );\n }\n if (unchecked > 0) {\n hints.push(\n `${changes(unchecked)} can only be checked by Google at publish (the reason is on each one). Nothing here says they will fail.`,\n );\n }\n if (refused + blocked === 0 && !data.publishHeld && data.ops.length > 0) {\n hints.push(\n \"Google accepted every change it was asked about. The draft is ready for the user to review and publish.\",\n );\n }\n return hints;\n}\n\n/**\n * The `draft validate` envelope. Compact by default: counts for everything, and only the ops that\n * need attention listed — a 300-keyword draft that Google accepts reads as one line, not 300.\n * `full` keeps every op with its built request and Google's raw answer.\n */\nexport function validationEnvelope(\n data: GoogleDraftValidateResponse,\n full = false,\n): { ok: true; data: GoogleDraftValidateResponse; hints: string[] } {\n const ops = full ? data.ops : data.ops.filter((op) => !QUIET.has(op.verdict));\n return { ok: true, data: { ...data, ops }, hints: validationHints(data) };\n}\n","import type { GoogleDraftListResponse } from \"@baker/api/ads-google\";\n\n/**\n * `draft remove|amend --where kind=…,under=…,<payload field>=…` — pick staged ops by what they are\n * instead of by ref, so a cleanup over a whole campaign (\"every EXACT keyword under it → BROAD\") is\n * one command, not a draft dump, a script and a call per op.\n */\n\ntype DraftOp = GoogleDraftListResponse[\"ops\"][number];\n\nexport interface DraftWhere {\n /** Op kinds, `google.` prefix optional. */\n kinds: string[];\n /** Refs or resource names the op sits under: through its staged parents, or named in its payload. */\n under: string[];\n /** Top-level payload fields and the values (any of, case-insensitive) they must hold. */\n fields: Record<string, string[]>;\n}\n\n/** Parse the selector, or say what is wrong with it. `|` separates alternatives: `matchType=EXACT|PHRASE`. */\nexport function parseDraftWhere(value: string): DraftWhere | { error: string } {\n const where: DraftWhere = { kinds: [], under: [], fields: {} };\n const pairs = value\n .split(\",\")\n .map((pair) => pair.trim())\n .filter(Boolean);\n if (pairs.length === 0) return { error: \"--where names no condition\" };\n for (const pair of pairs) {\n const eq = pair.indexOf(\"=\");\n const key = pair.slice(0, eq).trim();\n const values = pair\n .slice(eq + 1)\n .split(\"|\")\n .map((v) => v.trim())\n .filter(Boolean);\n if (eq <= 0 || values.length === 0) return { error: `--where condition \"${pair}\" is not key=value` };\n if (key === \"kind\") where.kinds.push(...values.map((k) => (k.startsWith(\"google.\") ? k : `google.${k}`)));\n else if (key === \"under\") where.under.push(...values);\n else where.fields[key] = [...(where.fields[key] ?? []), ...values];\n }\n return where;\n}\n\nfunction payloadOf(op: DraftOp): Record<string, unknown> {\n return typeof op.payload === \"object\" && op.payload !== null ? (op.payload as Record<string, unknown>) : {};\n}\n\n/** Everything an op sits under: its staged parents up the chain, and the ids its payload names. */\nfunction parentsOf(op: DraftOp, byRef: Map<string, DraftOp>): Set<string> {\n const seen = new Set<string>();\n const queue = [op];\n for (let current = queue.shift(); current; current = queue.shift()) {\n const named = Object.values(payloadOf(current)).filter((v): v is string => typeof v === \"string\");\n for (const parent of [...current.dependsOn, ...named]) {\n if (seen.has(parent)) continue;\n seen.add(parent);\n const staged = byRef.get(parent);\n if (staged) queue.push(staged);\n }\n }\n return seen;\n}\n\n/** The refs of the staged ops the selector matches, in staging order. */\nexport function selectDraftRefs(ops: readonly DraftOp[], where: DraftWhere): string[] {\n const byRef = new Map(ops.map((op) => [op.ref, op]));\n return ops\n .filter((op) => {\n if (where.kinds.length > 0 && !where.kinds.includes(op.kind)) return false;\n if (where.under.length > 0) {\n const parents = parentsOf(op, byRef);\n if (!where.under.some((ref) => parents.has(ref))) return false;\n }\n const payload = payloadOf(op);\n return Object.entries(where.fields).every(([key, values]) => {\n const actual = payload[key];\n if (typeof actual !== \"string\" && typeof actual !== \"number\" && typeof actual !== \"boolean\") return false;\n return values.some((v) => v.toLowerCase() === String(actual).toLowerCase());\n });\n })\n .map((op) => op.ref);\n}\n"],"mappings":"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","names":["patch","ref"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/flows/index.ts"],"sourcesContent":["import {\n driftRepairHint,\n FLOW_AGENT_DESTINATION_KINDS,\n type FlowConfigStatus,\n type FlowDrift,\n type FlowSummary,\n type FlowsDriftResponse,\n type FlowsShowResponse,\n flowNodeTriggers,\n} from \"@baker/api\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport {\n collectConfigStatus,\n collectSideEffects,\n listFlowSlugs,\n readFlowTree,\n readSettings,\n redactTree,\n requestFlowInputCall,\n withSettings,\n} from \"./shared.ts\";\n\nregisterSchema({\n command: \"flows.list\",\n description:\n \"List the Forms (flows) in this workspace and how many confidential fields each still needs configured. Read-only.\",\n args: {},\n});\n\nregisterSchema({\n command: \"flows.show\",\n description:\n \"Show a Form's confidential fields and whether each is configured (secrets/connections/third-party resources), AND whether its destination has changed under it — never reveals secret values. Destination drift is the one problem a Form cannot show you itself: when a HubSpot field a Form maps is deleted, HubSpot refuses the WHOLE submission and the visitor still sees the thank-you screen, so every lead is lost silently. Run this before changing any Form. Each sealed destination says where it sends (recipients, subject, sheet) — never a credential. Author structure by editing the flow's _data.json; set destinations yourself with `baker flows connect` (email: --email/--subject); only a typed secret goes to the request_flow_input tool.\",\n args: {\n slug: { type: \"positional\", description: \"Form slug (folder under flows/)\", required: true },\n full: { type: \"boolean\", description: \"Include the full flow tree (secret values redacted)\", required: false },\n },\n});\n\nfunction statusFor(slug: string): FlowConfigStatus[] {\n const tree = readFlowTree(slug);\n const config: FlowConfigStatus[] = [];\n collectConfigStatus(tree, config);\n return config;\n}\n\n/**\n * The calls that close out everything this form is still waiting on.\n *\n * `show` is the command an agent runs to answer \"is this form wired up?\", and\n * it answered with `needsInput: true` and nothing else — leaving the agent to\n * work out that a tool exists, which tool, and how to address the exact node or\n * side effect. The whole point of asking is to find out what to do next, so the\n * answer is the call itself.\n */\nfunction pendingInputHints(slug: string, config: FlowConfigStatus[]): string[] {\n const pending = config.filter((row) => row.needsInput);\n if (pending.length === 0) return [];\n const calls = pending.slice(0, MAX_PENDING_HINTS).map((row) => `${row.kind}: ${requestFlowInputCall(slug, row)}`);\n const rest = pending.length - calls.length;\n return [\n ...repeatedKindHints(slug, pending),\n `${pending.length} item${pending.length === 1 ? \"\" : \"s\"} still unwired. Wire each yourself with the command below when you know which resource is meant; the card is the fallback, and its result carries the destination — read the names from there rather than looking them up again.`,\n ...calls,\n ...(rest > 0 ? [`…and ${rest} more — see \\`config\\` above.`] : []),\n ];\n}\n\n/**\n * Several unwired items of one kind usually share one destination — chat\n * r57ed43j had 24 HubSpot side effects all sending to the same form — so\n * name the call that fills them all at once.\n */\nfunction repeatedKindHints(slug: string, pending: FlowConfigStatus[]): string[] {\n const counts = new Map<string, number>();\n for (const row of pending) counts.set(row.kind, (counts.get(row.kind) ?? 0) + 1);\n return [...counts].flatMap(([kind, count]) => {\n if (count < 2) return [];\n if (kind === \"hubspotForm\") {\n return [\n `${count} hubspotForm side effects are unwired. When they all send to the same HubSpot form: baker flows connect ${slug} --all --hubspot-form <formId>.`,\n ];\n }\n if (!(FLOW_AGENT_DESTINATION_KINDS as readonly string[]).includes(kind)) return [];\n return [\n `${count} ${kind} items are unwired. When they share one destination: baker flows connect ${slug} --all --type ${kind} [--resource <id>].`,\n ];\n });\n}\n\n/** Enough for any real form; the cap only stops a pathological tree flooding the response. */\nconst MAX_PENDING_HINTS = 6;\n\n/**\n * Side effects wired to a moment their own step never raises.\n *\n * `fireSideEffects` filters on `triggerId` equality, so one that does not match\n * is inert: written, valid, green on every check in the repo, and it never\n * runs. Nothing else in the toolchain looks at the pair — `validate-flow.mjs`\n * only checks the key is present and `validate-flow-schema.mjs` does not read\n * it at all — so a form can report \"fully configured\" while a side effect on it\n * has never fired once. This is the one command that is asked whether a form is\n * wired up, so it is the one that has to say.\n *\n * Silent about a node type the trigger table does not cover: no opinion is the\n * honest answer there, and a false \"this never fires\" on a working form would\n * cost more than the warning is worth.\n */\nexport function inertSideEffectHints(tree: Record<string, unknown>): string[] {\n const dead = collectSideEffects(tree).flatMap(({ node, sideEffect }) => {\n const triggers = flowNodeTriggers(node.nodeData);\n if (!triggers.known) return [];\n const triggerId = String(sideEffect.triggerId ?? \"\");\n if (triggers.available.includes(triggerId)) return [];\n const where = `${String(sideEffect.id ?? sideEffect.type)} on \"${String(node.name ?? node.id)}\"`;\n const raises =\n triggers.available.length > 0\n ? `It raises: ${triggers.available.join(\", \")}.`\n : (triggers.why ?? \"That step raises nothing.\");\n return [`${where} fires on \\`${triggerId || \"(none)\"}\\`, which that step never raises. ${raises}`];\n });\n\n if (dead.length === 0) return [];\n return [\n `${dead.length} side effect${dead.length === 1 ? \" has\" : \"s have\"} a triggerId their step never raises, so ${dead.length === 1 ? \"it never runs\" : \"they never run\"} — no error, nothing half-written, just nothing. A triggerId belongs to the STEP, not to the side-effect type.`,\n ...dead.slice(0, MAX_PENDING_HINTS),\n ...(dead.length > MAX_PENDING_HINTS ? [`…and ${dead.length - MAX_PENDING_HINTS} more.`] : []),\n \"Fix each by setting the id its own step raises: `baker flows schema node <nodeType>` lists them.\",\n ];\n}\n\n/**\n * Where the company funnel stands on this Form.\n *\n * A Form moves nobody along the company funnel until a step names one of its\n * endings, and nothing places it for the agent — so a Form that is configured,\n * fires every pixel and counts its conversions can still leave \"Became a lead\"\n * at zero. `show` reads only the local file and cannot tell whether a step\n * names it; `baker funnel` can, so the hint names that read and the write.\n */\nexport function funnelPlacementHint(slug: string): string {\n return `Whether this Form moves anyone along the company funnel is not in _data.json either: \\`baker funnel\\` names every Form no step counts. If it names this one, place its ending on the step it moves people to — \\`submit:${slug}\\`, or its booking trigger, both listed by \\`baker funnel --moments\\` — with \\`baker funnel --step\\`, which replaces the step it names, so keep that step's other ways in.`;\n}\n\n/**\n * What this Form's destination has changed under it, asked of Baker.\n *\n * A read the Company Workspace cannot do for itself twice over: the findings\n * live on the `flows` row, and the HubSpot form id a repair needs is inside an\n * encrypted config. Before this, detection had no reader in the Runtime at all\n * — 47 live findings across 11 Forms, and an agent editing one of those Forms\n * could not see a single one.\n *\n * A failure returns null rather than `[]`. They are different answers and\n * collapsing them would report a Form healthy on the strength of a network\n * error, which is exactly the silence the drift check exists to break.\n */\nasync function readDrift(slug: string): Promise<FlowsDriftResponse | null> {\n try {\n const response = await apiPost<{ ok: true; data: FlowsDriftResponse }>(\"/api/flows/drift\", { slug });\n return response.data;\n } catch {\n return null;\n }\n}\n\n/**\n * Drift said to an agent: what is wrong, and the command that fixes it.\n *\n * The summary comes from `@baker/api`, which the dashboard badge reads too, so\n * this and the badge cannot come apart about whether a Form is healthy. What is\n * added here is the half that is the CLI's: the repair, spelled as a command\n * line, because an agent that has to go and work out `--prune-missing` for\n * itself will instead reach for `--replace` and delete the mappings that still\n * work.\n */\nexport function driftHints(slug: string, drift: FlowsDriftResponse | null): string[] {\n if (drift === null) {\n return [\n \"Could not check whether this Form's destination has changed under it. Treat that as UNKNOWN, not as healthy — a deleted HubSpot field refuses every submission while the visitor still sees the thank-you screen.\",\n ];\n }\n\n const forms = drift.forms.filter((form) => form.slug === slug);\n if (forms.length === 0) {\n return drift.checkedAt === null\n ? [\n \"This Form's destination has never been checked, so nothing here says it is healthy — only that nothing was compared.\",\n ]\n : [];\n }\n\n return forms.flatMap((form: FlowDrift) => {\n const repair = driftRepairHint(slug, form.formGuid, form.deadFields, form.sideEffectId);\n return [`DESTINATION DRIFT (${form.severity}): ${form.summary}`, ...(repair === null ? [] : [repair])];\n });\n}\n\nfunction displayName(slug: string): string {\n const tree = readFlowTree(slug);\n const name = tree.displayName;\n return typeof name === \"string\" && name.trim() ? name.trim() : slug;\n}\n\nconst listCommand = defineCommand({\n meta: {\n name: \"list\",\n description:\n \"List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list\",\n },\n run: () => {\n const flows: FlowSummary[] = listFlowSlugs().map((slug) => ({\n slug,\n name: displayName(slug),\n needsConfig: statusFor(slug).filter((c) => c.needsInput).length,\n }));\n const pending = flows.filter((flow) => flow.needsConfig > 0);\n writeJson({\n ok: true,\n data: { flows },\n hints: [\n ...(pending.length > 0\n ? [\n `Still unwired: ${pending.map((flow) => `${flow.slug} (${flow.needsConfig})`).join(\", \")}. \\`baker flows show <slug>\\` returns the command that wires each — most you run yourself.`,\n ]\n : []),\n // \"Set the conversions on the Forms\" lands here first, and nothing in\n // this family can do it — the conversion side effects it does offer\n // fire a pixel and are not what any Baker report counts.\n \"Setting what a Form COUNTS is not in this family: a conversion is a named event held in Baker. `baker analytics conversions` lists what this company counts; `--flow <slug>` spells one Form's endings as keys you can count, traffic or no traffic.\",\n ],\n });\n },\n});\n\nconst showCommand = defineCommand({\n meta: {\n name: \"show\",\n description:\n \"Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact\",\n },\n args: {\n slug: { type: \"positional\", description: \"Form slug\", required: true },\n full: { type: \"boolean\", description: \"Include the full flow tree (secret values redacted)\" },\n },\n run: async ({ args }) => {\n const slug = String(args.slug);\n const tree = readFlowTree(slug);\n const [drift, settings] = await Promise.all([readDrift(slug), readSettings(tree)]);\n const config = withSettings(statusFor(slug), settings ?? {});\n const response: FlowsShowResponse = {\n slug,\n name: displayName(slug),\n config,\n drift: drift === null ? null : drift.forms.filter((form) => form.slug === slug),\n ...(drift === null ? {} : { driftCheckedAt: drift.checkedAt }),\n ...(args.full === true ? { tree: redactTree(tree) } : {}),\n };\n writeJson({\n ok: true,\n data: response,\n // Drift first, above everything. The other hints are about work still to\n // do; this one is about leads already being lost, and it is the only\n // thing here that is true of a Form that looks completely finished.\n hints: [\n ...driftHints(slug, drift),\n ...inertSideEffectHints(tree),\n ...pendingInputHints(slug, config),\n // The question this command is asked — \"is this Form wired up?\" — has\n // an answer that is not in this file at all. What a Form counts is a\n // named event in Baker, and a Form can be perfectly configured, fire\n // every pixel it has, and still report converting nobody.\n `What this Form counts as a conversion is NOT in _data.json and not in any side effect here: it is a named event held in Baker. Read it, and this Form's own endings spelled as event keys, with \\`baker analytics conversions --flow ${slug}\\`.`,\n funnelPlacementHint(slug),\n ],\n });\n },\n});\n\nexport const flowsCommand = defineCommand({\n meta: {\n name: \"flows\",\n description: `Read and shape this workspace's Forms (flows).\n\nReads never reveal a secret value. Writes touch only the form's own _data.json — they stage structure, never a live system.\n\nWire every destination yourself — no card for the user: an email (\\`connect --email \"a@x.com, b@x.com\" --subject \"New lead — Contact\"\\`; write the subject yourself), a webhook without a token (\\`--url\\`), and any connected platform once you know which resource is meant (\\`baker flows options <kind>\\` lists it; Calendly, SavvyCal, GoHighLevel steps; Google Sheets, Pipedrive, GoHighLevel, ActiveCampaign and HubSpot destinations; \\`--same-as\\` copies another Form's). A HubSpot step takes \\`baker hubspot forms view <id> --as-node\\`. \\`show\\` reads back where each destination sends; a credential is never shown.\n\nThe request_flow_input tool (baker_ui MCP server) is only for what the user alone holds: a typed secret (a webhook token, Zapier, Crmble), a platform nobody connected, or several resources that could equally be meant.\n\nExamples:\n baker flows list # every Form + how many fields still need setup\n baker flows show contact # one Form's confidential fields and their status\n baker flows schema node customForm # the shape of a step, before you author one\n baker flows add-node contact --type text --name \"Thanks\"\n baker flows add-side-effect contact --node <id> --type googleSpreadsheet\n baker flows options calendly # what the connected account holds\n baker flows connect contact --node book --resource <id>\n baker flows connect contact --side-effect se-email-1 --email \"ana@x.com, luis@x.com\" --subject \"New lead — Contact\"\n baker flows connect contact --side-effect se-hubspotForm-1 --hubspot-form <formId> # --all: every unwired one\n baker flows map contact --map A=name --map B=email --write\nFull guide: __tooling__/docs/tools/baker/flows.md`,\n },\n subCommands: {\n list: listCommand,\n show: showCommand,\n schema: () => import(\"./schema.ts\").then((m) => m.schemaCommand),\n \"add-node\": () => import(\"./add.ts\").then((m) => m.addNodeCommand),\n \"add-side-effect\": () => import(\"./add.ts\").then((m) => m.addSideEffectCommand),\n options: () => import(\"./options.ts\").then((m) => m.optionsCommand),\n connect: () => import(\"./connect.ts\").then((m) => m.connectCommand),\n map: () => import(\"./map.ts\").then((m) => m.mapCommand),\n normalize: () => import(\"./normalize.ts\").then((m) => m.normalizeCommand),\n },\n // Bare `baker flows` lists the Forms. This must be `default`, not `run`: citty falls\n // through to `run` after dispatching a subcommand, so a `run` here would also print\n // the list on every `baker flows show <slug>`.\n default: \"list\",\n});\n"],"mappings":"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","names":[]}
|
package/dist/map-6FIEOF2C.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/flows/map.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport type { HubspotFormsViewResponse } from \"@baker/api\";\nimport {\n type ActiveCampaignCatalog,\n type ActiveCampaignFieldsRequest,\n type ActiveCampaignFieldsResponse,\n activeCampaignFieldsResponseSchema,\n} from \"@baker/api/activecampaign\";\nimport { defineCommand } from \"citty\";\nimport { apiPost } from \"../../client.ts\";\nimport { repeatedFlagValues } from \"../../lib/repeatedFlags.ts\";\nimport { writeJson } from \"../../output.ts\";\nimport { registerSchema } from \"../../schemas.ts\";\nimport {\n activeCampaignDestinationFields,\n activeCampaignMappingHints,\n activeCampaignUnlistedField,\n type BuiltMapping,\n buildFieldMapping,\n type DestinationField,\n describeSlots,\n type MapOptions,\n MappingError,\n namesComeFromAccount,\n otherSlots,\n shapeFor,\n} from \"./mapping.ts\";\nimport {\n collectConfigStatus,\n collectSideEffects,\n flowDataPath,\n readFlowTree,\n requestFlowInputCall,\n sideEffectNeedsInput,\n writeFlowTree,\n} from \"./shared.ts\";\n\nregisterSchema({\n command: \"flows.map\",\n description:\n \"Map form fields onto any named value a side effect sends: a CRM fieldMapping, a sheet columnMapping, a webhook payloadKeys, a pixel eventParams, or a platform matching block. Emits the mapping and splices it in with --write. Configure the destination through request_flow_input FIRST — the destination-side names come from the connected account, not from you.\",\n args: {\n slug: { type: \"positional\", description: \"Form slug (folder under flows/)\", required: true },\n map: {\n type: \"string\",\n description:\n '<destField>[:<fieldType>]=<value>, repeatable. Omit both this and --from to be told what the side effect accepts instead. Sheet: A=name. HubSpot with --hubspot-form: firstname=nombre (the type is read off the form). ActiveCampaign: email=email, SECTOR=sector (custom field by id, personalization tag or label; custom.UTM_SOURCE for one only staged so far), tags=\"withbaker-\"+tracking:page_path, lists=\"Newsletter\", automations=\"Welcome\", deal.title=…/deal.pipeline=\"Sales\"/deal.value=budget, account.name=company, note=…, event.name=\"demo_requested\" — every type is read off the connected account. Where a destination cannot be read, state the type on the LEFT — c0ffee:varchar=email — because `:` on the right belongs to the value grammar.',\n required: false,\n },\n from: {\n type: \"string\",\n description:\n 'The whole mapping as a JSON file, or `-` for stdin: { \"sideEffect\": \"…\", \"map\": { \"<destField>\": \"<value>\", … } }. Past ~3 fields prefer this over repeated --map.',\n required: false,\n },\n \"side-effect\": { type: \"string\", description: \"Side-effect id, when the form has more than one\", required: false },\n \"hubspot-form\": {\n type: \"string\",\n description:\n \"HubSpot formGuid of the configured destination. Fills every mapping's fieldType and objectTypeId from the form itself, so you write no types at all. The guid is the `formGuid` in the `destination` request_flow_input returned.\",\n required: false,\n },\n into: {\n type: \"string\",\n description:\n \"Slot to map into when the type has more than one: meta/tiktok/pinterest take eventParams (default) or their matching record; googleAds takes enhancedConversions or value/currency/transactionId.\",\n required: false,\n },\n entity: {\n type: \"string\",\n description: \"Destination object (pipedrive: person|organization|lead, …)\",\n required: false,\n },\n custom: { type: \"boolean\", description: \"The destination fields are custom fields\", required: false },\n standard: { type: \"boolean\", description: \"The destination fields are standard fields\", required: false },\n \"object-type\": { type: \"string\", description: \"HubSpot objectTypeId (default 0-1, contact)\", required: false },\n \"prune-missing\": {\n type: \"boolean\",\n description:\n \"Drop the mappings whose destination field no longer exists on the account, and nothing else. The repair for a deleted HubSpot property: HubSpot refuses the WHOLE submission when it names a field it does not have, so one dead mapping loses every lead. Needs --hubspot-form so the live field list can be read. Runs on its own — no --map required. Prefer this to --replace, which drops everything this call does not name.\",\n required: false,\n },\n replace: {\n type: \"boolean\",\n description:\n \"Make the slot exactly what this call passes, dropping every mapping already in it. Without it, mappings MERGE by destination name — re-mapping a name overwrites it, a new name is appended, and the rest are left alone. To REMOVE a dead mapping, reach for --prune-missing instead: this one also deletes every mapping you did not re-state.\",\n required: false,\n },\n write: {\n type: \"boolean\",\n description: \"Splice the mapping into the form. Without it, prints and changes nothing\",\n required: false,\n },\n },\n});\n\n/**\n * Every `--map` on the command line.\n *\n * Read from `rawArgs`, not `args.map`: citty collapses a repeated flag to its\n * LAST value, so `--map A=name --map B=email` arrives as the single string\n * `\"B=email\"`. Taken from `args`, this command would map one field, report\n * success, and leave the other silently unmapped — which is the exact\n * failure mode it exists to prevent, one level up.\n */\nexport function mapSpecsFrom(rawArgs: readonly string[]): string[] {\n return repeatedFlagValues(rawArgs, \"map\");\n}\n\n/**\n * A whole mapping in one file, which is what a real one looks like.\n *\n * A CRM mapping is eight to fifteen fields. As repeated `--map` flags that is a\n * fifteen-flag command line whose shell quoting is its own hazard — an\n * improvement on hand-writing 230 lines of ProseMirror, but not much of one.\n * The JSON form is what the agent is actually holding in its head, and it is one\n * Write plus one command however many fields there are.\n *\n * {\n * \"sideEffect\": \"se-hubspotForm-1\",\n * \"hubspotForm\": \"8b1f…\",\n * \"map\": {\n * \"email\": \"email\",\n * \"firstname\": \"nombre\",\n * \"hs_lead_source\": \"tracking:utm_source\",\n * \"full_name\": \"nombre + \\\" \\\" + apellido\"\n * }\n * }\n *\n * `\"firstname\": { \"type\": \"…\", \"value\": \"…\" }` is still accepted for a\n * destination this command cannot read, but naming the destination once\n * (`hubspotForm` here, `--hubspot-form` on the command line) is strictly better:\n * the types then come from the account instead of from memory.\n */\ntype MapSpecFile = {\n sideEffect?: string;\n into?: string;\n entity?: string;\n custom?: boolean;\n objectType?: string;\n /**\n * Treat this file as the WHOLE mapping: anything in the slot it does not name\n * is dropped. Off by default so a file that lists three fields cannot delete\n * the five that were mapped before it.\n */\n replace?: boolean;\n /** Drop the mappings the destination no longer has. See `MapOptions.pruneMissing`. */\n pruneMissing?: boolean;\n /** HubSpot formGuid of the configured destination, so its field types can be read. */\n hubspotForm?: string;\n map?: Record<string, string | { type?: string; value?: string }>;\n};\n\n/** Flatten the JSON form into the same `<dest>[:<type>]=<value>` specs the flags produce. */\nexport function specsFromFile(parsed: MapSpecFile): string[] {\n return Object.entries(parsed.map ?? {}).map(([destField, entry]) => {\n if (typeof entry === \"string\") return `${destField}=${entry}`;\n const type = entry?.type ? `:${entry.type}` : \"\";\n return `${destField}${type}=${entry?.value ?? \"\"}`;\n });\n}\n\nfunction readSpecFile(path: string): MapSpecFile {\n let raw: string;\n try {\n raw = path === \"-\" ? readFileSync(0, \"utf-8\") : readFileSync(path, \"utf-8\");\n } catch (error) {\n refuse(\n `Could not read ${path === \"-\" ? \"the mapping from stdin\" : `\"${path}\"`}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n refuse(\n `${path === \"-\" ? \"stdin\" : `\"${path}\"`} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n 'Expected { \"map\": { \"<destField>\": \"<value>\", … } }',\n );\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n refuse(\"A mapping file must be a JSON object.\", 'Expected { \"map\": { \"<destField>\": \"<value>\", … } }');\n }\n const spec = parsed as MapSpecFile;\n if (!spec.map || typeof spec.map !== \"object\" || Object.keys(spec.map).length === 0) {\n refuse(\"A mapping file needs a non-empty `map` object.\", 'Expected { \"map\": { \"firstname\": \"nombre\", … } }');\n }\n return spec;\n}\n\n/** Refuse with the same envelope shape everywhere, so the agent parses one thing. */\nfunction refuse(message: string, fix?: string): never {\n writeJson({ ok: false, error: { code: \"VALIDATION_ERROR\", message, ...(fix ? { fix } : {}) } });\n process.exit(1);\n}\n\n/**\n * The destination's own field catalog, read off the connected account.\n *\n * This is the whole reason a HubSpot mapping no longer needs a type per field.\n * `fieldType` and `objectTypeId` are HubSpot's answers about its own properties,\n * not the agent's — the engine concatenates them into\n * `<objectTypeId>.<fieldType>.<fieldName>`, which is byte-for-byte the key the\n * dashboard's picker writes. Asking the agent to remember them is both more work\n * and less accurate than asking HubSpot, and a plausible-but-wrong one is the\n * silent kind: on a date property the engine skips the YYYY-MM-DD coercion and\n * HubSpot drops the value.\n *\n * One call for the whole mapping, and only when a destination was named. A\n * failure refuses rather than falling back to writing types nobody verified.\n */\nasync function hubspotFieldCatalog(\n formId: string,\n): Promise<{ fields: Map<string, DestinationField>; captchaEnabled: boolean }> {\n let response: HubspotFormsViewResponse;\n try {\n response = await apiPost<HubspotFormsViewResponse>(\"/api/hubspot/forms/view\", { formId });\n } catch (error) {\n refuse(\n `Could not read HubSpot form \"${formId}\": ${error instanceof Error ? error.message : String(error)}`,\n \"Check the guid against the `destination` request_flow_input returned, or `baker hubspot forms list`. Drop --hubspot-form and write `<field>:<fieldType>=<value>` per mapping only if HubSpot is unreachable.\",\n );\n }\n const fields = response.data.form?.fields ?? [];\n if (fields.length === 0) {\n refuse(\n `HubSpot form \"${formId}\" reports no fields, so nothing can be mapped against it.`,\n \"Confirm the guid names the form this side effect submits to: baker hubspot forms list\",\n );\n }\n return {\n fields: new Map(\n fields.map((field) => [\n field.name,\n { fieldType: field.fieldType, ...(field.objectTypeId ? { objectTypeId: field.objectTypeId } : {}) },\n ]),\n ),\n // Read while the form is already open, because this is the moment a\n // delivery is being wired: HubSpot refuses every submission sent to a form\n // with spam prevention on, so a mapping written against one is correct and\n // will still never arrive. Reported, not refused — the mapping is not the\n // mistake, and the client can switch it off without the work being redone.\n captchaEnabled: response.data.form?.captchaEnabled === true,\n };\n}\n\n/**\n * The connected ActiveCampaign account's fields, read for every\n * `activeCampaignContact` mapping — there is no resource to name, so there is\n * no flag to ask for: the side effect's own connection is the destination.\n *\n * Read rather than remembered for the same reason as HubSpot's: the field type\n * decides how the backend sends each value, and a custom field is stored by an\n * id only the account knows. A failure refuses rather than writing a guess.\n */\nasync function activeCampaignFieldCatalog(\n sideEffect: Record<string, unknown>,\n): Promise<{ fields: Map<string, DestinationField>; catalog: ActiveCampaignCatalog }> {\n const account = typeof sideEffect.oauthProviderId === \"string\" ? sideEffect.oauthProviderId : undefined;\n const body: ActiveCampaignFieldsRequest = account ? { account } : {};\n let response: ActiveCampaignFieldsResponse;\n try {\n response = activeCampaignFieldsResponseSchema.parse(\n await apiPost<ActiveCampaignFieldsResponse>(\"/api/activecampaign/fields\", body),\n );\n } catch (error) {\n refuse(\n `Could not read the ActiveCampaign account's fields: ${error instanceof Error ? error.message : String(error)}`,\n 'If ActiveCampaign is not connected (or its key stopped working), call request_connection with { platform: \"activecampaign\" } — the user pastes the API URL and key into that card, never into the chat — then run this again.',\n );\n }\n const { account: _account, ...catalog } = response.data;\n return { fields: new Map(activeCampaignDestinationFields(catalog.fields)), catalog };\n}\n\n/**\n * Answer the bare `baker flows map <slug> --side-effect <id>` probe.\n *\n * The left of a mapping is a different question per slot — a closed platform\n * set, a name the agent picks, or a name that only exists in the connected\n * account — and none of it was readable without guessing wrong first.\n */\nfunction describeDestination(chosen: Located): void {\n const type = String(chosen.sideEffect.type ?? \"\");\n const slots = describeSlots(type);\n if (slots.length === 0) {\n refuse(\n `A ${type} side effect has no mappable field.`,\n `Nothing on it addresses named values. \\`baker flows schema side-effect ${type}\\` shows what it does take.`,\n );\n }\n writeJson({\n ok: true,\n data: { sideEffectId: chosen.sideEffect.id, type, mappable: slots },\n hints: [\n `Nothing mapped — this is what a ${type} side effect accepts. Add --map <key>=<value> to build one.`,\n ...slots.map((slot) =>\n slot.keys\n ? `${slot.slot}: ${slot.keys.join(\", \")}`\n : `${slot.slot}: ${slot.keysFrom === \"account\" ? \"keys come from the connected account (request_flow_input returns them)\" : \"keys are yours to choose — whatever the receiving system expects\"}`,\n ),\n // Named separately from the key hint above: the key and its field type are\n // two different questions with two different answers, and the type is the\n // one an agent does not know it is being asked until a mapping is refused.\n ...slots.flatMap((slot) => (slot.fieldTypes ? [`${slot.slot} field types — ${slot.fieldTypes}`] : [])),\n 'Values (right of the `=`) are the same for every slot: a form field, tracking:<var>, global:<name>, code:<name>, a \"literal\", or those joined with +. A field may also be written as the file stores it, {{<stepId>.customForm.<field>}}. A value cannot run code (no .split(), .slice(), [0]).',\n ],\n });\n}\n\n/**\n * `shapeFor` as a refusal rather than a throw.\n *\n * `assertDestinationReady` is the one place `shapeFor` is reached BEFORE the\n * try/catch around `buildFieldMapping`, so an uncaught error here would escape\n * the `{ ok: false }` envelope every other path emits and reach the agent as a\n * stack trace.\n *\n * In practice the live case is an unrecognised `--into`, because only a type in\n * `FLOW_DELIVERY_SIDE_EFFECT_TYPES` gets this far (everything else returns at the\n * `sideEffectNeedsInput` check above) and every one of those has a slot. So\n * `--into eventParams` on an unconfigured `googleSpreadsheet` is enough to hit\n * it, and the message it would lose — the list of slots that type does have —\n * is exactly the one that answers it.\n */\nfunction shapeOrRefuse(type: string, into: string | undefined): ReturnType<typeof shapeFor> {\n try {\n return shapeFor(type, into);\n } catch (error) {\n if (error instanceof MappingError) refuse(error.message, error.fix);\n throw error;\n }\n}\n\n/**\n * Stop a mapping written against a destination nobody has picked yet.\n *\n * This is the failure the whole command exists to prevent, one level up: the\n * column letters and field keys live in an account only `request_flow_input`\n * can see, so before that call has run they can only be guesses — and a guessed\n * destination is structurally valid, passes every check here, ships, and sends\n * nothing forever. `verify` does catch it later (`flow-schema-unconfigured-oauth`),\n * but by then the mapping is written and the agent has moved on.\n *\n * Only for slots whose names come from the account. A webhook body or a pixel\n * parameter is the agent's to name, so an unset endpoint is a note, not a block.\n */\nfunction assertDestinationReady(\n slug: string,\n tree: Record<string, unknown>,\n chosen: Located,\n into: string | undefined,\n): void {\n if (!sideEffectNeedsInput(chosen.sideEffect)) return;\n\n const type = String(chosen.sideEffect.type ?? \"\");\n const status = collectConfigStatusFor(tree, slug, String(chosen.sideEffect.id ?? \"\"));\n const call = status ? requestFlowInputCall(slug, status) : `request_flow_input for the ${type} side effect`;\n\n if (!namesComeFromAccount(shapeOrRefuse(type, into))) return;\n\n refuse(\n `The ${type} destination is not configured yet, so its field names cannot be anything but a guess.`,\n `Configure it first, then map against the names that call returns: ${call}`,\n );\n}\n\n/** The config row for one side effect, so the refusal can carry a ready-to-issue call. */\nfunction collectConfigStatusFor(tree: Record<string, unknown>, _slug: string, sideEffectId: string) {\n const rows: Parameters<typeof requestFlowInputCall>[1][] = [];\n collectConfigStatus(tree, rows);\n return rows.find((row) => row.sideEffectId === sideEffectId);\n}\n\n/**\n * Name the slots this side effect has and this call did not use.\n *\n * A `meta` side effect has both `eventParams` and `advancedMatching`, and the\n * one an agent most often needs — advanced matching, which decides whether Meta\n * can attribute the conversion at all — is not the default. Saying so on every\n * response is cheaper than the agent finding out from a reference file it may\n * not open.\n */\nfunction slotHintFor(type: string, into: string | undefined): string[] {\n const others = otherSlots(type, shapeFor(type, into));\n if (others.length === 0) return [];\n return [`This side effect also takes ${others.join(\" and \")} — pass --into <slot> to map into one of those instead.`];\n}\n\n/**\n * What happened to the mappings this call did NOT name.\n *\n * Said out loud in both directions, because a slot whose size moved without\n * being mentioned is exactly how the loss stays silent: \"kept\" answers the\n * question a merge raises (\"did it drop the others?\"), and `--replace` has to\n * state its drop or it is the same bug with a flag on it.\n */\nfunction survivorHint(built: BuiltMapping, replacing: boolean): string[] {\n if (built.kept > 0) {\n return [`${built.kept} mapping${built.kept === 1 ? \"\" : \"s\"} already in ${built.key} kept — this merged by name.`];\n }\n if (!replacing) return [];\n return [`--replace: ${built.key} is now exactly these ${built.count}; anything else it held is gone.`];\n}\n\n/**\n * Every mapping `--prune-missing` removed, named one by one.\n *\n * A count would be the same mistake this whole repair exists to undo: the drift\n * Task that nobody could act on said \"an answer HubSpot no longer accepts\" and\n * named none of them, and six Forms were closed as false positives off that\n * sentence. A removal the agent cannot repeat back to the user is a removal\n * nobody can check.\n */\nfunction droppedHint(built: BuiltMapping): string[] {\n if (built.dropped.length === 0) return [];\n return [\n `--prune-missing dropped ${built.dropped.length} mapping${built.dropped.length === 1 ? \"\" : \"s\"} the destination no longer has: ${built.dropped.join(\", \")}. Every other mapping in ${built.key} was left alone.`,\n ];\n}\n\n/**\n * A note, not a block: these keys are the agent's to choose, but the endpoint\n * they are posted to is still the user's to supply, and nothing later in this\n * command will mention it.\n */\nfunction pendingEndpointHint(slug: string, tree: Record<string, unknown>, chosen: Located): string[] {\n if (!sideEffectNeedsInput(chosen.sideEffect)) return [];\n const status = collectConfigStatusFor(tree, slug, String(chosen.sideEffect.id ?? \"\"));\n if (!status) return [];\n return [`The mapping is written, but this destination still needs the user: ${requestFlowInputCall(slug, status)}`];\n}\n\ntype Located = { node: Record<string, unknown>; sideEffect: Record<string, unknown> };\n\n/** The side effect to map into: the named one, or the only one. Never a guess between several. */\nfunction pickSideEffect(slug: string, found: Located[], named: string | undefined): Located {\n if (found.length === 0) {\n refuse(\n `\"${slug}\" has no side effects — author the side effect first, then map into it.`,\n `baker flows add-side-effect ${slug} --node <nodeId> --type <type>`,\n );\n }\n const chosen = named\n ? found.find((entry) => entry.sideEffect.id === named)\n : found.length === 1\n ? found[0]\n : undefined;\n if (chosen) return chosen;\n\n const inventory = found.map((entry) => `${entry.sideEffect.id} (${entry.sideEffect.type})`).join(\", \");\n refuse(\n named\n ? `No side effect with id \"${named}\" in \"${slug}\".`\n : `\"${slug}\" has ${found.length} side effects — name one with --side-effect <id>.`,\n `Side effects in this form: ${inventory}`,\n );\n}\n\n/**\n * `--custom` and `--standard` answer the same question, and the answer decides\n * whether the write lands or is silently dropped. Taking the last flag would\n * pick one of two contradictory instructions at random.\n */\nfunction customFlag(custom: unknown, standard: unknown): boolean | undefined {\n if (custom === true && standard === true) {\n refuse(\"--custom and --standard contradict each other. Pass one.\");\n }\n if (custom === true) return true;\n if (standard === true) return false;\n return undefined;\n}\n\n/**\n * The destination-side options, from the flags and the mapping file together.\n *\n * A flag beats the file, so a saved mapping can be retargeted without editing\n * it. The destination catalog is read HERE, before anything is built, so every\n * mapping's field type is derived from the account rather than remembered —\n * and only when a destination was actually named: without one the build still\n * runs, and refuses per mapping if it turns out a type was needed.\n */\nasync function mapOptions(\n args: Record<string, unknown>,\n fromFile: MapSpecFile | undefined,\n into: string | undefined,\n sideEffect: Record<string, unknown>,\n): Promise<{ options: MapOptions; hints: string[]; activeCampaign?: ActiveCampaignCatalog | undefined }> {\n const hubspotForm = args[\"hubspot-form\"] ? String(args[\"hubspot-form\"]) : fromFile?.hubspotForm;\n const hubspot = hubspotForm ? await hubspotFieldCatalog(hubspotForm) : undefined;\n const activeCampaign =\n !hubspot && sideEffect.type === \"activeCampaignContact\" ? await activeCampaignFieldCatalog(sideEffect) : undefined;\n return {\n options: {\n into,\n entity: args.entity ? String(args.entity) : fromFile?.entity,\n isCustomField: customFlag(args.custom, args.standard) ?? fromFile?.custom,\n objectType: args[\"object-type\"] ? String(args[\"object-type\"]) : fromFile?.objectType,\n replace: args.replace === true || fromFile?.replace === true,\n pruneMissing: args[\"prune-missing\"] === true || fromFile?.pruneMissing === true,\n destinationFields: hubspot?.fields ?? activeCampaign?.fields,\n unlistedField: activeCampaign ? activeCampaignUnlistedField : undefined,\n },\n hints: hubspot?.captchaEnabled\n ? [\n \"WARNING: this HubSpot form has spam prevention (captcha) on. HubSpot refuses every submission sent to a form with it on, so nothing mapped here will arrive — the mapping is fine, the destination is not. Only the user can switch it off, on the form in HubSpot. Tell them that, and do not swap the destination yourself.\",\n ]\n : [],\n activeCampaign: activeCampaign?.catalog,\n };\n}\n\nexport const mapCommand = defineCommand({\n meta: {\n name: \"map\",\n description:\n \"Map form fields onto any value a side effect sends — never hand-write a mapping. Start here: baker flows map contact --from map.json --write\",\n },\n args: {\n slug: { type: \"positional\", description: \"Form slug\", required: true },\n map: { type: \"string\", description: \"<destField>[:<fieldType>]=<value> (repeatable)\" },\n from: { type: \"string\", description: \"Read the whole mapping from a JSON file, or `-` for stdin\" },\n \"side-effect\": { type: \"string\", description: \"Side-effect id, when the form has more than one\" },\n \"hubspot-form\": {\n type: \"string\",\n description: \"HubSpot formGuid — reads every field's type off the form so you write none\",\n },\n into: {\n type: \"string\",\n description: \"Which slot to map into, for a type with more than one (e.g. meta: eventParams | advancedMatching)\",\n },\n entity: { type: \"string\", description: \"Destination object (person, contact, lead, …)\" },\n custom: { type: \"boolean\", description: \"Destination fields are custom fields\" },\n standard: { type: \"boolean\", description: \"Destination fields are standard fields\" },\n \"object-type\": { type: \"string\", description: \"HubSpot objectTypeId (default 0-1)\" },\n \"prune-missing\": {\n type: \"boolean\",\n description: \"Drop only the mappings the destination no longer has — the repair for a deleted HubSpot field\",\n },\n replace: {\n type: \"boolean\",\n description: \"Drop every mapping already in the slot. Default merges by destination name\",\n },\n write: { type: \"boolean\", description: \"Splice the mapping into the form\" },\n },\n run: async ({ args, rawArgs }) => {\n const slug = String(args.slug);\n const fromFile = args.from ? readSpecFile(String(args.from)) : undefined;\n const specs = fromFile ? specsFromFile(fromFile) : mapSpecsFrom(rawArgs);\n const into = args.into ? String(args.into) : fromFile?.into;\n const replacing = args.replace === true || fromFile?.replace === true;\n const pruning = args[\"prune-missing\"] === true || fromFile?.pruneMissing === true;\n\n const tree = readFlowTree(slug);\n // A flag beats the file, so a saved mapping can be retargeted without editing it.\n const chosen = pickSideEffect(\n slug,\n collectSideEffects(tree),\n args[\"side-effect\"] ? String(args[\"side-effect\"]) : fromFile?.sideEffect,\n );\n\n // No mappings given: answer \"what can I map here, and where do the key names\n // come from\" rather than printing usage. The command already holds the side\n // effect, so refusing threw the answer away and left the only discovery path\n // a wrong guess — name a key outside a closed set and read it off the refusal.\n // `--prune-missing` is a whole call on its own: the repair for a deleted\n // destination field is a removal, and requiring a `--map` alongside it would\n // mean inventing a mapping to make a deletion legal.\n if (specs.length === 0 && !pruning) {\n describeDestination(chosen);\n return;\n }\n\n assertDestinationReady(slug, tree, chosen, into);\n\n const {\n options,\n hints: destinationHints,\n activeCampaign,\n } = await mapOptions(args, fromFile, into, chosen.sideEffect);\n\n let built: ReturnType<typeof buildFieldMapping>;\n try {\n built = buildFieldMapping(tree, chosen.sideEffect, specs, options);\n } catch (error) {\n if (error instanceof MappingError) {\n refuse(error.message, error.fix);\n }\n throw error;\n }\n\n const slotHint = [\n ...destinationHints,\n ...(activeCampaign && Array.isArray(built.patch.fieldMapping)\n ? activeCampaignMappingHints(built.patch.fieldMapping as Record<string, unknown>[], activeCampaign)\n : []),\n ...droppedHint(built),\n ...survivorHint(built, replacing),\n ...slotHintFor(String(chosen.sideEffect.type ?? \"\"), into),\n ...pendingEndpointHint(slug, tree, chosen),\n ];\n\n if (args.write !== true) {\n emitDryRun(slug, chosen, built, slotHint);\n return;\n }\n\n Object.assign(chosen.sideEffect, built.patch);\n writeFlowTree(slug, tree);\n emitWritten(slug, chosen, built, slotHint);\n },\n});\n\n/**\n * The first line of the answer: what this call did, or would do.\n *\n * It has to survive a call that only REMOVES. `--prune-missing` on its own\n * writes nothing and drops something, and \"Wrote 0 fieldMapping mappings\"\n * describes the opposite of what happened — it reads as a no-op, which is the\n * one reading that sends an agent looking for a different command after the\n * repair has already landed. The drops are named by `droppedHint` two lines\n * further down, and that is not where anybody looks to find out whether a\n * command worked.\n *\n * Exported for its own test, because this sentence is the whole report.\n */\nexport function mapHeadline(built: BuiltMapping, phase: \"written\" | \"dry-run\", slug = \"\"): string {\n const wrote = `${built.count} ${built.key} mapping${built.count === 1 ? \"\" : \"s\"}`;\n const drops = `${built.dropped.length} dead mapping${built.dropped.length === 1 ? \"\" : \"s\"}`;\n\n if (phase === \"dry-run\") {\n if (built.count === 0 && built.dropped.length > 0) {\n return `Nothing written. Re-run with --write to drop ${drops} from ${slug}.`;\n }\n return `Nothing written. Re-run with --write to splice ${wrote} into ${slug}.`;\n }\n\n if (built.dropped.length === 0) return `Wrote ${wrote}.`;\n if (built.count === 0) return `Dropped ${drops} from ${built.key}; nothing else changed.`;\n return `Wrote ${wrote} and dropped ${drops}.`;\n}\n\n/** What the call WOULD do, plus the one sentence saying how to make it happen. */\nfunction emitDryRun(slug: string, chosen: Located, built: BuiltMapping, slotHint: string[]): void {\n writeJson({\n ok: true,\n data: {\n sideEffectId: chosen.sideEffect.id,\n type: chosen.sideEffect.type,\n key: built.key,\n patch: built.patch,\n },\n hints: [mapHeadline(built, \"dry-run\", slug), ...slotHint],\n });\n}\n\nfunction emitWritten(slug: string, chosen: Located, built: BuiltMapping, slotHint: string[]): void {\n writeJson({\n ok: true,\n data: {\n sideEffectId: chosen.sideEffect.id,\n type: chosen.sideEffect.type,\n key: built.key,\n written: built.count,\n kept: built.kept,\n dropped: built.dropped,\n path: flowDataPath(slug),\n },\n hints: [\n mapHeadline(built, \"written\"),\n `A mapping is only real once the destination is set — check with: baker flows show ${slug}`,\n ...slotHint,\n ],\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,oBAAoB;AAQ7B,SAAS,qBAAqB;AA6B9B,eAAe;AAAA,EACb,SAAS;AAAA,EACT,aACE;AAAA,EACF,MAAM;AAAA,IACJ,MAAM,EAAE,MAAM,cAAc,aAAa,mCAAmC,UAAU,KAAK;AAAA,IAC3F,KAAK;AAAA,MACH,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,eAAe,EAAE,MAAM,UAAU,aAAa,mDAAmD,UAAU,MAAM;AAAA,IACjH,gBAAgB;AAAA,MACd,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ,EAAE,MAAM,WAAW,aAAa,4CAA4C,UAAU,MAAM;AAAA,IACpG,UAAU,EAAE,MAAM,WAAW,aAAa,8CAA8C,UAAU,MAAM;AAAA,IACxG,eAAe,EAAE,MAAM,UAAU,aAAa,+CAA+C,UAAU,MAAM;AAAA,IAC7G,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aACE;AAAA,MACF,UAAU;AAAA,IACZ;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,EACF;AACF,CAAC;AAWM,SAAS,aAAa,SAAsC;AACjE,SAAO,mBAAmB,SAAS,KAAK;AAC1C;AA+CO,SAAS,cAAc,QAA+B;AAC3D,SAAO,OAAO,QAAQ,OAAO,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,KAAK,MAAM;AAClE,QAAI,OAAO,UAAU,SAAU,QAAO,GAAG,SAAS,IAAI,KAAK;AAC3D,UAAM,OAAO,OAAO,OAAO,IAAI,MAAM,IAAI,KAAK;AAC9C,WAAO,GAAG,SAAS,GAAG,IAAI,IAAI,OAAO,SAAS,EAAE;AAAA,EAClD,CAAC;AACH;AAEA,SAAS,aAAa,MAA2B;AAC/C,MAAI;AACJ,MAAI;AACF,UAAM,SAAS,MAAM,aAAa,GAAG,OAAO,IAAI,aAAa,MAAM,OAAO;AAAA,EAC5E,SAAS,OAAO;AACd;AAAA,MACE,kBAAkB,SAAS,MAAM,2BAA2B,IAAI,IAAI,GAAG,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IACpI;AAAA,EACF;AACA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,OAAO;AACd;AAAA,MACE,GAAG,SAAS,MAAM,UAAU,IAAI,IAAI,GAAG,uBAAuB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACpH;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAClE,WAAO,yCAAyC,0DAAqD;AAAA,EACvG;AACA,QAAM,OAAO;AACb,MAAI,CAAC,KAAK,OAAO,OAAO,KAAK,QAAQ,YAAY,OAAO,KAAK,KAAK,GAAG,EAAE,WAAW,GAAG;AACnF,WAAO,kDAAkD,uDAAkD;AAAA,EAC7G;AACA,SAAO;AACT;AAGA,SAAS,OAAO,SAAiB,KAAqB;AACpD,YAAU,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,oBAAoB,SAAS,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC,EAAG,EAAE,CAAC;AAC9F,UAAQ,KAAK,CAAC;AAChB;AAiBA,eAAe,oBACb,QAC6E;AAC7E,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,QAAkC,2BAA2B,EAAE,OAAO,CAAC;AAAA,EAC1F,SAAS,OAAO;AACd;AAAA,MACE,gCAAgC,MAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAClG;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAAS,SAAS,KAAK,MAAM,UAAU,CAAC;AAC9C,MAAI,OAAO,WAAW,GAAG;AACvB;AAAA,MACE,iBAAiB,MAAM;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ,IAAI;AAAA,MACV,OAAO,IAAI,CAAC,UAAU;AAAA,QACpB,MAAM;AAAA,QACN,EAAE,WAAW,MAAM,WAAW,GAAI,MAAM,eAAe,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC,EAAG;AAAA,MACpG,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMA,gBAAgB,SAAS,KAAK,MAAM,mBAAmB;AAAA,EACzD;AACF;AAWA,eAAe,2BACb,YACoF;AACpF,QAAM,UAAU,OAAO,WAAW,oBAAoB,WAAW,WAAW,kBAAkB;AAC9F,QAAM,OAAoC,UAAU,EAAE,QAAQ,IAAI,CAAC;AACnE,MAAI;AACJ,MAAI;AACF,eAAW,mCAAmC;AAAA,MAC5C,MAAM,QAAsC,8BAA8B,IAAI;AAAA,IAChF;AAAA,EACF,SAAS,OAAO;AACd;AAAA,MACE,uDAAuD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAC7G;AAAA,IACF;AAAA,EACF;AACA,QAAM,EAAE,SAAS,UAAU,GAAG,QAAQ,IAAI,SAAS;AACnD,SAAO,EAAE,QAAQ,IAAI,IAAI,gCAAgC,QAAQ,MAAM,CAAC,GAAG,QAAQ;AACrF;AASA,SAAS,oBAAoB,QAAuB;AAClD,QAAM,OAAO,OAAO,OAAO,WAAW,QAAQ,EAAE;AAChD,QAAM,QAAQ,cAAc,IAAI;AAChC,MAAI,MAAM,WAAW,GAAG;AACtB;AAAA,MACE,KAAK,IAAI;AAAA,MACT,0EAA0E,IAAI;AAAA,IAChF;AAAA,EACF;AACA,YAAU;AAAA,IACR,IAAI;AAAA,IACJ,MAAM,EAAE,cAAc,OAAO,WAAW,IAAI,MAAM,UAAU,MAAM;AAAA,IAClE,OAAO;AAAA,MACL,wCAAmC,IAAI;AAAA,MACvC,GAAG,MAAM;AAAA,QAAI,CAAC,SACZ,KAAK,OACD,GAAG,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK,IAAI,CAAC,KACrC,GAAG,KAAK,IAAI,KAAK,KAAK,aAAa,YAAY,2EAA2E,uEAAkE;AAAA,MAClM;AAAA;AAAA;AAAA;AAAA,MAIA,GAAG,MAAM,QAAQ,CAAC,SAAU,KAAK,aAAa,CAAC,GAAG,KAAK,IAAI,uBAAkB,KAAK,UAAU,EAAE,IAAI,CAAC,CAAE;AAAA,MACrG;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAiBA,SAAS,cAAc,MAAc,MAAuD;AAC1F,MAAI;AACF,WAAO,SAAS,MAAM,IAAI;AAAA,EAC5B,SAAS,OAAO;AACd,QAAI,iBAAiB,aAAc,QAAO,MAAM,SAAS,MAAM,GAAG;AAClE,UAAM;AAAA,EACR;AACF;AAeA,SAAS,uBACP,MACA,MACA,QACA,MACM;AACN,MAAI,CAAC,qBAAqB,OAAO,UAAU,EAAG;AAE9C,QAAM,OAAO,OAAO,OAAO,WAAW,QAAQ,EAAE;AAChD,QAAM,SAAS,uBAAuB,MAAM,MAAM,OAAO,OAAO,WAAW,MAAM,EAAE,CAAC;AACpF,QAAM,OAAO,SAAS,qBAAqB,MAAM,MAAM,IAAI,8BAA8B,IAAI;AAE7F,MAAI,CAAC,qBAAqB,cAAc,MAAM,IAAI,CAAC,EAAG;AAEtD;AAAA,IACE,OAAO,IAAI;AAAA,IACX,qEAAqE,IAAI;AAAA,EAC3E;AACF;AAGA,SAAS,uBAAuB,MAA+B,OAAe,cAAsB;AAClG,QAAM,OAAqD,CAAC;AAC5D,sBAAoB,MAAM,IAAI;AAC9B,SAAO,KAAK,KAAK,CAAC,QAAQ,IAAI,iBAAiB,YAAY;AAC7D;AAWA,SAAS,YAAY,MAAc,MAAoC;AACrE,QAAM,SAAS,WAAW,MAAM,SAAS,MAAM,IAAI,CAAC;AACpD,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AACjC,SAAO,CAAC,+BAA+B,OAAO,KAAK,OAAO,CAAC,8DAAyD;AACtH;AAUA,SAAS,aAAa,OAAqB,WAA8B;AACvE,MAAI,MAAM,OAAO,GAAG;AAClB,WAAO,CAAC,GAAG,MAAM,IAAI,WAAW,MAAM,SAAS,IAAI,KAAK,GAAG,eAAe,MAAM,GAAG,mCAA8B;AAAA,EACnH;AACA,MAAI,CAAC,UAAW,QAAO,CAAC;AACxB,SAAO,CAAC,cAAc,MAAM,GAAG,yBAAyB,MAAM,KAAK,kCAAkC;AACvG;AAWA,SAAS,YAAY,OAA+B;AAClD,MAAI,MAAM,QAAQ,WAAW,EAAG,QAAO,CAAC;AACxC,SAAO;AAAA,IACL,2BAA2B,MAAM,QAAQ,MAAM,WAAW,MAAM,QAAQ,WAAW,IAAI,KAAK,GAAG,mCAAmC,MAAM,QAAQ,KAAK,IAAI,CAAC,4BAA4B,MAAM,GAAG;AAAA,EACjM;AACF;AAOA,SAAS,oBAAoB,MAAc,MAA+B,QAA2B;AACnG,MAAI,CAAC,qBAAqB,OAAO,UAAU,EAAG,QAAO,CAAC;AACtD,QAAM,SAAS,uBAAuB,MAAM,MAAM,OAAO,OAAO,WAAW,MAAM,EAAE,CAAC;AACpF,MAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,SAAO,CAAC,sEAAsE,qBAAqB,MAAM,MAAM,CAAC,EAAE;AACpH;AAKA,SAAS,eAAe,MAAc,OAAkB,OAAoC;AAC1F,MAAI,MAAM,WAAW,GAAG;AACtB;AAAA,MACE,IAAI,IAAI;AAAA,MACR,+BAA+B,IAAI;AAAA,IACrC;AAAA,EACF;AACA,QAAM,SAAS,QACX,MAAM,KAAK,CAAC,UAAU,MAAM,WAAW,OAAO,KAAK,IACnD,MAAM,WAAW,IACf,MAAM,CAAC,IACP;AACN,MAAI,OAAQ,QAAO;AAEnB,QAAM,YAAY,MAAM,IAAI,CAAC,UAAU,GAAG,MAAM,WAAW,EAAE,KAAK,MAAM,WAAW,IAAI,GAAG,EAAE,KAAK,IAAI;AACrG;AAAA,IACE,QACI,2BAA2B,KAAK,SAAS,IAAI,OAC7C,IAAI,IAAI,SAAS,MAAM,MAAM;AAAA,IACjC,8BAA8B,SAAS;AAAA,EACzC;AACF;AAOA,SAAS,WAAW,QAAiB,UAAwC;AAC3E,MAAI,WAAW,QAAQ,aAAa,MAAM;AACxC,WAAO,0DAA0D;AAAA,EACnE;AACA,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI,aAAa,KAAM,QAAO;AAC9B,SAAO;AACT;AAWA,eAAe,WACb,MACA,UACA,MACA,YACuG;AACvG,QAAM,cAAc,KAAK,cAAc,IAAI,OAAO,KAAK,cAAc,CAAC,IAAI,UAAU;AACpF,QAAM,UAAU,cAAc,MAAM,oBAAoB,WAAW,IAAI;AACvE,QAAM,iBACJ,CAAC,WAAW,WAAW,SAAS,0BAA0B,MAAM,2BAA2B,UAAU,IAAI;AAC3G,SAAO;AAAA,IACL,SAAS;AAAA,MACP;AAAA,MACA,QAAQ,KAAK,SAAS,OAAO,KAAK,MAAM,IAAI,UAAU;AAAA,MACtD,eAAe,WAAW,KAAK,QAAQ,KAAK,QAAQ,KAAK,UAAU;AAAA,MACnE,YAAY,KAAK,aAAa,IAAI,OAAO,KAAK,aAAa,CAAC,IAAI,UAAU;AAAA,MAC1E,SAAS,KAAK,YAAY,QAAQ,UAAU,YAAY;AAAA,MACxD,cAAc,KAAK,eAAe,MAAM,QAAQ,UAAU,iBAAiB;AAAA,MAC3E,mBAAmB,SAAS,UAAU,gBAAgB;AAAA,MACtD,eAAe,iBAAiB,8BAA8B;AAAA,IAChE;AAAA,IACA,OAAO,SAAS,iBACZ;AAAA,MACE;AAAA,IACF,IACA,CAAC;AAAA,IACL,gBAAgB,gBAAgB;AAAA,EAClC;AACF;AAEO,IAAM,aAAa,cAAc;AAAA,EACtC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aACE;AAAA,EACJ;AAAA,EACA,MAAM;AAAA,IACJ,MAAM,EAAE,MAAM,cAAc,aAAa,aAAa,UAAU,KAAK;AAAA,IACrE,KAAK,EAAE,MAAM,UAAU,aAAa,iDAAiD;AAAA,IACrF,MAAM,EAAE,MAAM,UAAU,aAAa,4DAA4D;AAAA,IACjG,eAAe,EAAE,MAAM,UAAU,aAAa,kDAAkD;AAAA,IAChG,gBAAgB;AAAA,MACd,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,QAAQ,EAAE,MAAM,UAAU,aAAa,qDAAgD;AAAA,IACvF,QAAQ,EAAE,MAAM,WAAW,aAAa,uCAAuC;AAAA,IAC/E,UAAU,EAAE,MAAM,WAAW,aAAa,yCAAyC;AAAA,IACnF,eAAe,EAAE,MAAM,UAAU,aAAa,qCAAqC;AAAA,IACnF,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,OAAO,EAAE,MAAM,WAAW,aAAa,mCAAmC;AAAA,EAC5E;AAAA,EACA,KAAK,OAAO,EAAE,MAAM,QAAQ,MAAM;AAChC,UAAM,OAAO,OAAO,KAAK,IAAI;AAC7B,UAAM,WAAW,KAAK,OAAO,aAAa,OAAO,KAAK,IAAI,CAAC,IAAI;AAC/D,UAAM,QAAQ,WAAW,cAAc,QAAQ,IAAI,aAAa,OAAO;AACvE,UAAM,OAAO,KAAK,OAAO,OAAO,KAAK,IAAI,IAAI,UAAU;AACvD,UAAM,YAAY,KAAK,YAAY,QAAQ,UAAU,YAAY;AACjE,UAAM,UAAU,KAAK,eAAe,MAAM,QAAQ,UAAU,iBAAiB;AAE7E,UAAM,OAAO,aAAa,IAAI;AAE9B,UAAM,SAAS;AAAA,MACb;AAAA,MACA,mBAAmB,IAAI;AAAA,MACvB,KAAK,aAAa,IAAI,OAAO,KAAK,aAAa,CAAC,IAAI,UAAU;AAAA,IAChE;AASA,QAAI,MAAM,WAAW,KAAK,CAAC,SAAS;AAClC,0BAAoB,MAAM;AAC1B;AAAA,IACF;AAEA,2BAAuB,MAAM,MAAM,QAAQ,IAAI;AAE/C,UAAM;AAAA,MACJ;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IACF,IAAI,MAAM,WAAW,MAAM,UAAU,MAAM,OAAO,UAAU;AAE5D,QAAI;AACJ,QAAI;AACF,cAAQ,kBAAkB,MAAM,OAAO,YAAY,OAAO,OAAO;AAAA,IACnE,SAAS,OAAO;AACd,UAAI,iBAAiB,cAAc;AACjC,eAAO,MAAM,SAAS,MAAM,GAAG;AAAA,MACjC;AACA,YAAM;AAAA,IACR;AAEA,UAAM,WAAW;AAAA,MACf,GAAG;AAAA,MACH,GAAI,kBAAkB,MAAM,QAAQ,MAAM,MAAM,YAAY,IACxD,2BAA2B,MAAM,MAAM,cAA2C,cAAc,IAChG,CAAC;AAAA,MACL,GAAG,YAAY,KAAK;AAAA,MACpB,GAAG,aAAa,OAAO,SAAS;AAAA,MAChC,GAAG,YAAY,OAAO,OAAO,WAAW,QAAQ,EAAE,GAAG,IAAI;AAAA,MACzD,GAAG,oBAAoB,MAAM,MAAM,MAAM;AAAA,IAC3C;AAEA,QAAI,KAAK,UAAU,MAAM;AACvB,iBAAW,MAAM,QAAQ,OAAO,QAAQ;AACxC;AAAA,IACF;AAEA,WAAO,OAAO,OAAO,YAAY,MAAM,KAAK;AAC5C,kBAAc,MAAM,IAAI;AACxB,gBAAY,MAAM,QAAQ,OAAO,QAAQ;AAAA,EAC3C;AACF,CAAC;AAeM,SAAS,YAAY,OAAqB,OAA8B,OAAO,IAAY;AAChG,QAAM,QAAQ,GAAG,MAAM,KAAK,IAAI,MAAM,GAAG,WAAW,MAAM,UAAU,IAAI,KAAK,GAAG;AAChF,QAAM,QAAQ,GAAG,MAAM,QAAQ,MAAM,gBAAgB,MAAM,QAAQ,WAAW,IAAI,KAAK,GAAG;AAE1F,MAAI,UAAU,WAAW;AACvB,QAAI,MAAM,UAAU,KAAK,MAAM,QAAQ,SAAS,GAAG;AACjD,aAAO,gDAAgD,KAAK,SAAS,IAAI;AAAA,IAC3E;AACA,WAAO,kDAAkD,KAAK,SAAS,IAAI;AAAA,EAC7E;AAEA,MAAI,MAAM,QAAQ,WAAW,EAAG,QAAO,SAAS,KAAK;AACrD,MAAI,MAAM,UAAU,EAAG,QAAO,WAAW,KAAK,SAAS,MAAM,GAAG;AAChE,SAAO,SAAS,KAAK,gBAAgB,KAAK;AAC5C;AAGA,SAAS,WAAW,MAAc,QAAiB,OAAqB,UAA0B;AAChG,YAAU;AAAA,IACR,IAAI;AAAA,IACJ,MAAM;AAAA,MACJ,cAAc,OAAO,WAAW;AAAA,MAChC,MAAM,OAAO,WAAW;AAAA,MACxB,KAAK,MAAM;AAAA,MACX,OAAO,MAAM;AAAA,IACf;AAAA,IACA,OAAO,CAAC,YAAY,OAAO,WAAW,IAAI,GAAG,GAAG,QAAQ;AAAA,EAC1D,CAAC;AACH;AAEA,SAAS,YAAY,MAAc,QAAiB,OAAqB,UAA0B;AACjG,YAAU;AAAA,IACR,IAAI;AAAA,IACJ,MAAM;AAAA,MACJ,cAAc,OAAO,WAAW;AAAA,MAChC,MAAM,OAAO,WAAW;AAAA,MACxB,KAAK,MAAM;AAAA,MACX,SAAS,MAAM;AAAA,MACf,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,MAAM,aAAa,IAAI;AAAA,IACzB;AAAA,IACA,OAAO;AAAA,MACL,YAAY,OAAO,SAAS;AAAA,MAC5B,0FAAqF,IAAI;AAAA,MACzF,GAAG;AAAA,IACL;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|