@koda-sl/baker-cli 0.450.0-dev.b454c3dd2 → 0.450.0-dev.d6701597d
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 -11
- package/dist/{account-XQXC7BR6.js → account-AL2ZDSR7.js} +4 -5
- package/dist/{account-XQXC7BR6.js.map → account-AL2ZDSR7.js.map} +1 -1
- package/dist/{accounts-722UY53A.js → accounts-HAFCLSR5.js} +3 -4
- package/dist/{accounts-722UY53A.js.map → accounts-HAFCLSR5.js.map} +1 -1
- package/dist/{accounts-E67BMK7T.js → accounts-O5MFO3QQ.js} +5 -6
- package/dist/{accounts-E67BMK7T.js.map → accounts-O5MFO3QQ.js.map} +1 -1
- package/dist/{actions-6TQMSVWD.js → actions-P35MEMGN.js} +18 -18
- package/dist/{add-2BEGRHUX.js → add-5GAN6CVO.js} +5 -28
- package/dist/add-5GAN6CVO.js.map +1 -0
- package/dist/{add-LEMKEOPO.js → add-6DTC6X5G.js} +2 -3
- package/dist/{add-LEMKEOPO.js.map → add-6DTC6X5G.js.map} +1 -1
- package/dist/{ads-AGYCVD62.js → ads-73PGA4YC.js} +4 -4
- package/dist/{advertisers-2VQKAYKG.js → advertisers-AE75CGVE.js} +3 -4
- package/dist/{advertisers-2VQKAYKG.js.map → advertisers-AE75CGVE.js.map} +1 -1
- package/dist/{analytics-IFELDWLL.js → analytics-FKCXIMPO.js} +20 -24
- package/dist/analytics-FKCXIMPO.js.map +1 -0
- package/dist/{analytics-OH5QEH7F.js → analytics-FPWQQGRM.js} +3 -4
- package/dist/{analytics-OH5QEH7F.js.map → analytics-FPWQQGRM.js.map} +1 -1
- package/dist/{assign-PTUJUCEL.js → assign-ABN2AQ4J.js} +3 -4
- package/dist/{assign-PTUJUCEL.js.map → assign-ABN2AQ4J.js.map} +1 -1
- package/dist/{audience-size-LRI6GJRT.js → audience-size-GNBJY35X.js} +3 -4
- package/dist/{audience-size-LRI6GJRT.js.map → audience-size-GNBJY35X.js.map} +1 -1
- package/dist/{audit-HWP7OPB7.js → audit-3VS63TBW.js} +3 -4
- package/dist/{audit-HWP7OPB7.js.map → audit-3VS63TBW.js.map} +1 -1
- package/dist/{autocomplete-J6DHU6MR.js → autocomplete-VS3XG3B7.js} +3 -4
- package/dist/{autocomplete-J6DHU6MR.js.map → autocomplete-VS3XG3B7.js.map} +1 -1
- package/dist/{avatars-467OSBD6.js → avatars-EKCKHCC3.js} +4 -4
- package/dist/{bid-pricing-EO5WLHGV.js → bid-pricing-Q72B65AY.js} +3 -4
- package/dist/{bid-pricing-EO5WLHGV.js.map → bid-pricing-Q72B65AY.js.map} +1 -1
- package/dist/{brand-YRTEPGBK.js → brand-C6PFGGQN.js} +2 -2
- package/dist/{brief-OSFJ2V7F.js → brief-YFJHQ5VQ.js} +7 -8
- package/dist/{brief-OSFJ2V7F.js.map → brief-YFJHQ5VQ.js.map} +1 -1
- package/dist/{campaign-groups-PQ6KSQJR.js → campaign-groups-KFFYQPU3.js} +8 -9
- package/dist/{campaign-groups-PQ6KSQJR.js.map → campaign-groups-KFFYQPU3.js.map} +1 -1
- package/dist/{campaign-writes-5OVLUD5E.js → campaign-writes-FHOS5XZY.js} +3 -4
- package/dist/{campaign-writes-5OVLUD5E.js.map → campaign-writes-FHOS5XZY.js.map} +1 -1
- package/dist/{campaigns-6T3NSUT2.js → campaigns-2NHWBF5C.js} +11 -12
- package/dist/{campaigns-6T3NSUT2.js.map → campaigns-2NHWBF5C.js.map} +1 -1
- package/dist/{campaigns-OYMXDGWX.js → campaigns-KZYZTXDS.js} +5 -5
- package/dist/{canvas-YQFG52IG.js → canvas-5NB27FX2.js} +13 -13
- package/dist/{capabilities-PXBKUN2G.js → capabilities-DJFTRJKS.js} +3 -4
- package/dist/{capabilities-PXBKUN2G.js.map → capabilities-DJFTRJKS.js.map} +1 -1
- package/dist/{catalog-XLXIM7IW.js → catalog-VSSY6FGI.js} +4 -4
- package/dist/{chats-UK47UE7C.js → chats-D2CSDX5Q.js} +3 -4
- package/dist/{chats-UK47UE7C.js.map → chats-D2CSDX5Q.js.map} +1 -1
- package/dist/{chunk-5ZNTADVR.js → chunk-3G3ZDLMI.js} +2 -2
- package/dist/{chunk-SJYEY5MV.js → chunk-3HJLHTWP.js} +3 -12
- package/dist/{chunk-SJYEY5MV.js.map → chunk-3HJLHTWP.js.map} +1 -1
- package/dist/{chunk-ZDMTXQ2Q.js → chunk-3IBYKLXR.js} +2 -2
- package/dist/{chunk-CWYAELVG.js → chunk-464O4MT2.js} +2 -2
- package/dist/{chunk-NA63BH7V.js → chunk-4AUMTNVB.js} +3 -3
- package/dist/{chunk-NDEE6G2J.js → chunk-4BQXAE7Z.js} +2 -2
- package/dist/{chunk-2AOE2MZQ.js → chunk-5ZDLTE5T.js} +3 -3
- package/dist/{chunk-ULG4QRTV.js → chunk-6NB47MRW.js} +2 -2
- package/dist/{chunk-24EB7EDR.js → chunk-7YCRFMXF.js} +3 -3
- package/dist/{chunk-WGUQHAJY.js → chunk-A4LOJ2VD.js} +2 -2
- package/dist/{chunk-6F7DVPOS.js → chunk-AEOSAVVL.js} +3 -3
- package/dist/{chunk-MACCF4JZ.js → chunk-CMPEUZOR.js} +22 -16
- package/dist/{chunk-MACCF4JZ.js.map → chunk-CMPEUZOR.js.map} +1 -1
- package/dist/{chunk-N4LAYIIN.js → chunk-CSYSX4D2.js} +2 -2
- package/dist/{chunk-RX2DKU3W.js → chunk-DGUNI37S.js} +2 -2
- package/dist/{chunk-QE7W555R.js → chunk-DWHIOO7E.js} +12 -163
- package/dist/chunk-DWHIOO7E.js.map +1 -0
- package/dist/{chunk-FPOGPFAG.js → chunk-EBWBG6YV.js} +51 -24
- package/dist/chunk-EBWBG6YV.js.map +1 -0
- package/dist/{chunk-NYIGXDUG.js → chunk-EDLZGTGN.js} +39 -1
- package/dist/chunk-EDLZGTGN.js.map +1 -0
- package/dist/{chunk-I3ZR655O.js → chunk-IR6D7K4H.js} +2 -2
- package/dist/{chunk-FUHN4MFY.js → chunk-JQJDXPCO.js} +2 -2
- package/dist/{chunk-7CTMH5AK.js → chunk-KAUOHQTF.js} +3 -3
- package/dist/{chunk-VYQ3QJ3C.js → chunk-KHRXPQID.js} +2 -2
- package/dist/{chunk-6Y7ZBENQ.js → chunk-LECGCWT5.js} +6 -6
- package/dist/{chunk-5WCSKQ7Z.js → chunk-LZ73CZGP.js} +6 -6
- package/dist/{chunk-R25YLW6H.js → chunk-MELOSESI.js} +2 -2
- package/dist/{chunk-DCRPXOJJ.js → chunk-MXYBTMKB.js} +2 -2
- package/dist/{chunk-54C6YDGJ.js → chunk-NPY4QUMQ.js} +2 -2
- package/dist/{chunk-LYQJ4PZW.js → chunk-OQ6663F4.js} +5 -5
- package/dist/{chunk-H3427GPU.js → chunk-OZRUJVIQ.js} +2 -2
- package/dist/{chunk-KMKEYI37.js → chunk-Q2V6E6SL.js} +3 -3
- package/dist/{chunk-VL43TNIP.js → chunk-QRP3PXWN.js} +2 -2
- package/dist/{chunk-HDLYPC6K.js → chunk-RPUSTYHL.js} +3 -5
- package/dist/{chunk-HDLYPC6K.js.map → chunk-RPUSTYHL.js.map} +1 -1
- package/dist/{chunk-C46GUI2S.js → chunk-RZBEK2VE.js} +2 -2
- package/dist/{chunk-2VPBIT65.js → chunk-S3A3YOKO.js} +8 -8
- package/dist/{chunk-FYGR3I2A.js → chunk-S77PZVYM.js} +3 -3
- package/dist/{chunk-VLMBTPXU.js → chunk-SHL7LOC3.js} +3 -3
- package/dist/{chunk-HR6IWNKE.js → chunk-SSJK7FEV.js} +1140 -1196
- package/dist/chunk-SSJK7FEV.js.map +1 -0
- package/dist/{chunk-KS2QY6MK.js → chunk-W3ZHJJVT.js} +4 -4
- package/dist/{chunk-7EPXVICM.js → chunk-XF4JUKVF.js} +5 -38
- package/dist/chunk-XF4JUKVF.js.map +1 -0
- package/dist/{chunk-RL5CP7N6.js → chunk-Y6O7EWYY.js} +5 -5
- package/dist/{chunk-6NY2GPR4.js → chunk-Y6ZQXUZ7.js} +3 -3
- package/dist/{chunk-HROZYQ5H.js → chunk-YRQYA2LR.js} +5 -63
- package/dist/chunk-YRQYA2LR.js.map +1 -0
- package/dist/{chunk-ASI4P6X2.js → chunk-YUCLMOEG.js} +6 -6
- package/dist/chunk-YUCLMOEG.js.map +1 -0
- package/dist/{chunk-WKQG6TER.js → chunk-ZEYEWPK6.js} +2 -2
- package/dist/{claim-W6G6VEG5.js → claim-FZ5OQLMU.js} +3 -4
- package/dist/{claim-W6G6VEG5.js.map → claim-FZ5OQLMU.js.map} +1 -1
- package/dist/cli.js +30 -30
- package/dist/{companies-TS6KBATJ.js → companies-DNI634RC.js} +3 -4
- package/dist/{companies-TS6KBATJ.js.map → companies-DNI634RC.js.map} +1 -1
- package/dist/{complete-LYR2HMQU.js → complete-2FZMGJV5.js} +3 -4
- package/dist/{complete-LYR2HMQU.js.map → complete-2FZMGJV5.js.map} +1 -1
- package/dist/{connect-FCXNVTXG.js → connect-QCOGEPP4.js} +6 -13
- package/dist/{conversation-6ZJGPCXM.js → conversation-6IOGV7B7.js} +3 -4
- package/dist/{conversation-6ZJGPCXM.js.map → conversation-6IOGV7B7.js.map} +1 -1
- package/dist/{conversions-UHB55MMQ.js → conversions-4SRZPBBX.js} +7 -8
- package/dist/{conversions-UHB55MMQ.js.map → conversions-4SRZPBBX.js.map} +1 -1
- package/dist/{create-EX6OWLNM.js → create-BJNMO6HT.js} +2 -3
- package/dist/{create-EX6OWLNM.js.map → create-BJNMO6HT.js.map} +1 -1
- package/dist/{create-JFSK4BOP.js → create-FX4OJ2XF.js} +3 -4
- package/dist/{create-JFSK4BOP.js.map → create-FX4OJ2XF.js.map} +1 -1
- package/dist/{create-JCA7JPLP.js → create-RM7HV77Y.js} +3 -4
- package/dist/{create-JCA7JPLP.js.map → create-RM7HV77Y.js.map} +1 -1
- package/dist/{create-WU22YYU2.js → create-VXM34ZWH.js} +3 -4
- package/dist/{create-WU22YYU2.js.map → create-VXM34ZWH.js.map} +1 -1
- package/dist/{creatives-FXUQ5WSD.js → creatives-B5NTXPUB.js} +10 -10
- package/dist/{creatives-KGXUOYPE.js → creatives-JSWBFQ5R.js} +8 -9
- package/dist/{creatives-KGXUOYPE.js.map → creatives-JSWBFQ5R.js.map} +1 -1
- package/dist/{credentials-MJC7PGKR.js → credentials-C33K6XCJ.js} +3 -4
- package/dist/{credentials-MJC7PGKR.js.map → credentials-C33K6XCJ.js.map} +1 -1
- package/dist/{critique-GS5VV5ZC.js → critique-4V5SKH7C.js} +6 -7
- package/dist/{critique-GS5VV5ZC.js.map → critique-4V5SKH7C.js.map} +1 -1
- package/dist/{critique-TPHR27KH.js → critique-ZS4ON3SU.js} +3 -4
- package/dist/{critique-TPHR27KH.js.map → critique-ZS4ON3SU.js.map} +1 -1
- package/dist/{crm-VK44O3ED.js → crm-52ROSWH5.js} +4 -5
- package/dist/{crm-VK44O3ED.js.map → crm-52ROSWH5.js.map} +1 -1
- package/dist/{crm-AVCM5D4G.js → crm-R5IXIFIV.js} +4 -5
- package/dist/{crm-AVCM5D4G.js.map → crm-R5IXIFIV.js.map} +1 -1
- package/dist/{customers-XH2DMTFH.js → customers-A36LOZOB.js} +5 -6
- package/dist/{delete-WI5E3DR3.js → delete-AIGE4Y4H.js} +3 -4
- package/dist/{delete-WI5E3DR3.js.map → delete-AIGE4Y4H.js.map} +1 -1
- package/dist/{delete-KRH2YMSZ.js → delete-HGHXY24R.js} +3 -4
- package/dist/{delete-KRH2YMSZ.js.map → delete-HGHXY24R.js.map} +1 -1
- package/dist/{delete-E3R3TKIL.js → delete-M2GDLPYN.js} +2 -3
- package/dist/{delete-E3R3TKIL.js.map → delete-M2GDLPYN.js.map} +1 -1
- package/dist/{demographics-XV5PBA77.js → demographics-NTWB2IMG.js} +3 -4
- package/dist/{demographics-XV5PBA77.js.map → demographics-NTWB2IMG.js.map} +1 -1
- package/dist/{discard-HTQUUHJR.js → discard-2WWQG6OU.js} +3 -4
- package/dist/{discard-HTQUUHJR.js.map → discard-2WWQG6OU.js.map} +1 -1
- package/dist/{domain-RECGZXJB.js → domain-Y2LT6JLT.js} +3 -4
- package/dist/{domain-RECGZXJB.js.map → domain-Y2LT6JLT.js.map} +1 -1
- package/dist/{draft-Q546QPPU.js → draft-EJXNNJ3Y.js} +4 -5
- package/dist/{draft-Q546QPPU.js.map → draft-EJXNNJ3Y.js.map} +1 -1
- package/dist/{draft-PVTX6QT6.js → draft-FJ7WHIXW.js} +3 -4
- package/dist/{draft-PVTX6QT6.js.map → draft-FJ7WHIXW.js.map} +1 -1
- package/dist/{draft-2IBSJEKC.js → draft-SLHAKJ2A.js} +3 -4
- package/dist/{draft-2IBSJEKC.js.map → draft-SLHAKJ2A.js.map} +1 -1
- package/dist/engine/index.js +3 -3
- package/dist/{facets-7EVPJMKS.js → facets-U7AQC4H6.js} +3 -4
- package/dist/{facets-7EVPJMKS.js.map → facets-U7AQC4H6.js.map} +1 -1
- package/dist/{feedback-EIZKS4JU.js → feedback-OLTCHE6C.js} +2 -2
- package/dist/{feedback-record-TKO54BOE.js → feedback-record-7WZ4H7EP.js} +8 -9
- package/dist/{feedback-record-TKO54BOE.js.map → feedback-record-7WZ4H7EP.js.map} +1 -1
- package/dist/{fetch-4BY6HYUM.js → fetch-W7NULDEO.js} +3 -4
- package/dist/{fetch-4BY6HYUM.js.map → fetch-W7NULDEO.js.map} +1 -1
- package/dist/{find-FRRHAPWX.js → find-OTDIX6V4.js} +4 -4
- package/dist/{flows-KTFAML22.js → flows-KABCBS3S.js} +17 -21
- package/dist/flows-KABCBS3S.js.map +1 -0
- package/dist/{fonts-MXR3ZKDX.js → fonts-EMMX3KII.js} +5 -6
- package/dist/{forecast-3QTJYVND.js → forecast-GNODEIIC.js} +3 -4
- package/dist/{forecast-3QTJYVND.js.map → forecast-GNODEIIC.js.map} +1 -1
- package/dist/{funnel-I6XIAEHG.js → funnel-AAX27NH4.js} +455 -11
- package/dist/funnel-AAX27NH4.js.map +1 -0
- package/dist/{ga4-DV2AXCSL.js → ga4-UDQ2HA2J.js} +1 -1
- package/dist/{get-5PKNKJ5S.js → get-QEYJRLV3.js} +4 -7
- package/dist/get-QEYJRLV3.js.map +1 -0
- package/dist/{get-72YPHJGV.js → get-RTVUZM6E.js} +3 -4
- package/dist/{get-72YPHJGV.js.map → get-RTVUZM6E.js.map} +1 -1
- package/dist/{google-QYYYSSXI.js → google-KTO3PLEU.js} +5 -5
- package/dist/{google-6OGZX47I.js → google-M7KEXVK5.js} +2 -2
- package/dist/{google-ads-QGMQKZQD.js → google-ads-OK6IG3UV.js} +3 -4
- package/dist/{google-ads-QGMQKZQD.js.map → google-ads-OK6IG3UV.js.map} +1 -1
- package/dist/{gsc-TAKOF7J5.js → gsc-P3QYGDV2.js} +1 -1
- package/dist/{history-6AVQX2OQ.js → history-PQUJKK26.js} +3 -4
- package/dist/{history-6AVQX2OQ.js.map → history-PQUJKK26.js.map} +1 -1
- package/dist/{hubspot-SVEMFK5S.js → hubspot-Y77VLY6Y.js} +8 -9
- package/dist/{hubspot-SVEMFK5S.js.map → hubspot-Y77VLY6Y.js.map} +1 -1
- package/dist/{icon-L4RSS6PZ.js → icon-I43F77FV.js} +4 -4
- package/dist/{ideas-NFOW3HKJ.js → ideas-MIDU7YOA.js} +2 -3
- package/dist/{images-2EFFUNNV.js → images-S254MS6O.js} +9 -9
- package/dist/{ingest-2SO62RRI.js → ingest-J4I3HKM3.js} +2 -3
- package/dist/{ingest-2SO62RRI.js.map → ingest-J4I3HKM3.js.map} +1 -1
- package/dist/{ingest-2EIKN4QC.js → ingest-YV2NLDBE.js} +3 -4
- package/dist/{inspect-4OOS4APT.js → inspect-Q5NHBBHX.js} +3 -4
- package/dist/{inspect-4OOS4APT.js.map → inspect-Q5NHBBHX.js.map} +1 -1
- package/dist/{inspiration-S3DU4CMQ.js → inspiration-P265QJ2H.js} +1 -1
- package/dist/{keyword-metrics-SF4CSNZ2.js → keyword-metrics-PDY4ZXSP.js} +3 -4
- package/dist/{keyword-metrics-SF4CSNZ2.js.map → keyword-metrics-PDY4ZXSP.js.map} +1 -1
- package/dist/{keywords-for-site-WDAOPNKC.js → keywords-for-site-GALSCV77.js} +3 -4
- package/dist/{keywords-for-site-WDAOPNKC.js.map → keywords-for-site-GALSCV77.js.map} +1 -1
- package/dist/{landing-2ZB46LXH.js → landing-CJYGWCK4.js} +3 -3
- package/dist/{leads-A4W5KTWB.js → leads-PHKG6CP3.js} +3 -4
- package/dist/{leads-A4W5KTWB.js.map → leads-PHKG6CP3.js.map} +1 -1
- package/dist/{learn-IPULBCOD.js → learn-FUQSY7DN.js} +4 -5
- package/dist/{learn-IPULBCOD.js.map → learn-FUQSY7DN.js.map} +1 -1
- package/dist/{line-item-writes-EMYSOJKM.js → line-item-writes-E6MZPIZZ.js} +3 -4
- package/dist/{line-item-writes-EMYSOJKM.js.map → line-item-writes-E6MZPIZZ.js.map} +1 -1
- package/dist/{line-items-5NECXUZT.js → line-items-7ZGIKEF2.js} +5 -5
- package/dist/{link-CI45HWFN.js → link-QYAW6A2W.js} +3 -4
- package/dist/{link-CI45HWFN.js.map → link-QYAW6A2W.js.map} +1 -1
- package/dist/{linkedin-B7SYR75X.js → linkedin-FFSDSGGS.js} +26 -27
- package/dist/{linkedin-B7SYR75X.js.map → linkedin-FFSDSGGS.js.map} +1 -1
- package/dist/{list-ZBT3EBVZ.js → list-5IC6KIKO.js} +3 -4
- package/dist/{list-ZBT3EBVZ.js.map → list-5IC6KIKO.js.map} +1 -1
- package/dist/{list-2BARXOT5.js → list-NVQC5SNY.js} +2 -3
- package/dist/{list-2BARXOT5.js.map → list-NVQC5SNY.js.map} +1 -1
- package/dist/{list-BIEVLEHS.js → list-SAV3LQHY.js} +3 -4
- package/dist/{list-BIEVLEHS.js.map → list-SAV3LQHY.js.map} +1 -1
- package/dist/{log-C23OOAJZ.js → log-XZPVOALD.js} +3 -4
- package/dist/{log-C23OOAJZ.js.map → log-XZPVOALD.js.map} +1 -1
- package/dist/{logo-Q5D7PZY6.js → logo-2IP663QO.js} +3 -3
- package/dist/{lookup-ETWY47F7.js → lookup-XK45W2SH.js} +5 -6
- package/dist/{make-TPKKJXGL.js → make-BMWRKIIY.js} +20 -18
- package/dist/{make-TPKKJXGL.js.map → make-BMWRKIIY.js.map} +1 -1
- package/dist/{map-SYZMPHLL.js → map-4J5WIWIG.js} +4 -5
- package/dist/{map-SYZMPHLL.js.map → map-4J5WIWIG.js.map} +1 -1
- package/dist/{mcp-6FQBVJ6F.js → mcp-XXD7ZQCP.js} +2 -3
- package/dist/{mcp-6FQBVJ6F.js.map → mcp-XXD7ZQCP.js.map} +1 -1
- package/dist/{media-sources-ZXHEEP6T.js → media-sources-O6ZRUA3N.js} +2 -2
- package/dist/{members-UDY4OOJW.js → members-D5ZYLS4Y.js} +3 -4
- package/dist/{members-UDY4OOJW.js.map → members-D5ZYLS4Y.js.map} +1 -1
- package/dist/{normalize-DAKHYS3V.js → normalize-PCNC6E2N.js} +3 -7
- package/dist/{normalize-DAKHYS3V.js.map → normalize-PCNC6E2N.js.map} +1 -1
- package/dist/{options-QL3ULED5.js → options-MQ65VEVD.js} +6 -7
- package/dist/{options-QL3ULED5.js.map → options-MQ65VEVD.js.map} +1 -1
- package/dist/{performance-UF5VTY2U.js → performance-6QW2KEEQ.js} +4 -5
- package/dist/{promoted-tweet-writes-7HGESJ46.js → promoted-tweet-writes-JPLHY3GM.js} +3 -4
- package/dist/{promoted-tweet-writes-7HGESJ46.js.map → promoted-tweet-writes-JPLHY3GM.js.map} +1 -1
- package/dist/{promoted-tweets-LZKS5JIF.js → promoted-tweets-SURKMHFI.js} +3 -3
- package/dist/{publish-NPD3SMZL.js → publish-HCQ6MXLB.js} +3 -4
- package/dist/{publish-NPD3SMZL.js.map → publish-HCQ6MXLB.js.map} +1 -1
- package/dist/{reddit-NU2N3LZD.js → reddit-GIP3ADMS.js} +4 -5
- package/dist/{refresh-EBVJ2C6L.js → refresh-UXQSLCR3.js} +2 -3
- package/dist/{refresh-EBVJ2C6L.js.map → refresh-UXQSLCR3.js.map} +1 -1
- package/dist/{release-V43YB2PY.js → release-5KVLXNP6.js} +3 -4
- package/dist/{release-V43YB2PY.js.map → release-5KVLXNP6.js.map} +1 -1
- package/dist/{remove-QPSWLFI4.js → remove-6FIVKCJI.js} +2 -3
- package/dist/{remove-QPSWLFI4.js.map → remove-6FIVKCJI.js.map} +1 -1
- package/dist/{reopen-GQ66NMWF.js → reopen-YM5LNOLB.js} +3 -4
- package/dist/{reopen-GQ66NMWF.js.map → reopen-YM5LNOLB.js.map} +1 -1
- package/dist/{rerun-PZK275DY.js → rerun-6XZG7BGK.js} +17 -18
- package/dist/{rerun-PZK275DY.js.map → rerun-6XZG7BGK.js.map} +1 -1
- package/dist/{research-FMM6AWZC.js → research-2BLEISBG.js} +10 -10
- package/dist/{research-GEOCUBXB.js → research-YOGE7GT2.js} +2 -3
- package/dist/{research-GEOCUBXB.js.map → research-YOGE7GT2.js.map} +1 -1
- package/dist/{reset-REXJ6AUK.js → reset-C4UHQ3EU.js} +2 -3
- package/dist/{reset-REXJ6AUK.js.map → reset-C4UHQ3EU.js.map} +1 -1
- package/dist/{reset-Y72IVESB.js → reset-OLVB6AE6.js} +2 -3
- package/dist/{reset-Y72IVESB.js.map → reset-OLVB6AE6.js.map} +1 -1
- package/dist/{resolve-OGX7C4TV.js → resolve-XYH2GDAE.js} +3 -4
- package/dist/{resolve-OGX7C4TV.js.map → resolve-XYH2GDAE.js.map} +1 -1
- package/dist/{retry-TCUBBFR5.js → retry-726GKI6V.js} +2 -3
- package/dist/{retry-TCUBBFR5.js.map → retry-726GKI6V.js.map} +1 -1
- package/dist/{retry-CD6JAQ3F.js → retry-7EELDEQP.js} +2 -3
- package/dist/{retry-CD6JAQ3F.js.map → retry-7EELDEQP.js.map} +1 -1
- package/dist/{run-EUO34T2J.js → run-MMEDKJDB.js} +17 -18
- package/dist/{run-A5ZDXTOI.js → run-P4KR2MXC.js} +3 -4
- package/dist/{run-A5ZDXTOI.js.map → run-P4KR2MXC.js.map} +1 -1
- package/dist/{scaffold-ad-SW2HEWM3.js → scaffold-ad-PBTEWDAC.js} +12 -13
- package/dist/{scaffold-ad-SW2HEWM3.js.map → scaffold-ad-PBTEWDAC.js.map} +1 -1
- package/dist/{scaffold-static-ad-ECTJL54Y.js → scaffold-static-ad-RM4M4X5U.js} +36 -37
- package/dist/scaffold-static-ad-RM4M4X5U.js.map +1 -0
- package/dist/{scaffold-video-EI7U7RBK.js → scaffold-video-O2TTKZIE.js} +11 -12
- package/dist/{scaffold-video-EI7U7RBK.js.map → scaffold-video-O2TTKZIE.js.map} +1 -1
- package/dist/{schedule-S5YZJZ5U.js → schedule-RDK4GEPI.js} +2 -3
- package/dist/{schedule-S5YZJZ5U.js.map → schedule-RDK4GEPI.js.map} +1 -1
- package/dist/{scheduled-agents-N4LJRM4C.js → scheduled-agents-6U44QE76.js} +11 -11
- package/dist/{schema-R7JWWOF4.js → schema-CHJDC7GQ.js} +4 -8
- package/dist/{schema-R7JWWOF4.js.map → schema-CHJDC7GQ.js.map} +1 -1
- package/dist/{search-KHMQH3AT.js → search-PMJRU3C4.js} +2 -3
- package/dist/{search-KHMQH3AT.js.map → search-PMJRU3C4.js.map} +1 -1
- package/dist/{select-O2FN2JEQ.js → select-OEUKOVZ5.js} +8 -9
- package/dist/{select-O2FN2JEQ.js.map → select-OEUKOVZ5.js.map} +1 -1
- package/dist/{sends-BQZM5PLS.js → sends-WGJVQUMF.js} +4 -5
- package/dist/{sends-BQZM5PLS.js.map → sends-WGJVQUMF.js.map} +1 -1
- package/dist/{set-prompt-2HASHGWC.js → set-prompt-5E5I7QAZ.js} +8 -9
- package/dist/{set-prompt-2HASHGWC.js.map → set-prompt-5E5I7QAZ.js.map} +1 -1
- package/dist/{setup-links-GYSE56GX.js → setup-links-REPREN3C.js} +3 -4
- package/dist/{setup-links-GYSE56GX.js.map → setup-links-REPREN3C.js.map} +1 -1
- package/dist/{site-4SKM7RKG.js → site-WFSWIA3S.js} +4 -5
- package/dist/{site-4SKM7RKG.js.map → site-WFSWIA3S.js.map} +1 -1
- package/dist/{sources-R2NKNC6J.js → sources-AMI2AWKZ.js} +9 -10
- package/dist/{sources-R2NKNC6J.js.map → sources-AMI2AWKZ.js.map} +1 -1
- package/dist/{sources-FQ2UZTHL.js → sources-YBQ6KPFM.js} +6 -6
- package/dist/{stale-W756ACKC.js → stale-IGFUKEN2.js} +7 -8
- package/dist/{stale-W756ACKC.js.map → stale-IGFUKEN2.js.map} +1 -1
- package/dist/{status-SE2VZJJB.js → status-7F2KHFGA.js} +3 -4
- package/dist/{status-SE2VZJJB.js.map → status-7F2KHFGA.js.map} +1 -1
- package/dist/{stock-KXJ26BY4.js → stock-2YCDN3N6.js} +5 -5
- package/dist/{studio-SYKOSNDB.js → studio-RA7QQH4O.js} +1 -1
- package/dist/{sync-LJGSODK3.js → sync-GWTLKZTU.js} +2 -3
- package/dist/{sync-LJGSODK3.js.map → sync-GWTLKZTU.js.map} +1 -1
- package/dist/{sync-definition-QR2N233R.js → sync-definition-UGSDX2SZ.js} +11 -12
- package/dist/{tags-PYWFSBTR.js → tags-3WPW6PTV.js} +4 -4
- package/dist/{tags-QQU3OKMZ.js → tags-6342FQEB.js} +3 -4
- package/dist/{tags-QQU3OKMZ.js.map → tags-6342FQEB.js.map} +1 -1
- package/dist/{tags-5SBMRC2A.js → tags-ABHSX6M5.js} +3 -4
- package/dist/{tags-5SBMRC2A.js.map → tags-ABHSX6M5.js.map} +1 -1
- package/dist/{tags-YYLNF3PK.js → tags-FJIBBBRG.js} +3 -4
- package/dist/{tags-YYLNF3PK.js.map → tags-FJIBBBRG.js.map} +1 -1
- package/dist/{tags-4BAVFH4S.js → tags-KFYLZLB3.js} +2 -3
- package/dist/{tags-4BAVFH4S.js.map → tags-KFYLZLB3.js.map} +1 -1
- package/dist/{targeting-criteria-RJFLFICN.js → targeting-criteria-NR47AF5C.js} +3 -3
- package/dist/{targets-S2MT2PNB.js → targets-L56KOVQE.js} +3 -4
- package/dist/{targets-S2MT2PNB.js.map → targets-L56KOVQE.js.map} +1 -1
- package/dist/{templates-ZE5TOGRT.js → templates-B6XGDYUF.js} +3 -4
- package/dist/{templates-ZE5TOGRT.js.map → templates-B6XGDYUF.js.map} +1 -1
- package/dist/{testimonials-DII5DYLR.js → testimonials-CVC4YIXO.js} +6 -6
- package/dist/{top-companies-PGIAEHDF.js → top-companies-45X3DT7Z.js} +3 -4
- package/dist/{top-companies-PGIAEHDF.js.map → top-companies-45X3DT7Z.js.map} +1 -1
- package/dist/{translate-GXTS633J.js → translate-VP5R67PL.js} +11 -12
- package/dist/{translate-GXTS633J.js.map → translate-VP5R67PL.js.map} +1 -1
- package/dist/{triggers-2PTONXRU.js → triggers-22EMIVFD.js} +3 -4
- package/dist/{triggers-2PTONXRU.js.map → triggers-22EMIVFD.js.map} +1 -1
- package/dist/{unlink-XRMYJ6DB.js → unlink-65KUN6ID.js} +3 -4
- package/dist/{unlink-XRMYJ6DB.js.map → unlink-65KUN6ID.js.map} +1 -1
- package/dist/{unstage-FY7A3YFF.js → unstage-2E3I5SWF.js} +3 -4
- package/dist/{unstage-FY7A3YFF.js.map → unstage-2E3I5SWF.js.map} +1 -1
- package/dist/{unstage-RM2RLXKD.js → unstage-4ZEULXEQ.js} +4 -5
- package/dist/{unstage-RM2RLXKD.js.map → unstage-4ZEULXEQ.js.map} +1 -1
- package/dist/{update-S4562V3O.js → update-2S7CSEAW.js} +3 -4
- package/dist/{update-S4562V3O.js.map → update-2S7CSEAW.js.map} +1 -1
- package/dist/{update-V6YVEUI2.js → update-7NCOTAQZ.js} +3 -4
- package/dist/{update-V6YVEUI2.js.map → update-7NCOTAQZ.js.map} +1 -1
- package/dist/{update-PJ67D2OG.js → update-D6DJC6T7.js} +2 -3
- package/dist/{update-PJ67D2OG.js.map → update-D6DJC6T7.js.map} +1 -1
- package/dist/{update-E5SRBXQR.js → update-KREBPGBH.js} +3 -4
- package/dist/{update-E5SRBXQR.js.map → update-KREBPGBH.js.map} +1 -1
- package/dist/{upload-R6CQVLKF.js → upload-O6NHRPS7.js} +3 -4
- package/dist/{upload-R6CQVLKF.js.map → upload-O6NHRPS7.js.map} +1 -1
- package/dist/{url-options-JOKU46F2.js → url-options-GGXAL3J4.js} +3 -4
- package/dist/{url-options-JOKU46F2.js.map → url-options-GGXAL3J4.js.map} +1 -1
- package/dist/{url-params-7U2XMOWF.js → url-params-3EFGVTZZ.js} +3 -4
- package/dist/{url-params-7U2XMOWF.js.map → url-params-3EFGVTZZ.js.map} +1 -1
- package/dist/{validate-7YPOUKPB.js → validate-CSJM7XZM.js} +9 -10
- package/dist/{validate-7YPOUKPB.js.map → validate-CSJM7XZM.js.map} +1 -1
- package/dist/{videos-LICG6ACJ.js → videos-YSXYGTBM.js} +5 -5
- package/dist/{web-BA2PGTWU.js → web-IGIGVEKS.js} +3 -4
- package/dist/{web-BA2PGTWU.js.map → web-IGIGVEKS.js.map} +1 -1
- package/dist/{winning-ads-C6S2C5VP.js → winning-ads-2WS7FI4E.js} +2 -2
- package/dist/{write-commands-7SJ3BOW5.js → write-commands-5C7FUOVN.js} +4 -5
- package/dist/{write-commands-7SJ3BOW5.js.map → write-commands-5C7FUOVN.js.map} +1 -1
- package/dist/{x-CZHRC6U7.js → x-BFSKFCZD.js} +6 -6
- package/package.json +1 -1
- package/dist/add-2BEGRHUX.js.map +0 -1
- package/dist/analytics-IFELDWLL.js.map +0 -1
- package/dist/chunk-4PDHHHUJ.js +0 -537
- package/dist/chunk-4PDHHHUJ.js.map +0 -1
- package/dist/chunk-7EPXVICM.js.map +0 -1
- package/dist/chunk-ASI4P6X2.js.map +0 -1
- package/dist/chunk-FPOGPFAG.js.map +0 -1
- package/dist/chunk-HR6IWNKE.js.map +0 -1
- package/dist/chunk-HROZYQ5H.js.map +0 -1
- package/dist/chunk-NYIGXDUG.js.map +0 -1
- package/dist/chunk-QE7W555R.js.map +0 -1
- package/dist/flows-KTFAML22.js.map +0 -1
- package/dist/funnel-I6XIAEHG.js.map +0 -1
- package/dist/get-5PKNKJ5S.js.map +0 -1
- package/dist/plan-FT632COT.js +0 -51
- package/dist/plan-FT632COT.js.map +0 -1
- package/dist/questionnaire-JNGYJTAY.js +0 -37
- package/dist/questionnaire-JNGYJTAY.js.map +0 -1
- package/dist/scaffold-static-ad-ECTJL54Y.js.map +0 -1
- /package/dist/{actions-6TQMSVWD.js.map → actions-P35MEMGN.js.map} +0 -0
- /package/dist/{ads-AGYCVD62.js.map → ads-73PGA4YC.js.map} +0 -0
- /package/dist/{avatars-467OSBD6.js.map → avatars-EKCKHCC3.js.map} +0 -0
- /package/dist/{brand-YRTEPGBK.js.map → brand-C6PFGGQN.js.map} +0 -0
- /package/dist/{campaigns-OYMXDGWX.js.map → campaigns-KZYZTXDS.js.map} +0 -0
- /package/dist/{canvas-YQFG52IG.js.map → canvas-5NB27FX2.js.map} +0 -0
- /package/dist/{catalog-XLXIM7IW.js.map → catalog-VSSY6FGI.js.map} +0 -0
- /package/dist/{chunk-5ZNTADVR.js.map → chunk-3G3ZDLMI.js.map} +0 -0
- /package/dist/{chunk-ZDMTXQ2Q.js.map → chunk-3IBYKLXR.js.map} +0 -0
- /package/dist/{chunk-CWYAELVG.js.map → chunk-464O4MT2.js.map} +0 -0
- /package/dist/{chunk-NA63BH7V.js.map → chunk-4AUMTNVB.js.map} +0 -0
- /package/dist/{chunk-NDEE6G2J.js.map → chunk-4BQXAE7Z.js.map} +0 -0
- /package/dist/{chunk-2AOE2MZQ.js.map → chunk-5ZDLTE5T.js.map} +0 -0
- /package/dist/{chunk-ULG4QRTV.js.map → chunk-6NB47MRW.js.map} +0 -0
- /package/dist/{chunk-24EB7EDR.js.map → chunk-7YCRFMXF.js.map} +0 -0
- /package/dist/{chunk-WGUQHAJY.js.map → chunk-A4LOJ2VD.js.map} +0 -0
- /package/dist/{chunk-6F7DVPOS.js.map → chunk-AEOSAVVL.js.map} +0 -0
- /package/dist/{chunk-N4LAYIIN.js.map → chunk-CSYSX4D2.js.map} +0 -0
- /package/dist/{chunk-RX2DKU3W.js.map → chunk-DGUNI37S.js.map} +0 -0
- /package/dist/{chunk-I3ZR655O.js.map → chunk-IR6D7K4H.js.map} +0 -0
- /package/dist/{chunk-FUHN4MFY.js.map → chunk-JQJDXPCO.js.map} +0 -0
- /package/dist/{chunk-7CTMH5AK.js.map → chunk-KAUOHQTF.js.map} +0 -0
- /package/dist/{chunk-VYQ3QJ3C.js.map → chunk-KHRXPQID.js.map} +0 -0
- /package/dist/{chunk-6Y7ZBENQ.js.map → chunk-LECGCWT5.js.map} +0 -0
- /package/dist/{chunk-5WCSKQ7Z.js.map → chunk-LZ73CZGP.js.map} +0 -0
- /package/dist/{chunk-R25YLW6H.js.map → chunk-MELOSESI.js.map} +0 -0
- /package/dist/{chunk-DCRPXOJJ.js.map → chunk-MXYBTMKB.js.map} +0 -0
- /package/dist/{chunk-54C6YDGJ.js.map → chunk-NPY4QUMQ.js.map} +0 -0
- /package/dist/{chunk-LYQJ4PZW.js.map → chunk-OQ6663F4.js.map} +0 -0
- /package/dist/{chunk-H3427GPU.js.map → chunk-OZRUJVIQ.js.map} +0 -0
- /package/dist/{chunk-KMKEYI37.js.map → chunk-Q2V6E6SL.js.map} +0 -0
- /package/dist/{chunk-VL43TNIP.js.map → chunk-QRP3PXWN.js.map} +0 -0
- /package/dist/{chunk-C46GUI2S.js.map → chunk-RZBEK2VE.js.map} +0 -0
- /package/dist/{chunk-2VPBIT65.js.map → chunk-S3A3YOKO.js.map} +0 -0
- /package/dist/{chunk-FYGR3I2A.js.map → chunk-S77PZVYM.js.map} +0 -0
- /package/dist/{chunk-VLMBTPXU.js.map → chunk-SHL7LOC3.js.map} +0 -0
- /package/dist/{chunk-KS2QY6MK.js.map → chunk-W3ZHJJVT.js.map} +0 -0
- /package/dist/{chunk-RL5CP7N6.js.map → chunk-Y6O7EWYY.js.map} +0 -0
- /package/dist/{chunk-6NY2GPR4.js.map → chunk-Y6ZQXUZ7.js.map} +0 -0
- /package/dist/{chunk-WKQG6TER.js.map → chunk-ZEYEWPK6.js.map} +0 -0
- /package/dist/{connect-FCXNVTXG.js.map → connect-QCOGEPP4.js.map} +0 -0
- /package/dist/{creatives-FXUQ5WSD.js.map → creatives-B5NTXPUB.js.map} +0 -0
- /package/dist/{customers-XH2DMTFH.js.map → customers-A36LOZOB.js.map} +0 -0
- /package/dist/{feedback-EIZKS4JU.js.map → feedback-OLTCHE6C.js.map} +0 -0
- /package/dist/{find-FRRHAPWX.js.map → find-OTDIX6V4.js.map} +0 -0
- /package/dist/{fonts-MXR3ZKDX.js.map → fonts-EMMX3KII.js.map} +0 -0
- /package/dist/{ga4-DV2AXCSL.js.map → ga4-UDQ2HA2J.js.map} +0 -0
- /package/dist/{google-QYYYSSXI.js.map → google-KTO3PLEU.js.map} +0 -0
- /package/dist/{google-6OGZX47I.js.map → google-M7KEXVK5.js.map} +0 -0
- /package/dist/{gsc-TAKOF7J5.js.map → gsc-P3QYGDV2.js.map} +0 -0
- /package/dist/{icon-L4RSS6PZ.js.map → icon-I43F77FV.js.map} +0 -0
- /package/dist/{ideas-NFOW3HKJ.js.map → ideas-MIDU7YOA.js.map} +0 -0
- /package/dist/{images-2EFFUNNV.js.map → images-S254MS6O.js.map} +0 -0
- /package/dist/{ingest-2EIKN4QC.js.map → ingest-YV2NLDBE.js.map} +0 -0
- /package/dist/{inspiration-S3DU4CMQ.js.map → inspiration-P265QJ2H.js.map} +0 -0
- /package/dist/{landing-2ZB46LXH.js.map → landing-CJYGWCK4.js.map} +0 -0
- /package/dist/{line-items-5NECXUZT.js.map → line-items-7ZGIKEF2.js.map} +0 -0
- /package/dist/{logo-Q5D7PZY6.js.map → logo-2IP663QO.js.map} +0 -0
- /package/dist/{lookup-ETWY47F7.js.map → lookup-XK45W2SH.js.map} +0 -0
- /package/dist/{media-sources-ZXHEEP6T.js.map → media-sources-O6ZRUA3N.js.map} +0 -0
- /package/dist/{performance-UF5VTY2U.js.map → performance-6QW2KEEQ.js.map} +0 -0
- /package/dist/{promoted-tweets-LZKS5JIF.js.map → promoted-tweets-SURKMHFI.js.map} +0 -0
- /package/dist/{reddit-NU2N3LZD.js.map → reddit-GIP3ADMS.js.map} +0 -0
- /package/dist/{research-FMM6AWZC.js.map → research-2BLEISBG.js.map} +0 -0
- /package/dist/{run-EUO34T2J.js.map → run-MMEDKJDB.js.map} +0 -0
- /package/dist/{scheduled-agents-N4LJRM4C.js.map → scheduled-agents-6U44QE76.js.map} +0 -0
- /package/dist/{sources-FQ2UZTHL.js.map → sources-YBQ6KPFM.js.map} +0 -0
- /package/dist/{stock-KXJ26BY4.js.map → stock-2YCDN3N6.js.map} +0 -0
- /package/dist/{studio-SYKOSNDB.js.map → studio-RA7QQH4O.js.map} +0 -0
- /package/dist/{sync-definition-QR2N233R.js.map → sync-definition-UGSDX2SZ.js.map} +0 -0
- /package/dist/{tags-PYWFSBTR.js.map → tags-3WPW6PTV.js.map} +0 -0
- /package/dist/{targeting-criteria-RJFLFICN.js.map → targeting-criteria-NR47AF5C.js.map} +0 -0
- /package/dist/{testimonials-DII5DYLR.js.map → testimonials-CVC4YIXO.js.map} +0 -0
- /package/dist/{videos-LICG6ACJ.js.map → videos-YSXYGTBM.js.map} +0 -0
- /package/dist/{winning-ads-C6S2C5VP.js.map → winning-ads-2WS7FI4E.js.map} +0 -0
- /package/dist/{x-CZHRC6U7.js.map → x-BFSKFCZD.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../api/src/analytics/sends.ts","../../api/src/analytics/sendsWire.ts","../../api/src/analytics/unstage.ts","../../api/src/analytics/questionnaire.ts","../../api/src/analytics/busy.ts","../../api/src/analytics/conversionNames.ts","../../api/src/analytics/destinations.ts","../../api/src/analytics/triggers.ts","../../api/src/analytics/feedNoise.ts","../../api/src/analytics/matchKeys.ts","../../api/src/analytics/trackingTemplate.ts"],"sourcesContent":["/**\n * Where a system's event is sent: its sends.\n *\n * A send is what Meta, Google Ads, LinkedIn and X all call an offline\n * conversion — an event that happened away from the browser, a deal won in a\n * CRM, a booking confirmed by a calendar, a payment taken by a checkout — sent\n * to the ad platform from a server so the campaign that brought the person\n * gets the credit. In Baker it hangs off an **event one of the company's own\n * systems raises**, by its key: `page:deal_won` from HubSpot → Meta Purchase.\n * What happens on a page or in a Form already reaches the platform through\n * the pixels on the page and the Form's own side effects, so a send is never\n * set on those: a send used to hang off a conversion name, and the same Form\n * event then went to Meta twice.\n *\n * ## Nothing to map, on purpose\n *\n * A previous shape was a Form side effect verbatim: a per-destination form\n * with a variable picker, where somebody chose which field of the event went\n * into Meta's `fn` and Google's `hashed_first_name`. That is a mapping a person\n * should never have had to write, because there is nothing to decide: every\n * event in Baker's stream arrives in one shape whoever sent it\n * (`sendPayload.ts`), and every platform's server API takes the same\n * customer-matching block, the same click id, the same amount and currency.\n * So a send says only what a person can actually choose — **which** tag on\n * Tracking sends it and **what** the platform calls the event — and the\n * forwarding of who, which click, how much and where is the sender's job, done\n * the same way for every conversion in every company.\n *\n * ## A tag on Tracking, with its server credential\n *\n * Every platform here sends from the server through a tag the company already\n * has on Tracking — the Meta pixel, the Google Ads conversion tag, the LinkedIn\n * Insight Tag, the X pixel, the GA4 property — using the credential that tag\n * holds for exactly this: a Conversions API access token, an ad-account\n * connection, a Measurement Protocol secret. A tag without that credential can\n * fire in a browser and nowhere else, so it cannot be a destination for an\n * event that arrived with no browser anywhere. {@link tagSendsServerSide} is the\n * rule, and it is the same rule the Form's server-side senders apply\n * (`isCapiConfigured` in `packages/backend/convex/tags/utils.ts`, held in step\n * by a test there).\n *\n * ## It sends\n *\n * A send is live from the moment it is saved: a poller in the backend reads\n * every event counted under the name, resolves the person, and uploads it to\n * the platform within about five minutes. What happened to each upload is read\n * back beside the send, on the same screen it was configured on.\n */\n\nimport { propertyKeyProblem } from \"../event-sources/fields\";\nimport { renderTemplate, templateMentions } from \"../event-sources/template\";\nimport { parseEventKey } from \"./eventKey\";\n\n/**\n * The platforms a conversion can be sent to. Each id is the tag type on\n * Tracking whose credential does the sending, so the platform IS the tag's\n * type — one vocabulary, and the tag's own mark beside it everywhere.\n *\n * Mirrored by `SEND_PLATFORMS` in `packages/backend/convex/lib/validators.ts`,\n * held in step by `../funnel/vocabulary.parity.test.ts`.\n */\nexport const SEND_PLATFORMS = [\n \"meta\",\n \"chatgptAds\",\n \"googleAds\",\n \"linkedinInsightTag\",\n \"twitterAds\",\n \"googleAnalytics\",\n] as const;\nexport type SendPlatform = (typeof SEND_PLATFORMS)[number];\n\nexport function isSendPlatform(value: string): value is SendPlatform {\n return (SEND_PLATFORMS as readonly string[]).includes(value);\n}\n\nexport interface SendPlatformSpec {\n /** The platform's name, as the product says it. */\n title: string;\n /** What `event` names on this platform, in one line. */\n eventMeans: string;\n /** Whether `event` is chosen from the platform's own list, or is an id the platform issued. */\n eventKind: \"name\" | \"id\";\n /** The tag config fields that have to be filled for the tag to send from the server. */\n credentialFields: readonly string[];\n /** What to do on Tracking when no tag qualifies. */\n setupHint: string;\n}\n\n/**\n * The per-platform facts, from the senders in `packages/backend/convex/sideEffects/**`.\n *\n * `credentialFields` are the fields those senders read before anything else —\n * a Meta send with no token, a LinkedIn, Google Ads or X send\n * with no connected account, a GA4 send with no API secret, all stop before\n * the request is built.\n */\nexport const SEND_PLATFORM_SPECS: Readonly<Record<SendPlatform, SendPlatformSpec>> = {\n meta: {\n title: \"Meta\",\n eventMeans: \"A Meta event name — Lead, Purchase, Schedule, or one of your own\",\n eventKind: \"name\",\n credentialFields: [\"accessToken\"],\n setupHint: \"Add the Conversions API access token to the Meta pixel in Tracking\",\n },\n chatgptAds: {\n title: \"ChatGPT Ads\",\n eventMeans: \"A ChatGPT Ads event — lead_created, order_created, or a custom name\",\n eventKind: \"name\",\n credentialFields: [\"apiKey\"],\n setupHint: \"Add the Conversions API key to the ChatGPT Ads pixel in Tracking\",\n },\n googleAds: {\n title: \"Google Ads\",\n eventMeans: \"One of the account's conversion actions, picked from its list\",\n eventKind: \"id\",\n credentialFields: [\"oauthProviderId\"],\n setupHint: \"Connect the Google Ads conversion tag to a Google Ads account in Tracking\",\n },\n linkedinInsightTag: {\n title: \"LinkedIn\",\n eventMeans: \"The id of a conversion rule in LinkedIn Campaign Manager\",\n eventKind: \"id\",\n credentialFields: [\"oauthProviderId\"],\n setupHint: \"Connect the LinkedIn Insight Tag to a LinkedIn account in Tracking\",\n },\n twitterAds: {\n title: \"X\",\n eventMeans: \"The event tag id from X Events Manager, like tw-oka17-abc12\",\n eventKind: \"id\",\n credentialFields: [\"oauthProviderId\"],\n setupHint: \"Connect the X pixel to an X Ads account in Tracking\",\n },\n googleAnalytics: {\n title: \"Google Analytics\",\n eventMeans: \"A GA4 event name — generate_lead, purchase, or one of your own\",\n eventKind: \"name\",\n credentialFields: [\"apiSecret\"],\n setupHint: \"Add the Measurement Protocol API secret to the Google Analytics tag in Tracking\",\n },\n};\n\n/**\n * Whether a tag on Tracking can send this platform's events from the server:\n * it is the platform's own tag type and every credential field is filled.\n *\n * `secretsSet` names credential fields held but not readable — a redacted tag\n * view carries the NAMES of its secrets and never their values, and a Google\n * Ads or LinkedIn connection IS a secret field. Without it, every redacted\n * view of a perfectly configured tag reads as unable to send: that is how a\n * connection captured in a chat stayed invisible to the send it was captured\n * for, leaving the agent unable to stage the send and unable to publish the\n * tag without ending the chat.\n */\nexport function tagSendsServerSide(\n platform: SendPlatform,\n config: Record<string, unknown>,\n secretsSet: readonly string[] = [],\n): boolean {\n return SEND_PLATFORM_SPECS[platform].credentialFields.every((field) => {\n const value = config[field];\n return (typeof value === \"string\" && value.trim() !== \"\") || secretsSet.includes(field);\n });\n}\n\n/**\n * Where the events a send uploads come from: the API and the integrations\n * (`server` — anything posted to Baker or read by it, the store's `ingest`\n * rows), Baker's pixel on the company's own website (`website`), or both\n * (`any`).\n *\n * `any` is what a send is set up as now: one event has one set of\n * destinations, whichever door it arrives by. A company that reports a\n * `lead` from the page AND from its server is reporting one lead twice, and\n * both rows carry the same `event_uid` when both pass the same `eventId`\n * (`PIXEL_DEDUPE_SNIPPET`) — so one send uploads it once: the claim key is\n * the send and the event id, and the platform's own event id is the same\n * `event_uid` either way. Two sends, one per door, uploaded it twice under\n * two claims and left the dedup to the platform.\n *\n * `server` and `website` are what sends were stored as before, and still mean\n * exactly that door. Absent on a stored send means `server`, the only door\n * sends had before the pixel.\n *\n * Never a page Baker publishes: what happens there reaches the platforms\n * through the Form's own side effects.\n */\nexport const SEND_ORIGINS = [\"server\", \"website\", \"any\"] as const;\nexport type SendOrigin = (typeof SEND_ORIGINS)[number];\n\n/** The two doors a stored event row can have arrived by. */\nexport type SendRowOrigin = Exclude<SendOrigin, \"any\">;\n\n/** Which door a send uploads from, reading an absent one as the API's. */\nexport function sendOrigin(send: Pick<ConversionSend, \"origin\">): SendOrigin {\n return send.origin ?? \"server\";\n}\n\n/** Whether a send uploads an event that arrived through this door. */\nexport function sendUploadsFrom(send: Pick<ConversionSend, \"origin\">, door: SendRowOrigin): boolean {\n const origin = sendOrigin(send);\n return origin === \"any\" || origin === door;\n}\n\n/** How long a send's id may be on the wire. */\nexport const MAX_SEND_ID = 64;\n\n/** How long an event key may be on the wire. */\nexport const MAX_SEND_EVENT_KEY = 320;\n\n/**\n * The event a send is on, in words: the name the system gave it — what\n * `page:deal_won` is called on Sources and on Events. A key of another family\n * shows itself, which reads as wrong on purpose: no system raises one.\n */\nexport function describeSendEvent(eventKey: string): string {\n const parsed = parseEventKey(eventKey);\n return parsed?.family === \"page\" ? parsed.eventName : eventKey;\n}\n\n/**\n * One place a system's event is sent.\n *\n * Two choices and nothing else: the tag that sends, and what the platform\n * calls the event. Everything the send carries — who the person is, the click\n * that brought them, the amount and currency, when and where it happened — is\n * the event's own and is forwarded the same way every time; see\n * `sendPayload.ts` for the list.\n */\nexport interface ConversionSend {\n /** Stable within the company, so a review and an outcome can point at one row. `s1`, `s2` — something a person can type. */\n id: string;\n /** The event it sends, by key: `page:<name>`, as a Source, the API or the pixel raises it. */\n eventKey: string;\n /** Which door's events it uploads — see {@link SEND_ORIGINS}. Absent is `server`. */\n origin?: SendOrigin;\n platform: SendPlatform;\n /** The tag on Tracking that sends it. Must hold the platform's server credential. */\n tagId: string;\n /**\n * What the platform calls the event: a name, or an id it issued — see\n * `SEND_PLATFORM_SPECS[platform].eventMeans`.\n *\n * On a platform that takes a **name** (Meta, Google Analytics) this may be\n * a template over the event, exactly like a parameter: `{{properties.plan}}`,\n * or `Purchase · {{properties.tier}}`. One HubSpot event whose records carry\n * a plan then reaches Meta under the plan's own name, instead of needing one\n * source, one send and one conversion action per plan. An **id** is issued\n * by the platform and cannot be written from a record, so a template there\n * is refused rather than uploaded as a literal `{{…}}`.\n */\n event: string;\n /** The ad account the event is filed under, where the platform needs one named (LinkedIn's conversion rules belong to one). */\n account?: string;\n /**\n * Extra parameters the platform is sent with every upload, beyond who, the\n * click and the amount: platform parameter name → a template over the\n * event (`sendPayload.ts` `SEND_TEMPLATE_FIELDS`, plus `{{properties.<key>}}`\n * for the event's own properties). Where they land is the platform's own\n * — Meta's `custom_data`, a GA4 event parameter, a Google Ads custom\n * variable — see {@link SEND_PARAMETERS}.\n */\n parameters?: Record<string, string>;\n}\n\n/** What one platform does with extra parameters, and what it calls them. */\nexport interface SendParameterSpec {\n /** Whether the platform's server API takes extra parameters at all. */\n takes: boolean;\n /** Where they land, in the platform's words. Empty when it takes none. */\n where: string;\n /** Why the platform takes none. Empty when it does. */\n refusal: string;\n /** The names the platform already knows. Anything else is the company's own, unless `onlyKnown`. */\n known: readonly { key: string; label: string }[];\n /** Whether an unknown name is refused — X's conversions take a closed set. */\n onlyKnown: boolean;\n /** What a name may look like, when the platform is stricter than the store's own rule. */\n namePattern?: RegExp;\n nameHint?: string;\n /** How many one send may carry. */\n max: number;\n}\n\n/**\n * The per-platform facts about extra parameters, from the senders in\n * `packages/backend/convex/sideEffects/**` and the platforms' own documents.\n */\nexport const SEND_PARAMETERS: Readonly<Record<SendPlatform, SendParameterSpec>> = {\n meta: {\n takes: true,\n where: \"custom_data on the Meta event, beside value and currency\",\n refusal: \"\",\n known: [\n { key: \"content_name\", label: \"Content name\" },\n { key: \"content_category\", label: \"Content category\" },\n { key: \"content_ids\", label: \"Content ids\" },\n { key: \"content_type\", label: \"Content type\" },\n { key: \"order_id\", label: \"Order id\" },\n { key: \"predicted_ltv\", label: \"Predicted lifetime value\" },\n { key: \"num_items\", label: \"Number of items\" },\n { key: \"search_string\", label: \"Search string\" },\n { key: \"status\", label: \"Status\" },\n { key: \"delivery_category\", label: \"Delivery category\" },\n ],\n onlyKnown: false,\n max: 30,\n },\n chatgptAds: {\n takes: false,\n where: \"\",\n refusal: \"ChatGPT Ads receives the event, person, click and amount from the source event.\",\n known: [],\n onlyKnown: false,\n max: 0,\n },\n googleAds: {\n takes: true,\n where: \"custom variables on the conversion — each name must exist as a custom variable in the Google Ads account\",\n refusal: \"\",\n known: [],\n onlyKnown: false,\n max: 20,\n },\n linkedinInsightTag: {\n takes: false,\n where: \"\",\n refusal: \"LinkedIn's Conversions API takes who, the click, the amount and the currency, and nothing else.\",\n known: [],\n onlyKnown: true,\n max: 0,\n },\n twitterAds: {\n takes: true,\n where: \"the conversion's contents and description\",\n refusal: \"\",\n known: [\n { key: \"content_id\", label: \"Content id\" },\n { key: \"content_name\", label: \"Content name\" },\n { key: \"content_type\", label: \"Content type\" },\n { key: \"content_price\", label: \"Content price\" },\n { key: \"num_items\", label: \"Number of items\" },\n { key: \"content_group_id\", label: \"Content group id\" },\n { key: \"description\", label: \"Description\" },\n ],\n onlyKnown: true,\n max: 7,\n },\n googleAnalytics: {\n takes: true,\n where: \"event parameters on the GA4 event, beside value and currency\",\n refusal: \"\",\n known: [\n { key: \"item_name\", label: \"Item name\" },\n { key: \"item_category\", label: \"Item category\" },\n { key: \"method\", label: \"Method\" },\n { key: \"content_type\", label: \"Content type\" },\n { key: \"coupon\", label: \"Coupon\" },\n { key: \"search_term\", label: \"Search term\" },\n ],\n onlyKnown: false,\n namePattern: /^[A-Za-z][A-Za-z0-9_]{0,39}$/,\n nameHint: \"letters, digits and underscore, starting with a letter, at most 40 characters\",\n max: 25,\n },\n};\n\n/**\n * Whether what the platform is called the event by is written from the event\n * rather than typed: it carries at least one `{{…}}`.\n */\nexport function sendEventIsTemplated(event: string): boolean {\n return templateMentions(event).length > 0;\n}\n\n/**\n * Why this platform cannot be told its event that way, or null.\n *\n * Only the platforms that take a name of your own can take a template. Google\n * Ads, LinkedIn and X each identify a conversion by an id **they** issued —\n * there is no id for a value a record happens to hold, so a template there\n * would upload against a conversion action that does not exist, which every\n * one of those APIs answers with a generic \"not found\".\n */\nexport function sendEventProblem(platform: SendPlatform, event: string): string | null {\n if (!isSendPlatform(platform)) return null;\n if (!sendEventIsTemplated(event)) return null;\n const spec = SEND_PLATFORM_SPECS[platform];\n if (spec.eventKind === \"name\") return null;\n return `${spec.title} identifies a conversion by an id it issued, so it cannot be written from the event. Paste the id; pass what varies as an extra parameter instead.`;\n}\n\n/** The parameter names a platform sets itself; a send naming one would fight the sender. */\nconst PARAMETERS_SET_BY_BAKER: readonly string[] = [\n \"value\",\n \"currency\",\n \"transaction_id\",\n \"session_id\",\n \"engagement_time_msec\",\n];\n\n/**\n * The parameters of one send, trimmed: blank names and blank templates are\n * dropped rather than stored, so an editor row left empty is not a parameter.\n */\nexport function cleanParameters(parameters: Readonly<Record<string, string>> | undefined): Record<string, string> {\n const cleaned: Record<string, string> = {};\n for (const [key, template] of Object.entries(parameters ?? {})) {\n const name = key.trim();\n const value = template.trim();\n if (name !== \"\" && value !== \"\") cleaned[name] = value;\n }\n return cleaned;\n}\n\n/** Why one parameter name cannot be sent to a platform, or null when it can. */\nexport function parameterNameProblem(platform: SendPlatform, name: string): string | null {\n const spec = SEND_PARAMETERS[platform];\n const title = SEND_PLATFORM_SPECS[platform].title;\n if (!spec.takes) return spec.refusal;\n const problem = propertyKeyProblem(name);\n if (problem !== null) return problem;\n if (PARAMETERS_SET_BY_BAKER.includes(name))\n return `\"${name}\" is sent by Baker itself, from the event's amount and id.`;\n if (spec.onlyKnown && !spec.known.some((known) => known.key === name)) {\n return `${title} takes only ${spec.known.map((known) => known.key).join(\", \")} — not \"${name}\".`;\n }\n if (spec.namePattern !== undefined && !spec.namePattern.test(name)) {\n return `${title} names a parameter with ${spec.nameHint}; \"${name}\" is not one.`;\n }\n return null;\n}\n\nexport const SEND_PROBLEM_CODES = [\n \"unknown_platform\",\n \"duplicate_id\",\n \"missing_event_key\",\n \"not_a_system_event\",\n \"missing_tag\",\n \"missing_event\",\n \"bad_parameter\",\n \"too_many_parameters\",\n \"event_not_templatable\",\n] as const;\nexport type SendProblemCode = (typeof SEND_PROBLEM_CODES)[number];\n\nexport interface SendProblem {\n code: SendProblemCode;\n sendId: string;\n message: string;\n}\n\n/**\n * What is wrong with a list of sends on their own terms.\n *\n * Whether a system of the company raises the event, whether the tag exists,\n * belongs to this company and holds the credential — those are checked where\n * Sources and tags can be read, in the backend door, not here.\n */\nexport function sendProblems(sends: readonly ConversionSend[]): SendProblem[] {\n const problems: SendProblem[] = [];\n const ids = new Set<string>();\n\n for (const send of sends) {\n if (ids.has(send.id)) {\n problems.push({ code: \"duplicate_id\", sendId: send.id, message: \"Two sends share one id\" });\n }\n ids.add(send.id);\n\n if (!isSendPlatform(send.platform)) {\n problems.push({\n code: \"unknown_platform\",\n sendId: send.id,\n message: `\"${send.platform}\" is not somewhere a conversion can be sent — one of ${SEND_PLATFORMS.join(\", \")}`,\n });\n continue;\n }\n\n problems.push(...eventKeyProblems(send), ...destinationProblems(send), ...parameterProblems(send));\n }\n\n return problems;\n}\n\n/** Whether a system of this company could raise what the send is on. */\nfunction eventKeyProblems(send: ConversionSend): SendProblem[] {\n if (send.eventKey.trim() === \"\") {\n return [{ code: \"missing_event_key\", sendId: send.id, message: \"Say which event this sends, by its key\" }];\n }\n // Only a named event can come from a system. A Form's step, a landing view,\n // a click away — those happen in a browser, where the page's own pixels\n // already report them.\n if (parseEventKey(send.eventKey)?.family === \"page\") return [];\n return [\n {\n code: \"not_a_system_event\",\n sendId: send.id,\n message: `\"${send.eventKey}\" is not an event a system sends. A send is for a named event a Source or your server raises (page:<name>); what happens in a Form or on a page reaches the platform through the Form's own side effects`,\n },\n ];\n}\n\n/** What is missing on the platform's side: the tag that sends, and what it calls the event. */\nfunction destinationProblems(send: ConversionSend): SendProblem[] {\n const platform = SEND_PLATFORM_SPECS[send.platform];\n const problems: SendProblem[] = [];\n if (send.tagId.trim() === \"\") {\n problems.push({\n code: \"missing_tag\",\n sendId: send.id,\n message: `Say which ${platform.title} tag on Tracking sends it`,\n });\n }\n if (send.event.trim() === \"\") {\n problems.push({\n code: \"missing_event\",\n sendId: send.id,\n message: `${platform.title} needs the event said: ${platform.eventMeans.charAt(0).toLowerCase()}${platform.eventMeans.slice(1)}`,\n });\n return problems;\n }\n const templated = sendEventProblem(send.platform, send.event);\n if (templated !== null) problems.push({ code: \"event_not_templatable\", sendId: send.id, message: templated });\n return problems;\n}\n\n/** What is wrong with a send's extra parameters, on the platform's terms. */\nfunction parameterProblems(send: ConversionSend): SendProblem[] {\n const parameters = cleanParameters(send.parameters);\n const names = Object.keys(parameters);\n const problems: SendProblem[] = [];\n const spec = SEND_PARAMETERS[send.platform];\n if (spec.takes && names.length > spec.max) {\n problems.push({\n code: \"too_many_parameters\",\n sendId: send.id,\n message: `${SEND_PLATFORM_SPECS[send.platform].title} takes at most ${spec.max} extra parameters; this send names ${names.length}.`,\n });\n }\n for (const name of names) {\n const problem = parameterNameProblem(send.platform, name);\n if (problem !== null) problems.push({ code: \"bad_parameter\", sendId: send.id, message: problem });\n }\n return problems;\n}\n\n/**\n * A send in one line, for a chip, a review and the CLI alike: the platform\n * and the event it sends as, when it has one.\n */\nexport function describeSend(send: Pick<ConversionSend, \"platform\" | \"event\">): string {\n const title = isSendPlatform(send.platform) ? SEND_PLATFORM_SPECS[send.platform].title : send.platform;\n return send.event === \"\" ? title : `${title} · ${send.event}`;\n}\n\n/**\n * What the platform is told the event is called, for one event: the name as\n * typed, or the template filled in from the event's own fields.\n *\n * Null when a template reads nothing on this event for **any** of its\n * mentions. An empty event name is not a name, and Meta takes it as a\n * *different* event rather than refusing it; `Purchase · {{properties.tier}}`\n * on an event with no tier would be \"Purchase ·\", which is the same phantom\n * event with text in front. So the upload is held back and the reason\n * recorded instead.\n *\n * Here rather than in the backend's body builders because both the builder\n * and the CLI's preview have to agree on it, and because it is a pure string\n * function with no Convex in it.\n */\nexport function resolveSendEventName(\n send: Pick<ConversionSend, \"platform\" | \"event\">,\n value: (path: string) => string | undefined,\n): string | null {\n const event = send.event.trim();\n if (!isSendPlatform(send.platform) || SEND_PLATFORM_SPECS[send.platform].eventKind === \"id\") {\n return event === \"\" ? null : event;\n }\n if (!sendEventIsTemplated(event)) return event === \"\" ? null : event;\n if (templateMentions(event).some((path) => (value(path) ?? \"\").trim() === \"\")) return null;\n const rendered = renderTemplate(event, value);\n return rendered === undefined ? null : rendered;\n}\n\n/**\n * What happened to a send's uploads over a window, read back from the\n * side-effect event log. `pending` is dispatched and not yet settled — the\n * difference between \"wait\" and \"act\".\n */\nexport interface SendOutcome {\n sendId: string;\n dispatched: number;\n succeeded: number;\n failed: number;\n pending: number;\n /** The most recent failure, in the platform's words already stripped of Baker's wrapper. Empty when clean. */\n lastError: string;\n /** ISO instant of the most recent upload. Empty when nothing was ever sent. */\n lastAt: string;\n /**\n * Events not uploaded because they carried nothing the platform can match a\n * person by (`sendMatch`). Absent on a mirror written before skips were recorded.\n */\n skipped?: number;\n /** Why the latest one was skipped, in plain words. */\n lastSkipReason?: string;\n}\n\n/** An outcome in one short line, for a chip. */\nexport function describeOutcome(outcome: SendOutcome | undefined): string {\n const skipped = outcome?.skipped ?? 0;\n if (outcome === undefined || (outcome.dispatched === 0 && skipped === 0)) return \"Nothing sent yet\";\n if (outcome.dispatched === 0) return `${skipped} skipped: not enough to match`;\n const parts = [`${outcome.succeeded} sent`];\n if (outcome.failed > 0) parts.push(`${outcome.failed} failed`);\n if (outcome.pending > 0) parts.push(`${outcome.pending} on the way`);\n if (skipped > 0) parts.push(`${skipped} skipped`);\n return parts.join(\" · \");\n}\n","/**\n * The request and response `baker analytics sends` and its Convex route both\n * speak — and the shape the dashboard's Sources page writes through its own\n * door, so one send is one row whoever set it.\n *\n * `set` names the sends to add or change and `remove` names the ids to drop;\n * neither is the whole list. Handing the whole list to a writer means a slow\n * read followed by a save erases everything saved in between, which is the\n * failure the ad-parameter mapping had to be rewritten to avoid.\n */\n\nimport { z } from \"zod\";\nimport { MAX_SEND_EVENT_KEY, MAX_SEND_ID, SEND_ORIGINS, SEND_PLATFORMS } from \"./sends\";\n\nexport const conversionSendSchema = z.object({\n /** Stable within the company. `s1`, `s2` — something a person can type. */\n id: z.string().min(1).max(MAX_SEND_ID),\n /** The event it sends, by key — `page:<name>`, from `events[]` of a plain read. */\n eventKey: z.string().min(1).max(MAX_SEND_EVENT_KEY),\n /** `website` for an event Baker's pixel raised on the company's own site; absent (or `server`) for the API and integrations. */\n origin: z.enum(SEND_ORIGINS).optional(),\n platform: z.enum(SEND_PLATFORMS),\n /** The tag's id on Tracking. Must be one of this company's tags of the platform's type, with its server credential set. */\n tagId: z.string().min(1).max(120),\n /** A Meta or GA4 event name; a Google Ads conversion action id; a LinkedIn conversion rule id; an X event tag id. */\n event: z.string().min(1).max(255),\n /** The LinkedIn ad account the conversion rule belongs to. */\n account: z.string().max(120).optional(),\n /** Extra platform parameters: name → template over the event. See `SEND_PARAMETERS[platform]`. */\n parameters: z.record(z.string().min(1).max(64), z.string().min(1).max(500)).optional(),\n});\nexport type ConversionSendWire = z.infer<typeof conversionSendSchema>;\n\n/** One upload of one send: which event, when, and what the platform said. */\nexport const sendUploadSchema = z.object({\n sendId: z.string(),\n eventUid: z.string(),\n /** The event's own name, as it was counted. Empty for a Form's submit, which has none. */\n eventName: z.string(),\n /** The event's key, as `conversions` spells it — what names a Form's submit. */\n eventKey: z.string(),\n /** The Form it happened in, for a `form:` or `submit:` key. */\n flowSlug: z.string(),\n /** ISO instant of the event itself. */\n eventAt: z.string(),\n /** ISO instant of the upload. */\n dispatchedAt: z.string(),\n /** `skipped`: never uploaded, because the event carried nothing the platform can match a person by. */\n outcome: z.enum([\"success\", \"failed\", \"pending\", \"skipped\"]),\n /** The platform's refusal in its own words, or why it was skipped. Empty otherwise. */\n error: z.string(),\n sessionId: z.string(),\n anonId: z.string(),\n});\nexport type SendUpload = z.infer<typeof sendUploadSchema>;\n\n/** How many sends one request may carry. Far above what any company needs; catches a loop. */\nconst MAX_SENDS_PER_REQUEST = 40;\n\nexport const sendsRequestSchema = z.object({\n set: z.array(conversionSendSchema).max(MAX_SENDS_PER_REQUEST).optional(),\n remove: z.array(z.string().min(1).max(MAX_SEND_ID)).max(MAX_SENDS_PER_REQUEST).optional(),\n /** How many days the outcomes beside each send cover. Default 30. */\n days: z.number().int().min(1).max(400).optional(),\n /** List one send's uploads over the window, newest first, by the send's id. */\n uploads: z.string().min(1).max(MAX_SEND_ID).optional(),\n /** With `uploads`: only the ones the platform refused. */\n failedOnly: z.boolean().optional(),\n /** With `uploads`: only the events skipped, with what each was missing. */\n skippedOnly: z.boolean().optional(),\n});\nexport type SendsRequest = z.infer<typeof sendsRequestSchema>;\n\nexport const sendOutcomeSchema = z.object({\n sendId: z.string(),\n dispatched: z.number(),\n succeeded: z.number(),\n failed: z.number(),\n pending: z.number(),\n lastError: z.string(),\n lastAt: z.string(),\n /** Events not uploaded: they carried nothing this platform can match a person by. */\n skipped: z.number().optional(),\n lastSkipReason: z.string().optional(),\n});\n\n/**\n * What comes back: the sends in effect, with what each did; the sends this\n * chat has staged on top of them, when any; and which tags can send.\n */\nexport const sendsResponseSchema = z.object({\n ok: z.literal(true),\n data: z.object({\n /** The company's sends, as they are live. */\n sends: z.array(conversionSendSchema.extend({ outcome: sendOutcomeSchema.optional() })),\n /** The ops this chat has staged and not yet published. Absent outside a chat. */\n staged: z\n .object({\n set: z.array(conversionSendSchema),\n remove: z.array(z.string()),\n })\n .optional(),\n /** The platforms, what `event` means on each, what a tag needs on Tracking to send, and the tags that can. */\n platforms: z.array(\n z.object({\n platform: z.string(),\n title: z.string(),\n eventMeans: z.string(),\n setupHint: z.string(),\n tags: z.array(z.object({ tagId: z.string(), label: z.string() })),\n /**\n * The conversions the platform already holds, by the id a send's `event`\n * takes and the name the person gave them. Google Ads only: its `event`\n * is an id Google issued, and an id the account does not hold is\n * accepted and files against nothing. `label` is the conversion label\n * the account's tag setup shows (`AW-…/<label>`) — how the person knows it.\n */\n conversionActions: z\n .array(\n z.object({ id: z.string(), name: z.string(), primaryForGoal: z.boolean(), label: z.string().optional() }),\n )\n .optional(),\n }),\n ),\n /** Every field a send forwards. Nothing to map. */\n carries: z.array(z.object({ name: z.string(), label: z.string(), group: z.string(), hashed: z.boolean() })),\n /**\n * The events this company's systems raise, so a send can be pointed at\n * one: every Source by the key it raises, and every named event the store\n * saw arrive from a system.\n */\n events: z.array(\n z.object({\n eventKey: z.string(),\n /** The event's own name. */\n name: z.string(),\n /** `source` for a Source on Sources, `systems` for a name the API posted, `both` when a page sends it too, `website` for a name Baker's pixel sent — a send on it carries `origin: \"website\"`. */\n origin: z.string(),\n /**\n * The last 30 days of it: how many arrived, and how many each platform\n * could match a person on. The rest would be skipped by a send there.\n */\n match: z.object({ events: z.number(), platforms: z.record(z.string(), z.number()) }).optional(),\n }),\n ),\n /** What each platform does with extra parameters, and the names it knows. */\n parameters: z.array(\n z.object({\n platform: z.string(),\n takes: z.boolean(),\n where: z.string(),\n known: z.array(z.string()),\n max: z.number(),\n }),\n ),\n /** The event fields a parameter template may read, beside `properties.<key>`. */\n templateFields: z.array(z.object({ name: z.string(), label: z.string() })),\n /** One send's uploads, when `uploads` named one. */\n uploads: z.object({ sendId: z.string(), rows: z.array(sendUploadSchema) }).optional(),\n }),\n hints: z.array(z.string()).optional(),\n});\nexport type SendsResponse = z.infer<typeof sendsResponseSchema>;\n","/**\n * Contract for `/api/analytics/draft-op/remove` — `baker analytics unstage`.\n *\n * Takes back Measure changes this chat staged and has not published: a\n * campaign-parameter answer (`mapping`, ref `<platform>/<name>`), a conversion\n * (`conversion`, ref the event key), a send (`send`, ref the send id) or a\n * source (`source`, ref the source id or `src_temp_*`). Never touches anything\n * already live — to change that, stage the change instead.\n */\nimport { z } from \"zod\";\n\nexport const ANALYTICS_UNSTAGE_KINDS = [\"mapping\", \"conversion\", \"send\", \"source\"] as const;\nexport const analyticsUnstageKindSchema = z.enum(ANALYTICS_UNSTAGE_KINDS);\nexport type AnalyticsUnstageKind = z.infer<typeof analyticsUnstageKindSchema>;\n\nexport const analyticsUnstageRequestSchema = z\n .object({\n chatId: z.string().min(1),\n kind: analyticsUnstageKindSchema.optional(),\n ref: z.string().min(1).optional(),\n /** Everything staged — of `kind` when given, of every kind otherwise. */\n all: z.boolean().optional(),\n })\n .refine((body) => (body.all === true ? body.ref === undefined : body.kind !== undefined && body.ref !== undefined), {\n message:\n \"Pass --kind with --ref to take back one staged change, or --all (optionally with --kind) to take back everything staged.\",\n });\nexport type AnalyticsUnstageRequest = z.infer<typeof analyticsUnstageRequestSchema>;\n\nexport const analyticsUnstageResponseSchema = z.object({\n ok: z.literal(true),\n data: z.object({\n /** How many staged changes were taken back, per kind touched. */\n removed: z.partialRecord(analyticsUnstageKindSchema, z.number().int().min(0)),\n }),\n hints: z.array(z.string()).optional(),\n});\nexport type AnalyticsUnstageResponse = z.infer<typeof analyticsUnstageResponseSchema>;\n","import { z } from \"zod\";\n\nexport const questionnaireObservationSchema = z.object({\n attemptId: z.string().min(1).max(100), version: z.string().min(1).max(100),\n stepId: z.string().max(100), sequence: z.number().int().positive(),\n phase: z.enum([\"start\", \"view\", \"complete\", \"skip\", \"finish\"]), timestamp: z.number().finite(),\n}).refine((event) => [\"start\", \"finish\"].includes(event.phase) || event.stepId.length > 0, \"A question event needs its stable step id\");\nexport type QuestionnaireObservation = z.infer<typeof questionnaireObservationSchema>;\n\nexport const questionnaireRequestSchema = z.object({ eventName: z.string().min(1).max(100).default(\"questionnaire_step\"), days: z.number().int().min(1).max(90).default(7), inactivityMinutes: z.number().int().min(5).max(1440).default(30) });\nconst stepSchema = z.object({ version: z.string(), stepId: z.string(), reached: z.number(), completed: z.number(), skipped: z.number(), abandoned: z.number(), pending: z.number(), incomplete: z.number() });\nexport const questionnaireResponseSchema = z.object({ ok: z.literal(true), data: z.object({ steps: z.array(stepSchema), attempts: z.number(), excludedAttempts: z.number(), unmeasuredEvents: z.number(), observationEndsAt: z.string(), inactivityMinutes: z.number() }), hints: z.array(z.string()) });\n\n/** Drop-off is the last unanswered viewed step of a closed/inactive attempt, never a gap between totals. */\nexport function questionnaireDropoff(observations: readonly QuestionnaireObservation[], now: number, inactivityMs: number) {\n const attempts = new Map<string, QuestionnaireObservation[]>();\n for (const event of observations) {\n const key = JSON.stringify([event.attemptId, event.version]);\n attempts.set(key, [...(attempts.get(key) ?? []), event]);\n }\n const rows = new Map<string, z.infer<typeof stepSchema>>();\n let excludedAttempts = 0;\n for (const raw of attempts.values()) {\n const events = [...raw].sort((a, b) => a.sequence - b.sequence);\n if (events[0]?.phase !== \"start\") { excludedAttempts++; continue; }\n const last = events[events.length - 1];\n if (!last) continue;\n const closed = last.phase === \"finish\" || Math.max(...events.map((event) => event.timestamp)) <= now - inactivityMs;\n const viewed = new Set(events.filter((event) => event.phase === \"view\").map((event) => event.stepId));\n const completed = new Set(events.filter((event) => event.phase === \"complete\").map((event) => event.stepId));\n const skipped = new Set(events.filter((event) => event.phase === \"skip\").map((event) => event.stepId));\n const views = events.filter((event) => event.phase === \"view\");\n const lastView = views[views.length - 1]?.stepId;\n for (const stepId of new Set([...viewed, ...skipped])) {\n const key = JSON.stringify([last.version, stepId]);\n const row = rows.get(key) ?? { version: last.version, stepId, reached: 0, completed: 0, skipped: 0, abandoned: 0, pending: 0, incomplete: 0 };\n if (viewed.has(stepId)) {\n row.reached++;\n if (completed.has(stepId)) row.completed++;\n else if (!skipped.has(stepId)) {\n if (stepId !== lastView || last.phase === \"finish\") row.incomplete++;\n else if (closed) row.abandoned++;\n else row.pending++;\n }\n }\n if (skipped.has(stepId)) row.skipped++;\n rows.set(key, row);\n }\n }\n return { steps: [...rows.values()].sort((a, b) => a.version.localeCompare(b.version) || a.stepId.localeCompare(b.stepId)), attempts: attempts.size - excludedAttempts, excludedAttempts };\n}\n","/**\n * What everybody says when the analytics store is at its compute limit.\n *\n * The store bills reads against a rolling per-minute allowance and refuses a\n * query outright once a burst has spent it. That refusal is not a failure of\n * anything: no data is lost, no query was wrong, and the same question answered\n * a moment later returns the same numbers. It is the one store error whose\n * correct response is to wait.\n *\n * Three readers have to agree about it and each used to guess separately — the\n * backend throwing it, the dashboard deciding whether to try again, and the CLI\n * deciding whether an agent should abandon a report or carry on. So the\n * sentence is written once here and recognised by comparing against it, rather\n * than by three regexes over prose that one of them will reword.\n *\n * The words are the marketer's, not the store's. \"vCPU usage limit exceeded\" is\n * the truth and is unreadable; a reader told their query failed goes looking\n * for a problem they do not have.\n */\nexport const ANALYTICS_BUSY_MESSAGE =\n \"Analytics is busy right now. The numbers will be there in a moment — try again shortly.\";\n\n/**\n * Whether a failed read was a refusal to wait out.\n *\n * Substring rather than equality: the message crosses a Convex action boundary\n * on the way to both the dashboard and the CLI, and Convex prefixes its own\n * wrapper onto a thrown message as it goes.\n */\nexport function isAnalyticsBusy(message: string | undefined | null): boolean {\n return typeof message === \"string\" && message.includes(ANALYTICS_BUSY_MESSAGE);\n}\n\n/**\n * What an agent should do about it, in the `error.fix` an agent actually reads.\n *\n * A report is usually one step of a longer job, and abandoning the job over a\n * refusal that clears in seconds is the expensive mistake here — the whole\n * point of saying this rather than returning a bare failure.\n */\nexport const ANALYTICS_BUSY_FIX =\n \"Nothing went wrong and nothing was lost — the analytics store was briefly at capacity. \" +\n \"Wait a few seconds and ask for the same report again. If you were in the middle of a larger \" +\n \"job, carry on with the rest of it and come back to this read; do not abandon the job.\";\n","/**\n * The name two conversions share when they are the same outcome.\n *\n * Baker counts by NAME: two definitions given the same name are one row and one\n * number, which is how \"booked a call\" across three Forms becomes the single\n * figure anybody wants. That makes the name the whole grouping mechanism — and\n * it makes a near-miss the most expensive typo in the feature. \"Booked a call\"\n * and \"Booked a Call\" are two rows, two numbers, and one headline that is quietly\n * split; nothing errors, and both numbers look plausible.\n *\n * So a name is compared the way a person reads it rather than the way a string\n * compares: case, accents, punctuation and a trailing plural are not the\n * difference between two outcomes.\n *\n * Shared rather than CLI-local because both doors write these names — the agent\n * through `baker analytics conversions` and a person through the dashboard's\n * Conversions screen. Today only the CLI refuses a near-miss, and that is where\n * it matters most: the agent is writing into a list it cannot see, while the\n * dashboard shows the two rows one under the other. Keeping the comparison here\n * means the screen can adopt the same rule without inventing a second one that\n * disagrees.\n */\n\n/**\n * A name reduced to what it means, for comparison only. Never displayed: the\n * name a person typed is the name every report shows.\n *\n * The plural rule is per word and deliberately naive — `leads` and `lead`, or\n * `reservas` and `reserva`, are one outcome in every language this product is\n * used in. It over-reaches on a word that genuinely ends in `s` (`proceso` is\n * untouched, `access` becomes `acces`), which costs nothing: both sides of\n * every comparison are reduced the same way.\n */\nexport function normalizeConversionName(name: string): string {\n return name\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \" \")\n .trim()\n .split(\" \")\n .filter((word) => word !== \"\")\n .map((word) => (word.length > 3 && word.endsWith(\"s\") ? word.slice(0, -1) : word))\n .join(\" \");\n}\n\n/**\n * The existing name this one would have been split from, or `null`.\n *\n * `null` for an exact match too: reusing a name on purpose is the whole point\n * of the mechanism, so it is never something to warn about. Only a name that\n * *reads* the same and *stores* differently is a finding.\n */\nexport function findNameCollision(name: string, existing: readonly string[]): string | null {\n const normalized = normalizeConversionName(name);\n return existing.find((candidate) => candidate !== name && normalizeConversionName(candidate) === normalized) ?? null;\n}\n\n/**\n * Where to start when a company counts nothing yet.\n *\n * Not a closed set and not enforced — a company's outcome is whatever its\n * business does, and an enforced vocabulary would make somebody name a\n * WhatsApp click \"Lead\" because the list had no better row. It exists so the\n * first outcome in a company is one of a handful of recognisable words rather\n * than a phrase somebody invented, which is what makes two accounts comparable\n * at all.\n *\n * **Keep the company's language.** Once a company has named one outcome, the\n * rule that matters is reuse: read what it already counts and use that name\n * again. A Spanish account whose outcomes read \"Reserva\" and \"Presupuesto\" is\n * standardised; the same account with \"Reserva\" and \"Booking\" is not.\n */\nexport const STANDARD_CONVERSION_NAMES: readonly { name: string; meaning: string }[] = [\n { name: \"Lead\", meaning: \"Somebody handed over contact details\" },\n { name: \"Booked a call\", meaning: \"A meeting or demo was scheduled\" },\n { name: \"Quote requested\", meaning: \"Somebody asked what it would cost\" },\n { name: \"Purchase\", meaning: \"Money changed hands\" },\n { name: \"Signed up\", meaning: \"An account or trial was created\" },\n { name: \"Subscribed\", meaning: \"Somebody opted in to hear from them again\" },\n { name: \"Downloaded\", meaning: \"A guide, price list or asset was taken\" },\n { name: \"Contacted us\", meaning: \"A call, WhatsApp or email started from the page\" },\n];\n","/**\n * What a delivery's destination is called, wherever it is reported.\n *\n * A `side_effect_type` is an internal slug and it reaches a person on four\n * surfaces: the Events feed, the visit replay, the lead panel, and every\n * `baker analytics` report an agent reads and then repeats to a marketer. Each\n * of those had its own answer, and two of them had no answer at all — so one\n * account read **\"Meta Pixel\"** where its tag is configured, **\"Meta\"** where\n * its uploads are listed, and **`metaCapi`** on the row our own server wrote,\n * one line apart, for the same Meta account.\n *\n * ## The three spellings one destination arrives in\n *\n * 1. **The tag or the Form action** — `meta`, `googleAds`, `httpWebhook`. What\n * the builder configured.\n * 2. **The server-side sender** — `metaCapi`, `ga4Mp`, `googleAdsCapi`,\n * `linkedinCapi`, `twitterAdsCapi`. The *dispatcher's* own name, written\n * when a tag carrying its credential fires from our server rather than from\n * the visitor's browser (`isCapiConfigured`). These names exist nowhere a\n * marketer can see them and nothing resolved them, so the feed printed the\n * slug and drew its \"unknown destination\" glyph — on 34% of one production\n * company's events, and on the two destination types carrying the largest\n * number of silent upload failures on the platform.\n * 3. **A send's upload** — `conversionSend:<platform>`. The platform is the\n * part that matters.\n *\n * All three resolve to one name here, and the server-side senders resolve\n * *through* the tag they belong to rather than to names of their own: that is\n * what makes it impossible for a delivery and the tag that caused it to drift\n * apart. Whether it went from the browser or from our server is not lost by\n * this — it is a different column's job, and the feed has one.\n *\n * ## Why this is in `@baker/api` and not in the dashboard\n *\n * Because the CLI reports the same rows to an agent, and an agent that reads\n * `metaCapi` writes `metaCapi` into a chat message. Every name a person can\n * see has to have exactly one owner, and a table only the dashboard can import\n * is not one.\n *\n * Kept in step with `computeSigForTag` in `convex/tags/utils.ts` — where a tag\n * type becomes a dispatcher name — by `destinations.parity.test.ts`, which\n * reads that function, `DISPATCHERS`, and the Tinybird generator's own copy of\n * the alias table. It said so before it did so: the test only checked that the\n * builder's catalogue was named, so the sixth server-side sender would have\n * been added in one place with everything green.\n */\n\nimport { isSendPlatform, SEND_PLATFORM_SPECS } from \"./sends\";\n\n/** A send's upload is logged as `conversionSend:<platform>`. */\nexport const CONVERSION_SEND_PREFIX = \"conversionSend:\";\n\n/** Whether a destination type is an upload a conversion's send made, rather than a Form's side effect. */\nexport function isConversionSend(type: string): boolean {\n return type.startsWith(CONVERSION_SEND_PREFIX);\n}\n\n/**\n * The tag each server-side sender belongs to.\n *\n * The dispatcher names are the ones `convex/sideEffects/utils.ts` registers in\n * `DISPATCHERS` and `convex/tags/utils.ts` signs with. `posthog` and\n * `datafast` are deliberately absent: their dispatcher name IS their tag name,\n * so they need no alias.\n *\n * Mirrored in `tinybird/definitions.ts` as `SERVER_SIDE_SENDERS`, which is\n * what `sent_to` narrows through — the generator runs in the Tinybird CLI's\n * own runtime and cannot import this. Held by the same test.\n */\nexport const SERVER_SIDE_SENDER_TAG: Readonly<Record<string, string>> = {\n metaCapi: \"meta\",\n chatgptAdsCapi: \"chatgptAds\",\n googleAdsCapi: \"googleAds\",\n linkedinCapi: \"linkedinInsightTag\",\n twitterAdsCapi: \"twitterAds\",\n ga4Mp: \"googleAnalytics\",\n};\n\n/**\n * Every destination Baker delivers to, by the name a person is shown.\n *\n * The five platforms a conversion send can reach are **not** listed here: they\n * are named by {@link SEND_PLATFORM_SPECS}, which is Sources' own vocabulary\n * and the one a marketer has already met on the screen where the send is set\n * up. Listing them twice is how \"Meta\" and \"Meta Pixel\" happened.\n *\n * Everything else keeps the builder's own title, down to the word — \"HubSpot\n * Events\" and \"HubSpot Form\" are two different destinations on the same\n * platform, and shortening both to \"HubSpot\" would make a refusal name\n * something the reader cannot act on. Only the five need shortening, because\n * only they arrive in three spellings and have to read as one account.\n *\n * `destinations.parity.test.ts` fails if the dashboard's builder catalogue\n * grows a destination this does not name, because that is precisely the\n * direction the drift runs: a destination is added where it is configured, and\n * the four places that *report* it find out later or never.\n */\nconst DESTINATION_NAMES: Readonly<Record<string, string>> = {\n email: \"Email\",\n httpWebhook: \"HTTP Webhook\",\n zapier: \"Zapier\",\n tiktok: \"TikTok Pixel\",\n pinterest: \"Pinterest Tag\",\n googleTagManager: \"Google Tag Manager\",\n amplitude: \"Amplitude\",\n hotjar: \"Hotjar\",\n clarity: \"Microsoft Clarity\",\n hubspot: \"HubSpot Events\",\n vwo: \"VWO\",\n posthog: \"PostHog\",\n datafast: \"DataFast\",\n code: \"Custom Code\",\n pipedrive: \"Pipedrive\",\n googleSpreadsheet: \"Google Sheets\",\n hubspotForm: \"HubSpot Form\",\n goHighlevelContact: \"GoHighLevel\",\n crmble: \"Crmble\",\n};\n/**\n * The catalogue key behind a destination type, whichever spelling it arrived in.\n *\n * Exported because the dashboard resolves a *logo* by the same key and must\n * not answer that question a second way — a row reading \"Meta\" under Google's\n * mark is worse than either name alone.\n */\nexport function destinationKey(type: string): string {\n const platform = isConversionSend(type) ? type.slice(CONVERSION_SEND_PREFIX.length) : type;\n return SERVER_SIDE_SENDER_TAG[platform] ?? platform;\n}\n\n/**\n * What to call this destination, or the type itself when we do not know it.\n *\n * The fallback is the raw type on purpose. A destination nobody has named is a\n * gap to fill in {@link DESTINATION_NAMES}, and showing the slug is what makes\n * the gap visible; inventing a title from the slug is how `httpWebhook`\n * becomes \"Http Webhook\" on one screen and \"HTTP Webhook\" on the next.\n */\nexport function destinationName(type: string): string {\n if (type === \"\") return \"\";\n const key = destinationKey(type);\n if (isSendPlatform(key)) return SEND_PLATFORM_SPECS[key].title;\n return DESTINATION_NAMES[key] ?? type;\n}\n","/**\n * What each Form trigger means, said as an outcome rather than as an API event.\n *\n * The ONE answer, shared. It used to live in the dashboard, which was right\n * until a second package had to say the same thing: `experiments/goal.ts`\n * renders a test's goal for the same marketer, on a card that sits beside the\n * Conversions screen, and a private copy there produced a third vocabulary for\n * the same events — \"step reached\" against \"Screen shown\", \"booking made\"\n * against \"Call booked\" — plus a de-camelCase for everything the copy had not\n * thought of. That de-camelCase is exactly what this table was written to\n * replace, so the copy reintroduced the defect it was modelled on.\n *\n * Free of every import, so the Convex runtime, the CLI and the dashboard all\n * read one table.\n */\n\nexport interface TriggerDescription {\n what: string;\n meaning: string;\n /** Fires on its own, without the visitor deciding anything. */\n lifecycle?: true;\n}\n\n/**\n * What each trigger means, said as an outcome rather than as an API event.\n *\n * \"Form submitted\", not `customForm.onFormSubmitted`. A marketer choosing what\n * to count should never have to know an embed's API, which is the reason the\n * previous design's per-trigger checkbox list needed a paragraph of explanation\n * above it.\n *\n * `lifecycle` is the field that earns this table its second column. Four of\n * HubSpot's events are named almost identically and only one of them is an\n * outcome; renaming them more carefully was tried and does not work, because\n * \"Form about to submit\" and \"Form submitted\" are genuinely a hair apart in\n * English and a chasm apart in meaning. The sentence says which is which, and\n * the flag lets a picker put the other three away.\n *\n * Anything absent falls back to the raw trigger id with no sentence. That is\n * deliberate and not a gap: the `iframe.<name>` family is named by whatever a\n * client's embedded page posts, so the raw name IS the best available\n * description of it, and inventing a friendlier one would be inventing a\n * meaning.\n */\nconst TRIGGERS: Readonly<Record<string, TriggerDescription>> = {\n \"calendlyEvent.eventScheduled\": {\n what: \"Call booked\",\n meaning: \"Somebody picked a slot and confirmed it. This is the booking.\",\n },\n \"calendlyEvent.dateAndTimeSelected\": {\n what: \"Time picked\",\n meaning: \"Somebody chose a slot but has not confirmed the booking yet.\",\n },\n \"calendlyEvent.eventTypeViewed\": {\n what: \"Calendar opened\",\n meaning: \"The calendar appeared. Nobody has picked a time yet.\",\n lifecycle: true,\n },\n \"calendlyEvent.profilePageViewed\": {\n what: \"Booking page shown\",\n meaning: \"Calendly's own page appeared. Nobody has picked a time yet.\",\n lifecycle: true,\n },\n \"customForm.onFormSubmitted\": {\n what: \"Form submitted\",\n meaning: \"Somebody filled this step in and sent it.\",\n },\n \"highlevelEvent.appointmentScheduled\": {\n what: \"Appointment booked\",\n meaning: \"Somebody picked a slot and confirmed it. This is the booking.\",\n },\n \"highlevelEvent.calendarLoaded\": {\n what: \"Calendar finished loading\",\n meaning: \"The calendar appeared. Nobody has picked a time yet.\",\n lifecycle: true,\n },\n \"highlevelFormEvent.formSubmitted\": {\n what: \"Form submitted\",\n meaning: \"Somebody filled the form in and sent it.\",\n },\n \"highlevelFormEvent.formLoaded\": {\n what: \"Form finished loading\",\n meaning: \"The form appeared. Nobody has typed anything yet.\",\n lifecycle: true,\n },\n \"hubspotForm.onFormSubmitted\": {\n what: \"Form submitted\",\n meaning: \"Somebody filled the form in and sent it. This is the one that means a lead.\",\n },\n \"hubspotForm.onBeforeFormSubmit\": {\n what: \"Form about to be sent\",\n meaning: \"Fires an instant before the form is sent — not the same as it arriving.\",\n lifecycle: true,\n },\n \"hubspotForm.onFormReady\": {\n what: \"Form finished loading\",\n meaning: \"The form appeared. Nobody has typed anything yet.\",\n lifecycle: true,\n },\n \"hubspotForm.onBeforeFormInit\": {\n what: \"Form starting to load\",\n meaning: \"Fires before the form has even drawn. It only means the page was opened.\",\n lifecycle: true,\n },\n \"hubspotMeeting.onMeetingScheduled\": {\n what: \"Meeting booked\",\n meaning: \"Somebody picked a slot and confirmed it. This is the booking.\",\n },\n \"link.onClick\": {\n what: \"Link clicked\",\n meaning: \"Somebody clicked the link on this step and left for wherever it points.\",\n },\n \"savvycalEvent.scheduled\": {\n what: \"Call booked\",\n meaning: \"Somebody picked a slot and confirmed it. This is the booking.\",\n },\n \"text.onTextDisplayed\": {\n what: \"Screen shown\",\n meaning: \"This screen appeared. On a thank-you screen that is the outcome; elsewhere it is not.\",\n },\n \"text.onButtonClicked\": {\n what: \"Button pressed\",\n meaning: \"Somebody pressed the button on this screen.\",\n },\n};\n\n/**\n * One trigger, described — for the surfaces that hold a trigger id rather than\n * an event key.\n *\n * The replay and the events feed both had their own answer before this: a\n * `triggerLabel` that de-camelCased the raw id, so `hubspotForm.onBeforeFormInit`\n * reached a marketer's screen as **\"Before form init\"** and\n * `text.onTextDisplayed` as **\"Text displayed\"**. Both are engineering internals\n * in the product's voice, and — worse — they were a *second* vocabulary: the\n * Conversions picker called the same event \"Form starting to load\" on the\n * screen next door.\n *\n * So the table is exported and there is one answer. The mechanical fallback\n * stays where it belongs, at the call site, for `iframe.<whatever the embed\n * posts>`: there the raw name really is the best description there is.\n */\nexport function triggerDescription(triggerId: string): TriggerDescription | undefined {\n return TRIGGERS[triggerId];\n}\n","/**\n * The rows the store keeps so a *report* can be computed, which are not events.\n *\n * ## Why this is shared and not a dashboard detail\n *\n * Two readers ask the same question of the same rows. The Events tab shows\n * them to a marketer; `baker analytics feed` hands them to an agent, which\n * reads them and then tells a marketer what happened. Only the first one had\n * this rule, so the feed a person saw and the feed an agent saw were different\n * lists — and the agent's was the noisier one, in a context window where noise\n * is paid for by the token and crowds out the rows it was called to find.\n *\n * Measured on one production account over 25 days: **559 of its 573 trigger\n * rows** were an embedded HubSpot form announcing that it had drawn, against\n * **7** where somebody actually filled one in. An agent asked \"did anything\n * arrive today\" read eighty rows of housekeeping for every real answer.\n *\n * ## What counts as bookkeeping, and why each one\n *\n * None of these is an event somebody sent or did. Each is either a restatement\n * of the row beside it or a fact about the machinery:\n *\n * - `visitor_new` / `session_start` — written in the same millisecond as the\n * page view that carried them, about the same page view.\n * - `identify` — what the submit beside it *revealed*, not a separate act.\n * - `form_step_view` — a Form reporting that it wired itself up. Every Form on\n * a page emits one on load.\n * - `side_effect_settled` — the destination's answer, already folded onto the\n * dispatch row that asked the question (`event_stream` joins it).\n * - a **submit trigger** — `onFormSubmitted` and its siblings fire because the\n * visitor pressed the button, and the step completion beside them fires\n * because they pressed the same button. Two rows, one press.\n * - an **embed lifecycle trigger** — \"Form starting to load\", \"Form finished\n * loading\", \"Calendar opened\". `triggerDescription` has always known which\n * these are, and the Conversions picker has always used that flag to put\n * them away; the two feeds did not.\n *\n * ## Hidden, not dropped — and that is load-bearing\n *\n * Nothing here is unreachable. Both readers say how many rows they are holding\n * back and both can ask for them (`?raw=1`, `--everything`), because the\n * moment somebody is debugging the collector rather than their integration\n * these are the only rows that matter: an embed that draws and never fires\n * again is a real failure, and its lifecycle rows are the only evidence of it.\n */\n\nimport { STEP_SUBMIT_TRIGGERS } from \"./conversions\";\nimport { triggerDescription } from \"./triggers\";\n\n/** Row shape this rule needs. Deliberately narrower than `AnalyticsTimelineRow`, so a caller can pass either spelling. */\nexport interface FeedNoiseRow {\n eventType: string;\n triggerId: string;\n}\n\nconst BOOKKEEPING_TYPES: ReadonlySet<string> = new Set([\n \"visitor_new\",\n \"session_start\",\n \"identify\",\n \"form_step_view\",\n \"side_effect_settled\",\n]);\n\n/** The triggers a visitor raises BY submitting a step, which the completion beside them reports. */\nconst SUBMIT_TRIGGERS: ReadonlySet<string> = new Set(Object.values(STEP_SUBMIT_TRIGGERS));\n\n/**\n * A trigger nobody raised: the embed reporting on itself.\n *\n * Read through {@link triggerDescription} rather than from a list here,\n * because that table already carries the flag and a second list would be a\n * second thing to remember when an embed's vocabulary grows.\n */\nexport function isEmbedLifecycle(row: FeedNoiseRow): boolean {\n return row.eventType === \"form_trigger\" && triggerDescription(row.triggerId)?.lifecycle === true;\n}\n\n/** Whether this row is machinery rather than something somebody sent or did. */\nexport function isBookkeepingRow(row: FeedNoiseRow): boolean {\n if (BOOKKEEPING_TYPES.has(row.eventType)) return true;\n if (isEmbedLifecycle(row)) return true;\n return row.eventType === \"form_trigger\" && SUBMIT_TRIGGERS.has(row.triggerId);\n}\n","/**\n * Every way one event could be matched to a person — the whole ladder, not the\n * top rung.\n *\n * ## The reading this replaces\n *\n * A stored row reports **one** key: `known_by` is the store's answer to \"what\n * is the best thing on this row\", and by construction it cannot say there were\n * four. Every surface read it as if it were the whole truth, so an event\n * carrying an address, a phone number, the CRM's own contact id *and* the\n * Google click that produced it was reported as **\"By email\"**, and a page view\n * carrying two Google click ids was reported as **\"Not identified\"**.\n *\n * Both readings are wrong in the same direction: they say matching is one\n * question with one answer, when it is a ladder walked in order. The email if\n * there is one, the phone if there is not, the contact id, then the click that\n * brought them, then the platform cookie. The count is the fact that matters —\n * *\"there is more than one way we will find this person again\"* — and it is\n * the difference between an event that survives a missing field and one that\n * is lost by it. Measured on one production account: every deal event read\n * \"By email\" and every one of them carried four keys.\n *\n * ## Why it is here rather than in the dashboard\n *\n * Two readers, and the second is the expensive one. The Events tab shows this\n * in a column; `baker analytics feed` hands the same rows to an agent, which\n * reasons about them and then tells a marketer what happened. An agent given\n * one key concludes the event is fragile, or that two rows are two strangers —\n * the same wrong conclusion the column invited, reached somewhere nobody can\n * see it.\n *\n * ## Derived, never restated\n *\n * The list is built from {@link INGEST_CLICK_ID_PARAMS} and\n * {@link MATCH_COOKIES} rather than written out, because this is the fifth\n * copy of that vocabulary in the repo and the other four have already proved\n * that a hand-written one drifts: `vocabulary.parity.test.ts` exists because\n * an omission here is silent in the worst way — the key arrived, we stored it,\n * and every screen reports that we did not have it.\n */\n\nimport { MATCH_COOKIES } from \"../event-ingest/matching\";\nimport { INGEST_CLICK_ID_PARAMS } from \"../event-ingest/vocabulary\";\n\n/**\n * The keys that name a *person* rather than a browser or a click, best first.\n *\n * `baker_id` is Baker's own visitor id as a sender may pass it back, which is\n * why it is a contact key and not a cookie: a sender that has it took it from\n * a page and is telling us which visitor this is.\n */\nconst CONTACT_KEYS = [\"email\", \"phone\", \"external_id\", \"baker_id\"] as const;\n\n/**\n * Every field a row can be matched on, in the order matching walks them.\n *\n * Contact details first, then the ad click that brought them, then the\n * platform cookies — the same precedence `knownBySql` and `personRowKeySql`\n * apply in the store, so the first entry of this list is the key the store\n * would actually have resolved the row by. A summary that led with a different\n * one would describe a resolution that did not happen.\n */\nexport const MATCH_KEY_FIELDS: readonly string[] = [...CONTACT_KEYS, ...INGEST_CLICK_ID_PARAMS, ...MATCH_COOKIES];\n\n/**\n * What each key is called where a person reads it.\n *\n * The click ids are named by their platform and not by their parameter —\n * \"we know them by their Google Ads click\" is an answer and \"we know them by\n * a `gbraid`\" is a support ticket. The parameter survives in the field name\n * beside it, for anyone debugging the payload rather than reading the row.\n *\n * `external_id` and `baker_id` keep their contract spellings, the same\n * decision `USER_DATA_FIELDS` made and for the same reason: these two are\n * field names a sender types into their own integration, and a friendlier\n * label leaves them checking a screen that never mentions what they sent.\n */\nexport const MATCH_KEY_LABELS: Readonly<Record<string, string>> = {\n email: \"email\",\n phone: \"phone\",\n external_id: \"external ID\",\n baker_id: \"Baker ID\",\n gclid: \"Google click\",\n wbraid: \"Google click (wbraid)\",\n gbraid: \"Google click (gbraid)\",\n dclid: \"Google Display click\",\n fbclid: \"Meta click\",\n ttclid: \"TikTok click\",\n twclid: \"X click\",\n li_fat_id: \"LinkedIn click\",\n msclkid: \"Microsoft click\",\n rdt_cid: \"Reddit click\",\n epik: \"Pinterest click\",\n sccid: \"Snapchat click\",\n oppref: \"ChatGPT Ads click\",\n fbp: \"Meta browser cookie\",\n fbc: \"Meta click cookie\",\n};\n\n/**\n * One key a row carries: the field it arrived under, and what to call it.\n *\n * `RowMatchKey` rather than `MatchKey`, which is taken and means something\n * narrower: {@link MATCH_KEYS} in `sendMatch.ts` is the subset an *ad\n * platform* will accept, and this is every key *Baker* can recognise a row by.\n * The two overlap and must never disagree about a spelling, which\n * `matchKeys.parity.test.ts` holds.\n */\nexport interface RowMatchKey {\n field: string;\n label: string;\n}\n\n/**\n * The three spellings one key arrives in, all of which mean \"present\".\n *\n * A `user_data` map carries a field in the clear, as `<field>_sha256` when it\n * is held as a digest, or as `<field>_preview` when a masked copy was kept for\n * a person to recognise. All three say the key was there; only the first says\n * what it was. Reading just the plain name was how a row holding five digests\n * reported that it held nothing.\n */\nfunction carries(userData: Readonly<Record<string, string>>, field: string): boolean {\n for (const key of [field, `${field}_sha256`, `${field}_preview`]) {\n const value = userData[key];\n if (typeof value === \"string\" && value !== \"\") return true;\n }\n return false;\n}\n\n/**\n * Every key this row could be matched on, in precedence order.\n *\n * Read off the row's own `user_data` — which the store builds by merging\n * `match_keys` with the click-id columns (`userDataSql`) — rather than off\n * `known_by`, which holds one.\n */\nexport function rowMatchKeys(userData: Readonly<Record<string, string>> | undefined): RowMatchKey[] {\n if (userData === undefined) return [];\n return MATCH_KEY_FIELDS.filter((field) => carries(userData, field)).map((field) => ({\n field,\n label: MATCH_KEY_LABELS[field] ?? field,\n }));\n}\n\n/**\n * The keys as one line: the best one, and how many more there are.\n *\n * The first key and a count, never the whole list. A row with an address, a\n * phone and three click ids is one line of a table, and spelling it out pushes\n * the event's own name off the screen on the surface that exists to show it.\n * The count carries the meaning on its own, and the list is one hover away.\n */\nexport function rowMatchSummary(keys: readonly RowMatchKey[], userData?: Readonly<Record<string, string>>): string {\n const [first] = keys;\n if (first === undefined) return \"\";\n const more = keys.length === 1 ? \"\" : ` +${keys.length - 1}`;\n const shown = userData === undefined ? undefined : matchKeyPreview(userData, first.field);\n return shown === undefined ? `By ${first.label}${more}` : `${shown}${more}`;\n}\n\n/**\n * The best key as something a person can recognise: the masked copy the store\n * keeps beside a digest (`m***@icloud.com`), or the value itself for an id\n * the sender posted in the clear. Nothing for a digest with no masked copy,\n * and nothing for a click id or a platform cookie — sixty characters of\n * `gclid` name nobody.\n */\nexport function matchKeyPreview(userData: Readonly<Record<string, string>>, field: string): string | undefined {\n const preview = userData[`${field}_preview`];\n if (typeof preview === \"string\" && preview !== \"\") return preview;\n if (field !== \"external_id\" && field !== \"baker_id\") return undefined;\n const plain = userData[field];\n return typeof plain === \"string\" && plain !== \"\" ? plain : undefined;\n}\n","/**\n * What a campaign URL already says it carries, read back as ad dimensions.\n *\n * A tracking template is the client's own answer to \"what do you want to know\n * about a click\", written in the ad platform's placeholder vocabulary:\n * `?kw={keyword}&mt={matchtype}` says the URLs carry a keyword under `kw` and a\n * match type under `mt`. Baker cannot read either until it is told, and until\n * it is told the values are not stored at all — only the fact that the name\n * appeared.\n *\n * So the answer is already written down, in a place Baker can read, and the\n * step that gets missed is copying it across. This turns the template into the\n * `baker analytics map` call that would make it readable.\n *\n * It proposes nothing about the ad account itself. Every role here is derived\n * from a placeholder the account is *already* sending, which is the difference\n * between naming what arrives and telling a client to retag.\n */\nimport type { AdParamRole, AdPlatform } from \"./adParams\";\nimport { AD_PLATFORM_DEFINITIONS, builtinAdParamMapping, RESERVED_PARAM_NAMES } from \"./adParams\";\n\n/**\n * A placeholder, reduced to the part that identifies it.\n *\n * The platforms delimit their macros three different ways — `{keyword}`,\n * `{{ad.name}}`, `__CID__` — and two of them disagree with themselves about\n * case (`{{adSet.id}}` resolves, `{{adset.id}}` does not). Comparing the raw\n * spelling would therefore need a per-platform parser to say that a template is\n * carrying the macro the platform documents. Stripping the delimiters and the\n * case leaves exactly the identifying part, and it is only ever compared within\n * one platform's own list, so the flattening cannot collide across vocabularies.\n */\nfunction placeholderKey(raw: string): string {\n return raw\n .replace(/[{}]/g, \"\")\n .replace(/^_+|_+$/g, \"\")\n .trim()\n .toLowerCase();\n}\n\n/**\n * Extra Google spellings for placeholders that already have a canonical macro.\n *\n * `AD_PLATFORM_DEFINITIONS` names ONE macro per dimension, because it is shown\n * to a reader as evidence of what the platform can send and a list of four\n * synonyms would be worse evidence, not better. Reading a template is the\n * opposite job: whatever the account actually wrote has to be recognised. Only\n * Google needs this, because only Google has several placeholders resolving to\n * one dimension.\n */\nconst EXTRA_PLACEHOLDER_ROLES: Partial<Record<AdPlatform, Readonly<Record<string, AdParamRole>>>> = {\n google: {\n merchant_id: \"product_id\",\n product_partition_id: \"product_id\",\n },\n};\n\n/**\n * This platform's placeholders, and the dimension each one carries.\n *\n * Derived from the platform's own dimension list rather than kept as a second\n * copy, because the two would drift and the drift is invisible: a macro added\n * to the definitions and not here reads as \"no placeholder explains this\",\n * which is the message that tells somebody not to map their own parameter.\n *\n * A placeholder outside the list is surfaced as unexplained rather than forced\n * into `other`. `{adposition}` and `{loc_physical_ms}` are real Google\n * placeholders with no role in this vocabulary, and a proposal that has to be\n * corrected is worse than one that is not made.\n */\nfunction placeholderRoles(platform: AdPlatform): Readonly<Record<string, AdParamRole>> {\n const roles: Record<string, AdParamRole> = {};\n for (const dimension of AD_PLATFORM_DEFINITIONS[platform].dimensions) {\n roles[placeholderKey(dimension.macro)] = dimension.role;\n }\n return { ...roles, ...(EXTRA_PLACEHOLDER_ROLES[platform] ?? {}) };\n}\n\nexport interface TemplateParam {\n name: string;\n /** The placeholder or literal on the right of the `=`, verbatim. */\n value: string;\n}\n\nexport interface TemplateMappingProposal {\n /** Parameter name → the role its placeholder says it carries. */\n proposed: Record<string, AdParamRole>;\n /**\n * Parameters carrying something no placeholder explains — a literal, or a\n * placeholder outside the vocabulary.\n *\n * Reported rather than guessed at. `agency=acme` is the same shape as\n * `kw={keyword}` and means something entirely different, and only somebody\n * who knows the account can say which of `other` and `ignore` it is.\n */\n unexplained: TemplateParam[];\n}\n\n/**\n * The parameters a template or suffix carries.\n *\n * Everything before a `?` is dropped — a tracking template starts with a\n * redirect and `{lpurl}`, neither of which is a parameter — and a bare suffix\n * with no `?` is read as the query string it is.\n */\nexport function paramsFromTemplate(template: string): TemplateParam[] {\n const start = template.indexOf(\"?\");\n const query = start === -1 ? template : template.slice(start + 1);\n const params: TemplateParam[] = [];\n for (const pair of query.split(\"&\")) {\n const at = pair.indexOf(\"=\");\n if (at < 1) continue;\n const name = pair.slice(0, at).trim();\n if (name === \"\") continue;\n params.push({ name, value: pair.slice(at + 1).trim() });\n }\n return params;\n}\n\n/**\n * What `baker analytics map` would have to be told for this template to be read.\n *\n * Silent about two kinds of parameter, both deliberately. The five UTMs cannot\n * be mapped — they have their own columns and their own report. Anything the\n * platform is already understood to send is already readable, and proposing it\n * again spends a turn to change nothing.\n */\nexport function proposeMappingFromTemplate(template: string, platform: AdPlatform): TemplateMappingProposal {\n const builtIn = builtinAdParamMapping(platform);\n const vocabulary = placeholderRoles(platform);\n const proposed: Record<string, AdParamRole> = {};\n const unexplained: TemplateParam[] = [];\n\n for (const param of paramsFromTemplate(template)) {\n if (RESERVED_PARAM_NAMES.includes(param.name)) continue;\n if (param.name in builtIn) continue;\n const role = vocabulary[placeholderKey(param.value)];\n if (role) {\n proposed[param.name] = role;\n continue;\n }\n unexplained.push(param);\n }\n\n return { proposed, unexplained };\n}\n\n/** The proposal as the command that applies it, or `\"\"` when there is nothing to apply. */\nexport function mappingCommandFor(platform: AdPlatform, proposed: Record<string, AdParamRole>): string {\n const pairs = Object.entries(proposed).map(([name, role]) => `${name}=${role}`);\n if (pairs.length === 0) return \"\";\n return `baker analytics map --platform ${platform} --set ${pairs.join(\",\")}`;\n}\n"],"mappings":"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","names":["z","z"]}
|