@koda-sl/baker-cli 0.386.0-dev.d6e55699d → 0.387.0-dev.3bafd569e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/{account-5TGX45FO.js → account-V5Y2QHAK.js} +5 -5
- package/dist/{account-reads-ZK5RMLB2.js → account-reads-S5VXX2QU.js} +4 -4
- package/dist/{accounts-HGAFFOA7.js → accounts-LOJ4WLIX.js} +4 -4
- package/dist/{accounts-OWMXUT6D.js → accounts-UO4XBWM2.js} +6 -6
- package/dist/{actions-NSQYW7YS.js → actions-3AW3R63U.js} +18 -18
- package/dist/{add-IIW3NHZH.js → add-43DUOVNR.js} +3 -3
- package/dist/{add-HWIE5PGR.js → add-IE5WDELB.js} +4 -4
- package/dist/{ads-D6KKCQ3Q.js → ads-DZ4N5INZ.js} +5 -5
- package/dist/{ads-QKIHHXP5.js → ads-XZCMSPM5.js} +9 -9
- package/dist/{adsets-7WMWU45E.js → adsets-AKR75THA.js} +8 -8
- package/dist/{advertisers-6NZ2M57X.js → advertisers-52FMMBTQ.js} +6 -6
- package/dist/{analytics-SN6K7J7M.js → analytics-JPDBKETM.js} +7 -7
- package/dist/{analytics-QJC2BTZY.js → analytics-YVQ6H4BG.js} +4 -4
- package/dist/{assign-XFDA42KL.js → assign-66NTWTR2.js} +4 -4
- package/dist/{audience-size-DJPFYHPJ.js → audience-size-LVQJWQAS.js} +4 -4
- package/dist/{audiences-VXTIBZP6.js → audiences-NYGMBGQ3.js} +5 -4
- package/dist/{audiences-VXTIBZP6.js.map → audiences-NYGMBGQ3.js.map} +1 -1
- package/dist/{audit-M5B7TZGT.js → audit-XGN2OFLN.js} +4 -4
- package/dist/{autocomplete-NWHEASQY.js → autocomplete-LVPDV3JE.js} +6 -6
- package/dist/{avatars-RNMUVMFM.js → avatars-S6NSLMJK.js} +4 -4
- package/dist/{bid-pricing-EAY3HAHY.js → bid-pricing-2LYULXU2.js} +4 -4
- package/dist/{brand-XBHWYPMT.js → brand-WWHUZ72R.js} +2 -2
- package/dist/{brief-XBAAPKRR.js → brief-K3FILESK.js} +8 -8
- package/dist/{campaign-groups-7KA2RA5V.js → campaign-groups-N4TZ2F3L.js} +9 -9
- package/dist/{campaign-writes-D2UID2I6.js → campaign-writes-7YFRQIQT.js} +4 -4
- package/dist/{campaigns-NJ3KOPJS.js → campaigns-L43ZUKAI.js} +5 -5
- package/dist/{campaigns-SOO5RHYG.js → campaigns-OD7Z332M.js} +12 -12
- package/dist/{campaigns-QUTTH2TB.js → campaigns-R4DXIR2Q.js} +8 -8
- package/dist/{canvas-3VZ46BCF.js → canvas-57K7AGAP.js} +12 -12
- package/dist/{capabilities-KAYDPH7E.js → capabilities-FVTZAFPV.js} +4 -4
- package/dist/{changes-22EO52IY.js → changes-7ZIGNUW6.js} +4 -4
- package/dist/{chats-QG3IRHOD.js → chats-E7DBRHBF.js} +4 -4
- package/dist/{chunk-JRGPCPT2.js → chunk-2HCI5BXB.js} +2 -2
- package/dist/{chunk-RRIAHUWP.js → chunk-3N4PZIIV.js} +2 -2
- package/dist/{chunk-4OBO75XU.js → chunk-3U7TDBIB.js} +2 -2
- package/dist/{chunk-QL573PLH.js → chunk-3ZWWXAQZ.js} +2 -2
- package/dist/{chunk-EQEZAYPL.js → chunk-564AEU2Q.js} +5 -5
- package/dist/{chunk-QKE7GXZ7.js → chunk-5SJ3JNNY.js} +4 -4
- package/dist/{chunk-WIRBRCTJ.js → chunk-77DN7R35.js} +2 -2
- package/dist/{chunk-PAHLJMC3.js → chunk-7F7MFMLI.js} +2 -2
- package/dist/{chunk-XE3WS3QE.js → chunk-7THBBTJJ.js} +2 -2
- package/dist/{chunk-OBNWER4H.js → chunk-7XU3HKMX.js} +3 -3
- package/dist/{chunk-ZCFSHQBF.js → chunk-AEA5JV2X.js} +2 -2
- package/dist/{chunk-CKI3RLMU.js → chunk-B52DCYL2.js} +3 -3
- package/dist/{chunk-AUCITRRT.js → chunk-CYBLKMXQ.js} +2 -2
- package/dist/{chunk-M4PPFVYL.js → chunk-F3IJSR7O.js} +3 -3
- package/dist/{chunk-Y4HZNSBN.js → chunk-GPZH5ASB.js} +5 -5
- package/dist/{chunk-RDLB54KF.js → chunk-GYABNLWW.js} +2 -2
- package/dist/{chunk-YIMGUMXX.js → chunk-H7XVKLIY.js} +2 -2
- package/dist/{chunk-BEGARAVC.js → chunk-HYXKRNRV.js} +7 -5
- package/dist/chunk-HYXKRNRV.js.map +1 -0
- package/dist/{chunk-GOJXKIFQ.js → chunk-KBS5GH4T.js} +24 -3
- package/dist/chunk-KBS5GH4T.js.map +1 -0
- package/dist/{chunk-IMORFIUT.js → chunk-KUZFWMJN.js} +3 -3
- package/dist/{chunk-3V5E5SVE.js → chunk-KXGG6EQM.js} +2 -2
- package/dist/{chunk-PBVLPFJ6.js → chunk-KXRKPZZY.js} +2 -2
- package/dist/{chunk-DYZJBWT2.js → chunk-L45A3IYV.js} +2 -2
- package/dist/{chunk-LWBWCIWL.js → chunk-LERWCRY5.js} +3 -3
- package/dist/{chunk-KAHMADFH.js → chunk-MZWC6HHA.js} +2 -2
- package/dist/{chunk-HB3LNR4Y.js → chunk-N3XJ434P.js} +2 -2
- package/dist/{chunk-K2RYUZ5Y.js → chunk-NJEZM4OB.js} +3 -3
- package/dist/{chunk-455BTAHM.js → chunk-OHGTCFFE.js} +2 -2
- package/dist/{chunk-DIICZGIS.js → chunk-PKTLHYH4.js} +5 -5
- package/dist/{chunk-WPKOEFOE.js → chunk-PUPEGICD.js} +2 -2
- package/dist/{chunk-V5HDRJQW.js → chunk-QSGIWV4P.js} +2 -2
- package/dist/{chunk-MUVSWFLL.js → chunk-RFB6RYKA.js} +3 -3
- package/dist/{chunk-GPXIUYIA.js → chunk-RODLBWIR.js} +2 -2
- package/dist/{chunk-TWNFQUBS.js → chunk-SJH4EOZH.js} +2 -2
- package/dist/{chunk-KRIK2JR4.js → chunk-SMIENBNX.js} +2 -2
- package/dist/{chunk-HVJUMQYY.js → chunk-T7GT22KA.js} +2 -2
- package/dist/{chunk-L5WIRYNB.js → chunk-TLQ23DDW.js} +2 -2
- package/dist/{chunk-IRTYTT5D.js → chunk-TMIDUSOR.js} +2 -2
- package/dist/{chunk-V5GSRREZ.js → chunk-UOI5S62H.js} +2 -2
- package/dist/{chunk-32PSERWG.js → chunk-VNKVBY54.js} +2 -2
- package/dist/{chunk-JAYT43KX.js → chunk-XX6ZMCY5.js} +11 -11
- package/dist/{chunk-JAYT43KX.js.map → chunk-XX6ZMCY5.js.map} +1 -1
- package/dist/{claim-4AFNDV3A.js → claim-LF6VQ7OR.js} +4 -4
- package/dist/cli.js +28 -28
- package/dist/{companies-PZRRZZNV.js → companies-6HSK5BLK.js} +4 -4
- package/dist/{complete-IBW5DNVZ.js → complete-2PUAFQEC.js} +4 -4
- package/dist/{connect-WYUYS5V4.js → connect-RXPMAJQI.js} +7 -7
- package/dist/{conversation-6AG3UBYY.js → conversation-Y3NB2VDI.js} +4 -4
- package/dist/{conversion-upload-command-YML2UNJB.js → conversion-upload-command-YP4DGTPP.js} +4 -4
- package/dist/{conversions-NOBBFNIU.js → conversions-K7C32DPW.js} +8 -8
- package/dist/{create-JK42P564.js → create-AJ4KPSJ4.js} +4 -4
- package/dist/{create-MUPQ5CTH.js → create-ALKOAD5J.js} +4 -4
- package/dist/{create-LAWUVPCY.js → create-HTKZMXKB.js} +3 -3
- package/dist/{create-NQJNCFRO.js → create-TZMAOFBR.js} +4 -4
- package/dist/{creatives-NNDWCSKJ.js → creatives-BJYJFVXJ.js} +10 -10
- package/dist/{creatives-KCWFZIM5.js → creatives-OZHVU4WB.js} +9 -9
- package/dist/{creatives-RHNHTS2R.js → creatives-VMGY5SU4.js} +3 -3
- package/dist/{credentials-CEKGXR2C.js → credentials-FY4UH6TF.js} +4 -4
- package/dist/{critique-HDDYER52.js → critique-B3H7QFM2.js} +4 -4
- package/dist/{critique-QIN2FO4F.js → critique-YZBOA27H.js} +6 -6
- package/dist/{crm-KBPWZC6J.js → crm-2IBLUHDB.js} +5 -5
- package/dist/{crm-QBWD7CWB.js → crm-YMYO4U53.js} +5 -5
- package/dist/{currency-XTFGZFGB.js → currency-S6KWZSZ6.js} +4 -4
- package/dist/{custom-conversions-W3K33V33.js → custom-conversions-FABS6YVT.js} +2 -2
- package/dist/{customers-HYE7N2H5.js → customers-P6LLLJHK.js} +6 -6
- package/dist/{delete-AY3KL3N3.js → delete-B2TDEW7H.js} +4 -4
- package/dist/{delete-64REPCY2.js → delete-SDOZNDWQ.js} +4 -4
- package/dist/{delete-VO2LZXE4.js → delete-WKQPMVAM.js} +3 -3
- package/dist/{demographics-KOFLMGVW.js → demographics-Q3DCXULY.js} +4 -4
- package/dist/{discard-H4RPXZHX.js → discard-NEZM5CHF.js} +4 -4
- package/dist/{discover-L7OVXW4V.js → discover-6K3IOYXR.js} +4 -4
- package/dist/{domain-HURQ23KR.js → domain-7Y256IDR.js} +4 -4
- package/dist/{draft-5VH2PW3R.js → draft-F6TUGXAY.js} +4 -4
- package/dist/{draft-D6UTKSAA.js → draft-LY5ZPF73.js} +4 -4
- package/dist/{draft-UQYWDZS7.js → draft-M4ZHDQ46.js} +5 -5
- package/dist/{draft-YFAJHCKM.js → draft-QQMCVDDS.js} +4 -4
- package/dist/{facets-WYQUZMFJ.js → facets-7MBSM7BP.js} +4 -4
- package/dist/{feedback-SIMPRE37.js → feedback-ZOUL22TP.js} +2 -2
- package/dist/{feedback-record-L4MPIVML.js → feedback-record-XFFJRKS6.js} +8 -8
- package/dist/{fetch-DTBM3DE2.js → fetch-QE3EB756.js} +4 -4
- package/dist/{flows-IUDXVDOS.js → flows-C67KEMDU.js} +11 -11
- package/dist/{fonts-EUDHI6CA.js → fonts-UR7XZ5XZ.js} +6 -6
- package/dist/{forecast-BRSEH2H3.js → forecast-3F4SZNAK.js} +4 -4
- package/dist/{forecast-QV4U7TOY.js → forecast-K5E7CTKX.js} +4 -4
- package/dist/{funnel-JLF77MLF.js → funnel-2PPEPAMY.js} +5 -5
- package/dist/{get-AYX5HS64.js → get-BPMEHRUG.js} +4 -4
- package/dist/{get-EG2U7MIL.js → get-MQ6MMIZ7.js} +4 -4
- package/dist/{google-ITTPCJ7N.js → google-4XAYE4OI.js} +22 -22
- package/dist/{google-ads-U3JFFQLU.js → google-ads-PWX7OF5Z.js} +4 -4
- package/dist/{history-YTNCWSV3.js → history-XI5ABCFO.js} +4 -4
- package/dist/{hubspot-LXWQNKKB.js → hubspot-AVUOILRE.js} +8 -8
- package/dist/{ideas-JJIHQFV4.js → ideas-UCPV3KTM.js} +3 -3
- package/dist/{images-MWETBYKB.js → images-CD53I2W5.js} +4 -4
- package/dist/{ingest-THFAV4NO.js → ingest-KRJOYTCQ.js} +3 -3
- package/dist/{ingest-U6B7GR4A.js → ingest-WE3SPPND.js} +4 -4
- package/dist/{insights-FA6T6PT6.js → insights-XCA4BUJW.js} +2 -2
- package/dist/{inspect-N2WVVWGP.js → inspect-QKETG5UJ.js} +4 -4
- package/dist/{intent-YNAAVNHK.js → intent-YJOJGNVJ.js} +4 -4
- package/dist/{keyword-gap-4JKLWIBJ.js → keyword-gap-QU7O7UKC.js} +4 -4
- package/dist/{keyword-metrics-KU3OHTQK.js → keyword-metrics-HLCM3QU7.js} +6 -6
- package/dist/{keywords-for-site-M4MFWMVK.js → keywords-for-site-BDKPQKWB.js} +6 -6
- package/dist/{landing-7UVZ7IPP.js → landing-4K6XYNFM.js} +2 -2
- package/dist/{languages-PKYCZNUB.js → languages-P3ZM6R2A.js} +4 -4
- package/dist/{leads-MQPEA7DG.js → leads-GDF4S2AM.js} +4 -4
- package/dist/{leads-CSRESOB2.js → leads-TPB5OFSQ.js} +3 -3
- package/dist/{learn-K5YBUMBT.js → learn-NMFEA5H5.js} +5 -5
- package/dist/{line-item-writes-73NR2J5L.js → line-item-writes-O6SSS5NQ.js} +4 -4
- package/dist/{line-items-2YBGXOAQ.js → line-items-ZZAKH3YZ.js} +5 -5
- package/dist/{link-GVAWECJO.js → link-CRY57R3E.js} +4 -4
- package/dist/{linkedin-PZDT22AT.js → linkedin-WC7LGYPP.js} +27 -27
- package/dist/{list-REZGFWC5.js → list-CWAKX5TH.js} +4 -4
- package/dist/{list-FNDRV25Y.js → list-FJ5FSVL6.js} +3 -3
- package/dist/{list-S6MNXDTV.js → list-NH4ZRZTL.js} +4 -4
- package/dist/{locations-GJHHMV6Z.js → locations-LVVDOSXO.js} +4 -4
- package/dist/{log-HGDNLDUX.js → log-6JOWOY5G.js} +4 -4
- package/dist/{make-BT26YJXZ.js → make-Q2AMLCWE.js} +11 -11
- package/dist/{map-J5EX4HOX.js → map-4KOYFHAN.js} +5 -5
- package/dist/{mcp-MHDW6AFL.js → mcp-LSS2DHYL.js} +3 -3
- package/dist/{media-RNB7JFJP.js → media-JBCN6V4X.js} +2 -2
- package/dist/{media-sources-4NN3DWSG.js → media-sources-GSPAV7HT.js} +2 -2
- package/dist/{members-AIWMXAQD.js → members-GUUVEK2Y.js} +4 -4
- package/dist/{meta-WAPZMZI7.js → meta-Z37ZR3PJ.js} +12 -12
- package/dist/{metrics-6EHC4ESN.js → metrics-KW6SDULI.js} +4 -4
- package/dist/{normalize-ZAWN4XCS.js → normalize-EUDI5HEM.js} +4 -4
- package/dist/{options-3CZNT5KP.js → options-P4PPJQH4.js} +7 -7
- package/dist/{performance-GOMJMHPE.js → performance-A66LYIZX.js} +5 -5
- package/dist/{preview-UKYLPAW2.js → preview-5ROBOQG7.js} +2 -2
- package/dist/{promoted-tweet-writes-IYOAZTA5.js → promoted-tweet-writes-AEOUK2LK.js} +4 -4
- package/dist/{promoted-tweets-G3XFD5YM.js → promoted-tweets-L2CEC2BJ.js} +3 -3
- package/dist/{publish-ZG4J2GTH.js → publish-KHNR5ARF.js} +4 -4
- package/dist/{query-7AGG77WH.js → query-A34J7BGX.js} +5 -5
- package/dist/{reddit-FTO4SFQE.js → reddit-5NPFULGD.js} +5 -5
- package/dist/{refresh-OUENQ2FS.js → refresh-FGXW4Y4X.js} +3 -3
- package/dist/{release-5OG7AAFY.js → release-OKZMC73N.js} +4 -4
- package/dist/{relevant-pages-KUVDZPRU.js → relevant-pages-J76ZKNKF.js} +4 -4
- package/dist/{remove-33HI27KM.js → remove-CA2J6ACH.js} +3 -3
- package/dist/{reopen-KFFYE53A.js → reopen-XPKSOE6O.js} +4 -4
- package/dist/{rerun-P6XACA5Z.js → rerun-2ERJV4WC.js} +11 -11
- package/dist/{research-QOC53DLS.js → research-FZ63UZTE.js} +13 -13
- package/dist/{research-BEO3JMZI.js → research-YGQQ6CNG.js} +3 -3
- package/dist/{reset-I7M3HYMB.js → reset-BGPZ4HMA.js} +3 -3
- package/dist/{reset-E3OWE2WF.js → reset-HTD6LCIT.js} +3 -3
- package/dist/{resolve-GP7BHM6L.js → resolve-NRDZ6N2B.js} +4 -4
- package/dist/{retry-X5PU7QO3.js → retry-PF4BGKJV.js} +3 -3
- package/dist/{retry-33ZJCNQI.js → retry-XL26JDAV.js} +3 -3
- package/dist/{run-REK3TEGY.js → run-EMJLI7LR.js} +4 -4
- package/dist/{run-TH2662IC.js → run-L5K44UEA.js} +11 -11
- package/dist/{scaffold-ad-3WDRKUFT.js → scaffold-ad-AY2OL7RI.js} +9 -9
- package/dist/{scaffold-static-ad-X5NT52NF.js → scaffold-static-ad-FXYE46MT.js} +13 -13
- package/dist/{scaffold-video-WZPVACLE.js → scaffold-video-533BT6RX.js} +8 -8
- package/dist/{schedule-V4UHGY3V.js → schedule-PKPNSISL.js} +3 -3
- package/dist/{scheduled-agents-KLQ5H2PA.js → scheduled-agents-LP5LITA3.js} +11 -11
- package/dist/{schema-G3T4PZDI.js → schema-B6J6VPTO.js} +5 -5
- package/dist/{search-6XKEGABN.js → search-6WNUKCMP.js} +3 -3
- package/dist/{select-N2V55BEX.js → select-RSGLDQ5Z.js} +8 -8
- package/dist/{set-prompt-7HVHERRU.js → set-prompt-7WWJI6XW.js} +6 -6
- package/dist/{setup-links-4VVNQVPU.js → setup-links-6H5ONDCQ.js} +4 -4
- package/dist/{shopify-FSHM5M4I.js → shopify-2OY3J3OY.js} +1148 -802
- package/dist/shopify-2OY3J3OY.js.map +1 -0
- package/dist/{site-Q2HTRLIW.js → site-TBPERLY3.js} +5 -5
- package/dist/{sources-4I2YMS2K.js → sources-JFQKTK2L.js} +7 -7
- package/dist/{sources-2KN4RJNJ.js → sources-Q3I6DDV7.js} +6 -6
- package/dist/{stale-IN7WSBLC.js → stale-CAXBLZKJ.js} +7 -7
- package/dist/{status-6SLKZWNR.js → status-LIZWJYS4.js} +4 -4
- package/dist/{sync-LFZV5NBN.js → sync-ULKWDFXM.js} +3 -3
- package/dist/{sync-definition-IJISZ5VQ.js → sync-definition-P6QTHJJ6.js} +8 -8
- package/dist/{tags-TCFFP534.js → tags-4Q4I5GQJ.js} +4 -4
- package/dist/{tags-6OAZOQYO.js → tags-AMEVAQZ4.js} +4 -4
- package/dist/{tags-6YRMDX3R.js → tags-DPLOLH3E.js} +4 -4
- package/dist/{tags-SZCNPE2D.js → tags-LDHXONR3.js} +3 -3
- package/dist/{tags-EWXZSZYE.js → tags-UW3WJTAQ.js} +4 -4
- package/dist/{targeting-criteria-ESOC7KNX.js → targeting-criteria-BP6VJA7X.js} +3 -3
- package/dist/{targets-IPBEB5KU.js → targets-CQWO2UXD.js} +4 -4
- package/dist/{templates-IJ7FR3LA.js → templates-WZSTNRNZ.js} +4 -4
- package/dist/{testimonials-IXS7CP6P.js → testimonials-ETHSNWUH.js} +6 -6
- package/dist/{themes-MXNKJWMW.js → themes-YU663LQH.js} +4 -4
- package/dist/{top-companies-NO6L2V6M.js → top-companies-KTXHS472.js} +4 -4
- package/dist/{translate-QCE5ZB7M.js → translate-A7LYHUW3.js} +11 -11
- package/dist/{triggers-KXUDMDSA.js → triggers-4EDFLNGH.js} +4 -4
- package/dist/{unlink-E3N36NYQ.js → unlink-KY2OEKMD.js} +4 -4
- package/dist/{unstage-TRMHSHED.js → unstage-FHUG67RI.js} +4 -4
- package/dist/{update-VSFHID2D.js → update-27LGM65V.js} +4 -4
- package/dist/{update-OKOQE7U2.js → update-AIY46I2Q.js} +3 -3
- package/dist/{update-EWGWAXAQ.js → update-QYD2XZFM.js} +4 -4
- package/dist/{update-XGCGQDJ4.js → update-W2OSRNFO.js} +4 -4
- package/dist/{upload-BOYMDDEQ.js → upload-JGBTSKGH.js} +4 -4
- package/dist/{url-options-PCZEQE66.js → url-options-QHGA42RP.js} +4 -4
- package/dist/{url-params-DV37GEQF.js → url-params-NWSUHWRE.js} +4 -4
- package/dist/{validate-5AV4FJZ5.js → validate-VKL3XKQ2.js} +6 -6
- package/dist/{videos-IJ67PPJV.js → videos-DP3VCSYG.js} +5 -5
- package/dist/{web-LJ36FRWD.js → web-AFUIWPFU.js} +4 -4
- package/dist/{winning-ads-JIG2MQHJ.js → winning-ads-PCIJUYVA.js} +2 -2
- package/dist/{write-commands-KA3QXVSF.js → write-commands-N4FSGRVQ.js} +12 -6
- package/dist/{write-commands-KA3QXVSF.js.map → write-commands-N4FSGRVQ.js.map} +1 -1
- package/dist/{write-commands-GOZU6ENR.js → write-commands-Q4MQ3BGM.js} +5 -5
- package/dist/{x-6HBVXIKH.js → x-AUOZJNWE.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-BEGARAVC.js.map +0 -1
- package/dist/chunk-GOJXKIFQ.js.map +0 -1
- package/dist/shopify-FSHM5M4I.js.map +0 -1
- /package/dist/{account-5TGX45FO.js.map → account-V5Y2QHAK.js.map} +0 -0
- /package/dist/{account-reads-ZK5RMLB2.js.map → account-reads-S5VXX2QU.js.map} +0 -0
- /package/dist/{accounts-HGAFFOA7.js.map → accounts-LOJ4WLIX.js.map} +0 -0
- /package/dist/{accounts-OWMXUT6D.js.map → accounts-UO4XBWM2.js.map} +0 -0
- /package/dist/{actions-NSQYW7YS.js.map → actions-3AW3R63U.js.map} +0 -0
- /package/dist/{add-IIW3NHZH.js.map → add-43DUOVNR.js.map} +0 -0
- /package/dist/{add-HWIE5PGR.js.map → add-IE5WDELB.js.map} +0 -0
- /package/dist/{ads-D6KKCQ3Q.js.map → ads-DZ4N5INZ.js.map} +0 -0
- /package/dist/{ads-QKIHHXP5.js.map → ads-XZCMSPM5.js.map} +0 -0
- /package/dist/{adsets-7WMWU45E.js.map → adsets-AKR75THA.js.map} +0 -0
- /package/dist/{advertisers-6NZ2M57X.js.map → advertisers-52FMMBTQ.js.map} +0 -0
- /package/dist/{analytics-SN6K7J7M.js.map → analytics-JPDBKETM.js.map} +0 -0
- /package/dist/{analytics-QJC2BTZY.js.map → analytics-YVQ6H4BG.js.map} +0 -0
- /package/dist/{assign-XFDA42KL.js.map → assign-66NTWTR2.js.map} +0 -0
- /package/dist/{audience-size-DJPFYHPJ.js.map → audience-size-LVQJWQAS.js.map} +0 -0
- /package/dist/{audit-M5B7TZGT.js.map → audit-XGN2OFLN.js.map} +0 -0
- /package/dist/{autocomplete-NWHEASQY.js.map → autocomplete-LVPDV3JE.js.map} +0 -0
- /package/dist/{avatars-RNMUVMFM.js.map → avatars-S6NSLMJK.js.map} +0 -0
- /package/dist/{bid-pricing-EAY3HAHY.js.map → bid-pricing-2LYULXU2.js.map} +0 -0
- /package/dist/{brand-XBHWYPMT.js.map → brand-WWHUZ72R.js.map} +0 -0
- /package/dist/{brief-XBAAPKRR.js.map → brief-K3FILESK.js.map} +0 -0
- /package/dist/{campaign-groups-7KA2RA5V.js.map → campaign-groups-N4TZ2F3L.js.map} +0 -0
- /package/dist/{campaign-writes-D2UID2I6.js.map → campaign-writes-7YFRQIQT.js.map} +0 -0
- /package/dist/{campaigns-NJ3KOPJS.js.map → campaigns-L43ZUKAI.js.map} +0 -0
- /package/dist/{campaigns-SOO5RHYG.js.map → campaigns-OD7Z332M.js.map} +0 -0
- /package/dist/{campaigns-QUTTH2TB.js.map → campaigns-R4DXIR2Q.js.map} +0 -0
- /package/dist/{canvas-3VZ46BCF.js.map → canvas-57K7AGAP.js.map} +0 -0
- /package/dist/{capabilities-KAYDPH7E.js.map → capabilities-FVTZAFPV.js.map} +0 -0
- /package/dist/{changes-22EO52IY.js.map → changes-7ZIGNUW6.js.map} +0 -0
- /package/dist/{chats-QG3IRHOD.js.map → chats-E7DBRHBF.js.map} +0 -0
- /package/dist/{chunk-JRGPCPT2.js.map → chunk-2HCI5BXB.js.map} +0 -0
- /package/dist/{chunk-RRIAHUWP.js.map → chunk-3N4PZIIV.js.map} +0 -0
- /package/dist/{chunk-4OBO75XU.js.map → chunk-3U7TDBIB.js.map} +0 -0
- /package/dist/{chunk-QL573PLH.js.map → chunk-3ZWWXAQZ.js.map} +0 -0
- /package/dist/{chunk-EQEZAYPL.js.map → chunk-564AEU2Q.js.map} +0 -0
- /package/dist/{chunk-QKE7GXZ7.js.map → chunk-5SJ3JNNY.js.map} +0 -0
- /package/dist/{chunk-WIRBRCTJ.js.map → chunk-77DN7R35.js.map} +0 -0
- /package/dist/{chunk-PAHLJMC3.js.map → chunk-7F7MFMLI.js.map} +0 -0
- /package/dist/{chunk-XE3WS3QE.js.map → chunk-7THBBTJJ.js.map} +0 -0
- /package/dist/{chunk-OBNWER4H.js.map → chunk-7XU3HKMX.js.map} +0 -0
- /package/dist/{chunk-ZCFSHQBF.js.map → chunk-AEA5JV2X.js.map} +0 -0
- /package/dist/{chunk-CKI3RLMU.js.map → chunk-B52DCYL2.js.map} +0 -0
- /package/dist/{chunk-AUCITRRT.js.map → chunk-CYBLKMXQ.js.map} +0 -0
- /package/dist/{chunk-M4PPFVYL.js.map → chunk-F3IJSR7O.js.map} +0 -0
- /package/dist/{chunk-Y4HZNSBN.js.map → chunk-GPZH5ASB.js.map} +0 -0
- /package/dist/{chunk-RDLB54KF.js.map → chunk-GYABNLWW.js.map} +0 -0
- /package/dist/{chunk-YIMGUMXX.js.map → chunk-H7XVKLIY.js.map} +0 -0
- /package/dist/{chunk-IMORFIUT.js.map → chunk-KUZFWMJN.js.map} +0 -0
- /package/dist/{chunk-3V5E5SVE.js.map → chunk-KXGG6EQM.js.map} +0 -0
- /package/dist/{chunk-PBVLPFJ6.js.map → chunk-KXRKPZZY.js.map} +0 -0
- /package/dist/{chunk-DYZJBWT2.js.map → chunk-L45A3IYV.js.map} +0 -0
- /package/dist/{chunk-LWBWCIWL.js.map → chunk-LERWCRY5.js.map} +0 -0
- /package/dist/{chunk-KAHMADFH.js.map → chunk-MZWC6HHA.js.map} +0 -0
- /package/dist/{chunk-HB3LNR4Y.js.map → chunk-N3XJ434P.js.map} +0 -0
- /package/dist/{chunk-K2RYUZ5Y.js.map → chunk-NJEZM4OB.js.map} +0 -0
- /package/dist/{chunk-455BTAHM.js.map → chunk-OHGTCFFE.js.map} +0 -0
- /package/dist/{chunk-DIICZGIS.js.map → chunk-PKTLHYH4.js.map} +0 -0
- /package/dist/{chunk-WPKOEFOE.js.map → chunk-PUPEGICD.js.map} +0 -0
- /package/dist/{chunk-V5HDRJQW.js.map → chunk-QSGIWV4P.js.map} +0 -0
- /package/dist/{chunk-MUVSWFLL.js.map → chunk-RFB6RYKA.js.map} +0 -0
- /package/dist/{chunk-GPXIUYIA.js.map → chunk-RODLBWIR.js.map} +0 -0
- /package/dist/{chunk-TWNFQUBS.js.map → chunk-SJH4EOZH.js.map} +0 -0
- /package/dist/{chunk-KRIK2JR4.js.map → chunk-SMIENBNX.js.map} +0 -0
- /package/dist/{chunk-HVJUMQYY.js.map → chunk-T7GT22KA.js.map} +0 -0
- /package/dist/{chunk-L5WIRYNB.js.map → chunk-TLQ23DDW.js.map} +0 -0
- /package/dist/{chunk-IRTYTT5D.js.map → chunk-TMIDUSOR.js.map} +0 -0
- /package/dist/{chunk-V5GSRREZ.js.map → chunk-UOI5S62H.js.map} +0 -0
- /package/dist/{chunk-32PSERWG.js.map → chunk-VNKVBY54.js.map} +0 -0
- /package/dist/{claim-4AFNDV3A.js.map → claim-LF6VQ7OR.js.map} +0 -0
- /package/dist/{companies-PZRRZZNV.js.map → companies-6HSK5BLK.js.map} +0 -0
- /package/dist/{complete-IBW5DNVZ.js.map → complete-2PUAFQEC.js.map} +0 -0
- /package/dist/{connect-WYUYS5V4.js.map → connect-RXPMAJQI.js.map} +0 -0
- /package/dist/{conversation-6AG3UBYY.js.map → conversation-Y3NB2VDI.js.map} +0 -0
- /package/dist/{conversion-upload-command-YML2UNJB.js.map → conversion-upload-command-YP4DGTPP.js.map} +0 -0
- /package/dist/{conversions-NOBBFNIU.js.map → conversions-K7C32DPW.js.map} +0 -0
- /package/dist/{create-JK42P564.js.map → create-AJ4KPSJ4.js.map} +0 -0
- /package/dist/{create-MUPQ5CTH.js.map → create-ALKOAD5J.js.map} +0 -0
- /package/dist/{create-LAWUVPCY.js.map → create-HTKZMXKB.js.map} +0 -0
- /package/dist/{create-NQJNCFRO.js.map → create-TZMAOFBR.js.map} +0 -0
- /package/dist/{creatives-NNDWCSKJ.js.map → creatives-BJYJFVXJ.js.map} +0 -0
- /package/dist/{creatives-KCWFZIM5.js.map → creatives-OZHVU4WB.js.map} +0 -0
- /package/dist/{creatives-RHNHTS2R.js.map → creatives-VMGY5SU4.js.map} +0 -0
- /package/dist/{credentials-CEKGXR2C.js.map → credentials-FY4UH6TF.js.map} +0 -0
- /package/dist/{critique-HDDYER52.js.map → critique-B3H7QFM2.js.map} +0 -0
- /package/dist/{critique-QIN2FO4F.js.map → critique-YZBOA27H.js.map} +0 -0
- /package/dist/{crm-KBPWZC6J.js.map → crm-2IBLUHDB.js.map} +0 -0
- /package/dist/{crm-QBWD7CWB.js.map → crm-YMYO4U53.js.map} +0 -0
- /package/dist/{currency-XTFGZFGB.js.map → currency-S6KWZSZ6.js.map} +0 -0
- /package/dist/{custom-conversions-W3K33V33.js.map → custom-conversions-FABS6YVT.js.map} +0 -0
- /package/dist/{customers-HYE7N2H5.js.map → customers-P6LLLJHK.js.map} +0 -0
- /package/dist/{delete-AY3KL3N3.js.map → delete-B2TDEW7H.js.map} +0 -0
- /package/dist/{delete-64REPCY2.js.map → delete-SDOZNDWQ.js.map} +0 -0
- /package/dist/{delete-VO2LZXE4.js.map → delete-WKQPMVAM.js.map} +0 -0
- /package/dist/{demographics-KOFLMGVW.js.map → demographics-Q3DCXULY.js.map} +0 -0
- /package/dist/{discard-H4RPXZHX.js.map → discard-NEZM5CHF.js.map} +0 -0
- /package/dist/{discover-L7OVXW4V.js.map → discover-6K3IOYXR.js.map} +0 -0
- /package/dist/{domain-HURQ23KR.js.map → domain-7Y256IDR.js.map} +0 -0
- /package/dist/{draft-5VH2PW3R.js.map → draft-F6TUGXAY.js.map} +0 -0
- /package/dist/{draft-D6UTKSAA.js.map → draft-LY5ZPF73.js.map} +0 -0
- /package/dist/{draft-UQYWDZS7.js.map → draft-M4ZHDQ46.js.map} +0 -0
- /package/dist/{draft-YFAJHCKM.js.map → draft-QQMCVDDS.js.map} +0 -0
- /package/dist/{facets-WYQUZMFJ.js.map → facets-7MBSM7BP.js.map} +0 -0
- /package/dist/{feedback-SIMPRE37.js.map → feedback-ZOUL22TP.js.map} +0 -0
- /package/dist/{feedback-record-L4MPIVML.js.map → feedback-record-XFFJRKS6.js.map} +0 -0
- /package/dist/{fetch-DTBM3DE2.js.map → fetch-QE3EB756.js.map} +0 -0
- /package/dist/{flows-IUDXVDOS.js.map → flows-C67KEMDU.js.map} +0 -0
- /package/dist/{fonts-EUDHI6CA.js.map → fonts-UR7XZ5XZ.js.map} +0 -0
- /package/dist/{forecast-BRSEH2H3.js.map → forecast-3F4SZNAK.js.map} +0 -0
- /package/dist/{forecast-QV4U7TOY.js.map → forecast-K5E7CTKX.js.map} +0 -0
- /package/dist/{funnel-JLF77MLF.js.map → funnel-2PPEPAMY.js.map} +0 -0
- /package/dist/{get-AYX5HS64.js.map → get-BPMEHRUG.js.map} +0 -0
- /package/dist/{get-EG2U7MIL.js.map → get-MQ6MMIZ7.js.map} +0 -0
- /package/dist/{google-ITTPCJ7N.js.map → google-4XAYE4OI.js.map} +0 -0
- /package/dist/{google-ads-U3JFFQLU.js.map → google-ads-PWX7OF5Z.js.map} +0 -0
- /package/dist/{history-YTNCWSV3.js.map → history-XI5ABCFO.js.map} +0 -0
- /package/dist/{hubspot-LXWQNKKB.js.map → hubspot-AVUOILRE.js.map} +0 -0
- /package/dist/{ideas-JJIHQFV4.js.map → ideas-UCPV3KTM.js.map} +0 -0
- /package/dist/{images-MWETBYKB.js.map → images-CD53I2W5.js.map} +0 -0
- /package/dist/{ingest-THFAV4NO.js.map → ingest-KRJOYTCQ.js.map} +0 -0
- /package/dist/{ingest-U6B7GR4A.js.map → ingest-WE3SPPND.js.map} +0 -0
- /package/dist/{insights-FA6T6PT6.js.map → insights-XCA4BUJW.js.map} +0 -0
- /package/dist/{inspect-N2WVVWGP.js.map → inspect-QKETG5UJ.js.map} +0 -0
- /package/dist/{intent-YNAAVNHK.js.map → intent-YJOJGNVJ.js.map} +0 -0
- /package/dist/{keyword-gap-4JKLWIBJ.js.map → keyword-gap-QU7O7UKC.js.map} +0 -0
- /package/dist/{keyword-metrics-KU3OHTQK.js.map → keyword-metrics-HLCM3QU7.js.map} +0 -0
- /package/dist/{keywords-for-site-M4MFWMVK.js.map → keywords-for-site-BDKPQKWB.js.map} +0 -0
- /package/dist/{landing-7UVZ7IPP.js.map → landing-4K6XYNFM.js.map} +0 -0
- /package/dist/{languages-PKYCZNUB.js.map → languages-P3ZM6R2A.js.map} +0 -0
- /package/dist/{leads-MQPEA7DG.js.map → leads-GDF4S2AM.js.map} +0 -0
- /package/dist/{leads-CSRESOB2.js.map → leads-TPB5OFSQ.js.map} +0 -0
- /package/dist/{learn-K5YBUMBT.js.map → learn-NMFEA5H5.js.map} +0 -0
- /package/dist/{line-item-writes-73NR2J5L.js.map → line-item-writes-O6SSS5NQ.js.map} +0 -0
- /package/dist/{line-items-2YBGXOAQ.js.map → line-items-ZZAKH3YZ.js.map} +0 -0
- /package/dist/{link-GVAWECJO.js.map → link-CRY57R3E.js.map} +0 -0
- /package/dist/{linkedin-PZDT22AT.js.map → linkedin-WC7LGYPP.js.map} +0 -0
- /package/dist/{list-REZGFWC5.js.map → list-CWAKX5TH.js.map} +0 -0
- /package/dist/{list-FNDRV25Y.js.map → list-FJ5FSVL6.js.map} +0 -0
- /package/dist/{list-S6MNXDTV.js.map → list-NH4ZRZTL.js.map} +0 -0
- /package/dist/{locations-GJHHMV6Z.js.map → locations-LVVDOSXO.js.map} +0 -0
- /package/dist/{log-HGDNLDUX.js.map → log-6JOWOY5G.js.map} +0 -0
- /package/dist/{make-BT26YJXZ.js.map → make-Q2AMLCWE.js.map} +0 -0
- /package/dist/{map-J5EX4HOX.js.map → map-4KOYFHAN.js.map} +0 -0
- /package/dist/{mcp-MHDW6AFL.js.map → mcp-LSS2DHYL.js.map} +0 -0
- /package/dist/{media-RNB7JFJP.js.map → media-JBCN6V4X.js.map} +0 -0
- /package/dist/{media-sources-4NN3DWSG.js.map → media-sources-GSPAV7HT.js.map} +0 -0
- /package/dist/{members-AIWMXAQD.js.map → members-GUUVEK2Y.js.map} +0 -0
- /package/dist/{meta-WAPZMZI7.js.map → meta-Z37ZR3PJ.js.map} +0 -0
- /package/dist/{metrics-6EHC4ESN.js.map → metrics-KW6SDULI.js.map} +0 -0
- /package/dist/{normalize-ZAWN4XCS.js.map → normalize-EUDI5HEM.js.map} +0 -0
- /package/dist/{options-3CZNT5KP.js.map → options-P4PPJQH4.js.map} +0 -0
- /package/dist/{performance-GOMJMHPE.js.map → performance-A66LYIZX.js.map} +0 -0
- /package/dist/{preview-UKYLPAW2.js.map → preview-5ROBOQG7.js.map} +0 -0
- /package/dist/{promoted-tweet-writes-IYOAZTA5.js.map → promoted-tweet-writes-AEOUK2LK.js.map} +0 -0
- /package/dist/{promoted-tweets-G3XFD5YM.js.map → promoted-tweets-L2CEC2BJ.js.map} +0 -0
- /package/dist/{publish-ZG4J2GTH.js.map → publish-KHNR5ARF.js.map} +0 -0
- /package/dist/{query-7AGG77WH.js.map → query-A34J7BGX.js.map} +0 -0
- /package/dist/{reddit-FTO4SFQE.js.map → reddit-5NPFULGD.js.map} +0 -0
- /package/dist/{refresh-OUENQ2FS.js.map → refresh-FGXW4Y4X.js.map} +0 -0
- /package/dist/{release-5OG7AAFY.js.map → release-OKZMC73N.js.map} +0 -0
- /package/dist/{relevant-pages-KUVDZPRU.js.map → relevant-pages-J76ZKNKF.js.map} +0 -0
- /package/dist/{remove-33HI27KM.js.map → remove-CA2J6ACH.js.map} +0 -0
- /package/dist/{reopen-KFFYE53A.js.map → reopen-XPKSOE6O.js.map} +0 -0
- /package/dist/{rerun-P6XACA5Z.js.map → rerun-2ERJV4WC.js.map} +0 -0
- /package/dist/{research-QOC53DLS.js.map → research-FZ63UZTE.js.map} +0 -0
- /package/dist/{research-BEO3JMZI.js.map → research-YGQQ6CNG.js.map} +0 -0
- /package/dist/{reset-I7M3HYMB.js.map → reset-BGPZ4HMA.js.map} +0 -0
- /package/dist/{reset-E3OWE2WF.js.map → reset-HTD6LCIT.js.map} +0 -0
- /package/dist/{resolve-GP7BHM6L.js.map → resolve-NRDZ6N2B.js.map} +0 -0
- /package/dist/{retry-X5PU7QO3.js.map → retry-PF4BGKJV.js.map} +0 -0
- /package/dist/{retry-33ZJCNQI.js.map → retry-XL26JDAV.js.map} +0 -0
- /package/dist/{run-REK3TEGY.js.map → run-EMJLI7LR.js.map} +0 -0
- /package/dist/{run-TH2662IC.js.map → run-L5K44UEA.js.map} +0 -0
- /package/dist/{scaffold-ad-3WDRKUFT.js.map → scaffold-ad-AY2OL7RI.js.map} +0 -0
- /package/dist/{scaffold-static-ad-X5NT52NF.js.map → scaffold-static-ad-FXYE46MT.js.map} +0 -0
- /package/dist/{scaffold-video-WZPVACLE.js.map → scaffold-video-533BT6RX.js.map} +0 -0
- /package/dist/{schedule-V4UHGY3V.js.map → schedule-PKPNSISL.js.map} +0 -0
- /package/dist/{scheduled-agents-KLQ5H2PA.js.map → scheduled-agents-LP5LITA3.js.map} +0 -0
- /package/dist/{schema-G3T4PZDI.js.map → schema-B6J6VPTO.js.map} +0 -0
- /package/dist/{search-6XKEGABN.js.map → search-6WNUKCMP.js.map} +0 -0
- /package/dist/{select-N2V55BEX.js.map → select-RSGLDQ5Z.js.map} +0 -0
- /package/dist/{set-prompt-7HVHERRU.js.map → set-prompt-7WWJI6XW.js.map} +0 -0
- /package/dist/{setup-links-4VVNQVPU.js.map → setup-links-6H5ONDCQ.js.map} +0 -0
- /package/dist/{site-Q2HTRLIW.js.map → site-TBPERLY3.js.map} +0 -0
- /package/dist/{sources-4I2YMS2K.js.map → sources-JFQKTK2L.js.map} +0 -0
- /package/dist/{sources-2KN4RJNJ.js.map → sources-Q3I6DDV7.js.map} +0 -0
- /package/dist/{stale-IN7WSBLC.js.map → stale-CAXBLZKJ.js.map} +0 -0
- /package/dist/{status-6SLKZWNR.js.map → status-LIZWJYS4.js.map} +0 -0
- /package/dist/{sync-LFZV5NBN.js.map → sync-ULKWDFXM.js.map} +0 -0
- /package/dist/{sync-definition-IJISZ5VQ.js.map → sync-definition-P6QTHJJ6.js.map} +0 -0
- /package/dist/{tags-TCFFP534.js.map → tags-4Q4I5GQJ.js.map} +0 -0
- /package/dist/{tags-6OAZOQYO.js.map → tags-AMEVAQZ4.js.map} +0 -0
- /package/dist/{tags-6YRMDX3R.js.map → tags-DPLOLH3E.js.map} +0 -0
- /package/dist/{tags-SZCNPE2D.js.map → tags-LDHXONR3.js.map} +0 -0
- /package/dist/{tags-EWXZSZYE.js.map → tags-UW3WJTAQ.js.map} +0 -0
- /package/dist/{targeting-criteria-ESOC7KNX.js.map → targeting-criteria-BP6VJA7X.js.map} +0 -0
- /package/dist/{targets-IPBEB5KU.js.map → targets-CQWO2UXD.js.map} +0 -0
- /package/dist/{templates-IJ7FR3LA.js.map → templates-WZSTNRNZ.js.map} +0 -0
- /package/dist/{testimonials-IXS7CP6P.js.map → testimonials-ETHSNWUH.js.map} +0 -0
- /package/dist/{themes-MXNKJWMW.js.map → themes-YU663LQH.js.map} +0 -0
- /package/dist/{top-companies-NO6L2V6M.js.map → top-companies-KTXHS472.js.map} +0 -0
- /package/dist/{translate-QCE5ZB7M.js.map → translate-A7LYHUW3.js.map} +0 -0
- /package/dist/{triggers-KXUDMDSA.js.map → triggers-4EDFLNGH.js.map} +0 -0
- /package/dist/{unlink-E3N36NYQ.js.map → unlink-KY2OEKMD.js.map} +0 -0
- /package/dist/{unstage-TRMHSHED.js.map → unstage-FHUG67RI.js.map} +0 -0
- /package/dist/{update-VSFHID2D.js.map → update-27LGM65V.js.map} +0 -0
- /package/dist/{update-OKOQE7U2.js.map → update-AIY46I2Q.js.map} +0 -0
- /package/dist/{update-EWGWAXAQ.js.map → update-QYD2XZFM.js.map} +0 -0
- /package/dist/{update-XGCGQDJ4.js.map → update-W2OSRNFO.js.map} +0 -0
- /package/dist/{upload-BOYMDDEQ.js.map → upload-JGBTSKGH.js.map} +0 -0
- /package/dist/{url-options-PCZEQE66.js.map → url-options-QHGA42RP.js.map} +0 -0
- /package/dist/{url-params-DV37GEQF.js.map → url-params-NWSUHWRE.js.map} +0 -0
- /package/dist/{validate-5AV4FJZ5.js.map → validate-VKL3XKQ2.js.map} +0 -0
- /package/dist/{videos-IJ67PPJV.js.map → videos-DP3VCSYG.js.map} +0 -0
- /package/dist/{web-LJ36FRWD.js.map → web-AFUIWPFU.js.map} +0 -0
- /package/dist/{winning-ads-JIG2MQHJ.js.map → winning-ads-PCIJUYVA.js.map} +0 -0
- /package/dist/{write-commands-GOZU6ENR.js.map → write-commands-Q4MQ3BGM.js.map} +0 -0
- /package/dist/{x-6HBVXIKH.js.map → x-AUOZJNWE.js.map} +0 -0
|
@@ -21,12 +21,12 @@ import {
|
|
|
21
21
|
} from "./chunk-PFBQERWX.js";
|
|
22
22
|
import {
|
|
23
23
|
failApi
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-7THBBTJJ.js";
|
|
25
|
+
import "./chunk-SMIENBNX.js";
|
|
26
26
|
import "./chunk-GXDLWBOY.js";
|
|
27
27
|
import "./chunk-GIWHHCD6.js";
|
|
28
28
|
import "./chunk-UI6BKYQD.js";
|
|
29
|
-
import "./chunk-
|
|
29
|
+
import "./chunk-XX6ZMCY5.js";
|
|
30
30
|
import {
|
|
31
31
|
ApiError,
|
|
32
32
|
apiGet,
|
|
@@ -45,168 +45,173 @@ import {
|
|
|
45
45
|
import "./chunk-YQSBHWOI.js";
|
|
46
46
|
|
|
47
47
|
// src/commands/shopify/index.ts
|
|
48
|
-
import { defineCommand as
|
|
48
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
49
49
|
|
|
50
|
-
// src/
|
|
51
|
-
import {
|
|
50
|
+
// ../api/src/shopify/audiences.ts
|
|
51
|
+
import { z } from "zod";
|
|
52
|
+
var SHOPIFY_AUDIENCE_SEGMENTS = ["best", "loyal", "at_risk", "new", "one_time", "all"];
|
|
53
|
+
var shopifyAudienceSegmentSchema = z.enum(SHOPIFY_AUDIENCE_SEGMENTS);
|
|
54
|
+
var shopifyAudiencePlatformSchema = z.enum(["meta", "google"]);
|
|
55
|
+
var shopifyAudienceConsentSchema = z.enum(["marketing_subscribed"]);
|
|
56
|
+
var shopifyAudienceRefreshSchema = z.enum(["daily", "off"]);
|
|
57
|
+
var accountIdSchema = z.string().trim().regex(/^(act_)?\d+$|^\d{3}-?\d{3}-?\d{4}$/, "an ad account id: act_123\u2026 for Meta, 123-456-7890 for Google Ads");
|
|
58
|
+
var shopifyAudienceNameSchema = z.string().trim().min(1).max(120);
|
|
59
|
+
var shopifyAudienceDefinitionSchema = z.object({
|
|
60
|
+
segment: shopifyAudienceSegmentSchema,
|
|
61
|
+
platform: shopifyAudiencePlatformSchema,
|
|
62
|
+
accountId: accountIdSchema,
|
|
63
|
+
/** The audience's name on the platform; default "Shopify: <segment label>". */
|
|
64
|
+
name: shopifyAudienceNameSchema.optional(),
|
|
65
|
+
consent: shopifyAudienceConsentSchema.optional(),
|
|
66
|
+
refresh: shopifyAudienceRefreshSchema.optional()
|
|
67
|
+
}).strict();
|
|
68
|
+
var shopifyAudienceRemovalSchema = z.object({
|
|
69
|
+
/** Leave the audience on the ad platform (with whoever it holds) and only stop updating it. */
|
|
70
|
+
keepOnPlatform: z.boolean().optional()
|
|
71
|
+
}).strict();
|
|
72
|
+
var shopifyAudienceCountsSchema = z.object({
|
|
73
|
+
people: z.number(),
|
|
74
|
+
withConsent: z.number(),
|
|
75
|
+
willSend: z.number(),
|
|
76
|
+
emails: z.number(),
|
|
77
|
+
phones: z.number(),
|
|
78
|
+
largestCountry: z.object({ country: z.string(), people: z.number() }).nullable()
|
|
79
|
+
});
|
|
80
|
+
var shopifyAudienceCreateRequestSchema = z.object({
|
|
81
|
+
chatId: z.string(),
|
|
82
|
+
definition: shopifyAudienceDefinitionSchema
|
|
83
|
+
});
|
|
84
|
+
var shopifyAudienceCreateResponseSchema = z.object({
|
|
85
|
+
ref: z.string(),
|
|
86
|
+
staged: z.literal(true),
|
|
87
|
+
summary: z.string(),
|
|
88
|
+
platform: shopifyAudiencePlatformSchema,
|
|
89
|
+
accountId: z.string(),
|
|
90
|
+
counts: shopifyAudienceCountsSchema,
|
|
91
|
+
warnings: z.array(z.string())
|
|
92
|
+
});
|
|
93
|
+
var shopifyAudienceStatusSchema = z.enum(["active", "stopped", "removed"]);
|
|
94
|
+
var shopifyAudienceRunSchema = z.object({
|
|
95
|
+
at: z.number(),
|
|
96
|
+
outcome: z.enum(["sent", "failed"]),
|
|
97
|
+
people: z.number(),
|
|
98
|
+
withConsent: z.number(),
|
|
99
|
+
sent: z.number(),
|
|
100
|
+
/** What the platform said it could not use, when it says (Meta). */
|
|
101
|
+
invalid: z.number().optional(),
|
|
102
|
+
error: z.string().optional()
|
|
103
|
+
});
|
|
104
|
+
var shopifyAudienceViewSchema = z.object({
|
|
105
|
+
id: z.string(),
|
|
106
|
+
name: z.string(),
|
|
107
|
+
segment: shopifyAudienceSegmentSchema,
|
|
108
|
+
platform: shopifyAudiencePlatformSchema,
|
|
109
|
+
accountId: z.string(),
|
|
110
|
+
platformAudienceId: z.string(),
|
|
111
|
+
refresh: shopifyAudienceRefreshSchema,
|
|
112
|
+
status: shopifyAudienceStatusSchema,
|
|
113
|
+
stoppedBecause: z.string().optional(),
|
|
114
|
+
lastRun: shopifyAudienceRunSchema.optional(),
|
|
115
|
+
/** Full only. */
|
|
116
|
+
createdAt: z.number().optional(),
|
|
117
|
+
consent: shopifyAudienceConsentSchema.optional()
|
|
118
|
+
});
|
|
119
|
+
var shopifyAudienceListRequestSchema = z.object({
|
|
120
|
+
chatId: z.string().optional(),
|
|
121
|
+
full: z.coerce.boolean().optional()
|
|
122
|
+
});
|
|
123
|
+
var shopifyAudienceListResponseSchema = z.object({
|
|
124
|
+
audiences: z.array(shopifyAudienceViewSchema),
|
|
125
|
+
/** This chat's staged audience changes, not yet published. */
|
|
126
|
+
staged: z.array(z.object({ ref: z.string(), kind: z.string(), summary: z.string() }))
|
|
127
|
+
});
|
|
128
|
+
var shopifyAudienceRemoveRequestSchema = z.object({
|
|
129
|
+
chatId: z.string(),
|
|
130
|
+
id: z.string().min(1),
|
|
131
|
+
keepOnPlatform: z.boolean().optional()
|
|
132
|
+
});
|
|
133
|
+
var shopifyAudienceRemoveResponseSchema = z.object({
|
|
134
|
+
ref: z.string(),
|
|
135
|
+
staged: z.literal(true),
|
|
136
|
+
summary: z.string()
|
|
137
|
+
});
|
|
138
|
+
var shopifyAudienceRefreshRequestSchema = z.object({ id: z.string().min(1) });
|
|
139
|
+
var shopifyAudienceRefreshResponseSchema = z.object({
|
|
140
|
+
id: z.string(),
|
|
141
|
+
status: z.literal("running")
|
|
142
|
+
});
|
|
143
|
+
var SHOPIFY_AUDIENCE_PROTECTED_DATA_PREFIX = "Shopify hasn't approved Baker to read buyers' emails and phones";
|
|
144
|
+
var SHOPIFY_AUDIENCE_TERMS_PREFIX = "This ad account hasn't accepted";
|
|
52
145
|
|
|
53
|
-
// src/commands/shopify/
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const hints = [];
|
|
62
|
-
if (history.state === "importing") {
|
|
63
|
-
hints.push(
|
|
64
|
-
`Baker is still bringing in this store's past orders (${history.orders} so far): older periods, repeat buyers and cohorts are incomplete \u2014 say so rather than reporting a drop.`
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
if (history.state === "failed") {
|
|
68
|
-
hints.push("Baker couldn't finish bringing in this store's past orders; older periods may be incomplete.");
|
|
69
|
-
}
|
|
70
|
-
if (basis === "last_60_days") {
|
|
71
|
-
hints.push(
|
|
72
|
-
"Shopify gives Baker this store's last 60 days of orders only: older behaviour is not here, and a buyer whose earlier orders are older counts as new."
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
return hints;
|
|
76
|
-
}
|
|
77
|
-
function countriesHints(answer) {
|
|
78
|
-
const hints = buyerHistoryHints(answer.history, answer.basis);
|
|
79
|
-
if (answer.total.orders === 0) {
|
|
80
|
-
hints.push("No orders were placed in this period.");
|
|
81
|
-
return hints;
|
|
82
|
-
}
|
|
83
|
-
hints.push(storeFactsHint(answer.currency));
|
|
84
|
-
const money = (amount) => `${answer.currency ?? ""} ${amount}`.trim();
|
|
85
|
-
const growing = answer.rows.filter((row) => row.orders >= MIN_ORDERS_TO_SCALE && (row.ordersGrowth ?? 0) > 0).sort((a, b) => (b.ordersGrowth ?? 0) - (a.ordersGrowth ?? 0))[0];
|
|
86
|
-
if (growing && answer.level === "country") {
|
|
87
|
-
hints.push(
|
|
88
|
-
`Scale ${growing.name}: its orders grew ${percent(growing.ordersGrowth ?? 0)} against the period before (${growing.orders} orders, ${money(growing.net)}). Check which campaigns already target it (\`baker ads meta campaigns\`, \`baker ads google query --preset campaign-performance\`) before staging a change.`
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
const average = answer.total.averageOrder;
|
|
92
|
-
const promising = answer.rows.filter((row) => row.orders < MIN_ORDERS_TO_SCALE && average > 0 && row.averageOrder >= 1.5 * average).sort((a, b) => b.averageOrder - a.averageOrder)[0];
|
|
93
|
-
if (promising && answer.level === "country") {
|
|
94
|
-
hints.push(
|
|
95
|
-
`Test ${promising.name}: its average order is ${money(promising.averageOrder)}, ${(promising.averageOrder / average).toFixed(1)}\xD7 the store's, from only ${promising.orders} orders \u2014 a small budget there would show whether it scales.`
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
if (answer.unknown && answer.total.orders > 0 && answer.unknown.orders / answer.total.orders > 0.25) {
|
|
99
|
-
const lack = answer.level === "country" ? "have no address Baker could read (Unknown)" : `name no ${answer.level} on their address (${answer.unknown.name})`;
|
|
100
|
-
hints.push(
|
|
101
|
-
`${answer.unknown.orders} of these orders ${lack}: say so rather than leaving them out of a place's share.`
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
return hints;
|
|
105
|
-
}
|
|
106
|
-
function bestSellersHints(answer) {
|
|
107
|
-
const hints = buyerHistoryHints(answer.history, answer.basis);
|
|
108
|
-
const leader = answer.repeat?.[0];
|
|
109
|
-
if (leader && leader.buyersAgain > 0) {
|
|
110
|
-
hints.push(
|
|
111
|
-
`Lead a landing with "${leader.title}" (find it with \`baker shopify products --search\`): ${percent(leader.share)} of the buyers whose first order held it came back.`
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
const top = answer.products?.[0];
|
|
115
|
-
if (top && top.units > 0) {
|
|
116
|
-
hints.push(
|
|
117
|
-
`"${top.title}" is the best seller (${top.units} units). For which first buys bring buyers back, run \`baker shopify best-sellers --view repeat\`; for what is losing steam, \`--view momentum\`.`
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
const losing = answer.momentum?.[0];
|
|
121
|
-
if (losing) {
|
|
122
|
-
hints.push(
|
|
123
|
-
`"${losing.title}" sold ${losing.units} against ${losing.previousUnits} the period before: check its stock (\`baker shopify stock\`) and the ads that promote it before cutting it.`
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
const sellers = answer.products ?? answer.variants ?? [];
|
|
127
|
-
if (sellers.some((row) => row.units > 0)) hints.push(storeFactsHint(answer.currency));
|
|
128
|
-
const withRefunds = sellers.filter((row) => row.refundedUnits > 0).sort((a, b) => b.refundRate - a.refundRate).slice(0, 5);
|
|
129
|
-
if (withRefunds.length > 0) {
|
|
130
|
-
const money = (amount) => `${answer.currency ?? ""} ${amount}`.trim();
|
|
131
|
-
hints.push(
|
|
132
|
-
`Refunds: ${withRefunds.map((row) => `"${row.title}" ${percent(row.refundRate)} of units (${money(row.refunded)})`).join(", ")}. Only a product not named here had no refunds in the period.`
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
const refunded = answer.products?.find((row) => row.units >= 5 && row.refundRate >= 0.2);
|
|
136
|
-
if (refunded) {
|
|
137
|
-
hints.push(
|
|
138
|
-
`"${refunded.title}" comes back often (${percent(refunded.refundRate)} of units refunded): don't lead a campaign with it before finding out why.`
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
return hints;
|
|
142
|
-
}
|
|
143
|
-
function bestBuyersHint(best) {
|
|
144
|
-
if (!best || best.buyers === 0) return [];
|
|
145
|
-
const countries = best.topCountries.map((country) => country.name).join(", ");
|
|
146
|
-
const products = best.topFirstProducts.map((product) => `"${product.title}"`).join(", ");
|
|
147
|
-
if (!countries && !products) return [];
|
|
148
|
-
return [
|
|
149
|
-
`Find more buyers like your best (${best.buyers}): ${countries ? `target ${countries}` : ""}${countries && products ? "; " : ""}${products ? `lead with ${products}, what their first orders held` : ""}.`
|
|
146
|
+
// src/commands/shopify/audiences.ts
|
|
147
|
+
import { defineCommand as defineCommand2 } from "citty";
|
|
148
|
+
|
|
149
|
+
// src/commands/shopify/audienceHints.ts
|
|
150
|
+
var LOOKALIKE_MIN = 100;
|
|
151
|
+
function audienceCreateHints(answer) {
|
|
152
|
+
const hints = [
|
|
153
|
+
`Staged on this chat until Publish: nothing is sent before the user publishes it. Tell them the audience will hold ${answer.counts.willSend} of the ${answer.counts.people} buyers in this group \u2014 only people who accept marketing.`
|
|
150
154
|
];
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
const largest = answer.counts.largestCountry;
|
|
156
|
+
if (answer.platform === "meta") {
|
|
157
|
+
if (!largest || largest.people < LOOKALIKE_MIN) {
|
|
158
|
+
hints.push(
|
|
159
|
+
`A lookalike needs at least 100 people from one country in its source; this sends ${largest ? `${largest.people} from ${largest.country}` : "nobody with a known country"}. Don't stage a lookalike of it yet \u2014 it grows as more buyers subscribe.`
|
|
160
|
+
);
|
|
161
|
+
} else {
|
|
162
|
+
hints.push(
|
|
163
|
+
`To reach people like them, stage a lookalike of this audience once it is published: \`baker ads meta audiences create --subtype LOOKALIKE\` with the audience's id from \`baker shopify audiences list\` (country ${largest.country}).`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
160
166
|
}
|
|
161
|
-
if (answer.buyers > 0) hints.push(AUDIENCE_PATH);
|
|
162
167
|
return hints;
|
|
163
168
|
}
|
|
164
|
-
function
|
|
165
|
-
const hints =
|
|
166
|
-
if (answer.
|
|
167
|
-
hints.push("No orders were placed in this period.");
|
|
168
|
-
return hints;
|
|
169
|
-
}
|
|
170
|
-
hints.push(storeFactsHint(answer.currency));
|
|
171
|
-
if (answer.acquisition?.by === "campaign" && answer.acquisition.rows.length > 0) {
|
|
172
|
-
hints.push(
|
|
173
|
-
"Compare each campaign's lifetime value with what it cost for the same dates (`baker ads meta insights`, `baker ads google query --preset campaign-performance`): Baker keeps no ad spend."
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
if (!answer.acquisition) {
|
|
177
|
-
hints.push(
|
|
178
|
-
"For lifetime value by the campaign or channel that brought each buyer, add `--by campaign` or `--by channel`."
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
if (answer.summary.guestOrders > 0 && answer.summary.guestOrders >= answer.summary.orders / 2) {
|
|
169
|
+
function audienceListHints(answer) {
|
|
170
|
+
const hints = [];
|
|
171
|
+
if (answer.audiences.length === 0 && answer.staged.length === 0) {
|
|
182
172
|
hints.push(
|
|
183
|
-
|
|
173
|
+
"No buyer audience yet. Stage one with `baker shopify audiences create --segment <best|loyal|at_risk|new|one_time|all> --to meta|google --account-id <id>`."
|
|
184
174
|
);
|
|
185
175
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
function cohortsHints(answer) {
|
|
190
|
-
const hints = buyerHistoryHints(answer.history, answer.basis);
|
|
191
|
-
const reached = answer.cohorts.filter((cohort) => cohort.retention.m3 !== null && cohort.size >= 5);
|
|
192
|
-
if (reached.length >= 2) {
|
|
193
|
-
const best = [...reached].sort((a, b) => (b.retention.m3 ?? 0) - (a.retention.m3 ?? 0))[0];
|
|
194
|
-
if (best) {
|
|
176
|
+
for (const audience of answer.audiences) {
|
|
177
|
+
if (audience.lastRun?.outcome === "failed") {
|
|
195
178
|
hints.push(
|
|
196
|
-
`
|
|
179
|
+
`"${audience.name}" did not update last time: ${audience.lastRun.error ?? "the ad platform refused"}. Say so in plain words; \`baker shopify audiences refresh ${audience.id}\` tries again.`
|
|
197
180
|
);
|
|
198
181
|
}
|
|
199
182
|
}
|
|
200
183
|
return hints;
|
|
201
184
|
}
|
|
185
|
+
function audienceRefusal(code, message) {
|
|
186
|
+
if (code !== "FORBIDDEN") return null;
|
|
187
|
+
if (message.startsWith(SHOPIFY_AUDIENCE_PROTECTED_DATA_PREFIX)) {
|
|
188
|
+
return {
|
|
189
|
+
code: "SHOPIFY_CUSTOMER_DATA_NOT_APPROVED",
|
|
190
|
+
fix: {
|
|
191
|
+
action: "continue_without",
|
|
192
|
+
explanation: "Shopify hasn't approved Baker to read buyers' emails and phones, so no buyer audience can be made for this store yet; the user cannot change that from the chat. Say so plainly, offer an audience of the store's purchasers seen on the website instead (`baker ads meta audiences create --subtype WEBSITE`), and finish the rest of the task."
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (message.startsWith(SHOPIFY_AUDIENCE_TERMS_PREFIX)) {
|
|
197
|
+
return {
|
|
198
|
+
code: "AD_ACCOUNT_TERMS_NOT_ACCEPTED",
|
|
199
|
+
fix: {
|
|
200
|
+
action: "ask_user",
|
|
201
|
+
explanation: "The ad account has not accepted the platform's customer list terms, which only an admin of the account can do. Give the user the link or place from the message, ask them to accept the terms, and stage the audience again once they say they have. Keep going with the rest of the task meanwhile."
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
202
207
|
|
|
203
208
|
// ../api/src/shopify/buyers.ts
|
|
204
|
-
import { z } from "zod";
|
|
205
|
-
var flag =
|
|
209
|
+
import { z as z2 } from "zod";
|
|
210
|
+
var flag = z2.enum(["true", "false"]).transform((value) => value === "true");
|
|
206
211
|
var SHOPIFY_STORE_WINDOW_MAX_DAYS = 3650;
|
|
207
|
-
var days =
|
|
208
|
-
var countryCode =
|
|
209
|
-
var limit =
|
|
212
|
+
var days = z2.coerce.number().int().min(1).max(SHOPIFY_STORE_WINDOW_MAX_DAYS);
|
|
213
|
+
var countryCode = z2.string().regex(/^[A-Za-z]{2}$/, "a two-letter country code, like DE").transform((value) => value.toUpperCase());
|
|
214
|
+
var limit = z2.coerce.number().int().min(1).max(100);
|
|
210
215
|
var windowRequest = {
|
|
211
216
|
days: days.optional(),
|
|
212
217
|
/** Every order the store has. */
|
|
@@ -214,366 +219,366 @@ var windowRequest = {
|
|
|
214
219
|
country: countryCode.optional(),
|
|
215
220
|
full: flag.optional()
|
|
216
221
|
};
|
|
217
|
-
var shopifyStoreWindowSchema =
|
|
218
|
-
from:
|
|
219
|
-
to:
|
|
220
|
-
days:
|
|
221
|
-
timezone:
|
|
222
|
-
});
|
|
223
|
-
var shopifyBuyerHistorySchema =
|
|
224
|
-
state:
|
|
225
|
-
reach:
|
|
222
|
+
var shopifyStoreWindowSchema = z2.object({
|
|
223
|
+
from: z2.string().nullable(),
|
|
224
|
+
to: z2.string(),
|
|
225
|
+
days: z2.union([z2.number(), z2.literal("all")]),
|
|
226
|
+
timezone: z2.string()
|
|
227
|
+
});
|
|
228
|
+
var shopifyBuyerHistorySchema = z2.object({
|
|
229
|
+
state: z2.enum(["importing", "done", "failed", "none"]),
|
|
230
|
+
reach: z2.enum(["all", "60_days"]).nullable(),
|
|
226
231
|
/** The day of the oldest order Baker holds (YYYY-MM-DD). */
|
|
227
|
-
from:
|
|
232
|
+
from: z2.string().nullable(),
|
|
228
233
|
/** Orders brought in so far. */
|
|
229
|
-
orders:
|
|
234
|
+
orders: z2.number()
|
|
230
235
|
});
|
|
231
|
-
var shopifyBuyerBasisSchema =
|
|
236
|
+
var shopifyBuyerBasisSchema = z2.enum(["all_orders", "last_60_days"]);
|
|
232
237
|
var answerCommon = {
|
|
233
238
|
store: shopifyStoreStateSchema,
|
|
234
239
|
window: shopifyStoreWindowSchema,
|
|
235
240
|
/** The store's currency; null when it has no orders yet. */
|
|
236
|
-
currency:
|
|
241
|
+
currency: z2.string().nullable(),
|
|
237
242
|
/** Orders in another currency (the store changed currency), never added to these. */
|
|
238
|
-
otherCurrencies:
|
|
243
|
+
otherCurrencies: z2.array(z2.object({ currency: z2.string(), orders: z2.number(), net: z2.number() })).optional(),
|
|
239
244
|
history: shopifyBuyerHistorySchema,
|
|
240
245
|
basis: shopifyBuyerBasisSchema
|
|
241
246
|
};
|
|
242
|
-
var shopifyPlaceSchema =
|
|
243
|
-
country:
|
|
244
|
-
countryName:
|
|
245
|
-
region:
|
|
246
|
-
city:
|
|
247
|
-
});
|
|
248
|
-
var shopifyBuyerSegmentSchema =
|
|
249
|
-
var shopifySegmentThresholdsSchema =
|
|
247
|
+
var shopifyPlaceSchema = z2.object({
|
|
248
|
+
country: z2.string(),
|
|
249
|
+
countryName: z2.string(),
|
|
250
|
+
region: z2.string(),
|
|
251
|
+
city: z2.string()
|
|
252
|
+
});
|
|
253
|
+
var shopifyBuyerSegmentSchema = z2.enum(["best", "loyal", "at_risk", "new", "one_time"]);
|
|
254
|
+
var shopifySegmentThresholdsSchema = z2.object({
|
|
250
255
|
/** The store's typical days between a repeat buyer's orders (90 with too few to go on). */
|
|
251
|
-
gapDays:
|
|
256
|
+
gapDays: z2.number(),
|
|
252
257
|
/** The lifetime net that puts a buyer in the top fifth. */
|
|
253
|
-
netP80:
|
|
258
|
+
netP80: z2.number()
|
|
254
259
|
});
|
|
255
|
-
var shopifySegmentRowSchema =
|
|
260
|
+
var shopifySegmentRowSchema = z2.object({
|
|
256
261
|
segment: shopifyBuyerSegmentSchema,
|
|
257
|
-
label:
|
|
262
|
+
label: z2.string(),
|
|
258
263
|
/** The rule in words, with this store's numbers. */
|
|
259
|
-
rule:
|
|
260
|
-
buyers:
|
|
264
|
+
rule: z2.string(),
|
|
265
|
+
buyers: z2.number(),
|
|
261
266
|
/** Of every buyer, 0–1. */
|
|
262
|
-
share:
|
|
263
|
-
net:
|
|
264
|
-
averageOrders:
|
|
265
|
-
averageDaysSinceLastOrder:
|
|
266
|
-
topCountries:
|
|
267
|
+
share: z2.number(),
|
|
268
|
+
net: z2.number(),
|
|
269
|
+
averageOrders: z2.number(),
|
|
270
|
+
averageDaysSinceLastOrder: z2.number(),
|
|
271
|
+
topCountries: z2.array(z2.object({ code: z2.string(), name: z2.string(), buyers: z2.number() })),
|
|
267
272
|
/** The products their first orders held most often. */
|
|
268
|
-
topFirstProducts:
|
|
273
|
+
topFirstProducts: z2.array(z2.object({ title: z2.string(), buyers: z2.number(), productId: z2.string().optional() }))
|
|
269
274
|
});
|
|
270
|
-
var shopifySegmentsRequestSchema =
|
|
271
|
-
var shopifySegmentsResponseSchema =
|
|
275
|
+
var shopifySegmentsRequestSchema = z2.object({ ...windowRequest });
|
|
276
|
+
var shopifySegmentsResponseSchema = z2.object({
|
|
272
277
|
...answerCommon,
|
|
273
278
|
thresholds: shopifySegmentThresholdsSchema,
|
|
274
|
-
buyers:
|
|
275
|
-
segments:
|
|
279
|
+
buyers: z2.number(),
|
|
280
|
+
segments: z2.array(shopifySegmentRowSchema)
|
|
276
281
|
});
|
|
277
|
-
var shopifyBuyersSortSchema =
|
|
278
|
-
var shopifyAcquisitionBySchema =
|
|
279
|
-
var shopifyBuyersRequestSchema =
|
|
282
|
+
var shopifyBuyersSortSchema = z2.enum(["net", "orders", "recent", "first"]);
|
|
283
|
+
var shopifyAcquisitionBySchema = z2.enum(["campaign", "channel"]);
|
|
284
|
+
var shopifyBuyersRequestSchema = z2.object({
|
|
280
285
|
...windowRequest,
|
|
281
286
|
segment: shopifyBuyerSegmentSchema.optional(),
|
|
282
287
|
/** Lifetime value by the campaign or channel of each buyer's first order. */
|
|
283
288
|
by: shopifyAcquisitionBySchema.optional(),
|
|
284
289
|
/** Only buyers whose first order came through this channel (a key from `by=channel`). */
|
|
285
|
-
channel:
|
|
290
|
+
channel: z2.string().max(200).optional(),
|
|
286
291
|
sort: shopifyBuyersSortSchema.optional(),
|
|
287
292
|
limit: limit.optional(),
|
|
288
|
-
offset:
|
|
293
|
+
offset: z2.coerce.number().int().min(0).max(1e5).optional()
|
|
289
294
|
});
|
|
290
|
-
var shopifyBuyersSummarySchema =
|
|
295
|
+
var shopifyBuyersSummarySchema = z2.object({
|
|
291
296
|
/** Buyers who ordered in the period. */
|
|
292
|
-
buyers:
|
|
297
|
+
buyers: z2.number(),
|
|
293
298
|
/** Of them, whose first order was in the period. */
|
|
294
|
-
newBuyers:
|
|
295
|
-
returningBuyers:
|
|
299
|
+
newBuyers: z2.number(),
|
|
300
|
+
returningBuyers: z2.number(),
|
|
296
301
|
/** Orders with no customer: counted in money, never a buyer. */
|
|
297
|
-
guestOrders:
|
|
298
|
-
orders:
|
|
299
|
-
net:
|
|
300
|
-
averageOrder:
|
|
302
|
+
guestOrders: z2.number(),
|
|
303
|
+
orders: z2.number(),
|
|
304
|
+
net: z2.number(),
|
|
305
|
+
averageOrder: z2.number(),
|
|
301
306
|
/** Orders that were their buyer's first, and the rest (Shopify's new vs returning). */
|
|
302
|
-
newOrders:
|
|
303
|
-
returningOrders:
|
|
304
|
-
newNet:
|
|
305
|
-
returningNet:
|
|
307
|
+
newOrders: z2.number(),
|
|
308
|
+
returningOrders: z2.number(),
|
|
309
|
+
newNet: z2.number(),
|
|
310
|
+
returningNet: z2.number(),
|
|
306
311
|
/** Of every buyer up to the period's end, the share who ordered again (0–1). */
|
|
307
|
-
repeatRate:
|
|
312
|
+
repeatRate: z2.number(),
|
|
308
313
|
/** Median days from a buyer's first order to their second; null when nobody ordered twice. */
|
|
309
|
-
medianDaysToSecond:
|
|
314
|
+
medianDaysToSecond: z2.number().nullable()
|
|
310
315
|
});
|
|
311
|
-
var shopifyCameFromSchema =
|
|
312
|
-
channel:
|
|
313
|
-
label:
|
|
314
|
-
campaign:
|
|
316
|
+
var shopifyCameFromSchema = z2.object({
|
|
317
|
+
channel: z2.string(),
|
|
318
|
+
label: z2.string(),
|
|
319
|
+
campaign: z2.string().optional(),
|
|
315
320
|
// --full
|
|
316
|
-
source:
|
|
317
|
-
medium:
|
|
318
|
-
clickPlatform:
|
|
319
|
-
landingId:
|
|
321
|
+
source: z2.string().optional(),
|
|
322
|
+
medium: z2.string().optional(),
|
|
323
|
+
clickPlatform: z2.string().optional(),
|
|
324
|
+
landingId: z2.string().optional()
|
|
320
325
|
});
|
|
321
|
-
var shopifyBuyerRowSchema =
|
|
322
|
-
number:
|
|
326
|
+
var shopifyBuyerRowSchema = z2.object({
|
|
327
|
+
number: z2.number(),
|
|
323
328
|
/** "Customer #1042". */
|
|
324
|
-
label:
|
|
329
|
+
label: z2.string(),
|
|
325
330
|
place: shopifyPlaceSchema.nullable(),
|
|
326
|
-
orders:
|
|
327
|
-
net:
|
|
328
|
-
firstOrderAt:
|
|
329
|
-
lastOrderAt:
|
|
331
|
+
orders: z2.number(),
|
|
332
|
+
net: z2.number(),
|
|
333
|
+
firstOrderAt: z2.string(),
|
|
334
|
+
lastOrderAt: z2.string(),
|
|
330
335
|
segment: shopifyBuyerSegmentSchema,
|
|
331
336
|
cameFrom: shopifyCameFromSchema,
|
|
332
337
|
// --full
|
|
333
|
-
gross:
|
|
334
|
-
refunded:
|
|
335
|
-
ordersWithDiscount:
|
|
336
|
-
averageDaysBetweenOrders:
|
|
337
|
-
});
|
|
338
|
-
var shopifyAcquisitionRowSchema =
|
|
339
|
-
key:
|
|
340
|
-
label:
|
|
341
|
-
buyers:
|
|
338
|
+
gross: z2.number().optional(),
|
|
339
|
+
refunded: z2.number().optional(),
|
|
340
|
+
ordersWithDiscount: z2.number().optional(),
|
|
341
|
+
averageDaysBetweenOrders: z2.number().nullable().optional()
|
|
342
|
+
});
|
|
343
|
+
var shopifyAcquisitionRowSchema = z2.object({
|
|
344
|
+
key: z2.string(),
|
|
345
|
+
label: z2.string(),
|
|
346
|
+
buyers: z2.number(),
|
|
342
347
|
/** What their first orders came to. */
|
|
343
|
-
firstNet:
|
|
348
|
+
firstNet: z2.number(),
|
|
344
349
|
/** What they have spent since, to date. */
|
|
345
|
-
lifetimeNet:
|
|
346
|
-
lifetimePerBuyer:
|
|
347
|
-
averageOrders:
|
|
348
|
-
repeatRate:
|
|
350
|
+
lifetimeNet: z2.number(),
|
|
351
|
+
lifetimePerBuyer: z2.number(),
|
|
352
|
+
averageOrders: z2.number(),
|
|
353
|
+
repeatRate: z2.number(),
|
|
349
354
|
// --full
|
|
350
|
-
source:
|
|
351
|
-
medium:
|
|
352
|
-
campaign:
|
|
353
|
-
clickPlatform:
|
|
355
|
+
source: z2.string().optional(),
|
|
356
|
+
medium: z2.string().optional(),
|
|
357
|
+
campaign: z2.string().optional(),
|
|
358
|
+
clickPlatform: z2.string().optional()
|
|
354
359
|
});
|
|
355
|
-
var shopifyBuyersResponseSchema =
|
|
360
|
+
var shopifyBuyersResponseSchema = z2.object({
|
|
356
361
|
...answerCommon,
|
|
357
362
|
summary: shopifyBuyersSummarySchema,
|
|
358
363
|
thresholds: shopifySegmentThresholdsSchema,
|
|
359
|
-
segments:
|
|
364
|
+
segments: z2.array(z2.object({ segment: shopifyBuyerSegmentSchema, label: z2.string(), buyers: z2.number() })),
|
|
360
365
|
/** Buyers matching the filters, before the limit. */
|
|
361
|
-
total:
|
|
362
|
-
buyers:
|
|
363
|
-
acquisition:
|
|
366
|
+
total: z2.number(),
|
|
367
|
+
buyers: z2.array(shopifyBuyerRowSchema),
|
|
368
|
+
acquisition: z2.object({ by: shopifyAcquisitionBySchema, rows: z2.array(shopifyAcquisitionRowSchema) }).optional()
|
|
364
369
|
});
|
|
365
|
-
var shopifyBuyerNumberSchema =
|
|
366
|
-
var shopifyBuyerRequestSchema =
|
|
370
|
+
var shopifyBuyerNumberSchema = z2.string().trim().transform((value) => value.replace(/^customer\s*/i, "").replace(/^#/, "")).pipe(z2.string().regex(/^\d+$/, "a buyer's number, like 1042 or #1042")).transform((value) => Number(value)).pipe(z2.number().int().min(1).max(4e9));
|
|
371
|
+
var shopifyBuyerRequestSchema = z2.object({ number: shopifyBuyerNumberSchema, full: flag.optional() });
|
|
367
372
|
var SHOPIFY_BUYER_GONE_MESSAGE = "This buyer is no longer in Baker.";
|
|
368
|
-
var shopifyBuyerOrderSchema =
|
|
369
|
-
name:
|
|
373
|
+
var shopifyBuyerOrderSchema = z2.object({
|
|
374
|
+
name: z2.string(),
|
|
370
375
|
/** When it was placed, in the store's time (YYYY-MM-DD HH:MM). */
|
|
371
|
-
placedAt:
|
|
372
|
-
net:
|
|
373
|
-
gross:
|
|
374
|
-
refunded:
|
|
375
|
-
products:
|
|
376
|
-
discountCodes:
|
|
376
|
+
placedAt: z2.string(),
|
|
377
|
+
net: z2.number(),
|
|
378
|
+
gross: z2.number(),
|
|
379
|
+
refunded: z2.number(),
|
|
380
|
+
products: z2.array(z2.object({ title: z2.string(), quantity: z2.number() })),
|
|
381
|
+
discountCodes: z2.array(z2.string()),
|
|
377
382
|
place: shopifyPlaceSchema.nullable(),
|
|
378
383
|
/** Placed before Baker measured the store: counted, credited to no campaign. */
|
|
379
|
-
beforeBaker:
|
|
384
|
+
beforeBaker: z2.boolean(),
|
|
380
385
|
// --full
|
|
381
|
-
orderId:
|
|
382
|
-
items:
|
|
383
|
-
refundedItems:
|
|
386
|
+
orderId: z2.string().optional(),
|
|
387
|
+
items: z2.array(z2.object({ productId: z2.string(), variantId: z2.string(), quantity: z2.number(), amount: z2.number() })).optional(),
|
|
388
|
+
refundedItems: z2.array(z2.object({ productId: z2.string(), variantId: z2.string(), quantity: z2.number(), amount: z2.number() })).optional(),
|
|
384
389
|
cameFrom: shopifyCameFromSchema.optional()
|
|
385
390
|
});
|
|
386
|
-
var shopifyBuyerProfileSchema =
|
|
387
|
-
number:
|
|
388
|
-
label:
|
|
391
|
+
var shopifyBuyerProfileSchema = z2.object({
|
|
392
|
+
number: z2.number(),
|
|
393
|
+
label: z2.string(),
|
|
389
394
|
place: shopifyPlaceSchema.nullable(),
|
|
390
|
-
orders:
|
|
391
|
-
gross:
|
|
392
|
-
refunded:
|
|
393
|
-
net:
|
|
394
|
-
averageOrder:
|
|
395
|
+
orders: z2.number(),
|
|
396
|
+
gross: z2.number(),
|
|
397
|
+
refunded: z2.number(),
|
|
398
|
+
net: z2.number(),
|
|
399
|
+
averageOrder: z2.number(),
|
|
395
400
|
/** Average days between their orders; null with one order. */
|
|
396
|
-
averageDaysBetweenOrders:
|
|
397
|
-
firstOrderAt:
|
|
398
|
-
lastOrderAt:
|
|
399
|
-
ordersWithDiscount:
|
|
401
|
+
averageDaysBetweenOrders: z2.number().nullable(),
|
|
402
|
+
firstOrderAt: z2.string(),
|
|
403
|
+
lastOrderAt: z2.string(),
|
|
404
|
+
ordersWithDiscount: z2.number(),
|
|
400
405
|
segment: shopifyBuyerSegmentSchema,
|
|
401
|
-
segmentLabel:
|
|
406
|
+
segmentLabel: z2.string(),
|
|
402
407
|
cameFrom: shopifyCameFromSchema
|
|
403
408
|
});
|
|
404
|
-
var shopifyBuyerResponseSchema =
|
|
409
|
+
var shopifyBuyerResponseSchema = z2.object({
|
|
405
410
|
...answerCommon,
|
|
406
411
|
buyer: shopifyBuyerProfileSchema,
|
|
407
412
|
/** Newest first. */
|
|
408
|
-
orders:
|
|
409
|
-
products:
|
|
410
|
-
|
|
413
|
+
orders: z2.array(shopifyBuyerOrderSchema),
|
|
414
|
+
products: z2.array(
|
|
415
|
+
z2.object({ title: z2.string(), quantity: z2.number(), orders: z2.number(), productId: z2.string().optional() })
|
|
411
416
|
)
|
|
412
417
|
});
|
|
413
|
-
var shopifyCountriesRequestSchema =
|
|
418
|
+
var shopifyCountriesRequestSchema = z2.object({
|
|
414
419
|
...windowRequest,
|
|
415
420
|
/** Inside one region of `country` (its code or name): its cities. */
|
|
416
|
-
region:
|
|
421
|
+
region: z2.string().max(100).optional(),
|
|
417
422
|
/** Only orders holding this product (its id or handle); money is that product's lines. */
|
|
418
|
-
product:
|
|
423
|
+
product: z2.string().max(255).optional(),
|
|
419
424
|
limit: limit.optional()
|
|
420
425
|
});
|
|
421
|
-
var shopifyPlaceRowSchema =
|
|
426
|
+
var shopifyPlaceRowSchema = z2.object({
|
|
422
427
|
/** A country code, a region code (or name) or a city. */
|
|
423
|
-
key:
|
|
424
|
-
name:
|
|
425
|
-
orders:
|
|
426
|
-
buyers:
|
|
427
|
-
newBuyers:
|
|
428
|
-
net:
|
|
429
|
-
averageOrder:
|
|
428
|
+
key: z2.string(),
|
|
429
|
+
name: z2.string(),
|
|
430
|
+
orders: z2.number(),
|
|
431
|
+
buyers: z2.number(),
|
|
432
|
+
newBuyers: z2.number(),
|
|
433
|
+
net: z2.number(),
|
|
434
|
+
averageOrder: z2.number(),
|
|
430
435
|
/** Of the total's net, 0–1. */
|
|
431
|
-
share:
|
|
436
|
+
share: z2.number(),
|
|
432
437
|
/** Net against the period before; null when there was none before. */
|
|
433
|
-
growth:
|
|
434
|
-
ordersGrowth:
|
|
438
|
+
growth: z2.number().nullable(),
|
|
439
|
+
ordersGrowth: z2.number().nullable(),
|
|
435
440
|
/** The currency its buyers paid in most. */
|
|
436
|
-
paidIn:
|
|
441
|
+
paidIn: z2.string(),
|
|
437
442
|
// --full
|
|
438
|
-
previousNet:
|
|
439
|
-
previousOrders:
|
|
443
|
+
previousNet: z2.number().optional(),
|
|
444
|
+
previousOrders: z2.number().optional()
|
|
440
445
|
});
|
|
441
|
-
var shopifyCountriesResponseSchema =
|
|
446
|
+
var shopifyCountriesResponseSchema = z2.object({
|
|
442
447
|
...answerCommon,
|
|
443
|
-
level:
|
|
444
|
-
country:
|
|
445
|
-
region:
|
|
446
|
-
product:
|
|
448
|
+
level: z2.enum(["country", "region", "city"]),
|
|
449
|
+
country: z2.string().optional(),
|
|
450
|
+
region: z2.string().optional(),
|
|
451
|
+
product: z2.object({ id: z2.string(), title: z2.string() }).optional(),
|
|
447
452
|
total: shopifyPlaceRowSchema,
|
|
448
453
|
/** Named places, best first; with `unknown` and `other` they add up to `total`. */
|
|
449
|
-
rows:
|
|
454
|
+
rows: z2.array(shopifyPlaceRowSchema),
|
|
450
455
|
/** Orders whose address Baker could not read. Always shown, never folded into `other`. */
|
|
451
456
|
unknown: shopifyPlaceRowSchema.nullable(),
|
|
452
457
|
/** Places past the limit, together. */
|
|
453
458
|
other: shopifyPlaceRowSchema.nullable()
|
|
454
459
|
});
|
|
455
|
-
var shopifyBestSellersViewSchema =
|
|
456
|
-
var shopifyBestSellersSortSchema =
|
|
457
|
-
var shopifyBestSellersRequestSchema =
|
|
460
|
+
var shopifyBestSellersViewSchema = z2.enum(["products", "variants", "trend", "together", "repeat", "momentum"]);
|
|
461
|
+
var shopifyBestSellersSortSchema = z2.enum(["units", "revenue", "orders"]);
|
|
462
|
+
var shopifyBestSellersRequestSchema = z2.object({
|
|
458
463
|
...windowRequest,
|
|
459
464
|
view: shopifyBestSellersViewSchema.optional(),
|
|
460
465
|
sort: shopifyBestSellersSortSchema.optional(),
|
|
461
466
|
/** Only this product (its id or handle): its variants, its trend. */
|
|
462
|
-
product:
|
|
467
|
+
product: z2.string().max(255).optional(),
|
|
463
468
|
limit: limit.optional()
|
|
464
469
|
});
|
|
465
|
-
var shopifyBestSellerRowSchema =
|
|
466
|
-
title:
|
|
470
|
+
var shopifyBestSellerRowSchema = z2.object({
|
|
471
|
+
title: z2.string(),
|
|
467
472
|
/** The option's own title, by variant. */
|
|
468
|
-
variantTitle:
|
|
469
|
-
units:
|
|
470
|
-
refundedUnits:
|
|
471
|
-
orders:
|
|
472
|
-
buyers:
|
|
473
|
-
revenue:
|
|
474
|
-
refunded:
|
|
473
|
+
variantTitle: z2.string().optional(),
|
|
474
|
+
units: z2.number(),
|
|
475
|
+
refundedUnits: z2.number(),
|
|
476
|
+
orders: z2.number(),
|
|
477
|
+
buyers: z2.number(),
|
|
478
|
+
revenue: z2.number(),
|
|
479
|
+
refunded: z2.number(),
|
|
475
480
|
/** Refunded units of units ordered, 0–1. */
|
|
476
|
-
refundRate:
|
|
481
|
+
refundRate: z2.number(),
|
|
477
482
|
/** Units against the period before; null when none sold before. */
|
|
478
|
-
growth:
|
|
483
|
+
growth: z2.number().nullable(),
|
|
479
484
|
// --full
|
|
480
|
-
productId:
|
|
481
|
-
variantId:
|
|
482
|
-
previousUnits:
|
|
483
|
-
previousRevenue:
|
|
485
|
+
productId: z2.string().optional(),
|
|
486
|
+
variantId: z2.string().optional(),
|
|
487
|
+
previousUnits: z2.number().optional(),
|
|
488
|
+
previousRevenue: z2.number().optional()
|
|
484
489
|
});
|
|
485
|
-
var shopifyTrendRowSchema =
|
|
490
|
+
var shopifyTrendRowSchema = z2.object({
|
|
486
491
|
/** YYYY-MM, in the store's time. */
|
|
487
|
-
month:
|
|
488
|
-
title:
|
|
489
|
-
units:
|
|
490
|
-
revenue:
|
|
491
|
-
productId:
|
|
492
|
-
});
|
|
493
|
-
var shopifyTogetherRowSchema =
|
|
494
|
-
first:
|
|
495
|
-
second:
|
|
492
|
+
month: z2.string(),
|
|
493
|
+
title: z2.string(),
|
|
494
|
+
units: z2.number(),
|
|
495
|
+
revenue: z2.number(),
|
|
496
|
+
productId: z2.string().optional()
|
|
497
|
+
});
|
|
498
|
+
var shopifyTogetherRowSchema = z2.object({
|
|
499
|
+
first: z2.string(),
|
|
500
|
+
second: z2.string(),
|
|
496
501
|
/** Orders holding both. */
|
|
497
|
-
orders:
|
|
502
|
+
orders: z2.number(),
|
|
498
503
|
/** Of the orders holding the first, the share that also held the second (0–1). */
|
|
499
|
-
confidence:
|
|
500
|
-
firstId:
|
|
501
|
-
secondId:
|
|
504
|
+
confidence: z2.number(),
|
|
505
|
+
firstId: z2.string().optional(),
|
|
506
|
+
secondId: z2.string().optional()
|
|
502
507
|
});
|
|
503
|
-
var shopifyRepeatRowSchema =
|
|
504
|
-
title:
|
|
508
|
+
var shopifyRepeatRowSchema = z2.object({
|
|
509
|
+
title: z2.string(),
|
|
505
510
|
/** Buyers whose first order held it. */
|
|
506
|
-
buyers:
|
|
511
|
+
buyers: z2.number(),
|
|
507
512
|
/** Of them, who ordered again. */
|
|
508
|
-
buyersAgain:
|
|
509
|
-
share:
|
|
510
|
-
medianDaysToSecond:
|
|
511
|
-
productId:
|
|
512
|
-
});
|
|
513
|
-
var shopifyMomentumRowSchema =
|
|
514
|
-
title:
|
|
515
|
-
units:
|
|
516
|
-
previousUnits:
|
|
513
|
+
buyersAgain: z2.number(),
|
|
514
|
+
share: z2.number(),
|
|
515
|
+
medianDaysToSecond: z2.number().nullable(),
|
|
516
|
+
productId: z2.string().optional()
|
|
517
|
+
});
|
|
518
|
+
var shopifyMomentumRowSchema = z2.object({
|
|
519
|
+
title: z2.string(),
|
|
520
|
+
units: z2.number(),
|
|
521
|
+
previousUnits: z2.number(),
|
|
517
522
|
/** Units against the period before (−0.4 = 40% fewer). */
|
|
518
|
-
change:
|
|
519
|
-
revenue:
|
|
520
|
-
productId:
|
|
523
|
+
change: z2.number(),
|
|
524
|
+
revenue: z2.number(),
|
|
525
|
+
productId: z2.string().optional()
|
|
521
526
|
});
|
|
522
|
-
var shopifyBestSellersResponseSchema =
|
|
527
|
+
var shopifyBestSellersResponseSchema = z2.object({
|
|
523
528
|
...answerCommon,
|
|
524
529
|
view: shopifyBestSellersViewSchema,
|
|
525
530
|
sort: shopifyBestSellersSortSchema,
|
|
526
|
-
product:
|
|
527
|
-
products:
|
|
528
|
-
variants:
|
|
529
|
-
trend:
|
|
530
|
-
together:
|
|
531
|
-
repeat:
|
|
532
|
-
momentum:
|
|
533
|
-
});
|
|
534
|
-
var shopifyCohortsRequestSchema =
|
|
535
|
-
months:
|
|
531
|
+
product: z2.object({ id: z2.string(), title: z2.string() }).optional(),
|
|
532
|
+
products: z2.array(shopifyBestSellerRowSchema).optional(),
|
|
533
|
+
variants: z2.array(shopifyBestSellerRowSchema).optional(),
|
|
534
|
+
trend: z2.array(shopifyTrendRowSchema).optional(),
|
|
535
|
+
together: z2.array(shopifyTogetherRowSchema).optional(),
|
|
536
|
+
repeat: z2.array(shopifyRepeatRowSchema).optional(),
|
|
537
|
+
momentum: z2.array(shopifyMomentumRowSchema).optional()
|
|
538
|
+
});
|
|
539
|
+
var shopifyCohortsRequestSchema = z2.object({
|
|
540
|
+
months: z2.coerce.number().int().min(3).max(36).optional(),
|
|
536
541
|
country: countryCode.optional(),
|
|
537
542
|
full: flag.optional()
|
|
538
543
|
});
|
|
539
|
-
var shopifyCohortMonthSchema =
|
|
544
|
+
var shopifyCohortMonthSchema = z2.object({
|
|
540
545
|
/** Months since the first order: 0 is the month they first bought. */
|
|
541
|
-
offset:
|
|
542
|
-
activeBuyers:
|
|
543
|
-
orders:
|
|
544
|
-
net:
|
|
546
|
+
offset: z2.number(),
|
|
547
|
+
activeBuyers: z2.number(),
|
|
548
|
+
orders: z2.number(),
|
|
549
|
+
net: z2.number(),
|
|
545
550
|
/** Of the cohort, who ordered in that month (0–1). */
|
|
546
|
-
retention:
|
|
551
|
+
retention: z2.number(),
|
|
547
552
|
/** What the cohort spent up to that month, per buyer. */
|
|
548
|
-
cumulativeNetPerBuyer:
|
|
553
|
+
cumulativeNetPerBuyer: z2.number()
|
|
549
554
|
});
|
|
550
|
-
var shopifyCohortSchema =
|
|
555
|
+
var shopifyCohortSchema = z2.object({
|
|
551
556
|
/** The month of their first order, YYYY-MM in the store's time. */
|
|
552
|
-
month:
|
|
553
|
-
size:
|
|
557
|
+
month: z2.string(),
|
|
558
|
+
size: z2.number(),
|
|
554
559
|
/** Who ordered again 1, 2, 3, 6 and 12 months after; null for a month not reached yet. */
|
|
555
|
-
retention:
|
|
556
|
-
m1:
|
|
557
|
-
m2:
|
|
558
|
-
m3:
|
|
559
|
-
m6:
|
|
560
|
-
m12:
|
|
560
|
+
retention: z2.object({
|
|
561
|
+
m1: z2.number().nullable(),
|
|
562
|
+
m2: z2.number().nullable(),
|
|
563
|
+
m3: z2.number().nullable(),
|
|
564
|
+
m6: z2.number().nullable(),
|
|
565
|
+
m12: z2.number().nullable()
|
|
561
566
|
}),
|
|
562
|
-
netPerBuyerAt12:
|
|
567
|
+
netPerBuyerAt12: z2.number().nullable(),
|
|
563
568
|
// --full
|
|
564
|
-
matrix:
|
|
569
|
+
matrix: z2.array(shopifyCohortMonthSchema).optional()
|
|
565
570
|
});
|
|
566
|
-
var shopifyCohortsResponseSchema =
|
|
571
|
+
var shopifyCohortsResponseSchema = z2.object({
|
|
567
572
|
...answerCommon,
|
|
568
|
-
months:
|
|
569
|
-
cohorts:
|
|
573
|
+
months: z2.number(),
|
|
574
|
+
cohorts: z2.array(shopifyCohortSchema)
|
|
570
575
|
});
|
|
571
576
|
|
|
572
577
|
// ../api/src/shopify/writes.ts
|
|
573
|
-
import { z as
|
|
578
|
+
import { z as z3 } from "zod";
|
|
574
579
|
var SHOPIFY_TEMP_REF_PREFIX = "shopify_temp_";
|
|
575
580
|
var SHOPIFY_PERMISSION_NEEDED_PREFIX = "Baker isn't allowed to change this Shopify store yet";
|
|
576
|
-
var shopifyWriteEntitySchema =
|
|
581
|
+
var shopifyWriteEntitySchema = z3.enum([
|
|
577
582
|
"product",
|
|
578
583
|
"variant",
|
|
579
584
|
"metafield",
|
|
@@ -582,9 +587,10 @@ var shopifyWriteEntitySchema = z2.enum([
|
|
|
582
587
|
"urlRedirect",
|
|
583
588
|
"marketingActivity",
|
|
584
589
|
"webPixel",
|
|
585
|
-
"signupOffer"
|
|
590
|
+
"signupOffer",
|
|
591
|
+
"audience"
|
|
586
592
|
]);
|
|
587
|
-
var shopifyDraftOpKindSchema =
|
|
593
|
+
var shopifyDraftOpKindSchema = z3.enum([
|
|
588
594
|
"shopify.product.update",
|
|
589
595
|
"shopify.variant.update",
|
|
590
596
|
"shopify.metafield.set",
|
|
@@ -605,46 +611,48 @@ var shopifyDraftOpKindSchema = z2.enum([
|
|
|
605
611
|
"shopify.marketingActivity.delete",
|
|
606
612
|
"shopify.webPixel.update",
|
|
607
613
|
"shopify.signupOffer.set",
|
|
608
|
-
"shopify.signupOffer.end"
|
|
614
|
+
"shopify.signupOffer.end",
|
|
615
|
+
"shopify.audience.create",
|
|
616
|
+
"shopify.audience.remove"
|
|
609
617
|
]);
|
|
610
|
-
var shopifyDecimalSchema =
|
|
611
|
-
var tagSchema =
|
|
612
|
-
var seoSchema =
|
|
618
|
+
var shopifyDecimalSchema = z3.string().regex(/^\d{1,12}(\.\d{1,4})?$/, 'write amounts as a decimal string, e.g. "19.95"');
|
|
619
|
+
var tagSchema = z3.string().trim().min(1).max(255);
|
|
620
|
+
var seoSchema = z3.object({ title: z3.string().max(255).optional(), description: z3.string().max(320).optional() }).strict();
|
|
613
621
|
var SHOPIFY_DESCRIPTION_MAX_CHARS = 2e5;
|
|
614
|
-
var descriptionHtmlSchema =
|
|
615
|
-
var productUpdateSchema =
|
|
616
|
-
title:
|
|
622
|
+
var descriptionHtmlSchema = z3.string().max(SHOPIFY_DESCRIPTION_MAX_CHARS);
|
|
623
|
+
var productUpdateSchema = z3.object({
|
|
624
|
+
title: z3.string().trim().min(1).max(255).optional(),
|
|
617
625
|
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
618
626
|
seo: seoSchema.optional(),
|
|
619
627
|
/** The WHOLE tag list after the change (Shopify replaces it). `addTags`/`removeTags` are resolved against the live tags. */
|
|
620
|
-
tags:
|
|
621
|
-
addTags:
|
|
622
|
-
removeTags:
|
|
623
|
-
productType:
|
|
628
|
+
tags: z3.array(tagSchema).max(250).optional(),
|
|
629
|
+
addTags: z3.array(tagSchema).max(250).optional(),
|
|
630
|
+
removeTags: z3.array(tagSchema).max(250).optional(),
|
|
631
|
+
productType: z3.string().max(255).optional()
|
|
624
632
|
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change").refine(
|
|
625
633
|
(payload) => payload.tags === void 0 || payload.addTags === void 0 && payload.removeTags === void 0,
|
|
626
634
|
"give either the whole `tags` list or `addTags`/`removeTags`, not both"
|
|
627
635
|
);
|
|
628
|
-
var shopifyWeightUnitSchema =
|
|
629
|
-
var variantUpdateSchema =
|
|
630
|
-
barcode:
|
|
631
|
-
sku:
|
|
632
|
-
weight:
|
|
636
|
+
var shopifyWeightUnitSchema = z3.enum(["GRAMS", "KILOGRAMS", "OUNCES", "POUNDS"]);
|
|
637
|
+
var variantUpdateSchema = z3.object({
|
|
638
|
+
barcode: z3.string().trim().max(255).optional(),
|
|
639
|
+
sku: z3.string().trim().max(255).optional(),
|
|
640
|
+
weight: z3.object({ value: z3.number().nonnegative(), unit: shopifyWeightUnitSchema }).strict().optional(),
|
|
633
641
|
price: shopifyDecimalSchema.optional(),
|
|
634
642
|
/** `null` clears the sale ("compare at") price. */
|
|
635
643
|
compareAtPrice: shopifyDecimalSchema.nullable().optional()
|
|
636
644
|
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change");
|
|
637
|
-
var metafieldKeySchema =
|
|
638
|
-
var metafieldNamespaceSchema =
|
|
639
|
-
var metafieldSetSchema =
|
|
645
|
+
var metafieldKeySchema = z3.string().min(2).max(64).regex(/^[A-Za-z0-9_-]+$/, "letters, digits, `_` and `-` only");
|
|
646
|
+
var metafieldNamespaceSchema = z3.string().min(2).max(255).regex(/^[A-Za-z0-9_-]+$/, "letters, digits, `_` and `-` only");
|
|
647
|
+
var metafieldSetSchema = z3.object({
|
|
640
648
|
namespace: metafieldNamespaceSchema,
|
|
641
649
|
key: metafieldKeySchema,
|
|
642
650
|
/** Shopify's metafield type, e.g. `single_line_text_field`, `multi_line_text_field`, `rich_text_field`, `number_integer`, `boolean`, `json`. */
|
|
643
|
-
type:
|
|
644
|
-
value:
|
|
651
|
+
type: z3.string().min(1).max(100),
|
|
652
|
+
value: z3.string().max(1e5)
|
|
645
653
|
}).strict();
|
|
646
|
-
var metafieldDeleteSchema =
|
|
647
|
-
var shopifyCollectionSortOrderSchema =
|
|
654
|
+
var metafieldDeleteSchema = z3.object({ namespace: metafieldNamespaceSchema, key: metafieldKeySchema }).strict();
|
|
655
|
+
var shopifyCollectionSortOrderSchema = z3.enum([
|
|
648
656
|
"MANUAL",
|
|
649
657
|
"BEST_SELLING",
|
|
650
658
|
"ALPHA_ASC",
|
|
@@ -654,272 +662,280 @@ var shopifyCollectionSortOrderSchema = z2.enum([
|
|
|
654
662
|
"CREATED",
|
|
655
663
|
"CREATED_DESC"
|
|
656
664
|
]);
|
|
657
|
-
var handleSchema =
|
|
665
|
+
var handleSchema = z3.string().min(1).max(255).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "lowercase letters, digits and single dashes, e.g. summer-snowboards");
|
|
658
666
|
var SHOPIFY_COLLECTION_PRODUCTS_MAX = 250;
|
|
659
|
-
var collectionCreateSchema =
|
|
660
|
-
title:
|
|
667
|
+
var collectionCreateSchema = z3.object({
|
|
668
|
+
title: z3.string().trim().min(1).max(255),
|
|
661
669
|
handle: handleSchema.optional(),
|
|
662
670
|
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
663
671
|
seo: seoSchema.optional(),
|
|
664
672
|
sortOrder: shopifyCollectionSortOrderSchema.optional(),
|
|
665
673
|
/** The theme template the collection page uses (the part after `collection.`). Kept when a deleted collection is put back. */
|
|
666
|
-
templateSuffix:
|
|
674
|
+
templateSuffix: z3.string().max(255).optional(),
|
|
667
675
|
/** Product ids, handles or links, in the order shown with sort order MANUAL. */
|
|
668
|
-
products:
|
|
676
|
+
products: z3.array(z3.string().min(1)).max(SHOPIFY_COLLECTION_PRODUCTS_MAX).optional(),
|
|
669
677
|
/** Show it on the online store (a second change, staged with it). Default true. */
|
|
670
|
-
onlineStore:
|
|
678
|
+
onlineStore: z3.boolean().optional()
|
|
671
679
|
}).strict();
|
|
672
|
-
var collectionUpdateSchema =
|
|
673
|
-
title:
|
|
680
|
+
var collectionUpdateSchema = z3.object({
|
|
681
|
+
title: z3.string().trim().min(1).max(255).optional(),
|
|
674
682
|
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
675
683
|
seo: seoSchema.optional(),
|
|
676
684
|
sortOrder: shopifyCollectionSortOrderSchema.optional()
|
|
677
685
|
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change");
|
|
678
|
-
var collectionProductsSchema =
|
|
679
|
-
var isoDateTimeSchema =
|
|
680
|
-
var discountCodeSchema =
|
|
681
|
-
var discountValueSchema =
|
|
682
|
-
|
|
683
|
-
|
|
686
|
+
var collectionProductsSchema = z3.object({ products: z3.array(z3.string().min(1)).min(1).max(SHOPIFY_COLLECTION_PRODUCTS_MAX) }).strict();
|
|
687
|
+
var isoDateTimeSchema = z3.iso.datetime({ offset: true });
|
|
688
|
+
var discountCodeSchema = z3.string().regex(/^[A-Za-z0-9_-]{3,64}$/, "3\u201364 letters, digits, `_` or `-`, e.g. SPRING10");
|
|
689
|
+
var discountValueSchema = z3.union([
|
|
690
|
+
z3.object({ percentage: z3.number().min(1).max(100) }).strict(),
|
|
691
|
+
z3.object({ amount: shopifyDecimalSchema }).strict()
|
|
684
692
|
]);
|
|
685
|
-
var discountAppliesToSchema =
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
693
|
+
var discountAppliesToSchema = z3.union([
|
|
694
|
+
z3.object({ all: z3.literal(true) }).strict(),
|
|
695
|
+
z3.object({ products: z3.array(z3.string().min(1)).min(1).max(100) }).strict(),
|
|
696
|
+
z3.object({ collections: z3.array(z3.string().min(1)).min(1).max(100) }).strict()
|
|
689
697
|
]);
|
|
690
|
-
var discountCreateSchema =
|
|
698
|
+
var discountCreateSchema = z3.object({
|
|
691
699
|
code: discountCodeSchema,
|
|
692
700
|
/** What the store's staff see; defaults to the code. */
|
|
693
|
-
title:
|
|
701
|
+
title: z3.string().trim().min(1).max(255).optional(),
|
|
694
702
|
value: discountValueSchema,
|
|
695
703
|
appliesTo: discountAppliesToSchema,
|
|
696
704
|
minimumSubtotal: shopifyDecimalSchema.optional(),
|
|
697
|
-
minimumQuantity:
|
|
705
|
+
minimumQuantity: z3.number().int().min(1).max(1e4).optional(),
|
|
698
706
|
/** Default: the moment it is published. */
|
|
699
707
|
startsAt: isoDateTimeSchema.optional(),
|
|
700
708
|
endsAt: isoDateTimeSchema.optional(),
|
|
701
|
-
usageLimit:
|
|
709
|
+
usageLimit: z3.number().int().min(1).max(1e6).optional(),
|
|
702
710
|
/** Default true. */
|
|
703
|
-
oncePerCustomer:
|
|
704
|
-
combinesWith:
|
|
705
|
-
productDiscounts:
|
|
706
|
-
orderDiscounts:
|
|
707
|
-
shippingDiscounts:
|
|
711
|
+
oncePerCustomer: z3.boolean().optional(),
|
|
712
|
+
combinesWith: z3.object({
|
|
713
|
+
productDiscounts: z3.boolean().optional(),
|
|
714
|
+
orderDiscounts: z3.boolean().optional(),
|
|
715
|
+
shippingDiscounts: z3.boolean().optional()
|
|
708
716
|
}).strict().optional()
|
|
709
717
|
}).strict().refine(
|
|
710
718
|
(payload) => payload.minimumSubtotal === void 0 || payload.minimumQuantity === void 0,
|
|
711
719
|
"a discount takes a minimum amount or a minimum quantity, not both"
|
|
712
720
|
);
|
|
713
|
-
var discountScheduleSchema =
|
|
714
|
-
var storePathSchema =
|
|
715
|
-
var urlRedirectCreateSchema =
|
|
721
|
+
var discountScheduleSchema = z3.object({ startsAt: isoDateTimeSchema, endsAt: isoDateTimeSchema.nullable() }).strict();
|
|
722
|
+
var storePathSchema = z3.string().min(2).max(1024).regex(/^\/[^\s]*$/, 'a path on the store starting with "/", e.g. /collections/old');
|
|
723
|
+
var urlRedirectCreateSchema = z3.object({
|
|
716
724
|
from: storePathSchema,
|
|
717
|
-
to:
|
|
725
|
+
to: z3.union([storePathSchema, z3.url({ protocol: /^https$/ })])
|
|
718
726
|
}).strict();
|
|
719
|
-
var shopifyMarketingPlatformSchema =
|
|
720
|
-
var marketingUpsertSchema =
|
|
727
|
+
var shopifyMarketingPlatformSchema = z3.enum(["google-ads", "meta"]);
|
|
728
|
+
var marketingUpsertSchema = z3.object({
|
|
721
729
|
platform: shopifyMarketingPlatformSchema,
|
|
722
|
-
accountId:
|
|
723
|
-
campaignId:
|
|
724
|
-
utm:
|
|
725
|
-
campaign:
|
|
726
|
-
source:
|
|
727
|
-
medium:
|
|
730
|
+
accountId: z3.string().min(1).max(64),
|
|
731
|
+
campaignId: z3.string().regex(/^\d+$/, "the campaign's numeric id"),
|
|
732
|
+
utm: z3.object({
|
|
733
|
+
campaign: z3.string().trim().min(1).max(255),
|
|
734
|
+
source: z3.string().trim().min(1).max(255),
|
|
735
|
+
medium: z3.string().trim().min(1).max(255)
|
|
728
736
|
}).strict()
|
|
729
737
|
}).strict();
|
|
730
|
-
var signupOfferHandleSchema =
|
|
731
|
-
var signupOfferSetSchema =
|
|
738
|
+
var signupOfferHandleSchema = z3.string().regex(/^[a-z0-9][a-z0-9-]{1,39}$/, "2\u201340 lowercase letters, digits and dashes, e.g. welcome-10");
|
|
739
|
+
var signupOfferSetSchema = z3.object({
|
|
732
740
|
/** What the store's staff see in front of each code, and the Store page's row. */
|
|
733
|
-
name:
|
|
741
|
+
name: z3.string().trim().min(1).max(80),
|
|
734
742
|
value: discountValueSchema,
|
|
735
743
|
appliesTo: discountAppliesToSchema,
|
|
736
744
|
minimumSubtotal: shopifyDecimalSchema.optional(),
|
|
737
745
|
/** Each code's life, from the moment it is given. */
|
|
738
|
-
validForDays:
|
|
746
|
+
validForDays: z3.number().int().min(1).max(365),
|
|
739
747
|
/** The offer stops giving codes after this; no code outlives it. */
|
|
740
748
|
endsAt: isoDateTimeSchema.optional(),
|
|
741
749
|
/** How many codes the offer gives in all. */
|
|
742
|
-
maxCodes:
|
|
750
|
+
maxCodes: z3.number().int().min(1).max(1e5).optional(),
|
|
743
751
|
/** The start of every code (WELCOME-7Q2M9XKD); default: the handle in capitals. */
|
|
744
|
-
codePrefix:
|
|
745
|
-
combinesWith:
|
|
746
|
-
productDiscounts:
|
|
747
|
-
orderDiscounts:
|
|
748
|
-
shippingDiscounts:
|
|
752
|
+
codePrefix: z3.string().regex(/^[A-Z0-9]{2,12}$/, "2\u201312 capital letters or digits, e.g. WELCOME").optional(),
|
|
753
|
+
combinesWith: z3.object({
|
|
754
|
+
productDiscounts: z3.boolean().optional(),
|
|
755
|
+
orderDiscounts: z3.boolean().optional(),
|
|
756
|
+
shippingDiscounts: z3.boolean().optional()
|
|
749
757
|
}).strict().optional()
|
|
750
758
|
}).strict();
|
|
751
|
-
var emptySchema =
|
|
759
|
+
var emptySchema = z3.object({}).strict();
|
|
752
760
|
var opFields = {
|
|
753
761
|
/** Optional caller-chosen ref for a create, so later ops in the batch can name it (`shopify_temp_…`). */
|
|
754
|
-
ref:
|
|
762
|
+
ref: z3.string().startsWith(SHOPIFY_TEMP_REF_PREFIX).max(80).optional()
|
|
755
763
|
};
|
|
756
|
-
var target =
|
|
757
|
-
var shopifyDraftOpInputSchema =
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
kind:
|
|
764
|
+
var target = z3.string().trim().min(1).max(2048);
|
|
765
|
+
var shopifyDraftOpInputSchema = z3.discriminatedUnion("kind", [
|
|
766
|
+
z3.object({ kind: z3.literal("shopify.product.update"), target, payload: productUpdateSchema, ...opFields }),
|
|
767
|
+
z3.object({ kind: z3.literal("shopify.variant.update"), target, payload: variantUpdateSchema, ...opFields }),
|
|
768
|
+
z3.object({ kind: z3.literal("shopify.metafield.set"), target, payload: metafieldSetSchema, ...opFields }),
|
|
769
|
+
z3.object({ kind: z3.literal("shopify.metafield.delete"), target, payload: metafieldDeleteSchema, ...opFields }),
|
|
770
|
+
z3.object({ kind: z3.literal("shopify.collection.create"), payload: collectionCreateSchema, ...opFields }),
|
|
771
|
+
z3.object({ kind: z3.literal("shopify.collection.publish"), target, payload: emptySchema.optional(), ...opFields }),
|
|
772
|
+
z3.object({ kind: z3.literal("shopify.collection.unpublish"), target, payload: emptySchema.optional(), ...opFields }),
|
|
773
|
+
z3.object({ kind: z3.literal("shopify.collection.update"), target, payload: collectionUpdateSchema, ...opFields }),
|
|
774
|
+
z3.object({ kind: z3.literal("shopify.collection.delete"), target, payload: emptySchema.optional(), ...opFields }),
|
|
775
|
+
z3.object({
|
|
776
|
+
kind: z3.literal("shopify.collection.addProducts"),
|
|
769
777
|
target,
|
|
770
778
|
payload: collectionProductsSchema,
|
|
771
779
|
...opFields
|
|
772
780
|
}),
|
|
773
|
-
|
|
774
|
-
kind:
|
|
781
|
+
z3.object({
|
|
782
|
+
kind: z3.literal("shopify.collection.removeProducts"),
|
|
775
783
|
target,
|
|
776
784
|
payload: collectionProductsSchema,
|
|
777
785
|
...opFields
|
|
778
786
|
}),
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
kind:
|
|
787
|
+
z3.object({ kind: z3.literal("shopify.discountCode.create"), payload: discountCreateSchema, ...opFields }),
|
|
788
|
+
z3.object({
|
|
789
|
+
kind: z3.literal("shopify.discountCode.deactivate"),
|
|
782
790
|
target,
|
|
783
791
|
payload: emptySchema.optional(),
|
|
784
792
|
...opFields
|
|
785
793
|
}),
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
kind:
|
|
794
|
+
z3.object({ kind: z3.literal("shopify.discountCode.schedule"), target, payload: discountScheduleSchema, ...opFields }),
|
|
795
|
+
z3.object({ kind: z3.literal("shopify.urlRedirect.create"), payload: urlRedirectCreateSchema, ...opFields }),
|
|
796
|
+
z3.object({ kind: z3.literal("shopify.urlRedirect.delete"), target, payload: emptySchema.optional(), ...opFields }),
|
|
797
|
+
z3.object({ kind: z3.literal("shopify.marketingActivity.upsert"), payload: marketingUpsertSchema, ...opFields }),
|
|
798
|
+
z3.object({
|
|
799
|
+
kind: z3.literal("shopify.marketingActivity.delete"),
|
|
792
800
|
target,
|
|
793
801
|
payload: emptySchema.optional(),
|
|
794
802
|
...opFields
|
|
795
803
|
}),
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
kind:
|
|
804
|
+
z3.object({ kind: z3.literal("shopify.webPixel.update"), payload: emptySchema.optional(), ...opFields }),
|
|
805
|
+
z3.object({
|
|
806
|
+
kind: z3.literal("shopify.signupOffer.set"),
|
|
799
807
|
target: signupOfferHandleSchema,
|
|
800
808
|
payload: signupOfferSetSchema,
|
|
801
809
|
...opFields
|
|
802
810
|
}),
|
|
803
|
-
|
|
804
|
-
kind:
|
|
811
|
+
z3.object({
|
|
812
|
+
kind: z3.literal("shopify.signupOffer.end"),
|
|
805
813
|
target: signupOfferHandleSchema,
|
|
806
814
|
payload: emptySchema.optional(),
|
|
807
815
|
...opFields
|
|
816
|
+
}),
|
|
817
|
+
z3.object({ kind: z3.literal("shopify.audience.create"), payload: shopifyAudienceDefinitionSchema, ...opFields }),
|
|
818
|
+
/** `target`: the audience's id (`baker shopify audiences list`). */
|
|
819
|
+
z3.object({
|
|
820
|
+
kind: z3.literal("shopify.audience.remove"),
|
|
821
|
+
target,
|
|
822
|
+
payload: shopifyAudienceRemovalSchema.optional(),
|
|
823
|
+
...opFields
|
|
808
824
|
})
|
|
809
825
|
]);
|
|
810
826
|
var PAYLOAD_KEYS = new Map(
|
|
811
827
|
shopifyDraftOpInputSchema.options.map((option) => {
|
|
812
828
|
const payload = option.shape.payload;
|
|
813
|
-
const object = payload instanceof
|
|
814
|
-
return [option.shape.kind.value, object instanceof
|
|
829
|
+
const object = payload instanceof z3.ZodOptional ? payload.unwrap() : payload;
|
|
830
|
+
return [option.shape.kind.value, object instanceof z3.ZodObject ? Object.keys(object.shape) : []];
|
|
815
831
|
})
|
|
816
832
|
);
|
|
817
|
-
var askUserQuestionInputSchema =
|
|
818
|
-
questions:
|
|
819
|
-
|
|
820
|
-
question:
|
|
821
|
-
header:
|
|
822
|
-
multiSelect:
|
|
823
|
-
options:
|
|
833
|
+
var askUserQuestionInputSchema = z3.object({
|
|
834
|
+
questions: z3.array(
|
|
835
|
+
z3.object({
|
|
836
|
+
question: z3.string(),
|
|
837
|
+
header: z3.string(),
|
|
838
|
+
multiSelect: z3.boolean(),
|
|
839
|
+
options: z3.array(z3.object({ label: z3.string(), description: z3.string() })).min(2)
|
|
824
840
|
})
|
|
825
841
|
).min(1)
|
|
826
842
|
});
|
|
827
|
-
var shopifyNeedsApprovalSchema =
|
|
843
|
+
var shopifyNeedsApprovalSchema = z3.object({
|
|
828
844
|
/** Pass to AskUserQuestion exactly as given. */
|
|
829
845
|
askUserQuestion: askUserQuestionInputSchema,
|
|
830
846
|
/** The user already said no to (at least one of) these changes: don't ask again in this turn. */
|
|
831
|
-
declined:
|
|
832
|
-
});
|
|
833
|
-
var shopifyVerificationSchema =
|
|
834
|
-
status:
|
|
835
|
-
checkedAt:
|
|
836
|
-
note:
|
|
837
|
-
});
|
|
838
|
-
var shopifyDraftOpResultSchema =
|
|
839
|
-
status:
|
|
840
|
-
createdId:
|
|
841
|
-
error:
|
|
842
|
-
note:
|
|
843
|
-
skippedBecause:
|
|
844
|
-
executedAt:
|
|
845
|
-
pendingJob:
|
|
847
|
+
declined: z3.boolean()
|
|
848
|
+
});
|
|
849
|
+
var shopifyVerificationSchema = z3.object({
|
|
850
|
+
status: z3.enum(["confirmed", "drifted", "unconfirmed"]),
|
|
851
|
+
checkedAt: z3.number(),
|
|
852
|
+
note: z3.string().optional()
|
|
853
|
+
});
|
|
854
|
+
var shopifyDraftOpResultSchema = z3.object({
|
|
855
|
+
status: z3.enum(["applied", "failed", "skipped"]),
|
|
856
|
+
createdId: z3.string().optional(),
|
|
857
|
+
error: z3.string().optional(),
|
|
858
|
+
note: z3.string().optional(),
|
|
859
|
+
skippedBecause: z3.string().optional(),
|
|
860
|
+
executedAt: z3.number().optional(),
|
|
861
|
+
pendingJob: z3.string().optional(),
|
|
846
862
|
verification: shopifyVerificationSchema.optional()
|
|
847
863
|
});
|
|
848
|
-
var stagedOpSchema =
|
|
849
|
-
ref:
|
|
864
|
+
var stagedOpSchema = z3.object({
|
|
865
|
+
ref: z3.string(),
|
|
850
866
|
kind: shopifyDraftOpKindSchema,
|
|
851
|
-
summary:
|
|
852
|
-
warnings:
|
|
853
|
-
});
|
|
854
|
-
var shopifyDraftStageResponseSchema =
|
|
855
|
-
|
|
856
|
-
staged:
|
|
857
|
-
count:
|
|
858
|
-
ops:
|
|
859
|
-
amended:
|
|
867
|
+
summary: z3.string(),
|
|
868
|
+
warnings: z3.array(z3.string())
|
|
869
|
+
});
|
|
870
|
+
var shopifyDraftStageResponseSchema = z3.union([
|
|
871
|
+
z3.object({
|
|
872
|
+
staged: z3.literal(true),
|
|
873
|
+
count: z3.number(),
|
|
874
|
+
ops: z3.array(stagedOpSchema),
|
|
875
|
+
amended: z3.boolean().optional()
|
|
860
876
|
}),
|
|
861
|
-
|
|
877
|
+
z3.object({ staged: z3.literal(false), needsApproval: shopifyNeedsApprovalSchema })
|
|
862
878
|
]);
|
|
863
879
|
var SHOPIFY_DRAFT_BATCH_MAX = 100;
|
|
864
|
-
var shopifyDraftStageRequestSchema =
|
|
865
|
-
var shopifyDraftStageBatchRequestSchema =
|
|
866
|
-
chatId:
|
|
867
|
-
ops:
|
|
868
|
-
});
|
|
869
|
-
var shopifyDraftAmendRequestSchema =
|
|
870
|
-
chatId:
|
|
871
|
-
ref:
|
|
872
|
-
patch:
|
|
873
|
-
});
|
|
874
|
-
var shopifyDraftOpViewSchema =
|
|
875
|
-
ref:
|
|
880
|
+
var shopifyDraftStageRequestSchema = z3.object({ chatId: z3.string(), op: shopifyDraftOpInputSchema });
|
|
881
|
+
var shopifyDraftStageBatchRequestSchema = z3.object({
|
|
882
|
+
chatId: z3.string(),
|
|
883
|
+
ops: z3.array(shopifyDraftOpInputSchema).min(1).max(SHOPIFY_DRAFT_BATCH_MAX)
|
|
884
|
+
});
|
|
885
|
+
var shopifyDraftAmendRequestSchema = z3.object({
|
|
886
|
+
chatId: z3.string(),
|
|
887
|
+
ref: z3.string(),
|
|
888
|
+
patch: z3.record(z3.string(), z3.unknown())
|
|
889
|
+
});
|
|
890
|
+
var shopifyDraftOpViewSchema = z3.object({
|
|
891
|
+
ref: z3.string(),
|
|
876
892
|
kind: shopifyDraftOpKindSchema,
|
|
877
893
|
entity: shopifyWriteEntitySchema,
|
|
878
|
-
target:
|
|
879
|
-
targetLabel:
|
|
880
|
-
summary:
|
|
881
|
-
money:
|
|
882
|
-
warnings:
|
|
883
|
-
dependsOn:
|
|
884
|
-
undoOf:
|
|
885
|
-
stagedAt:
|
|
894
|
+
target: z3.string().optional(),
|
|
895
|
+
targetLabel: z3.string().optional(),
|
|
896
|
+
summary: z3.string(),
|
|
897
|
+
money: z3.boolean(),
|
|
898
|
+
warnings: z3.array(z3.string()).optional(),
|
|
899
|
+
dependsOn: z3.array(z3.string()),
|
|
900
|
+
undoOf: z3.string().optional(),
|
|
901
|
+
stagedAt: z3.number(),
|
|
886
902
|
result: shopifyDraftOpResultSchema.optional()
|
|
887
903
|
});
|
|
888
|
-
var shopifyDraftListRequestSchema =
|
|
889
|
-
var shopifyDraftListResponseSchema =
|
|
890
|
-
status:
|
|
891
|
-
store:
|
|
892
|
-
count:
|
|
893
|
-
ops:
|
|
894
|
-
publishError:
|
|
895
|
-
});
|
|
896
|
-
var shopifyDraftShowRequestSchema =
|
|
897
|
-
var shopifyDraftShowResponseSchema =
|
|
898
|
-
op: shopifyDraftOpViewSchema.extend({ payload:
|
|
899
|
-
});
|
|
900
|
-
var shopifyDraftRemoveRequestSchema =
|
|
901
|
-
var shopifyDraftRemoveResponseSchema =
|
|
902
|
-
var shopifyDraftClearRequestSchema =
|
|
903
|
-
var shopifyDraftClearResponseSchema =
|
|
904
|
-
var shopifyChangeViewSchema =
|
|
905
|
-
changeId:
|
|
906
|
-
when:
|
|
904
|
+
var shopifyDraftListRequestSchema = z3.object({ chatId: z3.string() });
|
|
905
|
+
var shopifyDraftListResponseSchema = z3.object({
|
|
906
|
+
status: z3.enum(["active", "publishing", "applied", "discarded", "none"]),
|
|
907
|
+
store: z3.string().optional(),
|
|
908
|
+
count: z3.number(),
|
|
909
|
+
ops: z3.array(shopifyDraftOpViewSchema),
|
|
910
|
+
publishError: z3.string().optional()
|
|
911
|
+
});
|
|
912
|
+
var shopifyDraftShowRequestSchema = z3.object({ chatId: z3.string(), ref: z3.string() });
|
|
913
|
+
var shopifyDraftShowResponseSchema = z3.object({
|
|
914
|
+
op: shopifyDraftOpViewSchema.extend({ payload: z3.unknown().optional(), before: z3.unknown().optional() })
|
|
915
|
+
});
|
|
916
|
+
var shopifyDraftRemoveRequestSchema = z3.object({ chatId: z3.string(), ref: z3.string() });
|
|
917
|
+
var shopifyDraftRemoveResponseSchema = z3.object({ removed: z3.array(z3.string()) });
|
|
918
|
+
var shopifyDraftClearRequestSchema = z3.object({ chatId: z3.string() });
|
|
919
|
+
var shopifyDraftClearResponseSchema = z3.object({ cleared: z3.number() });
|
|
920
|
+
var shopifyChangeViewSchema = z3.object({
|
|
921
|
+
changeId: z3.string(),
|
|
922
|
+
when: z3.string(),
|
|
907
923
|
kind: shopifyDraftOpKindSchema,
|
|
908
|
-
summary:
|
|
909
|
-
status:
|
|
910
|
-
chatId:
|
|
911
|
-
undoable:
|
|
924
|
+
summary: z3.string(),
|
|
925
|
+
status: z3.enum(["applied", "failed", "undone"]),
|
|
926
|
+
chatId: z3.string(),
|
|
927
|
+
undoable: z3.boolean(),
|
|
912
928
|
/** Why it can't be undone, when it can't. Whether the store still holds Baker's change is checked when undo is staged. */
|
|
913
|
-
notUndoableBecause:
|
|
929
|
+
notUndoableBecause: z3.string().optional()
|
|
914
930
|
});
|
|
915
|
-
var shopifyChangesRequestSchema =
|
|
916
|
-
limit:
|
|
917
|
-
chatId:
|
|
931
|
+
var shopifyChangesRequestSchema = z3.object({
|
|
932
|
+
limit: z3.coerce.number().int().min(1).max(100).optional(),
|
|
933
|
+
chatId: z3.string().optional()
|
|
918
934
|
});
|
|
919
|
-
var shopifyChangesResponseSchema =
|
|
920
|
-
var shopifyUndoRequestSchema =
|
|
921
|
-
chatId:
|
|
922
|
-
changeIds:
|
|
935
|
+
var shopifyChangesResponseSchema = z3.object({ changes: z3.array(shopifyChangeViewSchema) });
|
|
936
|
+
var shopifyUndoRequestSchema = z3.object({
|
|
937
|
+
chatId: z3.string(),
|
|
938
|
+
changeIds: z3.array(z3.string().min(1)).min(1).max(SHOPIFY_DRAFT_BATCH_MAX)
|
|
923
939
|
});
|
|
924
940
|
|
|
925
941
|
// src/commands/shopify/refusal.ts
|
|
@@ -967,59 +983,520 @@ function approvalRefusal(needsApproval) {
|
|
|
967
983
|
}
|
|
968
984
|
};
|
|
969
985
|
}
|
|
970
|
-
return {
|
|
971
|
-
code: "NEEDS_USER_APPROVAL",
|
|
972
|
-
fix: {
|
|
973
|
-
action: "ask_user",
|
|
974
|
-
askUserQuestion: needsApproval.askUserQuestion,
|
|
975
|
-
explanation: 'This changes money in the store, so the user says yes first. Call AskUserQuestion with `askUserQuestion` exactly as given (you may say a sentence before it, never change it). If the user chooses "Yes, make these changes", run this same command again. Do not stage it any other way.'
|
|
976
|
-
}
|
|
977
|
-
};
|
|
986
|
+
return {
|
|
987
|
+
code: "NEEDS_USER_APPROVAL",
|
|
988
|
+
fix: {
|
|
989
|
+
action: "ask_user",
|
|
990
|
+
askUserQuestion: needsApproval.askUserQuestion,
|
|
991
|
+
explanation: 'This changes money in the store, so the user says yes first. Call AskUserQuestion with `askUserQuestion` exactly as given (you may say a sentence before it, never change it). If the user chooses "Yes, make these changes", run this same command again. Do not stage it any other way.'
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// src/commands/shopify/common.ts
|
|
997
|
+
var PRODUCT_NOT_FOUND_HINT = "Find it with `baker shopify products --search <words>`. If `baker shopify store` shows products Baker couldn't read or products still coming in, it may be one of those \u2014 say so rather than that it doesn't exist.";
|
|
998
|
+
function fail(err) {
|
|
999
|
+
if (err instanceof ApiError) {
|
|
1000
|
+
const refusal = shopifyRefusal(err.code, err.message);
|
|
1001
|
+
if (refusal) {
|
|
1002
|
+
writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
|
|
1003
|
+
process.exit(1);
|
|
1004
|
+
}
|
|
1005
|
+
if (err.code === "NOT_FOUND" && err.message === SHOPIFY_BUYER_GONE_MESSAGE) {
|
|
1006
|
+
writeJson({
|
|
1007
|
+
ok: false,
|
|
1008
|
+
error: { code: err.code, message: err.message },
|
|
1009
|
+
hints: [
|
|
1010
|
+
"Their store asked Baker to erase this buyer, or they were merged into another one: say the buyer is no longer in Baker, and never guess who they were."
|
|
1011
|
+
]
|
|
1012
|
+
});
|
|
1013
|
+
process.exit(1);
|
|
1014
|
+
}
|
|
1015
|
+
if (err.code === "NOT_FOUND" && err.message.startsWith(SHOPIFY_PRODUCT_NOT_FOUND_PREFIX)) {
|
|
1016
|
+
writeJson({ ok: false, error: { code: err.code, message: err.message }, hints: [PRODUCT_NOT_FOUND_HINT] });
|
|
1017
|
+
process.exit(1);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
failApi(err);
|
|
1021
|
+
}
|
|
1022
|
+
function emit(data, meta, hints) {
|
|
1023
|
+
writeJson({ ok: true, ...hints.length > 0 ? { hints } : {}, data, meta });
|
|
1024
|
+
}
|
|
1025
|
+
function params(entries) {
|
|
1026
|
+
const out = {};
|
|
1027
|
+
for (const [name, value] of Object.entries(entries)) {
|
|
1028
|
+
if (value === void 0 || value === "" || value === false) continue;
|
|
1029
|
+
out[name] = String(value);
|
|
1030
|
+
}
|
|
1031
|
+
return out;
|
|
1032
|
+
}
|
|
1033
|
+
var fullArg = {
|
|
1034
|
+
type: "boolean",
|
|
1035
|
+
description: "Everything Baker keeps, not just what answers the question",
|
|
1036
|
+
required: false,
|
|
1037
|
+
default: false
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
// src/commands/shopify/writeCommon.ts
|
|
1041
|
+
import { defineCommand } from "citty";
|
|
1042
|
+
|
|
1043
|
+
// src/commands/shopify/writeHints.ts
|
|
1044
|
+
var STAGED = "Staged \u2014 nothing changes in the store until the user publishes the chat. Review: `baker shopify draft list`. Say the change is ready and happens when they publish, never that it is done.";
|
|
1045
|
+
var WARNINGS = "Read the warnings above before telling the user this is ready.";
|
|
1046
|
+
var DISCOUNT = "The code works only after the chat is published; don't announce it as live or share it as working yet.";
|
|
1047
|
+
var EMPTY_COLLECTION = "The new collection has no products yet: add them with `baker shopify change collection add <collection> <product\u2026>`.";
|
|
1048
|
+
var COLLECTION_DELETE = "Its address stops working when it is deleted: keep old links alive with `baker shopify change redirect create --from /collections/<handle> --to <page>` (ask the user where they should land).";
|
|
1049
|
+
function repointedRedirects(ops) {
|
|
1050
|
+
const removed = ops.flatMap(
|
|
1051
|
+
(op) => op.kind === "shopify.urlRedirect.delete" && op.ref.startsWith("urlRedirect:") ? [op.ref.slice("urlRedirect:".length)] : []
|
|
1052
|
+
);
|
|
1053
|
+
return removed.flatMap((path2) => {
|
|
1054
|
+
const made = ops.find(
|
|
1055
|
+
(op) => op.kind === "shopify.urlRedirect.create" && op.summary.startsWith(`Redirect ${path2} to `)
|
|
1056
|
+
);
|
|
1057
|
+
if (!made) return [];
|
|
1058
|
+
const to = made.summary.slice(`Redirect ${path2} to `.length);
|
|
1059
|
+
return [
|
|
1060
|
+
`${path2} still redirects after publish, now to ${to}: tell the user the old link goes there, not that its redirect is removed.`
|
|
1061
|
+
];
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
function stageHints(data) {
|
|
1065
|
+
if (!data.staged) return [];
|
|
1066
|
+
const hints = [STAGED, ...repointedRedirects(data.ops)];
|
|
1067
|
+
if (data.ops.some((op) => op.warnings.length > 0)) hints.push(WARNINGS);
|
|
1068
|
+
if (data.ops.some((op) => op.kind === "shopify.discountCode.create")) hints.push(DISCOUNT);
|
|
1069
|
+
if (data.ops.some((op) => op.kind === "shopify.collection.delete")) hints.push(COLLECTION_DELETE);
|
|
1070
|
+
if (data.ops.some(
|
|
1071
|
+
(op) => op.kind === "shopify.collection.create" && op.warnings.some((warning) => /no products/.test(warning))
|
|
1072
|
+
)) {
|
|
1073
|
+
hints.push(EMPTY_COLLECTION);
|
|
1074
|
+
}
|
|
1075
|
+
return hints;
|
|
1076
|
+
}
|
|
1077
|
+
function changesHints(data) {
|
|
1078
|
+
if (data.changes.length === 0) return ["Baker hasn't changed this store yet."];
|
|
1079
|
+
return data.changes.some((change) => change.undoable) ? ["Undo one with `baker shopify undo <changeId>` (staged like any change, applied when the user publishes)."] : [];
|
|
1080
|
+
}
|
|
1081
|
+
function auditHints(data) {
|
|
1082
|
+
const hints = [];
|
|
1083
|
+
for (const check of data.checks) {
|
|
1084
|
+
if (check.fix?.kind === "staged") hints.push(`Stage the fix for "${check.title}": \`${check.fix.command}\`.`);
|
|
1085
|
+
}
|
|
1086
|
+
for (const check of data.checks) {
|
|
1087
|
+
if (check.fix?.kind === "merchant") {
|
|
1088
|
+
hints.push(
|
|
1089
|
+
`Only the merchant can fix "${check.title}": ${check.fix.task}. Make it a Task with \`baker actions create\`${check.fix.link ? " and include the link" : ""}.`
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
for (const check of data.checks) {
|
|
1094
|
+
if (check.fix?.kind === "decision") hints.push(`A person decides "${check.title}": ${check.fix.where}.`);
|
|
1095
|
+
}
|
|
1096
|
+
return hints;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// src/commands/shopify/writeCommon.ts
|
|
1100
|
+
function failChange(err) {
|
|
1101
|
+
if (err instanceof ApiError) {
|
|
1102
|
+
const refusal = storeChangeRefusal(err.code, err.message);
|
|
1103
|
+
if (refusal) {
|
|
1104
|
+
writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
|
|
1105
|
+
process.exit(1);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
fail(err);
|
|
1109
|
+
}
|
|
1110
|
+
function emitStage(data) {
|
|
1111
|
+
if (!data.staged) {
|
|
1112
|
+
const refusal = approvalRefusal(data.needsApproval);
|
|
1113
|
+
writeJson({
|
|
1114
|
+
ok: false,
|
|
1115
|
+
error: {
|
|
1116
|
+
code: refusal.code,
|
|
1117
|
+
message: data.needsApproval.declined ? "The user said no to this change in the chat." : "This changes money in the store: the user has to say yes to it in the chat first.",
|
|
1118
|
+
fix: refusal.fix
|
|
1119
|
+
}
|
|
1120
|
+
});
|
|
1121
|
+
process.exit(1);
|
|
1122
|
+
}
|
|
1123
|
+
writeJson({ ok: true, hints: stageHints(data), data });
|
|
1124
|
+
}
|
|
1125
|
+
async function stage(ops) {
|
|
1126
|
+
const chatId = requireChatId();
|
|
1127
|
+
try {
|
|
1128
|
+
const [only] = ops;
|
|
1129
|
+
const data = ops.length === 1 && only ? await apiPost("/api/shopify/draft/stage", { chatId, op: only }) : await apiPost("/api/shopify/draft/stage-batch", { chatId, ops });
|
|
1130
|
+
emitStage(data);
|
|
1131
|
+
} catch (err) {
|
|
1132
|
+
failChange(err);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
function list(value) {
|
|
1136
|
+
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
1137
|
+
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
1138
|
+
}
|
|
1139
|
+
function defined(entries) {
|
|
1140
|
+
return Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== void 0 && value !== ""));
|
|
1141
|
+
}
|
|
1142
|
+
function payloadsFrom(args) {
|
|
1143
|
+
if (typeof args.json !== "string" && typeof args.file !== "string") return null;
|
|
1144
|
+
return loadJsonPayloads(args);
|
|
1145
|
+
}
|
|
1146
|
+
var JSON_ARGS = {
|
|
1147
|
+
json: {
|
|
1148
|
+
type: "string",
|
|
1149
|
+
description: 'The change as inline JSON: a payload for the target given (e.g. {"addTags":["summer"]}), or an array of {"kind","target","payload"} items to stage together in one store read',
|
|
1150
|
+
required: false
|
|
1151
|
+
},
|
|
1152
|
+
file: { type: "string", description: "A JSON file holding the same", required: false }
|
|
1153
|
+
};
|
|
1154
|
+
function leaf(schemaName, meta, args, run) {
|
|
1155
|
+
registerSchema({
|
|
1156
|
+
command: schemaName,
|
|
1157
|
+
description: meta.description,
|
|
1158
|
+
args: Object.fromEntries(
|
|
1159
|
+
Object.entries(args).map(([name, arg]) => [
|
|
1160
|
+
name,
|
|
1161
|
+
{
|
|
1162
|
+
type: String(arg.type ?? "string"),
|
|
1163
|
+
description: String(arg.description ?? ""),
|
|
1164
|
+
required: arg.required === true
|
|
1165
|
+
}
|
|
1166
|
+
])
|
|
1167
|
+
)
|
|
1168
|
+
});
|
|
1169
|
+
return defineCommand({ meta, args, run: async ({ args: parsed }) => await run(parsed) });
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// src/commands/shopify/audiences.ts
|
|
1173
|
+
function failAudience(err) {
|
|
1174
|
+
if (err instanceof ApiError) {
|
|
1175
|
+
const refusal = audienceRefusal(err.code, err.message);
|
|
1176
|
+
if (refusal) {
|
|
1177
|
+
writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
|
|
1178
|
+
process.exit(1);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
failChange(err);
|
|
1182
|
+
}
|
|
1183
|
+
var SEGMENTS = ["best", "loyal", "at_risk", "new", "one_time", "all"];
|
|
1184
|
+
var createDescription = "Start here to reach the store's own buyers with ads: stage a Meta or Google Ads audience made of one buyer segment (`baker shopify segments` explains each). Example: baker shopify audiences create --segment at_risk --to meta --account-id act_123. Only buyers who accept email or SMS marketing are sent, hashed; Baker never shows or keeps who they are. Staged until the user publishes the chat; then it is made, filled, and updated daily (--refresh off: filled once). Answers counts: people in the segment, how many accept marketing, how many will be sent.";
|
|
1185
|
+
registerSchema({
|
|
1186
|
+
command: "shopify.audiences.create",
|
|
1187
|
+
description: createDescription,
|
|
1188
|
+
args: {
|
|
1189
|
+
segment: {
|
|
1190
|
+
type: "string",
|
|
1191
|
+
description: "best | loyal | at_risk | new | one_time | all",
|
|
1192
|
+
required: true,
|
|
1193
|
+
enum: SEGMENTS
|
|
1194
|
+
},
|
|
1195
|
+
to: { type: "string", description: "meta | google", required: true, enum: ["meta", "google"] },
|
|
1196
|
+
"account-id": {
|
|
1197
|
+
type: "string",
|
|
1198
|
+
description: "The ad account: act_123\u2026 for Meta, 123-456-7890 for Google Ads",
|
|
1199
|
+
required: true
|
|
1200
|
+
},
|
|
1201
|
+
name: { type: "string", description: 'Its name on the platform (default "Shopify: <segment>")', required: false },
|
|
1202
|
+
refresh: { type: "string", description: "daily (default) | off", required: false, enum: ["daily", "off"] }
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
var createCommand = defineCommand2({
|
|
1206
|
+
meta: { name: "create", description: createDescription },
|
|
1207
|
+
args: {
|
|
1208
|
+
segment: { type: "string", description: "best | loyal | at_risk | new | one_time | all", required: true },
|
|
1209
|
+
to: { type: "string", description: "meta | google", required: true },
|
|
1210
|
+
"account-id": { type: "string", description: "act_123\u2026 for Meta, 123-456-7890 for Google Ads", required: true },
|
|
1211
|
+
name: { type: "string", description: "Its name on the platform", required: false },
|
|
1212
|
+
refresh: { type: "string", description: "daily (default) | off", required: false },
|
|
1213
|
+
full: { type: "boolean", description: "Add the definition that was staged", required: false, default: false }
|
|
1214
|
+
},
|
|
1215
|
+
async run({ args }) {
|
|
1216
|
+
const parsed = shopifyAudienceDefinitionSchema.safeParse({
|
|
1217
|
+
segment: args.segment,
|
|
1218
|
+
platform: args.to,
|
|
1219
|
+
accountId: args["account-id"],
|
|
1220
|
+
...args.name ? { name: args.name } : {},
|
|
1221
|
+
...args.refresh ? { refresh: args.refresh } : {}
|
|
1222
|
+
});
|
|
1223
|
+
if (!parsed.success) {
|
|
1224
|
+
const issue = parsed.error.issues[0];
|
|
1225
|
+
failValidation(`${issue?.path.join(".") ?? ""}: ${issue?.message ?? "invalid audience"}`);
|
|
1226
|
+
}
|
|
1227
|
+
const definition = parsed.data;
|
|
1228
|
+
const chatId = requireChatId();
|
|
1229
|
+
try {
|
|
1230
|
+
const data = await apiPost(
|
|
1231
|
+
"/api/shopify/audiences/create",
|
|
1232
|
+
{ chatId, definition },
|
|
1233
|
+
{ timeoutMs: 3e5 }
|
|
1234
|
+
);
|
|
1235
|
+
const compact = {
|
|
1236
|
+
ref: data.ref,
|
|
1237
|
+
staged: data.staged,
|
|
1238
|
+
platform: data.platform,
|
|
1239
|
+
accountId: data.accountId,
|
|
1240
|
+
people: data.counts.people,
|
|
1241
|
+
withConsent: data.counts.withConsent,
|
|
1242
|
+
willSend: data.counts.willSend,
|
|
1243
|
+
...data.warnings.length > 0 ? { warnings: data.warnings } : {},
|
|
1244
|
+
...args.full ? { summary: data.summary, counts: data.counts, definition } : {}
|
|
1245
|
+
};
|
|
1246
|
+
writeJson({ ok: true, hints: audienceCreateHints(data), data: compact });
|
|
1247
|
+
} catch (err) {
|
|
1248
|
+
failAudience(err);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
var listDescription = "The store's buyer audiences on Meta and Google Ads: each one's id, segment, ad account, whether it updates daily, and its last update in counts (people, how many accept marketing, how many were sent). With a chat, also this chat's staged audience changes. Example: baker shopify audiences list";
|
|
1253
|
+
registerSchema({
|
|
1254
|
+
command: "shopify.audiences.list",
|
|
1255
|
+
description: listDescription,
|
|
1256
|
+
args: {
|
|
1257
|
+
full: {
|
|
1258
|
+
type: "boolean",
|
|
1259
|
+
description: "Add removed audiences, when each was made and its consent rule",
|
|
1260
|
+
required: false
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1264
|
+
var listCommand = defineCommand2({
|
|
1265
|
+
meta: { name: "list", description: listDescription },
|
|
1266
|
+
args: { full: { type: "boolean", description: "Add removed ones and more detail", required: false, default: false } },
|
|
1267
|
+
async run({ args }) {
|
|
1268
|
+
try {
|
|
1269
|
+
const data = await apiGet(
|
|
1270
|
+
"/api/shopify/audiences",
|
|
1271
|
+
params({ chatId: optionalChatId(), full: args.full })
|
|
1272
|
+
);
|
|
1273
|
+
writeJson({ ok: true, hints: audienceListHints(data), data });
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
failAudience(err);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
var removeDescription = "Stage removing a buyer audience: Baker stops updating it and deletes it from the ad platform when the user publishes (--keep-on-platform: only stop updating). Ads using it stop reaching it once it is deleted. Example: baker shopify audiences remove <id>";
|
|
1280
|
+
registerSchema({
|
|
1281
|
+
command: "shopify.audiences.remove",
|
|
1282
|
+
description: removeDescription,
|
|
1283
|
+
args: {
|
|
1284
|
+
id: { type: "positional", description: "The audience's id (`baker shopify audiences list`)", required: true },
|
|
1285
|
+
"keep-on-platform": {
|
|
1286
|
+
type: "boolean",
|
|
1287
|
+
description: "Leave it on the ad platform, only stop updating it",
|
|
1288
|
+
required: false
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
var removeCommand = defineCommand2({
|
|
1293
|
+
meta: { name: "remove", description: removeDescription },
|
|
1294
|
+
args: {
|
|
1295
|
+
id: { type: "positional", description: "The audience's id", required: true },
|
|
1296
|
+
"keep-on-platform": { type: "boolean", description: "Only stop updating it", required: false, default: false }
|
|
1297
|
+
},
|
|
1298
|
+
async run({ args }) {
|
|
1299
|
+
const chatId = requireChatId();
|
|
1300
|
+
try {
|
|
1301
|
+
const data = await apiPost("/api/shopify/audiences/remove", {
|
|
1302
|
+
chatId,
|
|
1303
|
+
id: args.id,
|
|
1304
|
+
...args["keep-on-platform"] ? { keepOnPlatform: true } : {}
|
|
1305
|
+
});
|
|
1306
|
+
writeJson({
|
|
1307
|
+
ok: true,
|
|
1308
|
+
hints: ["Staged on this chat until Publish: the audience keeps updating until the user publishes it."],
|
|
1309
|
+
data
|
|
1310
|
+
});
|
|
1311
|
+
} catch (err) {
|
|
1312
|
+
failAudience(err);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
var refreshDescription = "Update a published buyer audience now instead of waiting for its daily update: Baker reads the segment again and replaces who the audience holds. Not staged \u2014 the audience was approved when it was published. Example: baker shopify audiences refresh <id>; read the outcome with `baker shopify audiences list` a minute later.";
|
|
1317
|
+
registerSchema({
|
|
1318
|
+
command: "shopify.audiences.refresh",
|
|
1319
|
+
description: refreshDescription,
|
|
1320
|
+
args: {
|
|
1321
|
+
id: { type: "positional", description: "The audience's id (`baker shopify audiences list`)", required: true }
|
|
1322
|
+
}
|
|
1323
|
+
});
|
|
1324
|
+
var refreshCommand = defineCommand2({
|
|
1325
|
+
meta: { name: "refresh", description: refreshDescription },
|
|
1326
|
+
args: { id: { type: "positional", description: "The audience's id", required: true } },
|
|
1327
|
+
async run({ args }) {
|
|
1328
|
+
try {
|
|
1329
|
+
const data = await apiPost("/api/shopify/audiences/refresh", { id: args.id });
|
|
1330
|
+
writeJson({
|
|
1331
|
+
ok: true,
|
|
1332
|
+
hints: ["Updating now; `baker shopify audiences list` shows the outcome under lastRun in a minute or two."],
|
|
1333
|
+
data
|
|
1334
|
+
});
|
|
1335
|
+
} catch (err) {
|
|
1336
|
+
failAudience(err);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
});
|
|
1340
|
+
var audiencesCommand = defineCommand2({
|
|
1341
|
+
meta: {
|
|
1342
|
+
name: "audiences",
|
|
1343
|
+
description: "The store's buyers as Meta and Google Ads audiences: create (staged), list, remove (staged), refresh. Example: baker shopify audiences create --segment best --to meta --account-id act_123"
|
|
1344
|
+
},
|
|
1345
|
+
subCommands: { create: createCommand, list: listCommand, remove: removeCommand, refresh: refreshCommand }
|
|
1346
|
+
});
|
|
1347
|
+
|
|
1348
|
+
// src/commands/shopify/buyers.ts
|
|
1349
|
+
import { defineCommand as defineCommand3 } from "citty";
|
|
1350
|
+
|
|
1351
|
+
// src/commands/shopify/buyerHints.ts
|
|
1352
|
+
var AUDIENCE_PATH = "To show ads to these buyers, stage an audience of a segment on Meta or Google Ads (`baker shopify audiences create --segment best --to meta|google --account-id <id>`): only buyers who accept marketing are sent, staged until Publish. On Meta, a lookalike of it (`baker ads meta audiences create --subtype LOOKALIKE`) reaches more people like them once it holds 100 people from one country.";
|
|
1353
|
+
var MIN_ORDERS_TO_SCALE = 5;
|
|
1354
|
+
function storeFactsHint(currency) {
|
|
1355
|
+
return `These are the store's own orders \u2014 never a demo or sample store: build the answer on them and quote their numbers${currency ? ` in ${currency}` : ""}. If Knowledge describes other products or markets, say the two disagree and ask which is current \u2014 never drop these numbers for it.`;
|
|
1356
|
+
}
|
|
1357
|
+
var percent = (value) => `${Math.round(value * 100)}%`;
|
|
1358
|
+
function buyerHistoryHints(history, basis) {
|
|
1359
|
+
const hints = [];
|
|
1360
|
+
if (history.state === "importing") {
|
|
1361
|
+
hints.push(
|
|
1362
|
+
`Baker is still bringing in this store's past orders (${history.orders} so far): older periods, repeat buyers and cohorts are incomplete \u2014 say so rather than reporting a drop.`
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
if (history.state === "failed") {
|
|
1366
|
+
hints.push("Baker couldn't finish bringing in this store's past orders; older periods may be incomplete.");
|
|
1367
|
+
}
|
|
1368
|
+
if (basis === "last_60_days") {
|
|
1369
|
+
hints.push(
|
|
1370
|
+
"Shopify gives Baker this store's last 60 days of orders only: older behaviour is not here, and a buyer whose earlier orders are older counts as new."
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
return hints;
|
|
1374
|
+
}
|
|
1375
|
+
function countriesHints(answer) {
|
|
1376
|
+
const hints = buyerHistoryHints(answer.history, answer.basis);
|
|
1377
|
+
if (answer.total.orders === 0) {
|
|
1378
|
+
hints.push("No orders were placed in this period.");
|
|
1379
|
+
return hints;
|
|
1380
|
+
}
|
|
1381
|
+
hints.push(storeFactsHint(answer.currency));
|
|
1382
|
+
const money = (amount) => `${answer.currency ?? ""} ${amount}`.trim();
|
|
1383
|
+
const growing = answer.rows.filter((row) => row.orders >= MIN_ORDERS_TO_SCALE && (row.ordersGrowth ?? 0) > 0).sort((a, b) => (b.ordersGrowth ?? 0) - (a.ordersGrowth ?? 0))[0];
|
|
1384
|
+
if (growing && answer.level === "country") {
|
|
1385
|
+
hints.push(
|
|
1386
|
+
`Scale ${growing.name}: its orders grew ${percent(growing.ordersGrowth ?? 0)} against the period before (${growing.orders} orders, ${money(growing.net)}). Check which campaigns already target it (\`baker ads meta campaigns\`, \`baker ads google query --preset campaign-performance\`) before staging a change.`
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
const average = answer.total.averageOrder;
|
|
1390
|
+
const promising = answer.rows.filter((row) => row.orders < MIN_ORDERS_TO_SCALE && average > 0 && row.averageOrder >= 1.5 * average).sort((a, b) => b.averageOrder - a.averageOrder)[0];
|
|
1391
|
+
if (promising && answer.level === "country") {
|
|
1392
|
+
hints.push(
|
|
1393
|
+
`Test ${promising.name}: its average order is ${money(promising.averageOrder)}, ${(promising.averageOrder / average).toFixed(1)}\xD7 the store's, from only ${promising.orders} orders \u2014 a small budget there would show whether it scales.`
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
if (answer.unknown && answer.total.orders > 0 && answer.unknown.orders / answer.total.orders > 0.25) {
|
|
1397
|
+
const lack = answer.level === "country" ? "have no address Baker could read (Unknown)" : `name no ${answer.level} on their address (${answer.unknown.name})`;
|
|
1398
|
+
hints.push(
|
|
1399
|
+
`${answer.unknown.orders} of these orders ${lack}: say so rather than leaving them out of a place's share.`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
return hints;
|
|
1403
|
+
}
|
|
1404
|
+
function bestSellersHints(answer) {
|
|
1405
|
+
const hints = buyerHistoryHints(answer.history, answer.basis);
|
|
1406
|
+
const leader = answer.repeat?.[0];
|
|
1407
|
+
if (leader && leader.buyersAgain > 0) {
|
|
1408
|
+
hints.push(
|
|
1409
|
+
`Lead a landing with "${leader.title}" (find it with \`baker shopify products --search\`): ${percent(leader.share)} of the buyers whose first order held it came back.`
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
const top = answer.products?.[0];
|
|
1413
|
+
if (top && top.units > 0) {
|
|
1414
|
+
hints.push(
|
|
1415
|
+
`"${top.title}" is the best seller (${top.units} units). For which first buys bring buyers back, run \`baker shopify best-sellers --view repeat\`; for what is losing steam, \`--view momentum\`.`
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1418
|
+
const losing = answer.momentum?.[0];
|
|
1419
|
+
if (losing) {
|
|
1420
|
+
hints.push(
|
|
1421
|
+
`"${losing.title}" sold ${losing.units} against ${losing.previousUnits} the period before: check its stock (\`baker shopify stock\`) and the ads that promote it before cutting it.`
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
const sellers = answer.products ?? answer.variants ?? [];
|
|
1425
|
+
if (sellers.some((row) => row.units > 0)) hints.push(storeFactsHint(answer.currency));
|
|
1426
|
+
const withRefunds = sellers.filter((row) => row.refundedUnits > 0).sort((a, b) => b.refundRate - a.refundRate).slice(0, 5);
|
|
1427
|
+
if (withRefunds.length > 0) {
|
|
1428
|
+
const money = (amount) => `${answer.currency ?? ""} ${amount}`.trim();
|
|
1429
|
+
hints.push(
|
|
1430
|
+
`Refunds: ${withRefunds.map((row) => `"${row.title}" ${percent(row.refundRate)} of units (${money(row.refunded)})`).join(", ")}. Only a product not named here had no refunds in the period.`
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
const refunded = answer.products?.find((row) => row.units >= 5 && row.refundRate >= 0.2);
|
|
1434
|
+
if (refunded) {
|
|
1435
|
+
hints.push(
|
|
1436
|
+
`"${refunded.title}" comes back often (${percent(refunded.refundRate)} of units refunded): don't lead a campaign with it before finding out why.`
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
return hints;
|
|
978
1440
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
if (
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
});
|
|
997
|
-
process.exit(1);
|
|
998
|
-
}
|
|
999
|
-
if (err.code === "NOT_FOUND" && err.message.startsWith(SHOPIFY_PRODUCT_NOT_FOUND_PREFIX)) {
|
|
1000
|
-
writeJson({ ok: false, error: { code: err.code, message: err.message }, hints: [PRODUCT_NOT_FOUND_HINT] });
|
|
1001
|
-
process.exit(1);
|
|
1002
|
-
}
|
|
1441
|
+
function bestBuyersHint(best) {
|
|
1442
|
+
if (!best || best.buyers === 0) return [];
|
|
1443
|
+
const countries = best.topCountries.map((country) => country.name).join(", ");
|
|
1444
|
+
const products = best.topFirstProducts.map((product) => `"${product.title}"`).join(", ");
|
|
1445
|
+
if (!countries && !products) return [];
|
|
1446
|
+
return [
|
|
1447
|
+
`Find more buyers like your best (${best.buyers}): ${countries ? `target ${countries}` : ""}${countries && products ? "; " : ""}${products ? `lead with ${products}, what their first orders held` : ""}.`
|
|
1448
|
+
];
|
|
1449
|
+
}
|
|
1450
|
+
function segmentsHints(answer) {
|
|
1451
|
+
const hints = buyerHistoryHints(answer.history, answer.basis);
|
|
1452
|
+
hints.push(...bestBuyersHint(answer.segments.find((segment) => segment.segment === "best")));
|
|
1453
|
+
const atRisk = answer.segments.find((segment) => segment.segment === "at_risk");
|
|
1454
|
+
if (atRisk && atRisk.buyers > 0) {
|
|
1455
|
+
hints.push(
|
|
1456
|
+
`${atRisk.buyers} repeat buyers have not ordered in ${Math.round(2 * answer.thresholds.gapDays)} days (At risk): a win-back offer to them is worth more than a new buyer of the same value.`
|
|
1457
|
+
);
|
|
1003
1458
|
}
|
|
1004
|
-
|
|
1459
|
+
if (answer.buyers > 0) hints.push(AUDIENCE_PATH);
|
|
1460
|
+
return hints;
|
|
1005
1461
|
}
|
|
1006
|
-
function
|
|
1007
|
-
|
|
1462
|
+
function buyersHints(answer) {
|
|
1463
|
+
const hints = buyerHistoryHints(answer.history, answer.basis);
|
|
1464
|
+
if (answer.summary.orders === 0) {
|
|
1465
|
+
hints.push("No orders were placed in this period.");
|
|
1466
|
+
return hints;
|
|
1467
|
+
}
|
|
1468
|
+
hints.push(storeFactsHint(answer.currency));
|
|
1469
|
+
if (answer.acquisition?.by === "campaign" && answer.acquisition.rows.length > 0) {
|
|
1470
|
+
hints.push(
|
|
1471
|
+
"Compare each campaign's lifetime value with what it cost for the same dates (`baker ads meta insights`, `baker ads google query --preset campaign-performance`): Baker keeps no ad spend."
|
|
1472
|
+
);
|
|
1473
|
+
}
|
|
1474
|
+
if (!answer.acquisition) {
|
|
1475
|
+
hints.push(
|
|
1476
|
+
"For lifetime value by the campaign or channel that brought each buyer, add `--by campaign` or `--by channel`."
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
if (answer.summary.guestOrders > 0 && answer.summary.guestOrders >= answer.summary.orders / 2) {
|
|
1480
|
+
hints.push(
|
|
1481
|
+
`${answer.summary.guestOrders} of ${answer.summary.orders} orders were placed as guests: they count in sales, never as buyers, so repeat rates read low.`
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
if (answer.summary.buyers > 0) hints.push(AUDIENCE_PATH);
|
|
1485
|
+
return hints;
|
|
1008
1486
|
}
|
|
1009
|
-
function
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1487
|
+
function cohortsHints(answer) {
|
|
1488
|
+
const hints = buyerHistoryHints(answer.history, answer.basis);
|
|
1489
|
+
const reached = answer.cohorts.filter((cohort) => cohort.retention.m3 !== null && cohort.size >= 5);
|
|
1490
|
+
if (reached.length >= 2) {
|
|
1491
|
+
const best = [...reached].sort((a, b) => (b.retention.m3 ?? 0) - (a.retention.m3 ?? 0))[0];
|
|
1492
|
+
if (best) {
|
|
1493
|
+
hints.push(
|
|
1494
|
+
`Buyers who first ordered in ${best.month} came back best (${percent(best.retention.m3 ?? 0)} ordered again in their third month): look at what was running then (\`baker shopify buyers --by campaign\`).`
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1014
1497
|
}
|
|
1015
|
-
return
|
|
1498
|
+
return hints;
|
|
1016
1499
|
}
|
|
1017
|
-
var fullArg = {
|
|
1018
|
-
type: "boolean",
|
|
1019
|
-
description: "Everything Baker keeps, not just what answers the question",
|
|
1020
|
-
required: false,
|
|
1021
|
-
default: false
|
|
1022
|
-
};
|
|
1023
1500
|
|
|
1024
1501
|
// src/commands/shopify/hints.ts
|
|
1025
1502
|
var RECONNECT = 'Baker has lost access to this Shopify store, so these products may be out of date. Say so, and ask the user to reconnect with `request_connection` { platform: "shopify" } \u2014 the card offers Reconnect.';
|
|
@@ -1356,7 +1833,7 @@ registerSchema({
|
|
|
1356
1833
|
}
|
|
1357
1834
|
}
|
|
1358
1835
|
});
|
|
1359
|
-
var buyersCommand =
|
|
1836
|
+
var buyersCommand = defineCommand3({
|
|
1360
1837
|
meta: {
|
|
1361
1838
|
name: "buyers",
|
|
1362
1839
|
description: "Who buys: buyers, new and returning, repeat rate, segments and the top buyers. Start here: baker shopify buyers --days 90 --by channel"
|
|
@@ -1403,7 +1880,7 @@ registerSchema({
|
|
|
1403
1880
|
full: { ...fullArg, description: "Add each order's id, lines with their amounts, refunded lines and campaign" }
|
|
1404
1881
|
}
|
|
1405
1882
|
});
|
|
1406
|
-
var buyerCommand =
|
|
1883
|
+
var buyerCommand = defineCommand3({
|
|
1407
1884
|
meta: {
|
|
1408
1885
|
name: "buyer",
|
|
1409
1886
|
description: "One buyer's history by number. Example: baker shopify buyer 1042"
|
|
@@ -1436,7 +1913,7 @@ registerSchema({
|
|
|
1436
1913
|
full: { ...fullArg, description: "Add the period before's net and orders per place" }
|
|
1437
1914
|
}
|
|
1438
1915
|
});
|
|
1439
|
-
var countriesCommand =
|
|
1916
|
+
var countriesCommand = defineCommand3({
|
|
1440
1917
|
meta: {
|
|
1441
1918
|
name: "countries",
|
|
1442
1919
|
description: "Where buyers are: orders, buyers and net by country, region or city, with growth. Start here: baker shopify countries --days 90"
|
|
@@ -1491,7 +1968,7 @@ registerSchema({
|
|
|
1491
1968
|
full: { ...fullArg, description: "Add product and variant ids and the period before" }
|
|
1492
1969
|
}
|
|
1493
1970
|
});
|
|
1494
|
-
var bestSellersCommand =
|
|
1971
|
+
var bestSellersCommand = defineCommand3({
|
|
1495
1972
|
meta: {
|
|
1496
1973
|
name: "best-sellers",
|
|
1497
1974
|
description: "What sells: best sellers, variants, trend, bought together, repeat leaders, losing momentum. Start here: baker shopify best-sellers --days 90"
|
|
@@ -1542,7 +2019,7 @@ registerSchema({
|
|
|
1542
2019
|
}
|
|
1543
2020
|
}
|
|
1544
2021
|
});
|
|
1545
|
-
var cohortsCommand =
|
|
2022
|
+
var cohortsCommand = defineCommand3({
|
|
1546
2023
|
meta: {
|
|
1547
2024
|
name: "cohorts",
|
|
1548
2025
|
description: "Buyers by first-order month: who came back and what they spent. Example: baker shopify cohorts --months 12"
|
|
@@ -1573,7 +2050,7 @@ registerSchema({
|
|
|
1573
2050
|
full: { ...fullArg, description: "Add the first products' ids" }
|
|
1574
2051
|
}
|
|
1575
2052
|
});
|
|
1576
|
-
var segmentsCommand =
|
|
2053
|
+
var segmentsCommand = defineCommand3({
|
|
1577
2054
|
meta: {
|
|
1578
2055
|
name: "segments",
|
|
1579
2056
|
description: "Buyers by segment: best, loyal, at risk, new, one-time. Example: baker shopify segments"
|
|
@@ -1597,141 +2074,7 @@ var segmentsCommand = defineCommand({
|
|
|
1597
2074
|
});
|
|
1598
2075
|
|
|
1599
2076
|
// src/commands/shopify/change.ts
|
|
1600
|
-
import { defineCommand as
|
|
1601
|
-
|
|
1602
|
-
// src/commands/shopify/writeCommon.ts
|
|
1603
|
-
import { defineCommand as defineCommand2 } from "citty";
|
|
1604
|
-
|
|
1605
|
-
// src/commands/shopify/writeHints.ts
|
|
1606
|
-
var STAGED = "Staged \u2014 nothing changes in the store until the user publishes the chat. Review: `baker shopify draft list`. Say the change is ready and happens when they publish, never that it is done.";
|
|
1607
|
-
var WARNINGS = "Read the warnings above before telling the user this is ready.";
|
|
1608
|
-
var DISCOUNT = "The code works only after the chat is published; don't announce it as live or share it as working yet.";
|
|
1609
|
-
var EMPTY_COLLECTION = "The new collection has no products yet: add them with `baker shopify change collection add <collection> <product\u2026>`.";
|
|
1610
|
-
var COLLECTION_DELETE = "Its address stops working when it is deleted: keep old links alive with `baker shopify change redirect create --from /collections/<handle> --to <page>` (ask the user where they should land).";
|
|
1611
|
-
function repointedRedirects(ops) {
|
|
1612
|
-
const removed = ops.flatMap(
|
|
1613
|
-
(op) => op.kind === "shopify.urlRedirect.delete" && op.ref.startsWith("urlRedirect:") ? [op.ref.slice("urlRedirect:".length)] : []
|
|
1614
|
-
);
|
|
1615
|
-
return removed.flatMap((path2) => {
|
|
1616
|
-
const made = ops.find(
|
|
1617
|
-
(op) => op.kind === "shopify.urlRedirect.create" && op.summary.startsWith(`Redirect ${path2} to `)
|
|
1618
|
-
);
|
|
1619
|
-
if (!made) return [];
|
|
1620
|
-
const to = made.summary.slice(`Redirect ${path2} to `.length);
|
|
1621
|
-
return [
|
|
1622
|
-
`${path2} still redirects after publish, now to ${to}: tell the user the old link goes there, not that its redirect is removed.`
|
|
1623
|
-
];
|
|
1624
|
-
});
|
|
1625
|
-
}
|
|
1626
|
-
function stageHints(data) {
|
|
1627
|
-
if (!data.staged) return [];
|
|
1628
|
-
const hints = [STAGED, ...repointedRedirects(data.ops)];
|
|
1629
|
-
if (data.ops.some((op) => op.warnings.length > 0)) hints.push(WARNINGS);
|
|
1630
|
-
if (data.ops.some((op) => op.kind === "shopify.discountCode.create")) hints.push(DISCOUNT);
|
|
1631
|
-
if (data.ops.some((op) => op.kind === "shopify.collection.delete")) hints.push(COLLECTION_DELETE);
|
|
1632
|
-
if (data.ops.some(
|
|
1633
|
-
(op) => op.kind === "shopify.collection.create" && op.warnings.some((warning) => /no products/.test(warning))
|
|
1634
|
-
)) {
|
|
1635
|
-
hints.push(EMPTY_COLLECTION);
|
|
1636
|
-
}
|
|
1637
|
-
return hints;
|
|
1638
|
-
}
|
|
1639
|
-
function changesHints(data) {
|
|
1640
|
-
if (data.changes.length === 0) return ["Baker hasn't changed this store yet."];
|
|
1641
|
-
return data.changes.some((change) => change.undoable) ? ["Undo one with `baker shopify undo <changeId>` (staged like any change, applied when the user publishes)."] : [];
|
|
1642
|
-
}
|
|
1643
|
-
function auditHints(data) {
|
|
1644
|
-
const hints = [];
|
|
1645
|
-
for (const check of data.checks) {
|
|
1646
|
-
if (check.fix?.kind === "staged") hints.push(`Stage the fix for "${check.title}": \`${check.fix.command}\`.`);
|
|
1647
|
-
}
|
|
1648
|
-
for (const check of data.checks) {
|
|
1649
|
-
if (check.fix?.kind === "merchant") {
|
|
1650
|
-
hints.push(
|
|
1651
|
-
`Only the merchant can fix "${check.title}": ${check.fix.task}. Make it a Task with \`baker actions create\`${check.fix.link ? " and include the link" : ""}.`
|
|
1652
|
-
);
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
for (const check of data.checks) {
|
|
1656
|
-
if (check.fix?.kind === "decision") hints.push(`A person decides "${check.title}": ${check.fix.where}.`);
|
|
1657
|
-
}
|
|
1658
|
-
return hints;
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
// src/commands/shopify/writeCommon.ts
|
|
1662
|
-
function failChange(err) {
|
|
1663
|
-
if (err instanceof ApiError) {
|
|
1664
|
-
const refusal = storeChangeRefusal(err.code, err.message);
|
|
1665
|
-
if (refusal) {
|
|
1666
|
-
writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
|
|
1667
|
-
process.exit(1);
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
fail(err);
|
|
1671
|
-
}
|
|
1672
|
-
function emitStage(data) {
|
|
1673
|
-
if (!data.staged) {
|
|
1674
|
-
const refusal = approvalRefusal(data.needsApproval);
|
|
1675
|
-
writeJson({
|
|
1676
|
-
ok: false,
|
|
1677
|
-
error: {
|
|
1678
|
-
code: refusal.code,
|
|
1679
|
-
message: data.needsApproval.declined ? "The user said no to this change in the chat." : "This changes money in the store: the user has to say yes to it in the chat first.",
|
|
1680
|
-
fix: refusal.fix
|
|
1681
|
-
}
|
|
1682
|
-
});
|
|
1683
|
-
process.exit(1);
|
|
1684
|
-
}
|
|
1685
|
-
writeJson({ ok: true, hints: stageHints(data), data });
|
|
1686
|
-
}
|
|
1687
|
-
async function stage(ops) {
|
|
1688
|
-
const chatId = requireChatId();
|
|
1689
|
-
try {
|
|
1690
|
-
const [only] = ops;
|
|
1691
|
-
const data = ops.length === 1 && only ? await apiPost("/api/shopify/draft/stage", { chatId, op: only }) : await apiPost("/api/shopify/draft/stage-batch", { chatId, ops });
|
|
1692
|
-
emitStage(data);
|
|
1693
|
-
} catch (err) {
|
|
1694
|
-
failChange(err);
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
function list(value) {
|
|
1698
|
-
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
1699
|
-
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
1700
|
-
}
|
|
1701
|
-
function defined(entries) {
|
|
1702
|
-
return Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== void 0 && value !== ""));
|
|
1703
|
-
}
|
|
1704
|
-
function payloadsFrom(args) {
|
|
1705
|
-
if (typeof args.json !== "string" && typeof args.file !== "string") return null;
|
|
1706
|
-
return loadJsonPayloads(args);
|
|
1707
|
-
}
|
|
1708
|
-
var JSON_ARGS = {
|
|
1709
|
-
json: {
|
|
1710
|
-
type: "string",
|
|
1711
|
-
description: 'The change as inline JSON: a payload for the target given (e.g. {"addTags":["summer"]}), or an array of {"kind","target","payload"} items to stage together in one store read',
|
|
1712
|
-
required: false
|
|
1713
|
-
},
|
|
1714
|
-
file: { type: "string", description: "A JSON file holding the same", required: false }
|
|
1715
|
-
};
|
|
1716
|
-
function leaf(schemaName, meta, args, run) {
|
|
1717
|
-
registerSchema({
|
|
1718
|
-
command: schemaName,
|
|
1719
|
-
description: meta.description,
|
|
1720
|
-
args: Object.fromEntries(
|
|
1721
|
-
Object.entries(args).map(([name, arg]) => [
|
|
1722
|
-
name,
|
|
1723
|
-
{
|
|
1724
|
-
type: String(arg.type ?? "string"),
|
|
1725
|
-
description: String(arg.description ?? ""),
|
|
1726
|
-
required: arg.required === true
|
|
1727
|
-
}
|
|
1728
|
-
])
|
|
1729
|
-
)
|
|
1730
|
-
});
|
|
1731
|
-
return defineCommand2({ meta, args, run: async ({ args: parsed }) => await run(parsed) });
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
// src/commands/shopify/change.ts
|
|
2077
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
1735
2078
|
var TARGET = (what) => ({ type: "positional", description: what, required: false });
|
|
1736
2079
|
function positionals(args) {
|
|
1737
2080
|
return Array.isArray(args._) ? args._.filter((value) => typeof value === "string") : [];
|
|
@@ -2221,8 +2564,8 @@ var measurementReconnect = leaf(
|
|
|
2221
2564
|
{},
|
|
2222
2565
|
async () => await stage([{ kind: "shopify.webPixel.update" }])
|
|
2223
2566
|
);
|
|
2224
|
-
var group = (name, description2, subCommands) =>
|
|
2225
|
-
var changeCommand =
|
|
2567
|
+
var group = (name, description2, subCommands) => defineCommand4({ meta: { name, description: description2 }, subCommands });
|
|
2568
|
+
var changeCommand = defineCommand4({
|
|
2226
2569
|
meta: {
|
|
2227
2570
|
name: "change",
|
|
2228
2571
|
description: `Stage a change to the connected store. Nothing changes until the user publishes the chat; every
|
|
@@ -2333,7 +2676,7 @@ var undoCommand = leaf(
|
|
|
2333
2676
|
);
|
|
2334
2677
|
|
|
2335
2678
|
// src/commands/shopify/draft.ts
|
|
2336
|
-
import { defineCommand as
|
|
2679
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
2337
2680
|
function refOf(args) {
|
|
2338
2681
|
const [ref] = Array.isArray(args._) ? args._ : [];
|
|
2339
2682
|
if (typeof ref !== "string" || ref === "")
|
|
@@ -2438,13 +2781,13 @@ var clear = leaf(
|
|
|
2438
2781
|
}
|
|
2439
2782
|
}
|
|
2440
2783
|
);
|
|
2441
|
-
var draftCommand =
|
|
2784
|
+
var draftCommand = defineCommand5({
|
|
2442
2785
|
meta: { name: "draft", description: "List, show, amend, remove or clear the store changes staged on this chat" },
|
|
2443
2786
|
subCommands: { list: list2, show, amend, remove, clear }
|
|
2444
2787
|
});
|
|
2445
2788
|
|
|
2446
2789
|
// src/commands/shopify/promotions.ts
|
|
2447
|
-
import { defineCommand as
|
|
2790
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
2448
2791
|
|
|
2449
2792
|
// src/commands/shopify/landingLinks.ts
|
|
2450
2793
|
import { readdir, readFile, stat } from "fs/promises";
|
|
@@ -2748,7 +3091,7 @@ function promotionsShown(answer, full) {
|
|
|
2748
3091
|
const { remembered: _remembered, ...shown } = answer;
|
|
2749
3092
|
return shown;
|
|
2750
3093
|
}
|
|
2751
|
-
var promotionsCommand =
|
|
3094
|
+
var promotionsCommand = defineCommand6({
|
|
2752
3095
|
meta: {
|
|
2753
3096
|
name: "promotions",
|
|
2754
3097
|
description: "What advertises one product: ads that lead to it, landings that link to it, Shopping that shows it. Example: baker shopify promotions 10310413942969"
|
|
@@ -2794,7 +3137,7 @@ var promotionsCommand = defineCommand5({
|
|
|
2794
3137
|
}
|
|
2795
3138
|
}
|
|
2796
3139
|
});
|
|
2797
|
-
var stockHoldsCommand =
|
|
3140
|
+
var stockHoldsCommand = defineCommand6({
|
|
2798
3141
|
meta: {
|
|
2799
3142
|
name: "stock-holds",
|
|
2800
3143
|
description: "The ads Baker paused because a product ran out, and whether each may be resumed now. Example: baker shopify stock-holds --product 10310413942969"
|
|
@@ -2822,7 +3165,7 @@ var stockHoldsCommand = defineCommand5({
|
|
|
2822
3165
|
});
|
|
2823
3166
|
|
|
2824
3167
|
// ../api/src/shopify/signups.ts
|
|
2825
|
-
import { z as
|
|
3168
|
+
import { z as z4 } from "zod";
|
|
2826
3169
|
var SIGNUP_CODE_PATTERN = /^[A-Z0-9]{2,12}-[0-9A-HJKMNP-TV-Z]{8}$/;
|
|
2827
3170
|
var SIGNUP_STATES = [
|
|
2828
3171
|
"waiting",
|
|
@@ -2835,10 +3178,10 @@ var SIGNUP_STATES = [
|
|
|
2835
3178
|
"unavailable"
|
|
2836
3179
|
];
|
|
2837
3180
|
var CODE_STATES = /* @__PURE__ */ new Set(["ready", "used", "expired"]);
|
|
2838
|
-
var shopifySignupReplySchema =
|
|
2839
|
-
state:
|
|
2840
|
-
code:
|
|
2841
|
-
endsAt:
|
|
3181
|
+
var shopifySignupReplySchema = z4.object({
|
|
3182
|
+
state: z4.enum(SIGNUP_STATES),
|
|
3183
|
+
code: z4.string().regex(SIGNUP_CODE_PATTERN).optional(),
|
|
3184
|
+
endsAt: z4.string().min(1).max(40).optional()
|
|
2842
3185
|
}).strict().refine(
|
|
2843
3186
|
(reply) => CODE_STATES.has(reply.state) ? reply.code !== void 0 && reply.endsAt !== void 0 : true,
|
|
2844
3187
|
"a code state carries the code and when it ends"
|
|
@@ -2846,39 +3189,39 @@ var shopifySignupReplySchema = z3.object({
|
|
|
2846
3189
|
(reply) => CODE_STATES.has(reply.state) ? true : reply.code === void 0 && reply.endsAt === void 0,
|
|
2847
3190
|
"only the browser the code was given to is told it"
|
|
2848
3191
|
);
|
|
2849
|
-
var shopifySignupResponseSchema =
|
|
2850
|
-
|
|
2851
|
-
|
|
3192
|
+
var shopifySignupResponseSchema = z4.union([
|
|
3193
|
+
z4.object({ ok: z4.literal(true), signup: shopifySignupReplySchema }).passthrough(),
|
|
3194
|
+
z4.object({ error: z4.string(), signup: shopifySignupReplySchema }).passthrough()
|
|
2852
3195
|
]);
|
|
2853
|
-
var signupOfferStatusSchema =
|
|
2854
|
-
var shopifySignupOfferViewSchema =
|
|
2855
|
-
handle:
|
|
2856
|
-
name:
|
|
3196
|
+
var signupOfferStatusSchema = z4.enum(["active", "ended", "staged"]);
|
|
3197
|
+
var shopifySignupOfferViewSchema = z4.object({
|
|
3198
|
+
handle: z4.string(),
|
|
3199
|
+
name: z4.string(),
|
|
2857
3200
|
/** "10% off everything, each code valid 14 days, at most 1,000 codes". */
|
|
2858
|
-
summary:
|
|
3201
|
+
summary: z4.string(),
|
|
2859
3202
|
status: signupOfferStatusSchema,
|
|
2860
|
-
validForDays:
|
|
2861
|
-
endsAt:
|
|
2862
|
-
maxCodes:
|
|
2863
|
-
codesGiven:
|
|
3203
|
+
validForDays: z4.number(),
|
|
3204
|
+
endsAt: z4.string().optional(),
|
|
3205
|
+
maxCodes: z4.number().optional(),
|
|
3206
|
+
codesGiven: z4.number()
|
|
2864
3207
|
});
|
|
2865
|
-
var shopifySignupOffersResponseSchema =
|
|
3208
|
+
var shopifySignupOffersResponseSchema = z4.object({
|
|
2866
3209
|
/** The company has a store connection Baker can use (connected, not waiting on a reconnect). */
|
|
2867
|
-
connected:
|
|
3210
|
+
connected: z4.boolean(),
|
|
2868
3211
|
/** The store allows Baker to add customers (sign-ups work). */
|
|
2869
|
-
canAddCustomers:
|
|
3212
|
+
canAddCustomers: z4.boolean(),
|
|
2870
3213
|
/** The store allows Baker to make discount codes (offers give codes). */
|
|
2871
|
-
canGiveCodes:
|
|
2872
|
-
offers:
|
|
3214
|
+
canGiveCodes: z4.boolean(),
|
|
3215
|
+
offers: z4.array(shopifySignupOfferViewSchema),
|
|
2873
3216
|
/** Sign-ups the store didn't take in the last 7 days: for a missing permission, and for anything else. */
|
|
2874
|
-
refusedLast7Days:
|
|
3217
|
+
refusedLast7Days: z4.object({ permission: z4.number(), other: z4.number() })
|
|
2875
3218
|
});
|
|
2876
3219
|
|
|
2877
3220
|
// src/commands/shopify/signupOffers.ts
|
|
2878
|
-
import { defineCommand as
|
|
3221
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
2879
3222
|
var description = "Start here for landing sign-ups: published and this chat's staged offers, codes given and store permissions. Example: baker shopify signup-offers. Forms name an offer handle; terms are staged with baker shopify change signup-offer set.";
|
|
2880
3223
|
registerSchema({ command: "shopify.signupOffers", description, args: {} });
|
|
2881
|
-
var signupOffersCommand =
|
|
3224
|
+
var signupOffersCommand = defineCommand7({
|
|
2882
3225
|
meta: { name: "signup-offers", description },
|
|
2883
3226
|
async run() {
|
|
2884
3227
|
try {
|
|
@@ -2910,7 +3253,7 @@ var signupOffersCommand = defineCommand6({
|
|
|
2910
3253
|
});
|
|
2911
3254
|
|
|
2912
3255
|
// src/commands/shopify/tracking.ts
|
|
2913
|
-
import { defineCommand as
|
|
3256
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
2914
3257
|
var audit = leaf(
|
|
2915
3258
|
"shopify.tracking.audit",
|
|
2916
3259
|
{
|
|
@@ -2927,7 +3270,7 @@ var audit = leaf(
|
|
|
2927
3270
|
}
|
|
2928
3271
|
}
|
|
2929
3272
|
);
|
|
2930
|
-
var trackingCommand =
|
|
3273
|
+
var trackingCommand = defineCommand8({
|
|
2931
3274
|
meta: { name: "tracking", description: "Check how the store is measured: baker shopify tracking audit" },
|
|
2932
3275
|
subCommands: { audit }
|
|
2933
3276
|
});
|
|
@@ -3013,7 +3356,7 @@ registerSchema({
|
|
|
3013
3356
|
});
|
|
3014
3357
|
registerSchema({
|
|
3015
3358
|
command: "shopify.collections",
|
|
3016
|
-
description: "The connected store's collections, with the handle `--collection` takes, how many products Shopify counts in each, and `storeUrl`: the collection's page on the store, the link for an ad, an email or a message \u2014 use it as given, never build a /collections/ link yourself; no `storeUrl` means shoppers can't open that collection. `--full` adds each one's description, image and SEO.",
|
|
3359
|
+
description: "The connected store's collections, with the handle `--collection` takes, how many products Shopify counts in each, and `storeUrl`: the collection's page on the store, the link for an ad, an email or a message, and on a landing `<ShopifyStoreLink href=\"<storeUrl>\">\u2026</ShopifyStoreLink>` \u2014 use it as given, never build a /collections/ link yourself; no `storeUrl` means shoppers can't open that collection. `--full` adds each one's description, image and SEO.",
|
|
3017
3360
|
args: {
|
|
3018
3361
|
search: { type: "string", description: "Words in the collection's title or handle", required: false },
|
|
3019
3362
|
full: { ...fullArg, description: "Add each collection's description, image and SEO" }
|
|
@@ -3060,7 +3403,7 @@ registerSchema({
|
|
|
3060
3403
|
}
|
|
3061
3404
|
}
|
|
3062
3405
|
});
|
|
3063
|
-
var salesCommand =
|
|
3406
|
+
var salesCommand = defineCommand9({
|
|
3064
3407
|
meta: {
|
|
3065
3408
|
name: "sales",
|
|
3066
3409
|
description: "What the store sold: orders, sales, refunds and net, by day, product, campaign or landing \u2014 or when buyers order (weekday, hour, month). Example: baker shopify sales --days 7 --by campaign"
|
|
@@ -3098,7 +3441,7 @@ var salesCommand = defineCommand8({
|
|
|
3098
3441
|
}
|
|
3099
3442
|
}
|
|
3100
3443
|
});
|
|
3101
|
-
var storeCommand =
|
|
3444
|
+
var storeCommand = defineCommand9({
|
|
3102
3445
|
meta: {
|
|
3103
3446
|
name: "store",
|
|
3104
3447
|
description: "The connected Shopify store: currency, countries, how many products, what is out of stock. Example: baker shopify store"
|
|
@@ -3116,7 +3459,7 @@ var storeCommand = defineCommand8({
|
|
|
3116
3459
|
}
|
|
3117
3460
|
}
|
|
3118
3461
|
});
|
|
3119
|
-
var productsCommand =
|
|
3462
|
+
var productsCommand = defineCommand9({
|
|
3120
3463
|
meta: {
|
|
3121
3464
|
name: "products",
|
|
3122
3465
|
description: 'What the store sells, with price and stock. Example: baker shopify products --search "snowboard" --stock out_of_stock'
|
|
@@ -3162,7 +3505,7 @@ var productsCommand = defineCommand8({
|
|
|
3162
3505
|
}
|
|
3163
3506
|
}
|
|
3164
3507
|
});
|
|
3165
|
-
var productCommand =
|
|
3508
|
+
var productCommand = defineCommand9({
|
|
3166
3509
|
meta: {
|
|
3167
3510
|
name: "product",
|
|
3168
3511
|
description: "One product: options with buy links, prices by country, stock, photo imageIds, video playbackIds. Accepts an id, handle or link. Example: baker shopify product the-complete-snowboard --content"
|
|
@@ -3225,7 +3568,7 @@ var productCommand = defineCommand8({
|
|
|
3225
3568
|
}
|
|
3226
3569
|
}
|
|
3227
3570
|
});
|
|
3228
|
-
var collectionsCommand =
|
|
3571
|
+
var collectionsCommand = defineCommand9({
|
|
3229
3572
|
meta: {
|
|
3230
3573
|
name: "collections",
|
|
3231
3574
|
description: "The store's collections, with the handles --collection takes and each one's page on the store (storeUrl). Example: baker shopify collections --full"
|
|
@@ -3250,7 +3593,7 @@ var collectionsCommand = defineCommand8({
|
|
|
3250
3593
|
}
|
|
3251
3594
|
}
|
|
3252
3595
|
});
|
|
3253
|
-
var stockCommand =
|
|
3596
|
+
var stockCommand = defineCommand9({
|
|
3254
3597
|
meta: {
|
|
3255
3598
|
name: "stock",
|
|
3256
3599
|
description: "Every product with options out of stock, naming them. Example: baker shopify stock"
|
|
@@ -3274,7 +3617,7 @@ var stockCommand = defineCommand8({
|
|
|
3274
3617
|
}
|
|
3275
3618
|
}
|
|
3276
3619
|
});
|
|
3277
|
-
var shopifyCommand =
|
|
3620
|
+
var shopifyCommand = defineCommand9({
|
|
3278
3621
|
meta: {
|
|
3279
3622
|
name: "shopify",
|
|
3280
3623
|
description: `Read the connected Shopify store as Baker keeps it \u2014 products, prices by country, stock, collections,
|
|
@@ -3313,6 +3656,8 @@ Product photos are already in the image library: place them by imageId
|
|
|
3313
3656
|
Product videos are in the video library: place them with <Video playbackId="\u2026" />.
|
|
3314
3657
|
On a landing, the buy button is <ShopifyProduct product="\u2026"/> \u2014 never a buyUrl or a Shopify link
|
|
3315
3658
|
written by hand. buyUrl is for ads, emails and messages; never use storeUrl (a page to look at) for it.
|
|
3659
|
+
A landing links to a page of the store (a collection, another product, the home) with
|
|
3660
|
+
<ShopifyStoreLink href="<storeUrl or storefrontUrl as given>">\u2026</ShopifyStoreLink>.
|
|
3316
3661
|
NO_SHOPIFY_CONNECTION means no store is connected: follow error.fix. SHOPIFY_NOT_AVAILABLE means it cannot be
|
|
3317
3662
|
connected here yet: carry on without it.
|
|
3318
3663
|
Full guide: __tooling__/docs/tools/baker/shopify.md`
|
|
@@ -3331,6 +3676,7 @@ Full guide: __tooling__/docs/tools/baker/shopify.md`
|
|
|
3331
3676
|
"best-sellers": bestSellersCommand,
|
|
3332
3677
|
cohorts: cohortsCommand,
|
|
3333
3678
|
segments: segmentsCommand,
|
|
3679
|
+
audiences: audiencesCommand,
|
|
3334
3680
|
promotions: promotionsCommand,
|
|
3335
3681
|
"stock-holds": stockHoldsCommand,
|
|
3336
3682
|
change: changeCommand,
|
|
@@ -3343,4 +3689,4 @@ Full guide: __tooling__/docs/tools/baker/shopify.md`
|
|
|
3343
3689
|
export {
|
|
3344
3690
|
shopifyCommand
|
|
3345
3691
|
};
|
|
3346
|
-
//# sourceMappingURL=shopify-
|
|
3692
|
+
//# sourceMappingURL=shopify-2OY3J3OY.js.map
|