@koda-sl/baker-cli 0.524.0 → 0.526.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 +10 -3
- package/dist/account-2G3IT7J4.js +82 -0
- package/dist/account-APMJVG2F.js +139 -0
- package/dist/account-ULC5N7SI.js +82 -0
- package/dist/account-assets-TAUEBCY5.js +290 -0
- package/dist/account-level-2MYDHOID.js +611 -0
- package/dist/account-reads-FRFI6OHK.js +219 -0
- package/dist/account-users-PINZLBT7.js +64 -0
- package/dist/account-writes-WRGJC7VU.js +68 -0
- package/dist/accounts-2KFG33EX.js +80 -0
- package/dist/accounts-5754XUS3.js +115 -0
- package/dist/accounts-MHPNZW3W.js +701 -0
- package/dist/accounts-MTNBMXHD.js +114 -0
- package/dist/accounts-VIAQC3PA.js +76 -0
- package/dist/actions-33IZOT5C.js +55 -0
- package/dist/active-entities-JR5B32X2.js +103 -0
- package/dist/activecampaign-BV5GZFVR.js +938 -0
- package/dist/activities-MJMAV3SI.js +75 -0
- package/dist/ad-group-writes-W6RCMYLC.js +172 -0
- package/dist/ad-groups-XAI2Z62X.js +70 -0
- package/dist/ad-writes-IGWZRTXY.js +176 -0
- package/dist/add-4PJDIW2M.js +148 -0
- package/dist/add-DBCN33GH.js +107 -0
- package/dist/add-KB7O7NSB.js +97 -0
- package/dist/add-PRU32PQN.js +81 -0
- package/dist/add-UZDOQAJL.js +80 -0
- package/dist/add-WDX66JSM.js +305 -0
- package/dist/add-accounts-ZWXG6HLM.js +91 -0
- package/dist/ads-255V76SZ.js +79 -0
- package/dist/ads-I6I4MYQH.js +128 -0
- package/dist/ads-NNKUR4HG.js +115 -0
- package/dist/ads-O4RL4JXD.js +48 -0
- package/dist/adsets-VO5C7PDM.js +182 -0
- package/dist/advertisers-BPJWOY7I.js +125 -0
- package/dist/advertisers-SJO6JYIO.js +123 -0
- package/dist/analytics-OUNKG2FW.js +2437 -0
- package/dist/analytics-TXPEXLPQ.js +447 -0
- package/dist/animate-425S4ZXS.js +480 -0
- package/dist/approved-KUVAJ5M7.js +73 -0
- package/dist/asset-writes-PQNENVYY.js +50 -0
- package/dist/assign-CTV6LDEI.js +80 -0
- package/dist/audience-size-5QYI5PKH.js +76 -0
- package/dist/audience-writes-QDDADCYE.js +327 -0
- package/dist/audiences-JZ6SCEUC.js +280 -0
- package/dist/audiences-OMLKMHEJ.js +85 -0
- package/dist/audiences-TQ5ZEWIR.js +86 -0
- package/dist/audit-2YFDJAKL.js +88 -0
- package/dist/audit-4UE6GFLG.js +154 -0
- package/dist/autocomplete-HTUV2UDS.js +114 -0
- package/dist/avatars-IJQOWSFC.js +38 -0
- package/dist/bid-pricing-OWP4SZP5.js +103 -0
- package/dist/brand-GBP4OEJI.js +22 -0
- package/dist/brief-ZDHUBPV5.js +543 -0
- package/dist/businesses-CW4RB36R.js +54 -0
- package/dist/campaign-groups-LDOQU65Q.js +99 -0
- package/dist/campaign-writes-SHF3XZXV.js +176 -0
- package/dist/campaign-writes-SK55QLY5.js +168 -0
- package/dist/campaigns-6CAKRANC.js +113 -0
- package/dist/campaigns-EHV7J7PW.js +111 -0
- package/dist/campaigns-GG7LLI4X.js +78 -0
- package/dist/campaigns-IQYYYD2S.js +130 -0
- package/dist/canvas-AZ47PNYZ.js +46 -0
- package/dist/capabilities-BEZXR2FZ.js +147 -0
- package/dist/cards-J2PGFKEF.js +85 -0
- package/dist/catalog-XECCXRM6.js +65 -0
- package/dist/catalogs-P5KMIMC2.js +130 -0
- package/dist/catalogs-PLBY32BE.js +781 -0
- package/dist/changes-3COSIJLU.js +135 -0
- package/dist/chatgpt-S5EVEKYV.js +47 -0
- package/dist/chats-AN52YVBT.js +279 -0
- package/dist/check-AQO7CMDD.js +107 -0
- package/dist/chunk-2MXDSPUO.js +76 -0
- package/dist/chunk-2SGREP24.js +76 -0
- package/dist/chunk-34FVKJS2.js +64 -0
- package/dist/chunk-364TCROV.js +207 -0
- package/dist/chunk-3J3W23S4.js +592 -0
- package/dist/chunk-3KMYOPBI.js +98 -0
- package/dist/chunk-3N2KAOVM.js +8954 -0
- package/dist/chunk-3WSJGYA3.js +148 -0
- package/dist/chunk-4745PLPI.js +111 -0
- package/dist/chunk-4JS2O2KV.js +89 -0
- package/dist/chunk-4VSD4NSZ.js +188 -0
- package/dist/chunk-4VXQAJRU.js +225 -0
- package/dist/chunk-52IYZCRS.js +476 -0
- package/dist/chunk-5CTNSIWY.js +69 -0
- package/dist/chunk-5G225R4A.js +91 -0
- package/dist/chunk-5LN7GWRE.js +219 -0
- package/dist/chunk-62QMJYML.js +167 -0
- package/dist/chunk-6B4KNOJZ.js +75 -0
- package/dist/chunk-6M77QNJ4.js +69 -0
- package/dist/chunk-7B73TSKJ.js +191 -0
- package/dist/chunk-7O4HFODK.js +26 -0
- package/dist/chunk-7ODQ6ZID.js +66 -0
- package/dist/chunk-7OVCUTEL.js +19 -0
- package/dist/chunk-AFQF6ISC.js +215 -0
- package/dist/chunk-AXTOIHH2.js +74 -0
- package/dist/chunk-B4UVJCJ4.js +229 -0
- package/dist/chunk-C5UFKDAX.js +377 -0
- package/dist/chunk-CREEY2FS.js +455 -0
- package/dist/chunk-DJWEQDBB.js +98 -0
- package/dist/chunk-DLNADMQV.js +547 -0
- package/dist/chunk-DNWP5DL6.js +42 -0
- package/dist/chunk-DW3OPKXI.js +51 -0
- package/dist/chunk-ECJIMIEJ.js +142 -0
- package/dist/chunk-EHIISZYD.js +296 -0
- package/dist/chunk-FBG3JDET.js +97 -0
- package/dist/chunk-FOWT6ENH.js +170 -0
- package/dist/chunk-FSGJSREN.js +2437 -0
- package/dist/chunk-FSGJSREN.js.map +1 -0
- package/dist/chunk-FX3MXXYD.js +91 -0
- package/dist/chunk-GLCHD54W.js +74 -0
- package/dist/chunk-GT77XMOG.js +23 -0
- package/dist/chunk-GXPZJ2QN.js +225 -0
- package/dist/chunk-HPAGYPAF.js +175 -0
- package/dist/chunk-HPDGVK6R.js +324 -0
- package/dist/chunk-HZ3RXKR4.js +3868 -0
- package/dist/chunk-ILEJXJH2.js +1518 -0
- package/dist/chunk-J4ASA24X.js +203 -0
- package/dist/chunk-JCVPZ7CV.js +638 -0
- package/dist/chunk-KDNOMRJA.js +942 -0
- package/dist/chunk-KG7FPYM2.js +64 -0
- package/dist/chunk-KRQ2AXFW.js +191 -0
- package/dist/chunk-L5IYVZM2.js +39 -0
- package/dist/chunk-LHQ6GXNF.js +46 -0
- package/dist/chunk-LS2KEAYJ.js +66 -0
- package/dist/chunk-LURM3KKS.js +94 -0
- package/dist/chunk-MHH7SGLS.js +106 -0
- package/dist/chunk-MZIYRWXL.js +285 -0
- package/dist/chunk-NY5VYGTP.js +97 -0
- package/dist/chunk-O37YK4P6.js +136 -0
- package/dist/chunk-OEJNZSJG.js +207 -0
- package/dist/chunk-OXARC5HH.js +429 -0
- package/dist/chunk-PN72Z2W2.js +56 -0
- package/dist/chunk-PTK7AFEE.js +224 -0
- package/dist/chunk-QJ5TU5J6.js +100 -0
- package/dist/chunk-QJ5TU5J6.js.map +1 -0
- package/dist/chunk-QNLPZOHV.js +84 -0
- package/dist/chunk-QNXDSNOQ.js +544 -0
- package/dist/chunk-QOC3JEUQ.js +363 -0
- package/dist/chunk-R44B522K.js +139 -0
- package/dist/chunk-R5GGTLYE.js +846 -0
- package/dist/chunk-R6T25WTZ.js +344 -0
- package/dist/chunk-RUJS2NOA.js +297 -0
- package/dist/chunk-SDQLZYQG.js +843 -0
- package/dist/chunk-SEC6FPWC.js +494 -0
- package/dist/chunk-SJAUMPL3.js +46 -0
- package/dist/chunk-SNDHR5QA.js +24026 -0
- package/dist/chunk-SP5L7EYC.js +125 -0
- package/dist/chunk-SPBNAGIN.js +1646 -0
- package/dist/chunk-SWNCS2OD.js +333 -0
- package/dist/chunk-T37PAZT2.js +274 -0
- package/dist/chunk-T6PTG6VM.js +5368 -0
- package/dist/chunk-TEKML2NW.js +35 -0
- package/dist/chunk-TRMZQRVV.js +1919 -0
- package/dist/chunk-TTKDFRON.js +149 -0
- package/dist/chunk-U2BPZ27S.js +910 -0
- package/dist/chunk-UPDIBQUC.js +106 -0
- package/dist/chunk-V2XEX2YR.js +84 -0
- package/dist/chunk-V62ZWGCL.js +103 -0
- package/dist/chunk-VCUXAPLM.js +169 -0
- package/dist/chunk-W7C7HZFJ.js +275 -0
- package/dist/chunk-WPAW6EVY.js +166 -0
- package/dist/chunk-WPSLL3S2.js +604 -0
- package/dist/chunk-WQKBEC4I.js +122 -0
- package/dist/chunk-WSYQ6LWB.js +710 -0
- package/dist/chunk-WW6JLISJ.js +200 -0
- package/dist/chunk-X3HPRECW.js +52 -0
- package/dist/chunk-XB2FODWU.js +287 -0
- package/dist/chunk-XGX2WOV2.js +8914 -0
- package/dist/chunk-XJHUSJY6.js +156 -0
- package/dist/chunk-XPDUBDPL.js +25 -0
- package/dist/chunk-XRSRHAEU.js +163 -0
- package/dist/chunk-XVHR2NCG.js +249 -0
- package/dist/chunk-XZWBLUDV.js +831 -0
- package/dist/chunk-YUCGCJKT.js +676 -0
- package/dist/chunk-ZBUIWVF3.js +197 -0
- package/dist/chunk-ZFJ2FQUH.js +131 -0
- package/dist/chunk-ZL5YETKR.js +45 -0
- package/dist/chunk-ZNXP3WNJ.js +58 -0
- package/dist/chunk-ZVXKWLLE.js +1744 -0
- package/dist/claim-NRNO4XCO.js +200 -0
- package/dist/cli.js +47 -44
- package/dist/cli.js.map +1 -1
- package/dist/client-463NKLRT.js +19 -0
- package/dist/code-R4JOQ27J.js +76 -0
- package/dist/companies-4TOBU44J.js +198 -0
- package/dist/company-RK34S3IA.js +308 -0
- package/dist/complete-7BNBQ5AI.js +84 -0
- package/dist/config-GDLHHBJZ.js +88 -0
- package/dist/connect-CRIRSXN3.js +45 -0
- package/dist/content-FCO6MGXW.js +85 -0
- package/dist/conversation-4CQG2B2C.js +96 -0
- package/dist/conversion-report-PDTQTRVB.js +127 -0
- package/dist/conversion-upload-command-MEO4WLZH.js +439 -0
- package/dist/conversion-writes-ZVBOXUIA.js +122 -0
- package/dist/conversions-BND5HYTL.js +78 -0
- package/dist/conversions-POBKTXQF.js +140 -0
- package/dist/copy-writes-GZ744FHU.js +170 -0
- package/dist/countries-TKL5T5JL.js +82 -0
- package/dist/create-BJ7XBNY5.js +62 -0
- package/dist/create-UI2YG2KA.js +135 -0
- package/dist/create-XN4KVB5U.js +210 -0
- package/dist/create-YSGBH6Q4.js +239 -0
- package/dist/creatives-57XIJAEG.js +223 -0
- package/dist/creatives-GTRQAZSB.js +89 -0
- package/dist/creatives-QFSIIFXB.js +58 -0
- package/dist/credentials-KIH6ICDU.js +290 -0
- package/dist/critique-GWRXVXVG.js +1451 -0
- package/dist/critique-OK2ENBOA.js +232 -0
- package/dist/crm-QSHUYXTW.js +323 -0
- package/dist/crm-Y5QTZAHO.js +227 -0
- package/dist/crop-WKTW3EMP.js +113 -0
- package/dist/currency-PTOI5SPU.js +88 -0
- package/dist/custom-conversions-VQ3LBWYV.js +128 -0
- package/dist/customers-2G32E6W7.js +59 -0
- package/dist/decide-X2UAKYXK.js +199 -0
- package/dist/delete-2ZTMTKYD.js +69 -0
- package/dist/delete-4CUEJZ2Z.js +67 -0
- package/dist/delete-FOSTK2RA.js +71 -0
- package/dist/delete-HIAZHA56.js +57 -0
- package/dist/delete-I43JQH2E.js +69 -0
- package/dist/delete-RF44ILYE.js +71 -0
- package/dist/demographics-2UYQW6II.js +141 -0
- package/dist/describe-M6DYXNQC.js +97 -0
- package/dist/describe-OQ6R3EF7.js +97 -0
- package/dist/dimensions-DGYM5E5P.js +101 -0
- package/dist/discard-NKPQ73UM.js +69 -0
- package/dist/discover-XLIH7RCB.js +93 -0
- package/dist/discover-YKMBVSPF.js +172 -0
- package/dist/domain-LUDUZB3F.js +101 -0
- package/dist/download-LL6DL62N.js +172 -0
- package/dist/download-SFWMT7DL.js +299 -0
- package/dist/draft-374Z4MGY.js +103 -0
- package/dist/draft-736FJJWK.js +310 -0
- package/dist/draft-7LPUJZCF.js +283 -0
- package/dist/draft-ME4TNPO7.js +240 -0
- package/dist/draft-MPWR47CG.js +308 -0
- package/dist/draft-R5ND5SWT.js +100 -0
- package/dist/draft-T7TWIFEX.js +335 -0
- package/dist/draft-XAAIGE6Q.js +220 -0
- package/dist/engine/index.js +13 -13
- package/dist/env-DQHY5ODN.js +53 -0
- package/dist/experiment-MO6MT6OJ.js +1397 -0
- package/dist/experiments-OGZV73W6.js +236 -0
- package/dist/export-6Z6QBU6V.js +168 -0
- package/dist/extract-YGOQBOQK.js +113 -0
- package/dist/facets-OLZ7JLFL.js +117 -0
- package/dist/favorites-R3JO4SJJ.js +178 -0
- package/dist/feed-IUMMHM3I.js +177 -0
- package/dist/feedback-ZBEZIIPT.js +111 -0
- package/dist/feedback-record-CZVSPZUR.js +265 -0
- package/dist/fetch-AL44XS4Q.js +139 -0
- package/dist/fetch-K3NRT2L2.js +179 -0
- package/dist/find-ZFIGMRYQ.js +143 -0
- package/dist/find-ZFIGMRYQ.js.map +1 -0
- package/dist/fit-5NVXWXZV.js +65 -0
- package/dist/flows-CAOMVQYZ.js +250 -0
- package/dist/follow-SS374QUW.js +94 -0
- package/dist/follow-competitors-3LTOTTBY.js +112 -0
- package/dist/following-YMA5O3LF.js +113 -0
- package/dist/fonts-E3CNWPD5.js +39 -0
- package/dist/forecast-KOBF5TKM.js +169 -0
- package/dist/forecast-PWGN4ETP.js +121 -0
- package/dist/funding-KLIZ73SS.js +85 -0
- package/dist/funnel-LKF6D7AA.js +397 -0
- package/dist/ga4-XPCE4EK5.js +55 -0
- package/dist/generate-GHIXVLMY.js +263 -0
- package/dist/get-HCGFATFD.js +38 -0
- package/dist/get-JR2KZXW5.js +63 -0
- package/dist/get-RDTJSWSA.js +92 -0
- package/dist/get-SGNT4JG2.js +59 -0
- package/dist/get-TB52FVNV.js +82 -0
- package/dist/get-TGFXZC5S.js +61 -0
- package/dist/get-WS744HAO.js +59 -0
- package/dist/get-YD7GDMDR.js +63 -0
- package/dist/gif-YK5HJXRE.js +102 -0
- package/dist/google-BI45CXMW.js +136 -0
- package/dist/google-FZVOB7HW.js +3267 -0
- package/dist/google-ads-DYZGUM6W.js +198 -0
- package/dist/group-7OWIYAKJ.js +43 -0
- package/dist/group-H6ZYRPE6.js +43 -0
- package/dist/gsc-HI2KXDEU.js +30 -0
- package/dist/history-3EQQHYKT.js +69 -0
- package/dist/history-SJJX6EXI.js +102 -0
- package/dist/history-SQPJ7PPE.js +136 -0
- package/dist/hubspot-MYTV36SM.js +782 -0
- package/dist/icon-HLJCWTR3.js +137 -0
- package/dist/ideas-CVXHFVX7.js +45 -0
- package/dist/images-K7JQ3ORB.js +92 -0
- package/dist/improve-BRC4R6MW.js +86 -0
- package/dist/ingest-4GNJ2PWL.js +26 -0
- package/dist/ingest-5NYBUZE2.js +110 -0
- package/dist/insights-CN3GUTT7.js +132 -0
- package/dist/insights-INIFHYR7.js +439 -0
- package/dist/inspect-25IVRU45.js +192 -0
- package/dist/inspiration-KAXPRINY.js +53 -0
- package/dist/instant-experiences-NMJUWNP3.js +260 -0
- package/dist/intent-3GDLPKKN.js +95 -0
- package/dist/job-2JJNKUHT.js +202 -0
- package/dist/job-create-BNTNZCSP.js +109 -0
- package/dist/job-status-N7RWRDRO.js +74 -0
- package/dist/keep-Z2WH3CKU.js +78 -0
- package/dist/keyword-gap-B2WPVHOB.js +130 -0
- package/dist/keyword-metrics-UDGWN7BO.js +200 -0
- package/dist/keywords-for-site-GEG6AXD3.js +131 -0
- package/dist/landing-BFMRM3HA.js +28 -0
- package/dist/landings-7QRITXZ2.js +151 -0
- package/dist/languages-RZLMZR57.js +55 -0
- package/dist/languages-UJAOPTV2.js +40 -0
- package/dist/launches-4H6ANGTG.js +19 -0
- package/dist/layerize-P5LFIA4X.js +190 -0
- package/dist/leads-MTTOYNPM.js +115 -0
- package/dist/leads-QBWR7FKT.js +540 -0
- package/dist/learn-QPXZZIZZ.js +207 -0
- package/dist/library-VW27X75P.js +211 -0
- package/dist/library-VW27X75P.js.map +1 -0
- package/dist/lighthouse-FGUFJRGR.js +75 -0
- package/dist/line-item-writes-RVOAMJ5R.js +211 -0
- package/dist/line-items-POZRAJLC.js +107 -0
- package/dist/link-IXEZKRM7.js +67 -0
- package/dist/linkedin-5PYG5HEM.js +1328 -0
- package/dist/linkedin-person-EMJXEZYR.js +139 -0
- package/dist/list-4KS7WSUG.js +306 -0
- package/dist/list-7GDMM26I.js +93 -0
- package/dist/list-DVVOP6FM.js +50 -0
- package/dist/list-J5KWXHFO.js +76 -0
- package/dist/list-PT4DVD4U.js +67 -0
- package/dist/list-PTK2HOUY.js +51 -0
- package/dist/list-Q5LVTPQP.js +57 -0
- package/dist/list-UG4V5AM2.js +65 -0
- package/dist/list-XOYU7UTX.js +154 -0
- package/dist/locations-EISZ6JOT.js +40 -0
- package/dist/locations-VJX64ZZR.js +69 -0
- package/dist/log-2F2N24DT.js +95 -0
- package/dist/logo-H2KHGLYD.js +18 -0
- package/dist/lookup-IUQWU346.js +23 -0
- package/dist/make-N5LVJSZD.js +1366 -0
- package/dist/map-QGJZIC5N.js +436 -0
- package/dist/mcp-RSW7KAWP.js +729 -0
- package/dist/media-23IW442U.js +18 -0
- package/dist/media-K5RJXLTN.js +89 -0
- package/dist/media-sources-7R7FO53Y.js +35 -0
- package/dist/members-B6TKGGT5.js +47 -0
- package/dist/meme-QMCUGXUE.js +100 -0
- package/dist/meta-H3KBPU33.js +122 -0
- package/dist/metrics-PRIKXVYZ.js +152 -0
- package/dist/models-M3E4YFCT.js +155 -0
- package/dist/normalize-5B4EQLUX.js +144 -0
- package/dist/normalize-5QIGANTK.js +806 -0
- package/dist/options-K33CJOR6.js +125 -0
- package/dist/organization-A4NFWWWI.js +949 -0
- package/dist/output-U5ZV6PST.js +24 -0
- package/dist/page-XVOUD4VV.js +105 -0
- package/dist/page-photos-SHIGXDYE.js +118 -0
- package/dist/pages-XJF3FBOJ.js +67 -0
- package/dist/performance-L3Q57H4H.js +5556 -0
- package/dist/performance-NVURSEZ6.js +27 -0
- package/dist/pinterest-NA6HGPMB.js +96 -0
- package/dist/pixels-AZCIWWXK.js +109 -0
- package/dist/pixels-THDQD3RF.js +62 -0
- package/dist/plan-VHMWZU7F.js +208 -0
- package/dist/posts-BDMC644W.js +36 -0
- package/dist/preview-BIEVHIDJ.js +218 -0
- package/dist/profile-YHI65VGK.js +159 -0
- package/dist/promoted-tweet-writes-MXXVRLVQ.js +183 -0
- package/dist/promoted-tweets-HFLGXWX2.js +119 -0
- package/dist/properties-ZLY6NYVK.js +101 -0
- package/dist/publish-6ZXFUBGP.js +344 -0
- package/dist/query-ELD7WSFR.js +247 -0
- package/dist/query-HFHTLNDN.js +236 -0
- package/dist/query-WMEX73ZB.js +62 -0
- package/dist/questionnaire-32BQ4ZUX.js +94 -0
- package/dist/read-2HQEZIJW.js +141 -0
- package/dist/reddit-BIHGJPGP.js +29 -0
- package/dist/refresh-4O32S4YR.js +97 -0
- package/dist/refresh-LVV4SPLT.js +42 -0
- package/dist/release-VIPNSPQ5.js +63 -0
- package/dist/relevant-pages-B5SYN575.js +99 -0
- package/dist/remove-2E77743U.js +53 -0
- package/dist/remove-TPOWWFZ6.js +49 -0
- package/dist/reopen-UOBTJBMQ.js +66 -0
- package/dist/rerun-HUFJUOEV.js +95 -0
- package/dist/research-ELM3KHGE.js +72 -0
- package/dist/research-FOJIDMSE.js +265 -0
- package/dist/reset-FTLWUFZK.js +57 -0
- package/dist/reset-GIXXLPHQ.js +57 -0
- package/dist/resolve-QHR5JJTJ.js +124 -0
- package/dist/retry-HNWXJR5U.js +65 -0
- package/dist/retry-NY5KFEDA.js +63 -0
- package/dist/retry-failed-OAH7JQKD.js +45 -0
- package/dist/revenue-JFMUODJO.js +91 -0
- package/dist/rule-writes-QLZNJ7CT.js +525 -0
- package/dist/rules-56E55SGC.js +99 -0
- package/dist/rules-FJHYG4SJ.js +217 -0
- package/dist/rules-add-ZOPOWJMY.js +465 -0
- package/dist/run-7OCCCNJ4.js +70 -0
- package/dist/run-MRC4UVHU.js +69 -0
- package/dist/scaffold-ad-7ADCDQBK.js +1512 -0
- package/dist/scaffold-static-ad-TV5OWISA.js +1010 -0
- package/dist/scaffold-video-LLBDO546.js +884 -0
- package/dist/schedule-OFPSZVZ2.js +67 -0
- package/dist/schedule-ZATNBBWD.js +64 -0
- package/dist/scheduled-agents-EPPP4SCZ.js +55 -0
- package/dist/schema-5Q6VO5MW.js +121 -0
- package/dist/schema-5Q6VO5MW.js.map +1 -0
- package/dist/schema-OGP4DUPP.js +135 -0
- package/dist/scrape-ZHL2BHS7.js +2241 -0
- package/dist/screenshot-ADMRDYWN.js +102 -0
- package/dist/search-6W4HXR2S.js +91 -0
- package/dist/search-6ZWI2NML.js +92 -0
- package/dist/search-CQUS7EOM.js +51 -0
- package/dist/search-HF5ECIYW.js +26 -0
- package/dist/search-MKVVMJ2Q.js +224 -0
- package/dist/search-QUF6LHQ5.js +177 -0
- package/dist/search-copy-O6FDX4HT.js +168 -0
- package/dist/seeds-5TM3O3K3.js +101 -0
- package/dist/select-BRH4QLWU.js +106 -0
- package/dist/sends-43FU3SJN.js +349 -0
- package/dist/sequences-3CEVHGHB.js +146 -0
- package/dist/set-prompt-SYWNE4CS.js +198 -0
- package/dist/setup-links-4STQ5B4P.js +144 -0
- package/dist/shared-HY2VP7PT.js +32 -0
- package/dist/shopify-7LDHCWUQ.js +3958 -0
- package/dist/site-I3NFMPJB.js +180 -0
- package/dist/sitemaps-PLAWVXQL.js +87 -0
- package/dist/sites-WX2IBTZT.js +101 -0
- package/dist/skills-O6EQOAMQ.js +47 -0
- package/dist/sources-CGXHNWJM.js +30 -0
- package/dist/sources-PUZ4WV4Q.js +457 -0
- package/dist/stale-QNIJZTGD.js +76 -0
- package/dist/stats-QQRYOMZA.js +34 -0
- package/dist/status-5OMVGFCH.js +65 -0
- package/dist/sticker-654HS3K2.js +94 -0
- package/dist/stock-35LOO3YN.js +179 -0
- package/dist/studies-Z2ZIWLTO.js +250 -0
- package/dist/studio-NRWLXOFZ.js +49 -0
- package/dist/study-writes-V7BXLTQG.js +470 -0
- package/dist/suggest-JASHCOL5.js +66 -0
- package/dist/sync-6AN67IX3.js +55 -0
- package/dist/sync-RCDODSOD.js +57 -0
- package/dist/sync-URIRLHTS.js +279 -0
- package/dist/sync-definition-EGHEQ57K.js +69 -0
- package/dist/tag-7YMFAZQQ.js +57 -0
- package/dist/tag-manager-LU4GAZ6R.js +43 -0
- package/dist/tags-6A7QOYBI.js +23 -0
- package/dist/tags-JHT3Q6VO.js +227 -0
- package/dist/tags-KSMLT4G2.js +26 -0
- package/dist/tags-MTVZJHCE.js +23 -0
- package/dist/tags-OU32R2SH.js +23 -0
- package/dist/targeting-YBIWD27C.js +762 -0
- package/dist/targeting-constants-QIB3UZHM.js +118 -0
- package/dist/targeting-criteria-NUXZB7NP.js +113 -0
- package/dist/targets-3WIBMP4B.js +106 -0
- package/dist/terms-X4OJWTQH.js +102 -0
- package/dist/testimonials-2NQMY23B.js +32 -0
- package/dist/themes-6KVP3COR.js +95 -0
- package/dist/top-companies-WWNPUJ23.js +111 -0
- package/dist/transcript-P7HKVABU.js +165 -0
- package/dist/translate-YGHRSEX6.js +600 -0
- package/dist/triggers-6EXLTW35.js +144 -0
- package/dist/tweets-X5PTAT6F.js +123 -0
- package/dist/unfollow-S5LHFLGW.js +46 -0
- package/dist/unlink-XTZA474P.js +70 -0
- package/dist/unstage-KEMVI37X.js +88 -0
- package/dist/unstage-YSVQ6DLB.js +96 -0
- package/dist/update-3NA6ABLW.js +101 -0
- package/dist/update-5ZNS2DKP.js +66 -0
- package/dist/update-DDKNKV6M.js +81 -0
- package/dist/update-MDVZ24VQ.js +192 -0
- package/dist/update-USKR3UOC.js +155 -0
- package/dist/upload-IMP5CUY5.js +129 -0
- package/dist/upload-SYFB2VTJ.js +150 -0
- package/dist/upscale-P5EYUVOZ.js +109 -0
- package/dist/url-options-6MFRIDNA.js +131 -0
- package/dist/url-params-Y5XQSDEF.js +101 -0
- package/dist/use-D3RBWLJO.js +95 -0
- package/dist/validate-JX4FT7PL.js +122 -0
- package/dist/variant-JQVZUUA4.js +338 -0
- package/dist/videos-EHDZ46UQ.js +41 -0
- package/dist/view-IKKRJ5YD.js +121 -0
- package/dist/viewer-check-5GREZIVJ.js +83 -0
- package/dist/web-7TPDDBI6.js +143 -0
- package/dist/winners-4PKEVMUC.js +113 -0
- package/dist/winning-ads-H7ZE5AQW.js +86 -0
- package/dist/write-commands-CTLF2M6L.js +713 -0
- package/dist/write-commands-FIS6Y2MN.js +206 -0
- package/dist/write-commands-R5SN6CVQ.js +1172 -0
- package/dist/write-commands-V77MD5SC.js +1525 -0
- package/dist/x-EMLFCHSG.js +47 -0
- package/package.json +3 -1
- package/dist/account-HDSDPK4L.js +0 -82
- package/dist/account-JXUUHDEB.js +0 -139
- package/dist/account-YDA4MRIK.js +0 -82
- package/dist/account-assets-3SIBPJXJ.js +0 -290
- package/dist/account-level-46AIGZXA.js +0 -611
- package/dist/account-reads-5VPDX6NF.js +0 -219
- package/dist/account-users-KWVYRT2M.js +0 -64
- package/dist/account-writes-D3ELXDOF.js +0 -68
- package/dist/accounts-6WPNPMFP.js +0 -701
- package/dist/accounts-D6FP4DC2.js +0 -76
- package/dist/accounts-GY7HP6ER.js +0 -80
- package/dist/accounts-JOHZTB3B.js +0 -114
- package/dist/accounts-LRS3BRF6.js +0 -115
- package/dist/actions-ATTUAZZ5.js +0 -55
- package/dist/active-entities-CM3HUCNK.js +0 -103
- package/dist/activecampaign-A7AMIRYU.js +0 -938
- package/dist/activities-NYWRMNCH.js +0 -75
- package/dist/ad-group-writes-QMLGO62B.js +0 -172
- package/dist/ad-groups-5KQWUB7J.js +0 -70
- package/dist/ad-writes-Y6BNCZGK.js +0 -176
- package/dist/add-A5VX5UUP.js +0 -80
- package/dist/add-HOA4WXER.js +0 -97
- package/dist/add-OHYKPUG7.js +0 -107
- package/dist/add-XGUD3TTD.js +0 -81
- package/dist/add-YXTVT2IS.js +0 -148
- package/dist/add-ZEPO6CVT.js +0 -305
- package/dist/add-accounts-4FIDJDNQ.js +0 -91
- package/dist/ads-DRMVHMJH.js +0 -115
- package/dist/ads-EDG3IYLY.js +0 -128
- package/dist/ads-F7ARRWCB.js +0 -79
- package/dist/ads-PNSXXDHI.js +0 -48
- package/dist/adsets-XE5S6J5S.js +0 -182
- package/dist/advertisers-523UPXDM.js +0 -123
- package/dist/advertisers-JIEBRSCX.js +0 -125
- package/dist/analytics-4KUANCID.js +0 -2437
- package/dist/analytics-TRUVVR6I.js +0 -447
- package/dist/animate-S4KGFV36.js +0 -480
- package/dist/approved-A2YR4M4Z.js +0 -73
- package/dist/asset-writes-5TAUIKSN.js +0 -50
- package/dist/assign-2AW5GY3T.js +0 -80
- package/dist/audience-size-VHFMQEMF.js +0 -76
- package/dist/audience-writes-P63WFDXJ.js +0 -327
- package/dist/audiences-53FR4K5I.js +0 -85
- package/dist/audiences-N6DE6EAV.js +0 -280
- package/dist/audiences-U6MQRRTP.js +0 -86
- package/dist/audit-PI35QDVW.js +0 -88
- package/dist/audit-WG6M3CXB.js +0 -154
- package/dist/autocomplete-WHNI5BQM.js +0 -114
- package/dist/avatars-WECPBQ4T.js +0 -38
- package/dist/bid-pricing-WVHPUM74.js +0 -103
- package/dist/brand-TNZRFKI4.js +0 -22
- package/dist/brief-F56MVJHA.js +0 -543
- package/dist/businesses-RRYQYTG4.js +0 -54
- package/dist/campaign-groups-OLJ5567X.js +0 -99
- package/dist/campaign-writes-2DVIWSWU.js +0 -168
- package/dist/campaign-writes-6LU3LDDY.js +0 -176
- package/dist/campaigns-7YE5UYPS.js +0 -78
- package/dist/campaigns-DDUXFR77.js +0 -130
- package/dist/campaigns-MJ64UJTS.js +0 -113
- package/dist/campaigns-PHSRKXVZ.js +0 -111
- package/dist/canvas-FUHHYUO7.js +0 -46
- package/dist/capabilities-5MXUVZJV.js +0 -147
- package/dist/cards-RZKM5TMV.js +0 -85
- package/dist/catalog-PKYW67IO.js +0 -65
- package/dist/catalogs-2GNJYFSF.js +0 -130
- package/dist/catalogs-A6CHXN5B.js +0 -781
- package/dist/changes-UQYFPZWO.js +0 -135
- package/dist/chatgpt-6PP4HANG.js +0 -47
- package/dist/chats-FVR35ZQ3.js +0 -279
- package/dist/check-4P2IVABH.js +0 -107
- package/dist/chunk-2BW4P45O.js +0 -203
- package/dist/chunk-2MCQ3UHO.js +0 -74
- package/dist/chunk-2MCQ3UHO.js.map +0 -1
- package/dist/chunk-2R77YWFG.js +0 -58
- package/dist/chunk-2UQJ5BDJ.js +0 -207
- package/dist/chunk-3EBK2267.js +0 -74
- package/dist/chunk-3P7TP3GP.js +0 -76
- package/dist/chunk-3U4T4CKO.js +0 -249
- package/dist/chunk-3XG6I4K6.js +0 -287
- package/dist/chunk-47RFRYEP.js +0 -197
- package/dist/chunk-4LV5JE4Z.js +0 -188
- package/dist/chunk-4MPB36CQ.js +0 -544
- package/dist/chunk-4U7HXXSA.js +0 -229
- package/dist/chunk-5OQKC5AV.js +0 -592
- package/dist/chunk-65QGMY3C.js +0 -51
- package/dist/chunk-735ZOMSR.js +0 -84
- package/dist/chunk-7EHBCACP.js +0 -156
- package/dist/chunk-7PMGAOHZ.js +0 -52
- package/dist/chunk-ABK536AV.js +0 -148
- package/dist/chunk-ALTTFAER.js +0 -377
- package/dist/chunk-AQ2XSUIG.js +0 -296
- package/dist/chunk-ARXNQRKT.js +0 -275
- package/dist/chunk-AYAVYXSL.js +0 -638
- package/dist/chunk-AZ7AFTSU.js +0 -64
- package/dist/chunk-BAK2MRBU.js +0 -46
- package/dist/chunk-BBQ4WZSA.js +0 -98
- package/dist/chunk-BKIE7DBG.js +0 -103
- package/dist/chunk-BYNBZIHS.js +0 -98
- package/dist/chunk-CK2SDG7U.js +0 -64
- package/dist/chunk-DEKAW43P.js +0 -111
- package/dist/chunk-DMGLSVZF.js +0 -547
- package/dist/chunk-ENGKUMTR.js +0 -1518
- package/dist/chunk-FBTECDEZ.js +0 -163
- package/dist/chunk-FLSWMHI2.js +0 -910
- package/dist/chunk-FMMSQIVK.js +0 -122
- package/dist/chunk-FZSJFSDC.js +0 -19
- package/dist/chunk-GGUQP6KI.js +0 -476
- package/dist/chunk-GOTPUACV.js +0 -846
- package/dist/chunk-GS4MMLXY.js +0 -191
- package/dist/chunk-GSVG7XT3.js +0 -297
- package/dist/chunk-GW3KJMSK.js +0 -200
- package/dist/chunk-GX75UQGS.js +0 -139
- package/dist/chunk-H4DBWD3O.js +0 -75
- package/dist/chunk-HQYXRF7E.js +0 -604
- package/dist/chunk-HXALY3VB.js +0 -45
- package/dist/chunk-I6QJJ7OY.js +0 -1646
- package/dist/chunk-ICHXD4IB.js +0 -344
- package/dist/chunk-IQ3MYXCJ.js +0 -676
- package/dist/chunk-IRDKHNKO.js +0 -142
- package/dist/chunk-IXPYC4D2.js +0 -170
- package/dist/chunk-JHEWSMOS.js +0 -175
- package/dist/chunk-JNW5S4ET.js +0 -125
- package/dist/chunk-JRQI6EVP.js +0 -97
- package/dist/chunk-JWMPFTEF.js +0 -8954
- package/dist/chunk-K6HH2KF3.js +0 -84
- package/dist/chunk-KLO366YG.js +0 -191
- package/dist/chunk-KNSUNB2Z.js +0 -207
- package/dist/chunk-L55PHMSR.js +0 -2319
- package/dist/chunk-L55PHMSR.js.map +0 -1
- package/dist/chunk-L5RAYYEF.js +0 -225
- package/dist/chunk-M7MLFR2S.js +0 -136
- package/dist/chunk-MF3BTAT6.js +0 -843
- package/dist/chunk-MIPZEBHV.js +0 -94
- package/dist/chunk-MJ4MJZV3.js +0 -710
- package/dist/chunk-MR3YYIOQ.js +0 -69
- package/dist/chunk-NAYO267Q.js +0 -219
- package/dist/chunk-NBXZHTSR.js +0 -42
- package/dist/chunk-NDFLI64C.js +0 -225
- package/dist/chunk-NE2F42MI.js +0 -149
- package/dist/chunk-NGHWLV3C.js +0 -35
- package/dist/chunk-NHQIGCFL.js +0 -274
- package/dist/chunk-NZ42DEU7.js +0 -3868
- package/dist/chunk-OA2IUTXA.js +0 -66
- package/dist/chunk-OGGE57JI.js +0 -76
- package/dist/chunk-OVBZ26PE.js +0 -89
- package/dist/chunk-PESH2VF7.js +0 -494
- package/dist/chunk-PWYGIUNB.js +0 -91
- package/dist/chunk-QBFJGCWA.js +0 -166
- package/dist/chunk-QDGDA2YD.js +0 -66
- package/dist/chunk-QKMMQPAJ.js +0 -224
- package/dist/chunk-QOOOYHMN.js +0 -91
- package/dist/chunk-R2QZBA7P.js +0 -8914
- package/dist/chunk-RL6UQXX7.js +0 -23
- package/dist/chunk-SBQQHP5H.js +0 -46
- package/dist/chunk-SV2NFDH2.js +0 -56
- package/dist/chunk-SZJKURRJ.js +0 -5368
- package/dist/chunk-UHQ2H3NQ.js +0 -363
- package/dist/chunk-UIUZXQV7.js +0 -74
- package/dist/chunk-UTFSUMLU.js +0 -25
- package/dist/chunk-UYVCBTC5.js +0 -97
- package/dist/chunk-V6AAOAMM.js +0 -215
- package/dist/chunk-VJINC2Q3.js +0 -131
- package/dist/chunk-VXXVPUBA.js +0 -169
- package/dist/chunk-W4NFBCCR.js +0 -167
- package/dist/chunk-W52LH3J3.js +0 -429
- package/dist/chunk-W5WKPVCJ.js +0 -831
- package/dist/chunk-WCJ3JTLF.js +0 -333
- package/dist/chunk-WTLNH34U.js +0 -1744
- package/dist/chunk-WVVPZJNX.js +0 -106
- package/dist/chunk-X3BOXZVP.js +0 -1919
- package/dist/chunk-X7DMNLDD.js +0 -324
- package/dist/chunk-XOHLV5MO.js +0 -69
- package/dist/chunk-YUYJH6OZ.js +0 -106
- package/dist/chunk-YYBP65UD.js +0 -26
- package/dist/chunk-Z5PSSFN7.js +0 -455
- package/dist/chunk-Z7MOJPTA.js +0 -39
- package/dist/chunk-ZKIWDT6R.js +0 -942
- package/dist/chunk-ZN5CI4CP.js +0 -285
- package/dist/chunk-ZRXFY2JM.js +0 -24026
- package/dist/claim-B6IX5MUB.js +0 -200
- package/dist/client-CRKH3ZYG.js +0 -19
- package/dist/code-OCSD6BPR.js +0 -76
- package/dist/companies-U4APTF2Z.js +0 -198
- package/dist/company-WFVBYXKK.js +0 -308
- package/dist/complete-FUPSG7MH.js +0 -84
- package/dist/config-6FHXEEN7.js +0 -88
- package/dist/connect-2TWKL3DQ.js +0 -45
- package/dist/content-7N2FPVPA.js +0 -85
- package/dist/conversation-7VQ7CGVT.js +0 -96
- package/dist/conversion-report-6IQKXWFU.js +0 -127
- package/dist/conversion-upload-command-TYGIB7XJ.js +0 -439
- package/dist/conversion-writes-UQU3QJTF.js +0 -122
- package/dist/conversions-P2A6R4FG.js +0 -140
- package/dist/conversions-ZP2SKL36.js +0 -78
- package/dist/copy-writes-GUOL2QUD.js +0 -170
- package/dist/countries-TKMYMMJN.js +0 -82
- package/dist/create-KE3GM4W6.js +0 -62
- package/dist/create-KKURENQ7.js +0 -210
- package/dist/create-M7OTWZ2W.js +0 -135
- package/dist/create-XLQEQYVN.js +0 -239
- package/dist/creatives-AXMG777O.js +0 -223
- package/dist/creatives-BGYARLCC.js +0 -89
- package/dist/creatives-VR3N5A3X.js +0 -58
- package/dist/credentials-HTPDDOYP.js +0 -290
- package/dist/critique-EZJMYQLC.js +0 -1451
- package/dist/critique-Q5ZZ6PKB.js +0 -232
- package/dist/crm-5QOSCQWL.js +0 -227
- package/dist/crm-YLSUKW6N.js +0 -323
- package/dist/crop-S5NAICO6.js +0 -113
- package/dist/currency-SVEUNKHP.js +0 -88
- package/dist/custom-conversions-SUXA7KSN.js +0 -128
- package/dist/customers-OGKISQAS.js +0 -59
- package/dist/decide-HTTX2ZIT.js +0 -199
- package/dist/delete-23FUCSTE.js +0 -67
- package/dist/delete-DGH3T6QI.js +0 -71
- package/dist/delete-JBGVVAHP.js +0 -71
- package/dist/delete-M7YWEURA.js +0 -69
- package/dist/delete-MD6QBKGM.js +0 -69
- package/dist/delete-OPIN5KCK.js +0 -57
- package/dist/demographics-AFNPWEZP.js +0 -141
- package/dist/describe-EASPZ57E.js +0 -97
- package/dist/describe-LZYLJXBH.js +0 -97
- package/dist/dimensions-6JA6LUUD.js +0 -101
- package/dist/discard-UKPRZTQT.js +0 -69
- package/dist/discover-2ZX3DYSF.js +0 -172
- package/dist/discover-B652QR7E.js +0 -93
- package/dist/domain-6TJPO4WO.js +0 -101
- package/dist/download-D6HQCD5H.js +0 -299
- package/dist/download-TBPG3ZIH.js +0 -172
- package/dist/draft-2EO63W4K.js +0 -308
- package/dist/draft-6JUQWX26.js +0 -103
- package/dist/draft-ALSOCILF.js +0 -310
- package/dist/draft-BAWIN2IN.js +0 -335
- package/dist/draft-KYO43IJD.js +0 -220
- package/dist/draft-L5AL6STE.js +0 -100
- package/dist/draft-PJT5TSFQ.js +0 -240
- package/dist/draft-QUXRJRNY.js +0 -283
- package/dist/env-OXMIRJRU.js +0 -53
- package/dist/experiment-XNEYJVLH.js +0 -1397
- package/dist/experiments-QXAC5BPW.js +0 -236
- package/dist/export-75ADGAGR.js +0 -168
- package/dist/extract-V26NW6CA.js +0 -113
- package/dist/facets-7IDDCZIY.js +0 -117
- package/dist/favorites-V6HWSOHN.js +0 -178
- package/dist/feed-K2NECCHS.js +0 -177
- package/dist/feedback-ZWFOBIGU.js +0 -111
- package/dist/feedback-record-ZZRR4LUM.js +0 -265
- package/dist/fetch-HYGMTCHK.js +0 -179
- package/dist/fetch-LQMNRF3B.js +0 -139
- package/dist/find-FTQM3ZQH.js +0 -134
- package/dist/find-FTQM3ZQH.js.map +0 -1
- package/dist/fit-KDY7PZFL.js +0 -65
- package/dist/flows-U646JOQN.js +0 -250
- package/dist/follow-RNVJZVFG.js +0 -94
- package/dist/follow-competitors-DF73HPQT.js +0 -112
- package/dist/following-WX7DHO5K.js +0 -113
- package/dist/fonts-6RIJJ222.js +0 -39
- package/dist/forecast-4NJXBMZV.js +0 -121
- package/dist/forecast-IECMUBL2.js +0 -169
- package/dist/funding-67ZORHHQ.js +0 -85
- package/dist/funnel-OFJ5XMOU.js +0 -397
- package/dist/ga4-G5NKZI3Y.js +0 -55
- package/dist/generate-VQTLPEYW.js +0 -263
- package/dist/get-6JWGIPN2.js +0 -38
- package/dist/get-EEBGRH4P.js +0 -61
- package/dist/get-GD5MRH7N.js +0 -59
- package/dist/get-KUOCL3IX.js +0 -82
- package/dist/get-LHHYARGV.js +0 -63
- package/dist/get-MINQPB73.js +0 -59
- package/dist/get-N6IMHWZE.js +0 -92
- package/dist/get-VBLMBPFJ.js +0 -63
- package/dist/gif-QQR5VJS7.js +0 -102
- package/dist/google-3EREXOK2.js +0 -136
- package/dist/google-LVOGKNDV.js +0 -3267
- package/dist/google-ads-RIIV4EJI.js +0 -198
- package/dist/group-JUYQHY5I.js +0 -43
- package/dist/group-YWHTJLS7.js +0 -43
- package/dist/gsc-7D62WFOR.js +0 -30
- package/dist/history-7OLO7HIP.js +0 -136
- package/dist/history-JK6S5KWG.js +0 -69
- package/dist/history-VFA6IVKN.js +0 -102
- package/dist/hubspot-IMLZUTT3.js +0 -782
- package/dist/icon-REVUB32Y.js +0 -137
- package/dist/ideas-ZUXLYR6Y.js +0 -45
- package/dist/images-WNMQFAC3.js +0 -92
- package/dist/improve-RHY7SH7B.js +0 -86
- package/dist/ingest-FKC5PBBE.js +0 -110
- package/dist/ingest-L5YC6U2N.js +0 -26
- package/dist/insights-7CCOJ4G6.js +0 -132
- package/dist/insights-VW475N6G.js +0 -439
- package/dist/inspect-2XJ6LLSJ.js +0 -192
- package/dist/inspiration-ZA6MI7TK.js +0 -53
- package/dist/instant-experiences-JJJKZAQQ.js +0 -260
- package/dist/intent-VGQHKKNW.js +0 -95
- package/dist/job-PW4MM7ZV.js +0 -202
- package/dist/job-create-EOBCQRUK.js +0 -109
- package/dist/job-status-KZDFSCJ5.js +0 -74
- package/dist/keep-IYR4KE2G.js +0 -78
- package/dist/keyword-gap-JKC3U3OS.js +0 -130
- package/dist/keyword-metrics-OYHBOWA3.js +0 -200
- package/dist/keywords-for-site-EUTBLXRT.js +0 -131
- package/dist/landing-PRG5PT7J.js +0 -28
- package/dist/landings-433WRB5F.js +0 -151
- package/dist/languages-JR3RSGUP.js +0 -40
- package/dist/languages-PK5RHB5H.js +0 -55
- package/dist/launches-LXN6XOAD.js +0 -19
- package/dist/layerize-5DBAU2EQ.js +0 -190
- package/dist/leads-2BXRQDT5.js +0 -540
- package/dist/leads-KXCGAJ34.js +0 -115
- package/dist/learn-N2XDH4XA.js +0 -207
- package/dist/library-QF7RMDHB.js +0 -109
- package/dist/library-QF7RMDHB.js.map +0 -1
- package/dist/lighthouse-BQFFFDV6.js +0 -75
- package/dist/line-item-writes-4YZNT3VI.js +0 -211
- package/dist/line-items-FSQPXOKE.js +0 -107
- package/dist/link-ITXPWVMH.js +0 -67
- package/dist/linkedin-Z6M3YEAQ.js +0 -1328
- package/dist/linkedin-person-IK2MWL7Y.js +0 -139
- package/dist/list-22PEYOWN.js +0 -76
- package/dist/list-33E2RTA5.js +0 -65
- package/dist/list-7SVSDERS.js +0 -57
- package/dist/list-CXXKUKCX.js +0 -51
- package/dist/list-EVIRF2CY.js +0 -154
- package/dist/list-VJRTBW6A.js +0 -306
- package/dist/list-WA3PQEWJ.js +0 -67
- package/dist/list-YLS62E6D.js +0 -50
- package/dist/list-Z7NOJY3P.js +0 -93
- package/dist/locations-N5TZTS5F.js +0 -40
- package/dist/locations-QRISCNMR.js +0 -69
- package/dist/log-VFGFY5PT.js +0 -95
- package/dist/logo-ZWRHTSRM.js +0 -18
- package/dist/lookup-SX6GZMO5.js +0 -23
- package/dist/make-DRWMUES6.js +0 -1366
- package/dist/map-3YMLKUNL.js +0 -436
- package/dist/mcp-MIZR2NFZ.js +0 -729
- package/dist/media-KXBWT2YJ.js +0 -18
- package/dist/media-ZUNR6AMT.js +0 -89
- package/dist/media-sources-RKIBHCTU.js +0 -35
- package/dist/members-XMHVOMNT.js +0 -47
- package/dist/meme-HZOKMZJZ.js +0 -100
- package/dist/meta-5ODNL2LA.js +0 -122
- package/dist/metrics-NCSG7SLD.js +0 -152
- package/dist/models-2NPHMHN7.js +0 -155
- package/dist/normalize-CBPJIIXG.js +0 -806
- package/dist/normalize-PSPLM7OO.js +0 -144
- package/dist/options-5KONPMEL.js +0 -125
- package/dist/organization-BU6WIFXV.js +0 -949
- package/dist/output-UPGKR3FB.js +0 -24
- package/dist/page-GP5FFVQ3.js +0 -105
- package/dist/page-photos-CJIFQDW5.js +0 -118
- package/dist/pages-NJN2E5HU.js +0 -67
- package/dist/performance-74OQO2QQ.js +0 -27
- package/dist/performance-TIA3O7YO.js +0 -5556
- package/dist/pinterest-TLKIRVDC.js +0 -96
- package/dist/pixels-COONSHMC.js +0 -62
- package/dist/pixels-E7UYF4KE.js +0 -109
- package/dist/plan-RNDLIOZY.js +0 -208
- package/dist/posts-PPSQ726T.js +0 -36
- package/dist/preview-QGLUDJ3A.js +0 -218
- package/dist/profile-JVVIISSQ.js +0 -159
- package/dist/promoted-tweet-writes-IYDFXFVR.js +0 -183
- package/dist/promoted-tweets-A42JISSP.js +0 -119
- package/dist/properties-7P6GSOVE.js +0 -101
- package/dist/publish-C3NUBIID.js +0 -344
- package/dist/query-DI7ZGS4A.js +0 -236
- package/dist/query-G4L42FHT.js +0 -62
- package/dist/query-IO5NESSN.js +0 -247
- package/dist/questionnaire-7YHG733R.js +0 -94
- package/dist/read-ESTTW6WU.js +0 -141
- package/dist/reddit-VMNGERE6.js +0 -29
- package/dist/refresh-EBRMXZAC.js +0 -97
- package/dist/refresh-ZCKZ6RPU.js +0 -42
- package/dist/release-MKGBYUKY.js +0 -63
- package/dist/relevant-pages-IVHAKIOI.js +0 -99
- package/dist/remove-EHHTOC7T.js +0 -53
- package/dist/remove-PPLOR5BM.js +0 -49
- package/dist/reopen-ILUWK3W3.js +0 -66
- package/dist/rerun-367PVEIF.js +0 -95
- package/dist/research-7BWH4VVV.js +0 -72
- package/dist/research-VDSOAQ77.js +0 -265
- package/dist/reset-VAKJGC3Q.js +0 -57
- package/dist/reset-X2JMHREN.js +0 -57
- package/dist/resolve-7OXBK4CU.js +0 -124
- package/dist/retry-2L2B3FOJ.js +0 -65
- package/dist/retry-GJBALRAZ.js +0 -63
- package/dist/retry-failed-JGONEZFL.js +0 -45
- package/dist/revenue-H66XC7JC.js +0 -91
- package/dist/rule-writes-AHDYOYVO.js +0 -525
- package/dist/rules-5HIC2F34.js +0 -217
- package/dist/rules-PJJSIQWM.js +0 -99
- package/dist/rules-add-UFY7TAO3.js +0 -465
- package/dist/run-6PDML7YJ.js +0 -70
- package/dist/run-QBXFCGML.js +0 -69
- package/dist/scaffold-ad-KOBSZMKJ.js +0 -1512
- package/dist/scaffold-static-ad-2I7TXF7L.js +0 -1010
- package/dist/scaffold-video-P5UOTXWT.js +0 -884
- package/dist/schedule-JNBK267N.js +0 -64
- package/dist/schedule-N5NXFCIW.js +0 -67
- package/dist/scheduled-agents-274ZTTUZ.js +0 -55
- package/dist/schema-7HR57YTC.js +0 -135
- package/dist/schema-YO5VLVDS.js +0 -69
- package/dist/schema-YO5VLVDS.js.map +0 -1
- package/dist/scrape-Z3W44ZH2.js +0 -2241
- package/dist/screenshot-FC4WIRNT.js +0 -102
- package/dist/search-22MOVZ2F.js +0 -26
- package/dist/search-33EMRTMI.js +0 -177
- package/dist/search-BZ7TSFYU.js +0 -92
- package/dist/search-DRD2GYJZ.js +0 -91
- package/dist/search-PQV7IO4M.js +0 -224
- package/dist/search-ZWQJCYAB.js +0 -51
- package/dist/search-copy-HOHYX6GF.js +0 -168
- package/dist/seeds-K3K6WB5G.js +0 -101
- package/dist/select-3ZRWAYT7.js +0 -106
- package/dist/sends-2BR7A434.js +0 -349
- package/dist/sequences-KT7CMFU6.js +0 -146
- package/dist/set-prompt-SCSC7BRO.js +0 -198
- package/dist/setup-links-BEIHAXVR.js +0 -144
- package/dist/shared-S7ZPZXF5.js +0 -32
- package/dist/shopify-XDDDUQTQ.js +0 -3958
- package/dist/site-DWVWM3HD.js +0 -180
- package/dist/sitemaps-QKQB64M2.js +0 -87
- package/dist/sites-MB7H2BNT.js +0 -101
- package/dist/skills-RCXAZVMB.js +0 -47
- package/dist/sources-74OM3T4V.js +0 -457
- package/dist/sources-O7ZOL5YR.js +0 -30
- package/dist/stale-WAKIZSQS.js +0 -76
- package/dist/stats-TGAKUBDH.js +0 -34
- package/dist/status-JOIUSIE7.js +0 -65
- package/dist/sticker-BWTRJKQ4.js +0 -94
- package/dist/stock-SKFA4HSO.js +0 -179
- package/dist/studies-FXX4XW4A.js +0 -250
- package/dist/studio-FJL2TIZK.js +0 -49
- package/dist/study-writes-H6RDMXF3.js +0 -470
- package/dist/suggest-6DLRLGOR.js +0 -66
- package/dist/sync-EFIN4VNC.js +0 -55
- package/dist/sync-NJKQVHO7.js +0 -279
- package/dist/sync-XBCQXUD7.js +0 -57
- package/dist/sync-definition-2BQUWH3Y.js +0 -69
- package/dist/tag-VIE22YTB.js +0 -57
- package/dist/tag-manager-M2Z6TEV6.js +0 -43
- package/dist/tags-3YUICYEG.js +0 -227
- package/dist/tags-AQ2JGXPQ.js +0 -23
- package/dist/tags-AXIDVYMK.js +0 -23
- package/dist/tags-HISOVNNV.js +0 -23
- package/dist/tags-NSCLNPLU.js +0 -26
- package/dist/targeting-URLZVNS2.js +0 -762
- package/dist/targeting-constants-WHK63KKJ.js +0 -118
- package/dist/targeting-criteria-DFJQKQV4.js +0 -113
- package/dist/targets-NQKCNVQ7.js +0 -106
- package/dist/terms-VIAM2BO5.js +0 -102
- package/dist/testimonials-K5D2KRYK.js +0 -32
- package/dist/themes-CIXQPTFX.js +0 -95
- package/dist/top-companies-3M7H5NPQ.js +0 -111
- package/dist/transcript-CQTAZJK4.js +0 -165
- package/dist/translate-D2SJCT7D.js +0 -600
- package/dist/triggers-THBRMWM6.js +0 -144
- package/dist/tweets-7GVNM564.js +0 -123
- package/dist/unfollow-STHFAGMU.js +0 -46
- package/dist/unlink-WWPY4336.js +0 -70
- package/dist/unstage-HTYFDR33.js +0 -88
- package/dist/unstage-VLEPSA6I.js +0 -96
- package/dist/update-AMTTYSZP.js +0 -66
- package/dist/update-EM6EZQ73.js +0 -81
- package/dist/update-FMK63TCD.js +0 -192
- package/dist/update-HCQFGRDE.js +0 -101
- package/dist/update-N3DTFTQE.js +0 -155
- package/dist/upload-BCUR7GMG.js +0 -129
- package/dist/upload-JTX776YT.js +0 -150
- package/dist/upscale-G33XUZPK.js +0 -109
- package/dist/url-options-BSU46PR2.js +0 -131
- package/dist/url-params-YWPEV5V5.js +0 -101
- package/dist/use-LVOEX2T3.js +0 -95
- package/dist/validate-GZYVVNHQ.js +0 -122
- package/dist/variant-IMO5ZRNC.js +0 -338
- package/dist/videos-L5BDS2M4.js +0 -41
- package/dist/view-IYY37LYK.js +0 -121
- package/dist/viewer-check-DBQ6T3R5.js +0 -83
- package/dist/web-62AJC2EU.js +0 -143
- package/dist/winners-BYBOZ2XZ.js +0 -113
- package/dist/winning-ads-OHVZERTH.js +0 -86
- package/dist/write-commands-2VKVFEEK.js +0 -206
- package/dist/write-commands-3YFTN6OQ.js +0 -713
- package/dist/write-commands-AANGPJ5F.js +0 -1172
- package/dist/write-commands-BWWXFT2R.js +0 -1525
- package/dist/x-ACDJXCOY.js +0 -47
- /package/dist/{account-YDA4MRIK.js.map → account-2G3IT7J4.js.map} +0 -0
- /package/dist/{account-JXUUHDEB.js.map → account-APMJVG2F.js.map} +0 -0
- /package/dist/{account-HDSDPK4L.js.map → account-ULC5N7SI.js.map} +0 -0
- /package/dist/{account-assets-3SIBPJXJ.js.map → account-assets-TAUEBCY5.js.map} +0 -0
- /package/dist/{account-level-46AIGZXA.js.map → account-level-2MYDHOID.js.map} +0 -0
- /package/dist/{account-reads-5VPDX6NF.js.map → account-reads-FRFI6OHK.js.map} +0 -0
- /package/dist/{account-users-KWVYRT2M.js.map → account-users-PINZLBT7.js.map} +0 -0
- /package/dist/{account-writes-D3ELXDOF.js.map → account-writes-WRGJC7VU.js.map} +0 -0
- /package/dist/{accounts-GY7HP6ER.js.map → accounts-2KFG33EX.js.map} +0 -0
- /package/dist/{accounts-LRS3BRF6.js.map → accounts-5754XUS3.js.map} +0 -0
- /package/dist/{accounts-6WPNPMFP.js.map → accounts-MHPNZW3W.js.map} +0 -0
- /package/dist/{accounts-JOHZTB3B.js.map → accounts-MTNBMXHD.js.map} +0 -0
- /package/dist/{accounts-D6FP4DC2.js.map → accounts-VIAQC3PA.js.map} +0 -0
- /package/dist/{actions-ATTUAZZ5.js.map → actions-33IZOT5C.js.map} +0 -0
- /package/dist/{active-entities-CM3HUCNK.js.map → active-entities-JR5B32X2.js.map} +0 -0
- /package/dist/{activecampaign-A7AMIRYU.js.map → activecampaign-BV5GZFVR.js.map} +0 -0
- /package/dist/{activities-NYWRMNCH.js.map → activities-MJMAV3SI.js.map} +0 -0
- /package/dist/{ad-group-writes-QMLGO62B.js.map → ad-group-writes-W6RCMYLC.js.map} +0 -0
- /package/dist/{ad-groups-5KQWUB7J.js.map → ad-groups-XAI2Z62X.js.map} +0 -0
- /package/dist/{ad-writes-Y6BNCZGK.js.map → ad-writes-IGWZRTXY.js.map} +0 -0
- /package/dist/{add-YXTVT2IS.js.map → add-4PJDIW2M.js.map} +0 -0
- /package/dist/{add-OHYKPUG7.js.map → add-DBCN33GH.js.map} +0 -0
- /package/dist/{add-HOA4WXER.js.map → add-KB7O7NSB.js.map} +0 -0
- /package/dist/{add-XGUD3TTD.js.map → add-PRU32PQN.js.map} +0 -0
- /package/dist/{add-A5VX5UUP.js.map → add-UZDOQAJL.js.map} +0 -0
- /package/dist/{add-ZEPO6CVT.js.map → add-WDX66JSM.js.map} +0 -0
- /package/dist/{add-accounts-4FIDJDNQ.js.map → add-accounts-ZWXG6HLM.js.map} +0 -0
- /package/dist/{ads-F7ARRWCB.js.map → ads-255V76SZ.js.map} +0 -0
- /package/dist/{ads-EDG3IYLY.js.map → ads-I6I4MYQH.js.map} +0 -0
- /package/dist/{ads-DRMVHMJH.js.map → ads-NNKUR4HG.js.map} +0 -0
- /package/dist/{ads-PNSXXDHI.js.map → ads-O4RL4JXD.js.map} +0 -0
- /package/dist/{adsets-XE5S6J5S.js.map → adsets-VO5C7PDM.js.map} +0 -0
- /package/dist/{advertisers-JIEBRSCX.js.map → advertisers-BPJWOY7I.js.map} +0 -0
- /package/dist/{advertisers-523UPXDM.js.map → advertisers-SJO6JYIO.js.map} +0 -0
- /package/dist/{analytics-4KUANCID.js.map → analytics-OUNKG2FW.js.map} +0 -0
- /package/dist/{analytics-TRUVVR6I.js.map → analytics-TXPEXLPQ.js.map} +0 -0
- /package/dist/{animate-S4KGFV36.js.map → animate-425S4ZXS.js.map} +0 -0
- /package/dist/{approved-A2YR4M4Z.js.map → approved-KUVAJ5M7.js.map} +0 -0
- /package/dist/{asset-writes-5TAUIKSN.js.map → asset-writes-PQNENVYY.js.map} +0 -0
- /package/dist/{assign-2AW5GY3T.js.map → assign-CTV6LDEI.js.map} +0 -0
- /package/dist/{audience-size-VHFMQEMF.js.map → audience-size-5QYI5PKH.js.map} +0 -0
- /package/dist/{audience-writes-P63WFDXJ.js.map → audience-writes-QDDADCYE.js.map} +0 -0
- /package/dist/{audiences-N6DE6EAV.js.map → audiences-JZ6SCEUC.js.map} +0 -0
- /package/dist/{audiences-53FR4K5I.js.map → audiences-OMLKMHEJ.js.map} +0 -0
- /package/dist/{audiences-U6MQRRTP.js.map → audiences-TQ5ZEWIR.js.map} +0 -0
- /package/dist/{audit-PI35QDVW.js.map → audit-2YFDJAKL.js.map} +0 -0
- /package/dist/{audit-WG6M3CXB.js.map → audit-4UE6GFLG.js.map} +0 -0
- /package/dist/{autocomplete-WHNI5BQM.js.map → autocomplete-HTUV2UDS.js.map} +0 -0
- /package/dist/{avatars-WECPBQ4T.js.map → avatars-IJQOWSFC.js.map} +0 -0
- /package/dist/{bid-pricing-WVHPUM74.js.map → bid-pricing-OWP4SZP5.js.map} +0 -0
- /package/dist/{brand-TNZRFKI4.js.map → brand-GBP4OEJI.js.map} +0 -0
- /package/dist/{brief-F56MVJHA.js.map → brief-ZDHUBPV5.js.map} +0 -0
- /package/dist/{businesses-RRYQYTG4.js.map → businesses-CW4RB36R.js.map} +0 -0
- /package/dist/{campaign-groups-OLJ5567X.js.map → campaign-groups-LDOQU65Q.js.map} +0 -0
- /package/dist/{campaign-writes-6LU3LDDY.js.map → campaign-writes-SHF3XZXV.js.map} +0 -0
- /package/dist/{campaign-writes-2DVIWSWU.js.map → campaign-writes-SK55QLY5.js.map} +0 -0
- /package/dist/{campaigns-MJ64UJTS.js.map → campaigns-6CAKRANC.js.map} +0 -0
- /package/dist/{campaigns-PHSRKXVZ.js.map → campaigns-EHV7J7PW.js.map} +0 -0
- /package/dist/{campaigns-7YE5UYPS.js.map → campaigns-GG7LLI4X.js.map} +0 -0
- /package/dist/{campaigns-DDUXFR77.js.map → campaigns-IQYYYD2S.js.map} +0 -0
- /package/dist/{canvas-FUHHYUO7.js.map → canvas-AZ47PNYZ.js.map} +0 -0
- /package/dist/{capabilities-5MXUVZJV.js.map → capabilities-BEZXR2FZ.js.map} +0 -0
- /package/dist/{cards-RZKM5TMV.js.map → cards-J2PGFKEF.js.map} +0 -0
- /package/dist/{catalog-PKYW67IO.js.map → catalog-XECCXRM6.js.map} +0 -0
- /package/dist/{catalogs-2GNJYFSF.js.map → catalogs-P5KMIMC2.js.map} +0 -0
- /package/dist/{catalogs-A6CHXN5B.js.map → catalogs-PLBY32BE.js.map} +0 -0
- /package/dist/{changes-UQYFPZWO.js.map → changes-3COSIJLU.js.map} +0 -0
- /package/dist/{chatgpt-6PP4HANG.js.map → chatgpt-S5EVEKYV.js.map} +0 -0
- /package/dist/{chats-FVR35ZQ3.js.map → chats-AN52YVBT.js.map} +0 -0
- /package/dist/{check-4P2IVABH.js.map → check-AQO7CMDD.js.map} +0 -0
- /package/dist/{chunk-OGGE57JI.js.map → chunk-2MXDSPUO.js.map} +0 -0
- /package/dist/{chunk-3P7TP3GP.js.map → chunk-2SGREP24.js.map} +0 -0
- /package/dist/{chunk-CK2SDG7U.js.map → chunk-34FVKJS2.js.map} +0 -0
- /package/dist/{chunk-KNSUNB2Z.js.map → chunk-364TCROV.js.map} +0 -0
- /package/dist/{chunk-5OQKC5AV.js.map → chunk-3J3W23S4.js.map} +0 -0
- /package/dist/{chunk-BBQ4WZSA.js.map → chunk-3KMYOPBI.js.map} +0 -0
- /package/dist/{chunk-JWMPFTEF.js.map → chunk-3N2KAOVM.js.map} +0 -0
- /package/dist/{chunk-ABK536AV.js.map → chunk-3WSJGYA3.js.map} +0 -0
- /package/dist/{chunk-DEKAW43P.js.map → chunk-4745PLPI.js.map} +0 -0
- /package/dist/{chunk-OVBZ26PE.js.map → chunk-4JS2O2KV.js.map} +0 -0
- /package/dist/{chunk-4LV5JE4Z.js.map → chunk-4VSD4NSZ.js.map} +0 -0
- /package/dist/{chunk-NDFLI64C.js.map → chunk-4VXQAJRU.js.map} +0 -0
- /package/dist/{chunk-GGUQP6KI.js.map → chunk-52IYZCRS.js.map} +0 -0
- /package/dist/{chunk-MR3YYIOQ.js.map → chunk-5CTNSIWY.js.map} +0 -0
- /package/dist/{chunk-PWYGIUNB.js.map → chunk-5G225R4A.js.map} +0 -0
- /package/dist/{chunk-NAYO267Q.js.map → chunk-5LN7GWRE.js.map} +0 -0
- /package/dist/{chunk-W4NFBCCR.js.map → chunk-62QMJYML.js.map} +0 -0
- /package/dist/{chunk-H4DBWD3O.js.map → chunk-6B4KNOJZ.js.map} +0 -0
- /package/dist/{chunk-XOHLV5MO.js.map → chunk-6M77QNJ4.js.map} +0 -0
- /package/dist/{chunk-GS4MMLXY.js.map → chunk-7B73TSKJ.js.map} +0 -0
- /package/dist/{chunk-YYBP65UD.js.map → chunk-7O4HFODK.js.map} +0 -0
- /package/dist/{chunk-QDGDA2YD.js.map → chunk-7ODQ6ZID.js.map} +0 -0
- /package/dist/{chunk-FZSJFSDC.js.map → chunk-7OVCUTEL.js.map} +0 -0
- /package/dist/{chunk-V6AAOAMM.js.map → chunk-AFQF6ISC.js.map} +0 -0
- /package/dist/{chunk-UIUZXQV7.js.map → chunk-AXTOIHH2.js.map} +0 -0
- /package/dist/{chunk-4U7HXXSA.js.map → chunk-B4UVJCJ4.js.map} +0 -0
- /package/dist/{chunk-ALTTFAER.js.map → chunk-C5UFKDAX.js.map} +0 -0
- /package/dist/{chunk-Z5PSSFN7.js.map → chunk-CREEY2FS.js.map} +0 -0
- /package/dist/{chunk-BYNBZIHS.js.map → chunk-DJWEQDBB.js.map} +0 -0
- /package/dist/{chunk-DMGLSVZF.js.map → chunk-DLNADMQV.js.map} +0 -0
- /package/dist/{chunk-NBXZHTSR.js.map → chunk-DNWP5DL6.js.map} +0 -0
- /package/dist/{chunk-65QGMY3C.js.map → chunk-DW3OPKXI.js.map} +0 -0
- /package/dist/{chunk-IRDKHNKO.js.map → chunk-ECJIMIEJ.js.map} +0 -0
- /package/dist/{chunk-AQ2XSUIG.js.map → chunk-EHIISZYD.js.map} +0 -0
- /package/dist/{chunk-JRQI6EVP.js.map → chunk-FBG3JDET.js.map} +0 -0
- /package/dist/{chunk-IXPYC4D2.js.map → chunk-FOWT6ENH.js.map} +0 -0
- /package/dist/{chunk-QOOOYHMN.js.map → chunk-FX3MXXYD.js.map} +0 -0
- /package/dist/{chunk-3EBK2267.js.map → chunk-GLCHD54W.js.map} +0 -0
- /package/dist/{chunk-RL6UQXX7.js.map → chunk-GT77XMOG.js.map} +0 -0
- /package/dist/{chunk-L5RAYYEF.js.map → chunk-GXPZJ2QN.js.map} +0 -0
- /package/dist/{chunk-JHEWSMOS.js.map → chunk-HPAGYPAF.js.map} +0 -0
- /package/dist/{chunk-X7DMNLDD.js.map → chunk-HPDGVK6R.js.map} +0 -0
- /package/dist/{chunk-NZ42DEU7.js.map → chunk-HZ3RXKR4.js.map} +0 -0
- /package/dist/{chunk-ENGKUMTR.js.map → chunk-ILEJXJH2.js.map} +0 -0
- /package/dist/{chunk-2BW4P45O.js.map → chunk-J4ASA24X.js.map} +0 -0
- /package/dist/{chunk-AYAVYXSL.js.map → chunk-JCVPZ7CV.js.map} +0 -0
- /package/dist/{chunk-ZKIWDT6R.js.map → chunk-KDNOMRJA.js.map} +0 -0
- /package/dist/{chunk-AZ7AFTSU.js.map → chunk-KG7FPYM2.js.map} +0 -0
- /package/dist/{chunk-KLO366YG.js.map → chunk-KRQ2AXFW.js.map} +0 -0
- /package/dist/{chunk-Z7MOJPTA.js.map → chunk-L5IYVZM2.js.map} +0 -0
- /package/dist/{chunk-SBQQHP5H.js.map → chunk-LHQ6GXNF.js.map} +0 -0
- /package/dist/{chunk-OA2IUTXA.js.map → chunk-LS2KEAYJ.js.map} +0 -0
- /package/dist/{chunk-MIPZEBHV.js.map → chunk-LURM3KKS.js.map} +0 -0
- /package/dist/{chunk-WVVPZJNX.js.map → chunk-MHH7SGLS.js.map} +0 -0
- /package/dist/{chunk-ZN5CI4CP.js.map → chunk-MZIYRWXL.js.map} +0 -0
- /package/dist/{chunk-UYVCBTC5.js.map → chunk-NY5VYGTP.js.map} +0 -0
- /package/dist/{chunk-M7MLFR2S.js.map → chunk-O37YK4P6.js.map} +0 -0
- /package/dist/{chunk-2UQJ5BDJ.js.map → chunk-OEJNZSJG.js.map} +0 -0
- /package/dist/{chunk-W52LH3J3.js.map → chunk-OXARC5HH.js.map} +0 -0
- /package/dist/{chunk-SV2NFDH2.js.map → chunk-PN72Z2W2.js.map} +0 -0
- /package/dist/{chunk-QKMMQPAJ.js.map → chunk-PTK7AFEE.js.map} +0 -0
- /package/dist/{chunk-735ZOMSR.js.map → chunk-QNLPZOHV.js.map} +0 -0
- /package/dist/{chunk-4MPB36CQ.js.map → chunk-QNXDSNOQ.js.map} +0 -0
- /package/dist/{chunk-UHQ2H3NQ.js.map → chunk-QOC3JEUQ.js.map} +0 -0
- /package/dist/{chunk-GX75UQGS.js.map → chunk-R44B522K.js.map} +0 -0
- /package/dist/{chunk-GOTPUACV.js.map → chunk-R5GGTLYE.js.map} +0 -0
- /package/dist/{chunk-ICHXD4IB.js.map → chunk-R6T25WTZ.js.map} +0 -0
- /package/dist/{chunk-GSVG7XT3.js.map → chunk-RUJS2NOA.js.map} +0 -0
- /package/dist/{chunk-MF3BTAT6.js.map → chunk-SDQLZYQG.js.map} +0 -0
- /package/dist/{chunk-PESH2VF7.js.map → chunk-SEC6FPWC.js.map} +0 -0
- /package/dist/{chunk-BAK2MRBU.js.map → chunk-SJAUMPL3.js.map} +0 -0
- /package/dist/{chunk-ZRXFY2JM.js.map → chunk-SNDHR5QA.js.map} +0 -0
- /package/dist/{chunk-JNW5S4ET.js.map → chunk-SP5L7EYC.js.map} +0 -0
- /package/dist/{chunk-I6QJJ7OY.js.map → chunk-SPBNAGIN.js.map} +0 -0
- /package/dist/{chunk-WCJ3JTLF.js.map → chunk-SWNCS2OD.js.map} +0 -0
- /package/dist/{chunk-NHQIGCFL.js.map → chunk-T37PAZT2.js.map} +0 -0
- /package/dist/{chunk-SZJKURRJ.js.map → chunk-T6PTG6VM.js.map} +0 -0
- /package/dist/{chunk-NGHWLV3C.js.map → chunk-TEKML2NW.js.map} +0 -0
- /package/dist/{chunk-X3BOXZVP.js.map → chunk-TRMZQRVV.js.map} +0 -0
- /package/dist/{chunk-NE2F42MI.js.map → chunk-TTKDFRON.js.map} +0 -0
- /package/dist/{chunk-FLSWMHI2.js.map → chunk-U2BPZ27S.js.map} +0 -0
- /package/dist/{chunk-YUYJH6OZ.js.map → chunk-UPDIBQUC.js.map} +0 -0
- /package/dist/{chunk-K6HH2KF3.js.map → chunk-V2XEX2YR.js.map} +0 -0
- /package/dist/{chunk-BKIE7DBG.js.map → chunk-V62ZWGCL.js.map} +0 -0
- /package/dist/{chunk-VXXVPUBA.js.map → chunk-VCUXAPLM.js.map} +0 -0
- /package/dist/{chunk-ARXNQRKT.js.map → chunk-W7C7HZFJ.js.map} +0 -0
- /package/dist/{chunk-QBFJGCWA.js.map → chunk-WPAW6EVY.js.map} +0 -0
- /package/dist/{chunk-HQYXRF7E.js.map → chunk-WPSLL3S2.js.map} +0 -0
- /package/dist/{chunk-FMMSQIVK.js.map → chunk-WQKBEC4I.js.map} +0 -0
- /package/dist/{chunk-MJ4MJZV3.js.map → chunk-WSYQ6LWB.js.map} +0 -0
- /package/dist/{chunk-GW3KJMSK.js.map → chunk-WW6JLISJ.js.map} +0 -0
- /package/dist/{chunk-7PMGAOHZ.js.map → chunk-X3HPRECW.js.map} +0 -0
- /package/dist/{chunk-3XG6I4K6.js.map → chunk-XB2FODWU.js.map} +0 -0
- /package/dist/{chunk-R2QZBA7P.js.map → chunk-XGX2WOV2.js.map} +0 -0
- /package/dist/{chunk-7EHBCACP.js.map → chunk-XJHUSJY6.js.map} +0 -0
- /package/dist/{chunk-UTFSUMLU.js.map → chunk-XPDUBDPL.js.map} +0 -0
- /package/dist/{chunk-FBTECDEZ.js.map → chunk-XRSRHAEU.js.map} +0 -0
- /package/dist/{chunk-3U4T4CKO.js.map → chunk-XVHR2NCG.js.map} +0 -0
- /package/dist/{chunk-W5WKPVCJ.js.map → chunk-XZWBLUDV.js.map} +0 -0
- /package/dist/{chunk-IQ3MYXCJ.js.map → chunk-YUCGCJKT.js.map} +0 -0
- /package/dist/{chunk-47RFRYEP.js.map → chunk-ZBUIWVF3.js.map} +0 -0
- /package/dist/{chunk-VJINC2Q3.js.map → chunk-ZFJ2FQUH.js.map} +0 -0
- /package/dist/{chunk-HXALY3VB.js.map → chunk-ZL5YETKR.js.map} +0 -0
- /package/dist/{chunk-2R77YWFG.js.map → chunk-ZNXP3WNJ.js.map} +0 -0
- /package/dist/{chunk-WTLNH34U.js.map → chunk-ZVXKWLLE.js.map} +0 -0
- /package/dist/{claim-B6IX5MUB.js.map → claim-NRNO4XCO.js.map} +0 -0
- /package/dist/{client-CRKH3ZYG.js.map → client-463NKLRT.js.map} +0 -0
- /package/dist/{code-OCSD6BPR.js.map → code-R4JOQ27J.js.map} +0 -0
- /package/dist/{companies-U4APTF2Z.js.map → companies-4TOBU44J.js.map} +0 -0
- /package/dist/{company-WFVBYXKK.js.map → company-RK34S3IA.js.map} +0 -0
- /package/dist/{complete-FUPSG7MH.js.map → complete-7BNBQ5AI.js.map} +0 -0
- /package/dist/{config-6FHXEEN7.js.map → config-GDLHHBJZ.js.map} +0 -0
- /package/dist/{connect-2TWKL3DQ.js.map → connect-CRIRSXN3.js.map} +0 -0
- /package/dist/{content-7N2FPVPA.js.map → content-FCO6MGXW.js.map} +0 -0
- /package/dist/{conversation-7VQ7CGVT.js.map → conversation-4CQG2B2C.js.map} +0 -0
- /package/dist/{conversion-report-6IQKXWFU.js.map → conversion-report-PDTQTRVB.js.map} +0 -0
- /package/dist/{conversion-upload-command-TYGIB7XJ.js.map → conversion-upload-command-MEO4WLZH.js.map} +0 -0
- /package/dist/{conversion-writes-UQU3QJTF.js.map → conversion-writes-ZVBOXUIA.js.map} +0 -0
- /package/dist/{conversions-ZP2SKL36.js.map → conversions-BND5HYTL.js.map} +0 -0
- /package/dist/{conversions-P2A6R4FG.js.map → conversions-POBKTXQF.js.map} +0 -0
- /package/dist/{copy-writes-GUOL2QUD.js.map → copy-writes-GZ744FHU.js.map} +0 -0
- /package/dist/{countries-TKMYMMJN.js.map → countries-TKL5T5JL.js.map} +0 -0
- /package/dist/{create-KE3GM4W6.js.map → create-BJ7XBNY5.js.map} +0 -0
- /package/dist/{create-M7OTWZ2W.js.map → create-UI2YG2KA.js.map} +0 -0
- /package/dist/{create-KKURENQ7.js.map → create-XN4KVB5U.js.map} +0 -0
- /package/dist/{create-XLQEQYVN.js.map → create-YSGBH6Q4.js.map} +0 -0
- /package/dist/{creatives-AXMG777O.js.map → creatives-57XIJAEG.js.map} +0 -0
- /package/dist/{creatives-BGYARLCC.js.map → creatives-GTRQAZSB.js.map} +0 -0
- /package/dist/{creatives-VR3N5A3X.js.map → creatives-QFSIIFXB.js.map} +0 -0
- /package/dist/{credentials-HTPDDOYP.js.map → credentials-KIH6ICDU.js.map} +0 -0
- /package/dist/{critique-EZJMYQLC.js.map → critique-GWRXVXVG.js.map} +0 -0
- /package/dist/{critique-Q5ZZ6PKB.js.map → critique-OK2ENBOA.js.map} +0 -0
- /package/dist/{crm-YLSUKW6N.js.map → crm-QSHUYXTW.js.map} +0 -0
- /package/dist/{crm-5QOSCQWL.js.map → crm-Y5QTZAHO.js.map} +0 -0
- /package/dist/{crop-S5NAICO6.js.map → crop-WKTW3EMP.js.map} +0 -0
- /package/dist/{currency-SVEUNKHP.js.map → currency-PTOI5SPU.js.map} +0 -0
- /package/dist/{custom-conversions-SUXA7KSN.js.map → custom-conversions-VQ3LBWYV.js.map} +0 -0
- /package/dist/{customers-OGKISQAS.js.map → customers-2G32E6W7.js.map} +0 -0
- /package/dist/{decide-HTTX2ZIT.js.map → decide-X2UAKYXK.js.map} +0 -0
- /package/dist/{delete-M7YWEURA.js.map → delete-2ZTMTKYD.js.map} +0 -0
- /package/dist/{delete-23FUCSTE.js.map → delete-4CUEJZ2Z.js.map} +0 -0
- /package/dist/{delete-DGH3T6QI.js.map → delete-FOSTK2RA.js.map} +0 -0
- /package/dist/{delete-OPIN5KCK.js.map → delete-HIAZHA56.js.map} +0 -0
- /package/dist/{delete-MD6QBKGM.js.map → delete-I43JQH2E.js.map} +0 -0
- /package/dist/{delete-JBGVVAHP.js.map → delete-RF44ILYE.js.map} +0 -0
- /package/dist/{demographics-AFNPWEZP.js.map → demographics-2UYQW6II.js.map} +0 -0
- /package/dist/{describe-EASPZ57E.js.map → describe-M6DYXNQC.js.map} +0 -0
- /package/dist/{describe-LZYLJXBH.js.map → describe-OQ6R3EF7.js.map} +0 -0
- /package/dist/{dimensions-6JA6LUUD.js.map → dimensions-DGYM5E5P.js.map} +0 -0
- /package/dist/{discard-UKPRZTQT.js.map → discard-NKPQ73UM.js.map} +0 -0
- /package/dist/{discover-B652QR7E.js.map → discover-XLIH7RCB.js.map} +0 -0
- /package/dist/{discover-2ZX3DYSF.js.map → discover-YKMBVSPF.js.map} +0 -0
- /package/dist/{domain-6TJPO4WO.js.map → domain-LUDUZB3F.js.map} +0 -0
- /package/dist/{download-TBPG3ZIH.js.map → download-LL6DL62N.js.map} +0 -0
- /package/dist/{download-D6HQCD5H.js.map → download-SFWMT7DL.js.map} +0 -0
- /package/dist/{draft-6JUQWX26.js.map → draft-374Z4MGY.js.map} +0 -0
- /package/dist/{draft-ALSOCILF.js.map → draft-736FJJWK.js.map} +0 -0
- /package/dist/{draft-QUXRJRNY.js.map → draft-7LPUJZCF.js.map} +0 -0
- /package/dist/{draft-PJT5TSFQ.js.map → draft-ME4TNPO7.js.map} +0 -0
- /package/dist/{draft-2EO63W4K.js.map → draft-MPWR47CG.js.map} +0 -0
- /package/dist/{draft-L5AL6STE.js.map → draft-R5ND5SWT.js.map} +0 -0
- /package/dist/{draft-BAWIN2IN.js.map → draft-T7TWIFEX.js.map} +0 -0
- /package/dist/{draft-KYO43IJD.js.map → draft-XAAIGE6Q.js.map} +0 -0
- /package/dist/{env-OXMIRJRU.js.map → env-DQHY5ODN.js.map} +0 -0
- /package/dist/{experiment-XNEYJVLH.js.map → experiment-MO6MT6OJ.js.map} +0 -0
- /package/dist/{experiments-QXAC5BPW.js.map → experiments-OGZV73W6.js.map} +0 -0
- /package/dist/{export-75ADGAGR.js.map → export-6Z6QBU6V.js.map} +0 -0
- /package/dist/{extract-V26NW6CA.js.map → extract-YGOQBOQK.js.map} +0 -0
- /package/dist/{facets-7IDDCZIY.js.map → facets-OLZ7JLFL.js.map} +0 -0
- /package/dist/{favorites-V6HWSOHN.js.map → favorites-R3JO4SJJ.js.map} +0 -0
- /package/dist/{feed-K2NECCHS.js.map → feed-IUMMHM3I.js.map} +0 -0
- /package/dist/{feedback-ZWFOBIGU.js.map → feedback-ZBEZIIPT.js.map} +0 -0
- /package/dist/{feedback-record-ZZRR4LUM.js.map → feedback-record-CZVSPZUR.js.map} +0 -0
- /package/dist/{fetch-LQMNRF3B.js.map → fetch-AL44XS4Q.js.map} +0 -0
- /package/dist/{fetch-HYGMTCHK.js.map → fetch-K3NRT2L2.js.map} +0 -0
- /package/dist/{fit-KDY7PZFL.js.map → fit-5NVXWXZV.js.map} +0 -0
- /package/dist/{flows-U646JOQN.js.map → flows-CAOMVQYZ.js.map} +0 -0
- /package/dist/{follow-RNVJZVFG.js.map → follow-SS374QUW.js.map} +0 -0
- /package/dist/{follow-competitors-DF73HPQT.js.map → follow-competitors-3LTOTTBY.js.map} +0 -0
- /package/dist/{following-WX7DHO5K.js.map → following-YMA5O3LF.js.map} +0 -0
- /package/dist/{fonts-6RIJJ222.js.map → fonts-E3CNWPD5.js.map} +0 -0
- /package/dist/{forecast-IECMUBL2.js.map → forecast-KOBF5TKM.js.map} +0 -0
- /package/dist/{forecast-4NJXBMZV.js.map → forecast-PWGN4ETP.js.map} +0 -0
- /package/dist/{funding-67ZORHHQ.js.map → funding-KLIZ73SS.js.map} +0 -0
- /package/dist/{funnel-OFJ5XMOU.js.map → funnel-LKF6D7AA.js.map} +0 -0
- /package/dist/{ga4-G5NKZI3Y.js.map → ga4-XPCE4EK5.js.map} +0 -0
- /package/dist/{generate-VQTLPEYW.js.map → generate-GHIXVLMY.js.map} +0 -0
- /package/dist/{get-6JWGIPN2.js.map → get-HCGFATFD.js.map} +0 -0
- /package/dist/{get-LHHYARGV.js.map → get-JR2KZXW5.js.map} +0 -0
- /package/dist/{get-N6IMHWZE.js.map → get-RDTJSWSA.js.map} +0 -0
- /package/dist/{get-GD5MRH7N.js.map → get-SGNT4JG2.js.map} +0 -0
- /package/dist/{get-KUOCL3IX.js.map → get-TB52FVNV.js.map} +0 -0
- /package/dist/{get-EEBGRH4P.js.map → get-TGFXZC5S.js.map} +0 -0
- /package/dist/{get-MINQPB73.js.map → get-WS744HAO.js.map} +0 -0
- /package/dist/{get-VBLMBPFJ.js.map → get-YD7GDMDR.js.map} +0 -0
- /package/dist/{gif-QQR5VJS7.js.map → gif-YK5HJXRE.js.map} +0 -0
- /package/dist/{google-3EREXOK2.js.map → google-BI45CXMW.js.map} +0 -0
- /package/dist/{google-LVOGKNDV.js.map → google-FZVOB7HW.js.map} +0 -0
- /package/dist/{google-ads-RIIV4EJI.js.map → google-ads-DYZGUM6W.js.map} +0 -0
- /package/dist/{group-JUYQHY5I.js.map → group-7OWIYAKJ.js.map} +0 -0
- /package/dist/{group-YWHTJLS7.js.map → group-H6ZYRPE6.js.map} +0 -0
- /package/dist/{gsc-7D62WFOR.js.map → gsc-HI2KXDEU.js.map} +0 -0
- /package/dist/{history-JK6S5KWG.js.map → history-3EQQHYKT.js.map} +0 -0
- /package/dist/{history-VFA6IVKN.js.map → history-SJJX6EXI.js.map} +0 -0
- /package/dist/{history-7OLO7HIP.js.map → history-SQPJ7PPE.js.map} +0 -0
- /package/dist/{hubspot-IMLZUTT3.js.map → hubspot-MYTV36SM.js.map} +0 -0
- /package/dist/{icon-REVUB32Y.js.map → icon-HLJCWTR3.js.map} +0 -0
- /package/dist/{ideas-ZUXLYR6Y.js.map → ideas-CVXHFVX7.js.map} +0 -0
- /package/dist/{images-WNMQFAC3.js.map → images-K7JQ3ORB.js.map} +0 -0
- /package/dist/{improve-RHY7SH7B.js.map → improve-BRC4R6MW.js.map} +0 -0
- /package/dist/{ingest-L5YC6U2N.js.map → ingest-4GNJ2PWL.js.map} +0 -0
- /package/dist/{ingest-FKC5PBBE.js.map → ingest-5NYBUZE2.js.map} +0 -0
- /package/dist/{insights-7CCOJ4G6.js.map → insights-CN3GUTT7.js.map} +0 -0
- /package/dist/{insights-VW475N6G.js.map → insights-INIFHYR7.js.map} +0 -0
- /package/dist/{inspect-2XJ6LLSJ.js.map → inspect-25IVRU45.js.map} +0 -0
- /package/dist/{inspiration-ZA6MI7TK.js.map → inspiration-KAXPRINY.js.map} +0 -0
- /package/dist/{instant-experiences-JJJKZAQQ.js.map → instant-experiences-NMJUWNP3.js.map} +0 -0
- /package/dist/{intent-VGQHKKNW.js.map → intent-3GDLPKKN.js.map} +0 -0
- /package/dist/{job-PW4MM7ZV.js.map → job-2JJNKUHT.js.map} +0 -0
- /package/dist/{job-create-EOBCQRUK.js.map → job-create-BNTNZCSP.js.map} +0 -0
- /package/dist/{job-status-KZDFSCJ5.js.map → job-status-N7RWRDRO.js.map} +0 -0
- /package/dist/{keep-IYR4KE2G.js.map → keep-Z2WH3CKU.js.map} +0 -0
- /package/dist/{keyword-gap-JKC3U3OS.js.map → keyword-gap-B2WPVHOB.js.map} +0 -0
- /package/dist/{keyword-metrics-OYHBOWA3.js.map → keyword-metrics-UDGWN7BO.js.map} +0 -0
- /package/dist/{keywords-for-site-EUTBLXRT.js.map → keywords-for-site-GEG6AXD3.js.map} +0 -0
- /package/dist/{landing-PRG5PT7J.js.map → landing-BFMRM3HA.js.map} +0 -0
- /package/dist/{landings-433WRB5F.js.map → landings-7QRITXZ2.js.map} +0 -0
- /package/dist/{languages-PK5RHB5H.js.map → languages-RZLMZR57.js.map} +0 -0
- /package/dist/{languages-JR3RSGUP.js.map → languages-UJAOPTV2.js.map} +0 -0
- /package/dist/{launches-LXN6XOAD.js.map → launches-4H6ANGTG.js.map} +0 -0
- /package/dist/{layerize-5DBAU2EQ.js.map → layerize-P5LFIA4X.js.map} +0 -0
- /package/dist/{leads-KXCGAJ34.js.map → leads-MTTOYNPM.js.map} +0 -0
- /package/dist/{leads-2BXRQDT5.js.map → leads-QBWR7FKT.js.map} +0 -0
- /package/dist/{learn-N2XDH4XA.js.map → learn-QPXZZIZZ.js.map} +0 -0
- /package/dist/{lighthouse-BQFFFDV6.js.map → lighthouse-FGUFJRGR.js.map} +0 -0
- /package/dist/{line-item-writes-4YZNT3VI.js.map → line-item-writes-RVOAMJ5R.js.map} +0 -0
- /package/dist/{line-items-FSQPXOKE.js.map → line-items-POZRAJLC.js.map} +0 -0
- /package/dist/{link-ITXPWVMH.js.map → link-IXEZKRM7.js.map} +0 -0
- /package/dist/{linkedin-Z6M3YEAQ.js.map → linkedin-5PYG5HEM.js.map} +0 -0
- /package/dist/{linkedin-person-IK2MWL7Y.js.map → linkedin-person-EMJXEZYR.js.map} +0 -0
- /package/dist/{list-VJRTBW6A.js.map → list-4KS7WSUG.js.map} +0 -0
- /package/dist/{list-Z7NOJY3P.js.map → list-7GDMM26I.js.map} +0 -0
- /package/dist/{list-YLS62E6D.js.map → list-DVVOP6FM.js.map} +0 -0
- /package/dist/{list-22PEYOWN.js.map → list-J5KWXHFO.js.map} +0 -0
- /package/dist/{list-WA3PQEWJ.js.map → list-PT4DVD4U.js.map} +0 -0
- /package/dist/{list-CXXKUKCX.js.map → list-PTK2HOUY.js.map} +0 -0
- /package/dist/{list-7SVSDERS.js.map → list-Q5LVTPQP.js.map} +0 -0
- /package/dist/{list-33E2RTA5.js.map → list-UG4V5AM2.js.map} +0 -0
- /package/dist/{list-EVIRF2CY.js.map → list-XOYU7UTX.js.map} +0 -0
- /package/dist/{locations-N5TZTS5F.js.map → locations-EISZ6JOT.js.map} +0 -0
- /package/dist/{locations-QRISCNMR.js.map → locations-VJX64ZZR.js.map} +0 -0
- /package/dist/{log-VFGFY5PT.js.map → log-2F2N24DT.js.map} +0 -0
- /package/dist/{logo-ZWRHTSRM.js.map → logo-H2KHGLYD.js.map} +0 -0
- /package/dist/{lookup-SX6GZMO5.js.map → lookup-IUQWU346.js.map} +0 -0
- /package/dist/{make-DRWMUES6.js.map → make-N5LVJSZD.js.map} +0 -0
- /package/dist/{map-3YMLKUNL.js.map → map-QGJZIC5N.js.map} +0 -0
- /package/dist/{mcp-MIZR2NFZ.js.map → mcp-RSW7KAWP.js.map} +0 -0
- /package/dist/{media-KXBWT2YJ.js.map → media-23IW442U.js.map} +0 -0
- /package/dist/{media-ZUNR6AMT.js.map → media-K5RJXLTN.js.map} +0 -0
- /package/dist/{media-sources-RKIBHCTU.js.map → media-sources-7R7FO53Y.js.map} +0 -0
- /package/dist/{members-XMHVOMNT.js.map → members-B6TKGGT5.js.map} +0 -0
- /package/dist/{meme-HZOKMZJZ.js.map → meme-QMCUGXUE.js.map} +0 -0
- /package/dist/{meta-5ODNL2LA.js.map → meta-H3KBPU33.js.map} +0 -0
- /package/dist/{metrics-NCSG7SLD.js.map → metrics-PRIKXVYZ.js.map} +0 -0
- /package/dist/{models-2NPHMHN7.js.map → models-M3E4YFCT.js.map} +0 -0
- /package/dist/{normalize-PSPLM7OO.js.map → normalize-5B4EQLUX.js.map} +0 -0
- /package/dist/{normalize-CBPJIIXG.js.map → normalize-5QIGANTK.js.map} +0 -0
- /package/dist/{options-5KONPMEL.js.map → options-K33CJOR6.js.map} +0 -0
- /package/dist/{organization-BU6WIFXV.js.map → organization-A4NFWWWI.js.map} +0 -0
- /package/dist/{output-UPGKR3FB.js.map → output-U5ZV6PST.js.map} +0 -0
- /package/dist/{page-GP5FFVQ3.js.map → page-XVOUD4VV.js.map} +0 -0
- /package/dist/{page-photos-CJIFQDW5.js.map → page-photos-SHIGXDYE.js.map} +0 -0
- /package/dist/{pages-NJN2E5HU.js.map → pages-XJF3FBOJ.js.map} +0 -0
- /package/dist/{performance-TIA3O7YO.js.map → performance-L3Q57H4H.js.map} +0 -0
- /package/dist/{performance-74OQO2QQ.js.map → performance-NVURSEZ6.js.map} +0 -0
- /package/dist/{pinterest-TLKIRVDC.js.map → pinterest-NA6HGPMB.js.map} +0 -0
- /package/dist/{pixels-E7UYF4KE.js.map → pixels-AZCIWWXK.js.map} +0 -0
- /package/dist/{pixels-COONSHMC.js.map → pixels-THDQD3RF.js.map} +0 -0
- /package/dist/{plan-RNDLIOZY.js.map → plan-VHMWZU7F.js.map} +0 -0
- /package/dist/{posts-PPSQ726T.js.map → posts-BDMC644W.js.map} +0 -0
- /package/dist/{preview-QGLUDJ3A.js.map → preview-BIEVHIDJ.js.map} +0 -0
- /package/dist/{profile-JVVIISSQ.js.map → profile-YHI65VGK.js.map} +0 -0
- /package/dist/{promoted-tweet-writes-IYDFXFVR.js.map → promoted-tweet-writes-MXXVRLVQ.js.map} +0 -0
- /package/dist/{promoted-tweets-A42JISSP.js.map → promoted-tweets-HFLGXWX2.js.map} +0 -0
- /package/dist/{properties-7P6GSOVE.js.map → properties-ZLY6NYVK.js.map} +0 -0
- /package/dist/{publish-C3NUBIID.js.map → publish-6ZXFUBGP.js.map} +0 -0
- /package/dist/{query-IO5NESSN.js.map → query-ELD7WSFR.js.map} +0 -0
- /package/dist/{query-DI7ZGS4A.js.map → query-HFHTLNDN.js.map} +0 -0
- /package/dist/{query-G4L42FHT.js.map → query-WMEX73ZB.js.map} +0 -0
- /package/dist/{questionnaire-7YHG733R.js.map → questionnaire-32BQ4ZUX.js.map} +0 -0
- /package/dist/{read-ESTTW6WU.js.map → read-2HQEZIJW.js.map} +0 -0
- /package/dist/{reddit-VMNGERE6.js.map → reddit-BIHGJPGP.js.map} +0 -0
- /package/dist/{refresh-EBRMXZAC.js.map → refresh-4O32S4YR.js.map} +0 -0
- /package/dist/{refresh-ZCKZ6RPU.js.map → refresh-LVV4SPLT.js.map} +0 -0
- /package/dist/{release-MKGBYUKY.js.map → release-VIPNSPQ5.js.map} +0 -0
- /package/dist/{relevant-pages-IVHAKIOI.js.map → relevant-pages-B5SYN575.js.map} +0 -0
- /package/dist/{remove-EHHTOC7T.js.map → remove-2E77743U.js.map} +0 -0
- /package/dist/{remove-PPLOR5BM.js.map → remove-TPOWWFZ6.js.map} +0 -0
- /package/dist/{reopen-ILUWK3W3.js.map → reopen-UOBTJBMQ.js.map} +0 -0
- /package/dist/{rerun-367PVEIF.js.map → rerun-HUFJUOEV.js.map} +0 -0
- /package/dist/{research-7BWH4VVV.js.map → research-ELM3KHGE.js.map} +0 -0
- /package/dist/{research-VDSOAQ77.js.map → research-FOJIDMSE.js.map} +0 -0
- /package/dist/{reset-VAKJGC3Q.js.map → reset-FTLWUFZK.js.map} +0 -0
- /package/dist/{reset-X2JMHREN.js.map → reset-GIXXLPHQ.js.map} +0 -0
- /package/dist/{resolve-7OXBK4CU.js.map → resolve-QHR5JJTJ.js.map} +0 -0
- /package/dist/{retry-2L2B3FOJ.js.map → retry-HNWXJR5U.js.map} +0 -0
- /package/dist/{retry-GJBALRAZ.js.map → retry-NY5KFEDA.js.map} +0 -0
- /package/dist/{retry-failed-JGONEZFL.js.map → retry-failed-OAH7JQKD.js.map} +0 -0
- /package/dist/{revenue-H66XC7JC.js.map → revenue-JFMUODJO.js.map} +0 -0
- /package/dist/{rule-writes-AHDYOYVO.js.map → rule-writes-QLZNJ7CT.js.map} +0 -0
- /package/dist/{rules-PJJSIQWM.js.map → rules-56E55SGC.js.map} +0 -0
- /package/dist/{rules-5HIC2F34.js.map → rules-FJHYG4SJ.js.map} +0 -0
- /package/dist/{rules-add-UFY7TAO3.js.map → rules-add-ZOPOWJMY.js.map} +0 -0
- /package/dist/{run-6PDML7YJ.js.map → run-7OCCCNJ4.js.map} +0 -0
- /package/dist/{run-QBXFCGML.js.map → run-MRC4UVHU.js.map} +0 -0
- /package/dist/{scaffold-ad-KOBSZMKJ.js.map → scaffold-ad-7ADCDQBK.js.map} +0 -0
- /package/dist/{scaffold-static-ad-2I7TXF7L.js.map → scaffold-static-ad-TV5OWISA.js.map} +0 -0
- /package/dist/{scaffold-video-P5UOTXWT.js.map → scaffold-video-LLBDO546.js.map} +0 -0
- /package/dist/{schedule-N5NXFCIW.js.map → schedule-OFPSZVZ2.js.map} +0 -0
- /package/dist/{schedule-JNBK267N.js.map → schedule-ZATNBBWD.js.map} +0 -0
- /package/dist/{scheduled-agents-274ZTTUZ.js.map → scheduled-agents-EPPP4SCZ.js.map} +0 -0
- /package/dist/{schema-7HR57YTC.js.map → schema-OGP4DUPP.js.map} +0 -0
- /package/dist/{scrape-Z3W44ZH2.js.map → scrape-ZHL2BHS7.js.map} +0 -0
- /package/dist/{screenshot-FC4WIRNT.js.map → screenshot-ADMRDYWN.js.map} +0 -0
- /package/dist/{search-DRD2GYJZ.js.map → search-6W4HXR2S.js.map} +0 -0
- /package/dist/{search-BZ7TSFYU.js.map → search-6ZWI2NML.js.map} +0 -0
- /package/dist/{search-ZWQJCYAB.js.map → search-CQUS7EOM.js.map} +0 -0
- /package/dist/{search-22MOVZ2F.js.map → search-HF5ECIYW.js.map} +0 -0
- /package/dist/{search-PQV7IO4M.js.map → search-MKVVMJ2Q.js.map} +0 -0
- /package/dist/{search-33EMRTMI.js.map → search-QUF6LHQ5.js.map} +0 -0
- /package/dist/{search-copy-HOHYX6GF.js.map → search-copy-O6FDX4HT.js.map} +0 -0
- /package/dist/{seeds-K3K6WB5G.js.map → seeds-5TM3O3K3.js.map} +0 -0
- /package/dist/{select-3ZRWAYT7.js.map → select-BRH4QLWU.js.map} +0 -0
- /package/dist/{sends-2BR7A434.js.map → sends-43FU3SJN.js.map} +0 -0
- /package/dist/{sequences-KT7CMFU6.js.map → sequences-3CEVHGHB.js.map} +0 -0
- /package/dist/{set-prompt-SCSC7BRO.js.map → set-prompt-SYWNE4CS.js.map} +0 -0
- /package/dist/{setup-links-BEIHAXVR.js.map → setup-links-4STQ5B4P.js.map} +0 -0
- /package/dist/{shared-S7ZPZXF5.js.map → shared-HY2VP7PT.js.map} +0 -0
- /package/dist/{shopify-XDDDUQTQ.js.map → shopify-7LDHCWUQ.js.map} +0 -0
- /package/dist/{site-DWVWM3HD.js.map → site-I3NFMPJB.js.map} +0 -0
- /package/dist/{sitemaps-QKQB64M2.js.map → sitemaps-PLAWVXQL.js.map} +0 -0
- /package/dist/{sites-MB7H2BNT.js.map → sites-WX2IBTZT.js.map} +0 -0
- /package/dist/{skills-RCXAZVMB.js.map → skills-O6EQOAMQ.js.map} +0 -0
- /package/dist/{sources-O7ZOL5YR.js.map → sources-CGXHNWJM.js.map} +0 -0
- /package/dist/{sources-74OM3T4V.js.map → sources-PUZ4WV4Q.js.map} +0 -0
- /package/dist/{stale-WAKIZSQS.js.map → stale-QNIJZTGD.js.map} +0 -0
- /package/dist/{stats-TGAKUBDH.js.map → stats-QQRYOMZA.js.map} +0 -0
- /package/dist/{status-JOIUSIE7.js.map → status-5OMVGFCH.js.map} +0 -0
- /package/dist/{sticker-BWTRJKQ4.js.map → sticker-654HS3K2.js.map} +0 -0
- /package/dist/{stock-SKFA4HSO.js.map → stock-35LOO3YN.js.map} +0 -0
- /package/dist/{studies-FXX4XW4A.js.map → studies-Z2ZIWLTO.js.map} +0 -0
- /package/dist/{studio-FJL2TIZK.js.map → studio-NRWLXOFZ.js.map} +0 -0
- /package/dist/{study-writes-H6RDMXF3.js.map → study-writes-V7BXLTQG.js.map} +0 -0
- /package/dist/{suggest-6DLRLGOR.js.map → suggest-JASHCOL5.js.map} +0 -0
- /package/dist/{sync-EFIN4VNC.js.map → sync-6AN67IX3.js.map} +0 -0
- /package/dist/{sync-XBCQXUD7.js.map → sync-RCDODSOD.js.map} +0 -0
- /package/dist/{sync-NJKQVHO7.js.map → sync-URIRLHTS.js.map} +0 -0
- /package/dist/{sync-definition-2BQUWH3Y.js.map → sync-definition-EGHEQ57K.js.map} +0 -0
- /package/dist/{tag-VIE22YTB.js.map → tag-7YMFAZQQ.js.map} +0 -0
- /package/dist/{tag-manager-M2Z6TEV6.js.map → tag-manager-LU4GAZ6R.js.map} +0 -0
- /package/dist/{tags-HISOVNNV.js.map → tags-6A7QOYBI.js.map} +0 -0
- /package/dist/{tags-3YUICYEG.js.map → tags-JHT3Q6VO.js.map} +0 -0
- /package/dist/{tags-NSCLNPLU.js.map → tags-KSMLT4G2.js.map} +0 -0
- /package/dist/{tags-AQ2JGXPQ.js.map → tags-MTVZJHCE.js.map} +0 -0
- /package/dist/{tags-AXIDVYMK.js.map → tags-OU32R2SH.js.map} +0 -0
- /package/dist/{targeting-URLZVNS2.js.map → targeting-YBIWD27C.js.map} +0 -0
- /package/dist/{targeting-constants-WHK63KKJ.js.map → targeting-constants-QIB3UZHM.js.map} +0 -0
- /package/dist/{targeting-criteria-DFJQKQV4.js.map → targeting-criteria-NUXZB7NP.js.map} +0 -0
- /package/dist/{targets-NQKCNVQ7.js.map → targets-3WIBMP4B.js.map} +0 -0
- /package/dist/{terms-VIAM2BO5.js.map → terms-X4OJWTQH.js.map} +0 -0
- /package/dist/{testimonials-K5D2KRYK.js.map → testimonials-2NQMY23B.js.map} +0 -0
- /package/dist/{themes-CIXQPTFX.js.map → themes-6KVP3COR.js.map} +0 -0
- /package/dist/{top-companies-3M7H5NPQ.js.map → top-companies-WWNPUJ23.js.map} +0 -0
- /package/dist/{transcript-CQTAZJK4.js.map → transcript-P7HKVABU.js.map} +0 -0
- /package/dist/{translate-D2SJCT7D.js.map → translate-YGHRSEX6.js.map} +0 -0
- /package/dist/{triggers-THBRMWM6.js.map → triggers-6EXLTW35.js.map} +0 -0
- /package/dist/{tweets-7GVNM564.js.map → tweets-X5PTAT6F.js.map} +0 -0
- /package/dist/{unfollow-STHFAGMU.js.map → unfollow-S5LHFLGW.js.map} +0 -0
- /package/dist/{unlink-WWPY4336.js.map → unlink-XTZA474P.js.map} +0 -0
- /package/dist/{unstage-HTYFDR33.js.map → unstage-KEMVI37X.js.map} +0 -0
- /package/dist/{unstage-VLEPSA6I.js.map → unstage-YSVQ6DLB.js.map} +0 -0
- /package/dist/{update-HCQFGRDE.js.map → update-3NA6ABLW.js.map} +0 -0
- /package/dist/{update-AMTTYSZP.js.map → update-5ZNS2DKP.js.map} +0 -0
- /package/dist/{update-EM6EZQ73.js.map → update-DDKNKV6M.js.map} +0 -0
- /package/dist/{update-FMK63TCD.js.map → update-MDVZ24VQ.js.map} +0 -0
- /package/dist/{update-N3DTFTQE.js.map → update-USKR3UOC.js.map} +0 -0
- /package/dist/{upload-BCUR7GMG.js.map → upload-IMP5CUY5.js.map} +0 -0
- /package/dist/{upload-JTX776YT.js.map → upload-SYFB2VTJ.js.map} +0 -0
- /package/dist/{upscale-G33XUZPK.js.map → upscale-P5EYUVOZ.js.map} +0 -0
- /package/dist/{url-options-BSU46PR2.js.map → url-options-6MFRIDNA.js.map} +0 -0
- /package/dist/{url-params-YWPEV5V5.js.map → url-params-Y5XQSDEF.js.map} +0 -0
- /package/dist/{use-LVOEX2T3.js.map → use-D3RBWLJO.js.map} +0 -0
- /package/dist/{validate-GZYVVNHQ.js.map → validate-JX4FT7PL.js.map} +0 -0
- /package/dist/{variant-IMO5ZRNC.js.map → variant-JQVZUUA4.js.map} +0 -0
- /package/dist/{videos-L5BDS2M4.js.map → videos-EHDZ46UQ.js.map} +0 -0
- /package/dist/{view-IYY37LYK.js.map → view-IKKRJ5YD.js.map} +0 -0
- /package/dist/{viewer-check-DBQ6T3R5.js.map → viewer-check-5GREZIVJ.js.map} +0 -0
- /package/dist/{web-62AJC2EU.js.map → web-7TPDDBI6.js.map} +0 -0
- /package/dist/{winners-BYBOZ2XZ.js.map → winners-4PKEVMUC.js.map} +0 -0
- /package/dist/{winning-ads-OHVZERTH.js.map → winning-ads-H7ZE5AQW.js.map} +0 -0
- /package/dist/{write-commands-3YFTN6OQ.js.map → write-commands-CTLF2M6L.js.map} +0 -0
- /package/dist/{write-commands-2VKVFEEK.js.map → write-commands-FIS6Y2MN.js.map} +0 -0
- /package/dist/{write-commands-AANGPJ5F.js.map → write-commands-R5SN6CVQ.js.map} +0 -0
- /package/dist/{write-commands-BWWXFT2R.js.map → write-commands-V77MD5SC.js.map} +0 -0
- /package/dist/{x-ACDJXCOY.js.map → x-EMLFCHSG.js.map} +0 -0
|
@@ -0,0 +1,2437 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readTargetsFile
|
|
3
|
+
} from "./chunk-S6VFDNSQ.js";
|
|
4
|
+
import "./chunk-I7AYMJZA.js";
|
|
5
|
+
import {
|
|
6
|
+
flowEventKeys,
|
|
7
|
+
flowNodes
|
|
8
|
+
} from "./chunk-Z4ZYFIDQ.js";
|
|
9
|
+
import {
|
|
10
|
+
flowDataPath,
|
|
11
|
+
flowExists,
|
|
12
|
+
listFlowSlugs,
|
|
13
|
+
readFlowTree
|
|
14
|
+
} from "./chunk-W7C7HZFJ.js";
|
|
15
|
+
import {
|
|
16
|
+
INGEST_ARRIVALS_MAX,
|
|
17
|
+
eventIngestUrl,
|
|
18
|
+
ingestBrief
|
|
19
|
+
} from "./chunk-EIDJCUMM.js";
|
|
20
|
+
import "./chunk-GRQ2AXDX.js";
|
|
21
|
+
import {
|
|
22
|
+
TAG_MANAGER_TIMEOUT_MS
|
|
23
|
+
} from "./chunk-TTKDFRON.js";
|
|
24
|
+
import {
|
|
25
|
+
peopleArgs,
|
|
26
|
+
peopleLimitError
|
|
27
|
+
} from "./chunk-4VSD4NSZ.js";
|
|
28
|
+
import {
|
|
29
|
+
analyticsErrorEnvelope
|
|
30
|
+
} from "./chunk-ZL5YETKR.js";
|
|
31
|
+
import {
|
|
32
|
+
ConversionArgsError,
|
|
33
|
+
conversionsWrite,
|
|
34
|
+
parseConversionsArgs
|
|
35
|
+
} from "./chunk-SXML3LQN.js";
|
|
36
|
+
import {
|
|
37
|
+
AD_PARAM_ROLE_SPECS,
|
|
38
|
+
ANALYTICS_EVENT_DOORS,
|
|
39
|
+
ANALYTICS_FULL_BREAKDOWN_LIMIT,
|
|
40
|
+
SEND_FILTERS,
|
|
41
|
+
STANDARD_CONVERSION_NAMES,
|
|
42
|
+
destinationName,
|
|
43
|
+
essentialAdDimensions,
|
|
44
|
+
isAdPlatform,
|
|
45
|
+
isBookkeepingRow,
|
|
46
|
+
parseEventKey,
|
|
47
|
+
rowMatchKeys
|
|
48
|
+
} from "./chunk-B65WCT6M.js";
|
|
49
|
+
import "./chunk-NKQWDEB7.js";
|
|
50
|
+
import {
|
|
51
|
+
repeatedValues
|
|
52
|
+
} from "./chunk-ERSX3MKH.js";
|
|
53
|
+
import "./chunk-D5FY4FAK.js";
|
|
54
|
+
import {
|
|
55
|
+
writeJsonEnvelope
|
|
56
|
+
} from "./chunk-HPDGVK6R.js";
|
|
57
|
+
import {
|
|
58
|
+
flowNodeTriggers
|
|
59
|
+
} from "./chunk-HVJJEQDQ.js";
|
|
60
|
+
import "./chunk-QV6AST5T.js";
|
|
61
|
+
import "./chunk-WCU362Z6.js";
|
|
62
|
+
import "./chunk-GIWHHCD6.js";
|
|
63
|
+
import "./chunk-SOPVIIUW.js";
|
|
64
|
+
import "./chunk-G4FG5EQO.js";
|
|
65
|
+
import "./chunk-NSBNIPIW.js";
|
|
66
|
+
import "./chunk-46YLDIQG.js";
|
|
67
|
+
import {
|
|
68
|
+
ApiError,
|
|
69
|
+
apiPost
|
|
70
|
+
} from "./chunk-B4UVJCJ4.js";
|
|
71
|
+
import "./chunk-AFQF6ISC.js";
|
|
72
|
+
import {
|
|
73
|
+
getEnv
|
|
74
|
+
} from "./chunk-52IYZCRS.js";
|
|
75
|
+
import {
|
|
76
|
+
registerSchema
|
|
77
|
+
} from "./chunk-FSGJSREN.js";
|
|
78
|
+
import "./chunk-YQSBHWOI.js";
|
|
79
|
+
|
|
80
|
+
// src/commands/analytics/index.ts
|
|
81
|
+
import { readFileSync } from "fs";
|
|
82
|
+
import { defineCommand } from "citty";
|
|
83
|
+
|
|
84
|
+
// src/commands/analytics/conversionCandidates.ts
|
|
85
|
+
function compact(row) {
|
|
86
|
+
return {
|
|
87
|
+
eventKey: row.eventKey,
|
|
88
|
+
events: row.events,
|
|
89
|
+
sessions: row.sessions,
|
|
90
|
+
...row.isCounted ? { countedAs: row.countedAs } : {}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function foldByForm(rows) {
|
|
94
|
+
const byForm = /* @__PURE__ */ new Map();
|
|
95
|
+
for (const row of rows) {
|
|
96
|
+
const form = byForm.get(row.flowSlug) ?? { form: row.flowSlug, keys: 0, countedKeys: 0, events: 0 };
|
|
97
|
+
form.keys += 1;
|
|
98
|
+
if (row.isCounted) form.countedKeys += 1;
|
|
99
|
+
form.events += row.events;
|
|
100
|
+
byForm.set(row.flowSlug, form);
|
|
101
|
+
}
|
|
102
|
+
return [...byForm.values()];
|
|
103
|
+
}
|
|
104
|
+
function candidatesForFlow(catalogue, flowSlug) {
|
|
105
|
+
return flowSlug === void 0 ? [...catalogue] : catalogue.filter((row) => row.flowSlug === flowSlug);
|
|
106
|
+
}
|
|
107
|
+
var FOLDED_FORMS_HINT = "A Form's candidates are folded into its `flows` row (`keys` fired, `events`; no `counted` means it counts nothing), or a `formCandidates` row when not listed. `--candidates --flow <slug>` lists that Form's keys; `--full` adds every field of every key.";
|
|
108
|
+
function candidatesView(rows, options) {
|
|
109
|
+
if (options.full) return { candidates: rows };
|
|
110
|
+
if (options.flowSlug !== void 0) return { candidates: rows.map(compact) };
|
|
111
|
+
const forms = foldByForm(rows.filter((row) => row.flowSlug !== ""));
|
|
112
|
+
return {
|
|
113
|
+
candidates: rows.filter((row) => row.flowSlug === "").map(compact),
|
|
114
|
+
...forms.length > 0 ? { formCandidates: forms } : {}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function fullFlagHints(args, format) {
|
|
118
|
+
if (!args.full || args.candidates && format !== "md") return [];
|
|
119
|
+
return ["`--full` only applies to `--candidates --output json`, so it changed nothing here."];
|
|
120
|
+
}
|
|
121
|
+
function compactConversionsEnvelope(envelope, options) {
|
|
122
|
+
const { candidates, flows, ...data } = envelope.data;
|
|
123
|
+
if (candidates === void 0) return { ...envelope };
|
|
124
|
+
const { formCandidates, ...view } = candidatesView(candidates, options);
|
|
125
|
+
const traffic = new Map(formCandidates?.map((form) => [form.form, form]));
|
|
126
|
+
const merged = flows?.map(({ slug, counted, noConversion }) => {
|
|
127
|
+
const form = traffic.get(slug);
|
|
128
|
+
traffic.delete(slug);
|
|
129
|
+
return {
|
|
130
|
+
slug,
|
|
131
|
+
...counted.length > 0 ? { counted } : {},
|
|
132
|
+
...noConversion !== null ? { noConversion } : {},
|
|
133
|
+
keys: form?.keys ?? 0,
|
|
134
|
+
events: form?.events ?? 0
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
const hints = [...envelope.hints ?? [], ...formCandidates ? [FOLDED_FORMS_HINT] : []];
|
|
138
|
+
return {
|
|
139
|
+
...envelope,
|
|
140
|
+
data: {
|
|
141
|
+
...data,
|
|
142
|
+
...merged ? { flows: merged } : {},
|
|
143
|
+
...view,
|
|
144
|
+
...traffic.size > 0 ? { formCandidates: [...traffic.values()] } : {}
|
|
145
|
+
},
|
|
146
|
+
...hints.length > 0 ? { hints } : {}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/commands/analytics/conversionHints.ts
|
|
151
|
+
var NAMED_CANDIDATES = 3;
|
|
152
|
+
function conversionHints(definitions, candidates, askedForCandidates) {
|
|
153
|
+
const hints = [];
|
|
154
|
+
if (definitions.length === 0) {
|
|
155
|
+
hints.push(
|
|
156
|
+
"Nothing is counted as a conversion, so EVERY conversion number in every other report is zero \u2014 whatever visitors actually did. Baker never guesses which event is the point of a page. Run `baker analytics conversions --candidates` to see what these pages produce, then count the ones that are worth money."
|
|
157
|
+
);
|
|
158
|
+
if (!askedForCandidates && candidates.length > 0) {
|
|
159
|
+
const top = candidates.slice(0, NAMED_CANDIDATES).map((row) => row.eventKey).join(", ");
|
|
160
|
+
hints.push(`${candidates.length} distinct events are available to count. Busiest: ${top}.`);
|
|
161
|
+
}
|
|
162
|
+
return hints;
|
|
163
|
+
}
|
|
164
|
+
const silent = definitions.filter((row) => row.lastSeen === null);
|
|
165
|
+
if (silent.length > 0) {
|
|
166
|
+
hints.push(
|
|
167
|
+
`${silent.length} counted outcome(s) have never fired in this window: ${silent.slice(0, NAMED_CANDIDATES).map((row) => row.name).join(
|
|
168
|
+
", "
|
|
169
|
+
)}. Either the page never reaches them, or the wrong event was named \u2014 check against --candidates before reporting a conversion rate.`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const uncounted = candidates.filter((row) => !row.isCounted);
|
|
173
|
+
const busiest = uncounted[0];
|
|
174
|
+
if (busiest && busiest.sessions > 0) {
|
|
175
|
+
const counted = candidates.filter((row) => row.isCounted);
|
|
176
|
+
const busiestCounted = counted.reduce((max, row) => Math.max(max, row.sessions), 0);
|
|
177
|
+
if (busiest.sessions > busiestCounted) {
|
|
178
|
+
hints.push(
|
|
179
|
+
`\`${busiest.eventKey}\` happened in ${busiest.sessions} visits and is not counted \u2014 more than anything that is. Check it is not the real outcome.`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return hints;
|
|
184
|
+
}
|
|
185
|
+
function namingHints(definitions) {
|
|
186
|
+
const names = [...new Set(definitions.map((row) => row.name))];
|
|
187
|
+
if (names.length === 0) {
|
|
188
|
+
return [
|
|
189
|
+
`Nothing is named yet, so the first name sets the vocabulary for this company. Start from the standard set \u2014 ${STANDARD_CONVERSION_NAMES.map((entry) => entry.name).join(", ")} \u2014 and stay in the company's own language once one exists.`
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
return [
|
|
193
|
+
`Names in use here: ${names.join(", ")}. Reuse one EXACTLY when another Form produces the same outcome \u2014 that is what makes them one number \u2014 and use \`--rename "<old>" --to "<existing>"\` to merge two that should always have been one.`
|
|
194
|
+
];
|
|
195
|
+
}
|
|
196
|
+
function stagedHints(definitions) {
|
|
197
|
+
const staged = definitions.filter((row) => row.staged === true);
|
|
198
|
+
if (staged.length === 0) return [];
|
|
199
|
+
return [
|
|
200
|
+
`Staged on this chat, not counted yet: ${staged.map((row) => `"${row.name}"`).join(", ")}. The person sees ${staged.length === 1 ? "it" : "them"} under Sources in the chat's changes, on the event's own row, and ${staged.length === 1 ? "it counts" : "they count"} from when they publish the chat; discarding the chat drops ${staged.length === 1 ? "it" : "them"}. Publishing also rescores events Baker ALREADY RECORDED under the key \u2014 never anything that happened in HubSpot or elsewhere before the event existed, so an event this chat just made starts at zero. Tell them that, not that it is already counted.`,
|
|
201
|
+
'When you talk to the person, call each event by its name ("Appointment scheduled"), never its key (`page:Appointment scheduled`): the key is how Baker spells it internally, and the `page:` part means nothing to them.'
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/commands/analytics/conversionList.ts
|
|
206
|
+
function mergeStoredWithCounts(stored, reported) {
|
|
207
|
+
const counts = new Map(reported.map((row) => [row.name, row]));
|
|
208
|
+
const groups = /* @__PURE__ */ new Map();
|
|
209
|
+
for (const row of stored) {
|
|
210
|
+
const group = groups.get(row.name) ?? [];
|
|
211
|
+
group.push(row);
|
|
212
|
+
groups.set(row.name, group);
|
|
213
|
+
}
|
|
214
|
+
return [...groups.entries()].map(([name, rows]) => {
|
|
215
|
+
const modes = new Set(rows.map((row) => row.countMode));
|
|
216
|
+
const counted = counts.get(name);
|
|
217
|
+
return {
|
|
218
|
+
name,
|
|
219
|
+
eventKeys: rows.map((row) => row.eventKey).sort(),
|
|
220
|
+
// A real state and usually an editing accident, which is why it is said
|
|
221
|
+
// out loud rather than resolved to one of them.
|
|
222
|
+
countMode: modes.size === 1 ? [...modes][0] : "mixed",
|
|
223
|
+
// Zero rather than absent: an outcome that is counted and has never
|
|
224
|
+
// fired is the most actionable row on this report, and dropping it
|
|
225
|
+
// would make it indistinguishable from one nobody has named.
|
|
226
|
+
conversions: counted?.conversions ?? 0,
|
|
227
|
+
convertingVisits: counted?.convertingVisits ?? 0,
|
|
228
|
+
unplaced: counted?.unplaced ?? 0,
|
|
229
|
+
lastSeen: counted?.lastSeen ?? null,
|
|
230
|
+
doors: counted?.doors ?? [],
|
|
231
|
+
...rows.some((row) => row.staged === true) ? { staged: true } : {}
|
|
232
|
+
};
|
|
233
|
+
}).sort((a, b) => a.name.localeCompare(b.name));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/commands/analytics/render.ts
|
|
237
|
+
var SPARKLINE_POINTS = 30;
|
|
238
|
+
var DASHBOARD_ONLY_FIELDS = /* @__PURE__ */ new Set([
|
|
239
|
+
// The Convex row id. It exists so a dashboard can link to the row; an agent
|
|
240
|
+
// addresses a landing by `landingId`, which is the id in its `_definition.md`.
|
|
241
|
+
"landingRef"
|
|
242
|
+
]);
|
|
243
|
+
function isAbsent(value) {
|
|
244
|
+
if (value === "") return true;
|
|
245
|
+
if (Array.isArray(value)) return value.length === 0;
|
|
246
|
+
if (typeof value === "object" && value !== null) return Object.keys(value).length === 0;
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
function resample(series, points) {
|
|
250
|
+
if (series.length <= points || points < 1) return [...series];
|
|
251
|
+
const out = [];
|
|
252
|
+
for (let i = 0; i < points; i += 1) {
|
|
253
|
+
const from = Math.floor(i * series.length / points);
|
|
254
|
+
const to = Math.floor((i + 1) * series.length / points);
|
|
255
|
+
let sum = 0;
|
|
256
|
+
for (let j = from; j < to; j += 1) sum += series[j] ?? 0;
|
|
257
|
+
out.push(sum);
|
|
258
|
+
}
|
|
259
|
+
return out;
|
|
260
|
+
}
|
|
261
|
+
function pruneValue(value, full) {
|
|
262
|
+
if (Array.isArray(value)) return value.map((entry) => pruneValue(entry, full));
|
|
263
|
+
if (typeof value === "object" && value !== null) {
|
|
264
|
+
return pruneRow(value, full);
|
|
265
|
+
}
|
|
266
|
+
return value;
|
|
267
|
+
}
|
|
268
|
+
function pruneRow(row, full) {
|
|
269
|
+
const out = {};
|
|
270
|
+
for (const [key, value] of Object.entries(row)) {
|
|
271
|
+
if (DASHBOARD_ONLY_FIELDS.has(key)) continue;
|
|
272
|
+
if (key === "sparkline" && Array.isArray(value)) {
|
|
273
|
+
if (!full) continue;
|
|
274
|
+
out[key] = resample(value, SPARKLINE_POINTS);
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (isAbsent(value)) continue;
|
|
278
|
+
out[key] = pruneValue(value, full);
|
|
279
|
+
}
|
|
280
|
+
return out;
|
|
281
|
+
}
|
|
282
|
+
function pruneForAgent(data, full) {
|
|
283
|
+
return pruneRow(data, full);
|
|
284
|
+
}
|
|
285
|
+
function isTabular(rows) {
|
|
286
|
+
return rows.every(
|
|
287
|
+
(row) => typeof row === "object" && row !== null && !Array.isArray(row) && Object.values(row).every(
|
|
288
|
+
(value) => value === null || typeof value !== "object" || Array.isArray(value) && value.every((e) => typeof e !== "object")
|
|
289
|
+
)
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
function cell(value, key) {
|
|
293
|
+
if (value === null || value === void 0) return "";
|
|
294
|
+
if (Array.isArray(value)) return value.join(" ");
|
|
295
|
+
if (typeof value === "number" && !Number.isInteger(value)) {
|
|
296
|
+
if (key?.endsWith("Ms")) return String(Math.round(value));
|
|
297
|
+
return value.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
|
|
298
|
+
}
|
|
299
|
+
return String(value);
|
|
300
|
+
}
|
|
301
|
+
var IDENTITY_COLUMNS = [
|
|
302
|
+
"landingId",
|
|
303
|
+
"name",
|
|
304
|
+
"slug",
|
|
305
|
+
"path",
|
|
306
|
+
"flowSlug",
|
|
307
|
+
"stepId",
|
|
308
|
+
"value",
|
|
309
|
+
"key",
|
|
310
|
+
"bucket",
|
|
311
|
+
"tag",
|
|
312
|
+
"eventName",
|
|
313
|
+
"release",
|
|
314
|
+
"place",
|
|
315
|
+
"bot",
|
|
316
|
+
"source",
|
|
317
|
+
"medium",
|
|
318
|
+
"campaign",
|
|
319
|
+
"platform",
|
|
320
|
+
"sessionId",
|
|
321
|
+
"eventId"
|
|
322
|
+
];
|
|
323
|
+
function byIdentityFirst(a, b) {
|
|
324
|
+
const ia = IDENTITY_COLUMNS.indexOf(a);
|
|
325
|
+
const ib = IDENTITY_COLUMNS.indexOf(b);
|
|
326
|
+
if (ia !== -1 || ib !== -1)
|
|
327
|
+
return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
|
|
328
|
+
return 0;
|
|
329
|
+
}
|
|
330
|
+
var BLOCK_ORDER = ["window", "totals", "previous", "pageInfo"];
|
|
331
|
+
function byBlockOrder(a, b) {
|
|
332
|
+
const rank = (key) => {
|
|
333
|
+
const at = BLOCK_ORDER.indexOf(key);
|
|
334
|
+
if (at !== -1) return at;
|
|
335
|
+
return key === "preset" ? BLOCK_ORDER.length + 1 : BLOCK_ORDER.length;
|
|
336
|
+
};
|
|
337
|
+
return rank(a) - rank(b);
|
|
338
|
+
}
|
|
339
|
+
function columnsOf(rows) {
|
|
340
|
+
const seen = [];
|
|
341
|
+
for (const row of rows) {
|
|
342
|
+
for (const key of Object.keys(row)) {
|
|
343
|
+
if (!seen.includes(key)) seen.push(key);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return seen.filter((key) => rows.some((row) => !isAbsent(row[key]) && row[key] !== null && row[key] !== void 0)).sort(byIdentityFirst);
|
|
347
|
+
}
|
|
348
|
+
function table(rows) {
|
|
349
|
+
const cols = columnsOf(rows);
|
|
350
|
+
if (cols.length === 0) return "";
|
|
351
|
+
const head = `| ${cols.join(" | ")} |`;
|
|
352
|
+
const rule = `| ${cols.map(() => "---").join(" | ")} |`;
|
|
353
|
+
const body = rows.map((row) => `| ${cols.map((col) => cell(row[col], col)).join(" | ")} |`);
|
|
354
|
+
return [head, rule, ...body].join("\n");
|
|
355
|
+
}
|
|
356
|
+
function isRowList(value) {
|
|
357
|
+
return Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
|
|
358
|
+
}
|
|
359
|
+
function labelOf(row, index) {
|
|
360
|
+
for (const key of IDENTITY_COLUMNS) {
|
|
361
|
+
const value = row[key];
|
|
362
|
+
if (typeof value === "string" && value !== "") return value;
|
|
363
|
+
}
|
|
364
|
+
return `#${index + 1}`;
|
|
365
|
+
}
|
|
366
|
+
function nestedBlock(name, rows) {
|
|
367
|
+
const parents = rows.map(
|
|
368
|
+
(row) => Object.fromEntries(Object.entries(row).filter(([, value]) => !isRowList(value) && !isPlainRow(value)))
|
|
369
|
+
);
|
|
370
|
+
const parts = [`### ${name}`, table(parents)];
|
|
371
|
+
rows.forEach((row, index) => {
|
|
372
|
+
for (const [key, value] of Object.entries(row)) {
|
|
373
|
+
if (isRowList(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table(value));
|
|
374
|
+
else if (isPlainRow(value)) parts.push(`#### ${name}[${labelOf(row, index)}].${key}`, table([value]));
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
return parts.filter((part) => part !== "").join("\n");
|
|
378
|
+
}
|
|
379
|
+
function isPlainRow(value) {
|
|
380
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
381
|
+
}
|
|
382
|
+
function block(name, value) {
|
|
383
|
+
if (Array.isArray(value)) {
|
|
384
|
+
if (value.length === 0) return "";
|
|
385
|
+
if (isTabular(value)) return `### ${name}
|
|
386
|
+
${table(value)}`;
|
|
387
|
+
if (isRowList(value)) return nestedBlock(name, value);
|
|
388
|
+
return `### ${name}
|
|
389
|
+
${JSON.stringify(value)}`;
|
|
390
|
+
}
|
|
391
|
+
if (typeof value === "object" && value !== null) {
|
|
392
|
+
const entries = Object.entries(value);
|
|
393
|
+
if (entries.length === 0) return "";
|
|
394
|
+
if (entries.every(([, v]) => v === null || typeof v !== "object")) {
|
|
395
|
+
return `### ${name}
|
|
396
|
+
${entries.map(([k, v]) => `- ${k}: ${v === null ? "null" : cell(v, k)}`).join("\n")}`;
|
|
397
|
+
}
|
|
398
|
+
return `### ${name}
|
|
399
|
+
${JSON.stringify(value)}`;
|
|
400
|
+
}
|
|
401
|
+
return `### ${name}
|
|
402
|
+
${cell(value)}`;
|
|
403
|
+
}
|
|
404
|
+
function renderMarkdown(envelope) {
|
|
405
|
+
const parts = [];
|
|
406
|
+
for (const warning of envelope.warnings ?? []) parts.push(`> **${warning.code}** \u2014 ${warning.message}`);
|
|
407
|
+
for (const hint of envelope.hints ?? []) parts.push(`> ${hint}`);
|
|
408
|
+
for (const [name, value] of Object.entries(envelope.data).sort(([a], [b]) => byBlockOrder(a, b))) {
|
|
409
|
+
const rendered = block(name, value);
|
|
410
|
+
if (rendered !== "") parts.push(rendered);
|
|
411
|
+
}
|
|
412
|
+
return `${parts.join("\n\n")}
|
|
413
|
+
`;
|
|
414
|
+
}
|
|
415
|
+
function missingBreakdownHint(data, asked) {
|
|
416
|
+
if (asked.eventName === void 0) return [];
|
|
417
|
+
const breakdown = data.eventBreakdown;
|
|
418
|
+
if (Array.isArray(breakdown) && breakdown.length > 0) return [];
|
|
419
|
+
const known = Array.isArray(data.customEvents) ? data.customEvents.flatMap((row) => isPlainRow(row) && typeof row.eventName === "string" ? [row.eventName] : []) : [];
|
|
420
|
+
return [
|
|
421
|
+
`No rows came back for --event ${asked.eventName}${asked.property ? ` --property ${asked.property}` : ""}. That event or property does not exist on these pages${known.length > 0 ? `; the ones that do are: ${known.slice(0, 12).join(", ")}${known.length > 12 ? ", \u2026" : ""}` : ""}.`
|
|
422
|
+
];
|
|
423
|
+
}
|
|
424
|
+
var ANALYTICS_OUTPUT_FORMATS = ["json", "md"];
|
|
425
|
+
function isAnalyticsOutputFormat(value) {
|
|
426
|
+
return ANALYTICS_OUTPUT_FORMATS.includes(value);
|
|
427
|
+
}
|
|
428
|
+
function writeAnalyticsReport(envelope, format) {
|
|
429
|
+
if (format === "md") {
|
|
430
|
+
process.stdout.write(renderMarkdown(envelope));
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
process.stdout.write(`${JSON.stringify(envelope)}
|
|
434
|
+
`);
|
|
435
|
+
}
|
|
436
|
+
var ROWS_BEFORE_FORMAT_HINT = 25;
|
|
437
|
+
function rowCount(data) {
|
|
438
|
+
let total = 0;
|
|
439
|
+
for (const value of Object.values(data)) {
|
|
440
|
+
if (Array.isArray(value)) total += value.length;
|
|
441
|
+
}
|
|
442
|
+
return total;
|
|
443
|
+
}
|
|
444
|
+
function formatHint(data, format) {
|
|
445
|
+
if (format === "md") return [];
|
|
446
|
+
const rows = rowCount(data);
|
|
447
|
+
if (rows < ROWS_BEFORE_FORMAT_HINT) return [];
|
|
448
|
+
return [
|
|
449
|
+
`This report is ${rows} rows. If you are going to read the numbers rather than pick one field out of them, --output md returns the same answer as tables, typically a third to a half smaller.`
|
|
450
|
+
];
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/commands/analytics/conversionsMarkdown.ts
|
|
454
|
+
function doorsCell(doors) {
|
|
455
|
+
return doors.map((door) => `${door.door}=${door.events}/${door.sessions}`).join(" ");
|
|
456
|
+
}
|
|
457
|
+
function eventKeysCell(eventKeys) {
|
|
458
|
+
const formKeys = eventKeys.filter((key) => key.startsWith("form:")).length;
|
|
459
|
+
const others = eventKeys.filter((key) => !key.startsWith("form:"));
|
|
460
|
+
return [...others, ...formKeys > 0 ? [`${formKeys} Form ending(s)`] : []].join(" + ");
|
|
461
|
+
}
|
|
462
|
+
function trafficByForm(candidates) {
|
|
463
|
+
const byForm = /* @__PURE__ */ new Map();
|
|
464
|
+
for (const row of candidates) {
|
|
465
|
+
const form = byForm.get(row.flowSlug) ?? { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
|
|
466
|
+
if (row.events > 0) form["endings seen"] += 1;
|
|
467
|
+
if (row.isCounted) form["endings counted"] += 1;
|
|
468
|
+
form.events += row.events;
|
|
469
|
+
if (row.lastSeen && row.lastSeen.slice(0, 10) > form.lastSeen) form.lastSeen = row.lastSeen.slice(0, 10);
|
|
470
|
+
byForm.set(row.flowSlug, form);
|
|
471
|
+
}
|
|
472
|
+
return byForm;
|
|
473
|
+
}
|
|
474
|
+
var NO_TRAFFIC = { "endings seen": 0, "endings counted": 0, events: 0, lastSeen: "" };
|
|
475
|
+
var FORM_KEYS_HINT = "A Form's candidates are one row per Form: `baker analytics conversions --flow <slug>` lists that Form's event keys, and `--candidates --full --output json` lists every key with every field.";
|
|
476
|
+
function renderConversionsMarkdown(envelope) {
|
|
477
|
+
const { definitions, flow, flows, candidates } = envelope.data;
|
|
478
|
+
const data = {
|
|
479
|
+
definitions: definitions.map(({ name, eventKeys, ...row }) => ({
|
|
480
|
+
name,
|
|
481
|
+
eventKeys: eventKeysCell(eventKeys),
|
|
482
|
+
...row
|
|
483
|
+
}))
|
|
484
|
+
};
|
|
485
|
+
if (flow) {
|
|
486
|
+
data.flow = { slug: flow.slug, noConversionReason: flow.noConversionReason };
|
|
487
|
+
data.flowEndings = flow.endings;
|
|
488
|
+
}
|
|
489
|
+
const traffic = candidates ? trafficByForm(candidates.filter((row) => row.flowSlug !== "")) : /* @__PURE__ */ new Map();
|
|
490
|
+
if (flows) {
|
|
491
|
+
data.flows = flows.map((row) => ({
|
|
492
|
+
slug: row.slug,
|
|
493
|
+
counted: row.counted.map((entry) => `${entry.name} @ ${entry.step}`).join("; "),
|
|
494
|
+
noConversion: row.noConversion,
|
|
495
|
+
...candidates ? traffic.get(row.slug) ?? NO_TRAFFIC : {}
|
|
496
|
+
}));
|
|
497
|
+
}
|
|
498
|
+
const hints = [...envelope.hints ?? []];
|
|
499
|
+
if (candidates) {
|
|
500
|
+
const listed = new Set(flows?.map((row) => row.slug));
|
|
501
|
+
const unlisted = [...traffic].filter(([slug]) => !listed.has(slug));
|
|
502
|
+
if (unlisted.length > 0) data.formCandidates = unlisted.map(([form, row]) => ({ form, ...row }));
|
|
503
|
+
data.candidates = candidates.filter((row) => row.flowSlug === "").map(({ doors, flowSlug: _flowSlug, nodeType: _nodeType, ...row }) => ({
|
|
504
|
+
...row,
|
|
505
|
+
"doors (events/sessions)": doorsCell(doors)
|
|
506
|
+
}));
|
|
507
|
+
if (traffic.size > 0) hints.push(FORM_KEYS_HINT);
|
|
508
|
+
}
|
|
509
|
+
return renderMarkdown({ data, ...hints.length > 0 ? { hints } : {} });
|
|
510
|
+
}
|
|
511
|
+
function withFormatHint(envelope, format) {
|
|
512
|
+
const hints = [...envelope.hints ?? [], ...formatHint({ ...envelope.data }, format)];
|
|
513
|
+
return { ...envelope, ...hints.length > 0 ? { hints } : {} };
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// src/commands/analytics/debugLink.ts
|
|
517
|
+
function debugStartHints(started) {
|
|
518
|
+
if (started.link === null) {
|
|
519
|
+
return [
|
|
520
|
+
`Code ${started.code} records for two hours. Run it again with --url <the page to test> for a link to send, or add ?baker_debug=${started.code} to that page's address yourself.`
|
|
521
|
+
];
|
|
522
|
+
}
|
|
523
|
+
return [
|
|
524
|
+
`Send the person this link: ${started.link} \u2014 they open it in the browser they normally use, accept the cookie banner, do exactly what did not work (open the widget, start the call, submit the form), then tell you they are done. Then run \`baker analytics debug ${started.code}\`. It records for two hours, nothing it records is counted anywhere, and emails and phone numbers are masked.`
|
|
525
|
+
];
|
|
526
|
+
}
|
|
527
|
+
function inner(row) {
|
|
528
|
+
if (!row.data) return "";
|
|
529
|
+
try {
|
|
530
|
+
const parsed = JSON.parse(row.data);
|
|
531
|
+
const name = parsed.event ?? parsed.action ?? parsed.name;
|
|
532
|
+
return typeof name === "string" ? name : "";
|
|
533
|
+
} catch {
|
|
534
|
+
return "";
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function isTagManagerNoise(label) {
|
|
538
|
+
return label.startsWith("gtm.") || label.startsWith("cookie_consent") || label === "consent" || label === "set";
|
|
539
|
+
}
|
|
540
|
+
var FOLLOWS_WITHIN_MS = 2e3;
|
|
541
|
+
function debugReadHints(read) {
|
|
542
|
+
if (read.records.length === 0) {
|
|
543
|
+
return [
|
|
544
|
+
`Nothing recorded under ${read.code}: the Baker tag never loaded on a visit with this link. Either the link was not opened yet, the cookie banner was not accepted (on a site that loads Tag Manager only after consent, the tag never starts), or the site dropped ?baker_debug from the address before the tag ran. ${read.active ? "The link still records \u2014 ask them to try again." : "The link has expired; start a new one."}`
|
|
545
|
+
];
|
|
546
|
+
}
|
|
547
|
+
const hints = [];
|
|
548
|
+
const boot = read.records.find((row) => row.kind === "pixel" && row.label === "boot");
|
|
549
|
+
if (boot?.data?.includes('"measuring":false')) {
|
|
550
|
+
hints.push(
|
|
551
|
+
"The tag did not measure this visit (its scope or the visitor's consent ruled it out), so its `track` calls sent nothing to Baker. The records below are still what the page heard."
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
const messages = read.records.filter((row) => row.kind === "message" && row.from && row.from !== "null");
|
|
555
|
+
const byOrigin = /* @__PURE__ */ new Map();
|
|
556
|
+
for (const row of messages) {
|
|
557
|
+
const said = byOrigin.get(row.from ?? "") ?? /* @__PURE__ */ new Map();
|
|
558
|
+
const what = inner(row) ? `${row.label} (${inner(row)})` : row.label;
|
|
559
|
+
said.set(what, (said.get(what) ?? 0) + 1);
|
|
560
|
+
byOrigin.set(row.from ?? "", said);
|
|
561
|
+
}
|
|
562
|
+
for (const [origin, said] of byOrigin) {
|
|
563
|
+
hints.push(
|
|
564
|
+
`${origin} sent: ${[...said].map(([what, count]) => count > 1 ? `${what} \xD7${count}` : what).join(", ")}. An event that is not on this list was never sent by that frame on this visit \u2014 the tag manager could not have passed it on.`
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
const unanswered = messages.filter(
|
|
568
|
+
(message) => !read.records.some(
|
|
569
|
+
(row) => row.kind === "dataLayer" && !isTagManagerNoise(row.label) && // Either side of it: a listener the site registered before the tag
|
|
570
|
+
// ran first, so its push is stamped before the message is.
|
|
571
|
+
Math.abs(row.t - message.t) <= FOLLOWS_WITHIN_MS
|
|
572
|
+
)
|
|
573
|
+
);
|
|
574
|
+
if (unanswered.length > 0) {
|
|
575
|
+
hints.push(
|
|
576
|
+
`${[...new Set(unanswered.map((row) => row.label))].join(", ")}: arrived as a message and no dataLayer event followed, so no tag listening for one could fire. Compare the message (--full) with the listener in the container (\`baker tag-manager read --entities tag --full\`) \u2014 a different \`type\` or event name is the usual cause.`
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
const tracked = read.records.filter((row) => row.kind === "track").map((row) => row.label);
|
|
580
|
+
if (tracked.length > 0) {
|
|
581
|
+
hints.push(
|
|
582
|
+
`The tag was asked to send: ${[...new Set(tracked)].join(", ")}. These reach Baker's feed within a minute or two (\`baker analytics feed --origin website --days 1\`).`
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
if (read.dropped > 0)
|
|
586
|
+
hints.push(`${read.dropped} records arrived after this link had kept its maximum and were not kept.`);
|
|
587
|
+
return hints;
|
|
588
|
+
}
|
|
589
|
+
function compactDebugRead(read, full) {
|
|
590
|
+
if (full) return read;
|
|
591
|
+
return { ...read, records: read.records.map(({ data: _data, ...row }) => row) };
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/commands/analytics/feedRows.ts
|
|
595
|
+
function isStreamRow(value) {
|
|
596
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
597
|
+
}
|
|
598
|
+
function enrich(row) {
|
|
599
|
+
const out = { ...row };
|
|
600
|
+
const destination = typeof row.sideEffectType === "string" ? row.sideEffectType : "";
|
|
601
|
+
if (destination !== "") out.destination = destinationName(destination);
|
|
602
|
+
const keys = rowMatchKeys(row.userData);
|
|
603
|
+
if (keys.length > 0) out.matchedBy = keys.map((key) => key.field);
|
|
604
|
+
return out;
|
|
605
|
+
}
|
|
606
|
+
function shapeFeed(stream, everything) {
|
|
607
|
+
if (!Array.isArray(stream)) return { rows: [], heldBack: 0 };
|
|
608
|
+
const rows = stream.filter(isStreamRow);
|
|
609
|
+
const kept = everything ? rows : rows.filter((row) => !isBookkeepingRow({ eventType: row.eventType ?? "", triggerId: row.triggerId ?? "" }));
|
|
610
|
+
return { rows: kept.map(enrich), heldBack: rows.length - kept.length };
|
|
611
|
+
}
|
|
612
|
+
function feedHints(shape) {
|
|
613
|
+
const hints = [];
|
|
614
|
+
if (shape.heldBack > 0) {
|
|
615
|
+
hints.push(
|
|
616
|
+
`${shape.heldBack} ${shape.heldBack === 1 ? "row is" : "rows are"} not listed: rows recorded to work the reports out \u2014 identifications, step views, session starts, a destination's answer already folded onto its dispatch \u2014 and embedded forms and calendars announcing that they drew. Add --everything to see them.`
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
const upload = shape.rows.find((row) => row.sideEffectType !== void 0 && row.eventId !== void 0);
|
|
620
|
+
if (upload !== void 0) {
|
|
621
|
+
hints.push(
|
|
622
|
+
`A delivery row carries the event it was made for in \`eventId\`. \`baker analytics feed --uid ${String(upload.eventId)}\` returns that event and every upload made for it, each with the platform's verdict.`
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
return hints;
|
|
626
|
+
}
|
|
627
|
+
function hiddenMachinesHints(hidden) {
|
|
628
|
+
if (hidden === void 0 || hidden.events === 0) return [];
|
|
629
|
+
const headless = hidden.reasons.some((share) => share.reason === "ua");
|
|
630
|
+
const why = headless ? "a headless browser, which is what agent-browser is, so a check you ran on the site lands here" : "a datacenter or crawler network, or headers no real browser sends";
|
|
631
|
+
return [
|
|
632
|
+
`${hidden.events} events in this window came from machines and are not listed \u2014 stored, but left out of the feed and every report (${why}). They arrived; this is not lost data. \`baker analytics feed --bots\` lists them, each with its \`botReason\`. Never present them to the client as visits.`
|
|
633
|
+
];
|
|
634
|
+
}
|
|
635
|
+
function peopleSearchHints(search, rows) {
|
|
636
|
+
const found = new Set(rows.flatMap((row) => Array.isArray(row.personTerms) ? row.personTerms : []));
|
|
637
|
+
return search.filter((term) => !found.has(term.term)).map(
|
|
638
|
+
(term) => term.problem !== "" ? `${term.input}: ${term.problem}` : `${term.input}: nothing in this window on this page. \`baker analytics lookup --person '${term.input}'\` reads everything Baker ever saw of them.`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// src/commands/analytics/flowConversionKeys.ts
|
|
643
|
+
function formKeyRefusal(eventKey, tree, slug) {
|
|
644
|
+
const parsed = parseEventKey(eventKey);
|
|
645
|
+
if (parsed?.family !== "form" || parsed.flowSlug !== slug) return null;
|
|
646
|
+
const node = flowNodes(tree).find((candidate) => candidate.id === parsed.nodeId);
|
|
647
|
+
if (!node) {
|
|
648
|
+
return {
|
|
649
|
+
message: `"${slug}" has no step with id "${parsed.nodeId}", so this key would be stored and count zero forever.`,
|
|
650
|
+
fix: `Steps in this Form: ${flowNodes(tree).map((n) => `${String(n.id)} (${String(n.name ?? "unnamed")})`).join(", ")}. \`baker analytics conversions --flow ${slug}\` prints each one already spelled as an event key.`
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
const triggers = flowNodeTriggers(node.nodeData);
|
|
654
|
+
if (!triggers.known || triggers.available.includes(parsed.triggerId)) return null;
|
|
655
|
+
return {
|
|
656
|
+
message: `Step "${String(node.name ?? node.id)}" never raises \`${parsed.triggerId}\`, so counting it would score zero however many people reach that step.`,
|
|
657
|
+
fix: triggers.available.length > 0 ? `It raises: ${triggers.available.join(", ")}.` : triggers.why ?? "That step raises nothing a conversion could be counted on."
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
function joinFlowConversions(candidates, definitions) {
|
|
661
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
662
|
+
for (const definition of definitions) {
|
|
663
|
+
for (const key of definition.eventKeys) byKey.set(key, definition.name);
|
|
664
|
+
}
|
|
665
|
+
return candidates.map((candidate) => ({ ...candidate, countedAs: byKey.get(candidate.eventKey) ?? null }));
|
|
666
|
+
}
|
|
667
|
+
function flowConversionHints(slug, rows, noConversionReason) {
|
|
668
|
+
const counted = rows.filter((row) => row.countedAs !== null);
|
|
669
|
+
if (counted.length > 0) {
|
|
670
|
+
return [
|
|
671
|
+
`Baker counts ${counted.length} of this Form's endings: ${counted.map((row) => `${row.countedAs} (${row.nodeName})`).join(
|
|
672
|
+
", "
|
|
673
|
+
)}. Every other ending here scores nothing \u2014 count another with \`--event <key> --name <outcome>\`, reusing the SAME name to make two Forms one number.`
|
|
674
|
+
];
|
|
675
|
+
}
|
|
676
|
+
if (noConversionReason) {
|
|
677
|
+
return [
|
|
678
|
+
`Nothing here is counted, and that is on purpose: this Form declares no outcome \u2014 "${noConversionReason}". Leave it alone unless that has stopped being true.`
|
|
679
|
+
];
|
|
680
|
+
}
|
|
681
|
+
return [
|
|
682
|
+
`Nothing on "${slug}" is counted, so it converts nobody on every report however many people finish it. Which ending is its outcome is your call, never Baker's: read the endings above by the step each happens on (\`nodeName\`), and when the step names do not make it obvious \u2014 a Form that branches into a rejection and a confirmation \u2014 ask the person which one means a real result. Then \`baker analytics conversions --event "<key>" --name "<what a person calls it>"\`. If this Form is already on a funnel step, count the key that step uses, so the two numbers agree.`,
|
|
683
|
+
`If this Form has no outcome of its own \u2014 it hands the visitor to a shop, a portal or a funnel that converts them there \u2014 say so instead, with \`noConversion: { "reason": "\u2026" }\` on its first step.`
|
|
684
|
+
];
|
|
685
|
+
}
|
|
686
|
+
function flowCoverage(forms, definitions) {
|
|
687
|
+
return forms.map(({ slug, tree }) => {
|
|
688
|
+
const rows = joinFlowConversions(flowEventKeys(tree, slug), definitions);
|
|
689
|
+
const declared = tree?.noConversion?.reason;
|
|
690
|
+
const seen = /* @__PURE__ */ new Set();
|
|
691
|
+
return {
|
|
692
|
+
slug,
|
|
693
|
+
counted: rows.filter((row) => row.countedAs !== null).filter((row) => {
|
|
694
|
+
const key = `${row.countedAs} ${row.nodeName}`;
|
|
695
|
+
if (seen.has(key)) return false;
|
|
696
|
+
seen.add(key);
|
|
697
|
+
return true;
|
|
698
|
+
}).map((row) => ({ name: String(row.countedAs), step: row.nodeName })),
|
|
699
|
+
noConversion: typeof declared === "string" && declared.trim() !== "" ? declared.trim() : null
|
|
700
|
+
};
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
function flowCoverageHints(coverage) {
|
|
704
|
+
const unset = coverage.filter((row) => row.counted.length === 0 && row.noConversion === null);
|
|
705
|
+
if (unset.length === 0) return [];
|
|
706
|
+
return [
|
|
707
|
+
`${unset.length} of ${coverage.length} Form(s) here count nothing, so every report shows them converting nobody: ${unset.map((row) => row.slug).join(
|
|
708
|
+
", "
|
|
709
|
+
)}. Read each one's endings with \`baker analytics conversions --flow <slug>\` and name the outcome, or declare on its first step why it has none.`
|
|
710
|
+
];
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// src/commands/analytics/hints.ts
|
|
714
|
+
var SEVERE_STEP_DROP = 0.6;
|
|
715
|
+
var MIN_SESSIONS_FOR_RATES = 100;
|
|
716
|
+
var SHALLOW_ENGAGEMENT_MS = 1e4;
|
|
717
|
+
function percent(value) {
|
|
718
|
+
return `${Math.round(value * 100)}%`;
|
|
719
|
+
}
|
|
720
|
+
var MIN_SESSIONS_FOR_TAGGING_CLAIM = 20;
|
|
721
|
+
function shapeHints(data) {
|
|
722
|
+
const hints = [];
|
|
723
|
+
const pageInfo = data.pageInfo;
|
|
724
|
+
if (pageInfo?.hasMore) {
|
|
725
|
+
hints.push(
|
|
726
|
+
`This is page ${pageInfo.page} of ${pageInfo.block} (${pageInfo.returned} rows) and there are more \u2014 pass --page ${pageInfo.page + 1} for the next one. Do not report a total from one page.`
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
for (const entry of data.adPlatformTraffic ?? []) {
|
|
730
|
+
if (entry.sessions >= MIN_SESSIONS_FOR_TAGGING_CLAIM && entry.taggedSessions === 0) {
|
|
731
|
+
hints.push(
|
|
732
|
+
`${entry.sessions} visits arrived from ${entry.platform} carrying no campaign parameters at all \u2014 the ad URLs are untagged, so there is nothing for a mapping to read. That is a change in their ad account, not in Baker.`
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
const unread = (data.adParams ?? []).filter((row) => row.role === void 0 && row.sessions > 0);
|
|
737
|
+
if (unread.length > 0) {
|
|
738
|
+
const named = unread.slice(0, 8).map((row) => `${row.name} (${row.sessions} visits)`).join(", ");
|
|
739
|
+
hints.push(
|
|
740
|
+
`Nothing reads these parameters yet: ${named}${unread.length > 8 ? ", \u2026" : ""}. Their values are not being stored \u2014 only the fact that the name appeared \u2014 so any breakdown over them is empty rather than wrong. Name each one with \`baker analytics map --platform <platform> --set <name>=<role>\`; mapping also fixes the history for a parameter Baker was already capturing.`
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
const unplaceable = data.adParamsUnattributed ?? [];
|
|
744
|
+
if (unplaceable.length > 0) {
|
|
745
|
+
hints.push(
|
|
746
|
+
`Some parameters arrive on visits with no click id and no recognised source, so no platform can be named for them: ${unplaceable.map((row) => row.name).join(", ")}. If you know where they come from, map them with --platform on that platform.`
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
return hints;
|
|
750
|
+
}
|
|
751
|
+
function adHierarchyHints(data, platform) {
|
|
752
|
+
if (platform === void 0) return [];
|
|
753
|
+
const traffic = (data.adPlatformTraffic ?? []).find((entry) => entry.platform === platform);
|
|
754
|
+
if (traffic === void 0 || traffic.sessions < MIN_SESSIONS_FOR_TAGGING_CLAIM) return [];
|
|
755
|
+
if (traffic.taggedSessions === 0) return [];
|
|
756
|
+
const carried = new Set(
|
|
757
|
+
(data.adParams ?? []).filter((row) => row.role !== void 0 && row.awaitingTraffic !== true).map((row) => row.role)
|
|
758
|
+
);
|
|
759
|
+
const missing = essentialAdDimensions(platform).filter((entry) => !carried.has(entry.role));
|
|
760
|
+
if (missing.length === 0) return [];
|
|
761
|
+
const suffix = missing.map((entry) => `${entry.names[0] ?? entry.role}=${entry.macro}`).join("&");
|
|
762
|
+
return [
|
|
763
|
+
`${platform} traffic carries no ${missing.map((entry) => AD_PARAM_ROLE_SPECS[entry.role].label.toLowerCase()).join(", ")}, so no report can say which ad sent a visit \u2014 only which platform. Add \`${suffix}\` to that account's tracking template. This cannot be backfilled: a parameter's values are only stored once it starts arriving.`
|
|
764
|
+
];
|
|
765
|
+
}
|
|
766
|
+
function sessionlessHint(data, origin) {
|
|
767
|
+
if (data.totals.pageViews === 0 || data.totals.sessions > 0) return [];
|
|
768
|
+
if (origin === "server") {
|
|
769
|
+
return [
|
|
770
|
+
"No sessions, because this report is scoped to events a client's own server posted and those carry no visit \u2014 a session would be an invented one. Every per-visitor rate here is null for the same reason; read the counts, and drop --origin for anything about behaviour."
|
|
771
|
+
];
|
|
772
|
+
}
|
|
773
|
+
return [
|
|
774
|
+
"Pages were served but no sessions were counted \u2014 visitors are declining analytics consent, so traffic is measurable and per-visitor behaviour is not. Say so rather than reporting zero visitors."
|
|
775
|
+
];
|
|
776
|
+
}
|
|
777
|
+
function measureScopeHint(data) {
|
|
778
|
+
const scope = data.measureScope?.scope;
|
|
779
|
+
if (scope === "all") {
|
|
780
|
+
return [
|
|
781
|
+
"This company's website tag measures EVERY visitor of their own website, but this report does not: visits, views and conversions here count only people who visited a Baker landing, and a sale on their site counts only when its person viewed a landing in the 90 days before it. Everything else the tag sees is in `baker analytics feed`, not in these numbers."
|
|
782
|
+
];
|
|
783
|
+
}
|
|
784
|
+
if (scope === "outcomes") {
|
|
785
|
+
return [
|
|
786
|
+
"This company's website tag reports outcomes only, so no browsing on their own site is measured. Visits and views cover Baker pages alone, and a drop-off between a Baker page and a sale is invisible rather than absent."
|
|
787
|
+
];
|
|
788
|
+
}
|
|
789
|
+
return [];
|
|
790
|
+
}
|
|
791
|
+
function buildAnalyticsHints(data, platform, origin) {
|
|
792
|
+
const hints = [];
|
|
793
|
+
hints.push(...measureScopeHint(data));
|
|
794
|
+
for (const funnel of data.funnels ?? []) {
|
|
795
|
+
const worst = funnel.worstStep;
|
|
796
|
+
if (worst && worst.dropRate !== null && worst.dropRate >= SEVERE_STEP_DROP) {
|
|
797
|
+
hints.push(
|
|
798
|
+
`Form "${funnel.flowSlug}" loses ${percent(worst.dropRate)} of people at step "${worst.stepId}" \u2014 open the flow-builder skill and look at what that step asks for.`
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (data.totals.sessions > 0 && data.totals.sessions < MIN_SESSIONS_FOR_RATES) {
|
|
803
|
+
hints.push(
|
|
804
|
+
"Too few sessions to read rates as reliable \u2014 report the absolute numbers and say the period is small, rather than quoting a conversion rate."
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
if (data.totals.avgEngagementMs !== null && data.totals.avgEngagementMs < SHALLOW_ENGAGEMENT_MS) {
|
|
808
|
+
hints.push(
|
|
809
|
+
"Visitors leave in under ten seconds on average \u2014 that is usually a mismatch between the ad and the page, not a form problem. Check the top sources against the page's headline."
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
hints.push(...sessionlessHint(data, origin));
|
|
813
|
+
hints.push(...shapeHints(data));
|
|
814
|
+
hints.push(...adHierarchyHints(data, platform));
|
|
815
|
+
if ((data.topCampaigns ?? []).length === 0 && (data.topSources ?? []).length > 0) {
|
|
816
|
+
hints.push(
|
|
817
|
+
"No campaign tagging on any traffic \u2014 ad clicks cannot be attributed to a campaign until the destination URLs carry utm parameters."
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
hints.push(...campaignOriginHints(data.topCampaigns));
|
|
821
|
+
return hints;
|
|
822
|
+
}
|
|
823
|
+
function campaignOriginHints(rows) {
|
|
824
|
+
const campaigns = rows ?? [];
|
|
825
|
+
const fromAds = campaigns.filter((row) => row.clickPlatform !== "");
|
|
826
|
+
if (fromAds.length === 0) return [];
|
|
827
|
+
const own = campaigns.length - fromAds.length;
|
|
828
|
+
return [
|
|
829
|
+
`${fromAds.length} of these campaigns arrived on an ad click (\`clickPlatform\` is set). \`baker analytics ads --role campaign_id\` MAY report the same campaigns under the platform's own ids \u2014 check before you quote both, or you will count one campaign twice. It may equally report nothing: \`ads\` only reads parameters the account tags separately, and \`utm_campaign\` is reserved and never reaches it, so an account whose only campaign signal is \`utm_campaign\` has its campaigns HERE and nowhere else. Never report "no campaigns" on the strength of an empty \`ads\`. ${own === 0 ? "Every row here came from an ad." : `The other ${own} carry no click id at all \u2014 a newsletter, a partner link, a tagged post \u2014 and only this report can show them.`}`
|
|
830
|
+
];
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// src/commands/analytics/presets.ts
|
|
834
|
+
var ANALYTICS_PRESET_INFO = [
|
|
835
|
+
{
|
|
836
|
+
name: "overview",
|
|
837
|
+
description: "Everything at once: traffic, top pages with their conversion rates, where visitors came from, the worst step of every Form, and what the conversion number consists of \u2014 one row per outcome the company marked, by the name they gave it. Start here. A `conversions` row at zero means the outcome is marked and has never fired, which is usually a Form that never reaches it.",
|
|
838
|
+
playbook: "landing \u2014 diagnose a page that gets traffic but few leads"
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
name: "traffic",
|
|
842
|
+
description: "Where visitors come from \u2014 trend, sources, campaigns, countries, devices.",
|
|
843
|
+
playbook: "the platform playbook for the channel that dominates"
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
name: "funnel",
|
|
847
|
+
description: "Per-step drop-off for the company's Forms. Narrow to one with --flow.",
|
|
848
|
+
playbook: "flow-builder \u2014 fix the step that loses people"
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
name: "flow",
|
|
852
|
+
description: "One Form in depth: conversions counted at the node that produced them, step-to-step paths for a branching Form, the per-step table, every trigger raised, and each marked conversion by name. Read convertedSessions rather than submits \u2014 a Form whose scheduling widget sits mid-flow never emits a submit and reports zero on every other report. An empty `conversions` array means nobody has marked what this Form is for, so every conversion number for it is a zero rather than a measurement \u2014 Baker never guesses which ending is the point of a Form. Mark it in the Forms builder or with `conversions: [{ triggerId }]` on the node. Before proposing a mark, check that Form's `_data.json` for `noConversion` on its first step: that is its author saying the outcome happens somewhere Baker cannot see, so its zero is a finished answer rather than a gap. The declaration lives in the Form and never reaches this report, which is built entirely from the event store. `flowDestinations` is the other half and is evidence rather than a count: which Forms demonstrably handed something over in this window. Read it against the scaffold's `flow-no-destination` warning before acting on one \u2014 the stored picture of a Form is only rewritten when it is published, so a destination added since then shows there and not in the tree.",
|
|
853
|
+
playbook: "flow-builder \u2014 fix the branch or the step that loses people"
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
name: "page",
|
|
857
|
+
description: "One page in detail. Requires --path.",
|
|
858
|
+
playbook: "landing"
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
name: "triggers",
|
|
862
|
+
description: "What visitors did inside a Form and how much of it fired a side effect \u2014 link clicks that leave the site, scheduling widgets, embedded checkouts. The funnel shows the steps they walked; this shows what they did. A trigger with many fires and no side effects is behaviour nobody is measuring yet.",
|
|
863
|
+
playbook: "flow-builder \u2014 wire up what matters, or tags for what should be measured"
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
name: "paid",
|
|
867
|
+
description: "Paid campaigns, grouped by session rather than by page view, with the click ids that resolve to a real ad click \u2014 and, crucially, how many of those leads were actually DELIVERED to the CRM. A campaign whose forms all submit and whose integration is rejecting every one of them looks perfect on every other preset and reads as zero delivered here.",
|
|
868
|
+
playbook: "the platform playbook for the channel \u2014 or tags, when the gap is delivery rather than acquisition"
|
|
869
|
+
},
|
|
870
|
+
{
|
|
871
|
+
name: "delivery",
|
|
872
|
+
description: 'Where each submission actually went: every destination it reached, whether that destination accepted it, and the id the destination gave the record it created. Failures only by default; --full lists every submission. This is the preset for "I filled in the form, where is my lead?".',
|
|
873
|
+
playbook: "flow-builder \u2014 repair the destination that is refusing leads"
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
name: "submissions",
|
|
877
|
+
description: "Every attempt anybody made at a Form \u2014 one visitor, one Form, one visit \u2014 finished, abandoned halfway, or completed on a Form that sends nowhere. The honest companion to `delivery`, which is built from dispatches and so cannot show a Form with no destination at all. Read it when the question is what was collected rather than what was handed over. A list, so it pages.",
|
|
878
|
+
playbook: "flow-builder \u2014 the Form that collects and sends nothing is the one to wire up"
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
name: "geo",
|
|
882
|
+
description: "Where the people who convert actually are, at whatever resolution you ask for: country, region, city, postcode or US DMA. Country answers 'which market is this working in'; postcode answers the question a local advertiser is actually asking, and matches the unit Google and Meta sell that targeting in.",
|
|
883
|
+
playbook: "the platform playbook for the channel \u2014 narrow the targeting to where it already works"
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
name: "bots",
|
|
887
|
+
description: "Which machines fetch this site. Every other report here excludes them; this one reads them. Answers whether Google is still crawling a page after it was republished, whether Meta fetched a link preview before spend went behind the URL, and how much of the traffic is now AI answer engines.",
|
|
888
|
+
playbook: "landing \u2014 a page that stopped being crawled stops ranking, weeks before the traffic shows it"
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
name: "companies",
|
|
892
|
+
description: "Which companies are visiting, named by the visitor's own network \u2014 never a person \u2014 with visits, pages read and first/last seen. Recorded only for visitors who accepted marketing cookies, on a company that switched it on. --targets keeps the target accounts that came and lists the ones that did not.",
|
|
893
|
+
playbook: "abm-playbook \u2014 which target accounts the ads warmed enough to read the pages"
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
name: "landings",
|
|
897
|
+
description: "Every landing side by side \u2014 views, entrances, conversion rate and a sparkline each, under the name a person gave it. Answers 'which of my pages is working' without having to know the answer first; `page` then answers one of them in depth. --tag narrows it to a campaign.",
|
|
898
|
+
playbook: "landing \u2014 pick the page worth working on before working on one"
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
name: "tags",
|
|
902
|
+
description: "The same numbers rolled up by the tag a landing is filed under \u2014 the unit a campaign is actually run at. A client asks how the September push did, and September was six landings.",
|
|
903
|
+
playbook: "the platform playbook for the channel \u2014 judge the campaign, not the page"
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
name: "events",
|
|
907
|
+
description: "Events the pages define for themselves: a section seen, a video played, a button clicked. Lists each with the property keys it carries so it can be broken down, and takes --steps for an ORDERED funnel over them \u2014 where a session only counts at a step if it reached it after the one before, so 'saw pricing then clicked demo' is not the same number as the reverse.",
|
|
908
|
+
playbook: "landing \u2014 measure the part of the page the Form funnel cannot see"
|
|
909
|
+
},
|
|
910
|
+
{
|
|
911
|
+
name: "devices",
|
|
912
|
+
description: "Browser, OS, engine or viewport of real visitors, with the conversion rate of each. Narrow enough to reproduce a bug on: 'mobile converts worse' is not actionable, 'Safari 17 under 380px converts at a third of the rate' is.",
|
|
913
|
+
playbook: "landing \u2014 fix the client the page is broken on"
|
|
914
|
+
},
|
|
915
|
+
{
|
|
916
|
+
name: "releases",
|
|
917
|
+
description: "Traffic and conversions per published build, newest first. Answers whether a change to a page moved the numbers.",
|
|
918
|
+
playbook: "landing \u2014 compare a page before and after a change"
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
name: "conversions",
|
|
922
|
+
description: "What this company counts as a conversion, and what each one produced. The report every other conversion number is derived from, so read it FIRST whenever a conversion figure looks wrong or reads zero: an empty list means nothing is counted and every conversion number everywhere is zero, whatever visitors did. `baker analytics conversions --candidates` lists everything these pages actually produce \u2014 every Form step, every data-baker-* event, every outbound destination \u2014 and counting one applies immediately and rescores the whole history, with no publish. Anything can be counted, not just a Form.",
|
|
923
|
+
playbook: "run `baker analytics conversions` \u2014 this one is fixed with the command, not with a skill"
|
|
924
|
+
}
|
|
925
|
+
];
|
|
926
|
+
|
|
927
|
+
// ../api/src/accounts/companyName.ts
|
|
928
|
+
var NOISE_WORDS = /* @__PURE__ */ new Set([
|
|
929
|
+
"inc",
|
|
930
|
+
"incorporated",
|
|
931
|
+
"llc",
|
|
932
|
+
"ltd",
|
|
933
|
+
"limited",
|
|
934
|
+
"plc",
|
|
935
|
+
"corp",
|
|
936
|
+
"corporation",
|
|
937
|
+
"co",
|
|
938
|
+
"company",
|
|
939
|
+
"gmbh",
|
|
940
|
+
"ag",
|
|
941
|
+
"kg",
|
|
942
|
+
"bv",
|
|
943
|
+
"nv",
|
|
944
|
+
"sa",
|
|
945
|
+
"sau",
|
|
946
|
+
"sl",
|
|
947
|
+
"slu",
|
|
948
|
+
"sas",
|
|
949
|
+
"sarl",
|
|
950
|
+
"srl",
|
|
951
|
+
"spa",
|
|
952
|
+
"oy",
|
|
953
|
+
"ab",
|
|
954
|
+
"as",
|
|
955
|
+
"aps",
|
|
956
|
+
"pty",
|
|
957
|
+
"lda",
|
|
958
|
+
"ltda",
|
|
959
|
+
"kk",
|
|
960
|
+
"group",
|
|
961
|
+
"grupo",
|
|
962
|
+
"holding",
|
|
963
|
+
"holdings",
|
|
964
|
+
"the"
|
|
965
|
+
]);
|
|
966
|
+
function companyNameKey(name) {
|
|
967
|
+
return name.normalize("NFD").replace(new RegExp("\\p{Diacritic}", "gu"), "").toLowerCase().replace(/\./g, "").split(/[^\p{L}\p{N}]+/u).filter((word) => word !== "" && !NOISE_WORDS.has(word)).join(" ");
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// src/commands/analytics/visitorCompanies.ts
|
|
971
|
+
var VISITOR_COMPANIES_FULL_ROWS = ANALYTICS_FULL_BREAKDOWN_LIMIT * 8;
|
|
972
|
+
function targetKey(target) {
|
|
973
|
+
return companyNameKey(target.name ?? target.domain.split(".")[0] ?? "");
|
|
974
|
+
}
|
|
975
|
+
function visitorCompanyHints(companies) {
|
|
976
|
+
if (companies.length === 0) {
|
|
977
|
+
return [
|
|
978
|
+
"No visitor companies in this window. They are recorded only when an admin has turned on 'Show which companies visit your pages' (Settings \u2192 General), the company measures in full, and the visitor accepted marketing cookies \u2014 so an empty list does not mean no target account came. Tell the user which of those to check rather than reporting zero interest."
|
|
979
|
+
];
|
|
980
|
+
}
|
|
981
|
+
const hints = [
|
|
982
|
+
"Each name is the visitor's network as registered, never a person, and there is no website: match accounts by name (`--targets` does it), and never present a row as an individual's visit."
|
|
983
|
+
];
|
|
984
|
+
if (companies.some((company) => company.confidence === "low")) {
|
|
985
|
+
hints.push(
|
|
986
|
+
"Rows with confidence low are a business only because their network is not a known ISP, carrier, cloud or VPN. Check the name reads as a real company before it goes into a sales brief."
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
return hints;
|
|
990
|
+
}
|
|
991
|
+
function matchTargets(companies, targets) {
|
|
992
|
+
const visitorByKey = /* @__PURE__ */ new Map();
|
|
993
|
+
for (const company of companies) {
|
|
994
|
+
const key = companyNameKey(company.name);
|
|
995
|
+
if (key !== "" && !visitorByKey.has(key)) visitorByKey.set(key, company);
|
|
996
|
+
}
|
|
997
|
+
const matched = [];
|
|
998
|
+
const notVisited = [];
|
|
999
|
+
const byTier = /* @__PURE__ */ new Map();
|
|
1000
|
+
for (const target of targets) {
|
|
1001
|
+
const key = targetKey(target);
|
|
1002
|
+
const visitor = key === "" ? void 0 : visitorByKey.get(key);
|
|
1003
|
+
if (visitor) matched.push({ ...visitor, target: target.domain });
|
|
1004
|
+
else notVisited.push(target);
|
|
1005
|
+
if (target.tier !== void 0) {
|
|
1006
|
+
const tier = byTier.get(target.tier) ?? { total: 0, visited: 0 };
|
|
1007
|
+
tier.total += 1;
|
|
1008
|
+
if (visitor) tier.visited += 1;
|
|
1009
|
+
byTier.set(target.tier, tier);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
const summary = { total: targets.length, visited: targets.length - notVisited.length, notVisited };
|
|
1013
|
+
return {
|
|
1014
|
+
companies: matched,
|
|
1015
|
+
targets: byTier.size > 0 ? { ...summary, byTier: Object.fromEntries(byTier) } : summary
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
function refineCompaniesReport(data, companies, targets) {
|
|
1019
|
+
if (!targets) {
|
|
1020
|
+
data.visitorCompanies = data.visitorCompanies ?? [];
|
|
1021
|
+
return visitorCompanyHints(companies);
|
|
1022
|
+
}
|
|
1023
|
+
const matched = matchTargets(companies, targets.targets);
|
|
1024
|
+
data.visitorCompanies = matched.companies;
|
|
1025
|
+
data.targets = matched.targets;
|
|
1026
|
+
const skipped = targets.unreadable.length > 0 ? [`Skipped targets that are not a website: ${targets.unreadable.map((entry) => `"${entry}"`).join(", ")}.`] : [];
|
|
1027
|
+
const cut = companies.length >= VISITOR_COMPANIES_FULL_ROWS ? [
|
|
1028
|
+
`Only the ${VISITOR_COMPANIES_FULL_ROWS} companies with the most visits were matched, so a target in notVisited may have come with fewer visits. Narrow the window (--days 7) and run it again before telling anyone an account never visited.`
|
|
1029
|
+
] : [];
|
|
1030
|
+
return [...visitorCompanyHints(matched.companies.length > 0 ? matched.companies : companies), ...skipped, ...cut];
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// src/commands/analytics/websiteTagCheck.ts
|
|
1034
|
+
var BAKER_CALL = /baker\s*\.\s*(?:track|conversion)\s*\(\s*(["'])([^"'\n]{1,120})\1/g;
|
|
1035
|
+
function tagHtml(raw) {
|
|
1036
|
+
if (typeof raw !== "object" || raw === null) return "";
|
|
1037
|
+
const parameters = raw.parameter;
|
|
1038
|
+
if (!Array.isArray(parameters)) return "";
|
|
1039
|
+
const html = parameters.find(
|
|
1040
|
+
(parameter) => typeof parameter === "object" && parameter !== null && parameter.key === "html" && typeof parameter.value === "string"
|
|
1041
|
+
);
|
|
1042
|
+
return html?.value ?? "";
|
|
1043
|
+
}
|
|
1044
|
+
function checkWebsiteEvents(tags, catalog) {
|
|
1045
|
+
const expected = /* @__PURE__ */ new Map();
|
|
1046
|
+
for (const tag of tags) {
|
|
1047
|
+
for (const match of tagHtml(tag.raw).matchAll(BAKER_CALL)) {
|
|
1048
|
+
const name = match[2];
|
|
1049
|
+
if (name === void 0) continue;
|
|
1050
|
+
const entry = expected.get(name) ?? { tags: [], paused: true };
|
|
1051
|
+
entry.tags.push(tag.name);
|
|
1052
|
+
entry.paused = entry.paused && tag.paused === true;
|
|
1053
|
+
expected.set(name, entry);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
const seen = new Map((catalog ?? []).map((row) => [row.eventKey, row]));
|
|
1057
|
+
const events = [...expected].map(([name, { tags: sentBy, paused }]) => {
|
|
1058
|
+
const arrived = seen.get(`page:${name}`);
|
|
1059
|
+
const events2 = arrived?.events ?? 0;
|
|
1060
|
+
const status = paused ? "paused" : catalog === null ? "not_checked" : events2 > 0 ? "arriving" : "never_seen";
|
|
1061
|
+
return { name, tags: sentBy, paused, status, events: events2, lastSeen: arrived?.lastSeen ?? null };
|
|
1062
|
+
});
|
|
1063
|
+
return { events };
|
|
1064
|
+
}
|
|
1065
|
+
function websiteEventCheckHints(events, days) {
|
|
1066
|
+
const hints = [];
|
|
1067
|
+
const missing = events.filter((event) => event.status === "never_seen");
|
|
1068
|
+
if (missing.length > 0) {
|
|
1069
|
+
hints.push(
|
|
1070
|
+
`${missing.map((event) => `\`${event.name}\``).join(", ")}: a tag sends ${missing.length === 1 ? "it" : "them"} and no real visit brought one in ${days} days. Tag Manager only fires the tag when something on the page pushes its trigger \u2014 find out whether the page ever does: \`baker analytics debug --start\` gives the person a link that records what their browser hears, and the agent-browser recipe "what a live site tells its tag manager" reads a widget's code for when it sends each event.`
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1073
|
+
const paused = events.filter((event) => event.status === "paused");
|
|
1074
|
+
if (paused.length > 0) {
|
|
1075
|
+
hints.push(
|
|
1076
|
+
`${paused.map((event) => `\`${event.name}\``).join(", ")}: every tag sending ${paused.length === 1 ? "it is" : "them is"} paused in Tag Manager, so nothing is sent. That is a setting in the container, not a fault on the site.`
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
const doubled = events.filter((event) => event.tags.length > 1);
|
|
1080
|
+
if (doubled.length > 0) {
|
|
1081
|
+
hints.push(
|
|
1082
|
+
`${doubled.map((event) => `\`${event.name}\` (${event.tags.join(", ")})`).join("; ")}: sent by more than one tag, so one moment can arrive twice. Give each call the same \`eventId\` or keep one tag.`
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
return hints;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// src/commands/analytics/websiteTagHints.ts
|
|
1089
|
+
function asTyped(origin) {
|
|
1090
|
+
return origin.replace(/^https?:\/\//, "");
|
|
1091
|
+
}
|
|
1092
|
+
function suggestionHint(suggested) {
|
|
1093
|
+
if (suggested.length === 0) return [];
|
|
1094
|
+
const commands = suggested.map((origin) => `baker analytics sites --add ${asTyped(origin)}`).join(" \xB7 ");
|
|
1095
|
+
return [
|
|
1096
|
+
`Baker publishes landing pages on ${suggested.map(asTyped).join(", ")} for this company, and no declared website covers ${suggested.length === 1 ? "it" : "them"}. Declaring the domain covers every subdomain of it \u2014 the marketing site, the shop, the booking page, and the ones that do not exist yet: ${commands}`
|
|
1097
|
+
];
|
|
1098
|
+
}
|
|
1099
|
+
function websiteTagHints(response) {
|
|
1100
|
+
const hints = [];
|
|
1101
|
+
if (response.origins.length === 0) {
|
|
1102
|
+
hints.push(
|
|
1103
|
+
"NO WEBSITE DECLARED \u2014 this tag will be ignored everywhere it is installed, silently, with no failing request to find. Declare the site before installing anything: baker analytics sites --add <the client's domain>. It takes effect at once and needs no republish."
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
hints.push(...suggestionHint(response.suggestedOrigins));
|
|
1107
|
+
if (response.firstParty) {
|
|
1108
|
+
hints.push(
|
|
1109
|
+
`This tag loads from ${response.host} \u2014 the client's own domain, not Baker's \u2014 so the script and every event it sends travel first-party, which a content blocker has no list entry for. The trade is a dependency: if that domain is ever removed from Baker, this tag 404s and measurement stops. Re-run this command after any domain change.`
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
if (response.measure === "all") {
|
|
1113
|
+
hints.push(
|
|
1114
|
+
"This tag measures the client's WHOLE WEBSITE \u2014 every visitor and every page view, not only the people your campaigns brought. Their reports will describe their business rather than their campaigns, and outcomes their site produces from organic, email and direct traffic will land in their conversion numbers. Only correct if somebody asked for that; otherwise re-run without --measure."
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
if (response.measure === "campaigns" && !response.campaignsCanMatch) {
|
|
1118
|
+
hints.push(
|
|
1119
|
+
"THIS TAG WILL MEASURE NOBODY \u2014 and will look installed. `campaigns` scope recognises a visitor by a first-party cookie, and a browser does not carry one between two different registrable domains. This company's landings are not on a subdomain of the site this tag goes on, so no visitor can ever match. Two fixes: put the landings on a subdomain of the client's own domain (a custom domain in Baker), or install with --measure outcomes, which measures no browsing and reports the outcomes the site tells Baker about."
|
|
1120
|
+
);
|
|
1121
|
+
} else if (response.measure === "campaigns") {
|
|
1122
|
+
hints.push(
|
|
1123
|
+
"This tag measures only visitors who have been on one of this company's Baker landing pages \u2014 their whole journey through the site, to the outcome. Anybody else is not measured at all. Use --measure all only if the client asked for their whole website measured."
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
hints.push(
|
|
1127
|
+
'Reporting an outcome is not the same as counting it. After a `window.baker.track("name")` call is live, name it with: baker analytics conversions --event page:<name> --name "<what to call it>". That applies immediately and counts everything already collected.'
|
|
1128
|
+
);
|
|
1129
|
+
return hints;
|
|
1130
|
+
}
|
|
1131
|
+
function analyticsSitesHints(response) {
|
|
1132
|
+
const hints = [];
|
|
1133
|
+
if (response.origins.length === 0) {
|
|
1134
|
+
hints.push(
|
|
1135
|
+
"No website is declared, so this company's measurement tag is ignored wherever it is installed \u2014 silently, with no failing request to find. Add one with: baker analytics sites --add <the client's domain>"
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
hints.push(...suggestionHint(response.suggestedOrigins));
|
|
1139
|
+
if (response.added.length > 0) {
|
|
1140
|
+
hints.push(
|
|
1141
|
+
`Live now. A tag already installed on ${response.added.map(asTyped).join(", ")} starts being accepted immediately \u2014 there is no new tag to paste and nothing to publish. Only events sent from here on are kept; the ones refused before this were never stored and cannot be recovered.`
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
if (response.removed.length > 0) {
|
|
1145
|
+
hints.push(
|
|
1146
|
+
`Measurement from ${response.removed.map(asTyped).join(", ")} will stop at once, with no error on that site \u2014 a tag still installed there goes quiet. Everything already collected from it is kept.`
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
hints.push(
|
|
1150
|
+
"One entry covers everything under it: example.com answers for www., go. and shop.eu. It never widens upward, so declaring go.example.com leaves example.com uncovered \u2014 declare the domain, not the subdomain you are installing on today."
|
|
1151
|
+
);
|
|
1152
|
+
return hints;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// src/commands/analytics/index.ts
|
|
1156
|
+
var SHARED_ARGS = {
|
|
1157
|
+
days: { type: "string", description: "Lookback window in days (default: 30)", required: false },
|
|
1158
|
+
"start-date": { type: "string", description: "Explicit start date (YYYY-MM-DD)", required: false },
|
|
1159
|
+
"end-date": { type: "string", description: "Explicit end date (YYYY-MM-DD, inclusive)", required: false },
|
|
1160
|
+
full: {
|
|
1161
|
+
type: "boolean",
|
|
1162
|
+
description: "Return long breakdowns and the per-day trend instead of the top few",
|
|
1163
|
+
required: false
|
|
1164
|
+
},
|
|
1165
|
+
timezone: {
|
|
1166
|
+
type: "string",
|
|
1167
|
+
description: "IANA zone the day boundaries are drawn in, e.g. Europe/Madrid (default: UTC). Pass the client's zone \u2014 in UTC, two hours of every Spanish evening land on the following day",
|
|
1168
|
+
required: false
|
|
1169
|
+
},
|
|
1170
|
+
granularity: {
|
|
1171
|
+
type: "string",
|
|
1172
|
+
description: "hour | day (default) | week | month \u2014 how wide one point of the trend is",
|
|
1173
|
+
required: false
|
|
1174
|
+
},
|
|
1175
|
+
compare: {
|
|
1176
|
+
type: "boolean",
|
|
1177
|
+
description: "Also return the preceding window of the same length, so every total has something to be read against",
|
|
1178
|
+
required: false
|
|
1179
|
+
},
|
|
1180
|
+
landing: {
|
|
1181
|
+
type: "string",
|
|
1182
|
+
description: "Narrow the whole report to one landing, by the internalId in its _definition.md \u2014 get it from `baker analytics landings`. Works on every report here: sources, geography, paid campaigns, Form drop-off and delivery all answer for that page alone. Prefer it over --path, which stops matching the moment a page is moved or renamed",
|
|
1183
|
+
required: false
|
|
1184
|
+
},
|
|
1185
|
+
role: {
|
|
1186
|
+
type: "string",
|
|
1187
|
+
description: 'Narrow the whole report to visits that arrived on one ad dimension: keyword, match_type, campaign_id, adgroup_id, ad_id, placement, network, audience, device, search_query and the rest \u2014 run `baker analytics ads` for the full list and what this company actually sends. Pair it with --value. It selects the VISITS that arrived on that value and keeps everything they then did, so `--role keyword --value "solar panels"` answers what those people read and whether they converted, not just where they landed',
|
|
1188
|
+
required: false
|
|
1189
|
+
},
|
|
1190
|
+
value: {
|
|
1191
|
+
type: "string",
|
|
1192
|
+
description: "The value of --role to narrow to. Pass an empty string to get the visits that arrived carrying no such parameter, which is how you size the untagged half of an account",
|
|
1193
|
+
required: false
|
|
1194
|
+
},
|
|
1195
|
+
page: {
|
|
1196
|
+
type: "string",
|
|
1197
|
+
description: "Which page of a list report to read, 1-based. `delivery` and `submissions` are the lists here; every other report is a breakdown, which is a top-N by construction and ignores this. The response carries pageInfo.hasMore \u2014 when it is true there ARE more rows, so never report a total from one page",
|
|
1198
|
+
required: false
|
|
1199
|
+
},
|
|
1200
|
+
"page-size": {
|
|
1201
|
+
type: "string",
|
|
1202
|
+
description: "Rows per page, up to 200 (default 50 when --page is given). Without --page or --page-size a list comes back at its old size, so nothing that worked before changes",
|
|
1203
|
+
required: false
|
|
1204
|
+
},
|
|
1205
|
+
platform: {
|
|
1206
|
+
type: "string",
|
|
1207
|
+
description: "Read the whole report in one ad platform's vocabulary, and from its traffic only: google, meta, microsoft, linkedin, tiktok, reddit, pinterest, snapchat, chatgpt. Two effects at once \u2014 --role resolves against the spellings that platform uses (`cid` is TikTok's ad and nobody else's campaign) and the report narrows to the visits that arrived from it. Start here when comparing platforms, because without it every dimension is the union across all of them and one parameter can land under two roles",
|
|
1208
|
+
required: false
|
|
1209
|
+
},
|
|
1210
|
+
origin: {
|
|
1211
|
+
type: "string",
|
|
1212
|
+
description: "Read one door only: `pages` for a browser on a page Baker publishes, `website` for a browser on the client's OWN website (the measurement tag), `server` for what their server posted to POST /v1/events. Omit it for all three, which is the default and the honest superset. Reach for it when a number moved and nothing on the pages changed \u2014 a CRM replaying history and a tag on the client's own site both land in the same totals as a landing page visitor, and this is the only thing that separates them. Honoured by overview, traffic, events and conversions; every session-scoped report ignores it, because a server-sent event carries no visit to be counted in",
|
|
1213
|
+
required: false
|
|
1214
|
+
},
|
|
1215
|
+
output: {
|
|
1216
|
+
type: "string",
|
|
1217
|
+
description: "json (default) | md. `md` renders each block as a table \u2014 one header instead of the keys repeated on every row \u2014 which is 20-50% smaller than the JSON on a typical report and more on a long breakdown. Reach for it whenever you are going to read the numbers rather than pick one field out of them. Both carry the same warnings and hints",
|
|
1218
|
+
required: false
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
function handleError(err) {
|
|
1222
|
+
writeJsonEnvelope({ ok: false, error: analyticsErrorEnvelope(err) });
|
|
1223
|
+
process.exit(1);
|
|
1224
|
+
}
|
|
1225
|
+
function pageOf(args) {
|
|
1226
|
+
const size = args["page-size"];
|
|
1227
|
+
return {
|
|
1228
|
+
...args.page ? { page: Number(args.page) } : {},
|
|
1229
|
+
...size ? { pageSize: Number(size) } : {}
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
function isWholePositive(raw) {
|
|
1233
|
+
return /^[1-9]\d*$/.test(String(raw));
|
|
1234
|
+
}
|
|
1235
|
+
function paginationError(args) {
|
|
1236
|
+
if (args.page !== void 0 && !isWholePositive(args.page)) {
|
|
1237
|
+
return `--page takes a page number of a list report (1, 2, \u2026), not "${String(args.page)}". To narrow a report to one page of the site, pass --landing <internalId> (from \`baker analytics landings\`), or read one path with \`baker analytics page --path /pricing\`.`;
|
|
1238
|
+
}
|
|
1239
|
+
const size = args["page-size"];
|
|
1240
|
+
if (size !== void 0 && !isWholePositive(size)) {
|
|
1241
|
+
return `--page-size takes a number of rows (1 to 200), not "${String(size)}".`;
|
|
1242
|
+
}
|
|
1243
|
+
return null;
|
|
1244
|
+
}
|
|
1245
|
+
function requestBody(args, options) {
|
|
1246
|
+
const candidates = {
|
|
1247
|
+
preset: options.preset,
|
|
1248
|
+
days: args.days ? Number(args.days) : void 0,
|
|
1249
|
+
startDate: args["start-date"],
|
|
1250
|
+
endDate: args["end-date"],
|
|
1251
|
+
full: args.full ? true : void 0,
|
|
1252
|
+
compare: args.compare ? true : void 0,
|
|
1253
|
+
timezone: args.timezone ? String(args.timezone) : void 0,
|
|
1254
|
+
granularity: args.granularity ? String(args.granularity) : void 0,
|
|
1255
|
+
path: options.path,
|
|
1256
|
+
flowSlug: options.flowSlug,
|
|
1257
|
+
grain: options.grain,
|
|
1258
|
+
country: options.country,
|
|
1259
|
+
// Read off the shared flag unless a preset resolved one itself. Every
|
|
1260
|
+
// report takes it, so wiring it per-preset would be fifteen identical lines
|
|
1261
|
+
// and, historically, four of them missing.
|
|
1262
|
+
landingId: options.landingId ?? (args.landing ? String(args.landing) : void 0),
|
|
1263
|
+
tag: options.tag,
|
|
1264
|
+
eventName: options.eventName,
|
|
1265
|
+
property: options.property,
|
|
1266
|
+
where: options.where,
|
|
1267
|
+
steps: options.steps && options.steps.length > 0 ? options.steps : void 0,
|
|
1268
|
+
deviceGrain: options.deviceGrain,
|
|
1269
|
+
adRole: options.adRole ?? (args.role ? String(args.role) : void 0),
|
|
1270
|
+
// Deliberately not dropped when empty: with a role set, an empty value is a
|
|
1271
|
+
// real question — "the visits that arrived carrying none of these" — and the
|
|
1272
|
+
// filter below would otherwise strip it and silently widen the report to
|
|
1273
|
+
// everything.
|
|
1274
|
+
adValue: args.role !== void 0 && args.value !== void 0 ? String(args.value) : void 0,
|
|
1275
|
+
adPlatform: args.platform ? String(args.platform) : void 0,
|
|
1276
|
+
eventOrigin: args.origin ? String(args.origin) : void 0,
|
|
1277
|
+
eventKey: options.eventKey,
|
|
1278
|
+
sourceName: options.sourceName,
|
|
1279
|
+
sends: options.sends,
|
|
1280
|
+
// `feed --send` and `--uid` were parsed and then dropped here, so both
|
|
1281
|
+
// answered with the whole unnarrowed feed as if they had worked.
|
|
1282
|
+
sendId: options.sendId,
|
|
1283
|
+
sentTo: options.sentTo,
|
|
1284
|
+
eventUid: options.eventUid,
|
|
1285
|
+
people: options.people,
|
|
1286
|
+
machines: options.machines,
|
|
1287
|
+
...pageOf(args)
|
|
1288
|
+
};
|
|
1289
|
+
return Object.fromEntries(
|
|
1290
|
+
Object.entries(candidates).filter(([key, value]) => value !== void 0 && (value !== "" || key === "adValue"))
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1293
|
+
var EVENT_ORIGINS = ANALYTICS_EVENT_DOORS;
|
|
1294
|
+
function feedReportHints(feed, data) {
|
|
1295
|
+
if (feed === void 0) return [];
|
|
1296
|
+
return [
|
|
1297
|
+
...feedHints(feed),
|
|
1298
|
+
...hiddenMachinesHints(data.hiddenMachines),
|
|
1299
|
+
...peopleSearchHints(data.peopleSearch ?? [], feed.rows)
|
|
1300
|
+
];
|
|
1301
|
+
}
|
|
1302
|
+
async function runPreset(args, options, refine) {
|
|
1303
|
+
const origin = args.origin === void 0 ? "" : String(args.origin);
|
|
1304
|
+
if (origin !== "" && !EVENT_ORIGINS.includes(origin)) {
|
|
1305
|
+
writeJsonEnvelope({
|
|
1306
|
+
ok: false,
|
|
1307
|
+
error: {
|
|
1308
|
+
code: "VALIDATION_ERROR",
|
|
1309
|
+
message: `Unknown --origin "${origin}". Use one of: ${EVENT_ORIGINS.join(", ")}, or omit it for all three.`
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
process.exit(1);
|
|
1313
|
+
}
|
|
1314
|
+
const pagination = paginationError(args);
|
|
1315
|
+
if (pagination) {
|
|
1316
|
+
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message: pagination } });
|
|
1317
|
+
process.exit(1);
|
|
1318
|
+
}
|
|
1319
|
+
try {
|
|
1320
|
+
const response = await apiPost("/api/analytics/query", requestBody(args, options));
|
|
1321
|
+
const requestedPlatform = args.platform === void 0 ? "" : String(args.platform);
|
|
1322
|
+
const adPlatformScope = isAdPlatform(requestedPlatform) ? requestedPlatform : void 0;
|
|
1323
|
+
const format = outputFormatOrExit(args.output);
|
|
1324
|
+
const data = pruneForAgent(response.data, args.full === true);
|
|
1325
|
+
const feed = "stream" in data ? shapeFeed(data.stream, args.everything === true) : void 0;
|
|
1326
|
+
if (feed !== void 0) data.stream = feed.rows;
|
|
1327
|
+
const refinedHints = refine ? refine(data, response.data) : [];
|
|
1328
|
+
const hints = [
|
|
1329
|
+
...feedReportHints(feed, response.data),
|
|
1330
|
+
// The platform the ad blocks were scoped to, so the tagging hint can
|
|
1331
|
+
// only speak about the inventory it was actually given. `adParams` is one
|
|
1332
|
+
// platform's list; a hint drawn from it without knowing which platform
|
|
1333
|
+
// would be a claim about Meta made from Google's URLs.
|
|
1334
|
+
...buildAnalyticsHints(response.data, adPlatformScope, origin === "" ? void 0 : origin),
|
|
1335
|
+
...missingBreakdownHint(response.data, {
|
|
1336
|
+
eventName: options.eventName,
|
|
1337
|
+
property: options.property
|
|
1338
|
+
}),
|
|
1339
|
+
...refinedHints,
|
|
1340
|
+
...formatHint(data, format)
|
|
1341
|
+
];
|
|
1342
|
+
writeAnalyticsReport(
|
|
1343
|
+
{
|
|
1344
|
+
ok: true,
|
|
1345
|
+
data,
|
|
1346
|
+
...response.warnings && response.warnings.length > 0 ? { warnings: response.warnings } : {},
|
|
1347
|
+
...hints.length > 0 ? { hints } : {}
|
|
1348
|
+
},
|
|
1349
|
+
format
|
|
1350
|
+
);
|
|
1351
|
+
} catch (err) {
|
|
1352
|
+
handleError(err);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
function outputFormatOrExit(raw) {
|
|
1356
|
+
const format = raw === void 0 ? "json" : String(raw);
|
|
1357
|
+
if (!isAnalyticsOutputFormat(format)) {
|
|
1358
|
+
writeJsonEnvelope({
|
|
1359
|
+
ok: false,
|
|
1360
|
+
error: {
|
|
1361
|
+
code: "VALIDATION_ERROR",
|
|
1362
|
+
message: `Unknown --output "${format}". Use one of: ${ANALYTICS_OUTPUT_FORMATS.join(", ")}.`
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
process.exit(1);
|
|
1366
|
+
}
|
|
1367
|
+
return format;
|
|
1368
|
+
}
|
|
1369
|
+
function presetCommand(options) {
|
|
1370
|
+
registerSchema({
|
|
1371
|
+
command: `analytics.${options.name}`,
|
|
1372
|
+
description: options.description,
|
|
1373
|
+
args: { ...SHARED_ARGS, ...options.extraArgs ?? {} }
|
|
1374
|
+
});
|
|
1375
|
+
return defineCommand({
|
|
1376
|
+
meta: { name: options.name, description: options.description },
|
|
1377
|
+
args: { ...SHARED_ARGS, ...options.extraArgs ?? {} },
|
|
1378
|
+
run: async ({ args }) => {
|
|
1379
|
+
const resolved = options.resolve ? options.resolve(args) : { preset: options.preset };
|
|
1380
|
+
if ("error" in resolved) {
|
|
1381
|
+
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message: resolved.error } });
|
|
1382
|
+
process.exit(1);
|
|
1383
|
+
}
|
|
1384
|
+
await runPreset(args, resolved);
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
var overviewCommand = presetCommand({
|
|
1389
|
+
name: "overview",
|
|
1390
|
+
preset: "overview",
|
|
1391
|
+
description: "Start here: traffic, top pages and their conversion rates, where visitors came from, and the worst step of every Form \u2014 in one call."
|
|
1392
|
+
});
|
|
1393
|
+
var trafficCommand = presetCommand({
|
|
1394
|
+
name: "traffic",
|
|
1395
|
+
preset: "traffic",
|
|
1396
|
+
description: "Where visitors come from \u2014 trend, sources, campaigns, countries and devices."
|
|
1397
|
+
});
|
|
1398
|
+
var funnelCommand = presetCommand({
|
|
1399
|
+
name: "funnel",
|
|
1400
|
+
preset: "funnel",
|
|
1401
|
+
description: "Per-step drop-off for the company's Forms. Narrow to one with --flow.",
|
|
1402
|
+
extraArgs: { flow: { type: "string", description: "Form slug (default: every Form)", required: false } },
|
|
1403
|
+
resolve: (args) => ({ preset: "funnel", flowSlug: args.flow ? String(args.flow) : void 0 })
|
|
1404
|
+
});
|
|
1405
|
+
var flowCommand = presetCommand({
|
|
1406
|
+
name: "flow",
|
|
1407
|
+
preset: "flow",
|
|
1408
|
+
description: "One Form in depth: how many people it converted, where they went between steps, the per-step table, and every trigger it raised. Every count is DISTINCT VISITS, so quote shares against `funnels[].visits` \u2014 the visits that opened the Form \u2014 and never against `starts`, which is only the visits that touched it. The gap between the two is people who read the Form and left, and on most Forms it is the largest loss there is. Read `flowSummary.convertedSessions`, not `submits` \u2014 a Form that books a call on a scheduling node in the MIDDLE of the flow never emits a submit, so it reports zero submits and every one of its real bookings as conversions. `flowPaths` is the flow as edges between steps, bracketed by __flow_start__, __flow_converted__ and __flow_exit__, which is how a branching Form is read at all: a per-step table cannot say that of the people who left step two, forty went to the booking branch and ninety went nowhere. `flowDestinations` is the other half and is evidence rather than a count: which Forms demonstrably handed something over in this window. Read it against the scaffold's `flow-no-destination` warning before acting on one \u2014 the stored picture of a Form is only rewritten when it is published, so a destination added since then shows there and not in the tree.",
|
|
1409
|
+
extraArgs: { flow: { type: "string", description: "Form slug (default: every Form)", required: false } },
|
|
1410
|
+
resolve: (args) => ({ preset: "flow", flowSlug: args.flow ? String(args.flow) : void 0 })
|
|
1411
|
+
});
|
|
1412
|
+
var pageCommand = presetCommand({
|
|
1413
|
+
name: "page",
|
|
1414
|
+
preset: "page",
|
|
1415
|
+
description: "One page in detail \u2014 its traffic, entrances, engagement and conversion rate.",
|
|
1416
|
+
extraArgs: { path: { type: "string", description: "Page path, e.g. /pricing (no trailing slash)", required: true } },
|
|
1417
|
+
resolve: (args) => args.path ? { preset: "page", path: String(args.path) } : {
|
|
1418
|
+
error: "Provide --path, e.g. --path /pricing. Run `baker analytics overview` to see which paths have traffic."
|
|
1419
|
+
}
|
|
1420
|
+
});
|
|
1421
|
+
var triggersCommand = presetCommand({
|
|
1422
|
+
name: "triggers",
|
|
1423
|
+
preset: "triggers",
|
|
1424
|
+
description: "What visitors actually do inside a Form \u2014 link clicks that send them off the site, scheduling widgets, embedded checkouts \u2014 and how much of it fires a side effect. Narrow to one Form with --flow.",
|
|
1425
|
+
extraArgs: { flow: { type: "string", description: "Form slug (default: every Form)", required: false } },
|
|
1426
|
+
resolve: (args) => ({ preset: "triggers", flowSlug: args.flow ? String(args.flow) : void 0 })
|
|
1427
|
+
});
|
|
1428
|
+
var releasesCommand = presetCommand({
|
|
1429
|
+
name: "releases",
|
|
1430
|
+
preset: "releases",
|
|
1431
|
+
description: "Traffic and conversions per published build, newest first. Use it to tell whether a change to a page moved the numbers, instead of guessing from the date."
|
|
1432
|
+
});
|
|
1433
|
+
var paidCommand = presetCommand({
|
|
1434
|
+
name: "paid",
|
|
1435
|
+
preset: "paid",
|
|
1436
|
+
description: "Paid campaigns, counted per visit rather than per page view, with the click ids that resolve to a real ad click \u2014 and how many of those leads were actually delivered. A campaign whose forms all submit while the CRM rejects every one of them reads as perfect everywhere else and as zero delivered here."
|
|
1437
|
+
});
|
|
1438
|
+
var deliveryCommand = presetCommand({
|
|
1439
|
+
name: "delivery",
|
|
1440
|
+
preset: "delivery",
|
|
1441
|
+
description: "Where each submission went: every destination it reached, whether that destination accepted it, and the id it gave the record it created. Failures first; --full lists every submission. Start here when someone says a lead never arrived."
|
|
1442
|
+
});
|
|
1443
|
+
var submissionsCommand = presetCommand({
|
|
1444
|
+
name: "submissions",
|
|
1445
|
+
preset: "submissions",
|
|
1446
|
+
description: "Every attempt anybody made at a Form \u2014 one visitor, one Form, one visit \u2014 whether they finished, gave up halfway, or completed a Form that sends nowhere. Read this rather than `delivery` when the question is what was collected: `delivery` starts from the dispatch, so a Form with no destination produces no row there at all. `stepsReached` against `stepsSubmitted` says how far they got; `finished` says whether the Form reached an ending; `destinations` is what it demonstrably reached, which beats the picture in its _data.json. A list, so it pages \u2014 read pageInfo.hasMore before quoting a total. Narrow to one Form with --flow.",
|
|
1447
|
+
extraArgs: { flow: { type: "string", description: "Form slug (default: every Form)", required: false } },
|
|
1448
|
+
resolve: (args) => ({ preset: "submissions", flowSlug: args.flow ? String(args.flow) : void 0 })
|
|
1449
|
+
});
|
|
1450
|
+
var geoCommand = presetCommand({
|
|
1451
|
+
name: "geo",
|
|
1452
|
+
preset: "geo",
|
|
1453
|
+
description: "Where the people who convert actually are. Country by default; --grain city|postal_code|metro_code goes finer, and --country narrows first so postcodes do not collide across markets. Use this when the campaign is local \u2014 a radius around a branch is a set of postcodes, never a set of countries.",
|
|
1454
|
+
extraArgs: {
|
|
1455
|
+
grain: {
|
|
1456
|
+
type: "string",
|
|
1457
|
+
description: "country (default) | region | city | postal_code | metro_code",
|
|
1458
|
+
required: false
|
|
1459
|
+
},
|
|
1460
|
+
country: { type: "string", description: "Two-letter code to look inside, e.g. ES", required: false }
|
|
1461
|
+
},
|
|
1462
|
+
resolve: (args) => ({
|
|
1463
|
+
preset: "geo",
|
|
1464
|
+
grain: args.grain ? String(args.grain) : void 0,
|
|
1465
|
+
country: args.country ? String(args.country) : void 0
|
|
1466
|
+
})
|
|
1467
|
+
});
|
|
1468
|
+
var botsCommand = presetCommand({
|
|
1469
|
+
name: "bots",
|
|
1470
|
+
preset: "bots",
|
|
1471
|
+
description: "Which machines are fetching this site \u2014 search crawlers, AI answer engines, link-preview scrapers, SEO tools \u2014 and whether each one is genuine or only claims to be. Every other report excludes these; this is the one that reads them. Use it to check that a republished page is still being crawled, or that Meta fetched a link preview before spend goes behind the URL."
|
|
1472
|
+
});
|
|
1473
|
+
var COMPANIES_DESCRIPTION = "Which companies are visiting these pages \u2014 named by the visitor's own network, never a person \u2014 with visits, pages read and first/last seen. Only recorded when an admin turned on 'Show which companies visit your pages', the company measures in full, and the visitor accepted marketing cookies; home and mobile connections are never named. --targets <file> keeps the target accounts that came and lists the ones that did not \u2014 the website half of an ABM report.";
|
|
1474
|
+
var COMPANIES_ARGS = {
|
|
1475
|
+
...SHARED_ARGS,
|
|
1476
|
+
targets: {
|
|
1477
|
+
type: "string",
|
|
1478
|
+
description: 'The target-account list `baker accounts --targets` takes: a .csv (a domain or website column; name and tier optional) or a .json file (["acme.com", \u2026] or [{"domain": "acme.com", "name": "Acme", "tier": 1}, \u2026]). Matched by company NAME, because a visitor company has no website \u2014 give each target its name; one without matches only when its name starts with the domain\'s first word. Build one with `node __tooling__/scripts/target-accounts.mjs --out targets.csv`',
|
|
1479
|
+
required: false
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
registerSchema({ command: "analytics.companies", description: COMPANIES_DESCRIPTION, args: COMPANIES_ARGS });
|
|
1483
|
+
var companiesCommand = defineCommand({
|
|
1484
|
+
meta: { name: "companies", description: COMPANIES_DESCRIPTION },
|
|
1485
|
+
args: COMPANIES_ARGS,
|
|
1486
|
+
run: async ({ args }) => {
|
|
1487
|
+
let targets;
|
|
1488
|
+
if (args.targets) {
|
|
1489
|
+
try {
|
|
1490
|
+
targets = readTargetsFile(String(args.targets), readFileSync(String(args.targets), "utf8"));
|
|
1491
|
+
} catch (err) {
|
|
1492
|
+
writeJsonEnvelope({
|
|
1493
|
+
ok: false,
|
|
1494
|
+
error: {
|
|
1495
|
+
code: "VALIDATION_ERROR",
|
|
1496
|
+
message: `Could not read --targets ${String(args.targets)}: ${err instanceof Error ? err.message : String(err)}`
|
|
1497
|
+
}
|
|
1498
|
+
});
|
|
1499
|
+
process.exit(1);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
const request = targets ? { ...args, full: true } : args;
|
|
1503
|
+
await runPreset(
|
|
1504
|
+
request,
|
|
1505
|
+
{ preset: "companies" },
|
|
1506
|
+
(data, raw) => refineCompaniesReport(data, raw.visitorCompanies ?? [], targets)
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
var landingsCommand = presetCommand({
|
|
1511
|
+
name: "landings",
|
|
1512
|
+
preset: "landings",
|
|
1513
|
+
description: "Every landing side by side \u2014 views, entrances, conversion rate and a sparkline each, under the name a person gave it rather than its id. This is the one that answers 'which of my pages is working' without having to know the answer first; `page` answers one page in depth once this has named it. Narrow to a campaign with --tag.",
|
|
1514
|
+
extraArgs: {
|
|
1515
|
+
tag: { type: "string", description: "Only landings filed under this tag", required: false }
|
|
1516
|
+
},
|
|
1517
|
+
resolve: (args) => ({ preset: "landings", tag: args.tag ? String(args.tag) : void 0 })
|
|
1518
|
+
});
|
|
1519
|
+
var tagsCommand = presetCommand({
|
|
1520
|
+
name: "tags",
|
|
1521
|
+
preset: "tags",
|
|
1522
|
+
description: "The same numbers grouped by the tag a landing is filed under \u2014 the unit a campaign is actually run at. Nobody asks how /pricing-b did; they ask how the September push did, and September was six landings. Tags are declared in each landing's _definition.md."
|
|
1523
|
+
});
|
|
1524
|
+
var eventsCommand = presetCommand({
|
|
1525
|
+
name: "events",
|
|
1526
|
+
preset: "events",
|
|
1527
|
+
description: "Events the pages define for themselves \u2014 a section scrolled into view, a video played, a button clicked. Lists each one with the property keys it carries, so you can then break it down: --event video --property milestone. Pass --steps a,b,c for an ORDERED funnel over them, where a session only counts at each step if it got there after the one before.",
|
|
1528
|
+
extraArgs: {
|
|
1529
|
+
event: { type: "string", description: "Break this one event down (needs --property too)", required: false },
|
|
1530
|
+
property: { type: "string", description: "Which of that event's property keys to group by", required: false },
|
|
1531
|
+
where: {
|
|
1532
|
+
type: "string",
|
|
1533
|
+
description: "Narrow to one property value before grouping, as key=value \u2014 e.g. --event vsl --property milestone --where autoplay=0 for the retention curve of the videos visitors chose to play, rather than the one a muted hero produces on its own",
|
|
1534
|
+
required: false
|
|
1535
|
+
},
|
|
1536
|
+
steps: {
|
|
1537
|
+
type: "string",
|
|
1538
|
+
description: "Comma-separated event names, in order, for a funnel \u2014 e.g. hero_view,pricing_view,demo_click",
|
|
1539
|
+
required: false
|
|
1540
|
+
}
|
|
1541
|
+
},
|
|
1542
|
+
resolve: (args) => {
|
|
1543
|
+
const steps = args.steps ? String(args.steps).split(",").map((step) => step.trim()).filter((step) => step !== "") : void 0;
|
|
1544
|
+
if (args.property && !args.event) {
|
|
1545
|
+
return {
|
|
1546
|
+
error: "Breaking an event down by a property needs --event too, e.g. --event video --property milestone"
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
if (steps && steps.length < 2) {
|
|
1550
|
+
return { error: "A funnel needs at least two steps, e.g. --steps hero_view,pricing_view" };
|
|
1551
|
+
}
|
|
1552
|
+
let where;
|
|
1553
|
+
if (args.where) {
|
|
1554
|
+
const raw = String(args.where);
|
|
1555
|
+
const at = raw.indexOf("=");
|
|
1556
|
+
if (at < 1) {
|
|
1557
|
+
return { error: "--where takes key=value, e.g. --where autoplay=0" };
|
|
1558
|
+
}
|
|
1559
|
+
if (!args.property) {
|
|
1560
|
+
return { error: "--where narrows a breakdown, so it needs --event and --property too" };
|
|
1561
|
+
}
|
|
1562
|
+
where = { property: raw.slice(0, at), value: raw.slice(at + 1) };
|
|
1563
|
+
}
|
|
1564
|
+
return {
|
|
1565
|
+
preset: "events",
|
|
1566
|
+
eventName: args.event ? String(args.event) : void 0,
|
|
1567
|
+
property: args.property ? String(args.property) : void 0,
|
|
1568
|
+
where,
|
|
1569
|
+
steps
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
var FEED_OUTCOMES = {
|
|
1574
|
+
counted: {},
|
|
1575
|
+
sent: { sends: "any" },
|
|
1576
|
+
refused: { sends: "failed" },
|
|
1577
|
+
skipped: { sends: "skipped" },
|
|
1578
|
+
test: { elsewhere: "baker analytics arrivals --mode test" },
|
|
1579
|
+
"not-counted": { elsewhere: "baker analytics arrivals --outcome rejected" }
|
|
1580
|
+
};
|
|
1581
|
+
function feedRequest(args) {
|
|
1582
|
+
const tooMany = peopleLimitError(args);
|
|
1583
|
+
if (tooMany !== void 0) return { error: tooMany };
|
|
1584
|
+
const raw = args.sends === void 0 ? void 0 : String(args.sends);
|
|
1585
|
+
if (raw !== void 0 && !SEND_FILTERS.includes(raw)) {
|
|
1586
|
+
return { error: `--sends is one of ${SEND_FILTERS.join(", ")}, not "${raw}".` };
|
|
1587
|
+
}
|
|
1588
|
+
const sends = raw;
|
|
1589
|
+
const outcome = args.outcome === void 0 ? void 0 : String(args.outcome);
|
|
1590
|
+
if (outcome !== void 0) {
|
|
1591
|
+
const mapped = FEED_OUTCOMES[outcome];
|
|
1592
|
+
if (mapped === void 0) {
|
|
1593
|
+
return { error: `--outcome is one of: ${Object.keys(FEED_OUTCOMES).join(", ")}. Not "${outcome}".` };
|
|
1594
|
+
}
|
|
1595
|
+
if (mapped.elsewhere !== void 0) {
|
|
1596
|
+
return {
|
|
1597
|
+
error: `--outcome ${outcome} is not on the feed: those requests never became events. Run \`${mapped.elsewhere}\` instead.`
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
if (mapped.sends !== void 0 && sends === void 0) {
|
|
1601
|
+
return { ...feedNarrowing(args), sends: mapped.sends };
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
return { ...feedNarrowing(args), ...sends === void 0 ? {} : { sends } };
|
|
1605
|
+
}
|
|
1606
|
+
function feedNarrowing(args) {
|
|
1607
|
+
return {
|
|
1608
|
+
preset: "stream",
|
|
1609
|
+
...args.source ? { sourceName: String(args.source) } : {},
|
|
1610
|
+
...args.kind ? { eventKey: String(args.kind) } : {},
|
|
1611
|
+
...args.send ? { sendId: String(args.send) } : {},
|
|
1612
|
+
...args["sent-to"] ? { sentTo: String(args["sent-to"]) } : {},
|
|
1613
|
+
...args.uid ? { eventUid: String(args.uid) } : {},
|
|
1614
|
+
...args.bots === true ? { machines: true } : {},
|
|
1615
|
+
...peopleArgs(args)
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
var feedCommand = presetCommand({
|
|
1619
|
+
name: "feed",
|
|
1620
|
+
preset: "stream",
|
|
1621
|
+
description: 'Every event recorded in the window, newest first, exactly as it was stored \u2014 the Measure \u2192 Events tab as rows. The one report that does not reduce, for "did anything arrive from Zapier today" and "what did that HubSpot read actually carry". --source <name> keeps one source\'s events (names from `baker analytics sources`; every event from an address or a HubSpot read carries its source\'s name as `baker_source`); --kind <event key> keeps one kind (keys from `conversions`); --origin pages|website|server keeps one door (a page Baker publishes, the client\'s own website, or their systems); --sends any|failed keeps only the uploads a conversion\'s sends made to Meta, Google Ads and the rest \u2014 `failed` is the rows behind "6 failed" on `baker analytics sends`, each with the platform\'s own words in `error`. Paged with --page; test sends and refusals are on `arrivals`, because they never became an event.',
|
|
1622
|
+
extraArgs: {
|
|
1623
|
+
outcome: {
|
|
1624
|
+
type: "string",
|
|
1625
|
+
description: "counted | sent | refused | skipped | test | not-counted \u2014 the Measure \u2192 Events outcome menu, in its own words. `counted` is every stored event (the default); `sent` and `refused` are the uploads an ad platform took and turned away; `skipped` are a send's events never uploaded because they carried nothing the platform matches a person by (no Meta click or email, no gclid, no li_fat_id\u2026), each with what was missing in `error`; `test` and `not-counted` never became events and are answered by `baker analytics arrivals`, which this names if you ask for them",
|
|
1626
|
+
required: false
|
|
1627
|
+
},
|
|
1628
|
+
sends: {
|
|
1629
|
+
type: "string",
|
|
1630
|
+
description: "any | failed | skipped \u2014 only what was SENT ON: every delivery a Form's actions made (a Meta or Google Ads pixel fired, a Conversions API call, a webhook, an email, a CRM contact) and every upload an event's send made (side_effect_type conversionSend:<platform>); `failed` keeps the ones the destination refused, with its reason in `error`; `skipped` the events a send never uploaded, with what they were missing in `error`. The same narrowing as --outcome sent | refused | skipped",
|
|
1631
|
+
required: false
|
|
1632
|
+
},
|
|
1633
|
+
"sent-to": {
|
|
1634
|
+
type: "string",
|
|
1635
|
+
description: `One destination, by its type \u2014 meta, googleAds, linkedinInsightTag, httpWebhook, email, hubspot\u2026 \u2014 keeping both a Form's deliveries there and the uploads sends made to it. The answer to "what went to Meta"`,
|
|
1636
|
+
required: false
|
|
1637
|
+
},
|
|
1638
|
+
send: {
|
|
1639
|
+
type: "string",
|
|
1640
|
+
description: "One send's uploads and nothing else, by its id from `baker analytics sends` (`s1`) \u2014 the rows behind that send's outcome, each with its verdict. Implies --sends any; add --sends failed for the refused ones only",
|
|
1641
|
+
required: false
|
|
1642
|
+
},
|
|
1643
|
+
uid: {
|
|
1644
|
+
type: "string",
|
|
1645
|
+
description: 'One event by its `event_uid`, together with every upload a send made for it (the rows carrying it as `event_id`), each with the platform\'s verdict \u2014 the answer to "is this the event that triggered that upload"',
|
|
1646
|
+
required: false
|
|
1647
|
+
},
|
|
1648
|
+
source: {
|
|
1649
|
+
type: "string",
|
|
1650
|
+
description: "One source, by its name from `baker analytics sources` \u2014 an address a tool posts to, or a HubSpot read. Omit it for every event, sourced or not",
|
|
1651
|
+
required: false
|
|
1652
|
+
},
|
|
1653
|
+
kind: {
|
|
1654
|
+
type: "string",
|
|
1655
|
+
description: "One kind of event, by the key `baker analytics conversions` lists (page:Deal won, form:contact:\u2026)",
|
|
1656
|
+
required: false
|
|
1657
|
+
},
|
|
1658
|
+
person: {
|
|
1659
|
+
type: "string",
|
|
1660
|
+
description: "One or more people and everything they did, by whatever identifies them \u2014 comma-separated: an email, a phone (+34\u2026), a HubSpot contact id, deal:<HubSpot deal id>, a gclid/fbclid, or the `anonId` off any row. Prefix to be exact (email:, phone:, hubspot:, deal:, gclid:, fbclid:, browser:). Emails and phones are hashed by Baker, never stored in the clear. Each is resolved to the whole person \u2014 across devices and every address, phone, CRM id, ad click and cookie ever seen beside it \u2014 so the deal their CRM posted is on the list beside the page view that named them. Every row says which of them it is in `personTerms` (positions in `peopleSearch`). Up to 50; `baker analytics lookup` answers the same list as one summary line each",
|
|
1661
|
+
required: false
|
|
1662
|
+
},
|
|
1663
|
+
"people-file": {
|
|
1664
|
+
type: "string",
|
|
1665
|
+
description: "A file with one person per line, read like --person \u2014 a column pasted from a CRM export",
|
|
1666
|
+
required: false
|
|
1667
|
+
},
|
|
1668
|
+
bots: {
|
|
1669
|
+
type: "boolean",
|
|
1670
|
+
description: "List ONLY the events taken for machine traffic \u2014 a headless browser (agent-browser is one: every check you run on a site from it lands here), a datacenter network \u2014 each with its `botReason`. Stored, but left out of the feed and every report. Reach for it to confirm a test visit you just made arrived; never quote these rows to the client as visitors",
|
|
1671
|
+
required: false
|
|
1672
|
+
},
|
|
1673
|
+
everything: {
|
|
1674
|
+
type: "boolean",
|
|
1675
|
+
description: "Include the rows held back by default: the ones recorded so the reports can be worked out (identifications, step views, session starts, a destination's answer already folded onto its dispatch) and embedded forms and calendars announcing that they drew. Reach for it when debugging the collector rather than an integration \u2014 an embed that draws and never fires again is only visible here",
|
|
1676
|
+
required: false
|
|
1677
|
+
}
|
|
1678
|
+
},
|
|
1679
|
+
resolve: (args) => feedRequest(args)
|
|
1680
|
+
});
|
|
1681
|
+
var devicesCommand = presetCommand({
|
|
1682
|
+
name: "devices",
|
|
1683
|
+
preset: "devices",
|
|
1684
|
+
description: "What visitors are actually using, narrow enough to reproduce a bug on: browser and version, OS and version, rendering engine, or viewport width. `traffic` says mobile converts worse; this says it is Safari 17 on viewports under 380px, which is a browser you can open and a width you can resize to.",
|
|
1685
|
+
extraArgs: {
|
|
1686
|
+
grain: {
|
|
1687
|
+
type: "string",
|
|
1688
|
+
description: "browser (default) | os | engine | device | viewport",
|
|
1689
|
+
required: false
|
|
1690
|
+
}
|
|
1691
|
+
},
|
|
1692
|
+
resolve: (args) => ({
|
|
1693
|
+
preset: "devices",
|
|
1694
|
+
deviceGrain: args.grain ? String(args.grain) : void 0
|
|
1695
|
+
})
|
|
1696
|
+
});
|
|
1697
|
+
var presetsCommand = defineCommand({
|
|
1698
|
+
meta: { name: "presets", description: "List the available reports and what each answers." },
|
|
1699
|
+
run: () => {
|
|
1700
|
+
writeJsonEnvelope({ ok: true, data: ANALYTICS_PRESET_INFO });
|
|
1701
|
+
}
|
|
1702
|
+
});
|
|
1703
|
+
var adsCommand = presetCommand({
|
|
1704
|
+
name: "ads",
|
|
1705
|
+
preset: "ads",
|
|
1706
|
+
description: "What the ad platforms told us about each click, and what those people then did. `--role keyword` breaks the window down by keyword with conversions AND bounced visits beside each one \u2014 the ad platform can tell you a keyword got clicks, only this can tell you the people it brought left immediately. Three things come back either way. `adPlatformTraffic` is visits, conversions and TAGGED visits per platform \u2014 read it first, because a platform with visits and zero tagged visits has untagged ad URLs and no mapping will ever help it. `adParams` is the parameters arriving on the traffic of the platform in --platform (Google when none is given), never a shared list: a visit comes from one platform, so `gclid` traffic is not also Meta traffic. A parameter with no `role` is one nobody has told us the meaning of, and until somebody does its values are not stored at all \u2014 only the fact that the name appeared. `adParamsUnattributed` is the parameters on visits with no click id and no recognisable source, which belong to no platform and can only be placed by somebody who recognises them. Map any of them with `baker analytics map`.",
|
|
1707
|
+
extraArgs: {}
|
|
1708
|
+
});
|
|
1709
|
+
var mapCommand = (() => {
|
|
1710
|
+
const args = {
|
|
1711
|
+
platform: {
|
|
1712
|
+
type: "string",
|
|
1713
|
+
description: "Which platform these parameters belong to: google, meta, microsoft, linkedin, tiktok, reddit, pinterest, snapchat, chatgpt. REQUIRED with --set or --remove, because there is no such thing as a parameter that means one thing everywhere \u2014 `cid` is TikTok's ad and everyone else's campaign, and Meta cannot send a keyword at all. Leave it off only to read the whole mapping back",
|
|
1714
|
+
required: false
|
|
1715
|
+
},
|
|
1716
|
+
set: {
|
|
1717
|
+
type: "string",
|
|
1718
|
+
description: "Parameter=role pairs, comma separated: --set kw=keyword,mt=match_type. Roles come from `baker analytics ads` (every row lists the role in force). Two of them are the flexible ones: `other` captures a parameter and lets you filter by its own name without claiming it means anything, and `ignore` says it is not campaign information at all \u2014 Baker stops storing it and stops listing it as something to deal with",
|
|
1719
|
+
required: false
|
|
1720
|
+
},
|
|
1721
|
+
remove: {
|
|
1722
|
+
type: "string",
|
|
1723
|
+
description: "Parameter names to stop reading, comma separated. Only affects this company's own entries, and only within --platform \u2014 removing an entry scoped to TikTok needs the same --platform tiktok that set it",
|
|
1724
|
+
required: false
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
registerSchema({
|
|
1728
|
+
command: "analytics.map",
|
|
1729
|
+
description: "Stage how this company's campaign URLs spell each ad dimension, applied on publish",
|
|
1730
|
+
args
|
|
1731
|
+
});
|
|
1732
|
+
return defineCommand({
|
|
1733
|
+
meta: {
|
|
1734
|
+
name: "map",
|
|
1735
|
+
description: "Teach Baker how this company's campaign URLs spell each ad dimension on one platform \u2014 `--platform google --set kw=keyword`. Run it with no flags to see the whole mapping, including what this chat has already staged. STAGED, not applied: the answers are reviewed in the chat and take effect when it is published, so nothing you map here changes a report or what the edge stores until then; discarding the chat takes them all back. Mappings are always per platform, because the platforms do not describe the same world: `builtIn` in the response is what that platform is already understood to send, so you do not spend a turn mapping `keyword` to keyword. Each --set is checked against the client's OWN ad account \u2014 `evidence` in the response says whether their tracking template really fills that name with what you claimed. Read it: `contradicted` means the account disagrees, and mapping it your way would produce a report that is wrong and looks plausible. Renaming a parameter Baker already captured fixes the history too, because roles are applied when a report is read; naming one it never read only starts collecting it from the publish onward, since no value was stored. You do NOT need to have seen a parameter to map it: a name nobody has sent yet is a valid --set, which is how a tracking template gets configured before the campaign that uses it runs. To drop an answer, --remove takes it back to whatever Baker knows by itself, and --set <name>=ignore says it is not campaign information at all so it stops being listed."
|
|
1736
|
+
},
|
|
1737
|
+
args,
|
|
1738
|
+
run: async ({ args: raw }) => {
|
|
1739
|
+
try {
|
|
1740
|
+
const body = {
|
|
1741
|
+
platform: raw.platform === void 0 ? void 0 : String(raw.platform),
|
|
1742
|
+
set: parsePairs(raw.set === void 0 ? void 0 : String(raw.set)),
|
|
1743
|
+
remove: parseList(raw.remove === void 0 ? void 0 : String(raw.remove))
|
|
1744
|
+
};
|
|
1745
|
+
const response = await apiPost("/api/analytics/mapping", body);
|
|
1746
|
+
writeJsonEnvelope(response);
|
|
1747
|
+
} catch (err) {
|
|
1748
|
+
handleError(err);
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
});
|
|
1752
|
+
})();
|
|
1753
|
+
var trackingCommand = (() => {
|
|
1754
|
+
const args = {
|
|
1755
|
+
platform: {
|
|
1756
|
+
type: "string",
|
|
1757
|
+
description: "One platform: google, meta, microsoft, linkedin, tiktok, reddit, pinterest, snapchat, chatgpt. Omit to check the ones worth checking \u2014 every platform sending visits, plus Google and Meta, whose accounts Baker can read directly",
|
|
1758
|
+
required: false
|
|
1759
|
+
},
|
|
1760
|
+
days: { type: "string", description: "Lookback window for the traffic half (default: 30)", required: false }
|
|
1761
|
+
};
|
|
1762
|
+
registerSchema({
|
|
1763
|
+
command: "analytics.tracking",
|
|
1764
|
+
description: "Check whether a platform's ad URLs carry the campaign, ad group and ad a report needs",
|
|
1765
|
+
args
|
|
1766
|
+
});
|
|
1767
|
+
return defineCommand({
|
|
1768
|
+
meta: {
|
|
1769
|
+
name: "tracking",
|
|
1770
|
+
description: `Check whether this company's ad URLs carry the dimensions any budget decision needs \u2014 the campaign, the ad group, the ad, and the keyword where the platform has one.
|
|
1771
|
+
|
|
1772
|
+
Read this before auditing an ad account and before answering any "which ad performed best" question. Each dimension comes back in one of four states, and they need different things:
|
|
1773
|
+
covered \u2014 arriving and understood, nothing to do
|
|
1774
|
+
unmapped \u2014 the URLs carry it under a name Baker does not read yet. Free to fix, and it repairs the traffic already collected: run the \`mapCommand\` in the response
|
|
1775
|
+
missing \u2014 nothing carries it. \`fix\` says which LEVELS that platform accepts tagging at (widest first \u2014 prefer it), which Baker can stage and which the user must do by hand, and how each field treats what is already in it. \`suffix\` is only the MISSING pairs, so read the current value, add them, write the union. This one cannot be filled in later \u2014 a parameter's values are only stored once it starts arriving
|
|
1776
|
+
unknown \u2014 no visit arrived AND the account could not be read. Not a finding; do not report it as untagged
|
|
1777
|
+
|
|
1778
|
+
Baker reads the client's own Google tracking templates and Meta URL parameters, so a platform that has not run yet still gets a real answer.
|
|
1779
|
+
|
|
1780
|
+
Examples:
|
|
1781
|
+
baker analytics tracking
|
|
1782
|
+
baker analytics tracking --platform meta
|
|
1783
|
+
baker analytics tracking --platform google --days 90`
|
|
1784
|
+
},
|
|
1785
|
+
args,
|
|
1786
|
+
run: async ({ args: raw }) => {
|
|
1787
|
+
try {
|
|
1788
|
+
const platform = raw.platform === void 0 ? void 0 : String(raw.platform);
|
|
1789
|
+
if (platform !== void 0 && !isAdPlatform(platform)) {
|
|
1790
|
+
writeJsonEnvelope({
|
|
1791
|
+
ok: false,
|
|
1792
|
+
error: { code: "BAD_REQUEST", message: `Unknown platform "${platform}"` }
|
|
1793
|
+
});
|
|
1794
|
+
process.exit(1);
|
|
1795
|
+
}
|
|
1796
|
+
const days = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
1797
|
+
const response = await apiPost("/api/analytics/tracking", {
|
|
1798
|
+
...platform ? { platform } : {},
|
|
1799
|
+
...days !== void 0 && Number.isFinite(days) ? { days } : {}
|
|
1800
|
+
});
|
|
1801
|
+
writeJsonEnvelope(response);
|
|
1802
|
+
} catch (err) {
|
|
1803
|
+
handleError(err);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
});
|
|
1807
|
+
})();
|
|
1808
|
+
function localFormKeyRefusal(eventKey) {
|
|
1809
|
+
const parsed = parseEventKey(eventKey);
|
|
1810
|
+
if (parsed?.family !== "form") return null;
|
|
1811
|
+
if (!flowExists(parsed.flowSlug)) return null;
|
|
1812
|
+
return formKeyRefusal(eventKey, readFlowTree(parsed.flowSlug), parsed.flowSlug);
|
|
1813
|
+
}
|
|
1814
|
+
function refuseUnmatchableKey(eventKey) {
|
|
1815
|
+
const refusal = eventKey === void 0 ? null : localFormKeyRefusal(eventKey);
|
|
1816
|
+
if (!refusal) return;
|
|
1817
|
+
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message: refusal.message, fix: refusal.fix } });
|
|
1818
|
+
process.exit(1);
|
|
1819
|
+
}
|
|
1820
|
+
function readWorkspaceFlows() {
|
|
1821
|
+
return listFlowSlugs().flatMap((slug) => {
|
|
1822
|
+
try {
|
|
1823
|
+
return [{ slug, tree: JSON.parse(readFileSync(flowDataPath(slug), "utf-8")) }];
|
|
1824
|
+
} catch {
|
|
1825
|
+
return [];
|
|
1826
|
+
}
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
function readFlowConversions(slug, definitions) {
|
|
1830
|
+
const tree = readFlowTree(slug);
|
|
1831
|
+
const declared = tree.noConversion;
|
|
1832
|
+
const reason = declared && typeof declared === "object" && typeof declared.reason === "string" ? String(declared.reason) : null;
|
|
1833
|
+
return {
|
|
1834
|
+
slug,
|
|
1835
|
+
noConversionReason: reason,
|
|
1836
|
+
endings: joinFlowConversions(flowEventKeys(tree, slug), definitions)
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
function conversionsEnvelope(args, definitions, candidates, leadingHints = []) {
|
|
1840
|
+
const flow = args.flowSlug === void 0 ? null : readFlowConversions(args.flowSlug, definitions);
|
|
1841
|
+
const forms = flow === null ? readWorkspaceFlows() : [];
|
|
1842
|
+
const coverage = flowCoverage(forms, definitions);
|
|
1843
|
+
const page = pageCandidates(definitions, candidates, args.candidates);
|
|
1844
|
+
const hints = [
|
|
1845
|
+
...leadingHints,
|
|
1846
|
+
...flow ? flowConversionHints(flow.slug, flow.endings, flow.noConversionReason) : [],
|
|
1847
|
+
...flowCoverageHints(coverage),
|
|
1848
|
+
...stagedHints(definitions),
|
|
1849
|
+
...page.hints,
|
|
1850
|
+
...namingHints(definitions)
|
|
1851
|
+
];
|
|
1852
|
+
return {
|
|
1853
|
+
ok: true,
|
|
1854
|
+
data: {
|
|
1855
|
+
definitions,
|
|
1856
|
+
...flow ? { flow } : {},
|
|
1857
|
+
...coverage.length > 0 ? { flows: coverage } : {},
|
|
1858
|
+
...args.candidates ? { candidates: candidatesForFlow(page.candidates, args.flowSlug) } : {}
|
|
1859
|
+
},
|
|
1860
|
+
...hints.length > 0 ? { hints } : {}
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1863
|
+
async function readConversionCounts(post, days, wrote) {
|
|
1864
|
+
try {
|
|
1865
|
+
const report = await post("/api/analytics/query", { preset: "conversions", days });
|
|
1866
|
+
return { conversions: report.data.conversions ?? [], eventCatalog: report.data.eventCatalog ?? [], hints: [] };
|
|
1867
|
+
} catch (err) {
|
|
1868
|
+
if (!wrote) throw err;
|
|
1869
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
1870
|
+
return {
|
|
1871
|
+
conversions: [],
|
|
1872
|
+
eventCatalog: [],
|
|
1873
|
+
hints: [`The change above was saved; its counts could not be read, so none are shown. ${reason}`]
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
var conversionsCommand = (() => {
|
|
1878
|
+
const args = {
|
|
1879
|
+
event: {
|
|
1880
|
+
type: "string",
|
|
1881
|
+
description: "The event to start counting, from the `candidates` or `--flow` list: form:<form>:<step>:<trigger>, submit:<form>, page:<name>, or exit:<host>. Requires --name. REPEATABLE \u2014 pass it several times with one --name to count all of them as that single outcome, which is the whole point of the name. Inside a chat it is STAGED: the chat lists it under Sources, on its event, and it counts from when the chat is published \u2014 then it scores the WHOLE history, not just from then on, so counting the right event also corrects last month's reports. An event a client's system sends (the API, HubSpot) counts here too: it is credited to the LAST LANDING its person viewed, up to 90 days before, so a deal won weeks later is that landing's conversion. A person who never saw a landing is not counted at all. Such an event is usually also a funnel step (`baker funnel`) and a send (`baker analytics sends`)",
|
|
1882
|
+
required: false
|
|
1883
|
+
},
|
|
1884
|
+
name: {
|
|
1885
|
+
type: "string",
|
|
1886
|
+
description: "What to call this outcome on every report \u2014 'Booked a call', 'Quote requested'. Baker groups by EXACT name: reuse one this company already counts and the two become one row and one number, which is how a call booked on three Forms reads as one outcome. Read the existing names first (run with no flags) and reuse one before inventing another; a name that only differs by case, accent, punctuation or a plural is refused, because it would split the number in two",
|
|
1887
|
+
required: false
|
|
1888
|
+
},
|
|
1889
|
+
rename: {
|
|
1890
|
+
type: "string",
|
|
1891
|
+
description: "An outcome's current name. With --to, renames every event counted under it. Renaming ONTO a name that already exists MERGES them into one row and one number \u2014 the way to fix a company whose Forms each invented their own word for the same outcome",
|
|
1892
|
+
required: false
|
|
1893
|
+
},
|
|
1894
|
+
to: {
|
|
1895
|
+
type: "string",
|
|
1896
|
+
description: "The new name for --rename",
|
|
1897
|
+
required: false
|
|
1898
|
+
},
|
|
1899
|
+
"remove-name": {
|
|
1900
|
+
type: "string",
|
|
1901
|
+
description: "Stop counting an outcome entirely, by name \u2014 removes every event counted under it. Use --remove for a single event key instead",
|
|
1902
|
+
required: false
|
|
1903
|
+
},
|
|
1904
|
+
"count-mode": {
|
|
1905
|
+
type: "string",
|
|
1906
|
+
description: "once_per_visit (default) or every_time. Ask whether doing it twice in one visit is one outcome or two: a booking clicked twice is one booking, a guide downloaded twice is two downloads. Getting this wrong inflates the rate every budget is set by. Pass it with --event and no --name to change the mode of something already counted, keeping its name",
|
|
1907
|
+
required: false
|
|
1908
|
+
},
|
|
1909
|
+
remove: {
|
|
1910
|
+
type: "string",
|
|
1911
|
+
description: "An event key to stop counting. REPEATABLE. Removes it from the history too, for the same reason adding it fills the history in",
|
|
1912
|
+
required: false
|
|
1913
|
+
},
|
|
1914
|
+
candidates: {
|
|
1915
|
+
type: "boolean",
|
|
1916
|
+
description: "Also list every event these pages actually produced, ranked by volume, with whether it is already counted. This is where an event key comes from \u2014 do not invent one. Compact by default in JSON: each page or system event is one line (eventKey, events, sessions, countedAs when counted) and a Form's keys fold onto its `flows` row as `keys` and `events` (or a `formCandidates` row for a Form not in `flows`). Add --flow <slug> for that Form's keys only, and --full --output json for every field of every row",
|
|
1917
|
+
required: false
|
|
1918
|
+
},
|
|
1919
|
+
full: {
|
|
1920
|
+
type: "boolean",
|
|
1921
|
+
description: "With --candidates: every field of every candidate (origin, nodeType, flowSlug, lastSeen, sources, doors) and every Form key unfolded. Large on a busy company \u2014 narrow it with --flow first",
|
|
1922
|
+
required: false
|
|
1923
|
+
},
|
|
1924
|
+
flow: {
|
|
1925
|
+
type: "string",
|
|
1926
|
+
description: "A Form slug. Lists that Form's own endings already spelled as event keys, each with the name Baker counts it under or nothing \u2014 read off the Form's file, so it works on a Form built minutes ago that has never been visited, which is exactly when --candidates is empty. With --candidates, narrows the candidates to that Form's keys. Use it whenever you create or edit a Form: it is the only way to see that the Form counts nothing before it is published counting nothing",
|
|
1927
|
+
required: false
|
|
1928
|
+
},
|
|
1929
|
+
days: {
|
|
1930
|
+
type: "string",
|
|
1931
|
+
description: "Lookback for the counts and for --candidates. Default 30",
|
|
1932
|
+
required: false
|
|
1933
|
+
},
|
|
1934
|
+
output: SHARED_ARGS.output
|
|
1935
|
+
};
|
|
1936
|
+
registerSchema({
|
|
1937
|
+
command: "analytics.conversions",
|
|
1938
|
+
description: "Read or change what this company counts as a conversion on its pages. Also `--flow <slug>` for one Form's own endings as event keys, whether or not any of them has fired.",
|
|
1939
|
+
args
|
|
1940
|
+
});
|
|
1941
|
+
return defineCommand({
|
|
1942
|
+
meta: {
|
|
1943
|
+
name: "conversions",
|
|
1944
|
+
description: "What this company counts as a conversion \u2014 the numerator of every conversion rate on Measure. A page event (a Form ending, a data-baker-* event) and an event one of the client's systems sends (a HubSpot event made with `baker analytics sources --create-hubspot`, an order the server posts) both count; a system's event is credited to the last landing its person viewed. A HubSpot event is `page:<its name>` here \u2014 `--event 'page:Deal won' --name 'Deal won'`. Run with no flags first: an empty `definitions` list means every conversion number in every other report is zero \u2014 not because nobody converted, but because nothing is marked as converting, and Baker never guesses. Add `--candidates` to see everything these pages actually do (every Form step, every data-baker-* event, every outbound destination) with counts and whether it is already counted; that list is where an event key comes from, so never invent one. It is compact: a Form's keys fold onto its `flows` row, `--candidates --flow <slug>` lists one Form's keys, and `--full --output json` returns every field of every row. Then `--event <key> --name 'Booked a call'` to count it. Inside a chat a change is STAGED: the person sees it under Sources in the chat's changes, on the event's own row and it applies when they publish, retroactively \u2014 the whole history is rescored, so a company that has been running for a month gets a month of correct numbers. A read shows a proposal marked `staged`. Call an event by its name when you talk to the person, never by its key. Two events given the SAME --name are one row and one number. `--remove <key>` stops counting one. `--flow <slug>` answers the other direction \u2014 what one Form counts, with every ending it has already spelled as an event key, read from the Form itself so it works before a single visitor has seen it. Run it whenever you create or edit a Form: a Form nobody named an outcome for is published converting nobody, and no report says so."
|
|
1945
|
+
},
|
|
1946
|
+
args,
|
|
1947
|
+
run: async ({ args: raw }) => {
|
|
1948
|
+
try {
|
|
1949
|
+
const format = outputFormatOrExit(raw.output);
|
|
1950
|
+
const args2 = parseConversionsArgs(raw, process.argv);
|
|
1951
|
+
for (const eventKey of args2.eventKeys) refuseUnmatchableKey(eventKey);
|
|
1952
|
+
const before = await apiPost("/api/analytics/conversions", {});
|
|
1953
|
+
const write = conversionsWrite(args2, before.data.definitions);
|
|
1954
|
+
const answer = write ? await apiPost("/api/analytics/conversions", write) : before;
|
|
1955
|
+
const stored = answer.data.definitions;
|
|
1956
|
+
const report = await readConversionCounts(
|
|
1957
|
+
(path, body) => apiPost(path, body),
|
|
1958
|
+
args2.days,
|
|
1959
|
+
write !== null
|
|
1960
|
+
);
|
|
1961
|
+
const envelope = conversionsEnvelope(
|
|
1962
|
+
args2,
|
|
1963
|
+
mergeStoredWithCounts(stored, report.conversions),
|
|
1964
|
+
report.eventCatalog,
|
|
1965
|
+
[...answer.hints ?? [], ...report.hints, ...fullFlagHints(args2, format)]
|
|
1966
|
+
);
|
|
1967
|
+
if (format === "md") process.stdout.write(renderConversionsMarkdown(envelope));
|
|
1968
|
+
else writeJsonEnvelope(withFormatHint(compactConversionsEnvelope(envelope, args2), format));
|
|
1969
|
+
} catch (err) {
|
|
1970
|
+
if (err instanceof ConversionArgsError) {
|
|
1971
|
+
if (err.fix !== void 0) {
|
|
1972
|
+
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message: err.message, fix: err.fix } });
|
|
1973
|
+
process.exit(1);
|
|
1974
|
+
}
|
|
1975
|
+
handleError(new ApiError("VALIDATION_ERROR", err.message));
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
handleError(err);
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
});
|
|
1982
|
+
})();
|
|
1983
|
+
function pageCandidates(definitions, catalogue, listing) {
|
|
1984
|
+
return { candidates: [...catalogue], hints: conversionHints(definitions, catalogue, listing) };
|
|
1985
|
+
}
|
|
1986
|
+
function parsePairs(raw) {
|
|
1987
|
+
if (raw === void 0) return void 0;
|
|
1988
|
+
const out = {};
|
|
1989
|
+
for (const pair of raw.split(",")) {
|
|
1990
|
+
const [name, role] = pair.split("=");
|
|
1991
|
+
if (name?.trim() && role?.trim()) out[name.trim()] = role.trim();
|
|
1992
|
+
}
|
|
1993
|
+
return out;
|
|
1994
|
+
}
|
|
1995
|
+
function parseList(raw) {
|
|
1996
|
+
if (raw === void 0) return void 0;
|
|
1997
|
+
const out = raw.split(",").map((entry) => entry.trim()).filter((entry) => entry !== "");
|
|
1998
|
+
return out.length > 0 ? out : void 0;
|
|
1999
|
+
}
|
|
2000
|
+
var arrivalsCommand = (() => {
|
|
2001
|
+
const args = {
|
|
2002
|
+
mode: {
|
|
2003
|
+
type: "string",
|
|
2004
|
+
description: "live | test. Rehearsals (X-Baker-Mode: test) are accepted and write nothing, so they never reach a report \u2014 filter to them to confirm a rehearsal landed, or to live to see only what counted",
|
|
2005
|
+
required: false
|
|
2006
|
+
},
|
|
2007
|
+
outcome: {
|
|
2008
|
+
type: "string",
|
|
2009
|
+
description: "accepted | rejected. Start with rejected: it is the half the sender's own logs threw away, and the reason to open this at all",
|
|
2010
|
+
required: false
|
|
2011
|
+
},
|
|
2012
|
+
event: {
|
|
2013
|
+
type: "string",
|
|
2014
|
+
description: "Only this event_name, for a company posting several kinds",
|
|
2015
|
+
required: false
|
|
2016
|
+
},
|
|
2017
|
+
limit: {
|
|
2018
|
+
type: "string",
|
|
2019
|
+
description: `How many to return, newest first (default 25, max ${INGEST_ARRIVALS_MAX})`,
|
|
2020
|
+
required: false
|
|
2021
|
+
},
|
|
2022
|
+
full: {
|
|
2023
|
+
type: "boolean",
|
|
2024
|
+
description: "Also return the masked request body and the per-field identity previews. Reach for it only once the codes have not explained it \u2014 it is most of the bytes",
|
|
2025
|
+
required: false
|
|
2026
|
+
}
|
|
2027
|
+
};
|
|
2028
|
+
registerSchema({
|
|
2029
|
+
command: "analytics.arrivals",
|
|
2030
|
+
description: "What a client's own server posted to POST /v1/events in the last 48 hours, and why any of it was refused",
|
|
2031
|
+
args
|
|
2032
|
+
});
|
|
2033
|
+
return defineCommand({
|
|
2034
|
+
meta: {
|
|
2035
|
+
name: "arrivals",
|
|
2036
|
+
description: `Every request a client's own server posted to POST /v1/events in the last 48 hours \u2014 accepted, refused or rehearsed. The one place a server-side integration can be debugged.
|
|
2037
|
+
|
|
2038
|
+
Read this FIRST whenever somebody says events are being sent and nothing shows up. Four different causes look identical from the sender's side and only this tells them apart:
|
|
2039
|
+
the request never reached us \u2014 nothing here at all: the key, the URL, or their own dispatch
|
|
2040
|
+
it was refused \u2014 rejectCode says which rule, rejectMessage says what the field had to be
|
|
2041
|
+
it was a rehearsal \u2014 mode: test is accepted, answered identically, and writes nothing on purpose
|
|
2042
|
+
it landed \u2014 then the question is a report's, not the endpoint's
|
|
2043
|
+
|
|
2044
|
+
Examples:
|
|
2045
|
+
baker analytics arrivals \u2014 the last 25, newest first
|
|
2046
|
+
baker analytics arrivals --outcome rejected \u2014 only the refusals, which is usually the whole answer
|
|
2047
|
+
baker analytics arrivals --mode test \u2014 did the rehearsal they just ran actually arrive
|
|
2048
|
+
baker analytics arrivals --event deal_won \u2014 one kind only
|
|
2049
|
+
baker analytics arrivals --full --limit 5 \u2014 the masked body, when the codes have not explained it`
|
|
2050
|
+
},
|
|
2051
|
+
args,
|
|
2052
|
+
run: async ({ args: raw }) => {
|
|
2053
|
+
try {
|
|
2054
|
+
const limit = raw.limit === void 0 ? void 0 : Number(raw.limit);
|
|
2055
|
+
const response = await apiPost("/api/analytics/arrivals", {
|
|
2056
|
+
...raw.mode ? { mode: String(raw.mode) } : {},
|
|
2057
|
+
...raw.outcome ? { outcome: String(raw.outcome) } : {},
|
|
2058
|
+
...raw.event ? { eventName: String(raw.event) } : {},
|
|
2059
|
+
...limit !== void 0 && Number.isFinite(limit) ? { limit } : {},
|
|
2060
|
+
...raw.full ? { full: true } : {}
|
|
2061
|
+
});
|
|
2062
|
+
writeJsonEnvelope(response);
|
|
2063
|
+
} catch (err) {
|
|
2064
|
+
handleError(err);
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
});
|
|
2068
|
+
})();
|
|
2069
|
+
function sendingEventsAddress(env) {
|
|
2070
|
+
return eventIngestUrl(env.BAKER_PUBLIC_API_URL, env.BAKER_API_URL);
|
|
2071
|
+
}
|
|
2072
|
+
var sendingEventsCommand = (() => {
|
|
2073
|
+
registerSchema({
|
|
2074
|
+
command: "analytics.sending-events",
|
|
2075
|
+
description: "The POST /v1/events contract as Markdown, for whoever is writing the integration",
|
|
2076
|
+
args: {}
|
|
2077
|
+
});
|
|
2078
|
+
return defineCommand({
|
|
2079
|
+
meta: {
|
|
2080
|
+
name: "sending-events",
|
|
2081
|
+
description: `The complete contract for sending events into Baker from a client's own systems \u2014 a CRM marking a deal won, a back office recording a refund \u2014 as Markdown you can hand straight to whoever writes the integration.
|
|
2082
|
+
|
|
2083
|
+
Use it whenever a client wants an outcome that happens AFTER the lead leaves the page to show up in Baker. Every bound, every rejection code and every rule is read off the code that enforces it, so it cannot go stale; the six mistakes that all produce a 200 are called out before the reader starts rather than explained afterwards.
|
|
2084
|
+
|
|
2085
|
+
It contains no key \u2014 the brief says to read one from an environment variable, and the key itself is minted in the dashboard under Settings \u2192 API keys. Never put one in a file or a message.
|
|
2086
|
+
|
|
2087
|
+
Examples:
|
|
2088
|
+
baker analytics sending-events \u2014 the contract, as Markdown
|
|
2089
|
+
baker analytics arrivals --outcome rejected \u2014 after they have wired it up, what is being refused`
|
|
2090
|
+
},
|
|
2091
|
+
args: {},
|
|
2092
|
+
run: () => {
|
|
2093
|
+
process.stdout.write(`${ingestBrief(sendingEventsAddress(getEnv()))}
|
|
2094
|
+
`);
|
|
2095
|
+
}
|
|
2096
|
+
});
|
|
2097
|
+
})();
|
|
2098
|
+
var websiteTagCommand = (() => {
|
|
2099
|
+
registerSchema({
|
|
2100
|
+
command: "analytics.website-tag",
|
|
2101
|
+
description: "The measurement tag for a website Baker does not publish, with this company's key in it",
|
|
2102
|
+
args: {
|
|
2103
|
+
measure: {
|
|
2104
|
+
type: "string",
|
|
2105
|
+
required: false,
|
|
2106
|
+
description: 'Whose activity to measure: "campaigns" (default), "outcomes" or "all"'
|
|
2107
|
+
},
|
|
2108
|
+
check: {
|
|
2109
|
+
type: "boolean",
|
|
2110
|
+
required: false,
|
|
2111
|
+
description: "Every event the Tag Manager container sends Baker, and whether a real visit has brought it"
|
|
2112
|
+
},
|
|
2113
|
+
days: { type: "string", required: false, description: "With --check: how far back to look (default 30)" }
|
|
2114
|
+
}
|
|
2115
|
+
});
|
|
2116
|
+
return defineCommand({
|
|
2117
|
+
meta: {
|
|
2118
|
+
name: "website-tag",
|
|
2119
|
+
description: `The one script tag that measures a website Baker does not publish \u2014 the client's own site, their shop, their booking page \u2014 with this company's site key already in it, plus the whole install as Markdown.
|
|
2120
|
+
|
|
2121
|
+
Reach for it whenever measurement has to reach a page Baker did not build. What it returns is real and complete: the tag, the websites the key is accepted from, and the rules for the hidden form fields, the identify call and the conversion call.
|
|
2122
|
+
|
|
2123
|
+
Three things worth knowing before you install it:
|
|
2124
|
+
the origins list \u2014 the key is IGNORED from any origin not on it, silently. An empty list means the tag will measure nothing.
|
|
2125
|
+
Tag Manager is usually the way in \u2014 a Custom HTML tag on All Pages. If the client has a container connected, you can stage that yourself (baker tag-manager).
|
|
2126
|
+
in a container, use tagManagerTag \u2014 the response carries two tags. \`tag\` is for a page somebody can edit; \`tagManagerTag\` is the one to stage, because a container rebuilds a Custom HTML tag's script element from its src alone and drops the key, so \`tag\` measures nothing there, published and silent. Check it on the page afterwards: window.baker in the browser console.
|
|
2127
|
+
--measure decides the BILL \u2014 the tag goes on every page whatever you do; this decides whose activity is measured. Leave it alone unless the client asked for their whole website.
|
|
2128
|
+
|
|
2129
|
+
--measure campaigns (default) people your Baker campaigns brought to the site. Their whole journey, through to the outcome. Nobody else is measured at all.
|
|
2130
|
+
--measure outcomes nobody's browsing. Only what the site reports with window.baker.track(...), and forms it wired to Baker.
|
|
2131
|
+
--measure all every visitor and every page view of the whole website. Their reports then describe their business, not their campaigns, and outcomes from organic, email and direct land in their conversion numbers. A decision, never a default.
|
|
2132
|
+
|
|
2133
|
+
Examples:
|
|
2134
|
+
baker analytics website-tag \u2014 the tag, the origins and the install brief
|
|
2135
|
+
baker analytics website-tag --measure all \u2014 measure their whole website, because they asked for that
|
|
2136
|
+
baker analytics website-tag --check \u2014 every event Tag Manager sends Baker, and which never arrived
|
|
2137
|
+
baker analytics events --origin website \u2014 after it is live, what that website is reporting`
|
|
2138
|
+
},
|
|
2139
|
+
args: {
|
|
2140
|
+
measure: {
|
|
2141
|
+
type: "string",
|
|
2142
|
+
description: 'Whose activity to measure: "campaigns" (default), "outcomes" or "all". Widening is a decision \u2014 see above.'
|
|
2143
|
+
},
|
|
2144
|
+
check: {
|
|
2145
|
+
type: "boolean",
|
|
2146
|
+
description: 'Read the connected Tag Manager container for every window.baker.track call its tags make, and say which events a real visit has brought in the window and which never arrived. Start here when "an event is missing": an event the container sends and nobody has seen is invisible on every other report'
|
|
2147
|
+
},
|
|
2148
|
+
days: { type: "string", description: "With --check: how many days back to look for each event (default 30)" }
|
|
2149
|
+
},
|
|
2150
|
+
run: async (ctx) => {
|
|
2151
|
+
if (ctx.args.check === true) {
|
|
2152
|
+
await runWebsiteEventCheck(Number(ctx.args.days ?? 30) || 30);
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
try {
|
|
2156
|
+
const measure = typeof ctx.args.measure === "string" ? ctx.args.measure : void 0;
|
|
2157
|
+
const envelope = await apiPost(
|
|
2158
|
+
"/api/analytics/website-tag",
|
|
2159
|
+
measure ? { measure } : {}
|
|
2160
|
+
);
|
|
2161
|
+
writeJsonEnvelope({ ...envelope, hints: websiteTagHints(envelope.data) });
|
|
2162
|
+
} catch (err) {
|
|
2163
|
+
handleError(err);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
});
|
|
2167
|
+
})();
|
|
2168
|
+
async function runWebsiteEventCheck(days) {
|
|
2169
|
+
let tags;
|
|
2170
|
+
try {
|
|
2171
|
+
tags = (await apiPost(
|
|
2172
|
+
"/api/tag-manager/read",
|
|
2173
|
+
{ entities: ["tag"], full: true },
|
|
2174
|
+
{ timeoutMs: TAG_MANAGER_TIMEOUT_MS }
|
|
2175
|
+
)).tags;
|
|
2176
|
+
} catch (err) {
|
|
2177
|
+
writeJsonEnvelope({
|
|
2178
|
+
ok: false,
|
|
2179
|
+
error: {
|
|
2180
|
+
code: "TAG_MANAGER_UNAVAILABLE",
|
|
2181
|
+
message: `The check reads the website's Tag Manager container, and it could not: ${err instanceof Error ? err.message : String(err)}`,
|
|
2182
|
+
fix: {
|
|
2183
|
+
action: "continue_without",
|
|
2184
|
+
explanation: "Without a connected container there is no list of what the site is wired to send. Read what did arrive with `baker analytics feed --origin website`, and ask the person to connect Tag Manager if the site uses it."
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
});
|
|
2188
|
+
process.exit(1);
|
|
2189
|
+
}
|
|
2190
|
+
try {
|
|
2191
|
+
let catalog;
|
|
2192
|
+
let unread = "";
|
|
2193
|
+
try {
|
|
2194
|
+
const response = await apiPost("/api/analytics/query", {
|
|
2195
|
+
preset: "conversions",
|
|
2196
|
+
eventOrigin: "website",
|
|
2197
|
+
days
|
|
2198
|
+
});
|
|
2199
|
+
catalog = response.data.eventCatalog ?? [];
|
|
2200
|
+
} catch (err) {
|
|
2201
|
+
catalog = null;
|
|
2202
|
+
unread = err instanceof Error ? err.message : String(err);
|
|
2203
|
+
}
|
|
2204
|
+
const { events } = checkWebsiteEvents(tags, catalog);
|
|
2205
|
+
const hints = websiteEventCheckHints(events, days);
|
|
2206
|
+
if (catalog === null) {
|
|
2207
|
+
hints.push(
|
|
2208
|
+
`What arrived could not be read (${unread}), so this lists what the container sends, unchecked. \`baker analytics feed --origin website\` is the other half once reading works.`
|
|
2209
|
+
);
|
|
2210
|
+
}
|
|
2211
|
+
if (events.length === 0) {
|
|
2212
|
+
hints.push(
|
|
2213
|
+
"No tag in the container calls window.baker.track, so the website sends Baker page views and nothing else. Outcomes come from tags you stage with `baker tag-manager`."
|
|
2214
|
+
);
|
|
2215
|
+
}
|
|
2216
|
+
writeJsonEnvelope({ ok: true, data: { days, events }, hints });
|
|
2217
|
+
} catch (err) {
|
|
2218
|
+
handleError(err);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
var DEBUG_ARGS = {
|
|
2222
|
+
code: {
|
|
2223
|
+
type: "positional",
|
|
2224
|
+
required: false,
|
|
2225
|
+
description: "The code `--start` returned: read what was recorded under it"
|
|
2226
|
+
},
|
|
2227
|
+
start: {
|
|
2228
|
+
type: "boolean",
|
|
2229
|
+
required: false,
|
|
2230
|
+
description: "Mint a debug link for the person to open in their own browser"
|
|
2231
|
+
},
|
|
2232
|
+
url: {
|
|
2233
|
+
type: "string",
|
|
2234
|
+
required: false,
|
|
2235
|
+
description: "With --start: the page the person should open (the link is built on it)"
|
|
2236
|
+
},
|
|
2237
|
+
full: { type: "boolean", required: false, description: "Every record's payload, masked, not just what it was" }
|
|
2238
|
+
};
|
|
2239
|
+
registerSchema({
|
|
2240
|
+
command: "analytics.debug",
|
|
2241
|
+
description: "A link that records what a person's own browser heard on their website, and the read of it",
|
|
2242
|
+
args: DEBUG_ARGS
|
|
2243
|
+
});
|
|
2244
|
+
var debugCommand = defineCommand({
|
|
2245
|
+
meta: {
|
|
2246
|
+
name: "debug",
|
|
2247
|
+
description: `Watch a real visit from the person's own browser: what the page heard \u2014 messages from its iframes, custom events, dataLayer pushes \u2014 and what Baker's website tag did with it.
|
|
2248
|
+
|
|
2249
|
+
Start here when an event from the client's own website never arrives and a test from your browser cannot settle it: a voice, video or chat widget your headless browser cannot run, a login that is theirs, a cookie banner only they answer. Your own browser is flagged as a bot and in no report, so their visit is the test that counts.
|
|
2250
|
+
|
|
2251
|
+
baker analytics debug --start --url https://client.com/ \u2014 a link to send them; it records for two hours
|
|
2252
|
+
baker analytics debug <code> \u2014 what their visit recorded, in order, with what to read first
|
|
2253
|
+
baker analytics debug <code> --full \u2014 every record's payload (emails and phones masked)
|
|
2254
|
+
|
|
2255
|
+
Nothing recorded is counted or shown in Baker; it is purged a day later.`
|
|
2256
|
+
},
|
|
2257
|
+
args: DEBUG_ARGS,
|
|
2258
|
+
run: async ({ args }) => {
|
|
2259
|
+
try {
|
|
2260
|
+
if (args.start === true) {
|
|
2261
|
+
const response2 = await apiPost("/api/analytics/debug", {
|
|
2262
|
+
start: true,
|
|
2263
|
+
...typeof args.url === "string" && args.url !== "" ? { url: args.url } : {}
|
|
2264
|
+
});
|
|
2265
|
+
writeJsonEnvelope({ ok: true, data: response2.data, hints: debugStartHints(response2.data) });
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
if (typeof args.code !== "string" || args.code === "") {
|
|
2269
|
+
writeJsonEnvelope({
|
|
2270
|
+
ok: false,
|
|
2271
|
+
error: {
|
|
2272
|
+
code: "VALIDATION_ERROR",
|
|
2273
|
+
message: "Pass --start to mint a debug link, or the code it returned to read it."
|
|
2274
|
+
}
|
|
2275
|
+
});
|
|
2276
|
+
process.exit(1);
|
|
2277
|
+
}
|
|
2278
|
+
const response = await apiPost("/api/analytics/debug", {
|
|
2279
|
+
code: args.code,
|
|
2280
|
+
full: true
|
|
2281
|
+
});
|
|
2282
|
+
writeJsonEnvelope({
|
|
2283
|
+
ok: true,
|
|
2284
|
+
data: compactDebugRead(response.data, args.full === true),
|
|
2285
|
+
hints: debugReadHints(response.data)
|
|
2286
|
+
});
|
|
2287
|
+
} catch (err) {
|
|
2288
|
+
handleError(err);
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
});
|
|
2292
|
+
var sitesCommand = (() => {
|
|
2293
|
+
registerSchema({
|
|
2294
|
+
command: "analytics.sites",
|
|
2295
|
+
description: "The websites this company's measurement tag is accepted from, and adding or removing one",
|
|
2296
|
+
args: {
|
|
2297
|
+
add: { type: "string", required: false, description: "Website address to accept measurement from" },
|
|
2298
|
+
remove: { type: "string", required: false, description: "Website address to stop accepting measurement from" }
|
|
2299
|
+
}
|
|
2300
|
+
});
|
|
2301
|
+
return defineCommand({
|
|
2302
|
+
meta: {
|
|
2303
|
+
name: "sites",
|
|
2304
|
+
description: `Which websites this company's measurement tag is accepted from \u2014 and the command that changes it.
|
|
2305
|
+
|
|
2306
|
+
The site key ships in the source of every page it is pasted on, so this list is the whole of what stops a stranger who read it appending forged conversions to these numbers. A tag on a website that is NOT on this list is ignored, silently, with no failing request anywhere. That is the single most common reason an install measures nothing.
|
|
2307
|
+
|
|
2308
|
+
One entry covers the estate under it: example.com answers for www.example.com, go.example.com and shop.eu.example.com. It never widens upward \u2014 declaring go.example.com does NOT cover example.com \u2014 so declare the DOMAIN, not the subdomain you happen to be installing on today.
|
|
2309
|
+
|
|
2310
|
+
Start here:
|
|
2311
|
+
baker analytics sites \u2014 what is declared now, and what is worth adding
|
|
2312
|
+
baker analytics sites --add example.com \u2014 accept measurement from that site and everything under it
|
|
2313
|
+
baker analytics sites --remove old-site.com
|
|
2314
|
+
|
|
2315
|
+
Examples:
|
|
2316
|
+
baker analytics website-tag \u2014 get the tag; if its origins are empty, come here first
|
|
2317
|
+
baker analytics sites --add foodforjoe.es \u2014 one entry covering www., go. and shop.`
|
|
2318
|
+
},
|
|
2319
|
+
args: {
|
|
2320
|
+
add: {
|
|
2321
|
+
type: "string",
|
|
2322
|
+
description: "Website address to accept measurement from, e.g. example.com \u2014 covers every subdomain of it. Repeat for several"
|
|
2323
|
+
},
|
|
2324
|
+
remove: { type: "string", description: "Website address to stop accepting measurement from" }
|
|
2325
|
+
},
|
|
2326
|
+
run: async (ctx) => {
|
|
2327
|
+
try {
|
|
2328
|
+
const raw = ctx.rawArgs;
|
|
2329
|
+
const body = {
|
|
2330
|
+
add: repeatedValues(raw, "add", ctx.args.add),
|
|
2331
|
+
remove: repeatedValues(raw, "remove", ctx.args.remove)
|
|
2332
|
+
};
|
|
2333
|
+
const envelope = await apiPost("/api/analytics/sites", body);
|
|
2334
|
+
writeJsonEnvelope({ ...envelope, hints: analyticsSitesHints(envelope.data) });
|
|
2335
|
+
} catch (err) {
|
|
2336
|
+
handleError(err);
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
});
|
|
2340
|
+
})();
|
|
2341
|
+
var analyticsCommand = defineCommand({
|
|
2342
|
+
meta: {
|
|
2343
|
+
name: "analytics",
|
|
2344
|
+
description: `Baker's own web analytics for this company's published pages. No connection to set up \u2014 data starts the moment a page is published.
|
|
2345
|
+
|
|
2346
|
+
Start here:
|
|
2347
|
+
baker analytics overview \u2014 traffic, pages, sources and Form drop-off in one call
|
|
2348
|
+
baker analytics landings \u2014 every page side by side, with a sparkline each
|
|
2349
|
+
baker analytics presets \u2014 what each report answers
|
|
2350
|
+
|
|
2351
|
+
Examples:
|
|
2352
|
+
baker analytics overview --days 7
|
|
2353
|
+
baker analytics funnel --flow contact \u2014 which step loses people
|
|
2354
|
+
baker analytics flow --flow contact \u2014 that Form in depth: conversions, step-to-step paths, triggers
|
|
2355
|
+
baker analytics overview --landing ld_7f2a \u2014 the whole report for one page only
|
|
2356
|
+
baker analytics page --path /pricing \u2014 one page in detail
|
|
2357
|
+
baker analytics triggers --flow contact \u2014 what people did in the Form, wired up or not
|
|
2358
|
+
baker analytics paid --days 30 \u2014 campaigns by click id, and how many leads actually arrived
|
|
2359
|
+
baker analytics delivery \u2014 submissions whose destination refused them
|
|
2360
|
+
baker analytics submissions --flow contact \u2014 every attempt at that Form, delivered or not
|
|
2361
|
+
baker analytics releases \u2014 did the last publish change anything
|
|
2362
|
+
baker analytics traffic --days 90 --full \u2014 full breakdowns and the per-day trend
|
|
2363
|
+
baker analytics geo --grain postal_code --country ES \u2014 which postcodes convert
|
|
2364
|
+
baker analytics bots --days 30 \u2014 is the site still being crawled
|
|
2365
|
+
baker analytics companies --targets targets.csv \u2014 which target accounts visited, and which did not
|
|
2366
|
+
baker analytics landings --tag q3 \u2014 how the Q3 campaign's pages did
|
|
2367
|
+
baker analytics tags \u2014 the same numbers rolled up per campaign
|
|
2368
|
+
baker analytics events --event video --property milestone \u2014 how far people watch
|
|
2369
|
+
baker analytics events --event video --property milestone --where autoplay=0 \u2014 ...among videos they chose to play
|
|
2370
|
+
baker analytics events --steps hero_view,pricing_view,demo_click \u2014 an ordered page funnel
|
|
2371
|
+
baker analytics devices --grain viewport \u2014 which widths the page has to survive
|
|
2372
|
+
baker analytics ads \u2014 every campaign parameter on this company's URLs, and what we make of it
|
|
2373
|
+
baker analytics ads --role keyword \u2014 keywords by conversions AND by how many bounced
|
|
2374
|
+
baker analytics ads --platform google --role keyword \u2014 the same, in Google's vocabulary and from Google's traffic only
|
|
2375
|
+
baker analytics overview --role keyword --value "solar panels" \u2014 the whole report for those visits only
|
|
2376
|
+
baker analytics tracking \u2014 do the ad URLs carry the campaign, ad group and ad at all
|
|
2377
|
+
baker analytics tracking --platform meta \u2014 the same for one platform, read from their own ad account
|
|
2378
|
+
baker analytics map --platform google --set kw=keyword \u2014 stage a parameter name, seen or not yet
|
|
2379
|
+
baker analytics map --platform google --remove kw \u2014 take that answer back
|
|
2380
|
+
baker analytics unstage --kind conversion --ref 'page:Deal won' \u2014 take back a change this chat staged
|
|
2381
|
+
baker analytics delivery --page 2 --page-size 50 \u2014 the next page of a long list
|
|
2382
|
+
baker analytics overview --compare \u2014 this window against the one before it
|
|
2383
|
+
baker analytics website-tag \u2014 the tag for a website Baker does not publish, key included
|
|
2384
|
+
baker analytics sending-events \u2014 the contract for a client's server to post its own events
|
|
2385
|
+
baker analytics arrivals --outcome rejected \u2014 what their server posted that we refused, and why
|
|
2386
|
+
baker analytics events --origin server \u2014 the events their systems reported, not ours
|
|
2387
|
+
baker analytics lookup --person 'ana@empresa.com, deal:40001234567' \u2014 which of these people Baker has, and what it saw of each
|
|
2388
|
+
baker analytics feed --person 'ana@empresa.com' --days 90 \u2014 everything one person did, in order
|
|
2389
|
+
Full guide: __tooling__/docs/tools/baker/analytics.md`
|
|
2390
|
+
},
|
|
2391
|
+
subCommands: {
|
|
2392
|
+
overview: overviewCommand,
|
|
2393
|
+
traffic: trafficCommand,
|
|
2394
|
+
funnel: funnelCommand,
|
|
2395
|
+
flow: flowCommand,
|
|
2396
|
+
page: pageCommand,
|
|
2397
|
+
triggers: triggersCommand,
|
|
2398
|
+
releases: releasesCommand,
|
|
2399
|
+
paid: paidCommand,
|
|
2400
|
+
delivery: deliveryCommand,
|
|
2401
|
+
submissions: submissionsCommand,
|
|
2402
|
+
geo: geoCommand,
|
|
2403
|
+
bots: botsCommand,
|
|
2404
|
+
companies: companiesCommand,
|
|
2405
|
+
landings: landingsCommand,
|
|
2406
|
+
tags: tagsCommand,
|
|
2407
|
+
events: eventsCommand,
|
|
2408
|
+
feed: feedCommand,
|
|
2409
|
+
lookup: () => import("./lookup-IUQWU346.js").then((m) => m.lookupCommand),
|
|
2410
|
+
devices: devicesCommand,
|
|
2411
|
+
ads: adsCommand,
|
|
2412
|
+
conversions: conversionsCommand,
|
|
2413
|
+
sends: () => import("./sends-43FU3SJN.js").then((m) => m.sendsCommand),
|
|
2414
|
+
map: mapCommand,
|
|
2415
|
+
unstage: () => import("./unstage-YSVQ6DLB.js").then((m) => m.unstageCommand),
|
|
2416
|
+
tracking: trackingCommand,
|
|
2417
|
+
arrivals: arrivalsCommand,
|
|
2418
|
+
"sending-events": sendingEventsCommand,
|
|
2419
|
+
sources: () => import("./sources-PUZ4WV4Q.js").then((m) => m.sourcesCommand),
|
|
2420
|
+
"website-tag": websiteTagCommand,
|
|
2421
|
+
debug: debugCommand,
|
|
2422
|
+
sites: sitesCommand,
|
|
2423
|
+
plan: () => import("./plan-VHMWZU7F.js").then((m) => m.planCommand),
|
|
2424
|
+
questionnaire: () => import("./questionnaire-32BQ4ZUX.js").then((m) => m.questionnaireCommand),
|
|
2425
|
+
presets: presetsCommand
|
|
2426
|
+
}
|
|
2427
|
+
});
|
|
2428
|
+
export {
|
|
2429
|
+
analyticsCommand,
|
|
2430
|
+
conversionsEnvelope,
|
|
2431
|
+
feedRequest,
|
|
2432
|
+
paginationError,
|
|
2433
|
+
readConversionCounts,
|
|
2434
|
+
requestBody,
|
|
2435
|
+
sendingEventsAddress
|
|
2436
|
+
};
|
|
2437
|
+
//# sourceMappingURL=analytics-OUNKG2FW.js.map
|