@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/blog/excerpt.ts","../src/blog/server-core.ts"],"names":["resolveServerApiConfig","fetchBlogPostBySlug","notFound","withSiteParam","fetchBlogCategories","resolveBlogPostUrl","createBlogRoutes","resolveBlogUrl","blogCategorySlug","resolveBlogArtwork","description","fetchRelatedBlogPosts"],"mappings":"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","file":"chunk-LMEUYRRR.js","sourcesContent":["/**\n * Excerpt sanitizing for blog metadata, schema and feeds.\n *\n * Pure (no `server-only` chain) so it is unit-testable and safe to reuse.\n * Source of truth for turning a stored excerpt into display-safe prose.\n */\n\n/**\n * Turn a stored excerpt into something safe to put in a meta description,\n * a schema `description`, or an RSS `<description>`.\n *\n * The AI blog pipeline stores content as JSON sections\n * (`{\"heading\": \"## ...\", \"content\": \"## ...\\n\\nIf you're asking **how**...\"}`)\n * and that value has been shipping verbatim into <meta name=\"description\">.\n * nkylawfirm.com had three live articles whose SERP snippet was raw JSON with\n * markdown asterisks and literal \\n. Parse the sections out, strip markdown,\n * and cap at a sentence boundary.\n */\nexport function sanitizeExcerpt(raw: string | undefined | null, maxLength = 160): string {\n if (!raw) return ''\n let text = String(raw).trim()\n\n // JSON section(s) — take the prose, not the heading, and never the braces.\n if (text.startsWith('{') || text.startsWith('[')) {\n const fromSections = (value: unknown): string => {\n const list = Array.isArray(value) ? value : [value]\n return list\n .map((s) => (s && typeof s === 'object' ? (s as any).content || (s as any).heading || '' : ''))\n .filter(Boolean)\n .join(' ')\n }\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n // Concatenated objects: \"{...}\\n\\n{...}\" — take the first.\n const first = text.split(/\\}\\s*[\\r\\n]+\\s*\\{/)[0]\n try {\n parsed = JSON.parse(first.endsWith('}') ? first : `${first}}`)\n } catch {\n parsed = null\n }\n }\n text = parsed ? fromSections(parsed) : text.replace(/[{}\"[\\]]/g, ' ')\n }\n\n const plain = text\n .replace(/```[\\s\\S]*?```/g, ' ') // fenced code\n .replace(/!\\[[^\\]]*\\]\\([^)]*\\)/g, ' ') // images\n .replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1') // links -> text\n .replace(/^#{1,6}\\s+/gm, '') // headings\n .replace(/[*_~`>]/g, '') // emphasis / quotes / code\n .replace(/\\\\n/g, ' ') // literal escaped newlines\n .replace(/\\s+/g, ' ')\n .trim()\n\n if (plain.length <= maxLength) return plain\n\n // Prefer a sentence boundary, then a word boundary.\n const window = plain.slice(0, maxLength + 1)\n const lastStop = Math.max(window.lastIndexOf('. '), window.lastIndexOf('? '), window.lastIndexOf('! '))\n if (lastStop > maxLength * 0.5) return window.slice(0, lastStop + 1).trim()\n\n const cut = plain.slice(0, maxLength)\n const lastSpace = cut.lastIndexOf(' ')\n return `${(lastSpace > maxLength * 0.6 ? cut.slice(0, lastSpace) : cut).replace(/[\\s,;:—–-]+$/, '')}…`\n}\n","/**\n * @sonordev/site-kit/blog/server\n *\n * Data and metadata helpers only (no React components). For `BlogPost` / `BlogList`\n * in the App Router, import from `@sonordev/site-kit/blog/server-ui` so Next never\n * treats `getAllBlogSlugs` / `generateBlogStaticParams` as client code.\n */\n\nimport type { Metadata } from 'next'\nimport { notFound } from 'next/navigation'\nimport type { BlogPost as BlogPostRecord, BlogAuthor, TocItem, TopicCluster, ClusterNavigation } from './types'\n\n/**\n * Server key/URL resolution — SINGLE SOURCE OF TRUTH.\n *\n * Every fetcher below resolves its API config through `resolveServerApiConfig`.\n * Do NOT re-fork a local `getConfig()` here: this file used to carry a drifted\n * copy of that helper, and the copy grew a `process.env.NEXT_PUBLIC_SONOR_API_KEY`\n * fallback the canonical one never had. Because Next inlines `NEXT_PUBLIC_*` into\n * every bundle a module lands in, and this module was reachable from the\n * client-stamped `@sonordev/site-kit/blog` barrel, that fallback published the\n * site's raw `sonor_` project key to the browser. One diverging copy, one leaked\n * credential.\n *\n * This import also carries `server-only` transitively, which is the point: if a\n * client component ever reaches this module again, the consumer's build fails\n * loudly instead of silently shipping an `x-api-key` fetch to visitors.\n */\nimport { resolveServerApiConfig } from '../server/server-fetch'\nimport { withSiteParam } from '../sites/site-param'\nimport { fetchBlogCategories, fetchBlogPostBySlug, fetchRelatedBlogPosts } from './public-reads'\nimport { sanitizeExcerpt } from './excerpt'\nimport { resolveBlogArtwork } from './artwork'\nimport { blogCategorySlug, createBlogRoutes, resolveBlogPostUrl, resolveBlogUrl, type BlogRoutingOptions, type BlogRoutePost } from './routes'\n\nexport { sanitizeExcerpt }\n\n// ============================================================================\n// SEO VALIDATION UTILITIES\n// ============================================================================\n\nexport const SEO_LIMITS = {\n title: { min: 30, max: 60, recommended: 55 },\n metaDescription: { min: 120, max: 160, recommended: 155 },\n excerpt: { min: 100, max: 300, recommended: 200 },\n slug: { max: 75 },\n focusKeyphrase: { min: 2, max: 4, words: true }, // 2-4 words\n} as const\n\nexport interface SeoValidationResult {\n field: string\n value: string\n length: number\n limit: { min?: number; max: number; recommended?: number }\n status: 'good' | 'warning' | 'error'\n message: string\n}\n\n/**\n * Validate SEO title (60 chars max, keyword-first recommended)\n */\nexport function validateSeoTitle(title: string, focusKeyphrase?: string): SeoValidationResult {\n const length = title.length\n let status: SeoValidationResult['status'] = 'good'\n let message = 'Title length is optimal'\n\n if (length > SEO_LIMITS.title.max) {\n status = 'error'\n message = `Title is ${length - SEO_LIMITS.title.max} characters too long (max ${SEO_LIMITS.title.max})`\n } else if (length < SEO_LIMITS.title.min) {\n status = 'warning'\n message = `Title is short (${length}/${SEO_LIMITS.title.min} min)`\n } else if (focusKeyphrase && !title.toLowerCase().includes(focusKeyphrase.toLowerCase())) {\n status = 'warning'\n message = 'Focus keyphrase not found in title'\n } else if (focusKeyphrase && !title.toLowerCase().startsWith(focusKeyphrase.toLowerCase())) {\n status = 'warning'\n message = 'Title should start with focus keyphrase for best results'\n }\n\n return { field: 'title', value: title, length, limit: SEO_LIMITS.title, status, message }\n}\n\n/**\n * Validate meta description (150-160 chars, benefit-driven)\n */\nexport function validateMetaDescription(description: string, focusKeyphrase?: string): SeoValidationResult {\n const length = description.length\n let status: SeoValidationResult['status'] = 'good'\n let message = 'Meta description is optimal'\n\n if (length > SEO_LIMITS.metaDescription.max) {\n status = 'error'\n message = `Description will be truncated (${length}/${SEO_LIMITS.metaDescription.max})`\n } else if (length < SEO_LIMITS.metaDescription.min) {\n status = 'warning'\n message = `Description is short (${length}/${SEO_LIMITS.metaDescription.min} min)`\n } else if (focusKeyphrase && !description.toLowerCase().includes(focusKeyphrase.toLowerCase())) {\n status = 'warning'\n message = 'Focus keyphrase not found in description'\n }\n\n return { field: 'meta_description', value: description, length, limit: SEO_LIMITS.metaDescription, status, message }\n}\n\n/**\n * Full SEO validation for a blog post\n */\nexport function validateBlogPostSeo(post: Partial<BlogPostRecord>): SeoValidationResult[] {\n const results: SeoValidationResult[] = []\n const focusKeyphrase = post.focus_keyphrase\n\n if (post.meta_title || post.title) {\n results.push(validateSeoTitle(post.meta_title || post.title || '', focusKeyphrase))\n }\n\n if (post.meta_description) {\n results.push(validateMetaDescription(post.meta_description, focusKeyphrase))\n }\n\n // Check H1 alignment (title should match keyword)\n if (post.title && focusKeyphrase) {\n const titleLower = post.title.toLowerCase()\n const keyLower = focusKeyphrase.toLowerCase()\n if (!titleLower.includes(keyLower)) {\n results.push({\n field: 'h1_alignment',\n value: post.title,\n length: post.title.length,\n limit: { max: 100 },\n status: 'warning',\n message: 'H1 (title) should include the focus keyphrase',\n })\n }\n }\n\n // Check word count (1200-2500 recommended for long-form)\n if (post.word_count !== undefined) {\n let wordStatus: SeoValidationResult['status'] = 'good'\n let wordMessage = 'Content length is optimal for SEO'\n \n if (post.word_count < 600) {\n wordStatus = 'error'\n wordMessage = `Content is thin (${post.word_count} words). Aim for 1200+ words.`\n } else if (post.word_count < 1200) {\n wordStatus = 'warning'\n wordMessage = `Content is short (${post.word_count} words). Long-form (1200-2500) ranks better.`\n } else if (post.word_count > 2500) {\n wordMessage = `Comprehensive content (${post.word_count} words). Consider splitting into a topic cluster.`\n }\n\n results.push({\n field: 'word_count',\n value: String(post.word_count),\n length: post.word_count,\n limit: { min: 1200, max: 2500, recommended: 1800 },\n status: wordStatus,\n message: wordMessage,\n })\n }\n\n return results\n}\n\n// ============================================================================\n// DATA FETCHING\n// ============================================================================\n//\n// Every blog read below tells the API which sub-site is asking: the URL (or,\n// for POST related, the body) carries `site=<host>` via `sites/site-param`.\n// On a multi-site project a post with no site is project-wide and a post\n// tagged `bd-charlotte.com` shows only on that host, so a read without `site`\n// would hand one microsite its siblings' posts. The host resolves from\n// NEXT_PUBLIC_SITE_URL, which every microsite already sets; fetchers that take\n// arguments also accept an explicit `{ site }` override. `getAllBlogSlugs` and\n// `getAllAuthorSlugs` stay zero-arg so they remain assignable to Next's\n// `generateStaticParams` (see 5.7.0), so they resolve from the env only.\n\n/**\n * Fetch a blog post by slug (server-side)\n *\n * @param options.site - Sub-site host override. Omit to resolve from\n * NEXT_PUBLIC_SITE_URL.\n */\nexport async function getBlogPost(\n slug: string,\n options?: { site?: string }\n): Promise<BlogPostRecord | null> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Blog] No API key configured')\n return null\n }\n return fetchBlogPostBySlug({ ...config, site: options?.site }, slug)\n}\n\n/**\n * Fetch a blog post by slug, or answer 404 when there isn't one.\n *\n * `getBlogPost` returns null for a mistyped or deleted slug, and the page\n * used to carry on rendering a \"not found\" message with HTTP 200 and an\n * indexable title: a soft 404 on every bad post URL (vsf-consulting-nextjs\n * /insights, found 2026-09-15). This calls Next's `notFound()` instead, so the\n * route answers 404 with `noindex`.\n *\n * Call it from `generateMetadata` (or the page) before rendering `BlogPost`:\n * metadata resolves before anything streams, so the status is a real 404.\n * The fetch is the same one `BlogPost` and `generateBlogPostMetadata` make,\n * and Next dedupes it within the render.\n *\n * @example\n * ```tsx\n * export async function generateMetadata({ params }) {\n * const { slug } = await params\n * await requireBlogPost(slug)\n * return generateBlogPostMetadata(slug, { siteName: 'Acme' })\n * }\n * ```\n */\nexport async function requireBlogPost(\n slug: string,\n options?: { site?: string }\n): Promise<BlogPostRecord> {\n const post = await getBlogPost(slug, options)\n if (!post) notFound()\n return post\n}\n\n/**\n * Fetch all blog post slugs for static generation\n */\nexport async function getAllBlogSlugs(): Promise<\n { slug: string; id?: string; last_modified?: string; article_type?: string }[]\n> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Blog] No API key configured')\n return []\n }\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/blog/slugs`), {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 300 },\n })\n\n if (!response.ok) return []\n\n const data = await response.json()\n return data.slugs || []\n } catch (error) {\n console.error('[Blog] Error fetching slugs:', error)\n return []\n }\n}\n\n/**\n * Fetch blog categories\n */\nexport async function getBlogCategories(\n options?: { site?: string }\n): Promise<{ name: string; slug: string; post_count: number }[]> {\n const config = resolveServerApiConfig()\n if (!config) return []\n // The public endpoint always returns post_count; BlogCategory types it\n // optional because the dashboard shape omits it.\n return (await fetchBlogCategories({ ...config, site: options?.site })) as {\n name: string\n slug: string\n post_count: number\n }[]\n}\n\n// ============================================================================\n// METADATA GENERATION\n// ============================================================================\n\nexport interface BlogMetadataOptions extends BlogRoutingOptions {\n /** Site name for og:site_name */\n siteName?: string\n /** Base URL of the site */\n siteUrl?: string\n /** URL path prefix for blog index and posts (default `/blog`, e.g. `/insights`) */\n blogBasePath?: string\n /** Default OG image */\n defaultImage?: string\n /** Twitter handle */\n twitterHandle?: string\n}\n\nexport interface BlogPostMetadataOptions extends BlogMetadataOptions {\n /**\n * Declare the featured image (or `defaultImage`) as `openGraph.images` and\n * `twitter.images`. Default true.\n *\n * Pass false when the post route has its own card, an\n * `opengraph-image.tsx` beside the page. Next lets declared images beat\n * that file, so leaving them in silently swaps the post's card for the raw\n * photo. With false the `images` keys are left out entirely, not set to\n * undefined: Next checks `hasOwnProperty('images')`, so even an undefined\n * value hides the card.\n */\n images?: boolean\n /**\n * What to do when the post doesn't exist. Default true: call Next's\n * `notFound()`, so the route answers 404. False returns placeholder\n * metadata marked `noindex` instead, for a page that renders its own\n * missing-post state.\n */\n notFound?: boolean\n}\n\n/**\n * Generate metadata for a blog post page\n */\nexport async function generateBlogPostMetadata(\n slug: string,\n options: BlogPostMetadataOptions = {}\n): Promise<Metadata> {\n const post = await getBlogPost(slug)\n const { siteName, siteUrl = '', defaultImage, twitterHandle } = options\n if (!post) {\n // A missing post used to get an indexable \"Post Not Found\" title with a\n // 200, which is a soft 404 on every mistyped or deleted post URL.\n if (options.notFound !== false) notFound()\n return {\n title: 'Post Not Found',\n description: 'The requested blog post could not be found.',\n robots: { index: false, follow: true },\n }\n }\n\n const title = post.meta_title || post.title\n const description = sanitizeExcerpt(post.meta_description || post.excerpt)\n // og_image / featured_image_width / featured_image_height never existed in\n // blog_posts (verified against the live schema) — reading them always\n // produced undefined. Resolution goes straight to featured_image.\n const image = options.images === false ? undefined : post.featured_image || defaultImage\n const url = resolveBlogPostUrl(post, options)\n\n return {\n title,\n description,\n openGraph: {\n title: post.og_title || title,\n description: post.og_description || description,\n url,\n siteName,\n type: 'article',\n publishedTime: post.published_at,\n authors: post.author ? [typeof post.author === 'string' ? post.author : post.author.name] : undefined,\n ...(image && {\n images: [\n {\n url: image,\n width: 1200,\n height: 630,\n alt: post.featured_image_alt || post.title,\n },\n ],\n }),\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n ...(image && { images: [image] }),\n creator: twitterHandle,\n },\n alternates: {\n canonical: url,\n },\n other: {\n 'article:published_time': post.published_at || '',\n 'article:section': typeof post.category === 'string' ? post.category : (post.category?.name || ''),\n },\n }\n}\n\n/**\n * Generate metadata for the blog index page\n */\nexport function generateBlogIndexMetadata(options: BlogMetadataOptions & {\n title?: string\n description?: string\n}): Metadata {\n const {\n title = 'Blog',\n description = 'Read our latest articles and insights.',\n siteName,\n siteUrl = '',\n defaultImage,\n twitterHandle,\n } = options\n const base = createBlogRoutes(options).index\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n url: resolveBlogUrl(base, siteUrl),\n siteName,\n type: 'website',\n ...(defaultImage && { images: [{ url: defaultImage }] }),\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n ...(defaultImage && { images: [defaultImage] }),\n creator: twitterHandle,\n },\n }\n}\n\n/**\n * Generate metadata for a category page\n */\nexport function generateBlogCategoryMetadata(\n categoryName: string,\n options: BlogMetadataOptions & { categorySlug?: string } = {}\n): Metadata {\n const { siteName, siteUrl = '', defaultImage } = options\n const title = `${categoryName} - Blog`\n const description = `Browse all posts in ${categoryName}.`\n // The URL wants the route slug, not the display name: lowercasing \"Case\n // Studies\" produced /blog/category/case%20studies against a real route of\n // /blog/category/case-studies. Callers that have the slug pass it; the\n // fallback slugifies the name the same way the dashboard does.\n const slug =\n options.categorySlug ??\n categoryName\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n url: resolveBlogUrl(createBlogRoutes(options).category(slug), siteUrl),\n siteName,\n type: 'website',\n ...(defaultImage && { images: [{ url: defaultImage }] }),\n },\n }\n}\n\n// ============================================================================\n// STATIC PARAMS GENERATION\n// ============================================================================\n\n/**\n * What Next passes to a route's `generateStaticParams`: the parent segments'\n * params. The blog helpers ignore it; it's typed so they can be exported\n * directly as `generateStaticParams`.\n */\nexport interface NextStaticParamsProps {\n params: unknown\n}\n\nfunction isNextStaticParamsProps(value: BlogRoutingOptions | NextStaticParamsProps): value is NextStaticParamsProps {\n return 'params' in value\n}\n\n/**\n * Generate static params for blog post pages.\n *\n * Export it directly for the default `/blog/[slug]` routes:\n *\n * export const generateStaticParams = generateBlogStaticParams\n *\n * With routing options, wrap it:\n *\n * export function generateStaticParams() {\n * return generateBlogStaticParams(routing)\n * }\n */\nexport function generateBlogStaticParams(options?: BlogRoutingOptions): Promise<{ slug: string; category?: string }[]>\n// Next's props overload must stay LAST. Next 16 checks the export two ways:\n// `.next/types/validator.ts` needs it assignable to `(props: { params }) => …`,\n// and on webpack builds `NextTypesPlugin` infers the first argument (from the\n// last overload) and requires it to be `{ params }`. A single optional\n// `BlogRoutingOptions` parameter fails both (site-kit 5.4.0–5.6.1).\nexport function generateBlogStaticParams(props: NextStaticParamsProps): Promise<{ slug: string; category?: string }[]>\nexport async function generateBlogStaticParams(\n arg: BlogRoutingOptions | NextStaticParamsProps = {},\n): Promise<{ slug: string; category?: string }[]> {\n // Called by Next as `generateStaticParams({ params })`: use the defaults.\n const options: BlogRoutingOptions = isNextStaticParamsProps(arg) ? {} : arg\n const posts = await getBlogRouteEntries(options)\n return posts.map(post => {\n const category = blogCategorySlug(post.category || options.category)\n return { slug: post.slug, ...(options.includeCategoryInPath && category ? { category } : {}) }\n })\n}\n\n/**\n * Generate static params for category pages. Takes no arguments, so it can be\n * exported directly:\n *\n * export const generateStaticParams = generateCategoryStaticParams\n */\nexport async function generateCategoryStaticParams(): Promise<{ category: string }[]> {\n const categories = await getBlogCategories()\n return categories.map((c) => ({ category: c.slug }))\n}\n\n// ============================================================================\n// SITEMAP GENERATION\n// ============================================================================\n\ninterface SitemapEntry {\n url: string\n lastModified?: Date\n changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'\n priority?: number\n}\n\n/**\n * Generate sitemap entries for blog posts\n */\nexport interface BlogSitemapOptions extends BlogRoutingOptions {\n includeCategories?: boolean\n includeClusters?: boolean\n}\n\n/** Sitemaps need canonicals; nested/custom static params also need full route records. */\nasync function getBlogRouteEntries(options: BlogRoutingOptions, withCanonicals = false): Promise<Array<BlogRoutePost & { last_modified?: string; article_type?: string }>> {\n if (withCanonicals || options.includeCategoryInPath || options.postPath) {\n return (await getAllBlogPosts({ maxPosts: Infinity })).map(post => ({ ...post, last_modified: post.updated_at }))\n }\n return getAllBlogSlugs()\n}\n\nexport async function generateBlogSitemap(\n siteUrl: string,\n options: BlogSitemapOptions = {},\n): Promise<SitemapEntry[]> {\n const slugs = await getBlogRouteEntries(options, true)\n const categories = options.includeCategories === false ? [] : await getBlogCategories()\n const clusters = options.includeClusters === false ? [] : await getTopicClusters()\n\n const entries: SitemapEntry[] = [\n // Blog index\n {\n url: resolveBlogUrl(createBlogRoutes(options).index, siteUrl),\n changeFrequency: 'daily',\n priority: 0.8,\n },\n ]\n\n // Cluster landing pages\n clusters.forEach((cluster) => {\n entries.push({\n url: resolveBlogUrl(createBlogRoutes(options).cluster(cluster.cluster_slug), siteUrl),\n changeFrequency: 'weekly',\n priority: 0.8,\n })\n })\n\n // Category pages\n categories.forEach((cat) => {\n entries.push({\n url: resolveBlogUrl(createBlogRoutes(options).category(cat.slug), siteUrl),\n changeFrequency: 'weekly',\n priority: 0.6,\n })\n })\n\n // Individual posts — pillar posts get higher priority (0.9 vs 0.7)\n slugs.forEach((post) => {\n const isPillar = (post as any).article_type === 'pillar'\n entries.push({\n url: resolveBlogPostUrl(post, { ...options, siteUrl }),\n lastModified: post.last_modified ? new Date(post.last_modified) : undefined,\n changeFrequency: isPillar ? 'weekly' : 'monthly',\n priority: isPillar ? 0.9 : 0.7,\n })\n })\n\n return entries\n}\n\n// ============================================================================\n// JSON-LD SCHEMA GENERATION\n// ============================================================================\n\n/**\n * Generate JSON-LD schema for a blog post\n */\nexport function generateBlogPostSchema(\n post: BlogPostRecord,\n options: BlogRoutingOptions & { siteUrl?: string; siteName?: string; logoUrl?: string } = {}\n): object {\n const { siteUrl = '', siteName, logoUrl } = options\n\n const schema: any = {\n '@context': 'https://schema.org',\n '@type': 'BlogPosting',\n headline: post.title,\n description: sanitizeExcerpt(post.excerpt || post.meta_description),\n url: resolveBlogPostUrl(post, { ...options, siteUrl }),\n datePublished: post.published_at,\n dateModified: post.updated_at,\n author: {\n '@type': 'Person',\n name: typeof post.author === 'string' ? post.author : post.author?.name,\n },\n }\n\n const articleImage = resolveBlogArtwork(post, 'article').src\n if (articleImage) schema.image = articleImage\n\n if (siteName || logoUrl) {\n schema.publisher = {\n '@type': 'Organization',\n name: siteName,\n logo: logoUrl\n ? {\n '@type': 'ImageObject',\n url: logoUrl,\n }\n : undefined,\n }\n }\n\n // Add FAQ schema if present\n if (post.faq_items && Array.isArray(post.faq_items) && post.faq_items.length > 0) {\n schema.mainEntity = {\n '@type': 'FAQPage',\n mainEntity: post.faq_items.map((faq: { question: string; answer: string }) => ({\n '@type': 'Question',\n name: faq.question,\n acceptedAnswer: {\n '@type': 'Answer',\n text: faq.answer,\n },\n })),\n }\n }\n\n return schema\n}\n\n/**\n * Generate JSON-LD schema for blog index/listing page\n */\nexport function generateBlogListSchema(\n options: BlogRoutingOptions & { siteUrl?: string; siteName?: string; description?: string } = {}\n): object {\n const { siteUrl = '', siteName, description } = options\n\n return {\n '@context': 'https://schema.org',\n '@type': 'Blog',\n name: siteName ? `${siteName} Blog` : 'Blog',\n description: description || 'Our latest articles and insights.',\n url: resolveBlogUrl(createBlogRoutes(options).index, siteUrl),\n }\n}\n\n// ============================================================================\n// FAQ SCHEMA (for PAA rankings)\n// ============================================================================\n\n/**\n * Generate standalone FAQ schema (great for PAA inclusion)\n */\nexport function generateFaqSchema(\n faqItems: { question: string; answer: string }[]\n): object | null {\n if (!faqItems || faqItems.length === 0) return null\n\n return {\n '@context': 'https://schema.org',\n '@type': 'FAQPage',\n mainEntity: faqItems.map((faq) => ({\n '@type': 'Question',\n name: faq.question,\n acceptedAnswer: {\n '@type': 'Answer',\n text: faq.answer,\n },\n })),\n }\n}\n\n// ============================================================================\n// HOWTO SCHEMA (for step-by-step posts)\n// ============================================================================\n\nexport interface HowToStep {\n name: string\n text: string\n image?: string\n url?: string\n}\n\n/**\n * Generate HowTo schema for step-by-step posts\n */\nexport function generateHowToSchema(\n post: BlogPostRecord,\n steps: HowToStep[],\n options: BlogRoutingOptions & { siteUrl?: string } = {}\n): object {\n const { siteUrl = '' } = options\n\n return {\n '@context': 'https://schema.org',\n '@type': 'HowTo',\n name: post.title,\n description: sanitizeExcerpt(post.excerpt || post.meta_description),\n image: resolveBlogArtwork(post, 'article').src,\n totalTime: post.reading_time ? `PT${post.reading_time}M` : undefined,\n step: steps.map((step, index) => ({\n '@type': 'HowToStep',\n position: index + 1,\n name: step.name,\n text: step.text,\n image: step.image,\n url: step.url || `${resolveBlogPostUrl(post, { ...options, siteUrl }).split(\"#\")[0]}#step-${index + 1}`,\n })),\n }\n}\n\n// ============================================================================\n// RSS FEED GENERATION\n// ============================================================================\n\nexport interface RssFeedOptions extends BlogRoutingOptions {\n siteUrl: string\n siteName: string\n description?: string\n language?: string\n copyright?: string\n managingEditor?: string\n webMaster?: string\n ttl?: number // Time to live in minutes\n imageUrl?: string\n}\n\n/**\n * Maximum posts a feed will accumulate. Preserves the historical intent of the\n * old `?limit=100` request (which the API silently ignored — it only reads\n * `per_page`, capped at 50, so feeds were stuck at the 12-post default).\n */\nconst FEED_MAX_POSTS = 100\n\n/**\n * Fetch all published blog posts for RSS feed.\n *\n * Paginates with `per_page`/`page` — the only pagination params the deployed\n * controller reads — accumulating up to FEED_MAX_POSTS. A mid-loop failure\n * returns what was accumulated so far: a partial feed beats an empty one.\n */\nexport async function getAllBlogPosts(\n options: { maxPosts?: number; /** Sub-site host override (see getBlogPost). */ site?: string } = {}\n): Promise<BlogPostRecord[]> {\n const maxPosts = options.maxPosts ?? FEED_MAX_POSTS\n if (!(maxPosts > 0)) return []\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Blog] No API key configured')\n return []\n }\n const { apiUrl, apiKey } = config\n\n const posts: BlogPostRecord[] = []\n let page = 1\n try {\n while (posts.length < maxPosts) {\n const response = await fetch(\n withSiteParam(`${apiUrl}/public/blog/posts?per_page=50&page=${page}`, options.site),\n {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 300 },\n }\n )\n\n if (!response.ok) break\n\n const data = await response.json()\n const batch = data.posts || []\n posts.push(...batch)\n if (!batch.length || !data.pagination?.has_next) break\n page += 1\n }\n } catch (error) {\n console.error('[Blog] Error fetching posts for RSS:', error)\n }\n return posts.slice(0, maxPosts)\n}\n\n/**\n * Escape XML special characters\n */\nfunction escapeXml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\n/**\n * Strip HTML tags for RSS descriptions\n */\nfunction stripHtml(html: string): string {\n return html.replace(/<[^>]*>/g, '').trim()\n}\n\n/**\n * Generate RSS 2.0 feed XML\n */\nexport async function generateRssFeed(options: RssFeedOptions): Promise<string> {\n const {\n siteUrl,\n siteName,\n description = 'Latest blog posts and insights',\n language = 'en-us',\n copyright,\n managingEditor,\n webMaster,\n ttl = 60,\n imageUrl,\n } = options\n\n const posts = await getAllBlogPosts()\n const now = new Date().toUTCString()\n\n let rss = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n <channel>\n <title>${escapeXml(siteName)}</title>\n <link>${siteUrl}</link>\n <description>${escapeXml(description)}</description>\n <language>${language}</language>\n <lastBuildDate>${now}</lastBuildDate>\n <pubDate>${now}</pubDate>\n <ttl>${ttl}</ttl>\n <atom:link href=\"${escapeXml(resolveBlogUrl(createBlogRoutes(options).rss, siteUrl))}\" rel=\"self\" type=\"application/rss+xml\"/>\n`\n\n if (copyright) {\n rss += ` <copyright>${escapeXml(copyright)}</copyright>\\n`\n }\n\n if (managingEditor) {\n rss += ` <managingEditor>${escapeXml(managingEditor)}</managingEditor>\\n`\n }\n\n if (webMaster) {\n rss += ` <webMaster>${escapeXml(webMaster)}</webMaster>\\n`\n }\n\n if (imageUrl) {\n rss += ` <image>\n <url>${imageUrl}</url>\n <title>${escapeXml(siteName)}</title>\n <link>${siteUrl}</link>\n </image>\\n`\n }\n\n // Add each post as an item with FULL content (not excerpts)\n for (const post of posts) {\n const postUrl = resolveBlogPostUrl(post, { ...options, siteUrl })\n const pubDate = post.published_at ? new Date(post.published_at).toUTCString() : now\n const author = typeof post.author === 'string' ? post.author : post.author?.name || 'Unknown'\n \n // Use full content_html if available, otherwise content\n const fullContent = post.content_html || post.content || ''\n const description = sanitizeExcerpt(post.excerpt, 300) || stripHtml(fullContent).substring(0, 300) + '...'\n\n rss += ` <item>\n <title>${escapeXml(post.title)}</title>\n <link>${escapeXml(postUrl)}</link>\n <guid isPermaLink=\"true\">${escapeXml(postUrl)}</guid>\n <description>${escapeXml(description)}</description>\n <content:encoded><![CDATA[${fullContent}]]></content:encoded>\n <pubDate>${pubDate}</pubDate>\n <author>${escapeXml(author)}</author>\n`\n\n if (post.category) {\n const categoryName = typeof post.category === 'string' ? post.category : post.category.name\n rss += ` <category>${escapeXml(categoryName)}</category>\\n`\n }\n\n if (post.tags && Array.isArray(post.tags)) {\n for (const tag of post.tags) {\n const tagName = typeof tag === 'string' ? tag : tag.name\n rss += ` <category>${escapeXml(tagName)}</category>\\n`\n }\n }\n\n if (post.featured_image) {\n rss += ` <enclosure url=\"${post.featured_image}\" type=\"image/jpeg\"/>\\n`\n }\n\n rss += ` </item>\\n`\n }\n\n rss += ` </channel>\n</rss>`\n\n return rss\n}\n\n/**\n * Generate Atom feed XML\n */\nexport async function generateAtomFeed(options: RssFeedOptions): Promise<string> {\n const {\n siteUrl,\n siteName,\n description = 'Latest blog posts and insights',\n managingEditor,\n } = options\n\n const posts = await getAllBlogPosts()\n const now = new Date().toISOString()\n\n let atom = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\">\n <title>${escapeXml(siteName)}</title>\n <subtitle>${escapeXml(description)}</subtitle>\n <link href=\"${escapeXml(resolveBlogUrl(createBlogRoutes(options).atom, siteUrl))}\" rel=\"self\"/>\n <link href=\"${siteUrl}\"/>\n <id>${escapeXml(resolveBlogUrl(createBlogRoutes(options).index, siteUrl))}</id>\n <updated>${now}</updated>\n`\n\n if (managingEditor) {\n atom += ` <author>\n <name>${escapeXml(managingEditor)}</name>\n </author>\\n`\n }\n\n for (const post of posts) {\n const postUrl = resolveBlogPostUrl(post, { ...options, siteUrl })\n const updated = post.updated_at || post.published_at || now\n const published = post.published_at || now\n const author = typeof post.author === 'string' ? post.author : post.author?.name || 'Unknown'\n const fullContent = post.content_html || post.content || ''\n\n atom += ` <entry>\n <title>${escapeXml(post.title)}</title>\n <link href=\"${escapeXml(postUrl)}\"/>\n <id>${escapeXml(postUrl)}</id>\n <updated>${new Date(updated).toISOString()}</updated>\n <published>${new Date(published).toISOString()}</published>\n <author>\n <name>${escapeXml(author)}</name>\n </author>\n <summary>${escapeXml(sanitizeExcerpt(post.excerpt, 300) || stripHtml(fullContent).substring(0, 300))}</summary>\n <content type=\"html\"><![CDATA[${fullContent}]]></content>\n </entry>\\n`\n }\n\n atom += `</feed>`\n\n return atom\n}\n\n// ============================================================================\n// TOPIC CLUSTER SUPPORT\n// ============================================================================\n\n/**\n * Fetch all active topic clusters for the project.\n * Uses the real cluster data from Portal API (not heuristic-based).\n */\nexport async function getTopicClusters(options?: { site?: string }): Promise<TopicCluster[]> {\n const config = resolveServerApiConfig()\n if (!config) return []\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/blog/clusters`, options?.site), {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 300 },\n })\n if (!response.ok) return []\n const data = await response.json()\n\n return (data.clusters || []).map((c: any) => ({\n id: c.id,\n cluster_name: c.cluster_name,\n cluster_slug: c.cluster_slug,\n core_topic: c.core_topic,\n primary_entity: c.primary_entity,\n industry: c.industry,\n geo_target: c.geo_target,\n commercial_goal: c.commercial_goal,\n pillar_post_id: c.pillar_post_id,\n target_service_page: c.target_service_page,\n article_count: c.article_count,\n created_at: c.created_at,\n pillar: null,\n supports: [],\n interlink_map: [],\n }))\n } catch (error) {\n console.error('[Blog] Error fetching topic clusters:', error)\n return []\n }\n}\n\n/**\n * Fetch a single topic cluster with its pillar and support articles.\n */\nexport async function getTopicCluster(\n slug: string,\n options?: { site?: string }\n): Promise<TopicCluster | null> {\n const config = resolveServerApiConfig()\n if (!config) return null\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/blog/clusters/${slug}`, options?.site), {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 300 },\n })\n if (!response.ok) return null\n const data = await response.json()\n\n return {\n id: data.id,\n cluster_name: data.cluster_name,\n cluster_slug: data.cluster_slug,\n core_topic: data.core_topic,\n primary_entity: data.primary_entity,\n industry: data.industry,\n geo_target: data.geo_target,\n commercial_goal: data.commercial_goal,\n // Authoritative column once the API's detail response ships it;\n // derived from the embedded (published) pillar until then.\n pillar_post_id: data.pillar_post_id ?? data.pillar?.id,\n target_service_page: data.target_service_page,\n article_count: data.article_count,\n created_at: data.created_at,\n pillar: data.pillar || null,\n supports: data.supports || [],\n interlink_map: data.interlink_map || [],\n }\n } catch (error) {\n console.error('[Blog] Error fetching topic cluster:', error)\n return null\n }\n}\n\n/**\n * Get cluster navigation context for a blog post.\n * Returns the cluster name, pillar link, and sibling articles.\n */\nexport function getClusterNavigation(post: BlogPostRecord): ClusterNavigation | null {\n if (!post.cluster_id && !post.cluster_slug) return null\n\n const isPillar = post.article_type === 'pillar'\n\n // Mirrored copy: BlogPost.tsx has an identical builder. Keep the two in\n // sync — they CANNOT be consolidated because blog/index is a CLIENT_ENTRY\n // that must never import blog/server-core (see build-entries.ts and\n // client-entry-boundary.test.ts).\n return {\n cluster_name: post.cluster_name || '',\n cluster_slug: post.cluster_slug || '',\n pillar: isPillar\n ? null\n : post.parent_pillar_slug\n ? {\n slug: post.parent_pillar_slug,\n title: post.parent_pillar_title || '',\n category: post.parent_pillar_category || undefined,\n }\n : null,\n siblings: post.sibling_articles || [],\n is_pillar: isPillar,\n }\n}\n\n/**\n * @deprecated Use getTopicCluster(slug) instead. This naive heuristic picks\n * the longest post as pillar. Real cluster data is now managed in the Sonor dashboard.\n */\nexport async function identifyTopicClusters(categorySlug: string): Promise<{\n pillar: BlogPostRecord\n supportingPosts: BlogPostRecord[]\n internalLinks: Array<{ from: string; to: string; anchor: string }>\n} | null> {\n console.warn(\n '[Blog] identifyTopicClusters() is deprecated. Use getTopicCluster(slug) for real cluster data managed in the Sonor dashboard.'\n )\n const posts = await getPostsByCategory(categorySlug)\n if (posts.length < 3) return null\n\n const sortedByLength = [...posts].sort((a, b) => (b.word_count || 0) - (a.word_count || 0))\n const pillar = sortedByLength[0]\n const supportingPosts = sortedByLength.slice(1)\n\n const internalLinks: Array<{ from: string; to: string; anchor: string }> = []\n for (const support of supportingPosts) {\n internalLinks.push({ from: pillar.slug, to: support.slug, anchor: support.title })\n internalLinks.push({ from: support.slug, to: pillar.slug, anchor: pillar.title })\n }\n\n return { pillar, supportingPosts, internalLinks }\n}\n\n/**\n * Fetch posts by category for topic cluster organization\n */\nexport async function getPostsByCategory(\n categorySlug: string,\n options?: { site?: string }\n): Promise<BlogPostRecord[]> {\n const config = resolveServerApiConfig()\n if (!config) return []\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/blog/posts?category=${encodeURIComponent(categorySlug)}&per_page=50`, options?.site), {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 300 },\n })\n if (!response.ok) return []\n const data = await response.json()\n return data.posts || []\n } catch (error) {\n console.error('[Blog] Error fetching category posts:', error)\n return []\n }\n}\n\n// ============================================================================\n// CLUSTER SCHEMA GENERATION\n// ============================================================================\n\n/**\n * Generate ItemList schema for a cluster's pillar page.\n * Wraps supporting posts as a structured list Google can parse.\n */\nexport function generateClusterItemListSchema(\n cluster: TopicCluster,\n options: BlogRoutingOptions & { siteUrl?: string } = {}\n): object {\n const { siteUrl = '' } = options\n\n return {\n '@context': 'https://schema.org',\n '@type': 'ItemList',\n name: cluster.cluster_name,\n description: `Articles about ${cluster.core_topic}`,\n numberOfItems: cluster.supports.length,\n itemListElement: cluster.supports.map((post, i) => ({\n '@type': 'ListItem',\n position: i + 1,\n name: post.title,\n url: resolveBlogPostUrl(post, { ...options, siteUrl }),\n })),\n }\n}\n\n/**\n * Generate Article schema with cluster relationship (isPartOf / hasPart).\n * - Support articles get `isPartOf` pointing to the pillar.\n * - Pillar articles get `hasPart` listing all supports.\n */\nexport function generateClusterArticleSchema(\n post: BlogPostRecord,\n cluster: TopicCluster,\n options: BlogRoutingOptions & { siteUrl?: string; siteName?: string; logoUrl?: string } = {}\n): object {\n const { siteUrl = '', siteName, logoUrl } = options\n const isPillar = post.article_type === 'pillar'\n\n const schema: any = {\n '@context': 'https://schema.org',\n '@type': 'Article',\n headline: post.title,\n description: sanitizeExcerpt(post.excerpt || post.meta_description),\n url: resolveBlogPostUrl(post, { ...options, siteUrl }),\n datePublished: post.published_at,\n dateModified: post.updated_at,\n author: {\n '@type': 'Person',\n name: typeof post.author === 'string' ? post.author : (post.author as any)?.name,\n },\n keywords: post.focus_keyphrase || post.keywords,\n }\n\n const articleImage = resolveBlogArtwork(post, 'article').src\n if (articleImage) schema.image = articleImage\n\n if (siteName || logoUrl) {\n schema.publisher = {\n '@type': 'Organization',\n name: siteName,\n ...(logoUrl && { logo: { '@type': 'ImageObject', url: logoUrl } }),\n }\n }\n\n // Cluster relationships\n if (isPillar && cluster.supports.length > 0) {\n schema.hasPart = cluster.supports.map((s) => ({\n '@type': 'Article',\n headline: s.title,\n url: resolveBlogPostUrl(s, { ...options, siteUrl }),\n }))\n } else if (!isPillar && cluster.pillar) {\n schema.isPartOf = {\n '@type': 'Article',\n headline: cluster.pillar.title,\n url: resolveBlogPostUrl(cluster.pillar, { ...options, siteUrl }),\n }\n }\n\n // Geo targeting\n if (cluster.geo_target) {\n schema.spatialCoverage = {\n '@type': 'Place',\n name: cluster.geo_target,\n }\n }\n\n return schema\n}\n\n/**\n * Generate BreadcrumbList schema for a cluster-linked post.\n * Path: Home > Blog > Cluster > Article\n */\nexport function generateClusterBreadcrumbSchema(\n post: BlogPostRecord,\n cluster: TopicCluster,\n options: BlogRoutingOptions & { siteUrl?: string; siteName?: string } = {}\n): object {\n const { siteUrl = '', siteName = 'Home' } = options\n\n const items: any[] = [\n { '@type': 'ListItem', position: 1, name: siteName, item: siteUrl },\n { '@type': 'ListItem', position: 2, name: 'Blog', item: resolveBlogUrl(createBlogRoutes(options).index, siteUrl) },\n {\n '@type': 'ListItem',\n position: 3,\n name: cluster.cluster_name,\n item: resolveBlogUrl(createBlogRoutes(options).cluster(cluster.cluster_slug), siteUrl),\n },\n {\n '@type': 'ListItem',\n position: 4,\n name: post.title,\n item: resolveBlogPostUrl(post, { ...options, siteUrl }),\n },\n ]\n\n return {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: items,\n }\n}\n\n/**\n * Generate CollectionPage schema for a cluster landing page.\n */\nexport function generateClusterLandingSchema(\n cluster: TopicCluster,\n options: BlogRoutingOptions & { siteUrl?: string; siteName?: string } = {}\n): object {\n const { siteUrl = '', siteName } = options\n\n return {\n '@context': 'https://schema.org',\n '@type': 'CollectionPage',\n name: cluster.cluster_name,\n description: `Comprehensive guide to ${cluster.core_topic}`,\n url: resolveBlogUrl(createBlogRoutes(options).cluster(cluster.cluster_slug), siteUrl),\n ...(siteName && {\n isPartOf: { '@type': 'WebSite', name: siteName, url: siteUrl },\n }),\n mainEntity: cluster.pillar\n ? {\n '@type': 'Article',\n headline: cluster.pillar.title,\n url: resolveBlogPostUrl(cluster.pillar, { ...options, siteUrl }),\n }\n : undefined,\n hasPart: cluster.supports.map((s) => ({\n '@type': 'Article',\n headline: s.title,\n url: resolveBlogPostUrl(s, { ...options, siteUrl }),\n })),\n }\n}\n\n/**\n * Generate metadata for a cluster landing page (Next.js generateMetadata).\n */\nexport async function generateClusterPageMetadata(\n clusterSlug: string,\n options: BlogRoutingOptions & { siteName?: string; siteUrl?: string } = {}\n) {\n const cluster = await getTopicCluster(clusterSlug)\n if (!cluster) return {}\n\n const { siteName = '', siteUrl = '' } = options\n const title = `${cluster.cluster_name}${siteName ? ` | ${siteName}` : ''}`\n const description = `Comprehensive guide to ${cluster.core_topic}. ${cluster.article_count} articles covering everything you need to know.`\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n url: resolveBlogUrl(createBlogRoutes(options).cluster(cluster.cluster_slug), siteUrl),\n type: 'website',\n },\n }\n}\n\n/**\n * Generate \"Related Insights\" section data\n */\nexport async function getRelatedInsights(\n currentSlug: string,\n options: { limit?: number; category?: string; /** Sub-site host override (see getBlogPost). */ site?: string } = {}\n): Promise<BlogPostRecord[]> {\n const config = resolveServerApiConfig()\n if (!config) return []\n const { limit = 3, site } = options\n // options.category is accepted for compatibility, but the endpoint derives\n // relatedness from the current post's own category server-side; a category\n // field in the body has always been ignored.\n\n // The endpoint takes `current_post_id` and looks the post up by id — it has\n // no slug path. Sending `slug` meant the lookup matched nothing and this\n // returned [] on every call since it shipped. Resolve the slug first (60s\n // cache via getBlogPost), then ask with the id.\n const current = await getBlogPost(currentSlug, { site })\n if (!current?.id) return []\n\n return fetchRelatedBlogPosts({ ...config, site }, current.id, limit, { revalidate: 300 })\n}\n\n// ============================================================================\n// BREADCRUMB SCHEMA\n// ============================================================================\n\n/**\n * Generate BreadcrumbList schema for blog navigation\n */\nexport function generateBreadcrumbSchema(\n post: BlogPostRecord,\n options: BlogRoutingOptions & { siteUrl?: string; siteName?: string } = {}\n): object {\n const { siteUrl = '', siteName = 'Home' } = options\n\n const items = [\n {\n '@type': 'ListItem',\n position: 1,\n name: siteName,\n item: siteUrl,\n },\n {\n '@type': 'ListItem',\n position: 2,\n name: 'Blog',\n item: resolveBlogUrl(createBlogRoutes(options).index, siteUrl),\n },\n ]\n\n if (post.category) {\n const categoryName = typeof post.category === 'string' ? post.category : post.category.name\n const categorySlug = typeof post.category === 'string' \n ? post.category.toLowerCase().replace(/\\s+/g, '-')\n : post.category.slug\n\n items.push({\n '@type': 'ListItem',\n position: 3,\n name: categoryName,\n item: resolveBlogUrl(createBlogRoutes(options).category(categorySlug), siteUrl),\n })\n\n items.push({\n '@type': 'ListItem',\n position: 4,\n name: post.title,\n item: resolveBlogPostUrl(post, { ...options, siteUrl }),\n })\n } else {\n items.push({\n '@type': 'ListItem',\n position: 3,\n name: post.title,\n item: resolveBlogPostUrl(post, { ...options, siteUrl }),\n })\n }\n\n return {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: items,\n }\n}\n\n// ============================================================================\n// COMBINED SCHEMA (Article + FAQ + Breadcrumb)\n// ============================================================================\n\n/**\n * Generate all relevant schemas for a blog post in a single array\n * This is the recommended way to include multiple schemas.\n * When post has E-E-A-T schema (post.schema), use it instead of generating Article/FAQ.\n */\nexport function generateAllBlogSchemas(\n post: BlogPostRecord,\n options: BlogRoutingOptions & { siteUrl?: string; siteName?: string; logoUrl?: string } = {}\n): object[] {\n const schemas: object[] = []\n\n // E-E-A-T: use pre-built schema from Signal when present. Single source of\n // truth for E-E-A-T schema resolution: the DB column is schema_json, which\n // the public API passes through raw today; `schema` is the mapped name the\n // dashboard serializer (and a future public mapping) uses. Do NOT also\n // normalize in getBlogPost — that would re-fork this rule.\n const eeatSchema = post.schema ?? post.schema_json\n if (eeatSchema) {\n const arr = Array.isArray(eeatSchema) ? eeatSchema : [eeatSchema]\n schemas.push(...arr)\n } else {\n // 1. Article/BlogPosting schema (always)\n schemas.push(generateBlogPostSchema(post, options))\n\n // 3. FAQ schema (if FAQs present)\n const faqItems = post.faq_items ?? (post as any).faqItems\n if (faqItems && faqItems.length > 0) {\n const faqSchema = generateFaqSchema(faqItems)\n if (faqSchema) schemas.push(faqSchema)\n }\n }\n\n // 2. Breadcrumb schema (always)\n schemas.push(generateBreadcrumbSchema(post, options))\n\n return schemas\n}\n\n// ============================================================================\n// AUTHOR PAGE DATA FETCHING\n// ============================================================================\n\n/**\n * Fetch a single author by slug\n */\nexport async function getAuthorBySlug(\n slug: string,\n options?: { site?: string }\n): Promise<BlogAuthor | null> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Blog] No API key configured')\n return null\n }\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/blog/authors/${slug}`, options?.site), {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 60 },\n })\n\n if (!response.ok) return null\n\n const data = await response.json()\n return data.author || null\n } catch (error) {\n console.error('[Blog] Error fetching author:', error)\n return null\n }\n}\n\n/**\n * Fetch an author's posts by slug.\n *\n * `offset` pages through the controller's existing offset support. Older API\n * versions return a stripped `{name, slug}` author on this endpoint; when\n * that shape is detected the full author row is hydrated via getAuthorBySlug\n * (both fetches revalidate:60, so the extra hop is cached and disappears once\n * the API returns the full row itself).\n */\nexport async function getAuthorPosts(\n slug: string,\n limit = 20,\n offset = 0,\n options?: { site?: string }\n): Promise<{ author: BlogAuthor | null; posts: BlogPostRecord[]; total: number }> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Blog] No API key configured')\n return { author: null, posts: [], total: 0 }\n }\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(\n withSiteParam(`${apiUrl}/public/blog/authors/${slug}/posts?limit=${limit}&offset=${offset}`, options?.site),\n {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 60 },\n }\n )\n\n if (!response.ok) return { author: null, posts: [], total: 0 }\n\n const data = await response.json()\n let author: BlogAuthor | null = data.author || null\n if (author && author.id === undefined) {\n try {\n const full = await getAuthorBySlug(slug, options)\n if (full) author = full\n } catch {\n // keep the stripped {name, slug} object\n }\n }\n return {\n author,\n posts: data.posts || [],\n total: data.total || 0,\n }\n } catch (error) {\n console.error('[Blog] Error fetching author posts:', error)\n return { author: null, posts: [], total: 0 }\n }\n}\n\n/**\n * Fetch all author slugs for static generation\n */\nexport async function getAllAuthorSlugs(): Promise<{ slug: string }[]> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Blog] No API key configured')\n return []\n }\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/blog/authors`), {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 300 },\n })\n\n if (!response.ok) return []\n\n const data = await response.json()\n const authors: BlogAuthor[] = data.authors || []\n return authors.map((a) => ({ slug: a.slug }))\n } catch (error) {\n console.error('[Blog] Error fetching author slugs:', error)\n return []\n }\n}\n\n/**\n * Generate static params for author pages. Takes no arguments, so it can be\n * exported directly:\n *\n * export const generateStaticParams = generateAuthorStaticParams\n */\nexport async function generateAuthorStaticParams(): Promise<{ slug: string }[]> {\n return getAllAuthorSlugs()\n}\n\n// ============================================================================\n// AUTHOR METADATA & SCHEMA\n// ============================================================================\n\n/**\n * Generate Next.js Metadata for an author page\n */\nexport function generateAuthorPageMetadata(\n author: BlogAuthor,\n options: BlogRoutingOptions & { siteUrl?: string; siteName?: string } = {}\n): Metadata {\n const { siteUrl = '', siteName } = options\n const title = `${author.name}${author.title ? ` - ${author.title}` : ''}`\n const description = author.short_bio || author.bio || `Articles by ${author.name}`\n const url = resolveBlogUrl(createBlogRoutes(options).author(author.slug), siteUrl)\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n url,\n siteName,\n type: 'profile',\n ...(author.avatar_url && { images: [{ url: author.avatar_url }] }),\n },\n twitter: {\n card: 'summary',\n title,\n description,\n ...(author.avatar_url && { images: [author.avatar_url] }),\n },\n alternates: {\n canonical: author.author_page_url || url,\n },\n }\n}\n\n/**\n * Person JSON-LD for an author page.\n *\n * The implementation lives in `./author-schema` because it is pure, and\n * `AuthorPage` — which is exported from the client-stamped `blog` barrel —\n * needs it. Importing it from here instead would drag this entire server module\n * into the browser bundle. Re-exported so `@sonordev/site-kit/blog/server`\n * keeps its existing public API.\n */\nexport { generateAuthorSchema } from './author-schema'\n\n// -----------------------------------------------------------------------------\n// Blog UI (BlogPost, BlogList) lives in `@sonordev/site-kit/blog/server-ui`.\n// This entry must stay free of React components so Next never marks server\n// helpers (e.g. getAllBlogSlugs) as client — see tsup onSuccess \"use client\".\n// -----------------------------------------------------------------------------\n\n/** Portal blog post document shape (alias of `BlogPost` from `./types`) */\nexport type { BlogPost as BlogPostRecord } from './types'\n\nexport { blogCategorySlug, createBlogRoutes, resolveBlogPostUrl, resolveBlogUrl } from './routes'\nexport type { BlogRoutePost, BlogRoutingOptions } from './routes'\nexport { resolveBlogArtwork } from './artwork'\nexport { wrapBlogTables, blogTableCss } from './blog-tables'\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkNG2TTI7D_js = require('./chunk-NG2TTI7D.js');
|
|
4
4
|
|
|
5
5
|
// src/shared/siteToken.ts
|
|
6
6
|
var SITE_TOKEN_PREFIX = "st1.";
|
|
@@ -99,7 +99,7 @@ async function doRefresh() {
|
|
|
99
99
|
method: "POST",
|
|
100
100
|
headers: {
|
|
101
101
|
"content-type": "application/json",
|
|
102
|
-
"x-sitekit-version":
|
|
102
|
+
"x-sitekit-version": chunkNG2TTI7D_js.SITE_KIT_VERSION,
|
|
103
103
|
// Send the current token as x-api-key too, so the server's key-scoped
|
|
104
104
|
// throttler buckets refreshes by token rather than by shared CDN IP.
|
|
105
105
|
"x-api-key": current
|
|
@@ -154,5 +154,5 @@ exports.getFreshCredential = getFreshCredential;
|
|
|
154
154
|
exports.isSiteToken = isSiteToken;
|
|
155
155
|
exports.isTokenMode = isTokenMode;
|
|
156
156
|
exports.refreshSiteToken = refreshSiteToken;
|
|
157
|
-
//# sourceMappingURL=chunk-
|
|
158
|
-
//# sourceMappingURL=chunk-
|
|
157
|
+
//# sourceMappingURL=chunk-LOEP76MQ.js.map
|
|
158
|
+
//# sourceMappingURL=chunk-LOEP76MQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/siteToken.ts"],"names":["SITE_KIT_VERSION"],"mappings":"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","file":"chunk-4WBTM6YE.js","sourcesContent":["/**\n * @sonordev/site-kit shared — Client token manager\n *\n * SiteKitLayout (a server component) no longer ships the raw `sonor_` API key to\n * the browser. Instead it mints a short-lived, project-scoped token server-side\n * and injects THAT. This module is the browser-side lifecycle for that token:\n *\n * - holds the current token (seeded from the injected value)\n * - a static page's seed can be days old and already expired on first view, so\n * it transparently REFRESHES via the public endpoint before first use\n * - dedupes concurrent refreshes (one in-flight request, awaited by all)\n * - persists the freshest token in sessionStorage so navigations within a\n * session don't each re-refresh\n *\n * Everything here is a no-op passthrough when the injected credential is a raw\n * key (a 2.x kit, or the mint-failed fallback) — legacy behavior is unchanged.\n * Fully SSR-safe: on the server there is no refresh, just the seed.\n *\n * The token payload is NOT secret (only its HMAC is unforgeable), so decoding it\n * client-side to read `exp`/`pid` is fine and needs no crypto.\n */\nimport { SITE_KIT_VERSION } from './version'\n\nexport const SITE_TOKEN_PREFIX = 'st1.'\n\n/** Refresh this many ms before expiry, so a request never races the deadline. */\nconst REFRESH_SKEW_MS = 5 * 60_000\nconst REFRESH_TIMEOUT_MS = 6_000\nconst STORAGE_KEY = '__sonor_site_token__'\n\nexport function isSiteToken(credential?: string | null): boolean {\n return typeof credential === 'string' && credential.startsWith(SITE_TOKEN_PREFIX)\n}\n\ninterface DecodedClaims {\n pid?: string\n iat?: number\n exp?: number\n}\n\n/** Decode the (non-secret) token payload. Returns null if not a token / malformed. */\nexport function decodeSiteTokenClaims(token?: string | null): DecodedClaims | null {\n if (!isSiteToken(token)) return null\n const seg = (token as string).split('.')[1]\n if (!seg) return null\n try {\n // base64url → JSON. atob handles standard base64; restore url-safe chars.\n const b64 = seg.replace(/-/g, '+').replace(/_/g, '/')\n const json =\n typeof atob === 'function'\n ? atob(b64)\n : Buffer.from(seg, 'base64url').toString('utf8')\n const claims = JSON.parse(json)\n return typeof claims === 'object' && claims ? claims : null\n } catch {\n return null\n }\n}\n\n/**\n * Stable id for the auth circuit breaker. Tokens rotate, so keying the breaker\n * by the raw value would reset it every refresh — key by the project id encoded\n * in the token instead. Raw keys use a safe prefix.\n */\nexport function credentialBreakerId(credential?: string | null): string {\n if (!credential) return '(anonymous)'\n const claims = decodeSiteTokenClaims(credential)\n if (claims?.pid) return `pid:${claims.pid}`\n return credential.slice(0, 16)\n}\n\ninterface TokenState {\n /** The credential injected by the layout (token or raw key). */\n seed: string | undefined\n /** Whether we're in token mode (seed is a token). */\n isToken: boolean\n /** Base API URL for the refresh endpoint. */\n apiUrl: string\n /** The freshest known token (>= seed). Null in raw-key mode. */\n token: string | null\n /** In-flight refresh, deduped. */\n refreshing: Promise<string | null> | null\n}\n\nfunction initialTokenState(): TokenState {\n return {\n seed: undefined,\n isToken: false,\n apiUrl: 'https://api.sonor.io',\n token: null,\n refreshing: null,\n }\n}\n\n/**\n * Page-wide singleton, keyed on window. Bundlers can (and in the field, do)\n * inline more than one copy of this module into a page — e.g. an app importing\n * site-kit directly while a transpiled component library bundles its own copy.\n * Module-scoped state then splits into per-copy brains: one copy gets\n * configured and refreshes fine while the other keeps sending the stale\n * prerendered seed, 401s, and trips its breaker (\"sonor-auth-paused\" with a\n * working network). Sharing the state object on window gives every copy the\n * same token, the same deduped refresh, and the same breaker. On the server\n * (no window) each module instance keeps private state — there's no refresh\n * lifecycle there anyway.\n */\nconst TOKEN_STATE_KEY = '__SONOR_SITE_TOKEN_STATE__'\n\nconst state: TokenState = (() => {\n if (typeof window === 'undefined') return initialTokenState()\n const w = window as unknown as Record<string, TokenState | undefined>\n return (w[TOKEN_STATE_KEY] ??= initialTokenState())\n})()\n\nfunction readStoredToken(): string | null {\n if (typeof window === 'undefined') return null\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY)\n if (!raw) return null\n const parsed = JSON.parse(raw)\n return typeof parsed?.token === 'string' ? parsed.token : null\n } catch {\n return null\n }\n}\n\nfunction storeToken(token: string): void {\n if (typeof window === 'undefined') return\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ token }))\n } catch {\n /* private mode / disabled storage — memory-only is fine */\n }\n try {\n ;(window as any).__SITE_KIT_API_KEY__ = token\n } catch {\n /* ignore */\n }\n}\n\nfunction tokenExp(token: string | null): number {\n const claims = decodeSiteTokenClaims(token)\n return typeof claims?.exp === 'number' ? claims.exp * 1000 : 0\n}\n\n/**\n * Configure the manager from the layout-injected values. Adopts a fresher token\n * from sessionStorage if a prior page in this session already refreshed.\n */\nexport function configureSiteCredential(opts: {\n credential?: string\n apiUrl?: string\n}): void {\n state.seed = opts.credential\n state.isToken = isSiteToken(opts.credential)\n if (opts.apiUrl) state.apiUrl = opts.apiUrl.replace(/\\/+$/, '')\n\n if (!state.isToken) {\n state.token = null\n return\n }\n\n // configure runs on every render — never downgrade. Keep the freshest of the\n // injected seed, a token stored by an earlier page this session, and whatever\n // an in-flight/prior refresh already put in memory.\n const prior = state.token\n let best = opts.credential ?? null\n const stored = readStoredToken()\n if (stored && tokenExp(stored) > tokenExp(best)) best = stored\n if (prior && tokenExp(prior) > tokenExp(best)) best = prior\n state.token = best\n}\n\nfunction needsRefresh(): boolean {\n if (!state.isToken) return false\n if (!state.token) return true\n return Date.now() >= tokenExp(state.token) - REFRESH_SKEW_MS\n}\n\nasync function doRefresh(): Promise<string | null> {\n const current = state.token\n if (!current) return null\n try {\n const res = await fetch(`${state.apiUrl}/api/public/site-token/refresh`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-sitekit-version': SITE_KIT_VERSION,\n // Send the current token as x-api-key too, so the server's key-scoped\n // throttler buckets refreshes by token rather than by shared CDN IP.\n 'x-api-key': current,\n },\n body: JSON.stringify({ token: current }),\n signal:\n typeof AbortSignal !== 'undefined' && AbortSignal.timeout\n ? AbortSignal.timeout(REFRESH_TIMEOUT_MS)\n : undefined,\n })\n if (!res.ok) return null\n const data = await res.json().catch(() => null)\n const next = data?.token\n if (typeof next === 'string' && isSiteToken(next)) {\n state.token = next\n storeToken(next)\n return next\n }\n return null\n } catch {\n return null\n }\n}\n\n/** Refresh now (deduped). Returns the new token, or null on failure. */\nexport function refreshSiteToken(): Promise<string | null> {\n if (!state.isToken) return Promise.resolve(null)\n if (state.refreshing) return state.refreshing\n state.refreshing = doRefresh().finally(() => {\n state.refreshing = null\n })\n return state.refreshing\n}\n\n/**\n * The credential to put on the next request. In token mode, refreshes a stale\n * seed first. In raw-key mode, returns the seed unchanged (legacy passthrough).\n */\nexport async function getFreshCredential(\n seed?: string,\n): Promise<string | undefined> {\n // Unconfigured but handed a token (a component received the prerendered seed\n // as a prop before any provider configured the manager): adopt it so the\n // refresh machinery works instead of replaying a possibly-expired seed.\n if (!state.isToken && isSiteToken(seed)) {\n configureSiteCredential({ credential: seed })\n }\n // A raw key (or nothing configured) — no token machinery.\n if (!state.isToken) return seed ?? state.seed\n if (needsRefresh()) {\n const refreshed = await refreshSiteToken()\n if (refreshed) return refreshed\n // Refresh failed — fall through to whatever we have; the request may 401 and\n // trip the breaker with friendly copy.\n }\n return state.token ?? seed ?? state.seed\n}\n\n/** Whether the given credential is being managed as a token. */\nexport function isTokenMode(): boolean {\n return state.isToken\n}\n\n/**\n * Best-known credential WITHOUT refreshing — for synchronous unload paths\n * (sonorBeacon) that can't await. In token mode returns the freshest token held;\n * in raw-key mode returns the seed.\n */\nexport function currentCredential(seed?: string): string | undefined {\n if (!state.isToken) return seed ?? state.seed\n return state.token ?? seed ?? state.seed\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/shared/siteToken.ts"],"names":["SITE_KIT_VERSION"],"mappings":"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","file":"chunk-LOEP76MQ.js","sourcesContent":["/**\n * @sonordev/site-kit shared — Client token manager\n *\n * SiteKitLayout (a server component) no longer ships the raw `sonor_` API key to\n * the browser. Instead it mints a short-lived, project-scoped token server-side\n * and injects THAT. This module is the browser-side lifecycle for that token:\n *\n * - holds the current token (seeded from the injected value)\n * - a static page's seed can be days old and already expired on first view, so\n * it transparently REFRESHES via the public endpoint before first use\n * - dedupes concurrent refreshes (one in-flight request, awaited by all)\n * - persists the freshest token in sessionStorage so navigations within a\n * session don't each re-refresh\n *\n * Everything here is a no-op passthrough when the injected credential is a raw\n * key (a 2.x kit, or the mint-failed fallback) — legacy behavior is unchanged.\n * Fully SSR-safe: on the server there is no refresh, just the seed.\n *\n * The token payload is NOT secret (only its HMAC is unforgeable), so decoding it\n * client-side to read `exp`/`pid` is fine and needs no crypto.\n */\nimport { SITE_KIT_VERSION } from './version'\n\nexport const SITE_TOKEN_PREFIX = 'st1.'\n\n/** Refresh this many ms before expiry, so a request never races the deadline. */\nconst REFRESH_SKEW_MS = 5 * 60_000\nconst REFRESH_TIMEOUT_MS = 6_000\nconst STORAGE_KEY = '__sonor_site_token__'\n\nexport function isSiteToken(credential?: string | null): boolean {\n return typeof credential === 'string' && credential.startsWith(SITE_TOKEN_PREFIX)\n}\n\ninterface DecodedClaims {\n pid?: string\n iat?: number\n exp?: number\n}\n\n/** Decode the (non-secret) token payload. Returns null if not a token / malformed. */\nexport function decodeSiteTokenClaims(token?: string | null): DecodedClaims | null {\n if (!isSiteToken(token)) return null\n const seg = (token as string).split('.')[1]\n if (!seg) return null\n try {\n // base64url → JSON. atob handles standard base64; restore url-safe chars.\n const b64 = seg.replace(/-/g, '+').replace(/_/g, '/')\n const json =\n typeof atob === 'function'\n ? atob(b64)\n : Buffer.from(seg, 'base64url').toString('utf8')\n const claims = JSON.parse(json)\n return typeof claims === 'object' && claims ? claims : null\n } catch {\n return null\n }\n}\n\n/**\n * Stable id for the auth circuit breaker. Tokens rotate, so keying the breaker\n * by the raw value would reset it every refresh — key by the project id encoded\n * in the token instead. Raw keys use a safe prefix.\n */\nexport function credentialBreakerId(credential?: string | null): string {\n if (!credential) return '(anonymous)'\n const claims = decodeSiteTokenClaims(credential)\n if (claims?.pid) return `pid:${claims.pid}`\n return credential.slice(0, 16)\n}\n\ninterface TokenState {\n /** The credential injected by the layout (token or raw key). */\n seed: string | undefined\n /** Whether we're in token mode (seed is a token). */\n isToken: boolean\n /** Base API URL for the refresh endpoint. */\n apiUrl: string\n /** The freshest known token (>= seed). Null in raw-key mode. */\n token: string | null\n /** In-flight refresh, deduped. */\n refreshing: Promise<string | null> | null\n}\n\nfunction initialTokenState(): TokenState {\n return {\n seed: undefined,\n isToken: false,\n apiUrl: 'https://api.sonor.io',\n token: null,\n refreshing: null,\n }\n}\n\n/**\n * Page-wide singleton, keyed on window. Bundlers can (and in the field, do)\n * inline more than one copy of this module into a page — e.g. an app importing\n * site-kit directly while a transpiled component library bundles its own copy.\n * Module-scoped state then splits into per-copy brains: one copy gets\n * configured and refreshes fine while the other keeps sending the stale\n * prerendered seed, 401s, and trips its breaker (\"sonor-auth-paused\" with a\n * working network). Sharing the state object on window gives every copy the\n * same token, the same deduped refresh, and the same breaker. On the server\n * (no window) each module instance keeps private state — there's no refresh\n * lifecycle there anyway.\n */\nconst TOKEN_STATE_KEY = '__SONOR_SITE_TOKEN_STATE__'\n\nconst state: TokenState = (() => {\n if (typeof window === 'undefined') return initialTokenState()\n const w = window as unknown as Record<string, TokenState | undefined>\n return (w[TOKEN_STATE_KEY] ??= initialTokenState())\n})()\n\nfunction readStoredToken(): string | null {\n if (typeof window === 'undefined') return null\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY)\n if (!raw) return null\n const parsed = JSON.parse(raw)\n return typeof parsed?.token === 'string' ? parsed.token : null\n } catch {\n return null\n }\n}\n\nfunction storeToken(token: string): void {\n if (typeof window === 'undefined') return\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ token }))\n } catch {\n /* private mode / disabled storage — memory-only is fine */\n }\n try {\n ;(window as any).__SITE_KIT_API_KEY__ = token\n } catch {\n /* ignore */\n }\n}\n\nfunction tokenExp(token: string | null): number {\n const claims = decodeSiteTokenClaims(token)\n return typeof claims?.exp === 'number' ? claims.exp * 1000 : 0\n}\n\n/**\n * Configure the manager from the layout-injected values. Adopts a fresher token\n * from sessionStorage if a prior page in this session already refreshed.\n */\nexport function configureSiteCredential(opts: {\n credential?: string\n apiUrl?: string\n}): void {\n state.seed = opts.credential\n state.isToken = isSiteToken(opts.credential)\n if (opts.apiUrl) state.apiUrl = opts.apiUrl.replace(/\\/+$/, '')\n\n if (!state.isToken) {\n state.token = null\n return\n }\n\n // configure runs on every render — never downgrade. Keep the freshest of the\n // injected seed, a token stored by an earlier page this session, and whatever\n // an in-flight/prior refresh already put in memory.\n const prior = state.token\n let best = opts.credential ?? null\n const stored = readStoredToken()\n if (stored && tokenExp(stored) > tokenExp(best)) best = stored\n if (prior && tokenExp(prior) > tokenExp(best)) best = prior\n state.token = best\n}\n\nfunction needsRefresh(): boolean {\n if (!state.isToken) return false\n if (!state.token) return true\n return Date.now() >= tokenExp(state.token) - REFRESH_SKEW_MS\n}\n\nasync function doRefresh(): Promise<string | null> {\n const current = state.token\n if (!current) return null\n try {\n const res = await fetch(`${state.apiUrl}/api/public/site-token/refresh`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-sitekit-version': SITE_KIT_VERSION,\n // Send the current token as x-api-key too, so the server's key-scoped\n // throttler buckets refreshes by token rather than by shared CDN IP.\n 'x-api-key': current,\n },\n body: JSON.stringify({ token: current }),\n signal:\n typeof AbortSignal !== 'undefined' && AbortSignal.timeout\n ? AbortSignal.timeout(REFRESH_TIMEOUT_MS)\n : undefined,\n })\n if (!res.ok) return null\n const data = await res.json().catch(() => null)\n const next = data?.token\n if (typeof next === 'string' && isSiteToken(next)) {\n state.token = next\n storeToken(next)\n return next\n }\n return null\n } catch {\n return null\n }\n}\n\n/** Refresh now (deduped). Returns the new token, or null on failure. */\nexport function refreshSiteToken(): Promise<string | null> {\n if (!state.isToken) return Promise.resolve(null)\n if (state.refreshing) return state.refreshing\n state.refreshing = doRefresh().finally(() => {\n state.refreshing = null\n })\n return state.refreshing\n}\n\n/**\n * The credential to put on the next request. In token mode, refreshes a stale\n * seed first. In raw-key mode, returns the seed unchanged (legacy passthrough).\n */\nexport async function getFreshCredential(\n seed?: string,\n): Promise<string | undefined> {\n // Unconfigured but handed a token (a component received the prerendered seed\n // as a prop before any provider configured the manager): adopt it so the\n // refresh machinery works instead of replaying a possibly-expired seed.\n if (!state.isToken && isSiteToken(seed)) {\n configureSiteCredential({ credential: seed })\n }\n // A raw key (or nothing configured) — no token machinery.\n if (!state.isToken) return seed ?? state.seed\n if (needsRefresh()) {\n const refreshed = await refreshSiteToken()\n if (refreshed) return refreshed\n // Refresh failed — fall through to whatever we have; the request may 401 and\n // trip the breaker with friendly copy.\n }\n return state.token ?? seed ?? state.seed\n}\n\n/** Whether the given credential is being managed as a token. */\nexport function isTokenMode(): boolean {\n return state.isToken\n}\n\n/**\n * Best-known credential WITHOUT refreshing — for synchronous unload paths\n * (sonorBeacon) that can't await. In token mode returns the freshest token held;\n * in raw-key mode returns the seed.\n */\nexport function currentCredential(seed?: string): string | undefined {\n if (!state.isToken) return seed ?? state.seed\n return state.token ?? seed ?? state.seed\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/shared/fresh-fetch.ts
|
|
4
|
+
function resolveFetch() {
|
|
5
|
+
const current = globalThis.fetch;
|
|
6
|
+
if (!current) throw new Error("site-kit: global fetch is unavailable");
|
|
7
|
+
const original = current._nextOriginalFetch;
|
|
8
|
+
if (typeof original === "function") return { fn: original, unpatched: true };
|
|
9
|
+
return { fn: current, unpatched: false };
|
|
10
|
+
}
|
|
11
|
+
var BUILD_NONCE = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
12
|
+
var FRESH_FETCH_NONCE_HEADER = "x-sitekit-build-nonce";
|
|
13
|
+
function freshFetch(input, init = {}) {
|
|
14
|
+
const current = globalThis.fetch;
|
|
15
|
+
const { fn, unpatched } = resolveFetch();
|
|
16
|
+
if (unpatched || !current?.__nextPatched) return fn(input, init);
|
|
17
|
+
const headers = new Headers(init.headers);
|
|
18
|
+
headers.set(FRESH_FETCH_NONCE_HEADER, BUILD_NONCE);
|
|
19
|
+
return fn(input, { ...init, headers });
|
|
20
|
+
}
|
|
21
|
+
function isNextProductionBuild() {
|
|
22
|
+
return typeof process !== "undefined" && process.env?.NEXT_PHASE === "phase-production-build";
|
|
23
|
+
}
|
|
24
|
+
function buildFetch(input, init = {}) {
|
|
25
|
+
return isNextProductionBuild() ? freshFetch(input, init) : fetch(input, init);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.buildFetch = buildFetch;
|
|
29
|
+
exports.freshFetch = freshFetch;
|
|
30
|
+
exports.resolveFetch = resolveFetch;
|
|
31
|
+
//# sourceMappingURL=chunk-LVGSOW2F.js.map
|
|
32
|
+
//# sourceMappingURL=chunk-LVGSOW2F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/fresh-fetch.ts"],"names":[],"mappings":";;;AAuCO,SAAS,YAAA,GAAsD;AACpE,EAAA,MAAM,UAAU,UAAA,CAAW,KAAA;AAC3B,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,IAAI,MAAM,uCAAuC,CAAA;AACrE,EAAA,MAAM,WAAW,OAAA,CAAQ,kBAAA;AACzB,EAAA,IAAI,OAAO,aAAa,UAAA,EAAY,OAAO,EAAE,EAAA,EAAI,QAAA,EAAU,WAAW,IAAA,EAAK;AAC3E,EAAA,OAAO,EAAE,EAAA,EAAI,OAAA,EAAS,SAAA,EAAW,KAAA,EAAM;AACzC;AAMA,IAAM,cAAc,CAAA,EAAG,IAAA,CAAK,KAAI,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AAClF,IAAM,wBAAA,GAA2B,uBAAA;AAYjC,SAAS,UAAA,CAAW,KAAA,EAAqB,IAAA,GAAoB,EAAC,EAAsB;AACzF,EAAA,MAAM,UAAU,UAAA,CAAW,KAAA;AAC3B,EAAA,MAAM,EAAE,EAAA,EAAI,SAAA,EAAU,GAAI,YAAA,EAAa;AACvC,EAAA,IAAI,aAAa,CAAC,OAAA,EAAS,eAAe,OAAO,EAAA,CAAG,OAAO,IAAI,CAAA;AAC/D,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAA;AACxC,EAAA,OAAA,CAAQ,GAAA,CAAI,0BAA0B,WAAW,CAAA;AACjD,EAAA,OAAO,GAAG,KAAA,EAAO,EAAE,GAAG,IAAA,EAAM,SAAS,CAAA;AACvC;AAGO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,OAAO,OAAO,OAAA,KAAY,WAAA,IAAe,OAAA,CAAQ,KAAK,UAAA,KAAe,wBAAA;AACvE;AASO,SAAS,UAAA,CAAW,KAAA,EAAqB,IAAA,GAAoB,EAAC,EAAsB;AACzF,EAAA,OAAO,qBAAA,KAA0B,UAAA,CAAW,KAAA,EAAO,IAAI,CAAA,GAAI,KAAA,CAAM,OAAO,IAAI,CAAA;AAC9E","file":"chunk-LVGSOW2F.js","sourcesContent":["/**\n * @sonordev/site-kit shared - Fetch outside Next's Data Cache\n *\n * Single source of truth for requests that must not touch Next's Data Cache\n * and must not change how the calling route renders. Used by the build-time\n * writers (public/llms.txt, the sitemap's Sonor reads) and the site credential\n * mint (server/mint-site-token.ts). Don't re-fork this into a module.\n *\n * Next.js monkey-patches `globalThis.fetch` so every call joins its Data Cache\n * and static-generation tracking. That's wrong for these requests, and the\n * obvious repairs are each wrong in their own way:\n *\n * - `cache: 'no-store'` marks the calling scope dynamic. During `next build`\n * Next throws DynamicServerError before the request goes out, so a static\n * route either stops being static or (caught) never makes the request.\n * - `next: { revalidate: N }` LOWERS the route's revalidate window\n * (patch-fetch.js: `finalRevalidate < revalidateStore.revalidate`), quietly\n * turning fully static pages into ISR.\n * - No option, or `revalidate: false`, keeps the route static but stores the\n * response in the Data Cache under .next/cache/fetch-cache. Hosts persist\n * that directory between builds (Netlify does), so every later build\n * replays the first response. That's how public/llms.txt shipped a\n * months-old copy: its fetch carried no option, was cached with a one-year\n * revalidate, and each build rewrote the same stale file (found on\n * vsfconsultingservices.com, 2026-09-15).\n *\n * So we call the original fetch Next keeps on the patched one and stay\n * invisible to the framework: no bailout, no cache entry, no effect on the\n * route's staticness.\n */\n\ntype FetchLike = typeof fetch\ntype PatchedFetch = FetchLike & { __nextPatched?: boolean; _nextOriginalFetch?: FetchLike }\n\n/**\n * The fetch to use for a request that must bypass Next's Data Cache.\n * `unpatched` is true when that's guaranteed: Next's saved original, or a\n * global fetch Next never patched (plain Node, a CLI, a test).\n */\nexport function resolveFetch(): { fn: FetchLike; unpatched: boolean } {\n const current = globalThis.fetch as PatchedFetch | undefined\n if (!current) throw new Error('site-kit: global fetch is unavailable')\n const original = current._nextOriginalFetch\n if (typeof original === 'function') return { fn: original, unpatched: true }\n return { fn: current, unpatched: false }\n}\n\n/**\n * Per-process nonce for the fallback below. One value per build process, so\n * requests within a build still dedupe and no build can read another's entry.\n */\nconst BUILD_NONCE = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`\nexport const FRESH_FETCH_NONCE_HEADER = 'x-sitekit-build-nonce'\n\n/**\n * Fetch that never reads a response cached by an earlier build.\n *\n * On current Next versions this is the saved original fetch. If a future Next\n * stops exposing it, we're back on the patched fetch: there, `no-store` and a\n * numeric revalidate still carry the costs listed above, so instead the\n * request gets a per-process nonce header. Next's cache key includes request\n * headers (incremental-cache generateCacheKey), so each build gets its own\n * key and never replays a previous build's response.\n */\nexport function freshFetch(input: string | URL, init: RequestInit = {}): Promise<Response> {\n const current = globalThis.fetch as PatchedFetch | undefined\n const { fn, unpatched } = resolveFetch()\n if (unpatched || !current?.__nextPatched) return fn(input, init)\n const headers = new Headers(init.headers)\n headers.set(FRESH_FETCH_NONCE_HEADER, BUILD_NONCE)\n return fn(input, { ...init, headers })\n}\n\n/** True while `next build` is running (Next sets NEXT_PHASE for the build). */\nexport function isNextProductionBuild(): boolean {\n return typeof process !== 'undefined' && process.env?.NEXT_PHASE === 'phase-production-build'\n}\n\n/**\n * Fresh during `next build`, Next's normal fetch otherwise.\n *\n * For reads that feed a build artifact AND can also run at request time (an\n * ISR sitemap regeneration): the build must see current data, while a runtime\n * render keeps whatever caching its route already declares.\n */\nexport function buildFetch(input: string | URL, init: RequestInit = {}): Promise<Response> {\n return isNextProductionBuild() ? freshFetch(input, init) : fetch(input, init)\n}\n"]}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkFVW6FT6L_js = require('./chunk-FVW6FT6L.js');
|
|
4
|
+
var chunkCXAXZFFW_js = require('./chunk-CXAXZFFW.js');
|
|
5
|
+
var chunkH5NBFNND_js = require('./chunk-H5NBFNND.js');
|
|
4
6
|
|
|
5
7
|
// src/seo/getManagedMetadata.ts
|
|
6
8
|
async function getManagedMetadata(options) {
|
|
7
9
|
const { path, fallback = {}, overrides = {}, favicon: faviconMode = "metadata" } = options;
|
|
8
10
|
const omitIcons = faviconMode === "component";
|
|
9
|
-
const result = await
|
|
11
|
+
const result = await chunkFVW6FT6L_js.getSEOPageData(path);
|
|
10
12
|
const pageData = result?.page;
|
|
11
13
|
const projectData = result?.project;
|
|
12
14
|
if (!pageData) {
|
|
@@ -35,16 +37,30 @@ async function getManagedMetadata(options) {
|
|
|
35
37
|
};
|
|
36
38
|
}
|
|
37
39
|
if (!pageData.managed_title && !pageData.managed_meta_description && !pageData.managed_description) {
|
|
38
|
-
|
|
40
|
+
chunkFVW6FT6L_js.ensureMetadata(path).catch(() => {
|
|
39
41
|
});
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
const identity = {
|
|
44
|
+
brand: projectData?.brand ?? projectData?.title ?? null,
|
|
45
|
+
hosts: [chunkH5NBFNND_js.resolveSiteHost(), pageData.site, projectData?.domain, projectData?.site_url]
|
|
46
|
+
};
|
|
47
|
+
const rejected = {};
|
|
48
|
+
const rawTitle = pageData.managed_title;
|
|
49
|
+
const titleIssue = rawTitle ? chunkCXAXZFFW_js.titleProblem(rawTitle, identity, { path }) : null;
|
|
50
|
+
if (titleIssue) rejected.title = titleIssue;
|
|
51
|
+
const managedTitle = rawTitle && !titleIssue ? rawTitle : void 0;
|
|
52
|
+
const rawDescription = pageData.managed_meta_description || pageData.managed_description;
|
|
53
|
+
const descriptionIssue = rawDescription ? chunkCXAXZFFW_js.descriptionProblem(rawDescription, identity) : null;
|
|
54
|
+
if (descriptionIssue) rejected.description = descriptionIssue;
|
|
55
|
+
const managedDescription = rawDescription && !descriptionIssue ? rawDescription : void 0;
|
|
56
|
+
if (titleIssue || descriptionIssue) metadata._rejected = rejected;
|
|
57
|
+
if (managedTitle) {
|
|
58
|
+
metadata.title = managedTitle;
|
|
43
59
|
} else if (fallback.title) {
|
|
44
60
|
metadata.title = fallback.title;
|
|
45
61
|
}
|
|
46
|
-
if (
|
|
47
|
-
metadata.description =
|
|
62
|
+
if (managedDescription) {
|
|
63
|
+
metadata.description = managedDescription;
|
|
48
64
|
} else if (fallback.description) {
|
|
49
65
|
metadata.description = fallback.description;
|
|
50
66
|
}
|
|
@@ -69,8 +85,10 @@ async function getManagedMetadata(options) {
|
|
|
69
85
|
languages: langAlts
|
|
70
86
|
};
|
|
71
87
|
}
|
|
72
|
-
const
|
|
73
|
-
const
|
|
88
|
+
const managedOgTitle = pageData.managed_og_title && !chunkCXAXZFFW_js.titleProblem(pageData.managed_og_title, identity, { path }) ? pageData.managed_og_title : void 0;
|
|
89
|
+
const managedOgDescription = pageData.managed_og_description && !chunkCXAXZFFW_js.descriptionProblem(pageData.managed_og_description, identity) ? pageData.managed_og_description : void 0;
|
|
90
|
+
const ogTitle = managedOgTitle || managedTitle;
|
|
91
|
+
const ogDescription = managedOgDescription || managedDescription;
|
|
74
92
|
const ogImage = pageData.managed_og_image;
|
|
75
93
|
if (ogTitle || ogDescription || ogImage) {
|
|
76
94
|
metadata.openGraph = {
|
|
@@ -96,7 +114,7 @@ async function getManagedMetadata(options) {
|
|
|
96
114
|
}
|
|
97
115
|
async function getABVariant(options) {
|
|
98
116
|
const { path, field, sessionId } = options;
|
|
99
|
-
const test = await
|
|
117
|
+
const test = await chunkFVW6FT6L_js.getABTest(path, field);
|
|
100
118
|
if (!test) {
|
|
101
119
|
return null;
|
|
102
120
|
}
|
|
@@ -109,7 +127,7 @@ async function getABVariant(options) {
|
|
|
109
127
|
} else {
|
|
110
128
|
variant = Math.random() < test.traffic_split ? "a" : "b";
|
|
111
129
|
}
|
|
112
|
-
|
|
130
|
+
chunkFVW6FT6L_js.recordABImpression(test.id, variant, sessionId).catch(() => {
|
|
113
131
|
});
|
|
114
132
|
return {
|
|
115
133
|
testId: test.id,
|
|
@@ -142,7 +160,7 @@ async function getManagedMetadataWithAB(options) {
|
|
|
142
160
|
// src/seo/routing.ts
|
|
143
161
|
async function getRedirect(options) {
|
|
144
162
|
const { path } = options;
|
|
145
|
-
const redirect = await
|
|
163
|
+
const redirect = await chunkFVW6FT6L_js.getRedirectData(path);
|
|
146
164
|
if (!redirect) {
|
|
147
165
|
return null;
|
|
148
166
|
}
|
|
@@ -184,7 +202,7 @@ function parseRobotsString(robots) {
|
|
|
184
202
|
}
|
|
185
203
|
async function getRobotsDirective(options) {
|
|
186
204
|
const { path } = options;
|
|
187
|
-
const robotsString = await
|
|
205
|
+
const robotsString = await chunkFVW6FT6L_js.getRobotsData(path);
|
|
188
206
|
if (!robotsString) {
|
|
189
207
|
return { index: true, follow: true };
|
|
190
208
|
}
|
|
@@ -192,7 +210,7 @@ async function getRobotsDirective(options) {
|
|
|
192
210
|
}
|
|
193
211
|
async function generateSitemap(options) {
|
|
194
212
|
const { baseUrl, publishedOnly = true } = options;
|
|
195
|
-
const pages = await
|
|
213
|
+
const pages = await chunkFVW6FT6L_js.getSitemapEntries({ publishedOnly });
|
|
196
214
|
const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
197
215
|
return pages.map((page) => ({
|
|
198
216
|
path: page.path,
|
|
@@ -203,11 +221,11 @@ async function generateSitemap(options) {
|
|
|
203
221
|
}));
|
|
204
222
|
}
|
|
205
223
|
async function registerLocalSitemap(options) {
|
|
206
|
-
const { registerSitemap } = await import('./server-api-
|
|
224
|
+
const { registerSitemap } = await import('./server-api-IWTZ7C3O.js');
|
|
207
225
|
let entries = options.entries || [];
|
|
208
226
|
if (options.autoDiscover && entries.length === 0) {
|
|
209
227
|
try {
|
|
210
|
-
const { discoverNextJsRoutes, findAppDirForDiscovery } = await import('./discover-
|
|
228
|
+
const { discoverNextJsRoutes, findAppDirForDiscovery } = await import('./discover-NGEPXZOD.js');
|
|
211
229
|
const appDir = findAppDirForDiscovery();
|
|
212
230
|
if (appDir) {
|
|
213
231
|
entries = discoverNextJsRoutes(appDir);
|
|
@@ -223,7 +241,7 @@ async function registerLocalSitemap(options) {
|
|
|
223
241
|
}
|
|
224
242
|
const mode = options.mode ?? "additive";
|
|
225
243
|
console.log(`[Sonor] Registering ${entries.length} sitemap entries (${mode})...`);
|
|
226
|
-
const result = await registerSitemap(entries, { mode });
|
|
244
|
+
const result = await registerSitemap(entries, { mode, site: options.site });
|
|
227
245
|
if (result.success) {
|
|
228
246
|
console.log(`[Sonor] Sitemap registered: ${result.created} new, ${result.updated} updated`);
|
|
229
247
|
}
|
|
@@ -242,5 +260,5 @@ exports.getRedirect = getRedirect;
|
|
|
242
260
|
exports.getRobotsDirective = getRobotsDirective;
|
|
243
261
|
exports.isIndexable = isIndexable;
|
|
244
262
|
exports.registerLocalSitemap = registerLocalSitemap;
|
|
245
|
-
//# sourceMappingURL=chunk-
|
|
246
|
-
//# sourceMappingURL=chunk-
|
|
263
|
+
//# sourceMappingURL=chunk-M45AL7EA.js.map
|
|
264
|
+
//# sourceMappingURL=chunk-M45AL7EA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/seo/getManagedMetadata.ts","../src/seo/routing.ts"],"names":["getSEOPageData","ensureMetadata","resolveSiteHost","titleProblem","descriptionProblem","getABTest","recordABImpression","getRedirectData","getRobotsData","getSitemapEntries"],"mappings":"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","file":"chunk-M45AL7EA.js","sourcesContent":["import type { Metadata } from 'next'\nimport { getSEOPageData, getABTest, recordABImpression, ensureMetadata } from './server-api'\nimport { descriptionProblem, titleProblem, type MetaIdentity } from '../seo-meta/contract'\nimport { resolveSiteHost } from '../sites/resolve'\nimport type { \n GetManagedMetadataOptions, \n ManagedMetadataResult,\n GetABVariantOptions,\n ABTestResult \n} from './types'\n\n/**\n * Get managed metadata for a page\n * \n * Use in generateMetadata() to fetch Portal-managed SEO data\n * \n * @example\n * ```tsx\n * export async function generateMetadata({ params }) {\n * return getManagedMetadata({\n * path: `/services/${params.slug}`,\n * fallback: {\n * title: 'Our Services',\n * description: 'Learn about our services'\n * }\n * })\n * }\n * ```\n */\nexport async function getManagedMetadata(\n options: GetManagedMetadataOptions\n): Promise<ManagedMetadataResult> {\n const { path, fallback = {}, overrides = {}, favicon: faviconMode = 'metadata' } = options\n const omitIcons = faviconMode === 'component'\n\n const result = await getSEOPageData(path)\n const pageData = result?.page\n const projectData = result?.project\n\n // If no managed data, return fallback (still include favicon from project if available, unless using component)\n if (!pageData) {\n const fallbackMeta: ManagedMetadataResult = {\n ...fallback,\n ...overrides,\n _managed: false,\n _source: 'fallback',\n } as ManagedMetadataResult\n\n if (!omitIcons && projectData?.logo_url) {\n fallbackMeta.icons = {\n icon: projectData.logo_url,\n apple: projectData.logo_url,\n }\n }\n\n return fallbackMeta\n }\n\n // Build metadata from managed values, falling back to provided fallbacks\n const metadata: ManagedMetadataResult = {\n _managed: true,\n _source: 'database',\n }\n\n if (!omitIcons && projectData?.logo_url) {\n metadata.icons = {\n icon: projectData.logo_url,\n apple: projectData.logo_url,\n }\n }\n\n // Signal fallback — when page exists but both title & description are empty,\n // trigger Signal AI to generate them (fire-and-forget so it never blocks TTFB;\n // the generated data will be available on the next request)\n if (!pageData.managed_title && !pageData.managed_meta_description && !pageData.managed_description) {\n ensureMetadata(path).catch(() => {})\n }\n\n // Quality gate (seo-meta/contract): a managed value that names the domain,\n // was hard-cut mid-word, ends on a separator, or respells the brand never\n // ships. The page's own fallback does, so no site needs its own guard.\n const identity: MetaIdentity = {\n brand: projectData?.brand ?? projectData?.title ?? null,\n hosts: [resolveSiteHost(), pageData.site, projectData?.domain, projectData?.site_url],\n }\n const rejected: NonNullable<ManagedMetadataResult['_rejected']> = {}\n const rawTitle = pageData.managed_title\n const titleIssue = rawTitle ? titleProblem(rawTitle, identity, { path }) : null\n if (titleIssue) rejected.title = titleIssue\n const managedTitle = rawTitle && !titleIssue ? rawTitle : undefined\n\n const rawDescription = pageData.managed_meta_description || pageData.managed_description\n const descriptionIssue = rawDescription ? descriptionProblem(rawDescription, identity) : null\n if (descriptionIssue) rejected.description = descriptionIssue\n const managedDescription = rawDescription && !descriptionIssue ? rawDescription : undefined\n\n if (titleIssue || descriptionIssue) metadata._rejected = rejected\n\n // Title\n if (managedTitle) {\n metadata.title = managedTitle\n } else if (fallback.title) {\n metadata.title = fallback.title\n }\n\n // Description\n if (managedDescription) {\n metadata.description = managedDescription\n } else if (fallback.description) {\n metadata.description = fallback.description\n }\n\n // Keywords\n if (pageData.managed_keywords?.length) {\n metadata.keywords = pageData.managed_keywords\n } else if (fallback.keywords) {\n metadata.keywords = fallback.keywords\n }\n\n // Robots\n if (pageData.managed_robots) {\n metadata.robots = pageData.managed_robots\n }\n\n // Canonical\n if (pageData.managed_canonical) {\n metadata.alternates = {\n ...metadata.alternates,\n canonical: pageData.managed_canonical,\n }\n }\n\n // Optional hreflang map from Portal (expansion / multilingual sites)\n const langAlts = pageData.language_alternates\n if (langAlts && typeof langAlts === 'object' && !Array.isArray(langAlts)) {\n metadata.alternates = {\n ...metadata.alternates,\n languages: langAlts as Record<string, string>,\n }\n }\n\n // Open Graph — the same gate, so a rejected title can't still ship in\n // every share preview through og:title / twitter:title.\n const managedOgTitle =\n pageData.managed_og_title && !titleProblem(pageData.managed_og_title, identity, { path })\n ? pageData.managed_og_title\n : undefined\n const managedOgDescription =\n pageData.managed_og_description && !descriptionProblem(pageData.managed_og_description, identity)\n ? pageData.managed_og_description\n : undefined\n const ogTitle = managedOgTitle || managedTitle\n const ogDescription = managedOgDescription || managedDescription\n const ogImage = pageData.managed_og_image\n\n if (ogTitle || ogDescription || ogImage) {\n metadata.openGraph = {\n ...(ogTitle && { title: ogTitle }),\n ...(ogDescription && { description: ogDescription }),\n ...(ogImage && { images: [{ url: ogImage }] }),\n }\n }\n\n // Twitter (use OG values as fallback)\n if (ogTitle || ogDescription || ogImage) {\n metadata.twitter = {\n card: 'summary_large_image',\n ...(ogTitle && { title: ogTitle }),\n ...(ogDescription && { description: ogDescription }),\n ...(ogImage && { images: [ogImage] }),\n }\n }\n\n // Apply overrides last\n return {\n ...metadata,\n ...overrides,\n _managed: true,\n _source: 'database',\n }\n}\n\n/**\n * Get A/B test variant for a field\n * \n * @example\n * ```tsx\n * const variant = await getABVariant({\n * path: '/pricing',\n * field: 'title',\n * sessionId: cookies().get('session_id')?.value\n * })\n * \n * if (variant) {\n * // Use variant.value instead of default\n * }\n * ```\n */\nexport async function getABVariant(\n options: GetABVariantOptions\n): Promise<ABTestResult | null> {\n const { path, field, sessionId } = options\n\n const test = await getABTest(path, field)\n\n if (!test) {\n return null\n }\n\n // Determine variant based on session ID or random\n let variant: 'a' | 'b'\n \n if (sessionId) {\n // Consistent variant for same session\n const hash = sessionId.split('').reduce((acc, char) => {\n return ((acc << 5) - acc) + char.charCodeAt(0)\n }, 0)\n variant = (Math.abs(hash) % 100) < (test.traffic_split * 100) ? 'a' : 'b'\n } else {\n // Random variant\n variant = Math.random() < test.traffic_split ? 'a' : 'b'\n }\n\n // Record impression (fire and forget)\n recordABImpression(test.id, variant, sessionId).catch(() => {\n // Silently fail - don't block rendering\n })\n\n return {\n testId: test.id,\n variant,\n value: variant === 'a' ? test.variant_a : test.variant_b,\n }\n}\n\n/**\n * Get managed metadata with A/B test support\n * \n * Automatically applies running A/B test variants to metadata\n */\nexport async function getManagedMetadataWithAB(\n options: GetManagedMetadataOptions & { sessionId?: string }\n): Promise<ManagedMetadataResult> {\n const { sessionId, ...metadataOptions } = options\n \n // Get base metadata\n const metadata = await getManagedMetadata(metadataOptions)\n\n // Check for title A/B test\n const titleTest = await getABVariant({\n path: options.path,\n field: 'title',\n sessionId,\n })\n\n if (titleTest) {\n metadata.title = titleTest.value\n }\n\n // Check for description A/B test\n const descTest = await getABVariant({\n path: options.path,\n field: 'description',\n sessionId,\n })\n\n if (descTest) {\n metadata.description = descTest.value\n }\n\n return metadata\n}\n","import { getRedirectData, getRobotsData, getSitemapEntries } from './server-api'\nimport type { \n GetRedirectOptions, \n RedirectResult, \n GetRobotsOptions, \n RobotsDirective,\n GetSitemapEntriesOptions,\n SitemapEntry \n} from './types'\n\n/**\n * Get redirect for a path if one exists\n * \n * Use in Next.js middleware to handle managed redirects\n * \n * @example\n * ```tsx\n * // proxy.ts\n * import { getRedirect } from '@sonordev/site-kit/seo'\n * \n * export default async function proxy(request) {\n * const redirect = await getRedirect({ path: request.nextUrl.pathname })\n * \n * if (redirect) {\n * return NextResponse.redirect(redirect.destination, redirect.statusCode)\n * }\n * }\n * ```\n */\nexport async function getRedirect(\n options: GetRedirectOptions\n): Promise<RedirectResult | null> {\n const { path } = options\n\n const redirect = await getRedirectData(path)\n\n if (!redirect) {\n return null\n }\n\n // Check if expired\n if (redirect.expires_at && new Date(redirect.expires_at) < new Date()) {\n return null\n }\n\n // Determine destination\n const destination = redirect.destination_url || redirect.destination_path\n const isExternal = destination.startsWith('http://') || destination.startsWith('https://')\n\n return {\n destination,\n statusCode: redirect.status_code,\n isExternal,\n }\n}\n\n/**\n * Parse robots directive string into structured object\n */\nfunction parseRobotsString(robots: string): RobotsDirective {\n const directive: RobotsDirective = {\n index: true,\n follow: true,\n }\n\n const parts = robots.toLowerCase().split(',').map(p => p.trim())\n\n for (const part of parts) {\n if (part === 'noindex') directive.index = false\n if (part === 'nofollow') directive.follow = false\n if (part === 'noarchive') directive.noarchive = true\n if (part === 'nosnippet') directive.nosnippet = true\n if (part === 'noimageindex') directive.noimageindex = true\n if (part.startsWith('max-snippet:')) {\n directive.max_snippet = parseInt(part.split(':')[1], 10)\n }\n if (part.startsWith('max-image-preview:')) {\n const value = part.split(':')[1] as 'none' | 'standard' | 'large'\n directive.max_image_preview = value\n }\n if (part.startsWith('max-video-preview:')) {\n directive.max_video_preview = parseInt(part.split(':')[1], 10)\n }\n }\n\n return directive\n}\n\n/**\n * Get robots directive for a page\n * \n * @example\n * ```tsx\n * const robots = await getRobotsDirective({ path: '/private-page' })\n * \n * if (!robots.index) {\n * // Page should not be indexed\n * }\n * ```\n */\nexport async function getRobotsDirective(\n options: GetRobotsOptions\n): Promise<RobotsDirective> {\n const { path } = options\n\n const robotsString = await getRobotsData(path)\n\n if (!robotsString) {\n // Default: index and follow\n return { index: true, follow: true }\n }\n\n return parseRobotsString(robotsString)\n}\n\n/**\n * Get the project's managed page list as sitemap entries\n *\n * Returns `{ path, url, lastmod, changefreq, priority }`, which is NOT Next's\n * `MetadataRoute.Sitemap` shape (`lastModified` / `changeFrequency`). For\n * app/sitemap.ts prefer `createSitemap` from `@sonordev/site-kit/sitemap`.\n *\n * @example\n * ```tsx\n * import { generateSitemap } from '@sonordev/site-kit/seo'\n *\n * const entries = await generateSitemap({ baseUrl: 'https://example.com' })\n * ```\n */\nexport async function generateSitemap(\n options: GetSitemapEntriesOptions\n): Promise<SitemapEntry[]> {\n const { baseUrl, publishedOnly = true } = options\n\n const pages = await getSitemapEntries({ publishedOnly })\n\n const normalizedBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n\n return pages.map((page: { path: string; lastmod?: string; changefreq?: string; priority?: number }) => ({\n path: page.path,\n url: `${normalizedBase}${page.path}`,\n lastmod: page.lastmod,\n changefreq: (page.changefreq || 'weekly') as SitemapEntry['changefreq'],\n priority: page.priority ?? 0.5,\n }))\n}\n\n/**\n * Register local sitemap entries with Sonor\n * \n * Call this at build time to sync your local routes to seo_pages.\n * This ensures analytics only tracks real pages.\n * \n * After registration, Signal AI will generate optimized meta titles\n * and descriptions for pages that don't have managed meta yet.\n * \n * @example\n * ```ts\n * // scripts/register-sitemap.ts\n * import { registerLocalSitemap } from '@sonordev/site-kit/seo/server'\n *\n * // Option 1: Provide entries directly\n * await registerLocalSitemap({\n * entries: [\n * { path: '/', title: 'Home', priority: 1.0 },\n * { path: '/about', title: 'About Us', priority: 0.8 },\n * ]\n * })\n *\n * // Option 2: Auto-discover from Next.js app directory\n * await registerLocalSitemap({ autoDiscover: true })\n * ```\n */\nexport async function registerLocalSitemap(options: {\n entries?: Array<{\n path: string\n title?: string\n priority?: number\n changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'\n }>\n autoDiscover?: boolean\n /** Trigger Signal AI to generate optimized meta titles/descriptions (default: true) */\n optimize_meta?: boolean\n /**\n * Sync mode. Defaults to 'additive' for explicit entries (a partial list must\n * never delete the rest of the site's pages) and 'full-replace' for\n * autoDiscover (which enumerates the complete route set).\n */\n mode?: 'additive' | 'full-replace'\n /** Sub-site host on a multi-site project. Defaults to NEXT_PUBLIC_SITE_URL's host. */\n site?: string\n}): Promise<{\n success: boolean\n created: number\n updated: number\n removed?: number\n meta_optimization?: {\n triggered: boolean\n pages_queued: number\n } | null\n}> {\n const { registerSitemap } = await import('./server-api')\n\n let entries = options.entries || []\n\n // Auto-discover from the Next.js app directory if requested. Lazy-import the\n // fs-backed discovery module so `fs` never enters this file's STATIC graph —\n // getRedirect/isIndexable below are imported by edge middleware, which has no\n // fs. Discovery only runs at build time, in Node, so a dynamic import is fine.\n if (options.autoDiscover && entries.length === 0) {\n try {\n const { discoverNextJsRoutes, findAppDirForDiscovery } = await import('../sitemap/discover')\n const appDir = findAppDirForDiscovery()\n if (appDir) {\n entries = discoverNextJsRoutes(appDir)\n console.log(`[Sonor] Auto-discovered ${entries.length} routes from app directory`)\n }\n } catch (error) {\n console.error('[Sonor] Auto-discovery failed:', error)\n }\n }\n\n if (entries.length === 0) {\n console.warn('[Sonor] No sitemap entries to register')\n return { success: true, created: 0, updated: 0 }\n }\n\n // A route set discovered from the filesystem is structurally incomplete (it\n // can't enumerate dynamic routes and ignores sitemap excludes), and an\n // explicit entry list is often partial — either way a full-replace would\n // silently delete real pages. Default everything to additive; a caller that\n // truly holds the complete page set opts in with mode: 'full-replace'. The\n // recommended `sonor-register-sitemap` postbuild additionally self-skips when\n // an app/sitemap route already owns the sync.\n const mode = options.mode ?? 'additive'\n\n console.log(`[Sonor] Registering ${entries.length} sitemap entries (${mode})...`)\n const result = await registerSitemap(entries, { mode, site: options.site })\n \n if (result.success) {\n console.log(`[Sonor] Sitemap registered: ${result.created} new, ${result.updated} updated`)\n }\n \n return result\n}\n\n/**\n * Check if a path should be indexed\n * \n * Quick helper to check indexability without full directive parsing\n */\nexport async function isIndexable(\n projectId: string,\n path: string\n): Promise<boolean> {\n const directive = await getRobotsDirective({ projectId, path })\n return directive.index\n}\n"]}
|