@sonordev/site-kit 5.7.0 → 5.8.1
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 +3 -3
- package/agent-manifest.json +14 -2
- package/dist/AnalyticsProvider-ERNSZ4DH.mjs +12 -0
- package/dist/{AnalyticsProvider-EWF7JN2X.mjs.map → AnalyticsProvider-ERNSZ4DH.mjs.map} +1 -1
- package/dist/AnalyticsProvider-HE6V5UJD.js +33 -0
- package/dist/{AnalyticsProvider-GJFG7YXA.js.map → AnalyticsProvider-HE6V5UJD.js.map} +1 -1
- package/dist/{BlogViewTracker-CKYG6MYU.mjs → BlogViewTracker-2NQ5LBVR.mjs} +13 -10
- package/dist/BlogViewTracker-2NQ5LBVR.mjs.map +1 -0
- package/dist/{BlogViewTracker-2D3IJPJK.js → BlogViewTracker-4OGWSC2Q.js} +14 -11
- package/dist/BlogViewTracker-4OGWSC2Q.js.map +1 -0
- package/dist/ChatWidget-67CHHONZ.js +24 -0
- package/dist/{ChatWidget-AWP6GBVW.js.map → ChatWidget-67CHHONZ.js.map} +1 -1
- package/dist/ChatWidget-T4RICLLT.mjs +15 -0
- package/dist/{ChatWidget-Z5QXDZP3.mjs.map → ChatWidget-T4RICLLT.mjs.map} +1 -1
- package/dist/EngageWidget-TDW2ZI3Q.js +21 -0
- package/dist/{EngageWidget-VT4DYXVO.js.map → EngageWidget-TDW2ZI3Q.js.map} +1 -1
- package/dist/EngageWidget-WXEQTV4X.mjs +12 -0
- package/dist/{EngageWidget-BKEY5TPO.mjs.map → EngageWidget-WXEQTV4X.mjs.map} +1 -1
- package/dist/{FileField-62ZWZMQK.js → FileField-DEVOXJSO.js} +6 -6
- package/dist/{FileField-62ZWZMQK.js.map → FileField-DEVOXJSO.js.map} +1 -1
- package/dist/{FileField-JJN5QKDL.mjs → FileField-Y5YM365S.mjs} +5 -5
- package/dist/{FileField-JJN5QKDL.mjs.map → FileField-Y5YM365S.mjs.map} +1 -1
- package/dist/{FormSpotlight-URS4XRS7.js → FormSpotlight-4Q5FM3YS.js} +25 -21
- package/dist/FormSpotlight-4Q5FM3YS.js.map +1 -0
- package/dist/{FormSpotlight-OTFB6QM5.mjs → FormSpotlight-T3ASGUYB.mjs} +11 -7
- package/dist/FormSpotlight-T3ASGUYB.mjs.map +1 -0
- package/dist/{FormStage-FVKMIV73.js → FormStage-PSAIPZBS.js} +20 -15
- package/dist/FormStage-PSAIPZBS.js.map +1 -0
- package/dist/{FormStage-VPGOCMAV.mjs → FormStage-U5V4MI5Q.mjs} +9 -4
- package/dist/FormStage-U5V4MI5Q.mjs.map +1 -0
- package/dist/ManagedForm-EAZOMNSL.mjs +16 -0
- package/dist/{ManagedForm-CXVDJMHN.mjs.map → ManagedForm-EAZOMNSL.mjs.map} +1 -1
- package/dist/ManagedForm-R6DJXU34.js +25 -0
- package/dist/{ManagedForm-FGNTDGED.js.map → ManagedForm-R6DJXU34.js.map} +1 -1
- package/dist/{ManagedNewsletterForm-SQYB4BZU.mjs → ManagedNewsletterForm-5RY3TWPQ.mjs} +9 -7
- package/dist/ManagedNewsletterForm-5RY3TWPQ.mjs.map +1 -0
- package/dist/{ManagedNewsletterForm-3O5L44AZ.js → ManagedNewsletterForm-VX6GMZXJ.js} +10 -8
- package/dist/ManagedNewsletterForm-VX6GMZXJ.js.map +1 -0
- package/dist/{SignalCore-RFBOBNLQ.js → SignalCore-MWHF2WG4.js} +14 -20
- package/dist/SignalCore-MWHF2WG4.js.map +1 -0
- package/dist/{SignalCore-M2PKKIGH.mjs → SignalCore-ZT6EQGV3.mjs} +8 -14
- package/dist/SignalCore-ZT6EQGV3.mjs.map +1 -0
- package/dist/SitemapSync-OG4TQLDB.mjs +9 -0
- package/dist/{SitemapSync-4OVMIIGC.mjs.map → SitemapSync-OG4TQLDB.mjs.map} +1 -1
- package/dist/SitemapSync-Z62BGZMV.js +18 -0
- package/dist/{SitemapSync-RK3SQ4M2.js.map → SitemapSync-Z62BGZMV.js.map} +1 -1
- package/dist/analytics/AnalyticsProvider.d.ts.map +1 -1
- package/dist/analytics/index.js +10 -9
- package/dist/analytics/index.mjs +5 -4
- package/dist/api-D745LGGU.mjs +0 -1
- package/dist/api-XR5APCH3.js +0 -1
- package/dist/blog/BlogLayout.d.ts +3 -1
- package/dist/blog/BlogLayout.d.ts.map +1 -1
- package/dist/blog/BlogList.d.ts +7 -1
- package/dist/blog/BlogList.d.ts.map +1 -1
- package/dist/blog/BlogPost.d.ts +20 -1
- package/dist/blog/BlogPost.d.ts.map +1 -1
- package/dist/blog/BlogSidebar.d.ts +3 -1
- package/dist/blog/BlogSidebar.d.ts.map +1 -1
- package/dist/blog/BlogViewTracker.d.ts +8 -2
- package/dist/blog/BlogViewTracker.d.ts.map +1 -1
- package/dist/blog/ClusterLandingPage.d.ts +3 -1
- package/dist/blog/ClusterLandingPage.d.ts.map +1 -1
- package/dist/blog/ClusterNavigation.d.ts +5 -2
- package/dist/blog/ClusterNavigation.d.ts.map +1 -1
- package/dist/blog/RelatedPosts.d.ts +3 -1
- package/dist/blog/RelatedPosts.d.ts.map +1 -1
- package/dist/blog/index.d.ts +1 -1
- package/dist/blog/index.d.ts.map +1 -1
- package/dist/blog/index.js +40 -31
- package/dist/blog/index.js.map +1 -1
- package/dist/blog/index.mjs +11 -6
- package/dist/blog/index.mjs.map +1 -1
- package/dist/blog/processBlogHtml.d.ts +19 -2
- package/dist/blog/processBlogHtml.d.ts.map +1 -1
- package/dist/blog/public-reads.d.ts +27 -0
- package/dist/blog/public-reads.d.ts.map +1 -0
- package/dist/blog/server-core.d.ts +76 -10
- package/dist/blog/server-core.d.ts.map +1 -1
- package/dist/blog/server-ui.js +29 -23
- package/dist/blog/server-ui.js.map +1 -1
- package/dist/blog/server-ui.mjs +12 -6
- package/dist/blog/server-ui.mjs.map +1 -1
- package/dist/blog/server.d.ts +76 -10
- package/dist/blog/server.d.ts.map +1 -1
- package/dist/blog/server.js +54 -47
- package/dist/blog/server.mjs +5 -2
- package/dist/brand/extract-brand-profile.d.ts +36 -2
- package/dist/brand/extract-brand-profile.d.ts.map +1 -1
- package/dist/{chunk-MW2M6O7A.mjs → chunk-26EKSVXM.mjs} +4 -4
- package/dist/{chunk-MW2M6O7A.mjs.map → chunk-26EKSVXM.mjs.map} +1 -1
- package/dist/{chunk-D553G64G.js → chunk-2HPQTRUB.js} +13 -13
- package/dist/{chunk-D553G64G.js.map → chunk-2HPQTRUB.js.map} +1 -1
- package/dist/{chunk-BFJOZ3MU.mjs → chunk-3EY5E35M.mjs} +36 -71
- package/dist/chunk-3EY5E35M.mjs.map +1 -0
- package/dist/{chunk-BUJWXSYZ.mjs → chunk-3TQUARVN.mjs} +4 -4
- package/dist/{chunk-BUJWXSYZ.mjs.map → chunk-3TQUARVN.mjs.map} +1 -1
- package/dist/{chunk-OYOO2OO5.js → chunk-3VRWKKTD.js} +10 -10
- package/dist/{chunk-OYOO2OO5.js.map → chunk-3VRWKKTD.js.map} +1 -1
- package/dist/{chunk-BFM5PEFV.js → chunk-43I7U5AI.js} +56 -177
- package/dist/chunk-43I7U5AI.js.map +1 -0
- package/dist/{chunk-ILNCUSXW.mjs → chunk-4L7OHRWB.mjs} +12 -9
- package/dist/chunk-4L7OHRWB.mjs.map +1 -0
- package/dist/chunk-4LYW6PMU.mjs +72 -0
- package/dist/chunk-4LYW6PMU.mjs.map +1 -0
- package/dist/chunk-4TLFZ6NR.mjs +16 -0
- package/dist/chunk-4TLFZ6NR.mjs.map +1 -0
- package/dist/{chunk-JQ7M6CVL.mjs → chunk-4VSDMNQU.mjs} +3 -3
- package/dist/{chunk-JQ7M6CVL.mjs.map → chunk-4VSDMNQU.mjs.map} +1 -1
- package/dist/{chunk-4B4S56WJ.mjs → chunk-5B4J3IBX.mjs} +75 -21
- package/dist/chunk-5B4J3IBX.mjs.map +1 -0
- package/dist/{chunk-M5GY2AI3.mjs → chunk-5K6B4LWV.mjs} +4 -10
- package/dist/chunk-5K6B4LWV.mjs.map +1 -0
- package/dist/chunk-5SANRSX3.mjs +17 -0
- package/dist/chunk-5SANRSX3.mjs.map +1 -0
- package/dist/chunk-5XFFUP6D.js +100 -0
- package/dist/chunk-5XFFUP6D.js.map +1 -0
- package/dist/chunk-5YA6SI4Z.mjs +0 -1
- package/dist/{chunk-TDJKGN5Q.mjs → chunk-62Y4W4LR.mjs} +216 -103
- package/dist/chunk-62Y4W4LR.mjs.map +1 -0
- package/dist/{chunk-3CLP35TT.mjs → chunk-6S3JE66D.mjs} +62 -97
- package/dist/chunk-6S3JE66D.mjs.map +1 -0
- package/dist/{chunk-4A5V73SR.mjs → chunk-6WEZWYRU.mjs} +9 -9
- package/dist/{chunk-4A5V73SR.mjs.map → chunk-6WEZWYRU.mjs.map} +1 -1
- package/dist/{chunk-JTF4DFUF.mjs → chunk-7AEVA667.mjs} +4 -4
- package/dist/{chunk-JTF4DFUF.mjs.map → chunk-7AEVA667.mjs.map} +1 -1
- package/dist/{chunk-H65OX263.js → chunk-7DV7Y7BZ.js} +15 -15
- package/dist/{chunk-H65OX263.js.map → chunk-7DV7Y7BZ.js.map} +1 -1
- package/dist/{chunk-7ZX6TO6C.mjs → chunk-7H4HB4UZ.mjs} +50 -26
- package/dist/chunk-7H4HB4UZ.mjs.map +1 -0
- package/dist/{chunk-FO4KGPGF.js → chunk-7TC3GRXQ.js} +73 -38
- package/dist/chunk-7TC3GRXQ.js.map +1 -0
- package/dist/{chunk-UQ5YULFU.mjs → chunk-AUHUEIBB.mjs} +4 -4
- package/dist/{chunk-UQ5YULFU.mjs.map → chunk-AUHUEIBB.mjs.map} +1 -1
- package/dist/{chunk-BQGEVMIR.mjs → chunk-AWF73RU2.mjs} +5 -5
- package/dist/{chunk-BQGEVMIR.mjs.map → chunk-AWF73RU2.mjs.map} +1 -1
- package/dist/{chunk-ELQ4SRRR.js → chunk-BHBW2SZF.js} +15 -15
- package/dist/{chunk-ELQ4SRRR.js.map → chunk-BHBW2SZF.js.map} +1 -1
- package/dist/{chunk-RNAGCAIB.js → chunk-BIGXEYKT.js} +7 -7
- package/dist/{chunk-RNAGCAIB.js.map → chunk-BIGXEYKT.js.map} +1 -1
- package/dist/chunk-BQP6JIE2.mjs +28 -0
- package/dist/chunk-BQP6JIE2.mjs.map +1 -0
- package/dist/{chunk-VFGEY6FJ.js → chunk-BY35X57A.js} +223 -110
- package/dist/chunk-BY35X57A.js.map +1 -0
- package/dist/{chunk-3YQILJKJ.js → chunk-CGCUHIAR.js} +60 -35
- package/dist/chunk-CGCUHIAR.js.map +1 -0
- package/dist/chunk-CUNZAD46.js +53 -0
- package/dist/chunk-CUNZAD46.js.map +1 -0
- package/dist/{chunk-FEWWGEQF.js → chunk-CWUYI6LI.js} +4 -4
- package/dist/{chunk-FEWWGEQF.js.map → chunk-CWUYI6LI.js.map} +1 -1
- package/dist/chunk-CXAXZFFW.js +157 -0
- package/dist/chunk-CXAXZFFW.js.map +1 -0
- package/dist/{chunk-H4OBGC43.mjs → chunk-DA7IANFG.mjs} +14 -3
- package/dist/chunk-DA7IANFG.mjs.map +1 -0
- package/dist/{chunk-57AFHENV.mjs → chunk-EHAUNF4V.mjs} +3 -3
- package/dist/{chunk-57AFHENV.mjs.map → chunk-EHAUNF4V.mjs.map} +1 -1
- package/dist/{chunk-2N27LCZH.js → chunk-FEKPEI2G.js} +9 -9
- package/dist/{chunk-2N27LCZH.js.map → chunk-FEKPEI2G.js.map} +1 -1
- package/dist/{chunk-LC7AM4J5.js → chunk-FHPW7XVH.js} +77 -20
- package/dist/chunk-FHPW7XVH.js.map +1 -0
- package/dist/{chunk-JNRHTZL4.js → chunk-FVW6FT6L.js} +73 -29
- package/dist/chunk-FVW6FT6L.js.map +1 -0
- package/dist/{chunk-YKUEFRZI.js → chunk-FWW4K6QP.js} +14 -14
- package/dist/{chunk-YKUEFRZI.js.map → chunk-FWW4K6QP.js.map} +1 -1
- package/dist/{chunk-JNAXDFC4.mjs → chunk-GF4LV5LX.mjs} +38 -156
- package/dist/chunk-GF4LV5LX.mjs.map +1 -0
- package/dist/{chunk-C563AHZZ.mjs → chunk-GKFTJ5AF.mjs} +3 -3
- package/dist/{chunk-C563AHZZ.mjs.map → chunk-GKFTJ5AF.mjs.map} +1 -1
- package/dist/{chunk-OZ3FU4BT.js → chunk-H5NBFNND.js} +2 -2
- package/dist/chunk-H5NBFNND.js.map +1 -0
- package/dist/chunk-HCN3IKMW.mjs +106 -0
- package/dist/chunk-HCN3IKMW.mjs.map +1 -0
- package/dist/{chunk-6FC5Q4KU.mjs → chunk-HOJ4J4X2.mjs} +30 -12
- package/dist/chunk-HOJ4J4X2.mjs.map +1 -0
- package/dist/{chunk-H6YVT3BL.js → chunk-I3ND4XYW.js} +12 -9
- package/dist/chunk-I3ND4XYW.js.map +1 -0
- package/dist/chunk-I7AZC5ZQ.js +0 -1
- package/dist/{chunk-V5THCFPG.mjs → chunk-JFJ7NHS3.mjs} +4 -4
- package/dist/{chunk-V5THCFPG.mjs.map → chunk-JFJ7NHS3.mjs.map} +1 -1
- package/dist/{chunk-KXGD4E7G.js → chunk-JI4EUPHB.js} +7 -7
- package/dist/{chunk-KXGD4E7G.js.map → chunk-JI4EUPHB.js.map} +1 -1
- package/dist/{chunk-GZJE23Y5.mjs → chunk-JLVCWC6A.mjs} +2 -2
- package/dist/chunk-JLVCWC6A.mjs.map +1 -0
- package/dist/chunk-JOYMIGR2.mjs +0 -1
- package/dist/chunk-JS75ORH7.js +0 -1
- package/dist/{chunk-Q7347KP6.mjs → chunk-JX5SM2MX.mjs} +6 -12
- package/dist/chunk-JX5SM2MX.mjs.map +1 -0
- package/dist/chunk-K4TCEAUX.js +52 -0
- package/dist/chunk-K4TCEAUX.js.map +1 -0
- package/dist/chunk-KV7XXLJV.mjs +30 -0
- package/dist/chunk-KV7XXLJV.mjs.map +1 -0
- package/dist/{chunk-JTCQJKJE.js → chunk-LIAISQUE.js} +76 -111
- package/dist/chunk-LIAISQUE.js.map +1 -0
- package/dist/{chunk-CPY74A4F.js → chunk-LMEUYRRR.js} +72 -106
- package/dist/chunk-LMEUYRRR.js.map +1 -0
- package/dist/{chunk-4WBTM6YE.js → chunk-LOEP76MQ.js} +4 -4
- package/dist/{chunk-4WBTM6YE.js.map → chunk-LOEP76MQ.js.map} +1 -1
- package/dist/chunk-LVGSOW2F.js +32 -0
- package/dist/chunk-LVGSOW2F.js.map +1 -0
- package/dist/{chunk-DOB37PV4.js → chunk-M45AL7EA.js} +37 -19
- package/dist/chunk-M45AL7EA.js.map +1 -0
- package/dist/{chunk-RCSTDJUH.js → chunk-M4UVFUFR.js} +8 -13
- package/dist/chunk-M4UVFUFR.js.map +1 -0
- package/dist/{chunk-R2SXXFXZ.mjs → chunk-MI2SRBCR.mjs} +3 -3
- package/dist/{chunk-R2SXXFXZ.mjs.map → chunk-MI2SRBCR.mjs.map} +1 -1
- package/dist/chunk-MLVHVKFT.mjs +148 -0
- package/dist/chunk-MLVHVKFT.mjs.map +1 -0
- package/dist/{chunk-L7ACQ6PC.js → chunk-MOAYT3KN.js} +4 -4
- package/dist/{chunk-L7ACQ6PC.js.map → chunk-MOAYT3KN.js.map} +1 -1
- package/dist/chunk-NG2TTI7D.js +8 -0
- package/dist/{chunk-5TXXTYXL.js.map → chunk-NG2TTI7D.js.map} +1 -1
- package/dist/{chunk-C4PZ2R3B.js → chunk-NLDN6PYM.js} +10 -10
- package/dist/{chunk-C4PZ2R3B.js.map → chunk-NLDN6PYM.js.map} +1 -1
- package/dist/chunk-NN2YE5WT.js +0 -1
- package/dist/chunk-NNZDWY3L.mjs +0 -1
- package/dist/chunk-NRBITVDK.js +114 -0
- package/dist/chunk-NRBITVDK.js.map +1 -0
- package/dist/{chunk-TSZIACRC.js → chunk-OBKYF4TP.js} +6 -12
- package/dist/chunk-OBKYF4TP.js.map +1 -0
- package/dist/{chunk-TP7H6BSK.mjs → chunk-OE7CTIOU.mjs} +73 -30
- package/dist/chunk-OE7CTIOU.mjs.map +1 -0
- package/dist/chunk-OESGRWI4.mjs +6 -0
- package/dist/{chunk-QRBPT6Z6.mjs.map → chunk-OESGRWI4.mjs.map} +1 -1
- package/dist/{chunk-UJ6CHZAI.mjs → chunk-OEW2LFOV.js} +169 -25
- package/dist/chunk-OEW2LFOV.js.map +1 -0
- package/dist/chunk-P4Y75QSU.js +19 -0
- package/dist/chunk-P4Y75QSU.js.map +1 -0
- package/dist/{chunk-47XQWV4S.mjs → chunk-PQVQAX67.mjs} +3 -3
- package/dist/{chunk-47XQWV4S.mjs.map → chunk-PQVQAX67.mjs.map} +1 -1
- package/dist/chunk-QRHVMTHF.mjs +94 -0
- package/dist/chunk-QRHVMTHF.mjs.map +1 -0
- package/dist/{chunk-FBDHKYNF.mjs → chunk-R4B3DFF4.mjs} +3 -3
- package/dist/{chunk-FBDHKYNF.mjs.map → chunk-R4B3DFF4.mjs.map} +1 -1
- package/dist/chunk-R7GHP3FY.js +81 -0
- package/dist/chunk-R7GHP3FY.js.map +1 -0
- package/dist/{chunk-4UVM7E2W.js → chunk-S5VL7AWW.js} +3 -3
- package/dist/{chunk-4UVM7E2W.js.map → chunk-S5VL7AWW.js.map} +1 -1
- package/dist/{chunk-P4TB4ROG.js → chunk-SEP5D4MI.js} +8 -2
- package/dist/chunk-SEP5D4MI.js.map +1 -0
- package/dist/{chunk-L4V6TKMJ.mjs → chunk-U2V542EO.mjs} +7 -3
- package/dist/chunk-U2V542EO.mjs.map +1 -0
- package/dist/{chunk-HBN4A2N4.mjs → chunk-U6H5ZY3B.mjs} +3 -3
- package/dist/{chunk-HBN4A2N4.mjs.map → chunk-U6H5ZY3B.mjs.map} +1 -1
- package/dist/{chunk-H7274TKR.mjs → chunk-VJV7WUR2.mjs} +12 -4
- package/dist/chunk-VJV7WUR2.mjs.map +1 -0
- package/dist/{chunk-F3AKYZOH.js → chunk-WED6ZDVS.js} +6 -13
- package/dist/chunk-WED6ZDVS.js.map +1 -0
- package/dist/{chunk-5B4FABFK.js → chunk-WS7MH3GD.js} +14 -2
- package/dist/chunk-WS7MH3GD.js.map +1 -0
- package/dist/{chunk-XLPU3TEE.mjs → chunk-X22BGNVL.mjs} +4 -4
- package/dist/{chunk-XLPU3TEE.mjs.map → chunk-X22BGNVL.mjs.map} +1 -1
- package/dist/{chunk-IPV2TUAT.js → chunk-XA2GJFVM.js} +12 -4
- package/dist/chunk-XA2GJFVM.js.map +1 -0
- package/dist/chunk-XBX2K3GA.js +33 -0
- package/dist/chunk-XBX2K3GA.js.map +1 -0
- package/dist/{chunk-ABZGEHTC.mjs → chunk-XSAHJ2BB.mjs} +3 -3
- package/dist/{chunk-ABZGEHTC.mjs.map → chunk-XSAHJ2BB.mjs.map} +1 -1
- package/dist/{chunk-6CJP7BFM.js → chunk-XZO5I4RS.mjs} +147 -20
- package/dist/chunk-XZO5I4RS.mjs.map +1 -0
- package/dist/chunk-Y5QZPUL3.mjs +47 -0
- package/dist/chunk-Y5QZPUL3.mjs.map +1 -0
- package/dist/{chunk-NOU3JQJK.js → chunk-Y6Z2W45H.js} +8 -8
- package/dist/{chunk-NOU3JQJK.js.map → chunk-Y6Z2W45H.js.map} +1 -1
- package/dist/{chunk-YYDZ2TYR.js → chunk-YCFYQN2Q.js} +3 -3
- package/dist/{chunk-YYDZ2TYR.js.map → chunk-YCFYQN2Q.js.map} +1 -1
- package/dist/chunk-YN7QHLWF.js +19 -0
- package/dist/chunk-YN7QHLWF.js.map +1 -0
- package/dist/{chunk-O2VJZOR2.mjs → chunk-YRNDASQY.mjs} +6 -11
- package/dist/chunk-YRNDASQY.mjs.map +1 -0
- package/dist/chunk-YU7QZ3PP.mjs +45 -0
- package/dist/chunk-YU7QZ3PP.mjs.map +1 -0
- package/dist/{chunk-3S5JN6KL.js → chunk-ZV6HIQRQ.js} +6 -6
- package/dist/{chunk-3S5JN6KL.js.map → chunk-ZV6HIQRQ.js.map} +1 -1
- package/dist/{chunk-RVRN5U7W.mjs → chunk-ZVI7MBVF.mjs} +73 -38
- package/dist/chunk-ZVI7MBVF.mjs.map +1 -0
- package/dist/cli/agent/checks.d.ts +15 -1
- package/dist/cli/agent/checks.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/og.d.ts +26 -8
- package/dist/cli/commands/og.d.ts.map +1 -1
- package/dist/cli/index.js +683 -323
- package/dist/cli/index.mjs +604 -244
- package/dist/client/index.js +6 -6
- package/dist/client/index.mjs +5 -5
- package/dist/commerce/CheckoutForm.d.ts.map +1 -1
- package/dist/commerce/ProductDetail.d.ts.map +1 -1
- package/dist/commerce/api.d.ts +14 -0
- package/dist/commerce/api.d.ts.map +1 -1
- package/dist/commerce/index.d.ts +1 -1
- package/dist/commerce/index.d.ts.map +1 -1
- package/dist/commerce/index.js +61 -56
- package/dist/commerce/index.mjs +6 -5
- package/dist/config/index.js +3 -3
- package/dist/config/index.mjs +1 -1
- package/dist/discover-CYXYKHZ2.mjs +4 -0
- package/dist/{discover-FGTKWOL3.mjs.map → discover-CYXYKHZ2.mjs.map} +1 -1
- package/dist/discover-NGEPXZOD.js +21 -0
- package/dist/{discover-NJZPWTDL.js.map → discover-NGEPXZOD.js.map} +1 -1
- package/dist/engage/index.js +12 -10
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +9 -7
- package/dist/engage/index.mjs.map +1 -1
- package/dist/fleet/index.js +8 -8
- package/dist/fleet/index.mjs +4 -4
- package/dist/forms/FormClient.d.ts.map +1 -1
- package/dist/forms/FormField.d.ts +7 -1
- package/dist/forms/FormField.d.ts.map +1 -1
- package/dist/forms/FormSpotlight.d.ts +1 -1
- package/dist/forms/FormSpotlight.d.ts.map +1 -1
- package/dist/forms/FormStage.d.ts +1 -1
- package/dist/forms/FormStage.d.ts.map +1 -1
- package/dist/forms/experience-plan.d.ts +0 -1
- package/dist/forms/experience-plan.d.ts.map +1 -1
- package/dist/forms/field-interactions.d.ts +63 -0
- package/dist/forms/field-interactions.d.ts.map +1 -0
- package/dist/forms/field-rules.d.ts +41 -0
- package/dist/forms/field-rules.d.ts.map +1 -0
- package/dist/forms/index.js +25 -23
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +13 -11
- package/dist/forms/index.mjs.map +1 -1
- package/dist/forms/server.js +11 -11
- package/dist/forms/server.mjs +9 -9
- package/dist/forms/static.js +8 -8
- package/dist/forms/static.mjs +7 -7
- package/dist/forms/tracking-session.d.ts +48 -3
- package/dist/forms/tracking-session.d.ts.map +1 -1
- package/dist/forms/types.d.ts +11 -0
- package/dist/forms/types.d.ts.map +1 -1
- package/dist/forms/useForm.d.ts +8 -0
- package/dist/forms/useForm.d.ts.map +1 -1
- package/dist/forms/useFormTracking.d.ts +29 -4
- package/dist/forms/useFormTracking.d.ts.map +1 -1
- package/dist/images/index.js +11 -11
- package/dist/images/index.mjs +4 -4
- package/dist/index.js +72 -68
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -10
- package/dist/index.mjs.map +1 -1
- package/dist/layout/client.js +10 -10
- package/dist/layout/client.mjs +9 -9
- package/dist/layout/index.js +13 -12
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/index.mjs +11 -10
- package/dist/layout/index.mjs.map +1 -1
- package/dist/lib-6HOOMENJ.js +0 -1
- package/dist/lib-BGAWCSUH.js +0 -1
- package/dist/lib-R7IQ4ZHE.mjs +0 -1
- package/dist/lib-RSDMEKDQ.mjs +0 -1
- package/dist/llms/aiRobots.d.ts +20 -4
- package/dist/llms/aiRobots.d.ts.map +1 -1
- package/dist/llms/api.d.ts +8 -3
- package/dist/llms/api.d.ts.map +1 -1
- package/dist/llms/discovery-headers.d.ts +24 -0
- package/dist/llms/discovery-headers.d.ts.map +1 -1
- package/dist/llms/generateLLMsTxt.d.ts.map +1 -1
- package/dist/llms/index.d.ts +2 -2
- package/dist/llms/index.d.ts.map +1 -1
- package/dist/llms/index.js +45 -96
- package/dist/llms/index.js.map +1 -1
- package/dist/llms/index.mjs +11 -81
- package/dist/llms/index.mjs.map +1 -1
- package/dist/llms/links.d.ts +26 -0
- package/dist/llms/links.d.ts.map +1 -0
- package/dist/llms/types.d.ts +15 -0
- package/dist/llms/types.d.ts.map +1 -1
- package/dist/llms/wiring.d.ts +22 -0
- package/dist/llms/wiring.d.ts.map +1 -1
- package/dist/llms/writeLLMsTxt.d.ts +9 -0
- package/dist/llms/writeLLMsTxt.d.ts.map +1 -1
- package/dist/maps/index.js +5 -5
- package/dist/maps/index.mjs +3 -3
- package/dist/motion/gsap.d.ts +54 -0
- package/dist/motion/gsap.d.ts.map +1 -1
- package/dist/motion/gsap.js +34 -4
- package/dist/motion/gsap.js.map +1 -1
- package/dist/motion/gsap.mjs +33 -5
- package/dist/motion/gsap.mjs.map +1 -1
- package/dist/og/config.d.ts +6 -0
- package/dist/og/config.d.ts.map +1 -1
- package/dist/og/contrast.d.ts +33 -0
- package/dist/og/contrast.d.ts.map +1 -0
- package/dist/og/index.d.ts +2 -0
- package/dist/og/index.d.ts.map +1 -1
- package/dist/og/index.js +26 -8
- package/dist/og/index.mjs +3 -1
- package/dist/og/pages.d.ts +101 -0
- package/dist/og/pages.d.ts.map +1 -1
- package/dist/og/route-copy.d.ts +34 -0
- package/dist/og/route-copy.d.ts.map +1 -0
- package/dist/og/route-fit.d.ts +77 -0
- package/dist/og/route-fit.d.ts.map +1 -0
- package/dist/og/route.d.ts +80 -20
- package/dist/og/route.d.ts.map +1 -1
- package/dist/og/route.js +195 -25
- package/dist/og/route.js.map +1 -1
- package/dist/og/route.mjs +193 -26
- package/dist/og/route.mjs.map +1 -1
- package/dist/og/template.d.ts.map +1 -1
- package/dist/og/wiring.d.ts +43 -3
- package/dist/og/wiring.d.ts.map +1 -1
- package/dist/proxy/index.d.ts.map +1 -1
- package/dist/proxy/index.js +15 -10
- package/dist/proxy/index.js.map +1 -1
- package/dist/proxy/index.mjs +12 -7
- package/dist/proxy/index.mjs.map +1 -1
- package/dist/redirects/index.d.ts +24 -0
- package/dist/redirects/index.d.ts.map +1 -1
- package/dist/redirects/index.js +11 -8
- package/dist/redirects/index.mjs +4 -1
- package/dist/redirects/not-found.js +8 -5
- package/dist/redirects/not-found.js.map +1 -1
- package/dist/redirects/not-found.mjs +4 -1
- package/dist/redirects/not-found.mjs.map +1 -1
- package/dist/robots/index.d.ts +2 -0
- package/dist/robots/index.d.ts.map +1 -1
- package/dist/robots/index.js +23 -3
- package/dist/robots/index.js.map +1 -1
- package/dist/robots/index.mjs +2 -2
- package/dist/robots/index.mjs.map +1 -1
- package/dist/search/index.js +4 -4
- package/dist/search/index.mjs +3 -3
- package/dist/seo/ManagedContent.d.ts +4 -2
- package/dist/seo/ManagedContent.d.ts.map +1 -1
- package/dist/seo/ManagedFAQ.d.ts.map +1 -1
- package/dist/seo/ManagedInternalLinks.d.ts.map +1 -1
- package/dist/seo/ManagedSchema.d.ts.map +1 -1
- package/dist/seo/client.js +6 -6
- package/dist/seo/client.mjs +5 -5
- package/dist/seo/getManagedMetadata.d.ts.map +1 -1
- package/dist/seo/index.js +59 -49
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +29 -19
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo/register-sitemap-cli-impl.d.ts +32 -0
- package/dist/seo/register-sitemap-cli-impl.d.ts.map +1 -1
- package/dist/seo/register-sitemap-cli.d.ts +7 -0
- package/dist/seo/register-sitemap-cli.d.ts.map +1 -1
- package/dist/seo/register-sitemap-cli.js +273 -57
- package/dist/seo/register-sitemap-cli.mjs +269 -53
- package/dist/seo/register-sitemap-request.d.ts +36 -0
- package/dist/seo/register-sitemap-request.d.ts.map +1 -0
- package/dist/seo/routing.d.ts +2 -0
- package/dist/seo/routing.d.ts.map +1 -1
- package/dist/seo/schema-filter.d.ts +43 -0
- package/dist/seo/schema-filter.d.ts.map +1 -0
- package/dist/seo/server-api.d.ts +15 -2
- package/dist/seo/server-api.d.ts.map +1 -1
- package/dist/seo/server.js +23 -18
- package/dist/seo/server.mjs +7 -2
- package/dist/seo/types.d.ts +30 -0
- package/dist/seo/types.d.ts.map +1 -1
- package/dist/seo-meta/contract.d.ts +60 -0
- package/dist/seo-meta/contract.d.ts.map +1 -0
- package/dist/seo-meta/contract.js +41 -0
- package/dist/seo-meta/contract.js.map +1 -0
- package/dist/seo-meta/contract.mjs +4 -0
- package/dist/seo-meta/contract.mjs.map +1 -0
- package/dist/server/index.js +4 -3
- package/dist/server/index.mjs +3 -2
- package/dist/server/mint-site-token.d.ts +2 -32
- package/dist/server/mint-site-token.d.ts.map +1 -1
- package/dist/{server-api-RG3ZL3DV.mjs → server-api-A2EFCTZX.mjs} +7 -3
- package/dist/{server-api-RG3ZL3DV.mjs.map → server-api-A2EFCTZX.mjs.map} +1 -1
- package/dist/{server-api-RYJQAUGO.js → server-api-IWTZ7C3O.js} +25 -21
- package/dist/{server-api-RYJQAUGO.js.map → server-api-IWTZ7C3O.js.map} +1 -1
- package/dist/shared/build-entries.d.ts +2 -0
- package/dist/shared/build-entries.d.ts.map +1 -1
- package/dist/shared/fresh-fetch.d.ts +64 -0
- package/dist/shared/fresh-fetch.d.ts.map +1 -0
- package/dist/shared/next-files.d.ts +7 -0
- package/dist/shared/next-files.d.ts.map +1 -1
- package/dist/shared/page-leave.d.ts +27 -0
- package/dist/shared/page-leave.d.ts.map +1 -0
- package/dist/shared/source-graph.d.ts +63 -0
- package/dist/shared/source-graph.d.ts.map +1 -0
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/SignalCore.d.ts.map +1 -1
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sitemap/index.d.ts +19 -4
- package/dist/sitemap/index.d.ts.map +1 -1
- package/dist/sitemap/index.js +53 -43
- package/dist/sitemap/index.js.map +1 -1
- package/dist/sitemap/index.mjs +37 -27
- package/dist/sitemap/index.mjs.map +1 -1
- package/dist/sitemap/shared.d.ts +65 -0
- package/dist/sitemap/shared.d.ts.map +1 -1
- package/dist/sites/resolve.d.ts.map +1 -1
- package/dist/sites/site-param.d.ts +16 -0
- package/dist/sites/site-param.d.ts.map +1 -0
- package/dist/sync/index.js +17 -17
- package/dist/sync/index.mjs +4 -4
- package/dist/writeLLMsTxt-CQ7A4AAL.js +19 -0
- package/dist/writeLLMsTxt-NX5MSPYX.mjs +10 -0
- package/package.json +9 -4
- package/dist/AnalyticsProvider-EWF7JN2X.mjs +0 -11
- package/dist/AnalyticsProvider-GJFG7YXA.js +0 -32
- package/dist/BlogViewTracker-2D3IJPJK.js.map +0 -1
- package/dist/BlogViewTracker-CKYG6MYU.mjs.map +0 -1
- package/dist/ChatWidget-AWP6GBVW.js +0 -22
- package/dist/ChatWidget-Z5QXDZP3.mjs +0 -13
- package/dist/EngageWidget-BKEY5TPO.mjs +0 -12
- package/dist/EngageWidget-VT4DYXVO.js +0 -21
- package/dist/FormSpotlight-OTFB6QM5.mjs.map +0 -1
- package/dist/FormSpotlight-URS4XRS7.js.map +0 -1
- package/dist/FormStage-FVKMIV73.js.map +0 -1
- package/dist/FormStage-VPGOCMAV.mjs.map +0 -1
- package/dist/ManagedForm-CXVDJMHN.mjs +0 -14
- package/dist/ManagedForm-FGNTDGED.js +0 -23
- package/dist/ManagedNewsletterForm-3O5L44AZ.js.map +0 -1
- package/dist/ManagedNewsletterForm-SQYB4BZU.mjs.map +0 -1
- package/dist/SignalCore-M2PKKIGH.mjs.map +0 -1
- package/dist/SignalCore-RFBOBNLQ.js.map +0 -1
- package/dist/SitemapSync-4OVMIIGC.mjs +0 -9
- package/dist/SitemapSync-RK3SQ4M2.js +0 -18
- package/dist/analytics/send-gate.test.d.ts +0 -20
- package/dist/analytics/send-gate.test.d.ts.map +0 -1
- package/dist/api-D745LGGU.mjs.map +0 -1
- package/dist/api-XR5APCH3.js.map +0 -1
- package/dist/blog/artwork-components.test.d.ts +0 -2
- package/dist/blog/artwork-components.test.d.ts.map +0 -1
- package/dist/blog/artwork.test.d.ts +0 -2
- package/dist/blog/artwork.test.d.ts.map +0 -1
- package/dist/blog/author-social.test.d.ts +0 -2
- package/dist/blog/author-social.test.d.ts.map +0 -1
- package/dist/blog/blog-tables.test.d.ts +0 -2
- package/dist/blog/blog-tables.test.d.ts.map +0 -1
- package/dist/blog/blog-view-tracker.test.d.ts +0 -2
- package/dist/blog/blog-view-tracker.test.d.ts.map +0 -1
- package/dist/blog/category-metadata.test.d.ts +0 -2
- package/dist/blog/category-metadata.test.d.ts.map +0 -1
- package/dist/blog/metadata-images.test.d.ts +0 -2
- package/dist/blog/metadata-images.test.d.ts.map +0 -1
- package/dist/blog/newsletter-widget.test.d.ts +0 -2
- package/dist/blog/newsletter-widget.test.d.ts.map +0 -1
- package/dist/blog/publication-render.test.d.ts +0 -2
- package/dist/blog/publication-render.test.d.ts.map +0 -1
- package/dist/blog/publication-routes.test.d.ts +0 -2
- package/dist/blog/publication-routes.test.d.ts.map +0 -1
- package/dist/blog/reading-time.test.d.ts +0 -2
- package/dist/blog/reading-time.test.d.ts.map +0 -1
- package/dist/blog/sanitize-excerpt.test.d.ts +0 -2
- package/dist/blog/sanitize-excerpt.test.d.ts.map +0 -1
- package/dist/blog/server-core-contract.test.d.ts +0 -2
- package/dist/blog/server-core-contract.test.d.ts.map +0 -1
- package/dist/blog/static-params.test.d.ts +0 -2
- package/dist/blog/static-params.test.d.ts.map +0 -1
- package/dist/blog/tag-links.test.d.ts +0 -2
- package/dist/blog/tag-links.test.d.ts.map +0 -1
- package/dist/blog/types-wire-shape.test.d.ts +0 -2
- package/dist/blog/types-wire-shape.test.d.ts.map +0 -1
- package/dist/brand/status-contrast.test.d.ts +0 -2
- package/dist/brand/status-contrast.test.d.ts.map +0 -1
- package/dist/chunk-3CLP35TT.mjs.map +0 -1
- package/dist/chunk-3UC6JETG.js +0 -32
- package/dist/chunk-3UC6JETG.js.map +0 -1
- package/dist/chunk-3YQILJKJ.js.map +0 -1
- package/dist/chunk-4B4S56WJ.mjs.map +0 -1
- package/dist/chunk-5B4FABFK.js.map +0 -1
- package/dist/chunk-5TXXTYXL.js +0 -8
- package/dist/chunk-5YA6SI4Z.mjs.map +0 -1
- package/dist/chunk-6CJP7BFM.js.map +0 -1
- package/dist/chunk-6FC5Q4KU.mjs.map +0 -1
- package/dist/chunk-7ZX6TO6C.mjs.map +0 -1
- package/dist/chunk-AWK57R5S.mjs +0 -29
- package/dist/chunk-AWK57R5S.mjs.map +0 -1
- package/dist/chunk-BFJOZ3MU.mjs.map +0 -1
- package/dist/chunk-BFM5PEFV.js.map +0 -1
- package/dist/chunk-CPY74A4F.js.map +0 -1
- package/dist/chunk-DOB37PV4.js.map +0 -1
- package/dist/chunk-F3AKYZOH.js.map +0 -1
- package/dist/chunk-FO4KGPGF.js.map +0 -1
- package/dist/chunk-GZJE23Y5.mjs.map +0 -1
- package/dist/chunk-H4OBGC43.mjs.map +0 -1
- package/dist/chunk-H6YVT3BL.js.map +0 -1
- package/dist/chunk-H7274TKR.mjs.map +0 -1
- package/dist/chunk-I7AZC5ZQ.js.map +0 -1
- package/dist/chunk-ILNCUSXW.mjs.map +0 -1
- package/dist/chunk-IPV2TUAT.js.map +0 -1
- package/dist/chunk-JEOKDUPQ.js +0 -45
- package/dist/chunk-JEOKDUPQ.js.map +0 -1
- package/dist/chunk-JNAXDFC4.mjs.map +0 -1
- package/dist/chunk-JNRHTZL4.js.map +0 -1
- package/dist/chunk-JOYMIGR2.mjs.map +0 -1
- package/dist/chunk-JS75ORH7.js.map +0 -1
- package/dist/chunk-JTCQJKJE.js.map +0 -1
- package/dist/chunk-L4V6TKMJ.mjs.map +0 -1
- package/dist/chunk-LC7AM4J5.js.map +0 -1
- package/dist/chunk-M5GY2AI3.mjs.map +0 -1
- package/dist/chunk-NN2YE5WT.js.map +0 -1
- package/dist/chunk-NNZDWY3L.mjs.map +0 -1
- package/dist/chunk-O2VJZOR2.mjs.map +0 -1
- package/dist/chunk-OZ3FU4BT.js.map +0 -1
- package/dist/chunk-P4TB4ROG.js.map +0 -1
- package/dist/chunk-Q7347KP6.mjs.map +0 -1
- package/dist/chunk-QJU6HBSK.mjs +0 -39
- package/dist/chunk-QJU6HBSK.mjs.map +0 -1
- package/dist/chunk-QRBPT6Z6.mjs +0 -6
- package/dist/chunk-RCSTDJUH.js.map +0 -1
- package/dist/chunk-RVRN5U7W.mjs.map +0 -1
- package/dist/chunk-TDJKGN5Q.mjs.map +0 -1
- package/dist/chunk-TP7H6BSK.mjs.map +0 -1
- package/dist/chunk-TSZIACRC.js.map +0 -1
- package/dist/chunk-UJ6CHZAI.mjs.map +0 -1
- package/dist/chunk-VFGEY6FJ.js.map +0 -1
- package/dist/cli/agent/envelope.test.d.ts +0 -2
- package/dist/cli/agent/envelope.test.d.ts.map +0 -1
- package/dist/cli/agent/ssr-bailout.test.d.ts +0 -2
- package/dist/cli/agent/ssr-bailout.test.d.ts.map +0 -1
- package/dist/cli/codemod/diff.test.d.ts +0 -2
- package/dist/cli/codemod/diff.test.d.ts.map +0 -1
- package/dist/cli/codemod/transforms.test.d.ts +0 -2
- package/dist/cli/codemod/transforms.test.d.ts.map +0 -1
- package/dist/cli/commands/config-regression.test.d.ts +0 -2
- package/dist/cli/commands/config-regression.test.d.ts.map +0 -1
- package/dist/cli/commands/geo.test.d.ts +0 -2
- package/dist/cli/commands/geo.test.d.ts.map +0 -1
- package/dist/cli/commands/og.test.d.ts +0 -2
- package/dist/cli/commands/og.test.d.ts.map +0 -1
- package/dist/cli/config.test.d.ts +0 -2
- package/dist/cli/config.test.d.ts.map +0 -1
- package/dist/cli/generators/index.test.d.ts +0 -2
- package/dist/cli/generators/index.test.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/index.mjs.map +0 -1
- package/dist/cli/state.test.d.ts +0 -2
- package/dist/cli/state.test.d.ts.map +0 -1
- package/dist/commerce/events-extras.test.d.ts +0 -2
- package/dist/commerce/events-extras.test.d.ts.map +0 -1
- package/dist/commerce/server-result.test.d.ts +0 -2
- package/dist/commerce/server-result.test.d.ts.map +0 -1
- package/dist/discover-FGTKWOL3.mjs +0 -4
- package/dist/discover-NJZPWTDL.js +0 -21
- package/dist/engage/chat-launcher.test.d.ts +0 -2
- package/dist/engage/chat-launcher.test.d.ts.map +0 -1
- package/dist/engage/dependency-contract.test.d.ts +0 -2
- package/dist/engage/dependency-contract.test.d.ts.map +0 -1
- package/dist/engage/launcher-placement.test.d.ts +0 -2
- package/dist/engage/launcher-placement.test.d.ts.map +0 -1
- package/dist/fleet/contract.test.d.ts +0 -2
- package/dist/fleet/contract.test.d.ts.map +0 -1
- package/dist/fleet/heartbeat.test.d.ts +0 -2
- package/dist/fleet/heartbeat.test.d.ts.map +0 -1
- package/dist/forms/contract.test.d.ts +0 -2
- package/dist/forms/contract.test.d.ts.map +0 -1
- package/dist/forms/ga4-identity.test.d.ts +0 -2
- package/dist/forms/ga4-identity.test.d.ts.map +0 -1
- package/dist/forms/native-fallback.test.d.ts +0 -2
- package/dist/forms/native-fallback.test.d.ts.map +0 -1
- package/dist/forms/stage.test.d.ts +0 -2
- package/dist/forms/stage.test.d.ts.map +0 -1
- package/dist/forms/static-form.test.d.ts +0 -2
- package/dist/forms/static-form.test.d.ts.map +0 -1
- package/dist/forms/tracking-session.test.d.ts +0 -22
- package/dist/forms/tracking-session.test.d.ts.map +0 -1
- package/dist/landing/contract.test.d.ts +0 -2
- package/dist/landing/contract.test.d.ts.map +0 -1
- package/dist/landing/server-entry.test.d.ts +0 -2
- package/dist/landing/server-entry.test.d.ts.map +0 -1
- package/dist/lib-6HOOMENJ.js.map +0 -1
- package/dist/lib-BGAWCSUH.js.map +0 -1
- package/dist/lib-R7IQ4ZHE.mjs.map +0 -1
- package/dist/lib-RSDMEKDQ.mjs.map +0 -1
- package/dist/llms/aiRobots.test.d.ts +0 -2
- package/dist/llms/aiRobots.test.d.ts.map +0 -1
- package/dist/llms/contract.test.d.ts +0 -2
- package/dist/llms/contract.test.d.ts.map +0 -1
- package/dist/llms/discovery-headers.test.d.ts +0 -2
- package/dist/llms/discovery-headers.test.d.ts.map +0 -1
- package/dist/llms/generateLLMsTxt.test.d.ts +0 -2
- package/dist/llms/generateLLMsTxt.test.d.ts.map +0 -1
- package/dist/llms/handlers.test.d.ts +0 -2
- package/dist/llms/handlers.test.d.ts.map +0 -1
- package/dist/llms/humanize-industry.test.d.ts +0 -2
- package/dist/llms/humanize-industry.test.d.ts.map +0 -1
- package/dist/llms/sourcedFacts.test.d.ts +0 -2
- package/dist/llms/sourcedFacts.test.d.ts.map +0 -1
- package/dist/llms/wiring.test.d.ts +0 -2
- package/dist/llms/wiring.test.d.ts.map +0 -1
- package/dist/llms/writeLLMsTxt.test.d.ts +0 -2
- package/dist/llms/writeLLMsTxt.test.d.ts.map +0 -1
- package/dist/mcp/protocol.test.d.ts +0 -2
- package/dist/mcp/protocol.test.d.ts.map +0 -1
- package/dist/motion/motion.test.d.ts +0 -16
- package/dist/motion/motion.test.d.ts.map +0 -1
- package/dist/og/pages.test.d.ts +0 -2
- package/dist/og/pages.test.d.ts.map +0 -1
- package/dist/og/template.test.d.ts +0 -2
- package/dist/og/template.test.d.ts.map +0 -1
- package/dist/og/wiring.test.d.ts +0 -2
- package/dist/og/wiring.test.d.ts.map +0 -1
- package/dist/portfolio/contract.test.d.ts +0 -2
- package/dist/portfolio/contract.test.d.ts.map +0 -1
- package/dist/proxy/securityHeaders.test.d.ts +0 -2
- package/dist/proxy/securityHeaders.test.d.ts.map +0 -1
- package/dist/proxy/segment.test.d.ts +0 -2
- package/dist/proxy/segment.test.d.ts.map +0 -1
- package/dist/robots/index.test.d.ts +0 -2
- package/dist/robots/index.test.d.ts.map +0 -1
- package/dist/seo/register-sitemap-cli-impl.test.d.ts +0 -2
- package/dist/seo/register-sitemap-cli-impl.test.d.ts.map +0 -1
- package/dist/seo/register-sitemap-cli.js.map +0 -1
- package/dist/seo/register-sitemap-cli.mjs.map +0 -1
- package/dist/seo-pages/contract.test.d.ts +0 -2
- package/dist/seo-pages/contract.test.d.ts.map +0 -1
- package/dist/server/mint-site-token.test.d.ts +0 -2
- package/dist/server/mint-site-token.test.d.ts.map +0 -1
- package/dist/server/server-fetch.test.d.ts +0 -2
- package/dist/server/server-fetch.test.d.ts.map +0 -1
- package/dist/shared/client-entry-boundary.test.d.ts +0 -2
- package/dist/shared/client-entry-boundary.test.d.ts.map +0 -1
- package/dist/shared/next-files.test.d.ts +0 -2
- package/dist/shared/next-files.test.d.ts.map +0 -1
- package/dist/shared/no-cjs-require.test.d.ts +0 -2
- package/dist/shared/no-cjs-require.test.d.ts.map +0 -1
- package/dist/shared/publishCredential.test.d.ts +0 -2
- package/dist/shared/publishCredential.test.d.ts.map +0 -1
- package/dist/shared/raw-browser-api-guard.test.d.ts +0 -15
- package/dist/shared/raw-browser-api-guard.test.d.ts.map +0 -1
- package/dist/shared/siteToken.test.d.ts +0 -2
- package/dist/shared/siteToken.test.d.ts.map +0 -1
- package/dist/shared/sonorFetch.test.d.ts +0 -2
- package/dist/shared/sonorFetch.test.d.ts.map +0 -1
- package/dist/shared/uuid.test.d.ts +0 -2
- package/dist/shared/uuid.test.d.ts.map +0 -1
- package/dist/shared/version.test.d.ts +0 -2
- package/dist/shared/version.test.d.ts.map +0 -1
- package/dist/shared/visual-viewport-gap.test.d.ts +0 -2
- package/dist/shared/visual-viewport-gap.test.d.ts.map +0 -1
- package/dist/sitemap/discover.test.d.ts +0 -2
- package/dist/sitemap/discover.test.d.ts.map +0 -1
- package/dist/sitemap/shared.test.d.ts +0 -2
- package/dist/sitemap/shared.test.d.ts.map +0 -1
- package/dist/sitemap/site-scope.test.d.ts +0 -2
- package/dist/sitemap/site-scope.test.d.ts.map +0 -1
- package/dist/sites/contract.test.d.ts +0 -2
- package/dist/sites/contract.test.d.ts.map +0 -1
- package/dist/slots/ManagedSlot.test.d.ts +0 -2
- package/dist/slots/ManagedSlot.test.d.ts.map +0 -1
- package/dist/slots/contract.test.d.ts +0 -2
- package/dist/slots/contract.test.d.ts.map +0 -1
- package/dist/slots/revalidate.test.d.ts +0 -2
- package/dist/slots/revalidate.test.d.ts.map +0 -1
- package/dist/slots/server-api.test.d.ts +0 -2
- package/dist/slots/server-api.test.d.ts.map +0 -1
- package/dist/sync/add-to-calendar.test.d.ts +0 -2
- package/dist/sync/add-to-calendar.test.d.ts.map +0 -1
- package/dist/sync/api-errors.test.d.ts +0 -2
- package/dist/sync/api-errors.test.d.ts.map +0 -1
- package/dist/sync/booking-flow.test.d.ts +0 -2
- package/dist/sync/booking-flow.test.d.ts.map +0 -1
|
@@ -1,8 +1,99 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { isFieldVisible, validateField, isFieldComplete } from './chunk-QRHVMTHF.mjs';
|
|
3
|
+
import { normalizeFormConfig, submitForm } from './chunk-U6H5ZY3B.mjs';
|
|
4
|
+
import { onPageLeave } from './chunk-5SANRSX3.mjs';
|
|
3
5
|
import { uuid } from './chunk-6EDVCUAG.mjs';
|
|
4
|
-
import { sonorFetch, sonorBeacon } from './chunk-
|
|
5
|
-
import { useRef,
|
|
6
|
+
import { sonorFetch, sonorBeacon } from './chunk-X22BGNVL.mjs';
|
|
7
|
+
import { useRef, useCallback, useEffect, useState, useMemo } from 'react';
|
|
8
|
+
|
|
9
|
+
// src/forms/field-interactions.ts
|
|
10
|
+
var MAX_TRACKED_FIELDS = 100;
|
|
11
|
+
var MAX_FIELD_SLUG_LENGTH = 100;
|
|
12
|
+
var FieldInteractionLog = class {
|
|
13
|
+
constructor() {
|
|
14
|
+
/**
|
|
15
|
+
* The field the visitor was on, reported as `abandonment_field` when they
|
|
16
|
+
* leave. The last FOCUSED field once the form reports focus; a headless form
|
|
17
|
+
* that never wires focus falls back to the last field whose value changed.
|
|
18
|
+
*/
|
|
19
|
+
this.lastField = null;
|
|
20
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
21
|
+
this.focusReported = false;
|
|
22
|
+
/** The one field holding focus, if any. Only one can, so this is a slot, not a flag per field. */
|
|
23
|
+
this.open = null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Visitor moved focus into `slug`. Returns true when that's a new visit to
|
|
27
|
+
* the field; false for an untrackable slug or a field that already has focus.
|
|
28
|
+
*/
|
|
29
|
+
focus(slug, now = Date.now()) {
|
|
30
|
+
if (this.open?.slug === slug) return false;
|
|
31
|
+
const entry = this.entry(slug);
|
|
32
|
+
if (!entry) return false;
|
|
33
|
+
this.close(now);
|
|
34
|
+
entry.focusCount++;
|
|
35
|
+
this.open = { slug, since: now };
|
|
36
|
+
this.focusReported = true;
|
|
37
|
+
this.lastField = slug;
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
/** Visitor moved focus out of `slug`. */
|
|
41
|
+
blur(slug, now = Date.now()) {
|
|
42
|
+
if (this.open?.slug === slug) this.close(now);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* `slug`'s value changed. Counts as reaching the field even without a focus
|
|
46
|
+
* event: autofill, a custom renderer that doesn't report focus, a picker
|
|
47
|
+
* that sets the value from outside the input.
|
|
48
|
+
*/
|
|
49
|
+
change(slug) {
|
|
50
|
+
if (!this.entry(slug)) return false;
|
|
51
|
+
if (!this.focusReported) this.lastField = slug;
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
get size() {
|
|
55
|
+
return this.entries.size;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Every field reached so far. Time for a field that still has focus counts
|
|
59
|
+
* up to `now`, so a report built as the page hides includes the field the
|
|
60
|
+
* visitor was sitting in.
|
|
61
|
+
*/
|
|
62
|
+
snapshot(isComplete, now = Date.now()) {
|
|
63
|
+
const out = {};
|
|
64
|
+
for (const [slug, entry] of this.entries) {
|
|
65
|
+
const openMs = this.open?.slug === slug ? Math.max(0, now - this.open.since) : 0;
|
|
66
|
+
out[slug] = {
|
|
67
|
+
completed: safeIsComplete(isComplete, slug),
|
|
68
|
+
focusCount: entry.focusCount,
|
|
69
|
+
timeMs: Math.round(entry.timeMs + openMs)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
close(now) {
|
|
75
|
+
if (!this.open) return;
|
|
76
|
+
const entry = this.entries.get(this.open.slug);
|
|
77
|
+
if (entry) entry.timeMs += Math.max(0, now - this.open.since);
|
|
78
|
+
this.open = null;
|
|
79
|
+
}
|
|
80
|
+
entry(slug) {
|
|
81
|
+
if (typeof slug !== "string" || slug.length === 0 || slug.length > MAX_FIELD_SLUG_LENGTH) return null;
|
|
82
|
+
const existing = this.entries.get(slug);
|
|
83
|
+
if (existing) return existing;
|
|
84
|
+
if (this.entries.size >= MAX_TRACKED_FIELDS) return null;
|
|
85
|
+
const created = { focusCount: 0, timeMs: 0 };
|
|
86
|
+
this.entries.set(slug, created);
|
|
87
|
+
return created;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
function safeIsComplete(isComplete, slug) {
|
|
91
|
+
try {
|
|
92
|
+
return isComplete(slug) === true;
|
|
93
|
+
} catch {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
6
97
|
|
|
7
98
|
// src/forms/tracking-session.ts
|
|
8
99
|
var SESSION_GRACE_MS = 2e3;
|
|
@@ -23,7 +114,11 @@ function acquireTrackingSession(formId, start) {
|
|
|
23
114
|
startedAt: Date.now(),
|
|
24
115
|
// Assigned below — declared here so the object shape is complete first.
|
|
25
116
|
analyticsId: null,
|
|
117
|
+
fields: new FieldInteractionLog(),
|
|
118
|
+
interacted: false,
|
|
119
|
+
completed: false,
|
|
26
120
|
abandonSent: false,
|
|
121
|
+
onEnd: null,
|
|
27
122
|
refCount: 1,
|
|
28
123
|
releaseTimer: null
|
|
29
124
|
};
|
|
@@ -39,17 +134,38 @@ function releaseTrackingSession(formId, session) {
|
|
|
39
134
|
session.releaseTimer = null;
|
|
40
135
|
if (session.refCount <= 0 && activeSessions.get(formId) === session) {
|
|
41
136
|
activeSessions.delete(formId);
|
|
137
|
+
const onEnd = session.onEnd;
|
|
138
|
+
session.onEnd = null;
|
|
139
|
+
try {
|
|
140
|
+
onEnd?.();
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
42
143
|
}
|
|
43
144
|
}, SESSION_GRACE_MS);
|
|
44
145
|
session.releaseTimer?.unref?.();
|
|
45
146
|
}
|
|
147
|
+
function noteActivity(session) {
|
|
148
|
+
if (session.completed) return;
|
|
149
|
+
session.interacted = true;
|
|
150
|
+
session.abandonSent = false;
|
|
151
|
+
}
|
|
152
|
+
function claimAbandon(session) {
|
|
153
|
+
if (session.completed || !session.interacted || session.abandonSent) return false;
|
|
154
|
+
session.abandonSent = true;
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
function markCompleted(session) {
|
|
158
|
+
session.completed = true;
|
|
159
|
+
session.abandonSent = true;
|
|
160
|
+
}
|
|
46
161
|
|
|
47
162
|
// src/forms/useFormTracking.ts
|
|
48
163
|
function useFormTracking({
|
|
49
164
|
formId,
|
|
50
165
|
totalSteps,
|
|
51
166
|
enabled = true,
|
|
52
|
-
debug = false
|
|
167
|
+
debug = false,
|
|
168
|
+
isFieldComplete: isFieldComplete2
|
|
53
169
|
}) {
|
|
54
170
|
const sessionRef = useRef(null);
|
|
55
171
|
const sessionIdRef = useRef("");
|
|
@@ -59,6 +175,12 @@ function useFormTracking({
|
|
|
59
175
|
const currentStepRef = useRef(1);
|
|
60
176
|
const maxStepRef = useRef(1);
|
|
61
177
|
const analyticsIdRef = useRef(null);
|
|
178
|
+
const isFieldCompleteRef = useRef(isFieldComplete2);
|
|
179
|
+
isFieldCompleteRef.current = isFieldComplete2;
|
|
180
|
+
const fieldReport = useCallback((session, now) => {
|
|
181
|
+
const check = isFieldCompleteRef.current;
|
|
182
|
+
return session.fields.snapshot((slug) => check ? check(slug) : false, now);
|
|
183
|
+
}, []);
|
|
62
184
|
useEffect(() => {
|
|
63
185
|
if (!enabled) return;
|
|
64
186
|
if (!formId) {
|
|
@@ -106,37 +228,40 @@ function useFormTracking({
|
|
|
106
228
|
void session.analyticsId.then((id) => {
|
|
107
229
|
if (joined) analyticsIdRef.current = id;
|
|
108
230
|
});
|
|
109
|
-
const
|
|
110
|
-
if (!
|
|
111
|
-
if (session.abandonSent) return;
|
|
231
|
+
const reportAbandon = (analyticsId) => {
|
|
232
|
+
if (!analyticsId) return;
|
|
112
233
|
const apiUrl = window.__SITE_KIT_API_URL__;
|
|
113
234
|
const apiKey = window.__SITE_KIT_API_KEY__;
|
|
114
235
|
if (!apiUrl || !apiKey) return;
|
|
236
|
+
if (!claimAbandon(session)) return;
|
|
115
237
|
const now = Date.now();
|
|
116
|
-
|
|
117
|
-
stepTimesRef.current[currentStepRef.current] = currentStepTime;
|
|
118
|
-
session.abandonSent = true;
|
|
238
|
+
stepTimesRef.current[currentStepRef.current] = Math.floor((now - stepStartTimeRef.current) / 1e3);
|
|
119
239
|
sonorBeacon(
|
|
120
240
|
`${apiUrl}/api/public/forms/analytics/abandon`,
|
|
121
241
|
{
|
|
122
|
-
analyticsId
|
|
242
|
+
analyticsId,
|
|
123
243
|
step: currentStepRef.current,
|
|
124
244
|
maxStep: maxStepRef.current,
|
|
125
245
|
stepTimes: stepTimesRef.current,
|
|
126
|
-
totalTimeSeconds: Math.floor((now - startTimeRef.current) / 1e3)
|
|
246
|
+
totalTimeSeconds: Math.floor((now - startTimeRef.current) / 1e3),
|
|
247
|
+
fieldInteractions: fieldReport(session, now),
|
|
248
|
+
abandonmentField: session.fields.lastField
|
|
127
249
|
},
|
|
128
250
|
apiKey
|
|
129
251
|
);
|
|
130
|
-
if (debug) console.log("[Forms] Abandonment tracked");
|
|
252
|
+
if (debug) console.log("[Forms] Abandonment tracked:", session.fields.lastField);
|
|
253
|
+
};
|
|
254
|
+
const stopLeaveListener = onPageLeave(() => reportAbandon(analyticsIdRef.current));
|
|
255
|
+
session.onEnd = () => {
|
|
256
|
+
void session.analyticsId.then(reportAbandon);
|
|
131
257
|
};
|
|
132
|
-
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
133
258
|
return () => {
|
|
134
259
|
joined = false;
|
|
135
|
-
|
|
260
|
+
stopLeaveListener();
|
|
136
261
|
releaseTrackingSession(formId, session);
|
|
137
262
|
sessionRef.current = null;
|
|
138
263
|
};
|
|
139
|
-
}, [formId, enabled, debug]);
|
|
264
|
+
}, [formId, enabled, debug, fieldReport]);
|
|
140
265
|
const resolveAnalyticsId = useCallback(async () => {
|
|
141
266
|
if (analyticsIdRef.current) return analyticsIdRef.current;
|
|
142
267
|
const session = sessionRef.current;
|
|
@@ -145,6 +270,19 @@ function useFormTracking({
|
|
|
145
270
|
if (id) analyticsIdRef.current = id;
|
|
146
271
|
return id;
|
|
147
272
|
}, []);
|
|
273
|
+
const trackFieldFocus = useCallback((slug) => {
|
|
274
|
+
const session = sessionRef.current;
|
|
275
|
+
if (!session || session.completed) return;
|
|
276
|
+
if (session.fields.focus(slug)) noteActivity(session);
|
|
277
|
+
}, []);
|
|
278
|
+
const trackFieldBlur = useCallback((slug) => {
|
|
279
|
+
sessionRef.current?.fields.blur(slug);
|
|
280
|
+
}, []);
|
|
281
|
+
const trackFieldChange = useCallback((slug) => {
|
|
282
|
+
const session = sessionRef.current;
|
|
283
|
+
if (!session || session.completed) return;
|
|
284
|
+
if (session.fields.change(slug)) noteActivity(session);
|
|
285
|
+
}, []);
|
|
148
286
|
const trackStepChange = useCallback(async (step) => {
|
|
149
287
|
if (!enabled) return;
|
|
150
288
|
const apiUrl = window.__SITE_KIT_API_URL__;
|
|
@@ -159,6 +297,8 @@ function useFormTracking({
|
|
|
159
297
|
currentStepRef.current = step;
|
|
160
298
|
maxStepRef.current = Math.max(maxStepRef.current, step);
|
|
161
299
|
stepStartTimeRef.current = now;
|
|
300
|
+
const session = sessionRef.current;
|
|
301
|
+
if (session) noteActivity(session);
|
|
162
302
|
const analyticsId = await resolveAnalyticsId();
|
|
163
303
|
if (!analyticsId) return;
|
|
164
304
|
try {
|
|
@@ -171,7 +311,8 @@ function useFormTracking({
|
|
|
171
311
|
analyticsId,
|
|
172
312
|
step,
|
|
173
313
|
maxStep: maxStepRef.current,
|
|
174
|
-
stepTimes: stepTimesRef.current
|
|
314
|
+
stepTimes: stepTimesRef.current,
|
|
315
|
+
...session ? { fieldInteractions: fieldReport(session, Date.now()) } : {}
|
|
175
316
|
})
|
|
176
317
|
},
|
|
177
318
|
{ apiKey, retries: 0 }
|
|
@@ -183,9 +324,11 @@ function useFormTracking({
|
|
|
183
324
|
} catch (error) {
|
|
184
325
|
if (debug) console.error("[Forms] Error updating step:", error);
|
|
185
326
|
}
|
|
186
|
-
}, [enabled, debug, resolveAnalyticsId]);
|
|
327
|
+
}, [enabled, debug, resolveAnalyticsId, fieldReport]);
|
|
187
328
|
const trackComplete = useCallback(async () => {
|
|
188
329
|
if (!enabled) return;
|
|
330
|
+
const session = sessionRef.current;
|
|
331
|
+
if (session) markCompleted(session);
|
|
189
332
|
const apiUrl = window.__SITE_KIT_API_URL__;
|
|
190
333
|
const apiKey = window.__SITE_KIT_API_KEY__;
|
|
191
334
|
if (!apiUrl || !apiKey) {
|
|
@@ -195,21 +338,26 @@ function useFormTracking({
|
|
|
195
338
|
const now = Date.now();
|
|
196
339
|
const finalStepTime = Math.floor((now - stepStartTimeRef.current) / 1e3);
|
|
197
340
|
stepTimesRef.current[currentStepRef.current] = finalStepTime;
|
|
341
|
+
const fieldInteractions = session ? fieldReport(session, now) : void 0;
|
|
198
342
|
const analyticsId = await resolveAnalyticsId();
|
|
199
343
|
if (!analyticsId) return;
|
|
200
|
-
const session = sessionRef.current;
|
|
201
|
-
if (session) session.abandonSent = true;
|
|
202
344
|
try {
|
|
203
345
|
const response = await sonorFetch(
|
|
204
346
|
`${apiUrl}/api/public/forms/analytics/complete`,
|
|
205
347
|
{
|
|
206
348
|
method: "POST",
|
|
349
|
+
// A form with a redirect_url navigates away right after submit, which
|
|
350
|
+
// cancels an ordinary in-flight fetch. And since completion now
|
|
351
|
+
// suppresses the abandon beacon, losing this would leave the row
|
|
352
|
+
// neither completed nor abandoned.
|
|
353
|
+
keepalive: true,
|
|
207
354
|
headers: { "Content-Type": "application/json" },
|
|
208
355
|
body: JSON.stringify({
|
|
209
356
|
analyticsId,
|
|
210
357
|
totalSteps,
|
|
211
358
|
stepTimes: stepTimesRef.current,
|
|
212
|
-
totalTimeSeconds: Math.floor((now - startTimeRef.current) / 1e3)
|
|
359
|
+
totalTimeSeconds: Math.floor((now - startTimeRef.current) / 1e3),
|
|
360
|
+
...fieldInteractions ? { fieldInteractions } : {}
|
|
213
361
|
})
|
|
214
362
|
},
|
|
215
363
|
{ apiKey, retries: 0 }
|
|
@@ -221,10 +369,13 @@ function useFormTracking({
|
|
|
221
369
|
} catch (error) {
|
|
222
370
|
if (debug) console.error("[Forms] Error completing tracking:", error);
|
|
223
371
|
}
|
|
224
|
-
}, [enabled, totalSteps,
|
|
372
|
+
}, [enabled, totalSteps, debug, resolveAnalyticsId, fieldReport]);
|
|
225
373
|
return {
|
|
226
374
|
trackStepChange,
|
|
227
375
|
trackComplete,
|
|
376
|
+
trackFieldFocus,
|
|
377
|
+
trackFieldBlur,
|
|
378
|
+
trackFieldChange,
|
|
228
379
|
sessionId: sessionIdRef.current
|
|
229
380
|
};
|
|
230
381
|
}
|
|
@@ -270,11 +421,6 @@ function useForm(formIdOrSlug, options = {}) {
|
|
|
270
421
|
const formLoadedAt = useRef(Date.now());
|
|
271
422
|
const totalSteps = form?.total_steps || 1;
|
|
272
423
|
const isMultiStep = form?.is_multi_step || false;
|
|
273
|
-
const { trackStepChange, trackComplete } = useFormTracking({
|
|
274
|
-
formId: form?.id || "",
|
|
275
|
-
totalSteps,
|
|
276
|
-
enabled: trackAnalytics
|
|
277
|
-
});
|
|
278
424
|
useEffect(() => {
|
|
279
425
|
const initialMatches = initialForm && (initialForm.slug === formIdOrSlug || initialForm.id === formIdOrSlug);
|
|
280
426
|
if (initialMatches) {
|
|
@@ -341,102 +487,67 @@ function useForm(formIdOrSlug, options = {}) {
|
|
|
341
487
|
if (!currentStepConfig) return allFields;
|
|
342
488
|
return allFields.filter((f) => f.step_id === currentStepConfig.id);
|
|
343
489
|
}, [form, step, allFields, isMultiStep]);
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
switch (operator) {
|
|
349
|
-
case "equals":
|
|
350
|
-
return fieldValue === value;
|
|
351
|
-
case "not_equals":
|
|
352
|
-
return fieldValue !== value;
|
|
353
|
-
case "contains":
|
|
354
|
-
return String(fieldValue || "").includes(String(value));
|
|
355
|
-
case "not_contains":
|
|
356
|
-
return !String(fieldValue || "").includes(String(value));
|
|
357
|
-
case "is_empty":
|
|
358
|
-
return !fieldValue || fieldValue === "";
|
|
359
|
-
case "not_empty":
|
|
360
|
-
return !!fieldValue && fieldValue !== "";
|
|
361
|
-
case "greater_than":
|
|
362
|
-
return Number(fieldValue) > Number(value);
|
|
363
|
-
case "less_than":
|
|
364
|
-
return Number(fieldValue) < Number(value);
|
|
365
|
-
default:
|
|
366
|
-
return true;
|
|
367
|
-
}
|
|
368
|
-
}, [values]);
|
|
490
|
+
const isFieldVisible2 = useCallback(
|
|
491
|
+
(field) => isFieldVisible(field, values),
|
|
492
|
+
[values]
|
|
493
|
+
);
|
|
369
494
|
const visibleFields = useMemo(() => {
|
|
370
|
-
return fields.filter(
|
|
371
|
-
}, [fields,
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
return
|
|
393
|
-
}
|
|
394
|
-
if (rules.pattern) {
|
|
395
|
-
try {
|
|
396
|
-
if (!new RegExp(rules.pattern).test(strValue)) {
|
|
397
|
-
return rules.custom_error || `${field.label} is invalid`;
|
|
398
|
-
}
|
|
399
|
-
} catch {
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
if (field.field_type === "email" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(strValue)) {
|
|
403
|
-
return "Please enter a valid email address";
|
|
404
|
-
}
|
|
405
|
-
if (field.field_type === "phone" && !/^[\d\s\-\+\(\)]+$/.test(strValue)) {
|
|
406
|
-
return "Please enter a valid phone number";
|
|
495
|
+
return fields.filter(isFieldVisible2);
|
|
496
|
+
}, [fields, isFieldVisible2]);
|
|
497
|
+
const validateField2 = useCallback(
|
|
498
|
+
(field) => validateField(field, values, isFieldVisible2),
|
|
499
|
+
[values, isFieldVisible2]
|
|
500
|
+
);
|
|
501
|
+
const fieldBySlug = useMemo(
|
|
502
|
+
() => new Map(allFields.map((f) => [f.slug, f])),
|
|
503
|
+
[allFields]
|
|
504
|
+
);
|
|
505
|
+
const {
|
|
506
|
+
trackStepChange,
|
|
507
|
+
trackComplete,
|
|
508
|
+
trackFieldFocus,
|
|
509
|
+
trackFieldBlur,
|
|
510
|
+
trackFieldChange
|
|
511
|
+
} = useFormTracking({
|
|
512
|
+
formId: form?.id || "",
|
|
513
|
+
totalSteps,
|
|
514
|
+
enabled: trackAnalytics,
|
|
515
|
+
isFieldComplete: (slug) => {
|
|
516
|
+
const field = fieldBySlug.get(slug);
|
|
517
|
+
return field ? isFieldComplete(field, values, isFieldVisible2) : false;
|
|
407
518
|
}
|
|
408
|
-
|
|
409
|
-
}, [values, isFieldVisible]);
|
|
519
|
+
});
|
|
410
520
|
const validate = useCallback(() => {
|
|
411
521
|
const newErrors = {};
|
|
412
522
|
for (const field of fields) {
|
|
413
|
-
const error =
|
|
523
|
+
const error = validateField2(field);
|
|
414
524
|
if (error) {
|
|
415
525
|
newErrors[field.slug] = error;
|
|
416
526
|
}
|
|
417
527
|
}
|
|
418
528
|
setErrors(newErrors);
|
|
419
529
|
return Object.keys(newErrors).length === 0;
|
|
420
|
-
}, [fields,
|
|
530
|
+
}, [fields, validateField2]);
|
|
421
531
|
const validateAll = useCallback(() => {
|
|
422
532
|
const newErrors = {};
|
|
423
533
|
for (const field of allFields) {
|
|
424
|
-
const error =
|
|
534
|
+
const error = validateField2(field);
|
|
425
535
|
if (error) newErrors[field.slug] = error;
|
|
426
536
|
}
|
|
427
537
|
setErrors(newErrors);
|
|
428
538
|
return Object.keys(newErrors).length === 0;
|
|
429
|
-
}, [allFields,
|
|
539
|
+
}, [allFields, validateField2]);
|
|
430
540
|
const buildVisibleValues = useCallback(() => {
|
|
431
541
|
const out = {};
|
|
432
542
|
for (const field of allFields) {
|
|
433
|
-
if (!
|
|
543
|
+
if (!isFieldVisible2(field)) continue;
|
|
434
544
|
if (field.slug in values) out[field.slug] = values[field.slug];
|
|
435
545
|
}
|
|
436
546
|
return out;
|
|
437
|
-
}, [allFields, values,
|
|
547
|
+
}, [allFields, values, isFieldVisible2]);
|
|
438
548
|
const setFieldValue = useCallback((key, value) => {
|
|
439
549
|
setValuesState((prev) => ({ ...prev, [key]: value }));
|
|
550
|
+
trackFieldChange(key);
|
|
440
551
|
setErrors((prev) => {
|
|
441
552
|
if (prev[key]) {
|
|
442
553
|
const next = { ...prev };
|
|
@@ -445,7 +556,7 @@ function useForm(formIdOrSlug, options = {}) {
|
|
|
445
556
|
}
|
|
446
557
|
return prev;
|
|
447
558
|
});
|
|
448
|
-
}, []);
|
|
559
|
+
}, [trackFieldChange]);
|
|
449
560
|
const setValues = useCallback((newValues) => {
|
|
450
561
|
setValuesState((prev) => ({ ...prev, ...newValues }));
|
|
451
562
|
}, []);
|
|
@@ -540,15 +651,17 @@ function useForm(formIdOrSlug, options = {}) {
|
|
|
540
651
|
canGoPrev,
|
|
541
652
|
isLastStep,
|
|
542
653
|
validate,
|
|
543
|
-
validateField,
|
|
544
|
-
isFieldVisible,
|
|
654
|
+
validateField: validateField2,
|
|
655
|
+
isFieldVisible: isFieldVisible2,
|
|
545
656
|
submit,
|
|
546
657
|
isSubmitting,
|
|
547
658
|
isComplete,
|
|
548
|
-
reset
|
|
659
|
+
reset,
|
|
660
|
+
trackFieldFocus,
|
|
661
|
+
trackFieldBlur
|
|
549
662
|
};
|
|
550
663
|
}
|
|
551
664
|
|
|
552
665
|
export { useForm, useFormTracking };
|
|
553
|
-
//# sourceMappingURL=chunk-
|
|
554
|
-
//# sourceMappingURL=chunk-
|
|
666
|
+
//# sourceMappingURL=chunk-62Y4W4LR.mjs.map
|
|
667
|
+
//# sourceMappingURL=chunk-62Y4W4LR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/forms/field-interactions.ts","../src/forms/tracking-session.ts","../src/forms/useFormTracking.ts","../src/forms/useForm.ts"],"names":["isFieldComplete","useRef","useEffect","isFieldVisible","useCallback","validateField"],"mappings":"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","file":"chunk-62Y4W4LR.mjs","sourcesContent":["/**\n * @sonordev/site-kit/forms - per-field interaction log\n *\n * What one form visit did with each field, reported as\n * `form_analytics.field_interactions` so the Sonor app can show field-level\n * drop-off. Lives on the shared tracking session (tracking-session.ts), one per\n * form_analytics row, never one per tracker.\n *\n * Wire shape, per field slug (the API caps these — keep them in sync with\n * sonor-api `forms/form-field-interactions.util.ts`):\n * { completed: boolean, focusCount: number, timeMs: number }\n *\n * `completed` isn't stored here. The caller evaluates it at report time against\n * the form's current values, so a report can never carry a stale verdict.\n */\n\n/** Most fields one report carries. A form with more is unusual; the rest are dropped. */\nexport const MAX_TRACKED_FIELDS = 100\n/** Longest field slug reported. Slugs come from form config, so this only stops garbage. */\nexport const MAX_FIELD_SLUG_LENGTH = 100\n\nexport interface FieldInteraction {\n /** The field held a complete, valid value when this report was built. */\n completed: boolean\n /** Times the visitor moved focus into the field. */\n focusCount: number\n /** Total time the field held focus, in ms. */\n timeMs: number\n}\n\nexport type FieldInteractions = Record<string, FieldInteraction>\n\ninterface Entry {\n focusCount: number\n timeMs: number\n}\n\nexport class FieldInteractionLog {\n /**\n * The field the visitor was on, reported as `abandonment_field` when they\n * leave. The last FOCUSED field once the form reports focus; a headless form\n * that never wires focus falls back to the last field whose value changed.\n */\n lastField: string | null = null\n\n private readonly entries = new Map<string, Entry>()\n private focusReported = false\n /** The one field holding focus, if any. Only one can, so this is a slot, not a flag per field. */\n private open: { slug: string; since: number } | null = null\n\n /**\n * Visitor moved focus into `slug`. Returns true when that's a new visit to\n * the field; false for an untrackable slug or a field that already has focus.\n */\n focus(slug: string, now: number = Date.now()): boolean {\n if (this.open?.slug === slug) return false\n const entry = this.entry(slug)\n if (!entry) return false\n // A focused input that unmounts (a step change, a conditional hide) may\n // never fire blur. Focus arriving anywhere closes whatever was open.\n this.close(now)\n entry.focusCount++\n this.open = { slug, since: now }\n this.focusReported = true\n this.lastField = slug\n return true\n }\n\n /** Visitor moved focus out of `slug`. */\n blur(slug: string, now: number = Date.now()): void {\n if (this.open?.slug === slug) this.close(now)\n }\n\n /**\n * `slug`'s value changed. Counts as reaching the field even without a focus\n * event: autofill, a custom renderer that doesn't report focus, a picker\n * that sets the value from outside the input.\n */\n change(slug: string): boolean {\n if (!this.entry(slug)) return false\n if (!this.focusReported) this.lastField = slug\n return true\n }\n\n get size(): number {\n return this.entries.size\n }\n\n /**\n * Every field reached so far. Time for a field that still has focus counts\n * up to `now`, so a report built as the page hides includes the field the\n * visitor was sitting in.\n */\n snapshot(isComplete: (slug: string) => boolean, now: number = Date.now()): FieldInteractions {\n const out: FieldInteractions = {}\n for (const [slug, entry] of this.entries) {\n const openMs = this.open?.slug === slug ? Math.max(0, now - this.open.since) : 0\n out[slug] = {\n completed: safeIsComplete(isComplete, slug),\n focusCount: entry.focusCount,\n timeMs: Math.round(entry.timeMs + openMs),\n }\n }\n return out\n }\n\n private close(now: number): void {\n if (!this.open) return\n const entry = this.entries.get(this.open.slug)\n if (entry) entry.timeMs += Math.max(0, now - this.open.since)\n this.open = null\n }\n\n private entry(slug: string): Entry | null {\n if (typeof slug !== 'string' || slug.length === 0 || slug.length > MAX_FIELD_SLUG_LENGTH) return null\n const existing = this.entries.get(slug)\n if (existing) return existing\n if (this.entries.size >= MAX_TRACKED_FIELDS) return null\n const created: Entry = { focusCount: 0, timeMs: 0 }\n this.entries.set(slug, created)\n return created\n }\n}\n\n/** Analytics must never throw into a form: a failing check reports \"not complete\". */\nfunction safeIsComplete(isComplete: (slug: string) => boolean, slug: string): boolean {\n try {\n return isComplete(slug) === true\n } catch {\n return false\n }\n}\n","/**\n * @sonordev/site-kit/forms - Form tracking session registry\n *\n * SINGLE SOURCE OF TRUTH for a form's `form_analytics` row: one\n * `/analytics/start` per formId per page load, shared by every tracker\n * mounted for that form. Do NOT re-fork start logic into a caller.\n *\n * The lesson from the double-count bug fixed in 4.2.2: `ManagedForm` called\n * `useForm` (which tracks) AND rendered `FormClient` (which also tracks). Two\n * independent hook instances each minted their own session uuid and POSTed\n * their own start, so a single page load wrote TWO `form_analytics` rows —\n * present in every release up to and including 4.2.1. That halved every reported\n * start -> submission conversion rate, and because each instance registered its\n * own `beforeunload` it wrote two abandonment rows per visit as well. The\n * signature in the data was unmistakable: paired rows where exactly one ever\n * completed (only FormClient's instance owns submit) but BOTH abandoned.\n *\n * Trackers SHARE the resulting analytics row id, so whichever component owns\n * submission can still complete the row no matter which one opened it. That\n * sharing is what makes this safe as a guard rather than a gamble on which\n * instance mounts first.\n *\n * Everything else that belongs to the ROW lives here too, for the same reason:\n * the per-field interaction log and the abandonment state. See\n * {@link claimAbandon} for when a visit counts as abandoned.\n */\n\n// Single source of truth for v4 UUIDs — crypto.randomUUID throws on plain HTTP\n// and older Safari. Do NOT re-fork ID generation here.\nimport { uuid } from '../shared/uuid'\nimport { FieldInteractionLog } from './field-interactions'\n\nexport interface TrackingSession {\n /** The uuid reported to the API as this form visit's session. */\n readonly sessionId: string\n readonly startedAt: number\n /** Resolves to the analytics row id, or null when the start POST failed. */\n readonly analyticsId: Promise<string | null>\n /** What this visit did with each field, reported as `field_interactions`. */\n readonly fields: FieldInteractionLog\n /**\n * The visitor did something with the form: focused or changed a field, or\n * moved between steps. A visit that only LOADED the form (the session opens\n * on mount) is a view, not an abandonment.\n */\n interacted: boolean\n /** The visit ended in site-kit's own submit. A completed row is never abandoned. */\n completed: boolean\n /**\n * The row's current state is already reported as abandoned. Abandonment\n * belongs to the ROW, not to a tracker: every mounted tracker listens for the\n * page leaving, and only one beacon may go out per state, or one visit\n * reports abandonment as many times as it has trackers. New activity clears\n * it ({@link noteActivity}), so a visitor who comes back to a hidden tab and\n * keeps going is reported again, with where they got to, when they leave.\n */\n abandonSent: boolean\n /**\n * Runs once when the session is torn down: its last tracker unmounted and\n * none rejoined within {@link SESSION_GRACE_MS}. That is how a client-side\n * navigation (or a closed modal) away from an unfinished form is reported,\n * since neither fires a page-leave event.\n */\n onEnd: (() => void) | null\n /** @internal */\n refCount: number\n /** @internal */\n releaseTimer: ReturnType<typeof setTimeout> | null\n}\n\n/**\n * How long a session outlives its last unmount before a fresh start POST is\n * allowed. Covers React StrictMode's dev-mode mount -> unmount -> mount and the\n * FormEnhancer static -> interactive swap; both remount a form within the same\n * page load and would otherwise mint a second row for one visit.\n */\nexport const SESSION_GRACE_MS = 2000\n\nconst activeSessions = new Map<string, TrackingSession>()\n\n/**\n * Join the tracking session for `formId`, opening one if none is live.\n *\n * `start` is invoked at most once per session and must resolve to the analytics\n * row id (or null when the POST failed). Callers MUST pair this with\n * {@link releaseTrackingSession} on unmount.\n */\nexport function acquireTrackingSession(\n formId: string,\n start: (sessionId: string) => Promise<string | null>,\n): TrackingSession {\n const existing = activeSessions.get(formId)\n if (existing) {\n // A tracker rejoined inside the grace window — cancel the pending teardown\n // rather than letting it delete a session that is live again.\n if (existing.releaseTimer) {\n clearTimeout(existing.releaseTimer)\n existing.releaseTimer = null\n }\n existing.refCount++\n return existing\n }\n\n const sessionId = uuid()\n const session: TrackingSession = {\n sessionId,\n startedAt: Date.now(),\n // Assigned below — declared here so the object shape is complete first.\n analyticsId: null as unknown as Promise<string | null>,\n fields: new FieldInteractionLog(),\n interacted: false,\n completed: false,\n abandonSent: false,\n onEnd: null,\n refCount: 1,\n releaseTimer: null,\n }\n\n // Register BEFORE invoking `start`, so a tracker mounting later in the same\n // commit joins this session instead of racing it to a second row. React runs\n // effects synchronously within a commit, so this check-then-set cannot be\n // interleaved — but only if nothing awaits in between.\n activeSessions.set(formId, session)\n ;(session as { analyticsId: Promise<string | null> }).analyticsId = start(sessionId)\n\n return session\n}\n\n/**\n * Leave the tracking session. The last tracker out schedules teardown after\n * {@link SESSION_GRACE_MS} rather than deleting immediately, so a remount\n * within the same page load reuses the row instead of opening another.\n */\nexport function releaseTrackingSession(formId: string, session: TrackingSession): void {\n session.refCount--\n if (session.refCount > 0) return\n if (session.releaseTimer) return\n\n session.releaseTimer = setTimeout(() => {\n session.releaseTimer = null\n // Re-check both conditions: a tracker may have rejoined, or the entry may\n // already have been replaced by a later session for the same form.\n if (session.refCount <= 0 && activeSessions.get(formId) === session) {\n activeSessions.delete(formId)\n const onEnd = session.onEnd\n session.onEnd = null\n try {\n onEnd?.()\n } catch {\n /* reporting must never throw out of a timer */\n }\n }\n }, SESSION_GRACE_MS)\n\n // Never hold the process open for a teardown timer (SSR/test environments).\n ;(session.releaseTimer as { unref?: () => void })?.unref?.()\n}\n\n/**\n * The visitor did something with the form. Arms abandonment, and makes any\n * abandonment already reported stale so the next page leave reports again.\n */\nexport function noteActivity(session: TrackingSession): void {\n if (session.completed) return\n session.interacted = true\n session.abandonSent = false\n}\n\n/**\n * Claim the one abandonment report for the row's current state. True means\n * the caller must send it now. False when the visit completed, never touched\n * the form, or has nothing new since the last report.\n *\n * Page leaves fire often and in pairs (visibilitychange then pagehide, every\n * tab switch), so this is what keeps them to one beacon per state.\n */\nexport function claimAbandon(session: TrackingSession): boolean {\n if (session.completed || !session.interacted || session.abandonSent) return false\n session.abandonSent = true\n return true\n}\n\n/**\n * The visit submitted. Set BEFORE any await in the completion path: a redirect\n * right after submit fires pagehide, and an abandon beacon must not beat the\n * completion out of the page.\n */\nexport function markCompleted(session: TrackingSession): void {\n session.completed = true\n session.abandonSent = true\n}\n\n/** Test-only: drop all live sessions so cases start from a clean registry. */\nexport function __resetTrackingSessions(): void {\n for (const session of activeSessions.values()) {\n if (session.releaseTimer) clearTimeout(session.releaseTimer)\n }\n activeSessions.clear()\n}\n","/**\n * @sonordev/site-kit/forms - Form Tracking Hook\n *\n * Tracks form analytics: step progress, per-field interactions, completion and\n * abandonment.\n *\n * The `form_analytics` row is owned by the shared session registry, not by this\n * hook — see `tracking-session.ts`. Every tracker mounted for the same form\n * joins ONE session and shares its analytics row id, field log and abandonment\n * state, so composing two trackers over a single form (as ManagedForm once did)\n * can no longer double-count.\n *\n * Abandonment is reported when a visitor who interacted with the form leaves\n * without submitting, by any of:\n * - the page being hidden or unloaded (shared/page-leave.ts) — tab close, tab\n * or app switch, full navigation, a mobile browser discarding the tab;\n * - the form going away without the page going away — a client-side\n * navigation or a closed modal — via the session's teardown (`onEnd`).\n * A hidden tab can come back; if the visitor keeps going, the next leave\n * reports again with where they got to, and a later submit clears it\n * server-side.\n */\n\n'use client'\n\nimport { useEffect, useRef, useCallback } from 'react'\nimport { sonorFetch, sonorBeacon } from '../shared/sonorFetch'\nimport { onPageLeave } from '../shared/page-leave'\nimport {\n acquireTrackingSession,\n releaseTrackingSession,\n noteActivity,\n claimAbandon,\n markCompleted,\n type TrackingSession,\n} from './tracking-session'\n\ninterface UseFormTrackingOptions {\n formId: string\n totalSteps: number\n enabled?: boolean\n debug?: boolean\n /**\n * Whether the field with this slug holds a complete, valid value right now.\n * Read whenever a report is built, so `field_interactions[slug].completed`\n * reflects the form as the visitor left it. Without it every field reports\n * `completed: false`.\n */\n isFieldComplete?: (slug: string) => boolean\n}\n\ninterface FormTrackingReturn {\n trackStepChange: (step: number) => void\n trackComplete: () => void\n /** Focus moved into a field (FormField's onFocus). */\n trackFieldFocus: (slug: string) => void\n /** Focus left a field (FormField's onBlur). */\n trackFieldBlur: (slug: string) => void\n /** A field's value changed (the form's setFieldValue). */\n trackFieldChange: (slug: string) => void\n sessionId: string\n}\n\nexport function useFormTracking({\n formId,\n totalSteps,\n enabled = true,\n debug = false,\n isFieldComplete,\n}: UseFormTrackingOptions): FormTrackingReturn {\n const sessionRef = useRef<TrackingSession | null>(null)\n const sessionIdRef = useRef<string>('')\n const startTimeRef = useRef<number>(0)\n const stepStartTimeRef = useRef<number>(0)\n const stepTimesRef = useRef<Record<number, number>>({})\n const currentStepRef = useRef<number>(1)\n const maxStepRef = useRef<number>(1)\n const analyticsIdRef = useRef<string | null>(null)\n // Latest render's check, so a report built from a listener or timer reads\n // the form's current values rather than the ones it mounted with.\n const isFieldCompleteRef = useRef(isFieldComplete)\n isFieldCompleteRef.current = isFieldComplete\n\n const fieldReport = useCallback((session: TrackingSession, now: number) => {\n const check = isFieldCompleteRef.current\n return session.fields.snapshot((slug) => (check ? check(slug) : false), now)\n }, [])\n\n // Initialize tracking\n useEffect(() => {\n if (!enabled) return\n if (!formId) {\n if (debug) console.warn('[Forms] Tracking skipped: formId is empty')\n return\n }\n\n // Record form start. Invoked at most once per session by the registry —\n // a second tracker for this form joins the existing session instead.\n const startTracking = async (sessionId: string): Promise<string | null> => {\n const apiUrl = (window as any).__SITE_KIT_API_URL__\n const apiKey = (window as any).__SITE_KIT_API_KEY__\n\n if (!apiUrl || !apiKey) {\n if (debug) console.error('[Forms] Missing API URL or API key')\n return null\n }\n\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/forms/analytics/start`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n formId,\n sessionId,\n deviceType: getDeviceType(),\n }),\n },\n { apiKey, retries: 0 },\n )\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n const data = await response.json()\n if (debug) console.log('[Forms] Started tracking:', data.id)\n return data.id ?? null\n } catch (error) {\n if (debug) console.error('[Forms] Error starting tracking:', error)\n return null\n }\n }\n\n const session = acquireTrackingSession(formId, startTracking)\n sessionRef.current = session\n sessionIdRef.current = session.sessionId\n startTimeRef.current = session.startedAt\n stepStartTimeRef.current = Date.now()\n\n let joined = true\n void session.analyticsId.then((id) => {\n if (joined) analyticsIdRef.current = id\n })\n\n const reportAbandon = (analyticsId: string | null) => {\n if (!analyticsId) return\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__\n const apiKey = (window as any).__SITE_KIT_API_KEY__\n if (!apiUrl || !apiKey) return\n\n // One report per row per state, and only for a visit that touched the\n // form and didn't submit. See claimAbandon.\n if (!claimAbandon(session)) return\n\n const now = Date.now()\n stepTimesRef.current[currentStepRef.current] = Math.floor((now - stepStartTimeRef.current) / 1000)\n\n // Fire-and-forget via sonorBeacon: keepalive fetch keeps the credential in\n // the x-api-key header (raw sendBeacon can't set headers), so abandonment\n // authenticates on 3.2+ token sites and uses the freshest minted token.\n // Keepalive bodies share a 64KB budget per page; the field log is capped\n // (field-interactions.ts) to stay well inside it.\n sonorBeacon(\n `${apiUrl}/api/public/forms/analytics/abandon`,\n {\n analyticsId,\n step: currentStepRef.current,\n maxStep: maxStepRef.current,\n stepTimes: stepTimesRef.current,\n totalTimeSeconds: Math.floor((now - startTimeRef.current) / 1000),\n fieldInteractions: fieldReport(session, now),\n abandonmentField: session.fields.lastField,\n },\n apiKey,\n )\n\n if (debug) console.log('[Forms] Abandonment tracked:', session.fields.lastField)\n }\n\n // The page is going away (or being backgrounded): the row id must already\n // be known — there is no time left to wait on the start POST.\n const stopLeaveListener = onPageLeave(() => reportAbandon(analyticsIdRef.current))\n\n // The form went away but the page didn't. The page is still alive, so this\n // one can wait for a start POST that's still in flight.\n session.onEnd = () => {\n void session.analyticsId.then(reportAbandon)\n }\n\n return () => {\n joined = false\n stopLeaveListener()\n releaseTrackingSession(formId, session)\n sessionRef.current = null\n }\n }, [formId, enabled, debug, fieldReport])\n\n /**\n * The analytics row id, waiting on the start POST if it is still in flight.\n * A fast submit used to race the start and silently drop the completion,\n * which understated conversions the same way double-starting overstated them.\n */\n const resolveAnalyticsId = useCallback(async (): Promise<string | null> => {\n if (analyticsIdRef.current) return analyticsIdRef.current\n const session = sessionRef.current\n if (!session) return null\n const id = await session.analyticsId\n if (id) analyticsIdRef.current = id\n return id\n }, [])\n\n // Field events. Cheap and synchronous — they only update the session's log;\n // the log travels with the next step, complete or abandon report.\n const trackFieldFocus = useCallback((slug: string) => {\n const session = sessionRef.current\n if (!session || session.completed) return\n if (session.fields.focus(slug)) noteActivity(session)\n }, [])\n\n const trackFieldBlur = useCallback((slug: string) => {\n sessionRef.current?.fields.blur(slug)\n }, [])\n\n const trackFieldChange = useCallback((slug: string) => {\n const session = sessionRef.current\n if (!session || session.completed) return\n if (session.fields.change(slug)) noteActivity(session)\n }, [])\n\n // Track step changes\n const trackStepChange = useCallback(async (step: number) => {\n if (!enabled) return\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__\n const apiKey = (window as any).__SITE_KIT_API_KEY__\n\n if (!apiUrl || !apiKey) {\n if (debug) console.error('[Forms] Missing API URL or API key')\n return\n }\n\n const now = Date.now()\n\n // Record time spent on previous step\n const prevStepTime = Math.floor((now - stepStartTimeRef.current) / 1000)\n stepTimesRef.current[currentStepRef.current] = prevStepTime\n\n // Update refs\n currentStepRef.current = step\n maxStepRef.current = Math.max(maxStepRef.current, step)\n stepStartTimeRef.current = now\n\n const session = sessionRef.current\n if (session) noteActivity(session)\n\n const analyticsId = await resolveAnalyticsId()\n if (!analyticsId) return\n\n // Update database\n try {\n const response = await sonorFetch(\n `${apiUrl}/api/public/forms/analytics/step`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n analyticsId,\n step,\n maxStep: maxStepRef.current,\n stepTimes: stepTimesRef.current,\n ...(session ? { fieldInteractions: fieldReport(session, Date.now()) } : {}),\n }),\n },\n { apiKey, retries: 0 },\n )\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n if (debug) console.log('[Forms] Step changed to:', step)\n } catch (error) {\n if (debug) console.error('[Forms] Error updating step:', error)\n }\n }, [enabled, debug, resolveAnalyticsId, fieldReport])\n\n // Track completion\n const trackComplete = useCallback(async () => {\n if (!enabled) return\n\n // A completed row must never also be reported as abandoned — not when the\n // success screen is later closed, and not when a redirect right after\n // submit fires pagehide while this function is still awaiting. So this is\n // set synchronously, before anything below can yield.\n const session = sessionRef.current\n if (session) markCompleted(session)\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__\n const apiKey = (window as any).__SITE_KIT_API_KEY__\n\n if (!apiUrl || !apiKey) {\n if (debug) console.error('[Forms] Missing API URL or API key')\n return\n }\n\n const now = Date.now()\n\n // Record time for final step\n const finalStepTime = Math.floor((now - stepStartTimeRef.current) / 1000)\n stepTimesRef.current[currentStepRef.current] = finalStepTime\n // Captured now: the values are the ones that were submitted.\n const fieldInteractions = session ? fieldReport(session, now) : undefined\n\n const analyticsId = await resolveAnalyticsId()\n if (!analyticsId) return\n\n try {\n // Complete form analytics tracking\n // Note: A database trigger will automatically log this as a conversion\n // in analytics_conversions when completed_at is set\n const response = await sonorFetch(\n `${apiUrl}/api/public/forms/analytics/complete`,\n {\n method: 'POST',\n // A form with a redirect_url navigates away right after submit, which\n // cancels an ordinary in-flight fetch. And since completion now\n // suppresses the abandon beacon, losing this would leave the row\n // neither completed nor abandoned.\n keepalive: true,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n analyticsId,\n totalSteps,\n stepTimes: stepTimesRef.current,\n totalTimeSeconds: Math.floor((now - startTimeRef.current) / 1000),\n ...(fieldInteractions ? { fieldInteractions } : {}),\n }),\n },\n { apiKey, retries: 0 },\n )\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n if (debug) console.log('[Forms] Form completed')\n\n // No client-side conversion POST: the Sonor API records the canonical\n // form_submission conversion (analytics_conversions + session flag)\n // when the submission lands at /api/public/forms/submit. The old POST\n // here sent this hook's form-tracking uuid as `sessionId`, which\n // matched no analytics session and double-counted the conversion.\n } catch (error) {\n if (debug) console.error('[Forms] Error completing tracking:', error)\n }\n }, [enabled, totalSteps, debug, resolveAnalyticsId, fieldReport])\n\n return {\n trackStepChange,\n trackComplete,\n trackFieldFocus,\n trackFieldBlur,\n trackFieldChange,\n sessionId: sessionIdRef.current,\n }\n}\n\n// Helper\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\n const ua = navigator.userAgent\n if (/tablet|ipad|playbook|silk/i.test(ua)) return 'tablet'\n if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return 'mobile'\n return 'desktop'\n}\n","/**\n * @sonordev/site-kit/forms - useForm Hook\n * \n * Headless hook for complete control over form rendering.\n * Fetches form config from API, handles validation, state, and submission.\n * \n * @example\n * ```tsx\n * const { form, fields, values, errors, setFieldValue, submit, isSubmitting } = useForm('contact-form')\n * \n * return (\n * <form onSubmit={(e) => { e.preventDefault(); submit() }}>\n * {fields.map(field => (\n * <MyCustomInput\n * key={field.slug}\n * label={field.label}\n * value={values[field.slug]}\n * error={errors[field.slug]}\n * onChange={(val) => setFieldValue(field.slug, val)}\n * />\n * ))}\n * <button type=\"submit\" disabled={isSubmitting}>Submit</button>\n * </form>\n * )\n * ```\n */\n\n'use client'\n\nimport { useState, useEffect, useCallback, useMemo, useRef } from 'react'\nimport { useFormTracking } from './useFormTracking'\nimport * as fieldRules from './field-rules'\n// Shared with StaticForm — the server shell and this client path MUST agree\n// on field order, step count and success copy or the enhancement swap jumps.\nimport { normalizeFormConfig } from './normalize-config'\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { submitForm } from './submitForm'\nimport type { \n ManagedFormConfig, \n FormField, \n FormSubmission \n} from './types'\nimport { DEFAULT_FORM_SUCCESS_MESSAGE } from './defaultSuccessMessage'\n\n// ============================================\n// Types\n// ============================================\n\nexport interface UseFormOptions {\n /** Project ID (defaults to SiteKitLayout config) */\n projectId?: string\n /** Callback when form submits successfully */\n onSuccess?: (submission: FormSubmission) => void\n /** Callback when submission fails */\n onError?: (error: Error) => void\n /** Initial values to prefill */\n initialValues?: Record<string, unknown>\n /** Auto-redirect after success (override form config) */\n redirectUrl?: string | false\n /**\n * Server-fetched form payload (from `getFormConfig` in\n * `@sonordev/site-kit/forms/server`). When provided, the fields render on\n * the first client render — no config fetch, no \"Loading form...\" flash.\n * Accepts the RAW API payload; normalized here exactly like a client fetch.\n */\n initialForm?: Record<string, unknown> | null\n /**\n * Report this form's funnel to Sonor (`form_analytics`). Defaults to true —\n * a headless `useForm` consumer renders and submits the form itself, so this\n * hook is the only thing that can track it.\n *\n * `ManagedForm` passes FALSE: it delegates rendering, step navigation and\n * submission to `FormClient`, which tracks that path. Exactly one component\n * may own a form's tracking — two owners was the double-count bug fixed\n * in 4.2.2.\n */\n trackAnalytics?: boolean\n}\n\n\nexport interface UseFormReturn {\n /** Form configuration (null while loading) */\n form: ManagedFormConfig | null\n /** Loading state */\n isLoading: boolean\n /** Error fetching form */\n fetchError: Error | null\n /** Human-readable error from the last submit attempt (null when none) */\n submitError: string | null\n\n /** All form fields */\n allFields: FormField[]\n /** Fields for current step (multi-step) or all fields (single step) */\n fields: FormField[]\n /** Visible fields only (respecting conditional logic) */\n visibleFields: FormField[]\n \n /** Current form values */\n values: Record<string, unknown>\n /** Current validation errors */\n errors: Record<string, string>\n \n /** Set a single field value */\n setFieldValue: (key: string, value: unknown) => void\n /** Set multiple field values at once */\n setValues: (values: Record<string, unknown>) => void\n /** Clear all errors */\n clearErrors: () => void\n \n /** Multi-step state */\n step: number\n totalSteps: number\n isMultiStep: boolean\n progress: number\n \n /** Multi-step navigation */\n nextStep: () => boolean\n prevStep: () => void\n goToStep: (step: number) => void\n canGoNext: boolean\n canGoPrev: boolean\n isLastStep: boolean\n \n /** Validate current step */\n validate: () => boolean\n /** Validate a single field */\n validateField: (field: FormField) => string | null\n /** Check if a field is visible (conditional logic) */\n isFieldVisible: (field: FormField) => boolean\n \n /** Submit the form */\n submit: () => Promise<void>\n /** Submission state */\n isSubmitting: boolean\n isComplete: boolean\n /** Reset form to initial state */\n reset: () => void\n\n /**\n * Report focus entering / leaving a field (wire to your inputs'\n * onFocus/onBlur), so Sonor's field-level drop-off knows which field a\n * visitor was on when they left. Value changes via setFieldValue are tracked\n * without them.\n */\n trackFieldFocus: (slug: string) => void\n trackFieldBlur: (slug: string) => void\n}\n\n// ============================================\n// Hook\n// ============================================\n\nexport function useForm(\n formIdOrSlug: string,\n options: UseFormOptions = {}\n): UseFormReturn {\n const {\n projectId: optionsProjectId,\n onSuccess,\n onError,\n initialValues = {},\n redirectUrl,\n initialForm,\n trackAnalytics = true,\n } = options\n\n // Get projectId from window globals if not provided\n const projectId = optionsProjectId ||\n (typeof window !== 'undefined' ? (window as any).__SITE_KIT_PROJECT_ID__ : undefined)\n\n // State — a server-provided config renders fields on the very first pass\n // (lazy initializer, so normalization runs once, and SSR + hydration agree).\n const [form, setForm] = useState<ManagedFormConfig | null>(() =>\n initialForm ? normalizeFormConfig(initialForm) : null,\n )\n const [isLoading, setIsLoading] = useState(!initialForm)\n const [fetchError, setFetchError] = useState<Error | null>(null)\n const [values, setValuesState] = useState<Record<string, unknown>>(() => {\n if (!initialForm) return initialValues\n const defaults: Record<string, unknown> = {}\n for (const field of (initialForm as any).fields || []) {\n if (field.default_value !== undefined && field.default_value !== null) {\n defaults[field.slug] = field.default_value\n }\n }\n return { ...defaults, ...initialValues }\n })\n const [errors, setErrors] = useState<Record<string, string>>({})\n const [step, setStep] = useState(1)\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [isComplete, setIsComplete] = useState(false)\n const [submitError, setSubmitError] = useState<string | null>(null)\n\n // Synchronous re-entrancy guard + anti-bot timing.\n const isSubmittingRef = useRef(false)\n const formLoadedAt = useRef(Date.now())\n\n const totalSteps = form?.total_steps || 1\n const isMultiStep = (form?.is_multi_step) || false\n\n // Fetch form config (project is derived from API key on the backend; projectId is optional)\n useEffect(() => {\n // Server already provided the config — the recaptcha site key still needs\n // publishing to the window global, then there is nothing to fetch. Only\n // honored when it matches the requested form, so a slug change after\n // mount still refetches instead of pinning the stale config.\n const initialMatches =\n initialForm &&\n ((initialForm as any).slug === formIdOrSlug || (initialForm as any).id === formIdOrSlug)\n if (initialMatches) {\n const siteKey = (initialForm as any).recaptcha_site_key\n if (typeof window !== 'undefined' && siteKey) {\n ;(window as any).__SITE_KIT_RECAPTCHA_SITE_KEY__ = siteKey\n }\n return\n }\n\n const apiUrl = typeof window !== 'undefined'\n ? (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n : 'https://api.sonor.io'\n\n async function fetchForm() {\n try {\n setIsLoading(true)\n setFetchError(null)\n\n // The provider sets __SITE_KIT_API_KEY__ during its render; if this\n // hook's effect happens to run first, poll briefly for it rather than\n // failing permanently and wedging the form on \"API key is required\".\n const readApiKey = (): string | undefined =>\n typeof window !== 'undefined' ? (window as any).__SITE_KIT_API_KEY__ : undefined\n let apiKey = readApiKey()\n for (let i = 0; i < 15 && !apiKey; i++) {\n await new Promise((r) => setTimeout(r, 100))\n apiKey = readApiKey()\n }\n if (!apiKey) {\n throw new Error('API key is required. Provide it via SiteKitLayout or set SONOR_API_KEY.')\n }\n\n const url = `${apiUrl}/api/public/forms/config`\n const init: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n formIdOrSlug: formIdOrSlug,\n }),\n }\n\n // Pass the credential via options.apiKey, NOT an Authorization header.\n // extractApiKey() server-side prefers Authorization: Bearer over x-api-key,\n // so a hand-set Bearer pins the stale build-time seed and defeats\n // sonorFetch's refresh — the seed 401s and the refresh-retry keeps\n // re-sending the same dead Bearer. Letting sonorFetch own x-api-key means\n // the server sees the FRESH token.\n const response = await sonorFetch(url, init, { apiKey, retries: 3, timeoutMs: 15000 })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch form: ${response.statusText}`)\n }\n \n const data = await response.json()\n if (!data) throw new Error('Form not found')\n\n if (typeof window !== 'undefined' && data.recaptcha_site_key) {\n ;(window as any).__SITE_KIT_RECAPTCHA_SITE_KEY__ = data.recaptcha_site_key\n }\n\n setForm(normalizeFormConfig(data))\n \n // Set default values from field configs\n const defaults: Record<string, unknown> = {}\n for (const field of data.fields || []) {\n if (field.default_value !== undefined && field.default_value !== null) {\n defaults[field.slug] = field.default_value\n }\n }\n setValuesState({ ...defaults, ...initialValues })\n \n } catch (err) {\n setFetchError(err as Error)\n } finally {\n setIsLoading(false)\n }\n }\n \n fetchForm()\n // initialForm intentionally captured once — server config for THIS render\n // of THIS form; a changed slug refetches, a re-created object must not.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [formIdOrSlug, projectId])\n \n // All fields\n const allFields = useMemo(() => form?.fields || [], [form])\n \n // Fields for current step\n const fields = useMemo(() => {\n if (!isMultiStep) return allFields\n \n const currentStepConfig = form?.steps?.find(s => s.step_number === step)\n if (!currentStepConfig) return allFields\n \n return allFields.filter(f => f.step_id === currentStepConfig.id)\n }, [form, step, allFields, isMultiStep])\n \n // Visibility and validation come from field-rules.ts, shared with\n // FormClient. These wrappers only bind the current values.\n const isFieldVisible = useCallback(\n (field: FormField): boolean => fieldRules.isFieldVisible(field, values),\n [values],\n )\n\n // Visible fields only\n const visibleFields = useMemo(() => {\n return fields.filter(isFieldVisible)\n }, [fields, isFieldVisible])\n \n // Validate a single field\n const validateField = useCallback(\n (field: FormField): string | null => fieldRules.validateField(field, values, isFieldVisible),\n [values, isFieldVisible],\n )\n\n const fieldBySlug = useMemo(\n () => new Map(allFields.map((f) => [f.slug, f] as const)),\n [allFields],\n )\n\n const {\n trackStepChange,\n trackComplete,\n trackFieldFocus,\n trackFieldBlur,\n trackFieldChange,\n } = useFormTracking({\n formId: form?.id || '',\n totalSteps,\n enabled: trackAnalytics,\n isFieldComplete: (slug) => {\n const field = fieldBySlug.get(slug)\n return field ? fieldRules.isFieldComplete(field, values, isFieldVisible) : false\n },\n })\n\n // Validate current step\n const validate = useCallback((): boolean => {\n const newErrors: Record<string, string> = {}\n \n for (const field of fields) {\n const error = validateField(field)\n if (error) {\n newErrors[field.slug] = error\n }\n }\n \n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }, [fields, validateField])\n\n // Validate EVERY field across all steps — used on final submit so a required\n // field left empty on an earlier step cannot slip through.\n const validateAll = useCallback((): boolean => {\n const newErrors: Record<string, string> = {}\n for (const field of allFields) {\n const error = validateField(field)\n if (error) newErrors[field.slug] = error\n }\n setErrors(newErrors)\n return Object.keys(newErrors).length === 0\n }, [allFields, validateField])\n\n // Visible field values only — never submit a value from a conditionally-hidden field.\n const buildVisibleValues = useCallback((): Record<string, unknown> => {\n const out: Record<string, unknown> = {}\n for (const field of allFields) {\n if (!isFieldVisible(field)) continue\n if (field.slug in values) out[field.slug] = values[field.slug]\n }\n return out\n }, [allFields, values, isFieldVisible])\n\n // Set single field value\n const setFieldValue = useCallback((key: string, value: unknown) => {\n setValuesState(prev => ({ ...prev, [key]: value }))\n trackFieldChange(key)\n // Clear error when field changes\n setErrors(prev => {\n if (prev[key]) {\n const next = { ...prev }\n delete next[key]\n return next\n }\n return prev\n })\n }, [trackFieldChange])\n \n // Set multiple values\n const setValues = useCallback((newValues: Record<string, unknown>) => {\n setValuesState(prev => ({ ...prev, ...newValues }))\n }, [])\n \n // Clear all errors\n const clearErrors = useCallback(() => {\n setErrors({})\n }, [])\n \n // Step navigation\n const canGoNext = step < totalSteps\n const canGoPrev = step > 1\n const isLastStep = step === totalSteps\n const progress = Math.round((step / totalSteps) * 100)\n \n const nextStep = useCallback((): boolean => {\n if (!validate()) return false\n \n if (step < totalSteps) {\n const newStep = step + 1\n setStep(newStep)\n trackStepChange(newStep)\n return true\n }\n return false\n }, [step, totalSteps, validate, trackStepChange])\n \n const prevStep = useCallback(() => {\n if (step > 1) {\n const newStep = step - 1\n setStep(newStep)\n trackStepChange(newStep)\n }\n }, [step, trackStepChange])\n \n const goToStep = useCallback((targetStep: number) => {\n if (targetStep >= 1 && targetStep <= totalSteps) {\n setStep(targetStep)\n trackStepChange(targetStep)\n }\n }, [totalSteps, trackStepChange])\n \n // Submit form\n const submit = useCallback(async () => {\n if (!form) return\n // Re-entrancy guard — blocks a concurrent double-submit in the same tick.\n if (isSubmittingRef.current) return\n if (!validateAll()) return\n\n isSubmittingRef.current = true\n setIsSubmitting(true)\n setSubmitError(null)\n\n try {\n const data = await submitForm({\n config: form,\n values: buildVisibleValues(),\n honeypotValue: '',\n formLoadedAt: formLoadedAt.current,\n })\n\n trackComplete()\n setIsComplete(true)\n onSuccess?.(data as FormSubmission)\n\n const finalRedirect = redirectUrl !== false\n ? (redirectUrl || form.redirect_url)\n : undefined\n if (finalRedirect) {\n window.location.href = finalRedirect\n }\n } catch (error) {\n console.error('[useForm] Submission error:', error)\n setSubmitError('Something went wrong sending your submission. Please try again.')\n onError?.(error as Error)\n } finally {\n isSubmittingRef.current = false\n setIsSubmitting(false)\n }\n }, [form, validateAll, buildVisibleValues, trackComplete, onSuccess, onError, redirectUrl])\n \n // Reset form\n const reset = useCallback(() => {\n setValuesState(initialValues)\n setErrors({})\n setStep(1)\n setIsComplete(false)\n setSubmitError(null)\n }, [initialValues])\n \n return {\n form,\n isLoading,\n fetchError,\n submitError,\n\n allFields,\n fields,\n visibleFields,\n \n values,\n errors,\n setFieldValue,\n setValues,\n clearErrors,\n \n step,\n totalSteps,\n isMultiStep,\n progress,\n \n nextStep,\n prevStep,\n goToStep,\n canGoNext,\n canGoPrev,\n isLastStep,\n \n validate,\n validateField,\n isFieldVisible,\n \n submit,\n isSubmitting,\n isComplete,\n reset,\n\n trackFieldFocus,\n trackFieldBlur,\n }\n}\n"]}
|