@sonordev/site-kit 6.3.5 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-manifest.json +8 -2
- package/dist/{AnalyticsProvider-2A75HPK6.mjs → AnalyticsProvider-4K5T7OQ7.mjs} +6 -6
- package/dist/{AnalyticsProvider-2A75HPK6.mjs.map → AnalyticsProvider-4K5T7OQ7.mjs.map} +1 -1
- package/dist/{AnalyticsProvider-2H3POGSJ.js → AnalyticsProvider-QXZN5O6D.js} +10 -10
- package/dist/{AnalyticsProvider-2H3POGSJ.js.map → AnalyticsProvider-QXZN5O6D.js.map} +1 -1
- package/dist/{ArticleViewTracker-75BLDTHR.mjs → ArticleViewTracker-BUG2TOHS.mjs} +5 -5
- package/dist/{ArticleViewTracker-75BLDTHR.mjs.map → ArticleViewTracker-BUG2TOHS.mjs.map} +1 -1
- package/dist/{ArticleViewTracker-R3LNZ4A4.js → ArticleViewTracker-FFMHR7AY.js} +6 -6
- package/dist/{ArticleViewTracker-R3LNZ4A4.js.map → ArticleViewTracker-FFMHR7AY.js.map} +1 -1
- package/dist/{ChatWidget-F6UWIR7I.mjs → ChatWidget-CRQPBDEF.mjs} +7 -7
- package/dist/{ChatWidget-F6UWIR7I.mjs.map → ChatWidget-CRQPBDEF.mjs.map} +1 -1
- package/dist/{ChatWidget-BLZSLYN2.js → ChatWidget-XFYLVXAX.js} +10 -10
- package/dist/{ChatWidget-BLZSLYN2.js.map → ChatWidget-XFYLVXAX.js.map} +1 -1
- package/dist/EngageWidget-S234YAT2.js +21 -0
- package/dist/{EngageWidget-YONW3W3Z.js.map → EngageWidget-S234YAT2.js.map} +1 -1
- package/dist/EngageWidget-SQU4T7CI.mjs +12 -0
- package/dist/{EngageWidget-4WB74GQR.mjs.map → EngageWidget-SQU4T7CI.mjs.map} +1 -1
- package/dist/{FileField-GXNFYVSY.mjs → FileField-HNEBEBLB.mjs} +5 -5
- package/dist/{FileField-GXNFYVSY.mjs.map → FileField-HNEBEBLB.mjs.map} +1 -1
- package/dist/{FileField-KYQVN4XB.js → FileField-XG4EYAZW.js} +6 -6
- package/dist/{FileField-KYQVN4XB.js.map → FileField-XG4EYAZW.js.map} +1 -1
- package/dist/{FormSpotlight-ZOSI7MXH.js → FormSpotlight-IODREOPN.js} +9 -9
- package/dist/{FormSpotlight-ZOSI7MXH.js.map → FormSpotlight-IODREOPN.js.map} +1 -1
- package/dist/{FormSpotlight-F4YZOWHA.mjs → FormSpotlight-VKD774PZ.mjs} +3 -3
- package/dist/{FormSpotlight-F4YZOWHA.mjs.map → FormSpotlight-VKD774PZ.mjs.map} +1 -1
- package/dist/{FormStage-DICKOW7R.js → FormStage-37KKZQH4.js} +9 -9
- package/dist/{FormStage-DICKOW7R.js.map → FormStage-37KKZQH4.js.map} +1 -1
- package/dist/{FormStage-TIQ43MF6.mjs → FormStage-PRZNRYNC.mjs} +3 -3
- package/dist/{FormStage-TIQ43MF6.mjs.map → FormStage-PRZNRYNC.mjs.map} +1 -1
- package/dist/ManagedForm-4PZOCKCV.mjs +16 -0
- package/dist/{ManagedForm-KKJOIEFW.mjs.map → ManagedForm-4PZOCKCV.mjs.map} +1 -1
- package/dist/ManagedForm-JCMEE626.js +25 -0
- package/dist/{ManagedForm-ZUPV4DPQ.js.map → ManagedForm-JCMEE626.js.map} +1 -1
- package/dist/{ManagedNewsletterForm-NFV2JGNA.js → ManagedNewsletterForm-CTC33B2U.js} +7 -7
- package/dist/{ManagedNewsletterForm-NFV2JGNA.js.map → ManagedNewsletterForm-CTC33B2U.js.map} +1 -1
- package/dist/{ManagedNewsletterForm-JOTIWXLQ.mjs → ManagedNewsletterForm-KMZG24OE.mjs} +6 -6
- package/dist/{ManagedNewsletterForm-JOTIWXLQ.mjs.map → ManagedNewsletterForm-KMZG24OE.mjs.map} +1 -1
- package/dist/{SignalCore-DLRQTFKK.js → SignalCore-YHT7WPXV.js} +11 -11
- package/dist/{SignalCore-DLRQTFKK.js.map → SignalCore-YHT7WPXV.js.map} +1 -1
- package/dist/{SignalCore-MUN44S6K.mjs → SignalCore-YIPKKIUG.mjs} +5 -5
- package/dist/{SignalCore-MUN44S6K.mjs.map → SignalCore-YIPKKIUG.mjs.map} +1 -1
- package/dist/SitemapSync-GN4OXIM2.js +18 -0
- package/dist/{SitemapSync-5TKLHXFL.js.map → SitemapSync-GN4OXIM2.js.map} +1 -1
- package/dist/SitemapSync-NG763CGN.mjs +9 -0
- package/dist/{SitemapSync-BIWCTMRJ.mjs.map → SitemapSync-NG763CGN.mjs.map} +1 -1
- package/dist/analytics/AnalyticsProvider.d.ts +0 -6
- package/dist/analytics/AnalyticsProvider.d.ts.map +1 -1
- package/dist/analytics/WebVitals.d.ts +4 -1
- package/dist/analytics/WebVitals.d.ts.map +1 -1
- package/dist/analytics/index.js +9 -9
- package/dist/analytics/index.mjs +4 -4
- package/dist/analytics/measurement-context.d.ts +13 -0
- package/dist/analytics/measurement-context.d.ts.map +1 -0
- package/dist/analytics/page-observation.d.ts +39 -0
- package/dist/analytics/page-observation.d.ts.map +1 -0
- package/dist/articles/AuthorPage.d.ts +1 -1
- package/dist/articles/AuthorPage.d.ts.map +1 -1
- package/dist/articles/author-schema.d.ts +59 -13
- package/dist/articles/author-schema.d.ts.map +1 -1
- package/dist/articles/index.js +24 -23
- package/dist/articles/index.js.map +1 -1
- package/dist/articles/index.mjs +12 -11
- package/dist/articles/index.mjs.map +1 -1
- package/dist/articles/routes.d.ts +9 -0
- package/dist/articles/routes.d.ts.map +1 -1
- package/dist/articles/server-core.d.ts +5 -2
- package/dist/articles/server-core.d.ts.map +1 -1
- package/dist/articles/server-ui.js +45 -45
- package/dist/articles/server-ui.mjs +8 -8
- package/dist/articles/server.d.ts +5 -2
- package/dist/articles/server.d.ts.map +1 -1
- package/dist/articles/server.js +72 -56
- package/dist/articles/server.mjs +3 -3
- package/dist/articles/types.d.ts +17 -0
- package/dist/articles/types.d.ts.map +1 -1
- package/dist/{chunk-H6F7T5Z6.mjs → chunk-24LFAQEG.mjs} +5 -5
- package/dist/{chunk-H6F7T5Z6.mjs.map → chunk-24LFAQEG.mjs.map} +1 -1
- package/dist/chunk-3AOKYAZ2.js +135 -0
- package/dist/chunk-3AOKYAZ2.js.map +1 -0
- package/dist/{chunk-QII2TNKS.mjs → chunk-4C3INRHE.mjs} +72 -15
- package/dist/chunk-4C3INRHE.mjs.map +1 -0
- package/dist/{chunk-ZR43XFUM.js → chunk-55J2KE7D.js} +3 -3
- package/dist/chunk-55J2KE7D.js.map +1 -0
- package/dist/{chunk-SIQX3GL3.mjs → chunk-5BARLEAI.mjs} +3 -3
- package/dist/{chunk-SIQX3GL3.mjs.map → chunk-5BARLEAI.mjs.map} +1 -1
- package/dist/{chunk-HTCMZAXW.mjs → chunk-5T3J24K4.mjs} +4 -4
- package/dist/{chunk-HTCMZAXW.mjs.map → chunk-5T3J24K4.mjs.map} +1 -1
- package/dist/{chunk-RWERWLRM.js → chunk-5W4S7XQD.js} +3 -3
- package/dist/{chunk-RWERWLRM.js.map → chunk-5W4S7XQD.js.map} +1 -1
- package/dist/{chunk-6DCAMW62.mjs → chunk-6C47333H.mjs} +3 -3
- package/dist/chunk-6C47333H.mjs.map +1 -0
- package/dist/{chunk-2OA274JZ.mjs → chunk-6QPKC6XP.mjs} +3 -3
- package/dist/{chunk-2OA274JZ.mjs.map → chunk-6QPKC6XP.mjs.map} +1 -1
- package/dist/{chunk-R7XCEUEI.mjs → chunk-BI7DH42Z.mjs} +4 -4
- package/dist/{chunk-R7XCEUEI.mjs.map → chunk-BI7DH42Z.mjs.map} +1 -1
- package/dist/{chunk-ID4RGBQT.js → chunk-C7J4XLBN.js} +15 -15
- package/dist/{chunk-ID4RGBQT.js.map → chunk-C7J4XLBN.js.map} +1 -1
- package/dist/{chunk-LWCAZDY2.js → chunk-CDRQYJUT.js} +4 -4
- package/dist/{chunk-LWCAZDY2.js.map → chunk-CDRQYJUT.js.map} +1 -1
- package/dist/chunk-CIB3RHNZ.js +8 -0
- package/dist/{chunk-LSB3CWSB.js.map → chunk-CIB3RHNZ.js.map} +1 -1
- package/dist/{chunk-NCLF7RUL.js → chunk-CUZ3I6CO.js} +5 -5
- package/dist/{chunk-NCLF7RUL.js.map → chunk-CUZ3I6CO.js.map} +1 -1
- package/dist/{chunk-UEYZXWIP.js → chunk-EWDWLY74.js} +11 -11
- package/dist/{chunk-UEYZXWIP.js.map → chunk-EWDWLY74.js.map} +1 -1
- package/dist/{chunk-4EMMMKDR.js → chunk-F2GECCK7.js} +12 -12
- package/dist/{chunk-4EMMMKDR.js.map → chunk-F2GECCK7.js.map} +1 -1
- package/dist/chunk-GFSQMK35.mjs +127 -0
- package/dist/chunk-GFSQMK35.mjs.map +1 -0
- package/dist/{chunk-XP63NBUV.js → chunk-GGGX54ZE.js} +14 -14
- package/dist/{chunk-XP63NBUV.js.map → chunk-GGGX54ZE.js.map} +1 -1
- package/dist/{chunk-ZPITTAT5.mjs → chunk-GSU6VTCZ.mjs} +3 -3
- package/dist/{chunk-ZPITTAT5.mjs.map → chunk-GSU6VTCZ.mjs.map} +1 -1
- package/dist/{chunk-XQPNCDGF.js → chunk-GXSSFQ5D.js} +15 -15
- package/dist/{chunk-XQPNCDGF.js.map → chunk-GXSSFQ5D.js.map} +1 -1
- package/dist/{chunk-BJ4T65OK.mjs → chunk-H4TSADY3.mjs} +3 -3
- package/dist/{chunk-BJ4T65OK.mjs.map → chunk-H4TSADY3.mjs.map} +1 -1
- package/dist/{chunk-3UT3XR6M.js → chunk-HSLPN3QK.js} +7 -7
- package/dist/{chunk-3UT3XR6M.js.map → chunk-HSLPN3QK.js.map} +1 -1
- package/dist/{chunk-QAYB7NCH.js → chunk-HTCNRTN6.js} +129 -69
- package/dist/chunk-HTCNRTN6.js.map +1 -0
- package/dist/{chunk-Y3SYVAP6.mjs → chunk-JXRGIE3V.mjs} +4 -4
- package/dist/{chunk-Y3SYVAP6.mjs.map → chunk-JXRGIE3V.mjs.map} +1 -1
- package/dist/chunk-K3PVUXKB.mjs +6 -0
- package/dist/{chunk-7JGD5TUI.mjs.map → chunk-K3PVUXKB.mjs.map} +1 -1
- package/dist/{chunk-L2KN3GYW.mjs → chunk-KOPFFKG2.mjs} +3 -3
- package/dist/{chunk-L2KN3GYW.mjs.map → chunk-KOPFFKG2.mjs.map} +1 -1
- package/dist/{chunk-LP6KJPAL.js → chunk-KZBDH5A3.js} +4 -4
- package/dist/{chunk-LP6KJPAL.js.map → chunk-KZBDH5A3.js.map} +1 -1
- package/dist/{chunk-DJAJB6AZ.mjs → chunk-LPDXS2B2.mjs} +3 -3
- package/dist/{chunk-DJAJB6AZ.mjs.map → chunk-LPDXS2B2.mjs.map} +1 -1
- package/dist/{chunk-I5X7BX6I.mjs → chunk-M3JCHPK3.mjs} +127 -67
- package/dist/chunk-M3JCHPK3.mjs.map +1 -0
- package/dist/{chunk-RSAQ7WGF.mjs → chunk-M62L2N5A.mjs} +3 -3
- package/dist/{chunk-RSAQ7WGF.mjs.map → chunk-M62L2N5A.mjs.map} +1 -1
- package/dist/{chunk-G3L26XQ7.js → chunk-OIPG3EGM.js} +5 -5
- package/dist/{chunk-G3L26XQ7.js.map → chunk-OIPG3EGM.js.map} +1 -1
- package/dist/{chunk-X3MY4PL7.mjs → chunk-QAQTDHHT.mjs} +10 -14
- package/dist/chunk-QAQTDHHT.mjs.map +1 -0
- package/dist/{chunk-VFXLB5JU.mjs → chunk-QOKMH2TD.mjs} +3 -3
- package/dist/{chunk-VFXLB5JU.mjs.map → chunk-QOKMH2TD.mjs.map} +1 -1
- package/dist/{chunk-HXHRS3PX.mjs → chunk-RCB6HEHM.mjs} +3 -3
- package/dist/{chunk-HXHRS3PX.mjs.map → chunk-RCB6HEHM.mjs.map} +1 -1
- package/dist/{chunk-NAA5J2JM.js → chunk-RQROZLH3.js} +47 -51
- package/dist/chunk-RQROZLH3.js.map +1 -0
- package/dist/{chunk-PHE5MIW4.js → chunk-S5QKNXLQ.js} +10 -10
- package/dist/{chunk-PHE5MIW4.js.map → chunk-S5QKNXLQ.js.map} +1 -1
- package/dist/{chunk-MERNU3MY.mjs → chunk-SBTA6B6Y.mjs} +4 -4
- package/dist/{chunk-MERNU3MY.mjs.map → chunk-SBTA6B6Y.mjs.map} +1 -1
- package/dist/{chunk-CPRCBO6Y.mjs → chunk-TPDDSEL3.mjs} +3 -3
- package/dist/{chunk-CPRCBO6Y.mjs.map → chunk-TPDDSEL3.mjs.map} +1 -1
- package/dist/{chunk-C4JCJ66V.js → chunk-U4CYO4NG.js} +5 -5
- package/dist/{chunk-C4JCJ66V.js.map → chunk-U4CYO4NG.js.map} +1 -1
- package/dist/{chunk-BVSTYFFI.js → chunk-U5NFIHLY.js} +4 -4
- package/dist/{chunk-BVSTYFFI.js.map → chunk-U5NFIHLY.js.map} +1 -1
- package/dist/{chunk-4KTPBCB3.mjs → chunk-USQPRLSG.mjs} +8 -8
- package/dist/{chunk-4KTPBCB3.mjs.map → chunk-USQPRLSG.mjs.map} +1 -1
- package/dist/{chunk-RR6U3Z76.js → chunk-VDEQVXNV.js} +3 -3
- package/dist/{chunk-RR6U3Z76.js.map → chunk-VDEQVXNV.js.map} +1 -1
- package/dist/{chunk-WYUYAMFL.js → chunk-VMNPLCZB.js} +14 -14
- package/dist/{chunk-WYUYAMFL.js.map → chunk-VMNPLCZB.js.map} +1 -1
- package/dist/{chunk-5EVGWCUB.js → chunk-W7IAG5YD.js} +3 -3
- package/dist/{chunk-5EVGWCUB.js.map → chunk-W7IAG5YD.js.map} +1 -1
- package/dist/{chunk-K5Q7UYZM.mjs → chunk-WIWHM47B.mjs} +3 -3
- package/dist/{chunk-K5Q7UYZM.mjs.map → chunk-WIWHM47B.mjs.map} +1 -1
- package/dist/{chunk-KRU755E3.js → chunk-XZHR4E2D.js} +8 -8
- package/dist/{chunk-KRU755E3.js.map → chunk-XZHR4E2D.js.map} +1 -1
- package/dist/{chunk-EW2GKDDC.js → chunk-YACU35MY.js} +9 -9
- package/dist/{chunk-EW2GKDDC.js.map → chunk-YACU35MY.js.map} +1 -1
- package/dist/chunk-YMZNEDFP.js +39 -0
- package/dist/chunk-YMZNEDFP.js.map +1 -0
- package/dist/{chunk-QMVBKSTZ.mjs → chunk-YRKWJCML.mjs} +3 -3
- package/dist/{chunk-QMVBKSTZ.mjs.map → chunk-YRKWJCML.mjs.map} +1 -1
- package/dist/chunk-Z2URIOKG.mjs +36 -0
- package/dist/chunk-Z2URIOKG.mjs.map +1 -0
- package/dist/{chunk-S2LJ26WQ.mjs → chunk-ZEBOOUBP.mjs} +3 -3
- package/dist/{chunk-S2LJ26WQ.mjs.map → chunk-ZEBOOUBP.mjs.map} +1 -1
- package/dist/{chunk-QXD7AWGV.js → chunk-ZOBUA65N.js} +74 -17
- package/dist/chunk-ZOBUA65N.js.map +1 -0
- package/dist/cli/index.js +3 -3
- package/dist/cli/index.mjs +1 -1
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/commerce/index.js +57 -57
- package/dist/commerce/index.mjs +5 -5
- package/dist/engage/DesignRenderer.d.ts.map +1 -1
- package/dist/engage/EngageWidget.d.ts.map +1 -1
- package/dist/engage/element-rules.d.ts +39 -0
- package/dist/engage/element-rules.d.ts.map +1 -0
- package/dist/engage/index.js +9 -9
- package/dist/engage/index.mjs +6 -6
- package/dist/fleet/index.js +8 -8
- package/dist/fleet/index.mjs +4 -4
- package/dist/forms/index.js +13 -13
- package/dist/forms/index.mjs +7 -7
- package/dist/forms/server.js +2 -2
- package/dist/forms/server.mjs +1 -1
- package/dist/images/index.js +11 -11
- package/dist/images/index.mjs +4 -4
- package/dist/index.js +63 -63
- package/dist/index.mjs +9 -9
- package/dist/layout/client.js +8 -8
- package/dist/layout/client.mjs +7 -7
- package/dist/layout/index.js +10 -10
- package/dist/layout/index.mjs +8 -8
- package/dist/llms/index.d.ts +2 -0
- package/dist/llms/index.d.ts.map +1 -1
- package/dist/llms/index.js +129 -14
- package/dist/llms/index.js.map +1 -1
- package/dist/llms/index.mjs +115 -5
- package/dist/llms/index.mjs.map +1 -1
- package/dist/llms/revalidate.d.ts +3 -0
- package/dist/llms/revalidate.d.ts.map +1 -1
- package/dist/llms/seo-revalidate.d.ts +105 -0
- package/dist/llms/seo-revalidate.d.ts.map +1 -0
- package/dist/maps/index.js +5 -5
- package/dist/maps/index.mjs +3 -3
- package/dist/mcp/transport.d.ts +166 -0
- package/dist/mcp/transport.d.ts.map +1 -0
- package/dist/mcp/transport.js +137 -0
- package/dist/mcp/transport.js.map +1 -0
- package/dist/mcp/transport.mjs +123 -0
- package/dist/mcp/transport.mjs.map +1 -0
- package/dist/search/index.js +4 -4
- package/dist/search/index.mjs +3 -3
- package/dist/seo/client.js +5 -5
- package/dist/seo/client.mjs +4 -4
- package/dist/seo/index.js +5 -5
- package/dist/seo/index.mjs +4 -4
- package/dist/seo/register-sitemap-cli.js +1 -1
- package/dist/seo/register-sitemap-cli.mjs +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/dist/shared/build-entries.d.ts +7 -0
- package/dist/shared/build-entries.d.ts.map +1 -1
- package/dist/shared/request-guards.d.ts +27 -0
- package/dist/shared/request-guards.d.ts.map +1 -0
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sitemap/index.js +3 -3
- package/dist/sitemap/index.mjs +2 -2
- package/dist/sync/index.js +17 -17
- package/dist/sync/index.mjs +4 -4
- package/dist/{writeLLMsTxt-LYYC3ZSN.mjs → writeLLMsTxt-IYJILIU3.mjs} +3 -3
- package/dist/{writeLLMsTxt-XHLHJ5XY.js → writeLLMsTxt-SQG4B63X.js} +4 -4
- package/package.json +6 -1
- package/dist/EngageWidget-4WB74GQR.mjs +0 -12
- package/dist/EngageWidget-YONW3W3Z.js +0 -21
- package/dist/ManagedForm-KKJOIEFW.mjs +0 -16
- package/dist/ManagedForm-ZUPV4DPQ.js +0 -25
- package/dist/SitemapSync-5TKLHXFL.js +0 -18
- package/dist/SitemapSync-BIWCTMRJ.mjs +0 -9
- package/dist/chunk-6DCAMW62.mjs.map +0 -1
- package/dist/chunk-7JGD5TUI.mjs +0 -6
- package/dist/chunk-I5X7BX6I.mjs.map +0 -1
- package/dist/chunk-LSB3CWSB.js +0 -8
- package/dist/chunk-NAA5J2JM.js.map +0 -1
- package/dist/chunk-QAYB7NCH.js.map +0 -1
- package/dist/chunk-QII2TNKS.mjs.map +0 -1
- package/dist/chunk-QXD7AWGV.js.map +0 -1
- package/dist/chunk-X3MY4PL7.mjs.map +0 -1
- package/dist/chunk-YRCR7WY3.js +0 -65
- package/dist/chunk-YRCR7WY3.js.map +0 -1
- package/dist/chunk-ZL35JCDA.mjs +0 -61
- package/dist/chunk-ZL35JCDA.mjs.map +0 -1
- package/dist/chunk-ZR43XFUM.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/analytics/send-gate.ts","../src/analytics/WebVitals.tsx","../src/analytics/AnalyticsProvider.tsx"],"names":["resolveAnalyticsTarget","sonorFetch","sonorBeacon","usePathname","useRef","useEffect","propApiUrl","propApiKey","propSite","allowInFrame","allowLocalhost","debug","createContext","wordCount","useState","useMemo","getOrCreateVisitorId","getOrCreateSessionId","onPageLeave","useCallback","registerAnalyticsDispatcher","jsxs","jsx","useContext"],"mappings":"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","file":"chunk-QXD7AWGV.js","sourcesContent":["/**\n * @sonordev/site-kit/analytics — the ONE analytics send decision\n *\n * SINGLE SOURCE OF TRUTH for \"may this document report analytics, and where\n * to\". Every phone-home in the analytics module — page views, journey /\n * session rows, scroll depth, heatmap clicks, web vitals, custom events,\n * conversions, and the sitemap-validation read — resolves through\n * {@link resolveAnalyticsTarget} and sends through {@link analyticsSend} /\n * {@link analyticsBeacon}. Do NOT call sonorFetch/sonorBeacon directly from\n * this module, and do not re-fork the credential resolution below; the\n * eight hand-rolled copies this replaced are exactly how a rule gets fixed\n * in one place and left broken in seven (see CLAUDE.md, \"Code Hygiene\").\n * `send-gate.test.ts` fails the build if a new direct call appears.\n *\n * Fleet, client SitemapSync and Engage also consult this gate. Local browser\n * hosts are blocked regardless of configured production site identity. Node\n * build callers retain their existing behavior.\n *\n * It also checks:\n *\n * 1. IS THIS DOCUMENT SOMEONE ELSE'S EMBED? A site loaded in a cross-origin\n * iframe must not report traffic against its own Sonor project. The\n * visitor is not on that site; they are on whatever page framed it, and\n * every metric the frame produces is phantom traffic in the analytics its\n * owner reads (and, for an agency, reports to the client).\n *\n * 2. IS THERE A CREDENTIAL? Unchanged behavior — no key, no send.\n *\n * ─── Why this landed on 2026-09-08, and what was measured ──────────────────\n *\n * Upforge case studies embed each client's whole production site in three\n * eager iframes per study (agency-site-kit `DeviceTrifolio`), and\n * `securityHeaders`' DEFAULT_FRAME_ANCESTORS has allowed https://upforge.io\n * to frame every managed site since it was introduced. DeviceTrifolio's own\n * doc comment reasons that nobody is affected because its cross-origin load\n * detection can never succeed, so the screenshot overlay never fades. That is\n * true of the PIXELS and false of the JAVASCRIPT: the overlay is an opacity\n * layer over a live frame, so the embedded site loads, hydrates and runs its\n * analytics whether or not it is ever revealed.\n *\n * Measured in the Sonor analytics table before this change (2026-09-08), the\n * signature is unmistakable — from `analytics_page_views`, three views of `/`\n * sharing ONE session_id and ONE visitor_id, milliseconds apart, with\n * referrer `https://upforge.io/`:\n *\n * abbeyglenapts.com 20:02:13.852 / .900 / .921 (48ms, 21ms apart)\n * goldenmilenky.com 04:12:23.840 / .868 / 24.624\n * queencityriverboats 22:12:33.609 / .690 / .784\n *\n * Three loads of one page inside 70 milliseconds is not a person; it is the\n * desktop + tablet + mobile frames of one trifolio, sharing storage because\n * they share the embedded site's origin. 23 client sites carried this traffic\n * on the day of the fix, the oldest from 2026-06-11. The widening of\n * frame-ancestors to upforgelabs.com (upforge-nextjs 0c12be5) does not start\n * this problem — it multiplies one that was already live.\n *\n * ─── Same-origin frames are ALLOWED, deliberately ──────────────────────────\n *\n * The block is on CROSS-origin embedding, not on being framed at all. A site\n * embedding itself (a preview pane, a print view, an on-domain booking frame)\n * has a real visitor really on that site and no other tenant to pollute, so\n * it keeps reporting. How that is detected, and why `window.top` rather than\n * `window.parent`, lives with the primitive in `shared/frame.ts` — this file\n * owns the analytics POLICY, that file owns the frame FACT.\n */\n\nimport { sonorBeacon, sonorFetch } from '../shared/sonorFetch'\nimport { resolveAnalyticsTarget, type AnalyticsGateOptions } from '../shared/reporting-gate'\nexport {\n resolveAnalyticsTarget,\n __resetSendGate,\n isCrossOriginFrame,\n isFramed,\n isTopFrameSameOrigin,\n type AnalyticsGateOptions,\n type AnalyticsTarget,\n} from '../shared/reporting-gate'\n\n/**\n * POST an analytics payload. Resolves the gate itself and no-ops when it\n * says no — so a caller that forgets its own early bail still cannot send\n * from a blocked document. That belt-and-braces is the point: this is the\n * choke point, and it does not rely on every call site remembering.\n *\n * `retries: 0` by default — every analytics endpoint here is non-idempotent\n * from the client's side (a retried page view after a lost response\n * double-counts). Never resolves to a rejected promise; tracking must not\n * break a page.\n */\nexport async function analyticsSend(\n path: string,\n body: unknown,\n options: AnalyticsGateOptions & {\n retries?: number\n method?: string\n /** Let the request outlive the page (scroll depth flushed on unmount). */\n keepalive?: boolean\n } = {},\n): Promise<Response | null> {\n const target = resolveAnalyticsTarget(options)\n if (!target) return null\n try {\n return await sonorFetch(\n `${target.apiUrl}${path}`,\n {\n method: options.method || 'POST',\n headers: { 'Content-Type': 'application/json' },\n ...(options.keepalive ? { keepalive: true } : {}),\n ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n },\n { apiKey: target.apiKey, retries: options.retries ?? 0 },\n )\n } catch {\n // Network failures are expected and non-fatal — callers log under debug.\n return null\n }\n}\n\n/**\n * Unload-time twin of {@link analyticsSend}, through the keepalive beacon so\n * the credential stays in a header. Gated identically.\n */\nexport function analyticsBeacon(\n path: string,\n body: unknown,\n options: AnalyticsGateOptions = {},\n): void {\n const target = resolveAnalyticsTarget(options)\n if (!target) return\n sonorBeacon(`${target.apiUrl}${path}`, body, target.apiKey)\n}\n","/**\n * @sonordev/site-kit/analytics - Web Vitals Component\n *\n * Reports Core Web Vitals to the Sonor API, per route and with attribution.\n *\n * Two things make this more than a number stream (web-vitals v6):\n *\n * 1. SOFT NAVIGATIONS. Vitals used to finalize once per document, so on an\n * App Router site every metric was attributed to the LANDING path — a\n * visitor who arrived on / and browsed to /services produced no data for\n * /services at all. With `reportSoftNavs`, the library re-measures across\n * in-session route changes and tells us which URL each metric belongs to\n * (`metric.navigationURL`), so per-page vitals finally reflect the journey\n * rather than the entry point.\n *\n * 2. ATTRIBUTION. The attribution build answers \"what was slow\": the LCP\n * element and its image URL, the element an interaction hit and which\n * phase dominated INP, the node responsible for the largest layout shift.\n * A value says a page is slow; this says what to fix.\n *\n * Ratings come from the library (`metric.rating`) rather than thresholds\n * copied into this file, so they can't drift from the official buckets.\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { usePathname } from 'next/navigation'\nimport type { MetricWithAttribution } from 'web-vitals/attribution'\n// Same send gate as the rest of the analytics module — credential resolution\n// and the cross-origin-frame guard. This file used to carry its own copy of\n// the credential resolution; it does not any more, and must not again.\nimport { analyticsBeacon, analyticsSend } from './send-gate'\n\ninterface WebVitalsProps {\n apiUrl?: string\n apiKey?: string\n /** Sub-site identifier (matches AnalyticsConfig.site). Tagged on every Web Vital event. */\n site?: string\n /**\n * Report vitals from inside a cross-origin frame. Default false — see\n * send-gate.ts. AnalyticsProvider passes its own `allowInFrame` down, so a\n * site that opts in gets vitals too; standalone mounts pass their own.\n */\n allowInFrame?: boolean\n /** Report from localhost/loopback browser hosts. Default false. */\n allowLocalhost?: boolean\n debug?: boolean\n}\n\n/** Path a metric belongs to. Soft-nav metrics carry the URL they were\n measured for, which is NOT necessarily the route showing when they\n report — trusting the current pathname would misattribute them. */\nfunction pathForMetric(metric: MetricWithAttribution, fallback: string): string {\n const url = (metric as { navigationURL?: string }).navigationURL\n if (url) {\n try {\n return new URL(url, window.location.origin).pathname || fallback\n } catch {\n /* fall through */\n }\n }\n return fallback\n}\n\n/**\n * Trim the library's attribution to the fields that answer \"what do I fix?\".\n * Kept small on purpose: this rides on every metric report, and the raw\n * objects carry PerformanceEntry arrays we have no use for downstream.\n */\nfunction summarizeAttribution(metric: MetricWithAttribution): Record<string, unknown> | undefined {\n const a = metric.attribution as Record<string, any> | undefined\n if (!a) return undefined\n const pick = (keys: string[]) => {\n const out: Record<string, unknown> = {}\n for (const key of keys) {\n const value = a[key]\n if (value !== undefined && value !== null && value !== '') out[key] = value\n }\n return Object.keys(out).length ? out : undefined\n }\n switch (metric.name) {\n case 'LCP':\n // target = the element; url = its image; the rest is the load broken\n // into the four subparts you can actually act on.\n return pick([\n 'target',\n 'url',\n 'timeToFirstByte',\n 'resourceLoadDelay',\n 'resourceLoadDuration',\n 'elementRenderDelay',\n ])\n case 'INP':\n return pick([\n 'interactionTarget',\n 'interactionType',\n 'inputDelay',\n 'processingDuration',\n 'presentationDelay',\n 'loadState',\n ])\n case 'CLS':\n return pick(['largestShiftTarget', 'largestShiftValue', 'largestShiftTime', 'loadState'])\n case 'FCP':\n return pick(['timeToFirstByte', 'firstByteToFCP', 'loadState'])\n case 'TTFB':\n return pick(['waitingDuration', 'dnsDuration', 'connectionDuration', 'requestDuration'])\n default:\n return undefined\n }\n}\n\nexport function WebVitals({\n apiUrl: propApiUrl,\n apiKey: propApiKey,\n site: propSite,\n allowInFrame = false,\n allowLocalhost = false,\n debug = false,\n}: WebVitalsProps) {\n const pathname = usePathname()\n\n // Observers register exactly once (mount): re-registering per pathname\n // leaked listeners on every navigation and re-reported the landing page's\n // LCP under later routes. Soft-navigation support means one registration\n // now covers the whole session, and each metric says which URL it is for.\n const landingPathRef = useRef<string>(pathname || '/')\n const propsRef = useRef({ propApiUrl, propApiKey, propSite, allowInFrame, allowLocalhost, debug })\n propsRef.current = { propApiUrl, propApiKey, propSite, allowInFrame, allowLocalhost, debug }\n\n useEffect(() => {\n let cancelled = false\n let teardown: (() => void) | undefined\n\n // Dynamic import to avoid SSR issues; catch ChunkLoadError (e.g. Turbopack dev)\n import('web-vitals/attribution').then(({ onCLS, onLCP, onTTFB, onINP, onFCP }) => {\n if (cancelled) return\n const { propApiUrl, propApiKey, propSite, allowInFrame, allowLocalhost, debug } = propsRef.current\n\n // Metric instances already sent. Metrics can report repeatedly as a\n // page evolves (and once more at page hide); the id is stable per\n // instance, so this keeps the last value per instance without\n // double-counting.\n const sent = new Map<string, number>()\n\n const report = (metric: MetricWithAttribution, viaBeacon = false) => {\n if (sent.get(metric.id) === metric.value) return\n sent.set(metric.id, metric.value)\n\n const site =\n propSite ||\n (typeof window !== 'undefined'\n ? (window as { __SITE_KIT_SITE__?: string }).__SITE_KIT_SITE__ ||\n window.location.host\n : '')\n\n const data = {\n site,\n pagePath: pathForMetric(metric, landingPathRef.current),\n metricName: metric.name,\n metricValue: metric.value,\n // The library's own rating — no thresholds duplicated here.\n metricRating: metric.rating,\n metricDelta: metric.delta,\n metricId: metric.id,\n navigationType: metric.navigationType,\n attribution: summarizeAttribution(metric),\n }\n\n if (debug) console.log('[Analytics] Web Vital:', data)\n\n const endpoint = '/api/public/analytics/web-vitals'\n const gate = { apiUrl: propApiUrl, apiKey: propApiKey, allowInFrame, allowLocalhost, debug }\n if (viaBeacon) {\n // Page is going away: keepalive fetch keeps the credential in the\n // header (raw sendBeacon can't set one).\n analyticsBeacon(endpoint, data, gate)\n return\n }\n void analyticsSend(endpoint, data, gate)\n }\n\n // reportSoftNavs: measure across in-session route changes, not just the\n // initial document. Without it, everything below the entry page is dark.\n const opts = { reportSoftNavs: true }\n const pending: MetricWithAttribution[] = []\n const collect = (metric: MetricWithAttribution) => {\n pending.push(metric)\n report(metric)\n }\n\n onLCP(collect, opts)\n onCLS(collect, opts)\n onTTFB(collect, opts)\n onINP(collect, opts)\n onFCP(collect, opts)\n\n // At page hide, flush final values (CLS and INP in particular keep\n // changing until the very end) using the beacon path.\n const handleVisibilityChange = () => {\n if (document.visibilityState !== 'hidden') return\n for (const metric of pending) report(metric, true)\n }\n document.addEventListener('visibilitychange', handleVisibilityChange)\n\n teardown = () => {\n document.removeEventListener('visibilitychange', handleVisibilityChange)\n }\n }).catch((err) => {\n // ChunkLoadError in Turbopack/dev - Web Vitals are optional\n if (propsRef.current.debug) console.warn('[Analytics] Web Vitals import failed:', err)\n })\n\n return () => {\n cancelled = true\n teardown?.()\n }\n // Mount-once by design — see comment above. Props are read via propsRef.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n return null\n}\n","/**\n * @sonordev/site-kit/analytics - Analytics Provider\n * \n * Provides analytics context and automatic page view tracking.\n * All data goes through Portal API with API key auth - never Supabase directly.\n */\n\n'use client'\n\nimport React, { createContext, useContext, useEffect, useRef, useCallback, useMemo, useState } from 'react'\nimport { usePathname } from 'next/navigation'\nimport type { AnalyticsContextValue, TrackEventOptions, TrackConversionOptions } from './types'\nimport { registerAnalyticsDispatcher } from './dispatch'\nimport { WebVitals } from './WebVitals'\n// Single source of truth for visitor/session IDs (storage keys _sk_vid/_sk_sid)\n// — shared with SignalBridge and EngageWidget. Includes the crypto.randomUUID\n// fallback for older browsers; do NOT re-fork ID logic into this module.\nimport { getOrCreateVisitorId, getOrCreateSessionId } from '../shared/identity'\n// THE single analytics send decision — credential resolution AND the\n// cross-origin-frame guard, in one place. Every phone-home below goes through\n// it; this module must never call sonorFetch/sonorBeacon directly (send-gate.ts\n// explains why, and send-gate.test.ts enforces it).\nimport {\n analyticsBeacon,\n analyticsSend,\n resolveAnalyticsTarget,\n} from './send-gate'\nimport { onPageLeave } from '../shared/page-leave'\n\nconst AnalyticsContext = createContext<AnalyticsContextValue | null>(null)\n\n// ============================================\n// Utility Functions\n// ============================================\n\n/**\n * Schedule a callback to run during browser idle time.\n * Safari has no requestIdleCallback — use a short real delay there so the\n * work lands after the post-hydration burst instead of right inside it.\n */\nfunction scheduleIdleTask(callback: () => void, timeout = 2000): void {\n if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {\n ;(window as typeof window & { requestIdleCallback: (cb: () => void, opts?: { timeout: number }) => number }).requestIdleCallback(\n callback,\n { timeout }\n )\n } else {\n setTimeout(callback, 300)\n }\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\n \n const ua = navigator.userAgent\n if (/tablet|ipad|playbook|silk/i.test(ua)) return 'tablet'\n if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return 'mobile'\n return 'desktop'\n}\n\nfunction getBrowser(): string {\n if (typeof window === 'undefined') return 'unknown'\n \n const ua = navigator.userAgent\n if (ua.includes('Firefox')) return 'Firefox'\n if (ua.includes('Edg')) return 'Edge'\n if (ua.includes('Chrome')) return 'Chrome'\n if (ua.includes('Safari')) return 'Safari'\n if (ua.includes('Opera') || ua.includes('OPR')) return 'Opera'\n return 'Other'\n}\n\nfunction getOS(): string {\n if (typeof window === 'undefined') return 'unknown'\n \n const ua = navigator.userAgent\n if (ua.includes('Windows')) return 'Windows'\n if (ua.includes('Mac OS X') || ua.includes('Macintosh')) return 'macOS'\n if (ua.includes('iPhone') || ua.includes('iPad')) return 'iOS'\n if (ua.includes('Android')) return 'Android'\n if (ua.includes('Linux')) return 'Linux'\n if (ua.includes('CrOS')) return 'ChromeOS'\n return 'Other'\n}\n\nfunction getUserAgent(): string {\n if (typeof window === 'undefined') return ''\n return navigator.userAgent\n}\n\nfunction getUTMParams(): Record<string, string> {\n if (typeof window === 'undefined') return {}\n\n const params = new URLSearchParams(window.location.search)\n const utmParams: Record<string, string> = {}\n\n for (const key of ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']) {\n const value = params.get(key)\n if (value) utmParams[key] = value\n }\n\n return utmParams\n}\n\n/**\n * Ad click IDs (Google/Microsoft auto-tagging sends these with NO utm\n * params). The server classifies gclid/msclkid as paid search — without\n * them, ad traffic silently reports as organic/direct.\n */\nfunction getClickIds(): { gclid?: string; fbclid?: string; msclkid?: string } {\n if (typeof window === 'undefined') return {}\n const params = new URLSearchParams(window.location.search)\n const ids: { gclid?: string; fbclid?: string; msclkid?: string } = {}\n for (const key of ['gclid', 'fbclid', 'msclkid'] as const) {\n const value = params.get(key)\n if (value) ids[key] = value.slice(0, 200)\n }\n return ids\n}\n\n/**\n * Landing-page markers set per-route by <LandingPage campaign=\"...\">\n * (@sonordev/site-kit/landing). Read at SEND time so SPA navigations onto\n * and off a landing route tag exactly the right payloads.\n */\nfunction getLandingContext(): { pageKind?: string; landingCampaign?: string } {\n if (typeof window === 'undefined') return {}\n const w = window as { __SITE_KIT_PAGE_KIND__?: string; __SITE_KIT_CAMPAIGN__?: string }\n if (w.__SITE_KIT_PAGE_KIND__ !== 'landing' || !w.__SITE_KIT_CAMPAIGN__) return {}\n return { pageKind: 'landing', landingCampaign: w.__SITE_KIT_CAMPAIGN__ }\n}\n\n/** Browser locale + IANA timezone — coarse audience signals, no PII. */\nfunction getLocaleInfo(): { language?: string; timezone?: string } {\n if (typeof navigator === 'undefined') return {}\n let timezone: string | undefined\n try {\n timezone = Intl.DateTimeFormat().resolvedOptions().timeZone\n } catch {\n timezone = undefined\n }\n return { language: navigator.language || undefined, timezone }\n}\n\n/**\n * Promise wrapper around scheduleIdleTask so the metadata scrape can yield\n * back to the main thread between slices.\n */\nfunction nextIdleSlice(timeout = 1500): Promise<void> {\n return new Promise(resolve => scheduleIdleTask(resolve, timeout))\n}\n\n/**\n * Extract SEO metadata from the current page.\n * This enriches seo_pages with live data from the actual page.\n *\n * Split into three slices so no single idle callback runs the whole scrape as\n * one long task on throttled mobile CPUs (full-tree clones + textContent reads\n * are the expensive part):\n * 1. getLightPageMetadata — meta tags, canonical, H1 (cheap queries)\n * 2. getLinkPageMetadata — word count + link graph (whole-tree text + anchors)\n * 3. getHeavyPageMetadata — images w/ context, content clone, sections, FAQs\n * Callers yield via nextIdleSlice() between them and merge the results; the\n * merged payload shape is identical to the old monolithic getPageMetadata().\n */\nfunction getLightPageMetadata(): Record<string, any> {\n if (typeof document === 'undefined') return {}\n\n const getMeta = (name: string): string | null => {\n const el = document.querySelector(`meta[name=\"${name}\"], meta[property=\"${name}\"]`)\n return el?.getAttribute('content') || null\n }\n \n const getCanonical = (): string | null => {\n const el = document.querySelector('link[rel=\"canonical\"]')\n return el?.getAttribute('href') || null\n }\n \n const getRobots = (): string | null => {\n return getMeta('robots')\n }\n \n const getH1 = (): string | null => {\n const h1 = document.querySelector('h1')\n return h1?.textContent?.trim() || null\n }\n \n const getH1Count = (): number => {\n return document.querySelectorAll('h1').length\n }\n \n return {\n metaDescription: getMeta('description'),\n canonical: getCanonical(),\n robots: getRobots(),\n ogTitle: getMeta('og:title'),\n ogDescription: getMeta('og:description'),\n ogImage: getMeta('og:image'),\n h1: getH1(),\n h1Count: getH1Count(),\n }\n}\n\n/** Slice 2: image inventory — per-image ancestor walks + surrounding text. */\nfunction getMediaPageMetadata(): Record<string, any> {\n if (typeof document === 'undefined') return {}\n\n interface PageImageReport {\n src: string\n alt: string | null\n elementType: 'img' | 'Image' | 'ManagedImage' | 'picture' | 'background'\n slotId?: string\n position: 'hero' | 'content' | 'sidebar' | 'footer' | 'header' | 'unknown'\n width?: number\n height?: number\n surroundingText?: string\n }\n\n // Helper to determine element position in page\n const getElementPosition = (el: Element): PageImageReport['position'] => {\n let current: Element | null = el\n while (current) {\n const tag = current.tagName?.toLowerCase()\n const role = current.getAttribute('role')\n const className = current.className?.toString?.() || ''\n \n // Check for hero sections\n if (className.includes('hero') || current.id?.includes('hero')) return 'hero'\n if (tag === 'header' || role === 'banner') return 'header'\n if (tag === 'nav' || role === 'navigation') return 'header'\n if (tag === 'footer' || role === 'contentinfo') return 'footer'\n if (tag === 'aside' || role === 'complementary') return 'sidebar'\n if (tag === 'main' || tag === 'article' || role === 'main') return 'content'\n \n current = current.parentElement\n }\n return 'unknown'\n }\n\n // Get surrounding text context for an image\n const getSurroundingText = (el: Element): string => {\n // Find closest paragraph, figcaption, or container\n const container = el.closest('figure, p, div, section, article')\n if (!container) return ''\n \n // Get text excluding script/style content\n const text = container.textContent?.replace(/\\s+/g, ' ').trim() || ''\n return text.slice(0, 300) // Limit to 300 chars\n }\n\n const getImageDetails = (): PageImageReport[] => {\n const images = document.querySelectorAll('img, [data-managed-image]')\n const seen = new Set<string>()\n const results: PageImageReport[] = []\n \n images.forEach(el => {\n const img = el as HTMLImageElement\n const src = img.getAttribute('src') || img.getAttribute('data-src') || ''\n \n // Skip duplicates, data URIs, and empty src\n if (!src || src.startsWith('data:') || seen.has(src)) return\n seen.add(src)\n \n // Detect if it's a ManagedImage\n const slotId = img.getAttribute('data-slot-id') || undefined\n const isManagedImage = img.hasAttribute('data-managed-image') || !!slotId\n \n results.push({\n src,\n alt: img.alt || null,\n elementType: isManagedImage ? 'ManagedImage' : 'img',\n slotId,\n position: getElementPosition(img),\n width: img.naturalWidth || parseInt(img.getAttribute('width') || '0') || undefined,\n height: img.naturalHeight || parseInt(img.getAttribute('height') || '0') || undefined,\n surroundingText: getSurroundingText(img),\n })\n })\n \n return results\n }\n\n const getImageStats = (): { count: number; withoutAlt: number; images: PageImageReport[] } => {\n const images = getImageDetails()\n let withoutAlt = 0\n images.forEach(img => {\n if (!img.alt || img.alt.trim() === '') withoutAlt++\n })\n return { count: images.length, withoutAlt, images }\n }\n\n const imageStats = getImageStats()\n return {\n imagesCount: imageStats.count,\n imagesWithoutAlt: imageStats.withoutAlt,\n images: imageStats.images, // Full image details for SEO optimization\n }\n}\n\n/** Slice 3: word count, link graph, and content extraction for Signal AI. */\nfunction getContentPageMetadata(): Record<string, any> {\n if (typeof document === 'undefined') return {}\n\n const getWordCount = (): number => {\n // Get main content, fallback to body\n const main = document.querySelector('main, article, [role=\"main\"]') || document.body\n const text = main.textContent || ''\n return text.split(/\\s+/).filter(w => w.length > 0).length\n }\n\n interface InternalLink {\n targetPath: string\n anchorText: string\n position: 'header' | 'nav' | 'content' | 'footer' | 'sidebar' | 'unknown'\n isNofollow: boolean\n }\n \n const getLinkStats = (): { \n internal: number\n external: number\n internalLinks: InternalLink[]\n } => {\n const links = document.querySelectorAll('a[href]')\n const currentHost = window.location.host\n let internal = 0\n let external = 0\n const internalLinks: InternalLink[] = []\n \n // Helper to determine link position in page\n const getLinkPosition = (el: Element): InternalLink['position'] => {\n let current: Element | null = el\n while (current) {\n const tag = current.tagName?.toLowerCase()\n const role = current.getAttribute('role')\n \n if (tag === 'header' || role === 'banner') return 'header'\n if (tag === 'nav' || role === 'navigation') return 'nav'\n if (tag === 'footer' || role === 'contentinfo') return 'footer'\n if (tag === 'aside' || role === 'complementary') return 'sidebar'\n if (tag === 'main' || tag === 'article' || role === 'main') return 'content'\n \n current = current.parentElement\n }\n return 'unknown'\n }\n \n links.forEach(link => {\n const href = link.getAttribute('href') || ''\n const rel = link.getAttribute('rel') || ''\n const isNofollow = rel.includes('nofollow')\n \n let isInternal = false\n let targetPath = ''\n \n if (href.startsWith('/') && !href.startsWith('//')) {\n isInternal = true\n targetPath = href.split('?')[0].split('#')[0] // Remove query/hash\n } else if (href.startsWith('#')) {\n // Same page anchor - skip\n internal++\n return\n } else if (href.startsWith('http')) {\n try {\n const url = new URL(href)\n if (url.host === currentHost) {\n isInternal = true\n targetPath = url.pathname\n } else {\n external++\n }\n } catch {\n // Invalid URL\n }\n }\n \n if (isInternal && targetPath) {\n internal++\n // Normalize path\n if (!targetPath.startsWith('/')) targetPath = '/' + targetPath\n if (targetPath !== '/' && targetPath.endsWith('/')) {\n targetPath = targetPath.slice(0, -1)\n }\n \n internalLinks.push({\n targetPath,\n anchorText: (link.textContent || '').trim().slice(0, 200),\n position: getLinkPosition(link),\n isNofollow,\n })\n }\n })\n \n return { internal, external, internalLinks }\n }\n\n // ============================================\n // Content Extraction for Signal AI Analysis\n // ============================================\n \n interface HeadingInfo {\n level: number\n text: string\n id?: string\n }\n\n interface ContentSection {\n heading?: string\n headingLevel?: number\n text: string\n wordCount: number\n }\n\n interface FAQItem {\n question: string\n answer: string\n }\n\n const getHeadingStructure = (): HeadingInfo[] => {\n const headings: HeadingInfo[] = []\n const elements = document.querySelectorAll('h1, h2, h3, h4, h5, h6')\n \n elements.forEach(el => {\n const level = parseInt(el.tagName[1])\n const text = el.textContent?.trim() || ''\n if (text) {\n headings.push({\n level,\n text: text.slice(0, 200), // Limit length\n id: el.id || undefined\n })\n }\n })\n \n return headings\n }\n\n const getContentText = (): { text: string; hash: string } => {\n // Get main content area\n const main = document.querySelector('main, article, [role=\"main\"]') || document.body\n \n // Clone to avoid modifying the page\n const clone = main.cloneNode(true) as Element\n \n // Remove script, style, nav, header, footer from clone\n clone.querySelectorAll('script, style, nav, header, footer, [role=\"navigation\"], [role=\"banner\"], [role=\"contentinfo\"]').forEach(el => el.remove())\n \n // Get clean text\n let text = clone.textContent || ''\n text = text.replace(/\\s+/g, ' ').trim()\n \n // Limit to 10KB for storage\n text = text.slice(0, 10000)\n \n // Simple hash for change detection\n let hash = 0\n for (let i = 0; i < text.length; i++) {\n const chr = text.charCodeAt(i)\n hash = ((hash << 5) - hash) + chr\n hash |= 0\n }\n \n return { text, hash: hash.toString(16) }\n }\n\n const getContentSections = (): ContentSection[] => {\n const sections: ContentSection[] = []\n const main = document.querySelector('main, article, [role=\"main\"]') || document.body\n \n // Find all heading + content pairs\n const headings = main.querySelectorAll('h1, h2, h3')\n \n headings.forEach((heading, idx) => {\n const headingText = heading.textContent?.trim() || ''\n const level = parseInt(heading.tagName[1])\n \n // Get content between this heading and the next\n let content = ''\n let sibling = heading.nextElementSibling\n \n while (sibling && !['H1', 'H2', 'H3'].includes(sibling.tagName)) {\n if (sibling.tagName === 'P' || sibling.tagName === 'UL' || sibling.tagName === 'OL' || sibling.tagName === 'DIV') {\n content += (sibling.textContent || '') + ' '\n }\n sibling = sibling.nextElementSibling\n }\n \n content = content.replace(/\\s+/g, ' ').trim().slice(0, 1000)\n const wordCount = content.split(/\\s+/).filter(w => w.length > 0).length\n \n if (content && wordCount > 10) {\n sections.push({\n heading: headingText.slice(0, 200),\n headingLevel: level,\n text: content,\n wordCount\n })\n }\n })\n \n return sections.slice(0, 20) // Limit to 20 sections\n }\n\n const detectFAQContent = (): FAQItem[] => {\n const faqs: FAQItem[] = []\n \n // Look for FAQ schema\n const scripts = document.querySelectorAll('script[type=\"application/ld+json\"]')\n scripts.forEach(script => {\n try {\n const data = JSON.parse(script.textContent || '')\n if (data['@type'] === 'FAQPage' && data.mainEntity) {\n data.mainEntity.forEach((item: any) => {\n if (item['@type'] === 'Question') {\n faqs.push({\n question: item.name?.slice(0, 200) || '',\n answer: (item.acceptedAnswer?.text || '').slice(0, 500)\n })\n }\n })\n }\n } catch { /* ignore parse errors */ }\n })\n \n // Look for common FAQ patterns in HTML\n if (faqs.length === 0) {\n // details/summary pattern\n const details = document.querySelectorAll('details')\n details.forEach(detail => {\n const summary = detail.querySelector('summary')\n if (summary) {\n const question = summary.textContent?.trim() || ''\n const answer = detail.textContent?.replace(question, '').trim().slice(0, 500) || ''\n if (question && answer) {\n faqs.push({ question: question.slice(0, 200), answer })\n }\n }\n })\n \n // Accordion pattern (common class names)\n const accordionItems = document.querySelectorAll('[class*=\"accordion\"], [class*=\"faq\"], [data-faq]')\n accordionItems.forEach(item => {\n const questionEl = item.querySelector('[class*=\"question\"], [class*=\"title\"], button, h3, h4')\n const answerEl = item.querySelector('[class*=\"answer\"], [class*=\"content\"], [class*=\"panel\"], p')\n if (questionEl && answerEl) {\n const question = questionEl.textContent?.trim() || ''\n const answer = answerEl.textContent?.trim().slice(0, 500) || ''\n if (question && answer && question.includes('?')) {\n faqs.push({ question: question.slice(0, 200), answer })\n }\n }\n })\n }\n \n return faqs.slice(0, 20) // Limit to 20 FAQs\n }\n\n const detectLists = (): { type: 'ul' | 'ol'; items: string[] }[] => {\n const lists: { type: 'ul' | 'ol'; items: string[] }[] = []\n const main = document.querySelector('main, article, [role=\"main\"]') || document.body\n \n main.querySelectorAll('ul, ol').forEach(list => {\n const type = list.tagName.toLowerCase() as 'ul' | 'ol'\n const items: string[] = []\n \n list.querySelectorAll(':scope > li').forEach(li => {\n const text = li.textContent?.trim().slice(0, 200) || ''\n if (text) items.push(text)\n })\n \n // Only include substantial lists (3+ items)\n if (items.length >= 3) {\n lists.push({ type, items: items.slice(0, 10) })\n }\n })\n \n return lists.slice(0, 10) // Limit to 10 lists\n }\n\n const estimateReadingTime = (wordCount: number): number => {\n // Average reading speed: 200-250 words per minute\n return Math.ceil(wordCount / 225)\n }\n \n const linkStats = getLinkStats()\n const headingStructure = getHeadingStructure()\n const contentData = getContentText()\n const contentSections = getContentSections()\n const faqContent = detectFAQContent()\n const listContent = detectLists()\n const wordCount = getWordCount()\n\n return {\n wordCount,\n internalLinks: linkStats.internal,\n internalLinkTargets: linkStats.internalLinks, // Full link graph data\n externalLinks: linkStats.external,\n // Content analysis data\n content: {\n text: contentData.text,\n hash: contentData.hash,\n headings: headingStructure,\n sections: contentSections,\n faqs: faqContent.length > 0 ? faqContent : undefined,\n lists: listContent.length > 0 ? listContent : undefined,\n readingTime: estimateReadingTime(wordCount),\n },\n }\n}\n\n/**\n * Collect full page metadata across three idle slices so the scrape never\n * runs as one long main-thread task. `isStale` is checked between slices —\n * if the user SPA-navigates mid-scrape, later slices would read the NEW\n * page's DOM under the old path, so we stop and return only the slices\n * scraped while the page was still current (partial metadata beats corrupt\n * metadata, and the page view itself is still recorded).\n */\nasync function collectPageMetadata(isStale: () => boolean): Promise<Record<string, any>> {\n const light = getLightPageMetadata()\n await nextIdleSlice()\n if (isStale()) return light\n const media = getMediaPageMetadata()\n await nextIdleSlice()\n if (isStale()) return { ...light, ...media }\n const content = getContentPageMetadata()\n return { ...light, ...media, ...content }\n}\n\n// ============================================\n// Provider Component\n// ============================================\n\ninterface AnalyticsProviderProps {\n /**\n * Optional. AnalyticsProvider is normally mounted as a CHILDLESS sibling of\n * page content (see SiteKitClientProviders) — it tracks via effects and a\n * metadata ref, it does not need to enclose the page. When rendered\n * childless, the AnalyticsContext simply has no consumers; components that\n * need it should use `useAnalyticsOptional()`.\n */\n children?: React.ReactNode\n apiUrl?: string\n apiKey?: string\n trackPageViews?: boolean\n trackWebVitals?: boolean\n trackScrollDepth?: boolean\n trackClicks?: boolean\n trackJourneys?: boolean // NEW: Track user journey paths\n sessionTimeout?: number\n excludePaths?: string[]\n validateAgainstSitemap?: boolean // Log debug warnings for paths not in sitemap (informational only, never blocks tracking)\n debug?: boolean\n /** External visitor ID from shared identity (used by SiteKitLayout) */\n externalVisitorId?: string\n /** External session ID from shared identity (used by SiteKitLayout) */\n externalSessionId?: string\n /** Callback invoked with page metadata after each page view (used by Signal bridge) */\n onPageMetadata?: (metadata: Record<string, unknown>) => void\n /**\n * Sub-site identifier (e.g. `ohiopowerstudies.com`). Every event tagged with\n * this string so a single Sonor project can host many sites and the\n * dashboard can filter / roll up per site. Normally passed in by\n * SiteKitClientProviders; if omitted, falls back to\n * `window.__SITE_KIT_SITE__` then `window.location.host`.\n */\n site?: string\n /**\n * Report analytics even when this page is rendered inside a CROSS-ORIGIN\n * iframe. Default false: an embedded page's traffic belongs to whoever\n * framed it, not to this project (see send-gate.ts for the measurement that\n * prompted this). Turn it on only for a site deliberately distributed as an\n * embed, where the frame is the product.\n *\n * Same-origin frames are unaffected — they always report.\n */\n allowInFrame?: boolean\n /** Report from localhost/loopback browser hosts. Default false. */\n allowLocalhost?: boolean\n}\n\nexport function AnalyticsProvider({\n children,\n apiUrl: propApiUrl,\n apiKey: propApiKey,\n trackPageViews = true,\n trackWebVitals = true,\n trackScrollDepth = true,\n trackClicks = true,\n trackJourneys = true, // NEW: Enable journey tracking by default\n sessionTimeout = 30,\n excludePaths = [],\n validateAgainstSitemap = false,\n debug = false,\n externalVisitorId,\n externalSessionId,\n onPageMetadata,\n site: propSite,\n allowInFrame = false,\n allowLocalhost = false,\n}: AnalyticsProviderProps) {\n const pathname = usePathname()\n // Use state to track query string changes instead of useSearchParams (avoids Suspense requirement)\n const [queryString, setQueryString] = useState('')\n\n // Sub-site identifier — every event body below carries this so a single\n // Sonor project can host many sites and the dashboard can filter / roll up\n // per site. Resolution: prop > window global (set by SiteKitClientProviders)\n // > window.location.host. Empty string is acceptable (older clients).\n const site =\n propSite ||\n (typeof window !== 'undefined'\n ? (window as { __SITE_KIT_SITE__?: string }).__SITE_KIT_SITE__ ||\n window.location.host\n : '')\n\n // Everything the send gate needs, resolved once. Every effect and callback\n // below passes THIS object to resolveAnalyticsTarget / analyticsSend /\n // analyticsBeacon — there is no second place that decides whether a send\n // may happen, and no second copy of the prop-over-global fallback.\n const gate = useMemo(\n () => ({ apiUrl: propApiUrl, apiKey: propApiKey, allowInFrame, allowLocalhost, debug }),\n [propApiUrl, propApiKey, allowInFrame, allowLocalhost, debug],\n )\n\n // Listen for URL changes including query string\n useEffect(() => {\n if (typeof window === 'undefined') return\n \n // Set initial query string\n setQueryString(window.location.search)\n \n // Listen for popstate (back/forward navigation)\n const handlePopState = () => {\n setQueryString(window.location.search)\n }\n \n window.addEventListener('popstate', handlePopState)\n return () => window.removeEventListener('popstate', handlePopState)\n }, [pathname]) // Re-check when pathname changes\n \n const visitorIdRef = useRef<string>('')\n const sessionIdRef = useRef<string>('')\n const lastPathRef = useRef<string>('')\n const validPathsRef = useRef<Set<string> | null>(null)\n const sitemapLoadedRef = useRef<boolean>(false)\n \n // Journey tracking state\n const journeyStartTimeRef = useRef<number>(0)\n const pageEnterTimeRef = useRef<number>(0)\n const currentScrollDepthRef = useRef<number>(0)\n \n // Initialize IDs — use external (shared) IDs when provided by SiteKitLayout\n useEffect(() => {\n visitorIdRef.current = externalVisitorId || getOrCreateVisitorId()\n sessionIdRef.current = externalSessionId || getOrCreateSessionId(sessionTimeout)\n }, [sessionTimeout, externalVisitorId, externalSessionId])\n \n // Fetch valid pages from seo_pages (populated by SitemapSync from SEO module)\n useEffect(() => {\n if (!validateAgainstSitemap) {\n if (debug) console.log('[Analytics] Page validation disabled')\n return\n }\n \n const fetchValidPages = async () => {\n try {\n // Fetch seo_pages which is the canonical source of truth\n // (populated by SitemapSync component from the SEO module).\n // Gated like every other call: a cross-origin frame should not spend\n // the project's rate limit on data it will never report against.\n const response = await analyticsSend(\n '/api/public/seo/pages',\n undefined,\n { ...gate, method: 'GET', retries: 2 },\n )\n if (!response) {\n if (debug) console.warn('[Analytics] Page validation skipped (no key, or embedded)')\n sitemapLoadedRef.current = true\n return\n }\n\n if (response.ok) {\n const data = await response.json()\n const pages = data?.pages || []\n validPathsRef.current = new Set(\n pages.map((p: any) => p.path).filter(Boolean)\n )\n sitemapLoadedRef.current = true\n\n if (debug) {\n console.log('[Analytics] Loaded', validPathsRef.current.size, 'valid pages from seo_pages')\n }\n } else {\n sitemapLoadedRef.current = true // Mark as loaded even on failure so we don't block\n if (debug) {\n console.error('[Analytics] Pages fetch failed:', response.statusText)\n }\n }\n } catch (error) {\n sitemapLoadedRef.current = true // Mark as loaded even on error so we don't block\n if (debug) console.error('[Analytics] Error fetching valid pages:', error)\n }\n }\n \n fetchValidPages()\n }, [gate, validateAgainstSitemap, debug])\n \n // Track page views\n useEffect(() => {\n if (!trackPageViews) return\n if (!pathname) return\n\n // Normalize path: strip trailing slashes (except root)\n const normalizedPath = pathname === '/' ? '/' : pathname.replace(/\\/+$/, '')\n\n if (excludePaths.some(p => normalizedPath.startsWith(p))) return\n if (normalizedPath === lastPathRef.current) return\n\n lastPathRef.current = normalizedPath\n \n const trackPageView = async () => {\n // Resolve BEFORE the metadata scrape: no point burning three idle\n // slices of the visitor's main thread on a DOM scrape whose result can\n // never be sent (no key, or a cross-origin embed).\n if (!resolveAnalyticsTarget(gate)) {\n if (debug) console.warn('[Analytics] Page view skipped (no key, or embedded)')\n return\n }\n\n const utmParams = getUTMParams()\n // Captured before the sliced scrape yields — the title must belong to\n // THIS page even if the user navigates while slices are pending.\n const pageTitle = document.title\n // Sliced scrape: yields to the main thread between phases; on SPA\n // navigation mid-scrape it returns only the slices read from this\n // page's DOM (the page view still records, with partial metadata).\n const pageMetadata = await collectPageMetadata(\n () => lastPathRef.current !== normalizedPath,\n )\n\n // Share page metadata with Signal bridge via callback\n if (onPageMetadata) {\n onPageMetadata(pageMetadata)\n }\n\n const clickIds = getClickIds()\n const locale = getLocaleInfo()\n const landing = getLandingContext()\n const pageView = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n pageKind: landing.pageKind,\n landingCampaign: landing.landingCampaign,\n pagePath: normalizedPath,\n pageTitle,\n referrer: document.referrer || null,\n deviceType: getDeviceType(),\n browser: getBrowser(),\n os: getOS(),\n userAgent: getUserAgent(),\n language: locale.language,\n timezone: locale.timezone,\n utmSource: utmParams.utm_source,\n utmMedium: utmParams.utm_medium,\n utmCampaign: utmParams.utm_campaign,\n utmTerm: utmParams.utm_term,\n utmContent: utmParams.utm_content,\n gclid: clickIds.gclid,\n fbclid: clickIds.fbclid,\n msclkid: clickIds.msclkid,\n // SEO enrichment data - updates seo_pages\n seo: pageMetadata,\n }\n\n if (debug) {\n console.log('[Analytics] Page view:', pageView)\n }\n\n // retries: 0 (the gate's default) — a retried page-view after a lost\n // response would double-count.\n const response = await analyticsSend('/api/public/analytics/page-view', pageView, gate)\n\n if (debug && response) {\n console.log('[Analytics] Page view response:', response.status, response.statusText)\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n console.error('[Analytics] Error tracking page view:', response.status, response.statusText, text)\n }\n }\n\n // Informational sitemap validation (never blocks tracking)\n if (validateAgainstSitemap && debug) {\n if (sitemapLoadedRef.current && validPathsRef.current && validPathsRef.current.size > 0) {\n if (!validPathsRef.current.has(normalizedPath)) {\n console.log('[Analytics] Note: path not found in sitemap (tracked anyway):', normalizedPath)\n }\n } else if (!sitemapLoadedRef.current) {\n console.log('[Analytics] Sitemap not yet loaded, tracked anyway:', normalizedPath)\n }\n }\n }\n \n // Use requestIdleCallback to defer tracking until browser is idle\n scheduleIdleTask(() => trackPageView())\n }, [pathname, queryString, gate, trackPageViews, excludePaths, debug, validateAgainstSitemap])\n\n // ============================================\n // Journey Path Tracking\n // ============================================\n useEffect(() => {\n if (!trackJourneys) return\n if (!pathname) return\n if (typeof window === 'undefined') return\n\n // Resolve up front so an embedded page never registers the pagehide\n // listener below — the guard should save the work, not just the request.\n if (!resolveAnalyticsTarget(gate)) return\n\n const now = Date.now()\n const previousPath = lastPathRef.current\n const previousDuration = pageEnterTimeRef.current > 0 \n ? Math.round((now - pageEnterTimeRef.current) / 1000) \n : 0\n const previousScrollDepth = currentScrollDepthRef.current\n\n // Update tracking refs for next navigation\n pageEnterTimeRef.current = now\n currentScrollDepthRef.current = 0\n\n // Determine if this is a new session or continuation\n const isNewSession = !previousPath || journeyStartTimeRef.current === 0\n \n if (isNewSession) {\n journeyStartTimeRef.current = now\n }\n\n const trackJourneyStep = async () => {\n // Landing markers ride on EVERY session action (not just 'start'): a\n // visitor can enter elsewhere and reach the landing page mid-session —\n // the server stamps the campaign first-touch either way.\n const landing = getLandingContext()\n const sessionData: Record<string, any> = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n action: isNewSession ? 'start' : 'update',\n lastPage: pathname,\n userAgent: getUserAgent(),\n pageKind: landing.pageKind,\n landingCampaign: landing.landingCampaign,\n // Journey step data\n journeyStep: {\n page: pathname,\n timestamp: new Date().toISOString(),\n },\n }\n\n // Include previous page duration when navigating\n if (!isNewSession && previousDuration > 0) {\n sessionData.previousPageDuration = previousDuration\n sessionData.previousPageScrollDepth = previousScrollDepth\n }\n\n // Include first page for new sessions\n if (isNewSession) {\n sessionData.firstPage = pathname\n const utmParams = getUTMParams()\n const clickIds = getClickIds()\n sessionData.referrer = document.referrer || null\n sessionData.utmSource = utmParams.utm_source\n sessionData.utmMedium = utmParams.utm_medium\n sessionData.utmCampaign = utmParams.utm_campaign\n sessionData.utmTerm = utmParams.utm_term\n sessionData.utmContent = utmParams.utm_content\n sessionData.gclid = clickIds.gclid\n sessionData.fbclid = clickIds.fbclid\n sessionData.msclkid = clickIds.msclkid\n sessionData.screenWidth = window.screen.width\n sessionData.screenHeight = window.screen.height\n }\n\n if (debug) {\n console.log('[Analytics] Journey step:', sessionData)\n }\n\n await analyticsSend('/api/public/analytics/session', sessionData, gate)\n }\n\n scheduleIdleTask(() => trackJourneyStep())\n\n // Track session end when the page is being hidden/unloaded. `pagehide`\n // (not `beforeunload`): beforeunload never fires on iOS Safari and makes\n // pages ineligible for the back/forward cache in Firefox.\n const handleUnload = () => {\n const duration = Math.round((Date.now() - journeyStartTimeRef.current) / 1000)\n // keepalive transport keeps the key in headers — never in the URL,\n // where server/CDN access logs would capture it.\n analyticsBeacon(\n '/api/public/analytics/session',\n {\n sessionId: sessionIdRef.current,\n site,\n action: 'end',\n duration,\n lastPage: pathname,\n previousPageDuration: Math.round((Date.now() - pageEnterTimeRef.current) / 1000),\n previousPageScrollDepth: currentScrollDepthRef.current,\n },\n gate,\n )\n }\n\n window.addEventListener('pagehide', handleUnload)\n\n return () => {\n window.removeEventListener('pagehide', handleUnload)\n }\n }, [pathname, gate, trackJourneys, debug])\n\n // ============================================\n // Scroll Depth Tracking\n // ============================================\n useEffect(() => {\n if (typeof window === 'undefined') return\n \n if (debug) console.log('[Analytics] Scroll tracking setup:', { trackScrollDepth, hasApiKey: !!propApiKey })\n \n if (!trackScrollDepth) return\n\n // Resolve before attaching the scroll listener: an embedded page should\n // not run scroll math on every frame for data it cannot report.\n if (!resolveAnalyticsTarget(gate)) {\n if (debug) console.warn('[Analytics] Scroll tracking disabled (no key, or embedded)')\n return\n }\n\n if (debug) console.log('[Analytics] Scroll tracking enabled for:', pathname)\n\n let maxDepth = 0\n let startTime = Date.now()\n let milestone25: number | null = null\n let milestone50: number | null = null\n let milestone75: number | null = null\n let milestone100: number | null = null\n let hasTracked = false\n\n const calculateScrollDepth = () => {\n const scrollTop = window.scrollY\n const docHeight = document.documentElement.scrollHeight\n const winHeight = window.innerHeight\n const scrollableHeight = docHeight - winHeight\n \n if (scrollableHeight <= 0) return 100\n return Math.min(100, Math.round((scrollTop / scrollableHeight) * 100))\n }\n\n const handleScroll = () => {\n const depth = calculateScrollDepth()\n const elapsed = (Date.now() - startTime) / 1000\n\n if (depth > maxDepth) {\n maxDepth = depth\n currentScrollDepthRef.current = depth // Update ref for journey tracking\n if (debug && depth % 25 === 0) console.log('[Analytics] Scroll milestone:', depth + '%')\n \n if (depth >= 25 && milestone25 === null) milestone25 = elapsed\n if (depth >= 50 && milestone50 === null) milestone50 = elapsed\n if (depth >= 75 && milestone75 === null) milestone75 = elapsed\n if (depth >= 100 && milestone100 === null) milestone100 = elapsed\n }\n }\n\n const sendScrollData = async (useBeacon = false) => {\n if (hasTracked || maxDepth === 0) return\n hasTracked = true\n\n const totalTime = (Date.now() - startTime) / 1000\n \n const payload = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n pagePath: pathname,\n maxDepthPercent: maxDepth,\n timeTo25: milestone25,\n timeTo50: milestone50,\n timeTo75: milestone75,\n timeTo100: milestone100,\n totalTimeSeconds: totalTime,\n deviceType: getDeviceType(),\n }\n\n // Unload sends go through the beacon (keepalive fetch) so the key stays\n // in headers instead of the URL; regular sends use the shared transport.\n if (useBeacon) {\n analyticsBeacon('/api/public/analytics/scroll-depth', payload, gate)\n } else {\n // keepalive: this also runs on unmount (SPA navigation), where a\n // plain fetch would be cancelled with the outgoing page.\n await analyticsSend('/api/public/analytics/scroll-depth', payload, {\n ...gate,\n keepalive: true,\n })\n }\n if (debug) console.log('[Analytics] Scroll depth:', { maxDepth, totalTime, useBeacon })\n }\n\n // Reset on page change\n maxDepth = 0\n startTime = Date.now()\n milestone25 = null\n milestone50 = null\n milestone75 = null\n milestone100 = null\n hasTracked = false\n\n window.addEventListener('scroll', handleScroll, { passive: true })\n\n // Capture the current position immediately — the provider mounts deferred\n // (idle/first-interaction), so the user may have already scrolled.\n handleScroll()\n\n // Send on page hide/unload via the beacon path (shared/page-leave.ts).\n const stopLeaveListener = onPageLeave(() => sendScrollData(true))\n\n return () => {\n window.removeEventListener('scroll', handleScroll)\n stopLeaveListener()\n sendScrollData(false) // Send when component unmounts (navigation) - can use fetch here\n }\n }, [pathname, gate, trackScrollDepth, debug])\n\n // ============================================\n // Click/Heatmap Tracking\n // ============================================\n useEffect(() => {\n if (!trackClicks) return\n if (typeof window === 'undefined') return\n\n // Resolve before attaching the document-wide click listener — an embedded\n // page should not run element inspection on every click for nothing.\n if (!resolveAnalyticsTarget(gate)) return\n\n const handleClick = async (e: MouseEvent) => {\n const target = e.target as HTMLElement\n if (!target) return\n\n const docHeight = document.documentElement.scrollHeight\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n // Calculate click position as percentage\n // Both axes in document space (pageX over the document's scrollWidth,\n // pageY over its scrollHeight) so heat positions reconstruct on the\n // page, not the viewport. pageX / viewportWidth overflowed 100% on\n // any horizontally-scrolled page.\n const docWidth = document.documentElement.scrollWidth || viewportWidth\n const xPercent = Math.round((e.pageX / docWidth) * 100)\n const yPercent = Math.round(((e.pageY) / docHeight) * 100)\n\n // Get element info\n const elementTag = target.tagName.toLowerCase()\n const elementId = target.id || null\n const elementClass = target.className && typeof target.className === 'string' \n ? target.className.split(' ').slice(0, 3).join(' ') \n : null\n const elementText = target.textContent?.slice(0, 50) || null\n\n const clickData = {\n sessionId: sessionIdRef.current,\n site,\n pagePath: pathname,\n xPercent,\n yPercent,\n xAbsolute: e.pageX,\n yAbsolute: e.pageY,\n viewportWidth,\n viewportHeight,\n pageHeight: docHeight,\n elementTag,\n elementId,\n elementClass,\n elementText,\n }\n\n if (debug) console.log('[Analytics] Click:', clickData)\n\n scheduleIdleTask(() => {\n void analyticsSend('/api/public/analytics/heatmap-click', clickData, gate)\n }, 500)\n }\n\n document.addEventListener('click', handleClick, { passive: true })\n\n return () => {\n document.removeEventListener('click', handleClick)\n }\n }, [pathname, gate, trackClicks, debug])\n\n // Track event function - uses idle callback for non-critical events\n const trackEvent = useCallback((options: TrackEventOptions) => {\n const doTrack = async () => {\n const event = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n eventName: options.name,\n eventCategory: options.category,\n eventLabel: options.label,\n eventValue: options.value,\n properties: options.properties,\n pagePath: pathname,\n }\n \n if (debug) {\n console.log('[Analytics] Event:', event)\n }\n \n const response = await analyticsSend('/api/public/analytics/event', event, gate)\n if (response && !response.ok && debug) {\n console.error('[Analytics] Error tracking event:', response.statusText)\n }\n }\n\n // Defer event tracking to idle time\n scheduleIdleTask(doTrack, 1000)\n }, [gate, site, pathname, debug])\n \n // Track conversion function - runs immediately (conversions are high priority)\n const trackConversion = useCallback((options: TrackConversionOptions) => {\n const doTrack = async () => {\n const conversion = {\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n site,\n conversionType: options.type,\n value: options.value,\n currency: options.currency,\n metadata: options.metadata,\n pagePath: pathname,\n referrer: document.referrer || null,\n deviceType: getDeviceType(),\n }\n \n if (debug) {\n console.log('[Analytics] Conversion:', conversion)\n }\n \n const response = await analyticsSend('/api/public/analytics/conversion', conversion, gate)\n if (response && !response.ok && debug) {\n console.error('[Analytics] Error tracking conversion:', response.statusText)\n }\n }\n\n // Conversions run immediately (not deferred) since they're high-value events\n doTrack()\n }, [gate, site, pathname, debug])\n \n // Bridge for code outside this provider's tree (the childless-sibling\n // mount pattern leaves the whole page un-provided): register the REAL\n // track functions with the standalone dispatch module, which queues any\n // calls made before this (idle-deferred) provider mounted.\n useEffect(() => {\n registerAnalyticsDispatcher({ trackEvent, trackConversion })\n return () => registerAnalyticsDispatcher(null)\n }, [trackEvent, trackConversion])\n\n const contextValue = useMemo<AnalyticsContextValue>(() => ({\n trackEvent,\n trackConversion,\n sessionId: sessionIdRef.current,\n visitorId: visitorIdRef.current,\n }), [trackEvent, trackConversion])\n \n return (\n <AnalyticsContext.Provider value={contextValue}>\n {trackWebVitals && (\n <WebVitals\n apiUrl={propApiUrl}\n apiKey={propApiKey}\n site={site}\n allowInFrame={allowInFrame}\n allowLocalhost={allowLocalhost}\n debug={debug}\n />\n )}\n {children}\n </AnalyticsContext.Provider>\n )\n}\n\n// ============================================\n// Hooks\n// ============================================\n\nexport function useAnalytics(): AnalyticsContextValue {\n const context = useContext(AnalyticsContext)\n if (!context) {\n throw new Error('useAnalytics must be used within an AnalyticsProvider')\n }\n return context\n}\n\n/**\n * Safe version of useAnalytics that returns null when used outside of AnalyticsProvider.\n * Use this in components that may be rendered without an AnalyticsProvider in the tree.\n */\nexport function useAnalyticsOptional(): AnalyticsContextValue | null {\n return useContext(AnalyticsContext)\n}\n\nexport function useTrackEvent() {\n const { trackEvent, trackConversion } = useAnalytics()\n return { trackEvent, trackConversion }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/articles/public-reads.ts","../src/articles/excerpt.ts","../src/articles/news-sitemap.ts","../src/articles/server-core.ts"],"names":["description"],"mappings":";;;;;;;AAgCA,eAAsB,mBACpB,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,IAClB,IAAA,EACyB;AACzB,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,aAAA,CAAc,CAAA,EAAG,MAAM,CAAA,uBAAA,EAA0B,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,EAAG;AAAA,MAC3F,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,MAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,EAAA;AAAG,KACxB,CAAA;AACD,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,IAAI,SAAS,MAAA,KAAW,GAAA,UAAa,KAAA,CAAM,kCAAA,EAAoC,SAAS,UAAU,CAAA;AAClG,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,KAAK,IAAA,IAAQ,IAAA;AAAA,EACtB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,mCAAmC,KAAK,CAAA;AACtD,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGA,eAAsB,sBAAA,CAAuB,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAK,EAAkD;AACpH,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,aAAA,CAAc,GAAG,MAAM,CAAA,2BAAA,CAAA,EAA+B,IAAI,CAAA,EAAG;AAAA,MACxF,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,MAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,GAAA;AAAI,KACzB,CAAA;AACD,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,EAAC;AAC1B,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,IAAA,CAAK,cAAc,EAAC;AAAA,EAC7B,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,yCAAyC,KAAK,CAAA;AAC5D,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAcA,eAAsB,oBAAA,CACpB,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,IAClB,aAAA,EACA,KAAA,EACA,KAAA,GAAiC,EAAC,EACd;AACpB,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,CAAA,EAAG,MAAM,CAAA,wBAAA,CAAA,EAA4B;AAAA,MAChE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,aAAa,MAAA,EAAO;AAAA,MACnE,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,YAAA,CAAa,EAAE,iBAAiB,aAAA,EAAe,KAAA,EAAM,EAAG,IAAI,CAAC,CAAA;AAAA,MAClF,GAAI,KAAA,CAAM,UAAA,KAAe,KAAA,CAAA,GAAY,EAAE,IAAA,EAAM,EAAE,UAAA,EAAY,KAAA,CAAM,UAAA,EAAW,EAAE,GAAI;AAAC,KACpF,CAAA;AACD,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,OAAA,CAAQ,KAAA,CAAM,2CAAA,EAA6C,QAAA,CAAS,UAAU,CAAA;AAC9E,MAAA,OAAO,EAAC;AAAA,IACV;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,IAAA,CAAK,SAAS,EAAC;AAAA,EACxB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,4CAA4C,KAAK,CAAA;AAC/D,IAAA,OAAO,EAAC;AAAA,EACV;AACF;;;ACtFO,SAAS,eAAA,CAAgB,GAAA,EAAgC,SAAA,GAAY,GAAA,EAAa;AACvF,EAAA,IAAI,CAAC,KAAK,OAAO,EAAA;AACjB,EAAA,IAAI,IAAA,GAAO,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,EAAK;AAG5B,EAAA,IAAI,KAAK,UAAA,CAAW,GAAG,KAAK,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,EAAG;AAChD,IAAA,MAAM,YAAA,GAAe,CAAC,KAAA,KAA2B;AAC/C,MAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAI,KAAA,GAAQ,CAAC,KAAK,CAAA;AAClD,MAAA,OAAO,KACJ,GAAA,CAAI,CAAC,MAAO,CAAA,IAAK,OAAO,MAAM,QAAA,GAAY,CAAA,CAAU,WAAY,CAAA,CAAU,OAAA,IAAW,KAAK,EAAG,CAAA,CAC7F,OAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,IACb,CAAA;AACA,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,IAC1B,CAAA,CAAA,MAAQ;AAEN,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,mBAAmB,EAAE,CAAC,CAAA;AAC/C,MAAA,IAAI;AACF,QAAA,MAAA,GAAS,IAAA,CAAK,MAAM,KAAA,CAAM,QAAA,CAAS,GAAG,CAAA,GAAI,KAAA,GAAQ,CAAA,EAAG,KAAK,CAAA,CAAA,CAAG,CAAA;AAAA,MAC/D,CAAA,CAAA,MAAQ;AACN,QAAA,MAAA,GAAS,IAAA;AAAA,MACX;AAAA,IACF;AACA,IAAA,IAAA,GAAO,SAAS,YAAA,CAAa,MAAM,IAAI,IAAA,CAAK,OAAA,CAAQ,aAAa,GAAG,CAAA;AAAA,EACtE;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAA,CACX,OAAA,CAAQ,iBAAA,EAAmB,GAAG,CAAA,CAC9B,OAAA,CAAQ,uBAAA,EAAyB,GAAG,CAAA,CACpC,OAAA,CAAQ,wBAAA,EAA0B,IAAI,CAAA,CACtC,OAAA,CAAQ,cAAA,EAAgB,EAAE,CAAA,CAC1B,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA,CACtB,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CACnB,OAAA,CAAQ,MAAA,EAAQ,GAAG,EACnB,IAAA,EAAK;AAER,EAAA,IAAI,KAAA,CAAM,MAAA,IAAU,SAAA,EAAW,OAAO,KAAA;AAGtC,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,YAAY,CAAC,CAAA;AAC3C,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,YAAY,IAAI,CAAA,EAAG,MAAA,CAAO,WAAA,CAAY,IAAI,CAAA,EAAG,MAAA,CAAO,WAAA,CAAY,IAAI,CAAC,CAAA;AACtG,EAAA,IAAI,QAAA,GAAW,SAAA,GAAY,GAAA,EAAK,OAAO,MAAA,CAAO,MAAM,CAAA,EAAG,QAAA,GAAW,CAAC,CAAA,CAAE,IAAA,EAAK;AAE1E,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA;AACpC,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,WAAA,CAAY,GAAG,CAAA;AACrC,EAAA,OAAO,CAAA,EAAA,CAAI,SAAA,GAAY,SAAA,GAAY,GAAA,GAAM,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA,GAAI,GAAA,EAAK,OAAA,CAAQ,cAAA,EAAgB,EAAE,CAAC,CAAA,MAAA,CAAA;AACrG;;;ACrDO,IAAM,sBAAA,GAAyB,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK;AAElD,IAAM,qBAAA,GAAwB;AAQ9B,IAAM,kBAAA,GAAqB;AAe3B,SAAS,UAAU,IAAA,EAAsB;AAC9C,EAAA,OAAO,KACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CACrB,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,EACpB,OAAA,CAAQ,IAAA,EAAM,QAAQ,CAAA,CACtB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B;AAMO,SAAS,MAAM,IAAA,EAAsB;AAC1C,EAAA,OAAO,CAAA,SAAA,EAAY,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,iBAAiB,CAAC,CAAA,GAAA,CAAA;AAC5D;AAGO,SAAS,eAAA,CAA2C,KAAA,EAAY,GAAA,mBAAY,IAAI,MAAK,EAAQ;AAClG,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,OAAA,EAAQ,GAAI,sBAAA;AAC/B,EAAA,OAAO,KAAA,CACJ,MAAA,CAAO,CAAC,IAAA,KAAS;AAChB,IAAA,MAAM,YAAY,IAAA,CAAK,YAAA,GAAe,KAAK,KAAA,CAAM,IAAA,CAAK,YAAY,CAAA,GAAI,GAAA;AACtE,IAAA,OAAO,MAAA,CAAO,SAAS,SAAS,CAAA,IAAK,aAAa,MAAA,IAAU,SAAA,IAAa,IAAI,OAAA,EAAQ;AAAA,EACvF,CAAC,CAAA,CACA,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,KAAK,KAAA,CAAM,CAAA,CAAE,YAAa,CAAA,GAAI,IAAA,CAAK,MAAM,CAAA,CAAE,YAAa,CAAC,CAAA,CACxE,KAAA,CAAM,GAAG,qBAAqB,CAAA;AACnC;AAMO,SAAS,oBACd,KAAA,EACA,OAAA,EACA,GAAA,mBAAY,IAAI,MAAK,EACb;AACR,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,IAAA;AACrC,EAAA,MAAM,QAAQ,eAAA,CAAgB,KAAA,EAAO,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,IAAA,KAAS;AACtD,IAAA,MAAM,GAAA,GAAM,kBAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,OAAA,EAAS,OAAA,CAAQ,OAAA,EAAS,CAAA;AAC5E,IAAA,OAAO,CAAA;AAAA,SAAA,EACA,SAAA,CAAU,GAAG,CAAC,CAAA;AAAA;AAAA;AAAA,mBAAA,EAGJ,SAAA,CAAU,OAAA,CAAQ,eAAe,CAAC,CAAA;AAAA,uBAAA,EAC9B,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA;AAAA,6BAAA,EAEb,IAAI,IAAA,CAAK,IAAA,CAAK,YAAa,CAAA,CAAE,aAAa,CAAA;AAAA,kBAAA,EACrD,SAAA,CAAU,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA;AAAA,QAAA,CAAA;AAAA,EAGvC,CAAC,CAAA;AAED,EAAA,OAAO,CAAA;AAAA;AAAA,EAEP,KAAA,CAAM,KAAK,IAAI,CAAC,GAAG,KAAA,CAAM,MAAA,GAAS,OAAO,EAAE,CAAA,SAAA,CAAA;AAC7C;;;ACrDO,IAAM,UAAA,GAAa;AAAA,EACxB,OAAO,EAAE,GAAA,EAAK,IAAI,GAAA,EAAK,EAAA,EAAI,aAAa,EAAA,EAAG;AAAA,EAC3C,iBAAiB,EAAE,GAAA,EAAK,KAAK,GAAA,EAAK,GAAA,EAAK,aAAa,GAAA,EAAI;AAAA,EACxD,SAAS,EAAE,GAAA,EAAK,KAAK,GAAA,EAAK,GAAA,EAAK,aAAa,GAAA,EAAI;AAAA,EAChD,IAAA,EAAM,EAAE,GAAA,EAAK,EAAA,EAAG;AAAA,EAChB,gBAAgB,EAAE,GAAA,EAAK,GAAG,GAAA,EAAK,CAAA,EAAG,OAAO,IAAA;AAAK;AAChD;AAcO,SAAS,gBAAA,CAAiB,OAAe,cAAA,EAA8C;AAC5F,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,EAAA,IAAI,MAAA,GAAwC,MAAA;AAC5C,EAAA,IAAI,OAAA,GAAU,yBAAA;AAEd,EAAA,IAAI,MAAA,GAAS,UAAA,CAAW,KAAA,CAAM,GAAA,EAAK;AACjC,IAAA,MAAA,GAAS,OAAA;AACT,IAAA,OAAA,GAAU,CAAA,SAAA,EAAY,SAAS,UAAA,CAAW,KAAA,CAAM,GAAG,CAAA,0BAAA,EAA6B,UAAA,CAAW,MAAM,GAAG,CAAA,CAAA,CAAA;AAAA,EACtG,CAAA,MAAA,IAAW,MAAA,GAAS,UAAA,CAAW,KAAA,CAAM,GAAA,EAAK;AACxC,IAAA,MAAA,GAAS,SAAA;AACT,IAAA,OAAA,GAAU,CAAA,gBAAA,EAAmB,MAAM,CAAA,CAAA,EAAI,UAAA,CAAW,MAAM,GAAG,CAAA,KAAA,CAAA;AAAA,EAC7D,CAAA,MAAA,IAAW,cAAA,IAAkB,CAAC,KAAA,CAAM,WAAA,GAAc,QAAA,CAAS,cAAA,CAAe,WAAA,EAAa,CAAA,EAAG;AACxF,IAAA,MAAA,GAAS,SAAA;AACT,IAAA,OAAA,GAAU,oCAAA;AAAA,EACZ,CAAA,MAAA,IAAW,cAAA,IAAkB,CAAC,KAAA,CAAM,WAAA,GAAc,UAAA,CAAW,cAAA,CAAe,WAAA,EAAa,CAAA,EAAG;AAC1F,IAAA,MAAA,GAAS,SAAA;AACT,IAAA,OAAA,GAAU,0DAAA;AAAA,EACZ;AAEA,EAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,KAAA,EAAO,QAAQ,KAAA,EAAO,UAAA,CAAW,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAQ;AAC1F;AAKO,SAAS,uBAAA,CAAwB,aAAqB,cAAA,EAA8C;AACzG,EAAA,MAAM,SAAS,WAAA,CAAY,MAAA;AAC3B,EAAA,IAAI,MAAA,GAAwC,MAAA;AAC5C,EAAA,IAAI,OAAA,GAAU,6BAAA;AAEd,EAAA,IAAI,MAAA,GAAS,UAAA,CAAW,eAAA,CAAgB,GAAA,EAAK;AAC3C,IAAA,MAAA,GAAS,OAAA;AACT,IAAA,OAAA,GAAU,CAAA,+BAAA,EAAkC,MAAM,CAAA,CAAA,EAAI,UAAA,CAAW,gBAAgB,GAAG,CAAA,CAAA,CAAA;AAAA,EACtF,CAAA,MAAA,IAAW,MAAA,GAAS,UAAA,CAAW,eAAA,CAAgB,GAAA,EAAK;AAClD,IAAA,MAAA,GAAS,SAAA;AACT,IAAA,OAAA,GAAU,CAAA,sBAAA,EAAyB,MAAM,CAAA,CAAA,EAAI,UAAA,CAAW,gBAAgB,GAAG,CAAA,KAAA,CAAA;AAAA,EAC7E,CAAA,MAAA,IAAW,cAAA,IAAkB,CAAC,WAAA,CAAY,WAAA,GAAc,QAAA,CAAS,cAAA,CAAe,WAAA,EAAa,CAAA,EAAG;AAC9F,IAAA,MAAA,GAAS,SAAA;AACT,IAAA,OAAA,GAAU,0CAAA;AAAA,EACZ;AAEA,EAAA,OAAO,EAAE,KAAA,EAAO,kBAAA,EAAoB,KAAA,EAAO,WAAA,EAAa,QAAQ,KAAA,EAAO,UAAA,CAAW,eAAA,EAAiB,MAAA,EAAQ,OAAA,EAAQ;AACrH;AAKO,SAAS,mBAAmB,IAAA,EAAqD;AACtF,EAAA,MAAM,UAAiC,EAAC;AACxC,EAAA,MAAM,iBAAiB,IAAA,CAAK,eAAA;AAE5B,EAAA,IAAI,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,KAAA,EAAO;AACjC,IAAA,OAAA,CAAQ,IAAA,CAAK,iBAAiB,IAAA,CAAK,UAAA,IAAc,KAAK,KAAA,IAAS,EAAA,EAAI,cAAc,CAAC,CAAA;AAAA,EACpF;AAEA,EAAA,IAAI,KAAK,gBAAA,EAAkB;AACzB,IAAA,OAAA,CAAQ,IAAA,CAAK,uBAAA,CAAwB,IAAA,CAAK,gBAAA,EAAkB,cAAc,CAAC,CAAA;AAAA,EAC7E;AAGA,EAAA,IAAI,IAAA,CAAK,SAAS,cAAA,EAAgB;AAChC,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,WAAA,EAAY;AAC1C,IAAA,MAAM,QAAA,GAAW,eAAe,WAAA,EAAY;AAC5C,IAAA,IAAI,CAAC,UAAA,CAAW,QAAA,CAAS,QAAQ,CAAA,EAAG;AAClC,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,KAAA,EAAO,cAAA;AAAA,QACP,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,MAAA,EAAQ,KAAK,KAAA,CAAM,MAAA;AAAA,QACnB,KAAA,EAAO,EAAE,GAAA,EAAK,GAAA,EAAI;AAAA,QAClB,MAAA,EAAQ,SAAA;AAAA,QACR,OAAA,EAAS;AAAA,OACV,CAAA;AAAA,IACH;AAAA,EACF;AAGA,EAAA,IAAI,IAAA,CAAK,eAAe,MAAA,EAAW;AACjC,IAAA,IAAI,UAAA,GAA4C,MAAA;AAChD,IAAA,IAAI,WAAA,GAAc,mCAAA;AAElB,IAAA,IAAI,IAAA,CAAK,aAAa,GAAA,EAAK;AACzB,MAAA,UAAA,GAAa,OAAA;AACb,MAAA,WAAA,GAAc,CAAA,iBAAA,EAAoB,KAAK,UAAU,CAAA,6BAAA,CAAA;AAAA,IACnD,CAAA,MAAA,IAAW,IAAA,CAAK,UAAA,GAAa,IAAA,EAAM;AACjC,MAAA,UAAA,GAAa,SAAA;AACb,MAAA,WAAA,GAAc,CAAA,kBAAA,EAAqB,KAAK,UAAU,CAAA,4CAAA,CAAA;AAAA,IACpD,CAAA,MAAA,IAAW,IAAA,CAAK,UAAA,GAAa,IAAA,EAAM;AACjC,MAAA,WAAA,GAAc,CAAA,uBAAA,EAA0B,KAAK,UAAU,CAAA,iDAAA,CAAA;AAAA,IACzD;AAEA,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,KAAA,EAAO,YAAA;AAAA,MACP,KAAA,EAAO,MAAA,CAAO,IAAA,CAAK,UAAU,CAAA;AAAA,MAC7B,QAAQ,IAAA,CAAK,UAAA;AAAA,MACb,OAAO,EAAE,GAAA,EAAK,MAAM,GAAA,EAAK,IAAA,EAAM,aAAa,IAAA,EAAK;AAAA,MACjD,MAAA,EAAQ,UAAA;AAAA,MACR,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,OAAA;AACT;AAsBA,eAAsB,UAAA,CACpB,MACA,OAAA,EAC+B;AAC/B,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAA,CAAQ,KAAK,kCAAkC,CAAA;AAC/C,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,kBAAA,CAAmB,EAAE,GAAG,MAAA,EAAQ,MAAM,OAAA,EAAS,IAAA,IAAQ,IAAI,CAAA;AACpE;AAyBA,eAAsB,cAAA,CACpB,MACA,OAAA,EACwB;AACxB,EAAA,MAAM,IAAA,GAAO,MAAM,UAAA,CAAW,IAAA,EAAM,OAAO,CAAA;AAC3C,EAAA,IAAI,CAAC,MAAM,QAAA,EAAS;AACpB,EAAA,OAAO,IAAA;AACT;AAKA,eAAsB,kBAAA,GAEpB;AACA,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAA,CAAQ,KAAK,kCAAkC,CAAA;AAC/C,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAA;AAE3B,EAAA,IAAI;AACF,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,cAAc,CAAA,EAAG,MAAM,wBAAwB,CAAA,EAAG;AAAA,MAC7E,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,MAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,GAAA;AAAI,KACzB,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,EAAC;AAE1B,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,IAAA,CAAK,SAAS,EAAC;AAAA,EACxB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,oCAAoC,KAAK,CAAA;AACvD,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAKA,eAAsB,qBACpB,OAAA,EAC+D;AAC/D,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,EAAC;AAGrB,EAAA,OAAQ,MAAM,uBAAuB,EAAE,GAAG,QAAQ,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AAKzE;AA2CA,eAAsB,uBAAA,CACpB,IAAA,EACA,OAAA,GAAkC,EAAC,EAChB;AACnB,EAAA,MAAM,IAAA,GAAO,MAAM,UAAA,CAAW,IAAI,CAAA;AAClC,EAAA,MAAM,EAAE,QAAA,EAAU,OAAA,GAAU,EAAA,EAAI,YAAA,EAAc,eAAc,GAAI,OAAA;AAChE,EAAA,IAAI,CAAC,IAAA,EAAM;AAGT,IAAA,IAAI,OAAA,CAAQ,QAAA,KAAa,KAAA,EAAO,QAAA,EAAS;AACzC,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,gBAAA;AAAA,MACP,WAAA,EAAa,2CAAA;AAAA,MACb,MAAA,EAAQ,EAAE,KAAA,EAAO,KAAA,EAAO,QAAQ,IAAA;AAAK,KACvC;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,KAAA;AACtC,EAAA,MAAM,WAAA,GAAc,eAAA,CAAgB,IAAA,CAAK,gBAAA,IAAoB,KAAK,OAAO,CAAA;AAIzE,EAAA,MAAM,QAAQ,OAAA,CAAQ,MAAA,KAAW,KAAA,GAAQ,MAAA,GAAY,KAAK,cAAA,IAAkB,YAAA;AAC5E,EAAA,MAAM,GAAA,GAAM,iBAAA,CAAkB,IAAA,EAAM,OAAO,CAAA;AAE3C,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA,EAAO,KAAK,QAAA,IAAY,KAAA;AAAA,MACxB,WAAA,EAAa,KAAK,cAAA,IAAkB,WAAA;AAAA,MACpC,GAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA,EAAM,SAAA;AAAA,MACN,eAAe,IAAA,CAAK,YAAA;AAAA,MACpB,OAAA,EAAS,IAAA,CAAK,MAAA,GAAS,CAAC,OAAO,IAAA,CAAK,MAAA,KAAW,QAAA,GAAW,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,GAAI,MAAA;AAAA,MAC5F,GAAI,KAAA,IAAS;AAAA,QACX,MAAA,EAAQ;AAAA,UACN;AAAA,YACE,GAAA,EAAK,KAAA;AAAA,YACL,KAAA,EAAO,IAAA;AAAA,YACP,MAAA,EAAQ,GAAA;AAAA,YACR,GAAA,EAAK,IAAA,CAAK,kBAAA,IAAsB,IAAA,CAAK;AAAA;AACvC;AACF;AACF,KACF;AAAA,IACA,OAAA,EAAS;AAAA,MACP,IAAA,EAAM,qBAAA;AAAA,MACN,KAAA;AAAA,MACA,WAAA;AAAA,MACA,GAAI,KAAA,IAAS,EAAE,MAAA,EAAQ,CAAC,KAAK,CAAA,EAAE;AAAA,MAC/B,OAAA,EAAS;AAAA,KACX;AAAA,IACA,UAAA,EAAY;AAAA,MACV,SAAA,EAAW;AAAA,KACb;AAAA,IACA,KAAA,EAAO;AAAA,MACL,wBAAA,EAA0B,KAAK,YAAA,IAAgB,EAAA;AAAA,MAC/C,iBAAA,EAAmB,OAAO,IAAA,CAAK,QAAA,KAAa,WAAW,IAAA,CAAK,QAAA,GAAY,IAAA,CAAK,QAAA,EAAU,IAAA,IAAQ;AAAA;AACjG,GACF;AACF;AAKO,SAAS,4BAA4B,OAAA,EAG/B;AACX,EAAA,MAAM;AAAA,IACJ,KAAA,GAAQ,MAAA;AAAA,IACR,WAAA,GAAc,wCAAA;AAAA,IACd,QAAA;AAAA,IACA,OAAA,GAAU,EAAA;AAAA,IACV,YAAA;AAAA,IACA;AAAA,GACF,GAAI,OAAA;AACJ,EAAA,MAAM,IAAA,GAAO,uBAAA,CAAwB,OAAO,CAAA,CAAE,KAAA;AAE9C,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA;AAAA,MACA,WAAA;AAAA,MACA,GAAA,EAAK,qBAAA,CAAsB,IAAA,EAAM,OAAO,CAAA;AAAA,MACxC,QAAA;AAAA,MACA,IAAA,EAAM,SAAA;AAAA,MACN,GAAI,gBAAgB,EAAE,MAAA,EAAQ,CAAC,EAAE,GAAA,EAAK,YAAA,EAAc,CAAA;AAAE,KACxD;AAAA,IACA,OAAA,EAAS;AAAA,MACP,IAAA,EAAM,qBAAA;AAAA,MACN,KAAA;AAAA,MACA,WAAA;AAAA,MACA,GAAI,YAAA,IAAgB,EAAE,MAAA,EAAQ,CAAC,YAAY,CAAA,EAAE;AAAA,MAC7C,OAAA,EAAS;AAAA;AACX,GACF;AACF;AAKO,SAAS,+BAAA,CACd,YAAA,EACA,OAAA,GAAkE,EAAC,EACzD;AACV,EAAA,MAAM,EAAE,QAAA,EAAU,OAAA,GAAU,EAAA,EAAI,cAAa,GAAI,OAAA;AACjD,EAAA,MAAM,KAAA,GAAQ,GAAG,YAAY,CAAA,WAAA,CAAA;AAC7B,EAAA,MAAM,WAAA,GAAc,uBAAuB,YAAY,CAAA,CAAA,CAAA;AAKvD,EAAA,MAAM,IAAA,GACJ,OAAA,CAAQ,YAAA,IACR,YAAA,CACG,aAAY,CACZ,IAAA,EAAK,CACL,OAAA,CAAQ,aAAA,EAAe,GAAG,CAAA,CAC1B,OAAA,CAAQ,YAAY,EAAE,CAAA;AAE3B,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA;AAAA,MACA,WAAA;AAAA,MACA,GAAA,EAAK,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,QAAA,CAAS,IAAI,GAAG,OAAO,CAAA;AAAA,MACnF,QAAA;AAAA,MACA,IAAA,EAAM,SAAA;AAAA,MACN,GAAI,gBAAgB,EAAE,MAAA,EAAQ,CAAC,EAAE,GAAA,EAAK,YAAA,EAAc,CAAA;AAAE;AACxD,GACF;AACF;AAeA,SAAS,wBAAwB,KAAA,EAA0F;AACzH,EAAA,OAAO,QAAA,IAAY,KAAA;AACrB;AAsBA,eAAsB,2BAAA,CACpB,GAAA,GAAyD,EAAC,EACV;AAEhD,EAAA,MAAM,OAAA,GAAqC,uBAAA,CAAwB,GAAG,CAAA,GAAI,EAAC,GAAI,GAAA;AAC/E,EAAA,MAAM,KAAA,GAAQ,MAAM,sBAAA,CAAuB,OAAO,CAAA;AAClD,EAAA,OAAO,KAAA,CAAM,IAAI,CAAA,IAAA,KAAQ;AACvB,IAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,IAAA,CAAK,QAAA,IAAY,QAAQ,QAAQ,CAAA;AACtE,IAAA,OAAO,EAAE,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,GAAI,OAAA,CAAQ,qBAAA,IAAyB,QAAA,GAAW,EAAE,QAAA,EAAS,GAAI,EAAC,EAAG;AAAA,EAC/F,CAAC,CAAA;AACH;AAQA,eAAsB,4BAAA,GAAgE;AACpF,EAAA,MAAM,UAAA,GAAa,MAAM,oBAAA,EAAqB;AAC9C,EAAA,OAAO,UAAA,CAAW,IAAI,CAAC,CAAA,MAAO,EAAE,QAAA,EAAU,CAAA,CAAE,MAAK,CAAE,CAAA;AACrD;AAgBA,SAAS,aAAA,CAAc,OAAkC,OAAA,EAAgC;AACvF,EAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,EAAK;AAC1B,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,KAAA,EAAO,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,GAAI,OAAA,GAAU,CAAA,EAAG,OAAO,CAAA,CAAA,CAAG,CAAA,CAAE,QAAA,EAAS;AAAA,EAClF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAWA,eAAe,sBAAA,CAAuB,OAAA,EAAoC,cAAA,GAAiB,KAAA,EAAsH;AAC/M,EAAA,IAAI,cAAA,IAAkB,OAAA,CAAQ,qBAAA,IAAyB,OAAA,CAAQ,QAAA,EAAU;AACvE,IAAA,OAAA,CAAQ,MAAM,cAAA,CAAe,EAAE,QAAA,EAAU,UAAU,CAAA,EAAG,GAAA,CAAI,CAAA,IAAA,MAAS,EAAE,GAAG,IAAA,EAAM,aAAA,EAAe,IAAA,CAAK,YAAW,CAAE,CAAA;AAAA,EACjH;AACA,EAAA,OAAO,kBAAA,EAAmB;AAC5B;AAEA,eAAsB,sBAAA,CACpB,OAAA,EACA,OAAA,GAAiC,EAAC,EACT;AACzB,EAAA,MAAM,KAAA,GAAQ,MAAM,sBAAA,CAAuB,OAAA,EAAS,IAAI,CAAA;AACxD,EAAA,MAAM,aAAa,OAAA,CAAQ,iBAAA,KAAsB,QAAQ,EAAC,GAAI,MAAM,oBAAA,EAAqB;AACzF,EAAA,MAAM,WAAW,OAAA,CAAQ,eAAA,KAAoB,QAAQ,EAAC,GAAI,MAAM,gBAAA,EAAiB;AAEjF,EAAA,MAAM,OAAA,GAA0B;AAAA;AAAA,IAE9B;AAAA,MACE,KAAK,qBAAA,CAAsB,uBAAA,CAAwB,OAAO,CAAA,CAAE,OAAO,OAAO,CAAA;AAAA,MAC1E,eAAA,EAAiB,OAAA;AAAA,MACjB,QAAA,EAAU;AAAA;AACZ,GACF;AAGA,EAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC5B,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,GAAA,EAAK,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,OAAA,CAAQ,OAAA,CAAQ,YAAY,CAAA,EAAG,OAAO,CAAA;AAAA,MAClG,eAAA,EAAiB,QAAA;AAAA,MACjB,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,EACH,CAAC,CAAA;AAGD,EAAA,UAAA,CAAW,OAAA,CAAQ,CAAC,GAAA,KAAQ;AAC1B,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,GAAA,EAAK,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAG,OAAO,CAAA;AAAA,MACvF,eAAA,EAAiB,QAAA;AAAA,MACjB,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,EACH,CAAC,CAAA;AAGD,EAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,KAAS;AACtB,IAAA,MAAM,QAAA,GAAY,KAAa,YAAA,KAAiB,QAAA;AAChD,IAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,IAAA,CAAK,cAAA,EAAgB,OAAO,CAAA;AACxD,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,KAAK,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS,CAAA;AAAA,MACpD,cAAc,IAAA,CAAK,aAAA,GAAgB,IAAI,IAAA,CAAK,IAAA,CAAK,aAAa,CAAA,GAAI,MAAA;AAAA,MAClE,eAAA,EAAiB,WAAW,QAAA,GAAW,SAAA;AAAA,MACvC,QAAA,EAAU,WAAW,GAAA,GAAM,GAAA;AAAA,MAC3B,GAAI,QAAQ,EAAE,MAAA,EAAQ,CAAC,KAAK,CAAA,KAAM;AAAC,KACpC,CAAA;AAAA,EACH,CAAC,CAAA;AAED,EAAA,OAAO,OAAA;AACT;AAMA,eAAsB,oBAAoB,OAAA,EAAkE;AAE1G,EAAA,MAAM,KAAA,GAAQ,MAAM,cAAA,CAAe,EAAE,UAAU,EAAA,EAAI,IAAA,EAAM,OAAA,CAAQ,IAAA,EAAM,CAAA;AACvE,EAAA,OAAO,mBAAA,CAAoB,OAAO,OAAO,CAAA;AAC3C;AASO,SAAS,qBAAA,CACd,IAAA,EACA,OAAA,GAAiG,EAAC,EAC1F;AACR,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAI,QAAA,EAAU,SAAQ,GAAI,OAAA;AAE5C,EAAA,MAAM,MAAA,GAAc;AAAA,IAClB,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,aAAA;AAAA,IACT,UAAU,IAAA,CAAK,KAAA;AAAA,IACf,WAAA,EAAa,eAAA,CAAgB,IAAA,CAAK,OAAA,IAAW,KAAK,gBAAgB,CAAA;AAAA,IAClE,KAAK,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS,CAAA;AAAA,IACpD,eAAe,IAAA,CAAK,YAAA;AAAA,IACpB,cAAc,IAAA,CAAK,UAAA;AAAA,IACnB,MAAA,EAAQ;AAAA,MACN,OAAA,EAAS,QAAA;AAAA,MACT,IAAA,EAAM,OAAO,IAAA,CAAK,MAAA,KAAW,WAAW,IAAA,CAAK,MAAA,GAAS,KAAK,MAAA,EAAQ;AAAA;AACrE,GACF;AAEA,EAAA,MAAM,YAAA,GAAe,qBAAA,CAAsB,IAAA,EAAM,SAAS,CAAA,CAAE,GAAA;AAC5D,EAAA,IAAI,YAAA,SAAqB,KAAA,GAAQ,YAAA;AAEjC,EAAA,IAAI,YAAY,OAAA,EAAS;AACvB,IAAA,MAAA,CAAO,SAAA,GAAY;AAAA,MACjB,OAAA,EAAS,cAAA;AAAA,MACT,IAAA,EAAM,QAAA;AAAA,MACN,MAAM,OAAA,GACF;AAAA,QACE,OAAA,EAAS,aAAA;AAAA,QACT,GAAA,EAAK;AAAA,OACP,GACA;AAAA,KACN;AAAA,EACF;AAGA,EAAA,IAAI,IAAA,CAAK,SAAA,IAAa,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAA,IAAK,IAAA,CAAK,SAAA,CAAU,MAAA,GAAS,CAAA,EAAG;AAChF,IAAA,MAAA,CAAO,UAAA,GAAa;AAAA,MAClB,OAAA,EAAS,SAAA;AAAA,MACT,UAAA,EAAY,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,CAAC,GAAA,MAA+C;AAAA,QAC7E,OAAA,EAAS,UAAA;AAAA,QACT,MAAM,GAAA,CAAI,QAAA;AAAA,QACV,cAAA,EAAgB;AAAA,UACd,OAAA,EAAS,QAAA;AAAA,UACT,MAAM,GAAA,CAAI;AAAA;AACZ,OACF,CAAE;AAAA,KACJ;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAKO,SAAS,yBAAA,CACd,OAAA,GAAqG,EAAC,EAC9F;AACR,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAI,QAAA,EAAU,aAAY,GAAI,OAAA;AAEhD,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,MAAA;AAAA,IACT,IAAA,EAAM,QAAA,GAAW,CAAA,EAAG,QAAQ,CAAA,KAAA,CAAA,GAAU,MAAA;AAAA,IACtC,aAAa,WAAA,IAAe,mCAAA;AAAA,IAC5B,KAAK,qBAAA,CAAsB,uBAAA,CAAwB,OAAO,CAAA,CAAE,OAAO,OAAO;AAAA,GAC5E;AACF;AASO,SAAS,kBACd,QAAA,EACe;AACf,EAAA,IAAI,CAAC,QAAA,IAAY,QAAA,CAAS,MAAA,KAAW,GAAG,OAAO,IAAA;AAE/C,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,SAAA;AAAA,IACT,UAAA,EAAY,QAAA,CAAS,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,MACjC,OAAA,EAAS,UAAA;AAAA,MACT,MAAM,GAAA,CAAI,QAAA;AAAA,MACV,cAAA,EAAgB;AAAA,QACd,OAAA,EAAS,QAAA;AAAA,QACT,MAAM,GAAA,CAAI;AAAA;AACZ,KACF,CAAE;AAAA,GACJ;AACF;AAgBO,SAAS,mBAAA,CACd,IAAA,EACA,KAAA,EACA,OAAA,GAA4D,EAAC,EACrD;AACR,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAG,GAAI,OAAA;AAEzB,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,OAAA;AAAA,IACT,MAAM,IAAA,CAAK,KAAA;AAAA,IACX,WAAA,EAAa,eAAA,CAAgB,IAAA,CAAK,OAAA,IAAW,KAAK,gBAAgB,CAAA;AAAA,IAClE,KAAA,EAAO,qBAAA,CAAsB,IAAA,EAAM,SAAS,CAAA,CAAE,GAAA;AAAA,IAC9C,WAAW,IAAA,CAAK,YAAA,GAAe,CAAA,EAAA,EAAK,IAAA,CAAK,YAAY,CAAA,CAAA,CAAA,GAAM,MAAA;AAAA,IAC3D,IAAA,EAAM,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,KAAA,MAAW;AAAA,MAChC,OAAA,EAAS,WAAA;AAAA,MACT,UAAU,KAAA,GAAQ,CAAA;AAAA,MAClB,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,OAAO,IAAA,CAAK,KAAA;AAAA,MACZ,KAAK,IAAA,CAAK,GAAA,IAAO,GAAG,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS,CAAA,CAAE,MAAM,GAAG,CAAA,CAAE,CAAC,CAAC,CAAA,MAAA,EAAS,QAAQ,CAAC,CAAA;AAAA,KACtG,CAAE;AAAA,GACJ;AACF;AAyBA,IAAM,cAAA,GAAiB,GAAA;AASvB,eAAsB,cAAA,CACpB,OAAA,GAAgG,EAAC,EACvE;AAC1B,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,cAAA;AACrC,EAAA,IAAI,EAAE,QAAA,GAAW,CAAA,CAAA,EAAI,OAAO,EAAC;AAC7B,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAA,CAAQ,KAAK,kCAAkC,CAAA;AAC/C,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAA;AAE3B,EAAA,MAAM,QAAyB,EAAC;AAChC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI;AACF,IAAA,OAAO,KAAA,CAAM,SAAS,QAAA,EAAU;AAC9B,MAAA,MAAM,WAAW,MAAM,KAAA;AAAA,QACrB,cAAc,CAAA,EAAG,MAAM,2CAA2C,IAAI,CAAA,CAAA,EAAI,QAAQ,IAAI,CAAA;AAAA,QACtF;AAAA,UACE,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,UAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,GAAA;AAAI;AAC1B,OACF;AAEA,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAElB,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,IAAS,EAAC;AAC7B,MAAA,KAAA,CAAM,IAAA,CAAK,GAAG,KAAK,CAAA;AACnB,MAAA,IAAI,CAAC,KAAA,CAAM,MAAA,IAAU,CAAC,IAAA,CAAK,YAAY,QAAA,EAAU;AACjD,MAAA,IAAA,IAAQ,CAAA;AAAA,IACV;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,4CAA4C,KAAK,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA;AAChC;AAMA,SAAS,UAAU,IAAA,EAAsB;AACvC,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,EAAE,EAAE,IAAA,EAAK;AAC3C;AAKA,eAAsB,gBAAgB,OAAA,EAA0C;AAC9E,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA,GAAc,8BAAA;AAAA,IACd,QAAA,GAAW,OAAA;AAAA,IACX,SAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA;AAAA,IACA,GAAA,GAAM,EAAA;AAAA,IACN;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,KAAA,GAAQ,MAAM,cAAA,CAAe,EAAE,UAAU,OAAA,CAAQ,QAAA,IAAY,oBAAoB,CAAA;AACvF,EAAA,MAAM,GAAA,GAAA,iBAAM,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAEnC,EAAA,IAAI,GAAA,GAAM,CAAA;AAAA;AAAA;AAAA,WAAA,EAGC,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,UAAA,EACpB,OAAO,CAAA;AAAA,iBAAA,EACA,SAAA,CAAU,WAAW,CAAC,CAAA;AAAA,cAAA,EACzB,QAAQ,CAAA;AAAA,mBAAA,EACH,GAAG,CAAA;AAAA,aAAA,EACT,GAAG,CAAA;AAAA,SAAA,EACP,GAAG,CAAA;AAAA,qBAAA,EACS,SAAA,CAAU,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,GAAA,EAAK,OAAO,CAAC,CAAC,CAAA;AAAA,CAAA;AAGpG,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,GAAA,IAAO,CAAA,eAAA,EAAkB,SAAA,CAAU,SAAS,CAAC,CAAA;AAAA,CAAA;AAAA,EAC/C;AAEA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,GAAA,IAAO,CAAA,oBAAA,EAAuB,SAAA,CAAU,cAAc,CAAC,CAAA;AAAA,CAAA;AAAA,EACzD;AAEA,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,GAAA,IAAO,CAAA,eAAA,EAAkB,SAAA,CAAU,SAAS,CAAC,CAAA;AAAA,CAAA;AAAA,EAC/C;AAEA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,GAAA,IAAO,CAAA;AAAA,WAAA,EACE,QAAQ,CAAA;AAAA,aAAA,EACN,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,YAAA,EACpB,OAAO,CAAA;AAAA;AAAA,CAAA;AAAA,EAEnB;AAGA,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,UAAU,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS,CAAA;AAC/D,IAAA,MAAM,OAAA,GAAU,KAAK,YAAA,GAAe,IAAI,KAAK,IAAA,CAAK,YAAY,CAAA,CAAE,WAAA,EAAY,GAAI,GAAA;AAChF,IAAA,MAAM,MAAA,GAAS,OAAO,IAAA,CAAK,MAAA,KAAW,WAAW,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,MAAA,EAAQ,IAAA,IAAQ,SAAA;AAGpF,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,OAAA,IAAW,EAAA;AACzD,IAAA,MAAMA,YAAAA,GAAc,eAAA,CAAgB,IAAA,CAAK,OAAA,EAAS,GAAG,CAAA,IAAK,SAAA,CAAU,WAAW,CAAA,CAAE,SAAA,CAAU,CAAA,EAAG,GAAG,CAAA,GAAI,KAAA;AAErG,IAAA,GAAA,IAAO,CAAA;AAAA,aAAA,EACI,SAAA,CAAU,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,YAAA,EACtB,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,+BAAA,EACC,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,mBAAA,EAC9B,SAAA,CAAUA,YAAW,CAAC,CAAA;AAAA,uBAAA,EAClB,KAAA,CAAM,WAAW,CAAC,CAAA;AAAA,eAAA,EAC1B,OAAO,CAAA;AAAA,cAAA,EACR,SAAA,CAAU,MAAM,CAAC,CAAA;AAAA,CAAA;AAG7B,IAAA,IAAI,KAAK,QAAA,EAAU;AACjB,MAAA,MAAM,YAAA,GAAe,OAAO,IAAA,CAAK,QAAA,KAAa,WAAW,IAAA,CAAK,QAAA,GAAW,KAAK,QAAA,CAAS,IAAA;AACvF,MAAA,GAAA,IAAO,CAAA,gBAAA,EAAmB,SAAA,CAAU,YAAY,CAAC,CAAA;AAAA,CAAA;AAAA,IACnD;AAEA,IAAA,IAAI,KAAK,IAAA,IAAQ,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA,EAAG;AACzC,MAAA,KAAA,MAAW,GAAA,IAAO,KAAK,IAAA,EAAM;AAC3B,QAAA,MAAM,OAAA,GAAU,OAAO,GAAA,KAAQ,QAAA,GAAW,MAAM,GAAA,CAAI,IAAA;AACpD,QAAA,GAAA,IAAO,CAAA,gBAAA,EAAmB,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,CAAA;AAAA,MAC9C;AAAA,IACF;AAEA,IAAA,IAAI,KAAK,cAAA,EAAgB;AACvB,MAAA,GAAA,IAAO,CAAA,sBAAA,EAAyB,KAAK,cAAc,CAAA;AAAA,CAAA;AAAA,IACrD;AAEA,IAAA,GAAA,IAAO,CAAA;AAAA,CAAA;AAAA,EACT;AAEA,EAAA,GAAA,IAAO,CAAA;AAAA,MAAA,CAAA;AAGP,EAAA,OAAO,GAAA;AACT;AAKA,eAAsB,iBAAiB,OAAA,EAA0C;AAC/E,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA,GAAc,8BAAA;AAAA,IACd;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,KAAA,GAAQ,MAAM,cAAA,CAAe,EAAE,UAAU,OAAA,CAAQ,QAAA,IAAY,oBAAoB,CAAA;AACvF,EAAA,MAAM,GAAA,GAAA,iBAAM,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAEnC,EAAA,IAAI,IAAA,GAAO,CAAA;AAAA;AAAA,SAAA,EAEF,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,YAAA,EAChB,SAAA,CAAU,WAAW,CAAC,CAAA;AAAA,cAAA,EACpB,SAAA,CAAU,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,IAAA,EAAM,OAAO,CAAC,CAAC,CAAA;AAAA,cAAA,EAChF,OAAO,CAAA;AAAA,MAAA,EACf,SAAA,CAAU,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,KAAA,EAAO,OAAO,CAAC,CAAC,CAAA;AAAA,WAAA,EAC5E,GAAG,CAAA;AAAA,CAAA;AAGd,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,IAAA,IAAQ,CAAA;AAAA,UAAA,EACA,SAAA,CAAU,cAAc,CAAC,CAAA;AAAA;AAAA,CAAA;AAAA,EAEnC;AAEA,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,UAAU,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS,CAAA;AAC/D,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,UAAA,IAAc,IAAA,CAAK,YAAA,IAAgB,GAAA;AACxD,IAAA,MAAM,SAAA,GAAY,KAAK,YAAA,IAAgB,GAAA;AACvC,IAAA,MAAM,MAAA,GAAS,OAAO,IAAA,CAAK,MAAA,KAAW,WAAW,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,MAAA,EAAQ,IAAA,IAAQ,SAAA;AACpF,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,YAAA,IAAgB,IAAA,CAAK,OAAA,IAAW,EAAA;AAEzD,IAAA,IAAA,IAAQ,CAAA;AAAA,WAAA,EACC,SAAA,CAAU,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,gBAAA,EAChB,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,QAAA,EAC1B,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,aAAA,EACb,IAAI,IAAA,CAAK,OAAO,CAAA,CAAE,aAAa,CAAA;AAAA,eAAA,EAC7B,IAAI,IAAA,CAAK,SAAS,CAAA,CAAE,aAAa,CAAA;AAAA;AAAA,YAAA,EAEpC,SAAA,CAAU,MAAM,CAAC,CAAA;AAAA;AAAA,aAAA,EAEhB,SAAA,CAAU,eAAA,CAAgB,IAAA,CAAK,OAAA,EAAS,GAAG,CAAA,IAAK,SAAA,CAAU,WAAW,CAAA,CAAE,SAAA,CAAU,CAAA,EAAG,GAAG,CAAC,CAAC,CAAA;AAAA,yBAAA,EAC7E,KAAA,CAAM,WAAW,CAAC,CAAA;AAAA;AAAA,CAAA;AAAA,EAE3C;AAEA,EAAA,IAAA,IAAQ,CAAA,OAAA,CAAA;AAER,EAAA,OAAO,IAAA;AACT;AAUA,eAAsB,iBAAiB,OAAA,EAAsD;AAC3F,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,EAAC;AACrB,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAA;AAE3B,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,aAAA,CAAc,GAAG,MAAM,CAAA,yBAAA,CAAA,EAA6B,OAAA,EAAS,IAAI,CAAA,EAAG;AAAA,MAC/F,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,MAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,GAAA;AAAI,KACzB,CAAA;AACD,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,EAAC;AAC1B,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AAEjC,IAAA,OAAA,CAAQ,KAAK,QAAA,IAAY,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,MAAY;AAAA,MAC5C,IAAI,CAAA,CAAE,EAAA;AAAA,MACN,cAAc,CAAA,CAAE,YAAA;AAAA,MAChB,cAAc,CAAA,CAAE,YAAA;AAAA,MAChB,YAAY,CAAA,CAAE,UAAA;AAAA,MACd,gBAAgB,CAAA,CAAE,cAAA;AAAA,MAClB,UAAU,CAAA,CAAE,QAAA;AAAA,MACZ,YAAY,CAAA,CAAE,UAAA;AAAA,MACd,iBAAiB,CAAA,CAAE,eAAA;AAAA,MACnB,gBAAgB,CAAA,CAAE,cAAA;AAAA,MAClB,qBAAqB,CAAA,CAAE,mBAAA;AAAA,MACvB,eAAe,CAAA,CAAE,aAAA;AAAA,MACjB,YAAY,CAAA,CAAE,UAAA;AAAA,MACd,MAAA,EAAQ,IAAA;AAAA,MACR,UAAU,EAAC;AAAA,MACX,eAAe;AAAC,KAClB,CAAE,CAAA;AAAA,EACJ,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,6CAA6C,KAAK,CAAA;AAChE,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAKA,eAAsB,eAAA,CACpB,MACA,OAAA,EAC8B;AAC9B,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAA;AAE3B,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,aAAA,CAAc,CAAA,EAAG,MAAM,CAAA,0BAAA,EAA6B,IAAI,CAAA,CAAA,EAAI,OAAA,EAAS,IAAI,CAAA,EAAG;AAAA,MACvG,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,MAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,GAAA;AAAI,KACzB,CAAA;AACD,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,IAAA;AACzB,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AAEjC,IAAA,OAAO;AAAA,MACL,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,cAAc,IAAA,CAAK,YAAA;AAAA,MACnB,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,gBAAgB,IAAA,CAAK,cAAA;AAAA,MACrB,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,iBAAiB,IAAA,CAAK,eAAA;AAAA;AAAA;AAAA,MAGtB,cAAA,EAAgB,IAAA,CAAK,cAAA,IAAkB,IAAA,CAAK,MAAA,EAAQ,EAAA;AAAA,MACpD,qBAAqB,IAAA,CAAK,mBAAA;AAAA,MAC1B,eAAe,IAAA,CAAK,aAAA;AAAA,MACpB,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,MAAA,EAAQ,KAAK,MAAA,IAAU,IAAA;AAAA,MACvB,QAAA,EAAU,IAAA,CAAK,QAAA,IAAY,EAAC;AAAA,MAC5B,aAAA,EAAe,IAAA,CAAK,aAAA,IAAiB;AAAC,KACxC;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,4CAA4C,KAAK,CAAA;AAC/D,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAMO,SAAS,qBAAqB,IAAA,EAA+C;AAClF,EAAA,IAAI,CAAC,IAAA,CAAK,UAAA,IAAc,CAAC,IAAA,CAAK,cAAc,OAAO,IAAA;AAEnD,EAAA,MAAM,QAAA,GAAW,KAAK,YAAA,KAAiB,QAAA;AAMvC,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,KAAK,YAAA,IAAgB,EAAA;AAAA,IACnC,YAAA,EAAc,KAAK,YAAA,IAAgB,EAAA;AAAA,IACnC,MAAA,EAAQ,QAAA,GACJ,IAAA,GACA,IAAA,CAAK,kBAAA,GACH;AAAA,MACE,MAAM,IAAA,CAAK,kBAAA;AAAA,MACX,KAAA,EAAO,KAAK,mBAAA,IAAuB,EAAA;AAAA,MACnC,QAAA,EAAU,KAAK,sBAAA,IAA0B;AAAA,KAC3C,GACA,IAAA;AAAA,IACN,QAAA,EAAU,IAAA,CAAK,gBAAA,IAAoB,EAAC;AAAA,IACpC,SAAA,EAAW;AAAA,GACb;AACF;AAMA,eAAsB,sBAAsB,YAAA,EAIlC;AACR,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN;AAAA,GACF;AACA,EAAA,MAAM,KAAA,GAAQ,MAAM,kBAAA,CAAmB,YAAY,CAAA;AACnD,EAAA,IAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,OAAO,IAAA;AAE7B,EAAA,MAAM,cAAA,GAAiB,CAAC,GAAG,KAAK,EAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAA,CAAO,CAAA,CAAE,UAAA,IAAc,CAAA,KAAM,CAAA,CAAE,cAAc,CAAA,CAAE,CAAA;AAC1F,EAAA,MAAM,MAAA,GAAS,eAAe,CAAC,CAAA;AAC/B,EAAA,MAAM,eAAA,GAAkB,cAAA,CAAe,KAAA,CAAM,CAAC,CAAA;AAE9C,EAAA,MAAM,gBAAqE,EAAC;AAC5E,EAAA,KAAA,MAAW,WAAW,eAAA,EAAiB;AACrC,IAAA,aAAA,CAAc,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,CAAO,IAAA,EAAM,EAAA,EAAI,OAAA,CAAQ,IAAA,EAAM,MAAA,EAAQ,OAAA,CAAQ,KAAA,EAAO,CAAA;AACjF,IAAA,aAAA,CAAc,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,CAAQ,IAAA,EAAM,EAAA,EAAI,MAAA,CAAO,IAAA,EAAM,MAAA,EAAQ,MAAA,CAAO,KAAA,EAAO,CAAA;AAAA,EAClF;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,eAAA,EAAiB,aAAA,EAAc;AAClD;AAKA,eAAsB,kBAAA,CACpB,cACA,OAAA,EAC0B;AAC1B,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,EAAC;AACrB,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAA;AAE3B,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,aAAA,CAAc,CAAA,EAAG,MAAM,CAAA,gCAAA,EAAmC,kBAAA,CAAmB,YAAY,CAAC,CAAA,YAAA,CAAA,EAAgB,OAAA,EAAS,IAAI,CAAA,EAAG;AAAA,MACrJ,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,MAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,GAAA;AAAI,KACzB,CAAA;AACD,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,EAAC;AAC1B,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,IAAA,CAAK,SAAS,EAAC;AAAA,EACxB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,6CAA6C,KAAK,CAAA;AAChE,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAUO,SAAS,6BAAA,CACd,OAAA,EACA,OAAA,GAA4D,EAAC,EACrD;AACR,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAG,GAAI,OAAA;AAEzB,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,UAAA;AAAA,IACT,MAAM,OAAA,CAAQ,YAAA;AAAA,IACd,WAAA,EAAa,CAAA,eAAA,EAAkB,OAAA,CAAQ,UAAU,CAAA,CAAA;AAAA,IACjD,aAAA,EAAe,QAAQ,QAAA,CAAS,MAAA;AAAA,IAChC,iBAAiB,OAAA,CAAQ,QAAA,CAAS,GAAA,CAAI,CAAC,MAAM,CAAA,MAAO;AAAA,MAClD,OAAA,EAAS,UAAA;AAAA,MACT,UAAU,CAAA,GAAI,CAAA;AAAA,MACd,MAAM,IAAA,CAAK,KAAA;AAAA,MACX,KAAK,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS;AAAA,KACtD,CAAE;AAAA,GACJ;AACF;AAOO,SAAS,4BAAA,CACd,IAAA,EACA,OAAA,EACA,OAAA,GAAiG,EAAC,EAC1F;AACR,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAI,QAAA,EAAU,SAAQ,GAAI,OAAA;AAC5C,EAAA,MAAM,QAAA,GAAW,KAAK,YAAA,KAAiB,QAAA;AAEvC,EAAA,MAAM,MAAA,GAAc;AAAA,IAClB,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,SAAA;AAAA,IACT,UAAU,IAAA,CAAK,KAAA;AAAA,IACf,WAAA,EAAa,eAAA,CAAgB,IAAA,CAAK,OAAA,IAAW,KAAK,gBAAgB,CAAA;AAAA,IAClE,KAAK,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS,CAAA;AAAA,IACpD,eAAe,IAAA,CAAK,YAAA;AAAA,IACpB,cAAc,IAAA,CAAK,UAAA;AAAA,IACnB,MAAA,EAAQ;AAAA,MACN,OAAA,EAAS,QAAA;AAAA,MACT,IAAA,EAAM,OAAO,IAAA,CAAK,MAAA,KAAW,WAAW,IAAA,CAAK,MAAA,GAAU,KAAK,MAAA,EAAgB;AAAA,KAC9E;AAAA,IACA,QAAA,EAAU,IAAA,CAAK,eAAA,IAAmB,IAAA,CAAK;AAAA,GACzC;AAEA,EAAA,MAAM,YAAA,GAAe,qBAAA,CAAsB,IAAA,EAAM,SAAS,CAAA,CAAE,GAAA;AAC5D,EAAA,IAAI,YAAA,SAAqB,KAAA,GAAQ,YAAA;AAEjC,EAAA,IAAI,YAAY,OAAA,EAAS;AACvB,IAAA,MAAA,CAAO,SAAA,GAAY;AAAA,MACjB,OAAA,EAAS,cAAA;AAAA,MACT,IAAA,EAAM,QAAA;AAAA,MACN,GAAI,WAAW,EAAE,IAAA,EAAM,EAAE,OAAA,EAAS,aAAA,EAAe,GAAA,EAAK,OAAA,EAAQ;AAAE,KAClE;AAAA,EACF;AAGA,EAAA,IAAI,QAAA,IAAY,OAAA,CAAQ,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AAC3C,IAAA,MAAA,CAAO,OAAA,GAAU,OAAA,CAAQ,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MAC5C,OAAA,EAAS,SAAA;AAAA,MACT,UAAU,CAAA,CAAE,KAAA;AAAA,MACZ,KAAK,iBAAA,CAAkB,CAAA,EAAG,EAAE,GAAG,OAAA,EAAS,SAAS;AAAA,KACnD,CAAE,CAAA;AAAA,EACJ,CAAA,MAAA,IAAW,CAAC,QAAA,IAAY,OAAA,CAAQ,MAAA,EAAQ;AACtC,IAAA,MAAA,CAAO,QAAA,GAAW;AAAA,MAChB,OAAA,EAAS,SAAA;AAAA,MACT,QAAA,EAAU,QAAQ,MAAA,CAAO,KAAA;AAAA,MACzB,GAAA,EAAK,kBAAkB,OAAA,CAAQ,MAAA,EAAQ,EAAE,GAAG,OAAA,EAAS,SAAS;AAAA,KAChE;AAAA,EACF;AAGA,EAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,IAAA,MAAA,CAAO,eAAA,GAAkB;AAAA,MACvB,OAAA,EAAS,OAAA;AAAA,MACT,MAAM,OAAA,CAAQ;AAAA,KAChB;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAMO,SAAS,+BAAA,CACd,IAAA,EACA,OAAA,EACA,OAAA,GAA+E,EAAC,EACxE;AACR,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAI,QAAA,GAAW,QAAO,GAAI,OAAA;AAE5C,EAAA,MAAM,KAAA,GAAe;AAAA,IACnB,EAAE,SAAS,UAAA,EAAY,QAAA,EAAU,GAAG,IAAA,EAAM,QAAA,EAAU,MAAM,OAAA,EAAQ;AAAA,IAClE,EAAE,OAAA,EAAS,UAAA,EAAY,QAAA,EAAU,GAAG,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,qBAAA,CAAsB,uBAAA,CAAwB,OAAO,CAAA,CAAE,KAAA,EAAO,OAAO,CAAA,EAAE;AAAA,IAC/H;AAAA,MACE,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,MAAM,OAAA,CAAQ,YAAA;AAAA,MACd,IAAA,EAAM,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,OAAA,CAAQ,OAAA,CAAQ,YAAY,CAAA,EAAG,OAAO;AAAA,KACrG;AAAA,IACA;AAAA,MACE,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,MAAM,IAAA,CAAK,KAAA;AAAA,MACX,MAAM,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS;AAAA;AACvD,GACF;AAEA,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,gBAAA;AAAA,IACT,eAAA,EAAiB;AAAA,GACnB;AACF;AAKO,SAAS,4BAAA,CACd,OAAA,EACA,OAAA,GAA+E,EAAC,EACxE;AACR,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAI,QAAA,EAAS,GAAI,OAAA;AAEnC,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,gBAAA;AAAA,IACT,MAAM,OAAA,CAAQ,YAAA;AAAA,IACd,WAAA,EAAa,CAAA,uBAAA,EAA0B,OAAA,CAAQ,UAAU,CAAA,CAAA;AAAA,IACzD,GAAA,EAAK,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,OAAA,CAAQ,OAAA,CAAQ,YAAY,CAAA,EAAG,OAAO,CAAA;AAAA,IAClG,GAAI,QAAA,IAAY;AAAA,MACd,UAAU,EAAE,OAAA,EAAS,WAAW,IAAA,EAAM,QAAA,EAAU,KAAK,OAAA;AAAQ,KAC/D;AAAA,IACA,UAAA,EAAY,QAAQ,MAAA,GAChB;AAAA,MACE,OAAA,EAAS,SAAA;AAAA,MACT,QAAA,EAAU,QAAQ,MAAA,CAAO,KAAA;AAAA,MACzB,GAAA,EAAK,kBAAkB,OAAA,CAAQ,MAAA,EAAQ,EAAE,GAAG,OAAA,EAAS,SAAS;AAAA,KAChE,GACA,MAAA;AAAA,IACJ,OAAA,EAAS,OAAA,CAAQ,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MACpC,OAAA,EAAS,SAAA;AAAA,MACT,UAAU,CAAA,CAAE,KAAA;AAAA,MACZ,KAAK,iBAAA,CAAkB,CAAA,EAAG,EAAE,GAAG,OAAA,EAAS,SAAS;AAAA,KACnD,CAAE;AAAA,GACJ;AACF;AAKA,eAAsB,2BAAA,CACpB,WAAA,EACA,OAAA,GAA+E,EAAC,EAChF;AACA,EAAA,MAAM,OAAA,GAAU,MAAM,eAAA,CAAgB,WAAW,CAAA;AACjD,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AAEtB,EAAA,MAAM,EAAE,QAAA,GAAW,EAAA,EAAI,OAAA,GAAU,IAAG,GAAI,OAAA;AACxC,EAAA,MAAM,KAAA,GAAQ,GAAG,OAAA,CAAQ,YAAY,GAAG,QAAA,GAAW,CAAA,GAAA,EAAM,QAAQ,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA;AACxE,EAAA,MAAM,cAAc,CAAA,uBAAA,EAA0B,OAAA,CAAQ,UAAU,CAAA,EAAA,EAAK,QAAQ,aAAa,CAAA,+CAAA,CAAA;AAE1F,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA;AAAA,MACA,WAAA;AAAA,MACA,GAAA,EAAK,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,OAAA,CAAQ,OAAA,CAAQ,YAAY,CAAA,EAAG,OAAO,CAAA;AAAA,MAClG,IAAA,EAAM;AAAA;AACR,GACF;AACF;AAKA,eAAsB,kBAAA,CACpB,WAAA,EACA,OAAA,GAAgH,EAAC,EACvF;AAC1B,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,EAAC;AACrB,EAAA,MAAM,EAAE,KAAA,GAAQ,CAAA,EAAG,IAAA,EAAK,GAAI,OAAA;AAS5B,EAAA,MAAM,UAAU,MAAM,UAAA,CAAW,WAAA,EAAa,EAAE,MAAM,CAAA;AACtD,EAAA,IAAI,CAAC,OAAA,EAAS,EAAA,EAAI,OAAO,EAAC;AAE1B,EAAA,OAAO,oBAAA,CAAqB,EAAE,GAAG,MAAA,EAAQ,IAAA,EAAK,EAAG,OAAA,CAAQ,EAAA,EAAI,KAAA,EAAO,EAAE,UAAA,EAAY,GAAA,EAAK,CAAA;AACzF;AASO,SAAS,wBAAA,CACd,IAAA,EACA,OAAA,GAA+E,EAAC,EACxE;AACR,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAI,QAAA,GAAW,QAAO,GAAI,OAAA;AAE5C,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ;AAAA,MACE,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,IAAA,EAAM,QAAA;AAAA,MACN,IAAA,EAAM;AAAA,KACR;AAAA,IACA;AAAA,MACE,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,IAAA,EAAM,MAAA;AAAA,MACN,MAAM,qBAAA,CAAsB,uBAAA,CAAwB,OAAO,CAAA,CAAE,OAAO,OAAO;AAAA;AAC7E,GACF;AAEA,EAAA,IAAI,KAAK,QAAA,EAAU;AACjB,IAAA,MAAM,YAAA,GAAe,OAAO,IAAA,CAAK,QAAA,KAAa,WAAW,IAAA,CAAK,QAAA,GAAW,KAAK,QAAA,CAAS,IAAA;AACvF,IAAA,MAAM,YAAA,GAAe,OAAO,IAAA,CAAK,QAAA,KAAa,WAC1C,IAAA,CAAK,QAAA,CAAS,WAAA,EAAY,CAAE,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,GAC/C,KAAK,QAAA,CAAS,IAAA;AAElB,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,IAAA,EAAM,YAAA;AAAA,MACN,IAAA,EAAM,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,QAAA,CAAS,YAAY,GAAG,OAAO;AAAA,KAC7F,CAAA;AAED,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,MAAM,IAAA,CAAK,KAAA;AAAA,MACX,MAAM,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS;AAAA,KACtD,CAAA;AAAA,EACH,CAAA,MAAO;AACL,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,MAAM,IAAA,CAAK,KAAA;AAAA,MACX,MAAM,iBAAA,CAAkB,IAAA,EAAM,EAAE,GAAG,OAAA,EAAS,SAAS;AAAA,KACtD,CAAA;AAAA,EACH;AAEA,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,gBAAA;AAAA,IACT,eAAA,EAAiB;AAAA,GACnB;AACF;AAWO,SAAS,yBAAA,CACd,IAAA,EACA,OAAA,GAAiG,EAAC,EACxF;AACV,EAAA,MAAM,UAAoB,EAAC;AAO3B,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,MAAA,IAAU,IAAA,CAAK,WAAA;AACvC,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,MAAM,MAAM,KAAA,CAAM,OAAA,CAAQ,UAAU,CAAA,GAAI,UAAA,GAAa,CAAC,UAAU,CAAA;AAChE,IAAA,OAAA,CAAQ,IAAA,CAAK,GAAG,GAAG,CAAA;AAAA,EACrB,CAAA,MAAO;AAEL,IAAA,OAAA,CAAQ,IAAA,CAAK,qBAAA,CAAsB,IAAA,EAAM,OAAO,CAAC,CAAA;AAGjD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,IAAc,IAAA,CAAa,QAAA;AACjD,IAAA,IAAI,QAAA,IAAY,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AACnC,MAAA,MAAM,SAAA,GAAY,kBAAkB,QAAQ,CAAA;AAC5C,MAAA,IAAI,SAAA,EAAW,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAA;AAAA,IACvC;AAAA,EACF;AAGA,EAAA,OAAA,CAAQ,IAAA,CAAK,wBAAA,CAAyB,IAAA,EAAM,OAAO,CAAC,CAAA;AAEpD,EAAA,OAAO,OAAA;AACT;AASA,eAAsB,eAAA,CACpB,MACA,OAAA,EAC+B;AAC/B,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAA,CAAQ,KAAK,kCAAkC,CAAA;AAC/C,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAA;AAE3B,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,aAAA,CAAc,CAAA,EAAG,MAAM,CAAA,yBAAA,EAA4B,IAAI,CAAA,CAAA,EAAI,OAAA,EAAS,IAAI,CAAA,EAAG;AAAA,MACtG,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,MAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,EAAA;AAAG,KACxB,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,IAAA;AAEzB,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO,KAAK,MAAA,IAAU,IAAA;AAAA,EACxB,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,qCAAqC,KAAK,CAAA;AACxD,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAWA,eAAsB,eACpB,IAAA,EACA,KAAA,GAAQ,EAAA,EACR,MAAA,GAAS,GACT,OAAA,EACkF;AAClF,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAA,CAAQ,KAAK,kCAAkC,CAAA;AAC/C,IAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,OAAO,EAAC,EAAG,OAAO,CAAA,EAAE;AAAA,EAC7C;AACA,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAA;AAE3B,EAAA,IAAI;AACF,IAAA,MAAM,WAAW,MAAM,KAAA;AAAA,MACrB,aAAA,CAAc,CAAA,EAAG,MAAM,CAAA,yBAAA,EAA4B,IAAI,CAAA,aAAA,EAAgB,KAAK,CAAA,QAAA,EAAW,MAAM,CAAA,CAAA,EAAI,OAAA,EAAS,IAAI,CAAA;AAAA,MAC9G;AAAA,QACE,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,QAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,EAAA;AAAG;AACzB,KACF;AAEA,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,KAAA,EAAO,EAAC,EAAG,KAAA,EAAO,CAAA,EAAE;AAE7D,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,IAAI,MAAA,GAA+B,KAAK,MAAA,IAAU,IAAA;AAClD,IAAA,IAAI,MAAA,IAAU,MAAA,CAAO,EAAA,KAAO,KAAA,CAAA,EAAW;AACrC,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,eAAA,CAAgB,IAAA,EAAM,OAAO,CAAA;AAChD,QAAA,IAAI,MAAM,MAAA,GAAS,IAAA;AAAA,MACrB,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,OAAO;AAAA,MACL,MAAA;AAAA,MACA,KAAA,EAAO,IAAA,CAAK,KAAA,IAAS,EAAC;AAAA,MACtB,KAAA,EAAO,KAAK,KAAA,IAAS;AAAA,KACvB;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,2CAA2C,KAAK,CAAA;AAC9D,IAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,OAAO,EAAC,EAAG,OAAO,CAAA,EAAE;AAAA,EAC7C;AACF;AAKA,eAAsB,iBAAA,GAAiD;AACrE,EAAA,MAAM,SAAS,sBAAA,EAAuB;AACtC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAA,CAAQ,KAAK,kCAAkC,CAAA;AAC/C,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,MAAA;AAE3B,EAAA,IAAI;AACF,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,cAAc,CAAA,EAAG,MAAM,0BAA0B,CAAA,EAAG;AAAA,MAC/E,OAAA,EAAS,EAAE,WAAA,EAAa,MAAA,EAAO;AAAA,MAC/B,IAAA,EAAM,EAAE,UAAA,EAAY,GAAA;AAAI,KACzB,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,EAAC;AAE1B,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,MAAM,OAAA,GAA2B,IAAA,CAAK,OAAA,IAAW,EAAC;AAClD,IAAA,OAAO,OAAA,CAAQ,IAAI,CAAC,CAAA,MAAO,EAAE,IAAA,EAAM,CAAA,CAAE,MAAK,CAAE,CAAA;AAAA,EAC9C,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,2CAA2C,KAAK,CAAA;AAC9D,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAQA,eAAsB,0BAAA,GAA0D;AAC9E,EAAA,OAAO,iBAAA,EAAkB;AAC3B;AASO,SAAS,0BAAA,CACd,MAAA,EACA,OAAA,GAA+E,EAAC,EACtE;AACV,EAAA,MAAM,EAAE,OAAA,GAAU,EAAA,EAAI,QAAA,EAAS,GAAI,OAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,CAAA,EAAG,MAAA,CAAO,IAAI,CAAA,EAAG,MAAA,CAAO,KAAA,GAAQ,CAAA,GAAA,EAAM,MAAA,CAAO,KAAK,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA;AACvE,EAAA,MAAM,cAAc,MAAA,CAAO,SAAA,IAAa,OAAO,GAAA,IAAO,CAAA,YAAA,EAAe,OAAO,IAAI,CAAA,CAAA;AAChF,EAAA,MAAM,GAAA,GAAM,sBAAsB,uBAAA,CAAwB,OAAO,EAAE,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA,EAAG,OAAO,CAAA;AAE/F,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA;AAAA,MACA,WAAA;AAAA,MACA,GAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA,EAAM,SAAA;AAAA,MACN,GAAI,MAAA,CAAO,UAAA,IAAc,EAAE,MAAA,EAAQ,CAAC,EAAE,GAAA,EAAK,MAAA,CAAO,UAAA,EAAY,CAAA;AAAE,KAClE;AAAA,IACA,OAAA,EAAS;AAAA,MACP,IAAA,EAAM,SAAA;AAAA,MACN,KAAA;AAAA,MACA,WAAA;AAAA,MACA,GAAI,OAAO,UAAA,IAAc,EAAE,QAAQ,CAAC,MAAA,CAAO,UAAU,CAAA;AAAE,KACzD;AAAA,IACA,UAAA,EAAY;AAAA,MACV,SAAA,EAAW,OAAO,eAAA,IAAmB;AAAA;AACvC,GACF;AACF","file":"chunk-X3MY4PL7.mjs","sourcesContent":["/**\n * @sonordev/site-kit/articles — shared public article reads (leaf module)\n *\n * SINGLE SOURCE OF TRUTH for the three article reads that both `server-core`\n * (credentials from resolveServerApiConfig) and the server-ui components\n * (credentials from their `apiUrl` / `apiKey` props) make:\n *\n * - post by slug — getArticle, <Article>\n * - categories — getArticleCategories, <ArticleList>, <PublicationSidebar>\n * - related posts — getRelatedInsights, <Article>, <RelatedPosts>\n *\n * Each used to be copied into every caller, which is how one copy of the\n * related read kept a camelCase body and a wrong path long after the others\n * were fixed (see the notes in RelatedPosts). Adding the multi-site `site`\n * dimension would have meant a fourth edit to each copy, so they live here now.\n *\n * A leaf on purpose: it takes credentials as arguments and imports no\n * `server-only` code, because the client-stamped `articles` barrel reaches it\n * through ArticleList / Article / PublicationSidebar. Callers resolve credentials; this\n * module only talks to the API.\n */\nimport { withSiteBody, withSiteParam } from '../sites/site-param'\nimport type { ArticleCategory, Article } from './types'\n\nexport interface ArticleReadConfig {\n apiUrl: string\n apiKey: string\n /** Sub-site host override. Omit to resolve from NEXT_PUBLIC_SITE_URL. */\n site?: string\n}\n\n/** GET /public/articles/posts/:slug — null when missing or on any failure. */\nexport async function fetchArticleBySlug(\n { apiUrl, apiKey, site }: ArticleReadConfig,\n slug: string\n): Promise<Article | null> {\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/articles/posts/${slug}`, site), {\n headers: { 'x-api-key': apiKey },\n next: { revalidate: 60 },\n })\n if (!response.ok) {\n if (response.status !== 404) console.error('[Articles] Failed to fetch post:', response.statusText)\n return null\n }\n const data = await response.json()\n return data.post || null\n } catch (error) {\n console.error('[Articles] Error fetching post:', error)\n return null\n }\n}\n\n/** GET /public/articles/categories — [] on any failure. */\nexport async function fetchArticleCategories({ apiUrl, apiKey, site }: ArticleReadConfig): Promise<ArticleCategory[]> {\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/articles/categories`, 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.categories || []\n } catch (error) {\n console.error('[Articles] Error fetching categories:', error)\n return []\n }\n}\n\n/**\n * POST /public/articles/related — [] on any failure.\n *\n * `/public/articles/*`, not `/api/public/articles/*`: public-article.controller is one of\n * only two public controllers whose @Controller() omits the `api/` segment.\n * The body is snake_case `current_post_id` (the controller looks the post up\n * by id — there is no slug path), and `site` rides in the body because this is\n * the one article read that isn't a GET.\n *\n * `revalidate` is optional so <RelatedPosts>, which never set a fetch cache\n * lifetime, keeps rendering exactly as it did.\n */\nexport async function fetchRelatedArticles(\n { apiUrl, apiKey, site }: ArticleReadConfig,\n currentPostId: string,\n limit: number,\n cache: { revalidate?: number } = {}\n): Promise<Article[]> {\n try {\n const response = await fetch(`${apiUrl}/public/articles/related`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },\n body: JSON.stringify(withSiteBody({ current_post_id: currentPostId, limit }, site)),\n ...(cache.revalidate !== undefined ? { next: { revalidate: cache.revalidate } } : {}),\n })\n if (!response.ok) {\n console.error('[Articles] Failed to fetch related posts:', response.statusText)\n return []\n }\n const data = await response.json()\n return data.posts || []\n } catch (error) {\n console.error('[Articles] Error fetching related posts:', error)\n return []\n }\n}\n","/**\n * Excerpt sanitizing for article 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 article 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 * Google News sitemap and feed-size helpers. Pure, environment-free: the\n * server helpers in server-core fetch the posts and hand them here, so the XML\n * rules can be tested without a network.\n *\n * News sitemap rules (https://developers.google.com/search/docs/crawling-indexing/sitemaps/news-sitemap):\n * only articles published in the last two days, at most 1,000 URLs, each with\n * a publication name, language and publication date. Older articles belong in\n * the ordinary sitemap, which already lists them.\n */\nimport { resolveArticleUrl, type PublicationRoutingOptions, type ArticleRoutePost } from './routes'\n\n/** Google only reads articles from the last two days in a News sitemap. */\nexport const NEWS_SITEMAP_WINDOW_MS = 2 * 24 * 60 * 60 * 1000\n/** Google's cap per News sitemap. */\nexport const NEWS_SITEMAP_MAX_URLS = 1000\n\n/**\n * Items a feed carries by default. Feeds hold each post's full HTML, so a\n * 100-post feed ran past half a megabyte, which is where some readers and\n * aggregators stop fetching. Readers poll often; 20 recent items is the\n * common convention, and older posts stay in the sitemap.\n */\nexport const FEED_DEFAULT_ITEMS = 20\n\nexport interface NewsSitemapPost extends ArticleRoutePost {\n title: string\n published_at?: string | null\n}\n\nexport interface NewsSitemapOptions extends PublicationRoutingOptions {\n siteUrl: string\n /** The publication name, exactly as it appears on the articles (e.g. \"The Forge by Upforge\"). */\n publicationName: string\n /** ISO 639 language code. Defaults to \"en\". */\n language?: string\n}\n\nexport function 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 * Wrap HTML in CDATA. A literal `]]>` inside the post would close the section\n * early and break the whole feed, so it's split across two sections.\n */\nexport function cdata(html: string): string {\n return `<![CDATA[${html.replace(/]]>/g, ']]]]><![CDATA[>')}]]>`\n}\n\n/** The posts a News sitemap may list: published in the window, newest first. */\nexport function recentNewsPosts<T extends NewsSitemapPost>(posts: T[], now: Date = new Date()): T[] {\n const cutoff = now.getTime() - NEWS_SITEMAP_WINDOW_MS\n return posts\n .filter((post) => {\n const published = post.published_at ? Date.parse(post.published_at) : NaN\n return Number.isFinite(published) && published >= cutoff && published <= now.getTime()\n })\n .sort((a, b) => Date.parse(b.published_at!) - Date.parse(a.published_at!))\n .slice(0, NEWS_SITEMAP_MAX_URLS)\n}\n\n/**\n * Build a Google News sitemap. With no post in the window it's a valid, empty\n * urlset, which Google accepts; it fills again on the next publish.\n */\nexport function buildNewsSitemapXml(\n posts: NewsSitemapPost[],\n options: NewsSitemapOptions,\n now: Date = new Date(),\n): string {\n const language = options.language || 'en'\n const items = recentNewsPosts(posts, now).map((post) => {\n const url = resolveArticleUrl(post, { ...options, siteUrl: options.siteUrl })\n return ` <url>\n <loc>${escapeXml(url)}</loc>\n <news:news>\n <news:publication>\n <news:name>${escapeXml(options.publicationName)}</news:name>\n <news:language>${escapeXml(language)}</news:language>\n </news:publication>\n <news:publication_date>${new Date(post.published_at!).toISOString()}</news:publication_date>\n <news:title>${escapeXml(post.title)}</news:title>\n </news:news>\n </url>`\n })\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\">\n${items.join('\\n')}${items.length ? '\\n' : ''}</urlset>`\n}\n","/**\n * @sonordev/site-kit/articles/server\n *\n * Data and metadata helpers only (no React components). For `Article` / `ArticleList`\n * in the App Router, import from `@sonordev/site-kit/articles/server-ui` so Next never\n * treats `getAllArticleSlugs` / `generateArticleStaticParams` as client code.\n */\n\nimport type { Metadata } from 'next'\nimport { notFound } from 'next/navigation'\nimport type { Article as ArticleRecord, ArticleAuthor, 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/articles` 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 { fetchArticleCategories, fetchArticleBySlug, fetchRelatedArticles } from './public-reads'\nimport { sanitizeExcerpt } from './excerpt'\nimport { resolveArticleArtwork } from './artwork'\nimport { articleCategorySlug, createPublicationRoutes, resolveArticleUrl, resolvePublicationUrl, type PublicationRoutingOptions, type ArticleRoutePost } from './routes'\nimport { FEED_DEFAULT_ITEMS, buildNewsSitemapXml, cdata, escapeXml, type NewsSitemapOptions } from './news-sitemap'\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 an article\n */\nexport function validateArticleSeo(post: Partial<ArticleRecord>): 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 article 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. `getAllArticleSlugs` 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 an article 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 getArticle(\n slug: string,\n options?: { site?: string }\n): Promise<ArticleRecord | null> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Articles] No API key configured')\n return null\n }\n return fetchArticleBySlug({ ...config, site: options?.site }, slug)\n}\n\n/**\n * Fetch an article by slug, or answer 404 when there isn't one.\n *\n * `getArticle` 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 `Article`:\n * metadata resolves before anything streams, so the status is a real 404.\n * The fetch is the same one `Article` and `generateArticleMetadata` 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 requireArticle(slug)\n * return generateArticleMetadata(slug, { siteName: 'Acme' })\n * }\n * ```\n */\nexport async function requireArticle(\n slug: string,\n options?: { site?: string }\n): Promise<ArticleRecord> {\n const post = await getArticle(slug, options)\n if (!post) notFound()\n return post\n}\n\n/**\n * Fetch all article slugs for static generation\n */\nexport async function getAllArticleSlugs(): Promise<\n { slug: string; id?: string; last_modified?: string; article_type?: string }[]\n> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Articles] No API key configured')\n return []\n }\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/articles/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('[Articles] Error fetching slugs:', error)\n return []\n }\n}\n\n/**\n * Fetch article categories\n */\nexport async function getArticleCategories(\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; ArticleCategory types it\n // optional because the dashboard shape omits it.\n return (await fetchArticleCategories({ ...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 PublicationMetadataOptions extends PublicationRoutingOptions {\n /** Site name for og:site_name */\n siteName?: string\n /** Base URL of the site */\n siteUrl?: string\n /** URL path prefix for publication index and posts (default `/article`, e.g. `/insights`) */\n /** Default OG image */\n defaultImage?: string\n /** Twitter handle */\n twitterHandle?: string\n}\n\nexport interface ArticleMetadataOptions extends PublicationMetadataOptions {\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 an article page\n */\nexport async function generateArticleMetadata(\n slug: string,\n options: ArticleMetadataOptions = {}\n): Promise<Metadata> {\n const post = await getArticle(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 article 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 = resolveArticleUrl(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 publication index page\n */\nexport function generatePublicationMetadata(options: PublicationMetadataOptions & {\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 = createPublicationRoutes(options).index\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n url: resolvePublicationUrl(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 generateArticleCategoryMetadata(\n categoryName: string,\n options: PublicationMetadataOptions & { categorySlug?: string } = {}\n): Metadata {\n const { siteName, siteUrl = '', defaultImage } = options\n const title = `${categoryName} - Articles`\n const description = `Browse all posts in ${categoryName}.`\n // The URL wants the route slug, not the display name: lowercasing \"Case\n // Studies\" produced /article/category/case%20studies against a real route of\n // /article/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: resolvePublicationUrl(createPublicationRoutes(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 publication 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: PublicationRoutingOptions | NextStaticParamsProps): value is NextStaticParamsProps {\n return 'params' in value\n}\n\n/**\n * Generate static params for article pages.\n *\n * Export it directly for the default `/article/[slug]` routes:\n *\n * export const generateStaticParams = generateArticleStaticParams\n *\n * With routing options, wrap it:\n *\n * export function generateStaticParams() {\n * return generateArticleStaticParams(routing)\n * }\n */\nexport function generateArticleStaticParams(options?: PublicationRoutingOptions): 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// `PublicationRoutingOptions` parameter fails both (site-kit 5.4.0–5.6.1).\nexport function generateArticleStaticParams(props: NextStaticParamsProps): Promise<{ slug: string; category?: string }[]>\nexport async function generateArticleStaticParams(\n arg: PublicationRoutingOptions | NextStaticParamsProps = {},\n): Promise<{ slug: string; category?: string }[]> {\n // Called by Next as `generateStaticParams({ params })`: use the defaults.\n const options: PublicationRoutingOptions = isNextStaticParamsProps(arg) ? {} : arg\n const posts = await getArticleRouteEntries(options)\n return posts.map(post => {\n const category = articleCategorySlug(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 getArticleCategories()\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 /** Image sitemap entries; Next's MetadataRoute.Sitemap renders them as <image:image>. */\n images?: string[]\n}\n\n/** A post's featured image as an absolute URL, for image sitemaps. */\nfunction absoluteImage(image: string | undefined | null, siteUrl: string): string | null {\n const value = image?.trim()\n if (!value) return null\n try {\n return new URL(value, siteUrl.endsWith('/') ? siteUrl : `${siteUrl}/`).toString()\n } catch {\n return null\n }\n}\n\n/**\n * Generate sitemap entries for articles\n */\nexport interface ArticleSitemapOptions extends PublicationRoutingOptions {\n includeCategories?: boolean\n includeClusters?: boolean\n}\n\n/** Sitemaps need canonicals; nested/custom static params also need full route records. */\nasync function getArticleRouteEntries(options: PublicationRoutingOptions, withCanonicals = false): Promise<Array<ArticleRoutePost & { last_modified?: string; article_type?: string; featured_image?: string }>> {\n if (withCanonicals || options.includeCategoryInPath || options.postPath) {\n return (await getAllArticles({ maxPosts: Infinity })).map(post => ({ ...post, last_modified: post.updated_at }))\n }\n return getAllArticleSlugs()\n}\n\nexport async function generateArticleSitemap(\n siteUrl: string,\n options: ArticleSitemapOptions = {},\n): Promise<SitemapEntry[]> {\n const slugs = await getArticleRouteEntries(options, true)\n const categories = options.includeCategories === false ? [] : await getArticleCategories()\n const clusters = options.includeClusters === false ? [] : await getTopicClusters()\n\n const entries: SitemapEntry[] = [\n // Publication index\n {\n url: resolvePublicationUrl(createPublicationRoutes(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: resolvePublicationUrl(createPublicationRoutes(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: resolvePublicationUrl(createPublicationRoutes(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 const image = absoluteImage(post.featured_image, siteUrl)\n entries.push({\n url: resolveArticleUrl(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 ...(image ? { images: [image] } : {}),\n })\n })\n\n return entries\n}\n\n/**\n * Google News sitemap XML for posts published in the last two days. Serve it\n * from a route (app/news-sitemap.xml/route.ts) and list it in robots.txt.\n */\nexport async function generateNewsSitemap(options: NewsSitemapOptions & { site?: string }): Promise<string> {\n // A window of two days never needs more than the newest page of posts.\n const posts = await getAllArticles({ maxPosts: 50, site: options.site })\n return buildNewsSitemapXml(posts, options)\n}\n\n// ============================================================================\n// JSON-LD SCHEMA GENERATION\n// ============================================================================\n\n/**\n * Generate JSON-LD schema for an article\n */\nexport function generateArticleSchema(\n post: ArticleRecord,\n options: PublicationRoutingOptions & { 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: resolveArticleUrl(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 = resolveArticleArtwork(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 publication index/listing page\n */\nexport function generateArticleListSchema(\n options: PublicationRoutingOptions & { 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: resolvePublicationUrl(createPublicationRoutes(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: ArticleRecord,\n steps: HowToStep[],\n options: PublicationRoutingOptions & { 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: resolveArticleArtwork(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 || `${resolveArticleUrl(post, { ...options, siteUrl }).split(\"#\")[0]}#step-${index + 1}`,\n })),\n }\n}\n\n// ============================================================================\n// RSS FEED GENERATION\n// ============================================================================\n\nexport interface RssFeedOptions extends PublicationRoutingOptions {\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 /** Most recent posts to include. Defaults to FEED_DEFAULT_ITEMS (20); older posts stay in the sitemap. */\n maxItems?: number\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 articles 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 getAllArticles(\n options: { maxPosts?: number; /** Sub-site host override (see getArticle). */ site?: string } = {}\n): Promise<ArticleRecord[]> {\n const maxPosts = options.maxPosts ?? FEED_MAX_POSTS\n if (!(maxPosts > 0)) return []\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Articles] No API key configured')\n return []\n }\n const { apiUrl, apiKey } = config\n\n const posts: ArticleRecord[] = []\n let page = 1\n try {\n while (posts.length < maxPosts) {\n const response = await fetch(\n withSiteParam(`${apiUrl}/public/articles/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('[Articles] Error fetching posts for RSS:', error)\n }\n return posts.slice(0, maxPosts)\n}\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 articles and insights',\n language = 'en-us',\n copyright,\n managingEditor,\n webMaster,\n ttl = 60,\n imageUrl,\n } = options\n\n const posts = await getAllArticles({ maxPosts: options.maxItems ?? FEED_DEFAULT_ITEMS })\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(resolvePublicationUrl(createPublicationRoutes(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 = resolveArticleUrl(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 articles and insights',\n managingEditor,\n } = options\n\n const posts = await getAllArticles({ maxPosts: options.maxItems ?? FEED_DEFAULT_ITEMS })\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(resolvePublicationUrl(createPublicationRoutes(options).atom, siteUrl))}\" rel=\"self\"/>\n <link href=\"${siteUrl}\"/>\n <id>${escapeXml(resolvePublicationUrl(createPublicationRoutes(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 = resolveArticleUrl(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/articles/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('[Articles] 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/articles/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('[Articles] Error fetching topic cluster:', error)\n return null\n }\n}\n\n/**\n * Get cluster navigation context for an article.\n * Returns the cluster name, pillar link, and sibling articles.\n */\nexport function getClusterNavigation(post: ArticleRecord): ClusterNavigation | null {\n if (!post.cluster_id && !post.cluster_slug) return null\n\n const isPillar = post.article_type === 'pillar'\n\n // Mirrored copy: Article.tsx has an identical builder. Keep the two in\n // sync — they CANNOT be consolidated because articles/index is a CLIENT_ENTRY\n // that must never import articles/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: ArticleRecord\n supportingPosts: ArticleRecord[]\n internalLinks: Array<{ from: string; to: string; anchor: string }>\n} | null> {\n console.warn(\n '[Articles] 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<ArticleRecord[]> {\n const config = resolveServerApiConfig()\n if (!config) return []\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/articles/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('[Articles] 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: PublicationRoutingOptions & { 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: resolveArticleUrl(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: ArticleRecord,\n cluster: TopicCluster,\n options: PublicationRoutingOptions & { 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: resolveArticleUrl(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 = resolveArticleArtwork(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: resolveArticleUrl(s, { ...options, siteUrl }),\n }))\n } else if (!isPillar && cluster.pillar) {\n schema.isPartOf = {\n '@type': 'Article',\n headline: cluster.pillar.title,\n url: resolveArticleUrl(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 > Article > Cluster > Article\n */\nexport function generateClusterBreadcrumbSchema(\n post: ArticleRecord,\n cluster: TopicCluster,\n options: PublicationRoutingOptions & { 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: resolvePublicationUrl(createPublicationRoutes(options).index, siteUrl) },\n {\n '@type': 'ListItem',\n position: 3,\n name: cluster.cluster_name,\n item: resolvePublicationUrl(createPublicationRoutes(options).cluster(cluster.cluster_slug), siteUrl),\n },\n {\n '@type': 'ListItem',\n position: 4,\n name: post.title,\n item: resolveArticleUrl(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: PublicationRoutingOptions & { 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: resolvePublicationUrl(createPublicationRoutes(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: resolveArticleUrl(cluster.pillar, { ...options, siteUrl }),\n }\n : undefined,\n hasPart: cluster.supports.map((s) => ({\n '@type': 'Article',\n headline: s.title,\n url: resolveArticleUrl(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: PublicationRoutingOptions & { 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: resolvePublicationUrl(createPublicationRoutes(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 getArticle). */ site?: string } = {}\n): Promise<ArticleRecord[]> {\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 getArticle), then ask with the id.\n const current = await getArticle(currentSlug, { site })\n if (!current?.id) return []\n\n return fetchRelatedArticles({ ...config, site }, current.id, limit, { revalidate: 300 })\n}\n\n// ============================================================================\n// BREADCRUMB SCHEMA\n// ============================================================================\n\n/**\n * Generate BreadcrumbList schema for article navigation\n */\nexport function generateBreadcrumbSchema(\n post: ArticleRecord,\n options: PublicationRoutingOptions & { 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: resolvePublicationUrl(createPublicationRoutes(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: resolvePublicationUrl(createPublicationRoutes(options).category(categorySlug), siteUrl),\n })\n\n items.push({\n '@type': 'ListItem',\n position: 4,\n name: post.title,\n item: resolveArticleUrl(post, { ...options, siteUrl }),\n })\n } else {\n items.push({\n '@type': 'ListItem',\n position: 3,\n name: post.title,\n item: resolveArticleUrl(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 an article 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 generateAllArticleSchemas(\n post: ArticleRecord,\n options: PublicationRoutingOptions & { 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 getArticle — 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(generateArticleSchema(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<ArticleAuthor | null> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Articles] No API key configured')\n return null\n }\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/articles/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('[Articles] 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: ArticleAuthor | null; posts: ArticleRecord[]; total: number }> {\n const config = resolveServerApiConfig()\n if (!config) {\n console.warn('[Articles] 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/articles/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: ArticleAuthor | 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('[Articles] 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('[Articles] No API key configured')\n return []\n }\n const { apiUrl, apiKey } = config\n\n try {\n const response = await fetch(withSiteParam(`${apiUrl}/public/articles/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: ArticleAuthor[] = data.authors || []\n return authors.map((a) => ({ slug: a.slug }))\n } catch (error) {\n console.error('[Articles] 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: ArticleAuthor,\n options: PublicationRoutingOptions & { 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 = resolvePublicationUrl(createPublicationRoutes(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 `articles` 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/articles/server`\n * keeps its existing public API.\n */\nexport { generateAuthorSchema } from './author-schema'\n\n// -----------------------------------------------------------------------------\n// Article UI (Article, ArticleList) lives in `@sonordev/site-kit/articles/server-ui`.\n// This entry must stay free of React components so Next never marks server\n// helpers (e.g. getAllArticleSlugs) as client — see tsup onSuccess \"use client\".\n// -----------------------------------------------------------------------------\n\n/** Portal article document shape (alias of `Article` from `./types`) */\nexport type { Article as ArticleRecord } from './types'\n\nexport { articleCategorySlug, createPublicationRoutes, resolveArticleUrl, resolvePublicationUrl } from './routes'\nexport type { ArticleRoutePost, PublicationRoutingOptions } from './routes'\nexport { resolveArticleArtwork } from './artwork'\nexport { wrapArticleTables, articleTableCss } from './article-tables'\nexport { FEED_DEFAULT_ITEMS, NEWS_SITEMAP_MAX_URLS, NEWS_SITEMAP_WINDOW_MS, buildNewsSitemapXml, cdata, recentNewsPosts } from './news-sitemap'\nexport type { NewsSitemapOptions, NewsSitemapPost } from './news-sitemap'\n"]}
|
package/dist/chunk-YRCR7WY3.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkZR43XFUM_js = require('./chunk-ZR43XFUM.js');
|
|
4
|
-
|
|
5
|
-
// src/articles/artwork.ts
|
|
6
|
-
function resolveArticleArtwork(post, placement = "card") {
|
|
7
|
-
const editorial = placement === "article" && !!post.editorial_image;
|
|
8
|
-
const src = (editorial ? post.editorial_image : post.featured_image) || void 0;
|
|
9
|
-
const alt = editorial ? post.editorial_image_alt ?? "" : post.featured_image_alt ?? post.title ?? "";
|
|
10
|
-
let composed = false;
|
|
11
|
-
if (src) {
|
|
12
|
-
try {
|
|
13
|
-
composed = /\/Blog\/Cards\//i.test(new URL(src, "https://site-kit.invalid").pathname);
|
|
14
|
-
} catch {
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return { src, alt, composed };
|
|
18
|
-
}
|
|
19
|
-
function articleArtworkImageStyle(artwork) {
|
|
20
|
-
return artwork.composed ? { display: "block", height: "auto", maxHeight: "none", objectFit: "contain", transform: "none" } : void 0;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// src/articles/author-schema.ts
|
|
24
|
-
function generateAuthorSchema(author, options = {}) {
|
|
25
|
-
const { siteUrl = "", siteName } = options;
|
|
26
|
-
const sameAs = [...author.same_as || []];
|
|
27
|
-
if (author.linkedin_url) sameAs.push(author.linkedin_url);
|
|
28
|
-
if (author.twitter_url) sameAs.push(author.twitter_url);
|
|
29
|
-
if (author.website_url) sameAs.push(author.website_url);
|
|
30
|
-
if (author.social_links?.twitter) sameAs.push(`https://twitter.com/${author.social_links.twitter}`);
|
|
31
|
-
if (author.social_links?.linkedin) sameAs.push(author.social_links.linkedin);
|
|
32
|
-
if (author.social_links?.github) sameAs.push(`https://github.com/${author.social_links.github}`);
|
|
33
|
-
const uniqueSameAs = [...new Set(sameAs.filter(Boolean))];
|
|
34
|
-
const schema = {
|
|
35
|
-
"@context": "https://schema.org",
|
|
36
|
-
"@type": "Person",
|
|
37
|
-
name: author.name,
|
|
38
|
-
url: author.author_page_url || chunkZR43XFUM_js.resolvePublicationUrl(chunkZR43XFUM_js.createPublicationRoutes(options).author(author.slug), siteUrl)
|
|
39
|
-
};
|
|
40
|
-
if (author.title) schema.jobTitle = author.title;
|
|
41
|
-
if (author.company || siteName) {
|
|
42
|
-
schema.worksFor = {
|
|
43
|
-
"@type": "Organization",
|
|
44
|
-
name: author.company || siteName,
|
|
45
|
-
...siteUrl ? { url: siteUrl } : {}
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
if (author.bio || author.short_bio) schema.description = author.short_bio || author.bio;
|
|
49
|
-
if (author.avatar_url) schema.image = author.avatar_url;
|
|
50
|
-
if (uniqueSameAs.length > 0) schema.sameAs = uniqueSameAs;
|
|
51
|
-
if (author.knows_about && author.knows_about.length > 0) schema.knowsAbout = author.knows_about;
|
|
52
|
-
if (author.credentials && author.credentials.length > 0) {
|
|
53
|
-
schema.hasCredential = author.credentials.map((c) => ({
|
|
54
|
-
"@type": "EducationalOccupationalCredential",
|
|
55
|
-
credentialCategory: c
|
|
56
|
-
}));
|
|
57
|
-
}
|
|
58
|
-
return schema;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
exports.articleArtworkImageStyle = articleArtworkImageStyle;
|
|
62
|
-
exports.generateAuthorSchema = generateAuthorSchema;
|
|
63
|
-
exports.resolveArticleArtwork = resolveArticleArtwork;
|
|
64
|
-
//# sourceMappingURL=chunk-YRCR7WY3.js.map
|
|
65
|
-
//# sourceMappingURL=chunk-YRCR7WY3.js.map
|