@sonordev/site-kit 3.0.4 → 3.2.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/AGENTS.md +107 -0
- package/agent-manifest.json +377 -0
- package/dist/AnalyticsProvider-CD635CHQ.mjs +8 -0
- package/dist/{AnalyticsProvider-MLT26JRP.mjs.map → AnalyticsProvider-CD635CHQ.mjs.map} +1 -1
- package/dist/AnalyticsProvider-WK2Z6AIN.js +29 -0
- package/dist/{AnalyticsProvider-WTOGN7LV.js.map → AnalyticsProvider-WK2Z6AIN.js.map} +1 -1
- package/dist/BlogPostFaqSection-4AD2NIGG.js +13 -0
- package/dist/{BlogPostFaqSection-H556RV62.js.map → BlogPostFaqSection-4AD2NIGG.js.map} +1 -1
- package/dist/{BlogPostFaqSection-VSHOKKUD.mjs → BlogPostFaqSection-TU6YEC7P.mjs} +3 -3
- package/dist/{BlogPostFaqSection-VSHOKKUD.mjs.map → BlogPostFaqSection-TU6YEC7P.mjs.map} +1 -1
- package/dist/ChatWidget-AIOOZY6H.js +17 -0
- package/dist/{ChatWidget-MAL7FB4M.js.map → ChatWidget-AIOOZY6H.js.map} +1 -1
- package/dist/ChatWidget-UAAWDBNS.mjs +8 -0
- package/dist/{ChatWidget-QPZTPSPE.mjs.map → ChatWidget-UAAWDBNS.mjs.map} +1 -1
- package/dist/EngageWidget-EZ5T6H3K.mjs +7 -0
- package/dist/{EngageWidget-IPBUA4DW.mjs.map → EngageWidget-EZ5T6H3K.mjs.map} +1 -1
- package/dist/EngageWidget-RWVWW56C.js +16 -0
- package/dist/{EngageWidget-N3CABK3L.js.map → EngageWidget-RWVWW56C.js.map} +1 -1
- package/dist/{SignalCore-4MDIJUAP.mjs → SignalCore-4B4RNYLV.mjs} +60 -47
- package/dist/SignalCore-4B4RNYLV.mjs.map +1 -0
- package/dist/{SignalCore-ZMFUE3N4.js → SignalCore-AECW2JFP.js} +60 -47
- package/dist/SignalCore-AECW2JFP.js.map +1 -0
- package/dist/SitemapSync-AICU4SSV.js +15 -0
- package/dist/{SitemapSync-FUCH6Y6J.js.map → SitemapSync-AICU4SSV.js.map} +1 -1
- package/dist/SitemapSync-CIZCAZXK.mjs +6 -0
- package/dist/{SitemapSync-LCSPRAWU.mjs.map → SitemapSync-CIZCAZXK.mjs.map} +1 -1
- package/dist/analytics/index.js +11 -9
- package/dist/analytics/index.mjs +4 -2
- package/dist/blog/index.js +12 -12
- package/dist/blog/index.mjs +2 -2
- package/dist/blog/server-ui.js +5 -5
- package/dist/blog/server-ui.mjs +1 -1
- package/dist/brand.css +8 -3
- package/dist/{chunk-QTWA44S3.mjs → chunk-2WYEJOGA.mjs} +7 -8
- package/dist/chunk-2WYEJOGA.mjs.map +1 -0
- package/dist/{chunk-AN4ATCYQ.mjs → chunk-45QHDA7Q.mjs} +3 -3
- package/dist/{chunk-AN4ATCYQ.mjs.map → chunk-45QHDA7Q.mjs.map} +1 -1
- package/dist/{chunk-RI6JZUAE.js → chunk-4FBV5BJW.js} +7 -8
- package/dist/chunk-4FBV5BJW.js.map +1 -0
- package/dist/{chunk-YJWKHCOB.js → chunk-4NTMIU6V.js} +13 -11
- package/dist/chunk-4NTMIU6V.js.map +1 -0
- package/dist/{chunk-YFGKIKXA.mjs → chunk-57QV6NIY.mjs} +3 -3
- package/dist/{chunk-YFGKIKXA.mjs.map → chunk-57QV6NIY.mjs.map} +1 -1
- package/dist/chunk-5OWZUNNE.js +102 -0
- package/dist/chunk-5OWZUNNE.js.map +1 -0
- package/dist/{chunk-EUDTPXUI.mjs → chunk-6HPNFWSC.mjs} +3 -3
- package/dist/{chunk-EUDTPXUI.mjs.map → chunk-6HPNFWSC.mjs.map} +1 -1
- package/dist/{chunk-ZM2ALSBM.js → chunk-7TX5BKVA.js} +18 -7
- package/dist/chunk-7TX5BKVA.js.map +1 -0
- package/dist/{chunk-FT5JNCD4.mjs → chunk-AB2VYIYU.mjs} +11 -11
- package/dist/{chunk-FT5JNCD4.mjs.map → chunk-AB2VYIYU.mjs.map} +1 -1
- package/dist/{chunk-I5TJIESQ.js → chunk-BMKZHXWQ.js} +11 -11
- package/dist/{chunk-I5TJIESQ.js.map → chunk-BMKZHXWQ.js.map} +1 -1
- package/dist/{chunk-KHFNPPOX.mjs → chunk-DSRPKUQI.mjs} +6 -6
- package/dist/{chunk-KHFNPPOX.mjs.map → chunk-DSRPKUQI.mjs.map} +1 -1
- package/dist/chunk-EAASMIWX.js +258 -0
- package/dist/chunk-EAASMIWX.js.map +1 -0
- package/dist/{chunk-T4QBSRA4.mjs → chunk-EIWRPGOK.mjs} +37 -60
- package/dist/chunk-EIWRPGOK.mjs.map +1 -0
- package/dist/{chunk-O7E6QVK3.js → chunk-GCDVKOSM.js} +3 -3
- package/dist/{chunk-O7E6QVK3.js.map → chunk-GCDVKOSM.js.map} +1 -1
- package/dist/{chunk-KMZ527EM.mjs → chunk-GN62H6EG.mjs} +34 -8
- package/dist/chunk-GN62H6EG.mjs.map +1 -0
- package/dist/{chunk-UJQYSVYV.js → chunk-GQF6QAQS.js} +4 -4
- package/dist/{chunk-UJQYSVYV.js.map → chunk-GQF6QAQS.js.map} +1 -1
- package/dist/{chunk-MLJXELPA.js → chunk-HAZN43I6.js} +60 -94
- package/dist/chunk-HAZN43I6.js.map +1 -0
- package/dist/chunk-LZSCCJ4O.mjs +253 -0
- package/dist/chunk-LZSCCJ4O.mjs.map +1 -0
- package/dist/{chunk-TCVHI3JP.mjs → chunk-N2HR2E4Z.mjs} +60 -92
- package/dist/chunk-N2HR2E4Z.mjs.map +1 -0
- package/dist/{chunk-VCWSSGCU.js → chunk-NAVDN4AE.js} +7 -7
- package/dist/{chunk-VCWSSGCU.js.map → chunk-NAVDN4AE.js.map} +1 -1
- package/dist/chunk-NDHFU4HV.mjs +97 -0
- package/dist/chunk-NDHFU4HV.mjs.map +1 -0
- package/dist/{chunk-PST3NOEM.mjs → chunk-O237KKCX.mjs} +4 -4
- package/dist/{chunk-PST3NOEM.mjs.map → chunk-O237KKCX.mjs.map} +1 -1
- package/dist/{chunk-5AESOLXS.mjs → chunk-OTY7EWET.mjs} +13 -11
- package/dist/chunk-OTY7EWET.mjs.map +1 -0
- package/dist/chunk-Q2NBD54V.js +69 -0
- package/dist/chunk-Q2NBD54V.js.map +1 -0
- package/dist/{chunk-DGHPOWLU.js → chunk-R5A64DCX.js} +8 -8
- package/dist/{chunk-DGHPOWLU.js.map → chunk-R5A64DCX.js.map} +1 -1
- package/dist/{chunk-3YQCPLGP.mjs → chunk-RFIWVH3D.mjs} +41 -79
- package/dist/chunk-RFIWVH3D.mjs.map +1 -0
- package/dist/{chunk-NNZDHLXN.js → chunk-S3YQGTBF.js} +35 -9
- package/dist/chunk-S3YQGTBF.js.map +1 -0
- package/dist/{chunk-IBDVZ6BF.js → chunk-SLWTG2LJ.js} +69 -74
- package/dist/chunk-SLWTG2LJ.js.map +1 -0
- package/dist/chunk-SN2O72UF.mjs +6 -0
- package/dist/chunk-SN2O72UF.mjs.map +1 -0
- package/dist/{chunk-65SMJBHW.mjs → chunk-T2DEEKVQ.mjs} +69 -74
- package/dist/chunk-T2DEEKVQ.mjs.map +1 -0
- package/dist/{chunk-3GCEFS73.js → chunk-TE3W5REY.js} +39 -62
- package/dist/chunk-TE3W5REY.js.map +1 -0
- package/dist/{chunk-IFVMZFNT.js → chunk-TVCCZ7NR.js} +41 -79
- package/dist/chunk-TVCCZ7NR.js.map +1 -0
- package/dist/{chunk-EBJ4S5DU.js → chunk-UT2CF4FC.js} +4 -4
- package/dist/{chunk-EBJ4S5DU.js.map → chunk-UT2CF4FC.js.map} +1 -1
- package/dist/chunk-V6NVBFEP.js +54 -0
- package/dist/chunk-V6NVBFEP.js.map +1 -0
- package/dist/{chunk-6FWQMKVO.mjs → chunk-WN5A3KSY.mjs} +18 -7
- package/dist/chunk-WN5A3KSY.mjs.map +1 -0
- package/dist/chunk-WRZQS7O4.js +8 -0
- package/dist/chunk-WRZQS7O4.js.map +1 -0
- package/dist/chunk-WZHWWOUC.js +51 -0
- package/dist/chunk-WZHWWOUC.js.map +1 -0
- package/dist/chunk-X3S6KXAP.mjs +47 -0
- package/dist/chunk-X3S6KXAP.mjs.map +1 -0
- package/dist/chunk-X4OPM3SK.mjs +43 -0
- package/dist/chunk-X4OPM3SK.mjs.map +1 -0
- package/dist/chunk-ZPLN537Q.mjs +57 -0
- package/dist/chunk-ZPLN537Q.mjs.map +1 -0
- package/dist/cli/index.js +8986 -1276
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +8972 -1280
- package/dist/cli/index.mjs.map +1 -1
- package/dist/commerce/index.js +50 -48
- package/dist/commerce/index.mjs +5 -3
- package/dist/engage/index.js +11 -8
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +8 -5
- package/dist/engage/index.mjs.map +1 -1
- package/dist/fleet/contract.d.mts +99 -0
- package/dist/fleet/contract.d.ts +99 -0
- package/dist/fleet/contract.js +53 -0
- package/dist/fleet/contract.js.map +1 -0
- package/dist/fleet/contract.mjs +4 -0
- package/dist/fleet/contract.mjs.map +1 -0
- package/dist/fleet/index.d.mts +89 -0
- package/dist/fleet/index.d.ts +89 -0
- package/dist/fleet/index.js +74 -0
- package/dist/fleet/index.js.map +1 -0
- package/dist/fleet/index.mjs +9 -0
- package/dist/fleet/index.mjs.map +1 -0
- package/dist/forms/contract.d.mts +69 -0
- package/dist/forms/contract.d.ts +69 -0
- package/dist/forms/contract.js +33 -0
- package/dist/forms/contract.js.map +1 -0
- package/dist/forms/contract.mjs +4 -0
- package/dist/forms/contract.mjs.map +1 -0
- package/dist/forms/index.js +21 -17
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +14 -10
- package/dist/forms/index.mjs.map +1 -1
- package/dist/forms/styles.css +10 -8
- package/dist/images/index.js +10 -8
- package/dist/images/index.mjs +3 -1
- package/dist/index.js +98 -96
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9 -7
- package/dist/index.mjs.map +1 -1
- package/dist/layout/client.d.mts +8 -1
- package/dist/layout/client.d.ts +8 -1
- package/dist/layout/client.js +8 -3
- package/dist/layout/client.mjs +7 -2
- package/dist/layout/index.d.mts +7 -1
- package/dist/layout/index.d.ts +7 -1
- package/dist/layout/index.js +57 -4
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/index.mjs +56 -3
- package/dist/layout/index.mjs.map +1 -1
- package/dist/llms/index.d.mts +4 -0
- package/dist/llms/index.d.ts +4 -0
- package/dist/llms/index.js +12 -12
- package/dist/llms/index.mjs +2 -2
- package/dist/maps/index.js +9 -18
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/index.mjs +9 -18
- package/dist/maps/index.mjs.map +1 -1
- package/dist/portfolio/contract.d.mts +61 -0
- package/dist/portfolio/contract.d.ts +61 -0
- package/dist/portfolio/contract.js +43 -0
- package/dist/portfolio/contract.js.map +1 -0
- package/dist/portfolio/contract.mjs +38 -0
- package/dist/portfolio/contract.mjs.map +1 -0
- package/dist/seo/client.js +4 -2
- package/dist/seo/client.mjs +3 -1
- package/dist/seo/index.js +4 -2
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +3 -1
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo-pages/contract.d.mts +62 -0
- package/dist/seo-pages/contract.d.ts +62 -0
- package/dist/seo-pages/contract.js +48 -0
- package/dist/seo-pages/contract.js.map +1 -0
- package/dist/seo-pages/contract.mjs +44 -0
- package/dist/seo-pages/contract.mjs.map +1 -0
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sitemap/index.js +2 -2
- package/dist/sitemap/index.mjs +1 -1
- package/dist/sites/contract.d.mts +57 -0
- package/dist/sites/contract.d.ts +57 -0
- package/dist/sites/contract.js +37 -0
- package/dist/sites/contract.js.map +1 -0
- package/dist/sites/contract.mjs +4 -0
- package/dist/sites/contract.mjs.map +1 -0
- package/package.json +44 -4
- package/skills/site-kit/SKILL.md +66 -0
- package/dist/AnalyticsProvider-MLT26JRP.mjs +0 -6
- package/dist/AnalyticsProvider-WTOGN7LV.js +0 -27
- package/dist/BlogPostFaqSection-H556RV62.js +0 -13
- package/dist/ChatWidget-MAL7FB4M.js +0 -14
- package/dist/ChatWidget-QPZTPSPE.mjs +0 -5
- package/dist/EngageWidget-IPBUA4DW.mjs +0 -5
- package/dist/EngageWidget-N3CABK3L.js +0 -14
- package/dist/SignalCore-4MDIJUAP.mjs.map +0 -1
- package/dist/SignalCore-ZMFUE3N4.js.map +0 -1
- package/dist/SitemapSync-FUCH6Y6J.js +0 -13
- package/dist/SitemapSync-LCSPRAWU.mjs +0 -4
- package/dist/chunk-3GCEFS73.js.map +0 -1
- package/dist/chunk-3YQCPLGP.mjs.map +0 -1
- package/dist/chunk-5AESOLXS.mjs.map +0 -1
- package/dist/chunk-65SMJBHW.mjs.map +0 -1
- package/dist/chunk-6FWQMKVO.mjs.map +0 -1
- package/dist/chunk-IBDVZ6BF.js.map +0 -1
- package/dist/chunk-IFVMZFNT.js.map +0 -1
- package/dist/chunk-KMZ527EM.mjs.map +0 -1
- package/dist/chunk-MLJXELPA.js.map +0 -1
- package/dist/chunk-NNZDHLXN.js.map +0 -1
- package/dist/chunk-QTWA44S3.mjs.map +0 -1
- package/dist/chunk-RI6JZUAE.js.map +0 -1
- package/dist/chunk-T4QBSRA4.mjs.map +0 -1
- package/dist/chunk-TCVHI3JP.mjs.map +0 -1
- package/dist/chunk-YJWKHCOB.js.map +0 -1
- package/dist/chunk-ZM2ALSBM.js.map +0 -1
package/dist/blog/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var chunkGQF6QAQS_js = require('../chunk-GQF6QAQS.js');
|
|
5
|
+
var chunkBMKZHXWQ_js = require('../chunk-BMKZHXWQ.js');
|
|
6
6
|
var chunkIB4FRJDV_js = require('../chunk-IB4FRJDV.js');
|
|
7
7
|
var chunkJ7QI3GDX_js = require('../chunk-J7QI3GDX.js');
|
|
8
8
|
require('../chunk-ZSMWDLMK.js');
|
|
@@ -880,43 +880,43 @@ function TableOfContents({
|
|
|
880
880
|
|
|
881
881
|
Object.defineProperty(exports, "BlogFAQ", {
|
|
882
882
|
enumerable: true,
|
|
883
|
-
get: function () { return
|
|
883
|
+
get: function () { return chunkGQF6QAQS_js.BlogFAQ; }
|
|
884
884
|
});
|
|
885
885
|
Object.defineProperty(exports, "BlogList", {
|
|
886
886
|
enumerable: true,
|
|
887
|
-
get: function () { return
|
|
887
|
+
get: function () { return chunkBMKZHXWQ_js.BlogList; }
|
|
888
888
|
});
|
|
889
889
|
Object.defineProperty(exports, "BlogPost", {
|
|
890
890
|
enumerable: true,
|
|
891
|
-
get: function () { return
|
|
891
|
+
get: function () { return chunkBMKZHXWQ_js.BlogPost; }
|
|
892
892
|
});
|
|
893
893
|
Object.defineProperty(exports, "ClusterLandingPage", {
|
|
894
894
|
enumerable: true,
|
|
895
|
-
get: function () { return
|
|
895
|
+
get: function () { return chunkBMKZHXWQ_js.ClusterLandingPage; }
|
|
896
896
|
});
|
|
897
897
|
Object.defineProperty(exports, "ClusterNavigation", {
|
|
898
898
|
enumerable: true,
|
|
899
|
-
get: function () { return
|
|
899
|
+
get: function () { return chunkBMKZHXWQ_js.ClusterNavigation; }
|
|
900
900
|
});
|
|
901
901
|
Object.defineProperty(exports, "ServiceCallout", {
|
|
902
902
|
enumerable: true,
|
|
903
|
-
get: function () { return
|
|
903
|
+
get: function () { return chunkBMKZHXWQ_js.ServiceCallout; }
|
|
904
904
|
});
|
|
905
905
|
Object.defineProperty(exports, "ServiceCallouts", {
|
|
906
906
|
enumerable: true,
|
|
907
|
-
get: function () { return
|
|
907
|
+
get: function () { return chunkBMKZHXWQ_js.ServiceCallouts; }
|
|
908
908
|
});
|
|
909
909
|
Object.defineProperty(exports, "addExternalLinkTargets", {
|
|
910
910
|
enumerable: true,
|
|
911
|
-
get: function () { return
|
|
911
|
+
get: function () { return chunkBMKZHXWQ_js.addExternalLinkTargets; }
|
|
912
912
|
});
|
|
913
913
|
Object.defineProperty(exports, "normalizeSiteHost", {
|
|
914
914
|
enumerable: true,
|
|
915
|
-
get: function () { return
|
|
915
|
+
get: function () { return chunkBMKZHXWQ_js.normalizeSiteHost; }
|
|
916
916
|
});
|
|
917
917
|
Object.defineProperty(exports, "resolveBlogSiteUrl", {
|
|
918
918
|
enumerable: true,
|
|
919
|
-
get: function () { return
|
|
919
|
+
get: function () { return chunkBMKZHXWQ_js.resolveBlogSiteUrl; }
|
|
920
920
|
});
|
|
921
921
|
exports.AuthorCard = AuthorCard;
|
|
922
922
|
exports.AuthorPage = AuthorPage;
|
package/dist/blog/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
export { BlogFAQ } from '../chunk-
|
|
3
|
-
export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation, ServiceCallout, ServiceCallouts, addExternalLinkTargets, normalizeSiteHost, resolveBlogSiteUrl } from '../chunk-
|
|
2
|
+
export { BlogFAQ } from '../chunk-O237KKCX.mjs';
|
|
3
|
+
export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation, ServiceCallout, ServiceCallouts, addExternalLinkTargets, normalizeSiteHost, resolveBlogSiteUrl } from '../chunk-AB2VYIYU.mjs';
|
|
4
4
|
import { generateAuthorSchema } from '../chunk-SH4VZDVX.mjs';
|
|
5
5
|
import { safeJsonLd } from '../chunk-662YHKWW.mjs';
|
|
6
6
|
import '../chunk-4XPGGLVP.mjs';
|
package/dist/blog/server-ui.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkBMKZHXWQ_js = require('../chunk-BMKZHXWQ.js');
|
|
4
4
|
require('../chunk-IB4FRJDV.js');
|
|
5
5
|
require('../chunk-ZSMWDLMK.js');
|
|
6
6
|
|
|
@@ -8,19 +8,19 @@ require('../chunk-ZSMWDLMK.js');
|
|
|
8
8
|
|
|
9
9
|
Object.defineProperty(exports, "BlogList", {
|
|
10
10
|
enumerable: true,
|
|
11
|
-
get: function () { return
|
|
11
|
+
get: function () { return chunkBMKZHXWQ_js.BlogList; }
|
|
12
12
|
});
|
|
13
13
|
Object.defineProperty(exports, "BlogPost", {
|
|
14
14
|
enumerable: true,
|
|
15
|
-
get: function () { return
|
|
15
|
+
get: function () { return chunkBMKZHXWQ_js.BlogPost; }
|
|
16
16
|
});
|
|
17
17
|
Object.defineProperty(exports, "ClusterLandingPage", {
|
|
18
18
|
enumerable: true,
|
|
19
|
-
get: function () { return
|
|
19
|
+
get: function () { return chunkBMKZHXWQ_js.ClusterLandingPage; }
|
|
20
20
|
});
|
|
21
21
|
Object.defineProperty(exports, "ClusterNavigation", {
|
|
22
22
|
enumerable: true,
|
|
23
|
-
get: function () { return
|
|
23
|
+
get: function () { return chunkBMKZHXWQ_js.ClusterNavigation; }
|
|
24
24
|
});
|
|
25
25
|
//# sourceMappingURL=server-ui.js.map
|
|
26
26
|
//# sourceMappingURL=server-ui.js.map
|
package/dist/blog/server-ui.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation } from '../chunk-
|
|
1
|
+
export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation } from '../chunk-AB2VYIYU.mjs';
|
|
2
2
|
import '../chunk-SH4VZDVX.mjs';
|
|
3
3
|
import '../chunk-4XPGGLVP.mjs';
|
|
4
4
|
//# sourceMappingURL=server-ui.mjs.map
|
package/dist/brand.css
CHANGED
|
@@ -19,9 +19,14 @@
|
|
|
19
19
|
|
|
20
20
|
:root {
|
|
21
21
|
/* ── Brand colors ─────────────────────────────────────────────────────── */
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
/* Default primary is blue-600 (#2563eb, ~5.2:1 on white) — NOT blue-500
|
|
23
|
+
(#3b82f6, ~3.68:1), which fails WCAG AA for white button text / link text.
|
|
24
|
+
Sites that set their own --sk-primary override this; sites that ship the
|
|
25
|
+
default must still pass Lighthouse a11y. Keep this the single source of
|
|
26
|
+
truth for the default primary — forms/styles.css mirrors it verbatim. */
|
|
27
|
+
--sk-primary: #2563eb;
|
|
28
|
+
--sk-primary-rgb: 37, 99, 235;
|
|
29
|
+
--sk-primary-hover: #1d4ed8;
|
|
25
30
|
--sk-primary-light: #dbeafe;
|
|
26
31
|
--sk-secondary: #8b5cf6;
|
|
27
32
|
--sk-secondary-rgb: 139, 92, 246;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
|
+
import { sonorFetch } from './chunk-LZSCCJ4O.mjs';
|
|
2
3
|
import { useRef, useEffect } from 'react';
|
|
3
4
|
|
|
4
|
-
// src/SitemapSync.tsx
|
|
5
5
|
function inferPageType(urlPath) {
|
|
6
6
|
if (urlPath === "/" || urlPath === "") return "homepage";
|
|
7
7
|
if (/^\/services(\/|$)/i.test(urlPath)) return "service";
|
|
@@ -61,7 +61,7 @@ function getApiConfig() {
|
|
|
61
61
|
}
|
|
62
62
|
async function parseSitemap(sitemapUrl, debug) {
|
|
63
63
|
try {
|
|
64
|
-
const response = await
|
|
64
|
+
const response = await sonorFetch(sitemapUrl);
|
|
65
65
|
if (!response.ok) {
|
|
66
66
|
if (debug) console.warn("[SitemapSync] Failed to fetch sitemap:", response.status);
|
|
67
67
|
return [];
|
|
@@ -118,11 +118,10 @@ async function syncToPortal(entries, apiUrl, apiKey, site, debug, mode = "additi
|
|
|
118
118
|
return { success: true, created: 0, updated: 0 };
|
|
119
119
|
}
|
|
120
120
|
try {
|
|
121
|
-
const response = await
|
|
121
|
+
const response = await sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {
|
|
122
122
|
method: "POST",
|
|
123
123
|
headers: {
|
|
124
|
-
"Content-Type": "application/json"
|
|
125
|
-
"x-api-key": apiKey
|
|
124
|
+
"Content-Type": "application/json"
|
|
126
125
|
},
|
|
127
126
|
body: JSON.stringify({
|
|
128
127
|
entries: entries.map((e) => ({
|
|
@@ -137,7 +136,7 @@ async function syncToPortal(entries, apiUrl, apiKey, site, debug, mode = "additi
|
|
|
137
136
|
// SiteKitClientProviders (see __SITE_KIT_SITE__).
|
|
138
137
|
...site ? { site } : {}
|
|
139
138
|
})
|
|
140
|
-
});
|
|
139
|
+
}, { apiKey });
|
|
141
140
|
if (!response.ok) {
|
|
142
141
|
if (debug) console.error("[SitemapSync] API error:", response.status, response.statusText);
|
|
143
142
|
return { success: false, created: 0, updated: 0 };
|
|
@@ -210,5 +209,5 @@ function SitemapSync({
|
|
|
210
209
|
}
|
|
211
210
|
|
|
212
211
|
export { SitemapSync };
|
|
213
|
-
//# sourceMappingURL=chunk-
|
|
214
|
-
//# sourceMappingURL=chunk-
|
|
212
|
+
//# sourceMappingURL=chunk-2WYEJOGA.mjs.map
|
|
213
|
+
//# sourceMappingURL=chunk-2WYEJOGA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/SitemapSync.tsx"],"names":[],"mappings":"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","file":"chunk-2WYEJOGA.mjs","sourcesContent":["/**\n * SitemapSync - Automatically sync sitemap.xml to Portal API\n *\n * Client-only component. Lives at package root so the main entry does not\n * pull in seo/ (and server-only code). For use in SiteKitProvider and\n * from @sonordev/site-kit/seo.\n *\n * @example\n * ```tsx\n * import { SitemapSync } from '@sonordev/site-kit'\n * // or\n * import { SitemapSync } from '@sonordev/site-kit/seo'\n * ```\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { sonorFetch } from './shared/sonorFetch'\n\ninterface SitemapSyncProps {\n /** Custom sitemap URL (defaults to /sitemap.xml) */\n sitemapUrl?: string\n /** How often to re-sync in minutes (0 = only on mount, default: 60) */\n syncInterval?: number\n /** Enable debug logging */\n debug?: boolean\n /**\n * Sync mode:\n * - 'additive' (default for runtime): adds/updates pages but never deletes existing ones\n * - 'full-replace': replaces the entire page set (use only for build-time sync via createSitemap)\n */\n mode?: 'additive' | 'full-replace'\n}\n\ninterface SitemapEntry {\n path: string\n lastmod?: string\n changefreq?: string\n priority?: number\n pageType?: string\n}\n\n/**\n * Infer page type from URL path pattern for Signal context.\n */\nfunction inferPageType(urlPath: string): string {\n if (urlPath === '/' || urlPath === '') return 'homepage'\n if (/^\\/services(\\/|$)/i.test(urlPath)) return 'service'\n if (/^\\/compare(\\/|$)/i.test(urlPath)) return 'comparison'\n if (/^\\/(insights|blog)(\\/|$)/i.test(urlPath)) return 'blog'\n if (/^\\/industries(\\/|$)/i.test(urlPath)) return 'industry'\n if (/^\\/work(\\/|$)/i.test(urlPath)) return 'portfolio'\n if (/^\\/faq(\\/|$)/i.test(urlPath)) return 'faq'\n if (/^\\/pricing(\\/|$)/i.test(urlPath)) return 'pricing'\n return 'page'\n}\n\n/**\n * Per-browser-session sync throttle. Build-time sync (createSitemap) is the\n * canonical source of truth; runtime SitemapSync is only a safety net — so\n * re-registering the sitemap on every full page load of every visitor is pure\n * waste (fetch + DOMParser on the visitor's main thread, plus a write per\n * pageview against the API). Stamp the last successful sync in sessionStorage\n * and skip while inside the throttle window.\n */\nconst SYNC_STAMP_KEY = '_sk_sitemap_synced_at'\nconst SYNC_HASH_KEY = '_sk_sitemap_hash'\n\nfunction isRecentlySynced(throttleMinutes: number): boolean {\n try {\n const stamp = sessionStorage.getItem(SYNC_STAMP_KEY)\n if (!stamp) return false\n const elapsed = Date.now() - parseInt(stamp, 10)\n return elapsed >= 0 && elapsed < throttleMinutes * 60 * 1000\n } catch {\n return false // storage unavailable (private mode) — sync as before\n }\n}\n\nfunction stampSynced(): void {\n try {\n sessionStorage.setItem(SYNC_STAMP_KEY, Date.now().toString())\n } catch {\n /* storage unavailable — throttle simply won't apply */\n }\n}\n\n/**\n * Content-hash guard (localStorage, so it survives across sessions): the\n * sitemap of a static site only changes at deploy, so once ONE sync of a given\n * sitemap succeeded from this browser, re-POSTing the identical entry set is\n * pure API load. Hash the parsed entries; skip the POST when unchanged.\n * Keyed by sitemap URL so multiple SitemapSync instances don't collide.\n */\nfunction hashEntries(sitemapUrl: string, entries: SitemapEntry[]): string {\n const text = entries\n .map(e => `${e.path}|${e.lastmod ?? ''}|${e.changefreq ?? ''}|${e.priority ?? ''}`)\n .join('\\n')\n let hash = 0\n for (let i = 0; i < text.length; i++) {\n hash = ((hash << 5) - hash + text.charCodeAt(i)) | 0\n }\n return `${sitemapUrl}:${entries.length}:${hash.toString(16)}`\n}\n\nfunction isAlreadySyncedHash(hash: string): boolean {\n try {\n return localStorage.getItem(SYNC_HASH_KEY) === hash\n } catch {\n return false\n }\n}\n\nfunction storeSyncedHash(hash: string): void {\n try {\n localStorage.setItem(SYNC_HASH_KEY, hash)\n } catch {\n /* storage unavailable — guard simply won't apply */\n }\n}\n\nfunction getApiConfig() {\n if (typeof window === 'undefined') return { apiUrl: '', apiKey: '', site: '' }\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n const apiKey = (window as any).__SITE_KIT_API_KEY__ || ''\n // Sub-site host — set by SiteKitClientProviders from analytics.site config,\n // NEXT_PUBLIC_SITE_URL host, or window.location.host. Tagged on every\n // seo_pages row from this sitemap so the dashboard can scope the page tree\n // when one Sonor project hosts many sites.\n const site = (window as any).__SITE_KIT_SITE__ || window.location.host || ''\n return { apiUrl, apiKey, site }\n}\n\nasync function parseSitemap(sitemapUrl: string, debug: boolean): Promise<SitemapEntry[]> {\n try {\n const response = await sonorFetch(sitemapUrl)\n if (!response.ok) {\n if (debug) console.warn('[SitemapSync] Failed to fetch sitemap:', response.status)\n return []\n }\n\n const text = await response.text()\n const parser = new DOMParser()\n const doc = parser.parseFromString(text, 'application/xml')\n\n const parseError = doc.querySelector('parsererror')\n if (parseError) {\n if (debug) console.warn('[SitemapSync] Sitemap parse error:', parseError.textContent)\n return []\n }\n\n const urls = doc.querySelectorAll('url')\n const entries: SitemapEntry[] = []\n\n urls.forEach(url => {\n const loc = url.querySelector('loc')?.textContent?.trim()\n if (!loc) return\n\n let path: string\n try {\n const urlObj = new URL(loc)\n path = urlObj.pathname\n } catch {\n path = loc.startsWith('/') ? loc : `/${loc}`\n }\n\n if (path !== '/' && path.endsWith('/')) {\n path = path.slice(0, -1)\n }\n\n // Reject malformed paths (embedded domains, double protocols, etc.)\n if (path.includes('://') || /\\/\\/[a-z0-9.-]+\\.[a-z]{2,}/i.test(path)) {\n if (debug) console.warn(`[SitemapSync] Skipping malformed path: ${path}`)\n return\n }\n\n const lastmod = url.querySelector('lastmod')?.textContent || undefined\n const changefreq = url.querySelector('changefreq')?.textContent || undefined\n const priorityStr = url.querySelector('priority')?.textContent\n const priority = priorityStr ? parseFloat(priorityStr) : undefined\n\n entries.push({ path, lastmod, changefreq, priority })\n })\n\n if (debug) {\n console.log(`[SitemapSync] Parsed ${entries.length} entries from sitemap`)\n }\n\n return entries\n } catch (error) {\n if (debug) console.error('[SitemapSync] Error parsing sitemap:', error)\n return []\n }\n}\n\nasync function syncToPortal(\n entries: SitemapEntry[],\n apiUrl: string,\n apiKey: string,\n site: string,\n debug: boolean,\n mode: 'additive' | 'full-replace' = 'additive'\n): Promise<{ success: boolean; created: number; updated: number }> {\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key configured')\n return { success: false, created: 0, updated: 0 }\n }\n\n if (entries.length === 0) {\n if (debug) console.log('[SitemapSync] No entries to sync')\n return { success: true, created: 0, updated: 0 }\n }\n\n try {\n // Registration is idempotent in both modes (same payload → same final\n // state), so retrying a timed-out attempt is safe.\n const response = await sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n entries: entries.map(e => ({\n path: e.path,\n priority: e.priority,\n changefreq: e.changefreq,\n pageType: inferPageType(e.path),\n })),\n mode,\n // Sub-site host — tagged on every seo_pages row so the dashboard\n // can scope the page tree to one microsite. Resolved by\n // SiteKitClientProviders (see __SITE_KIT_SITE__).\n ...(site ? { site } : {}),\n }),\n }, { apiKey })\n\n if (!response.ok) {\n if (debug) console.error('[SitemapSync] API error:', response.status, response.statusText)\n return { success: false, created: 0, updated: 0 }\n }\n\n const result = await response.json()\n\n if (debug) {\n console.log(`[SitemapSync] Synced: ${result.created} created, ${result.updated} updated`)\n }\n\n return {\n success: true,\n created: result.created || 0,\n updated: result.updated || 0,\n }\n } catch (error) {\n if (debug) console.error('[SitemapSync] Sync error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\nexport function SitemapSync({\n sitemapUrl = '/sitemap.xml',\n syncInterval = 60,\n debug = false,\n mode = 'additive',\n}: SitemapSyncProps) {\n const hasSyncedRef = useRef(false)\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n\n useEffect(() => {\n // Build-time sync via createSitemap is the canonical source of truth, but\n // it can fail during ISR revalidation (app/ dir unavailable on serverless).\n // Runtime SitemapSync in additive mode is a safe fallback — it adds/updates\n // pages that may be missing without ever deleting existing ones.\n // Full-replace is never safe at runtime — always force additive.\n const effectiveMode: 'additive' | 'full-replace' = 'additive'\n\n // Throttle window: reuse syncInterval when periodic syncing is on,\n // otherwise default to 60 minutes for the on-mount sync.\n const throttleMinutes = syncInterval > 0 ? syncInterval : 60\n\n const doSync = async () => {\n const { apiUrl, apiKey, site } = getApiConfig()\n\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key found')\n return\n }\n\n if (isRecentlySynced(throttleMinutes)) {\n if (debug) console.log('[SitemapSync] Skipped — synced within the last', throttleMinutes, 'min this session')\n return\n }\n\n if (debug) console.log('[SitemapSync] Starting sitemap sync...', site ? `(site: ${site})` : '')\n\n const entries = await parseSitemap(sitemapUrl, debug)\n\n if (entries.length > 0) {\n const hash = hashEntries(sitemapUrl, entries)\n if (isAlreadySyncedHash(hash)) {\n // This exact sitemap already synced from this browser — the server\n // state can't be improved by re-POSTing it. Stamp the session so we\n // don't even re-fetch/parse for the rest of the throttle window.\n stampSynced()\n if (debug) console.log('[SitemapSync] Skipped POST — sitemap unchanged since last successful sync')\n return\n }\n const result = await syncToPortal(entries, apiUrl, apiKey, site, debug, effectiveMode)\n if (result.success) {\n stampSynced()\n storeSyncedHash(hash)\n }\n }\n }\n\n if (!hasSyncedRef.current) {\n hasSyncedRef.current = true\n doSync()\n }\n\n if (syncInterval > 0) {\n intervalRef.current = setInterval(doSync, syncInterval * 60 * 1000)\n }\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [sitemapUrl, syncInterval, debug, mode])\n\n return null\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useAnalytics } from './chunk-
|
|
2
|
+
import { useAnalytics } from './chunk-T2DEEKVQ.mjs';
|
|
3
3
|
import { useCallback, useEffect } from 'react';
|
|
4
4
|
|
|
5
5
|
function useContactTracking(options = {}) {
|
|
@@ -65,5 +65,5 @@ function ContactTracking({ debug = false }) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
export { ContactTracking, useContactTracking };
|
|
68
|
-
//# sourceMappingURL=chunk-
|
|
69
|
-
//# sourceMappingURL=chunk-
|
|
68
|
+
//# sourceMappingURL=chunk-45QHDA7Q.mjs.map
|
|
69
|
+
//# sourceMappingURL=chunk-45QHDA7Q.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":["trackConversion"],"mappings":"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","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/analytics/useContactTracking.ts"],"names":["trackConversion"],"mappings":"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","file":"chunk-45QHDA7Q.mjs","sourcesContent":["/**\n * @sonordev/site-kit/analytics - Contact Tracking Hook\n * \n * Tracks phone calls and email clicks as conversions.\n * Use this hook to automatically track tel: and mailto: links,\n * or manually track contact interactions.\n */\n\n'use client'\n\nimport { useCallback, useEffect } from 'react'\nimport { useAnalytics } from './AnalyticsProvider'\n\nexport interface UseContactTrackingOptions {\n /** Automatically track all tel: and mailto: links (default: true) */\n autoTrack?: boolean\n /** Debug mode - logs events to console */\n debug?: boolean\n}\n\nexport interface ContactTrackingReturn {\n /** Manually track a phone call click */\n trackPhoneClick: (phoneNumber: string, metadata?: Record<string, unknown>) => void\n /** Manually track an email click */\n trackEmailClick: (email: string, metadata?: Record<string, unknown>) => void\n}\n\n/**\n * Hook for tracking phone and email contact interactions as conversions.\n * \n * @example\n * ```tsx\n * // Auto-track all tel: and mailto: links\n * useContactTracking()\n * \n * // Manual tracking\n * const { trackPhoneClick, trackEmailClick } = useContactTracking()\n * trackPhoneClick('513-555-1234')\n * trackEmailClick('hello@example.com')\n * ```\n */\nexport function useContactTracking(options: UseContactTrackingOptions = {}): ContactTrackingReturn {\n const { autoTrack = true, debug = false } = options\n const { trackConversion } = useAnalytics()\n \n const trackPhoneClick = useCallback((phoneNumber: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Phone click:', phoneNumber)\n \n trackConversion({\n type: 'phone_call',\n metadata: {\n phoneNumber: phoneNumber.replace(/\\D/g, ''), // Normalize to digits\n rawNumber: phoneNumber,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n const trackEmailClick = useCallback((email: string, metadata?: Record<string, unknown>) => {\n if (debug) console.log('[Analytics] Email click:', email)\n \n trackConversion({\n type: 'email_click',\n metadata: {\n email,\n ...metadata,\n },\n })\n }, [trackConversion, debug])\n \n // Auto-track tel: and mailto: links\n useEffect(() => {\n if (!autoTrack || typeof document === 'undefined') return\n \n const handleClick = (e: MouseEvent) => {\n const target = e.target as HTMLElement\n const anchor = target.closest('a')\n if (!anchor) return\n \n const href = anchor.getAttribute('href')\n if (!href) return\n \n if (href.startsWith('tel:')) {\n const phone = href.replace('tel:', '').trim()\n trackPhoneClick(phone, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n } else if (href.startsWith('mailto:')) {\n const email = href.replace('mailto:', '').split('?')[0].trim()\n trackEmailClick(email, {\n linkText: anchor.textContent?.trim(),\n source: 'auto',\n })\n }\n }\n \n document.addEventListener('click', handleClick, { capture: true })\n \n return () => {\n document.removeEventListener('click', handleClick, { capture: true })\n }\n }, [autoTrack, trackPhoneClick, trackEmailClick])\n \n return {\n trackPhoneClick,\n trackEmailClick,\n }\n}\n\n/**\n * Component wrapper for contact tracking\n * Simply include this component to auto-track all tel: and mailto: links\n * \n * @example\n * ```tsx\n * <ContactTracking />\n * ```\n */\nexport function ContactTracking({ debug = false }: { debug?: boolean }) {\n useContactTracking({ autoTrack: true, debug })\n return null\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var chunkEAASMIWX_js = require('./chunk-EAASMIWX.js');
|
|
4
5
|
var react = require('react');
|
|
5
6
|
|
|
6
|
-
// src/SitemapSync.tsx
|
|
7
7
|
function inferPageType(urlPath) {
|
|
8
8
|
if (urlPath === "/" || urlPath === "") return "homepage";
|
|
9
9
|
if (/^\/services(\/|$)/i.test(urlPath)) return "service";
|
|
@@ -63,7 +63,7 @@ function getApiConfig() {
|
|
|
63
63
|
}
|
|
64
64
|
async function parseSitemap(sitemapUrl, debug) {
|
|
65
65
|
try {
|
|
66
|
-
const response = await
|
|
66
|
+
const response = await chunkEAASMIWX_js.sonorFetch(sitemapUrl);
|
|
67
67
|
if (!response.ok) {
|
|
68
68
|
if (debug) console.warn("[SitemapSync] Failed to fetch sitemap:", response.status);
|
|
69
69
|
return [];
|
|
@@ -120,11 +120,10 @@ async function syncToPortal(entries, apiUrl, apiKey, site, debug, mode = "additi
|
|
|
120
120
|
return { success: true, created: 0, updated: 0 };
|
|
121
121
|
}
|
|
122
122
|
try {
|
|
123
|
-
const response = await
|
|
123
|
+
const response = await chunkEAASMIWX_js.sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {
|
|
124
124
|
method: "POST",
|
|
125
125
|
headers: {
|
|
126
|
-
"Content-Type": "application/json"
|
|
127
|
-
"x-api-key": apiKey
|
|
126
|
+
"Content-Type": "application/json"
|
|
128
127
|
},
|
|
129
128
|
body: JSON.stringify({
|
|
130
129
|
entries: entries.map((e) => ({
|
|
@@ -139,7 +138,7 @@ async function syncToPortal(entries, apiUrl, apiKey, site, debug, mode = "additi
|
|
|
139
138
|
// SiteKitClientProviders (see __SITE_KIT_SITE__).
|
|
140
139
|
...site ? { site } : {}
|
|
141
140
|
})
|
|
142
|
-
});
|
|
141
|
+
}, { apiKey });
|
|
143
142
|
if (!response.ok) {
|
|
144
143
|
if (debug) console.error("[SitemapSync] API error:", response.status, response.statusText);
|
|
145
144
|
return { success: false, created: 0, updated: 0 };
|
|
@@ -212,5 +211,5 @@ function SitemapSync({
|
|
|
212
211
|
}
|
|
213
212
|
|
|
214
213
|
exports.SitemapSync = SitemapSync;
|
|
215
|
-
//# sourceMappingURL=chunk-
|
|
216
|
-
//# sourceMappingURL=chunk-
|
|
214
|
+
//# sourceMappingURL=chunk-4FBV5BJW.js.map
|
|
215
|
+
//# sourceMappingURL=chunk-4FBV5BJW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/SitemapSync.tsx"],"names":["sonorFetch","useRef","useEffect"],"mappings":"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","file":"chunk-4FBV5BJW.js","sourcesContent":["/**\n * SitemapSync - Automatically sync sitemap.xml to Portal API\n *\n * Client-only component. Lives at package root so the main entry does not\n * pull in seo/ (and server-only code). For use in SiteKitProvider and\n * from @sonordev/site-kit/seo.\n *\n * @example\n * ```tsx\n * import { SitemapSync } from '@sonordev/site-kit'\n * // or\n * import { SitemapSync } from '@sonordev/site-kit/seo'\n * ```\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { sonorFetch } from './shared/sonorFetch'\n\ninterface SitemapSyncProps {\n /** Custom sitemap URL (defaults to /sitemap.xml) */\n sitemapUrl?: string\n /** How often to re-sync in minutes (0 = only on mount, default: 60) */\n syncInterval?: number\n /** Enable debug logging */\n debug?: boolean\n /**\n * Sync mode:\n * - 'additive' (default for runtime): adds/updates pages but never deletes existing ones\n * - 'full-replace': replaces the entire page set (use only for build-time sync via createSitemap)\n */\n mode?: 'additive' | 'full-replace'\n}\n\ninterface SitemapEntry {\n path: string\n lastmod?: string\n changefreq?: string\n priority?: number\n pageType?: string\n}\n\n/**\n * Infer page type from URL path pattern for Signal context.\n */\nfunction inferPageType(urlPath: string): string {\n if (urlPath === '/' || urlPath === '') return 'homepage'\n if (/^\\/services(\\/|$)/i.test(urlPath)) return 'service'\n if (/^\\/compare(\\/|$)/i.test(urlPath)) return 'comparison'\n if (/^\\/(insights|blog)(\\/|$)/i.test(urlPath)) return 'blog'\n if (/^\\/industries(\\/|$)/i.test(urlPath)) return 'industry'\n if (/^\\/work(\\/|$)/i.test(urlPath)) return 'portfolio'\n if (/^\\/faq(\\/|$)/i.test(urlPath)) return 'faq'\n if (/^\\/pricing(\\/|$)/i.test(urlPath)) return 'pricing'\n return 'page'\n}\n\n/**\n * Per-browser-session sync throttle. Build-time sync (createSitemap) is the\n * canonical source of truth; runtime SitemapSync is only a safety net — so\n * re-registering the sitemap on every full page load of every visitor is pure\n * waste (fetch + DOMParser on the visitor's main thread, plus a write per\n * pageview against the API). Stamp the last successful sync in sessionStorage\n * and skip while inside the throttle window.\n */\nconst SYNC_STAMP_KEY = '_sk_sitemap_synced_at'\nconst SYNC_HASH_KEY = '_sk_sitemap_hash'\n\nfunction isRecentlySynced(throttleMinutes: number): boolean {\n try {\n const stamp = sessionStorage.getItem(SYNC_STAMP_KEY)\n if (!stamp) return false\n const elapsed = Date.now() - parseInt(stamp, 10)\n return elapsed >= 0 && elapsed < throttleMinutes * 60 * 1000\n } catch {\n return false // storage unavailable (private mode) — sync as before\n }\n}\n\nfunction stampSynced(): void {\n try {\n sessionStorage.setItem(SYNC_STAMP_KEY, Date.now().toString())\n } catch {\n /* storage unavailable — throttle simply won't apply */\n }\n}\n\n/**\n * Content-hash guard (localStorage, so it survives across sessions): the\n * sitemap of a static site only changes at deploy, so once ONE sync of a given\n * sitemap succeeded from this browser, re-POSTing the identical entry set is\n * pure API load. Hash the parsed entries; skip the POST when unchanged.\n * Keyed by sitemap URL so multiple SitemapSync instances don't collide.\n */\nfunction hashEntries(sitemapUrl: string, entries: SitemapEntry[]): string {\n const text = entries\n .map(e => `${e.path}|${e.lastmod ?? ''}|${e.changefreq ?? ''}|${e.priority ?? ''}`)\n .join('\\n')\n let hash = 0\n for (let i = 0; i < text.length; i++) {\n hash = ((hash << 5) - hash + text.charCodeAt(i)) | 0\n }\n return `${sitemapUrl}:${entries.length}:${hash.toString(16)}`\n}\n\nfunction isAlreadySyncedHash(hash: string): boolean {\n try {\n return localStorage.getItem(SYNC_HASH_KEY) === hash\n } catch {\n return false\n }\n}\n\nfunction storeSyncedHash(hash: string): void {\n try {\n localStorage.setItem(SYNC_HASH_KEY, hash)\n } catch {\n /* storage unavailable — guard simply won't apply */\n }\n}\n\nfunction getApiConfig() {\n if (typeof window === 'undefined') return { apiUrl: '', apiKey: '', site: '' }\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n const apiKey = (window as any).__SITE_KIT_API_KEY__ || ''\n // Sub-site host — set by SiteKitClientProviders from analytics.site config,\n // NEXT_PUBLIC_SITE_URL host, or window.location.host. Tagged on every\n // seo_pages row from this sitemap so the dashboard can scope the page tree\n // when one Sonor project hosts many sites.\n const site = (window as any).__SITE_KIT_SITE__ || window.location.host || ''\n return { apiUrl, apiKey, site }\n}\n\nasync function parseSitemap(sitemapUrl: string, debug: boolean): Promise<SitemapEntry[]> {\n try {\n const response = await sonorFetch(sitemapUrl)\n if (!response.ok) {\n if (debug) console.warn('[SitemapSync] Failed to fetch sitemap:', response.status)\n return []\n }\n\n const text = await response.text()\n const parser = new DOMParser()\n const doc = parser.parseFromString(text, 'application/xml')\n\n const parseError = doc.querySelector('parsererror')\n if (parseError) {\n if (debug) console.warn('[SitemapSync] Sitemap parse error:', parseError.textContent)\n return []\n }\n\n const urls = doc.querySelectorAll('url')\n const entries: SitemapEntry[] = []\n\n urls.forEach(url => {\n const loc = url.querySelector('loc')?.textContent?.trim()\n if (!loc) return\n\n let path: string\n try {\n const urlObj = new URL(loc)\n path = urlObj.pathname\n } catch {\n path = loc.startsWith('/') ? loc : `/${loc}`\n }\n\n if (path !== '/' && path.endsWith('/')) {\n path = path.slice(0, -1)\n }\n\n // Reject malformed paths (embedded domains, double protocols, etc.)\n if (path.includes('://') || /\\/\\/[a-z0-9.-]+\\.[a-z]{2,}/i.test(path)) {\n if (debug) console.warn(`[SitemapSync] Skipping malformed path: ${path}`)\n return\n }\n\n const lastmod = url.querySelector('lastmod')?.textContent || undefined\n const changefreq = url.querySelector('changefreq')?.textContent || undefined\n const priorityStr = url.querySelector('priority')?.textContent\n const priority = priorityStr ? parseFloat(priorityStr) : undefined\n\n entries.push({ path, lastmod, changefreq, priority })\n })\n\n if (debug) {\n console.log(`[SitemapSync] Parsed ${entries.length} entries from sitemap`)\n }\n\n return entries\n } catch (error) {\n if (debug) console.error('[SitemapSync] Error parsing sitemap:', error)\n return []\n }\n}\n\nasync function syncToPortal(\n entries: SitemapEntry[],\n apiUrl: string,\n apiKey: string,\n site: string,\n debug: boolean,\n mode: 'additive' | 'full-replace' = 'additive'\n): Promise<{ success: boolean; created: number; updated: number }> {\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key configured')\n return { success: false, created: 0, updated: 0 }\n }\n\n if (entries.length === 0) {\n if (debug) console.log('[SitemapSync] No entries to sync')\n return { success: true, created: 0, updated: 0 }\n }\n\n try {\n // Registration is idempotent in both modes (same payload → same final\n // state), so retrying a timed-out attempt is safe.\n const response = await sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n entries: entries.map(e => ({\n path: e.path,\n priority: e.priority,\n changefreq: e.changefreq,\n pageType: inferPageType(e.path),\n })),\n mode,\n // Sub-site host — tagged on every seo_pages row so the dashboard\n // can scope the page tree to one microsite. Resolved by\n // SiteKitClientProviders (see __SITE_KIT_SITE__).\n ...(site ? { site } : {}),\n }),\n }, { apiKey })\n\n if (!response.ok) {\n if (debug) console.error('[SitemapSync] API error:', response.status, response.statusText)\n return { success: false, created: 0, updated: 0 }\n }\n\n const result = await response.json()\n\n if (debug) {\n console.log(`[SitemapSync] Synced: ${result.created} created, ${result.updated} updated`)\n }\n\n return {\n success: true,\n created: result.created || 0,\n updated: result.updated || 0,\n }\n } catch (error) {\n if (debug) console.error('[SitemapSync] Sync error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\nexport function SitemapSync({\n sitemapUrl = '/sitemap.xml',\n syncInterval = 60,\n debug = false,\n mode = 'additive',\n}: SitemapSyncProps) {\n const hasSyncedRef = useRef(false)\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n\n useEffect(() => {\n // Build-time sync via createSitemap is the canonical source of truth, but\n // it can fail during ISR revalidation (app/ dir unavailable on serverless).\n // Runtime SitemapSync in additive mode is a safe fallback — it adds/updates\n // pages that may be missing without ever deleting existing ones.\n // Full-replace is never safe at runtime — always force additive.\n const effectiveMode: 'additive' | 'full-replace' = 'additive'\n\n // Throttle window: reuse syncInterval when periodic syncing is on,\n // otherwise default to 60 minutes for the on-mount sync.\n const throttleMinutes = syncInterval > 0 ? syncInterval : 60\n\n const doSync = async () => {\n const { apiUrl, apiKey, site } = getApiConfig()\n\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key found')\n return\n }\n\n if (isRecentlySynced(throttleMinutes)) {\n if (debug) console.log('[SitemapSync] Skipped — synced within the last', throttleMinutes, 'min this session')\n return\n }\n\n if (debug) console.log('[SitemapSync] Starting sitemap sync...', site ? `(site: ${site})` : '')\n\n const entries = await parseSitemap(sitemapUrl, debug)\n\n if (entries.length > 0) {\n const hash = hashEntries(sitemapUrl, entries)\n if (isAlreadySyncedHash(hash)) {\n // This exact sitemap already synced from this browser — the server\n // state can't be improved by re-POSTing it. Stamp the session so we\n // don't even re-fetch/parse for the rest of the throttle window.\n stampSynced()\n if (debug) console.log('[SitemapSync] Skipped POST — sitemap unchanged since last successful sync')\n return\n }\n const result = await syncToPortal(entries, apiUrl, apiKey, site, debug, effectiveMode)\n if (result.success) {\n stampSynced()\n storeSyncedHash(hash)\n }\n }\n }\n\n if (!hasSyncedRef.current) {\n hasSyncedRef.current = true\n doSync()\n }\n\n if (syncInterval > 0) {\n intervalRef.current = setInterval(doSync, syncInterval * 60 * 1000)\n }\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [sitemapUrl, syncInterval, debug, mode])\n\n return null\n}\n"]}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var chunk3BNFUMLL_js = require('./chunk-3BNFUMLL.js');
|
|
5
|
+
var chunkEAASMIWX_js = require('./chunk-EAASMIWX.js');
|
|
5
6
|
var React = require('react');
|
|
6
7
|
var ReactDOM = require('react-dom');
|
|
7
8
|
var dynamic = require('next/dynamic');
|
|
@@ -274,7 +275,7 @@ function DesignRenderer({
|
|
|
274
275
|
)) });
|
|
275
276
|
}
|
|
276
277
|
var LazyChatWidget = dynamic__default.default(
|
|
277
|
-
() => import('./ChatWidget-
|
|
278
|
+
() => import('./ChatWidget-AIOOZY6H.js').then((m) => ({ default: m.ChatWidget })),
|
|
278
279
|
{ ssr: false }
|
|
279
280
|
);
|
|
280
281
|
function getApiConfig() {
|
|
@@ -310,9 +311,10 @@ function EngageWidget({
|
|
|
310
311
|
const visitorId = chunk3BNFUMLL_js.getOrCreateVisitorId();
|
|
311
312
|
const url = typeof window !== "undefined" ? window.location.href : "";
|
|
312
313
|
try {
|
|
313
|
-
const response = await
|
|
314
|
+
const response = await chunkEAASMIWX_js.sonorFetch(
|
|
314
315
|
`${apiUrl.replace(/\/$/, "")}/engage/widget/elements?url=${encodeURIComponent(url)}&visitorId=${encodeURIComponent(visitorId)}`,
|
|
315
|
-
{
|
|
316
|
+
{},
|
|
317
|
+
{ apiKey }
|
|
316
318
|
);
|
|
317
319
|
if (!response.ok) {
|
|
318
320
|
if (debug) console.error("[Engage] Error loading elements:", response.statusText);
|
|
@@ -441,8 +443,8 @@ function EngageWidget({
|
|
|
441
443
|
projectId: propProjectId ?? void 0,
|
|
442
444
|
config: {
|
|
443
445
|
position,
|
|
444
|
-
buttonColor: "#
|
|
445
|
-
// Default blue, overridden by --sk-primary CSS var or API brand_primary
|
|
446
|
+
buttonColor: "#2563eb"
|
|
447
|
+
// Default blue-600 (AA on white), overridden by --sk-primary CSS var or API brand_primary
|
|
446
448
|
}
|
|
447
449
|
}
|
|
448
450
|
)
|
|
@@ -453,12 +455,12 @@ function EngageWidget({
|
|
|
453
455
|
function trackEngageEvent(apiUrl, apiKey, endpoint, data) {
|
|
454
456
|
if (!apiKey) return;
|
|
455
457
|
const visitorId = typeof localStorage !== "undefined" ? localStorage.getItem("_sk_vid") : null;
|
|
456
|
-
|
|
458
|
+
chunkEAASMIWX_js.sonorFetch(`${apiUrl.replace(/\/$/, "")}/engage/widget/${endpoint}`, {
|
|
457
459
|
method: "POST",
|
|
458
|
-
headers: { "Content-Type": "application/json"
|
|
460
|
+
headers: { "Content-Type": "application/json" },
|
|
459
461
|
body: JSON.stringify({ ...data, visitorId, pageUrl: window.location.href }),
|
|
460
462
|
keepalive: true
|
|
461
|
-
}).catch(() => {
|
|
463
|
+
}, { apiKey, retries: 0 }).catch(() => {
|
|
462
464
|
});
|
|
463
465
|
}
|
|
464
466
|
function handleEngageAction(action, _node, element, apiUrl, apiKey) {
|
|
@@ -677,7 +679,7 @@ function EngageElementRenderer({
|
|
|
677
679
|
top: 0,
|
|
678
680
|
left: 0,
|
|
679
681
|
right: 0,
|
|
680
|
-
backgroundColor: element.config?.backgroundColor || "var(--sk-primary, #
|
|
682
|
+
backgroundColor: element.config?.backgroundColor || "var(--sk-primary, #2563eb)",
|
|
681
683
|
color: element.config?.textColor || "var(--sk-bg, #ffffff)",
|
|
682
684
|
padding: "12px 24px",
|
|
683
685
|
display: "flex",
|
|
@@ -724,5 +726,5 @@ function getDeviceType() {
|
|
|
724
726
|
|
|
725
727
|
exports.DesignRenderer = DesignRenderer;
|
|
726
728
|
exports.EngageWidget = EngageWidget;
|
|
727
|
-
//# sourceMappingURL=chunk-
|
|
728
|
-
//# sourceMappingURL=chunk-
|
|
729
|
+
//# sourceMappingURL=chunk-4NTMIU6V.js.map
|
|
730
|
+
//# sourceMappingURL=chunk-4NTMIU6V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engage/DesignRenderer.tsx","../src/engage/EngageWidget.tsx"],"names":["useState","jsx","createElement","jsxs","React","dynamic","usePathname","useEffect","getOrCreateVisitorId","sonorFetch","useCallback","ReactDOM","Fragment","useRef"],"mappings":";;;;;;;;;;;;;;;;AA0EA,SAAS,YAAA,CACP,MAAA,EACA,IAAA,EACA,OAAA,EACA,QAAA,EACM;AACN,EAAA,IAAI,CAAC,MAAA,EAAQ,MAAA,IAAU,MAAA,CAAO,WAAW,MAAA,EAAQ;AAGjD,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,QAAA,CAAS,QAAQ,IAAI,CAAA;AAAA,EACvB;AAEA,EAAA,QAAQ,OAAO,MAAA;AAAQ,IACrB,KAAK,MAAA;AACH,MAAA,IAAI,OAAO,GAAA,EAAK;AACd,QAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,UAAA,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,GAAA,EAAK,QAAA,EAAU,qBAAqB,CAAA;AAAA,QACzD,CAAA,MAAO;AACL,UAAA,MAAA,CAAO,QAAA,CAAS,OAAO,MAAA,CAAO,GAAA;AAAA,QAChC;AAAA,MACF;AACA,MAAA;AAAA,IAEF,KAAK,QAAA;AACH,MAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,QAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,MAAA,CAAO,MAAM,CAAA;AACpD,QAAA,OAAA,EAAS,cAAA,CAAe,EAAE,QAAA,EAAU,QAAA,EAAU,CAAA;AAAA,MAChD;AACA,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,OAAA,IAAU;AACV,MAAA;AAAA,IAEF,KAAK,MAAA;AACH,MAAA,IAAI,OAAO,IAAA,EAAM;AACf,QAAA,SAAA,CAAU,UAAU,SAAA,CAAU,MAAA,CAAO,IAAI,CAAA,CAAE,KAAA,CAAM,QAAQ,KAAK,CAAA;AAAA,MAChE;AACA,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,IAAI,UAAU,KAAA,EAAO;AACnB,QAAA,SAAA,CAAU,KAAA,CAAM;AAAA,UACd,OAAO,QAAA,CAAS,KAAA;AAAA,UAChB,GAAA,EAAK,OAAO,QAAA,CAAS;AAAA,SACtB,CAAA,CAAE,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA;AAAA,MACxB;AACA,MAAA;AAAA,IAEF,KAAK,UAAA;AACH,MAAA,IAAI,OAAO,GAAA,EAAK;AACd,QAAA,MAAM,CAAA,GAAI,QAAA,CAAS,aAAA,CAAc,GAAG,CAAA;AACpC,QAAA,CAAA,CAAE,OAAO,MAAA,CAAO,GAAA;AAChB,QAAA,CAAA,CAAE,QAAA,GAAW,EAAA;AACb,QAAA,CAAA,CAAE,KAAA,EAAM;AAAA,MACV;AACA,MAAA;AASA;AAEN;AAMA,IAAM,kBAAA,GAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAW3B,SAAS,iBAAA,CAAkB,SAAA,EAAoB,KAAA,EAAgB,QAAA,EAAkC;AAC/F,EAAA,IAAI,CAAC,SAAA,IAAa,SAAA,KAAc,MAAA,SAAe,EAAC;AAEhD,EAAA,MAAM,YAAA,GAAuC;AAAA,IAC3C,MAAA,EAAQ,cAAA;AAAA,IACR,QAAA,EAAU,gBAAA;AAAA,IACV,UAAA,EAAY,kBAAA;AAAA,IACZ,WAAA,EAAa,mBAAA;AAAA,IACb,YAAA,EAAc,oBAAA;AAAA,IACd,SAAA,EAAW,iBAAA;AAAA,IACX,OAAA,EAAS,eAAA;AAAA,IACT,QAAA,EAAU;AAAA,GACZ;AAEA,EAAA,MAAM,aAAA,GAAgB,aAAa,SAAS,CAAA;AAC5C,EAAA,IAAI,CAAC,aAAA,EAAe,OAAO,EAAC;AAE5B,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,GAAG,aAAa,CAAA,CAAA,EAAI,YAAY,GAAG,CAAA,YAAA,EAAe,SAAS,CAAC,CAAA,WAAA,CAAA;AAAA,IACvE,OAAA,EAAS;AAAA;AAAA,GACX;AACF;AAaA,SAAS,aAAa,EAAE,IAAA,EAAM,OAAA,EAAS,QAAA,EAAU,SAAQ,EAAiD;AACxG,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAS,KAAK,CAAA;AAChD,EAAA,MAAM,EAAE,MAAM,KAAA,GAAQ,IAAI,KAAA,GAAQ,EAAC,EAAG,QAAA,EAAS,GAAI,IAAA;AAGnD,EAAA,MAAM,aAAA,GAA+B,EAAE,GAAG,KAAA,EAAM;AAGhD,EAAA,IAAI,MAAM,SAAA,EAAW;AACnB,IAAA,MAAA,CAAO,OAAO,aAAA,EAAe,iBAAA;AAAA,MAC3B,KAAA,CAAM,SAAA;AAAA,MACN,KAAA,CAAM,cAAA;AAAA,MACN,KAAA,CAAM;AAAA,KACP,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,IAAI,KAAA,CAAM,UAAA,IAAc,KAAA,CAAM,UAAA,KAAe,MAAA,EAAQ;AACnD,MAAA,aAAA,CAAc,SAAA,GAAY,CAAA,MAAA,EAAS,KAAA,CAAM,UAAU,CAAA,CAAA,CAAA;AACnD,MAAA,aAAA,CAAc,UAAA,GAAa,qBAAA;AAAA,IAC7B;AACA,IAAA,IAAI,KAAA,CAAM,WAAA,IAAe,KAAA,CAAM,WAAA,KAAgB,MAAA,EAAQ;AACrD,MAAA,MAAM,SAAA,GAAoC;AAAA,QACxC,EAAA,EAAI,+BAAA;AAAA,QACJ,EAAA,EAAI,iCAAA;AAAA,QACJ,EAAA,EAAI;AAAA,OACN;AACA,MAAA,aAAA,CAAc,SAAA,GAAY,SAAA,CAAU,KAAA,CAAM,WAAW,CAAA;AAAA,IACvD;AAAA,EACF;AAGA,EAAA,MAAM,aAAA,GAAyD;AAAA,IAC7D,YAAA,EAAc,MAAM,YAAA,CAAa,IAAI,CAAA;AAAA,IACrC,YAAA,EAAc,MAAM,YAAA,CAAa,KAAK;AAAA,GACxC;AAGA,EAAA,IAAI,MAAM,OAAA,EAAS;AACjB,IAAA,aAAA,CAAc,OAAA,GAAU,CAAC,CAAA,KAAkB;AACzC,MAAA,CAAA,CAAE,cAAA,EAAe;AACjB,MAAA,YAAA,CAAa,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,QAAQ,CAAA;AAAA,IACrD,CAAA;AACA,IAAA,aAAA,CAAc,MAAA,GAAS,SAAA;AAAA,EACzB;AAGA,EAAA,MAAM,gBAAA,GAAmB,QAAA,EAAU,GAAA,CAAI,CAAC,KAAA,qBACtCC,cAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MAEC,IAAA,EAAM,KAAA;AAAA,MACN,OAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KAAA;AAAA,IAJK,KAAA,CAAM;AAAA,GAMd,CAAA;AAGD,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,WAAA;AAAA,IACL,KAAK,KAAA;AAAA,IACL,KAAK,SAAA;AACH,MAAA,sCACG,KAAA,EAAA,EAAI,KAAA,EAAO,aAAA,EAAgB,GAAG,eAC5B,QAAA,EAAA,gBAAA,EACH,CAAA;AAAA,IAGJ,KAAK,MAAA;AACH,MAAA,uBACEA,cAAA,CAAC,GAAA,EAAA,EAAE,KAAA,EAAO,aAAA,EAAgB,GAAG,eAC1B,QAAA,EAAA,WAAA,CAAY,KAAA,CAAM,IAAA,EAAM,OAAO,CAAA,EAClC,CAAA;AAAA,IAGJ,KAAK,SAAA;AACH,MAAA,MAAM,UAAA,GAAa,CAAA,CAAA,EAAI,KAAA,CAAM,KAAA,IAAS,CAAC,CAAA,CAAA;AACvC,MAAA,OAAOC,mBAAA;AAAA,QACL,UAAA;AAAA,QACA,EAAE,KAAA,EAAO,aAAA,EAAe,GAAG,aAAA,EAAc;AAAA,QACzC,WAAA,CAAY,KAAA,CAAM,IAAA,EAAM,OAAO;AAAA,OACjC;AAAA,IAEF,KAAK,QAAA;AAAA,IACL,KAAK,eAAA;AAAA,IACL,KAAK,QAAA;AAAA,IACL,KAAK,WAAA;AAAA,IACL,KAAK,WAAA;AACH,MAAA,uBACED,cAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,aAAA;AAAA,UACN,GAAG,aAAA;AAAA,UACJ,IAAA,EAAK,QAAA;AAAA,UAEJ,sBAAY,KAAA,CAAM,IAAA,IAAQ,KAAA,CAAM,KAAA,EAAO,OAAO,CAAA,IAAK;AAAA;AAAA,OACtD;AAAA,IAGJ,KAAK,OAAA;AACH,MAAA,uBACEA,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAK,KAAA,CAAM,GAAA;AAAA,UACX,GAAA,EAAK,MAAM,GAAA,IAAO,EAAA;AAAA,UAClB,KAAA,EAAO,aAAA;AAAA,UACN,GAAG;AAAA;AAAA,OACN;AAAA,IAGJ,KAAK,MAAA;AACH,MAAA,uBACEA,cAAA;AAAA,QAAC,GAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAM,MAAM,IAAA,IAAQ,GAAA;AAAA,UACpB,MAAA,EAAQ,KAAA,CAAM,MAAA,GAAS,QAAA,GAAW,MAAA;AAAA,UAClC,GAAA,EAAK,KAAA,CAAM,MAAA,GAAS,qBAAA,GAAwB,MAAA;AAAA,UAC5C,KAAA,EAAO,aAAA;AAAA,UACN,GAAG,aAAA;AAAA,UAEH,QAAA,EAAA,WAAA,CAAY,KAAA,CAAM,IAAA,EAAM,OAAO,CAAA,IAAK;AAAA;AAAA,OACvC;AAAA,IAGJ,KAAK,OAAA;AACH,MAAA,uBACEA,cAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAM,MAAM,SAAA,IAAa,MAAA;AAAA,UACzB,aAAa,KAAA,CAAM,WAAA;AAAA,UACnB,KAAA,EAAO,aAAA;AAAA,UACN,GAAG;AAAA;AAAA,OACN;AAAA,IAGJ,KAAK,SAAA;AACH,MAAA,uBAAOA,cAAA,CAAC,IAAA,EAAA,EAAG,KAAA,EAAO,EAAE,MAAA,EAAQ,QAAQ,SAAA,EAAW,qCAAA,EAAuC,GAAG,aAAA,EAAc,EAAG,CAAA;AAAA,IAE5G,KAAK,QAAA;AACH,MAAA,uBAAOA,cAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,GAAG,aAAA,EAAe,KAAA,EAAO,KAAA,CAAM,KAAA,EAAO,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAO,EAAG,CAAA;AAAA,IAErF,KAAK,MAAA;AAEH,MAAA,uBACEA,cAAA,CAAC,UAAK,KAAA,EAAO,aAAA,EAAgB,GAAG,aAAA,EAC7B,QAAA,EAAA,KAAA,CAAM,QAAQ,QAAA,EACjB,CAAA;AAAA,IAGJ,KAAK,WAAA;AAGH,MAAA,uBACEA,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,aAAA;AAAA,UACP,oBAAkB,KAAA,CAAM,OAAA;AAAA,UACvB,GAAG,aAAA;AAAA,UAGJ,QAAA,kBAAAE,eAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAY,gCAAA,EAAkC,YAAA,EAAc,KAAA,EAAO,SAAA,EAAW,QAAA,EAAS,EAAG,QAAA,EAAA;AAAA,YAAA,QAAA;AAAA,YAChH,MAAM,OAAA,IAAW;AAAA,WAAA,EAC1B;AAAA;AAAA,OACF;AAAA,IAGJ,KAAK,aAAA;AAAA,IACL,KAAK,WAAA;AAEH,MAAA,uBACEF,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,aAAA;AAAA,UACP,wBAAsB,KAAA,CAAM,WAAA;AAAA,UAC3B,GAAG,aAAA;AAAA,UAEH,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,IAGJ;AAEE,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,oCAAA,EAAuC,IAAI,CAAA,CAAE,CAAA;AAC1D,MAAA,sCACG,KAAA,EAAA,EAAI,KAAA,EAAO,aAAA,EAAgB,GAAG,eAC5B,QAAA,EAAA,gBAAA,EACH,CAAA;AAAA;AAGR;AAMA,SAAS,WAAA,CAAY,MAA0B,OAAA,EAAiC;AAC9E,EAAA,IAAI,CAAC,MAAM,OAAO,EAAA;AAClB,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAGrB,EAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,0BAAA,EAA4B,CAAC,OAAO,IAAA,KAAS;AAC/D,IAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,OAAA,EAAS,IAAI,CAAA;AAC1C,IAAA,OAAO,KAAA,KAAU,MAAA,GAAY,MAAA,CAAO,KAAK,CAAA,GAAI,KAAA;AAAA,EAC/C,CAAC,CAAA;AACH;AAEA,SAAS,cAAA,CAAe,KAA0B,IAAA,EAAmB;AACnE,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,MAAA,CAAO,CAAC,GAAA,EAAK,GAAA,KAAQ,GAAA,GAAM,GAAG,CAAA,EAAG,GAAG,CAAA;AAC7D;AAMO,SAAS,cAAA,CAAe;AAAA,EAC7B,MAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAA4C;AAE1C,EAAAG,sBAAA,CAAM,UAAU,MAAM;AACpB,IAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AAErC,IAAA,MAAM,OAAA,GAAU,mCAAA;AAChB,IAAA,IAAI,CAAC,QAAA,CAAS,cAAA,CAAe,OAAO,CAAA,EAAG;AACrC,MAAA,MAAM,UAAA,GAAa,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AACjD,MAAA,UAAA,CAAW,EAAA,GAAK,OAAA;AAChB,MAAA,UAAA,CAAW,WAAA,GAAc,kBAAA;AACzB,MAAA,QAAA,CAAS,IAAA,CAAK,YAAY,UAAU,CAAA;AAAA,IACtC;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,MAAM,SAAA,GAA2B;AAAA,IAC/B,GAAG,MAAA,CAAO;AAAA,GACZ;AAEA,EAAA,uBACEH,cAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,SAAA,EAAW,oBAAA,EAAoB,MAAA,CAAO,EAAA,EAC/C,QAAA,EAAA,MAAA,CAAO,QAAA,EAAU,GAAA,CAAI,CAAC,IAAA,qBACrBA,cAAA;AAAA,IAAC,YAAA;AAAA,IAAA;AAAA,MAEC,IAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KAAA;AAAA,IAJK,IAAA,CAAK;AAAA,GAMb,CAAA,EACH,CAAA;AAEJ;AClaA,IAAM,cAAA,GAAiBI,wBAAA;AAAA,EACrB,MAAM,OAAO,0BAAc,CAAA,CAAE,IAAA,CAAK,QAAM,EAAE,OAAA,EAAS,CAAA,CAAE,UAAA,EAAW,CAAE,CAAA;AAAA,EAClE,EAAE,KAAK,KAAA;AACT,CAAA;AAYA,SAAS,YAAA,GAAe;AACtB,EAAA,MAAM,QAAQ,OAAO,OAAA,KAAY,WAAA,IAAe,OAAA,CAAQ,KAAK,QAAA,KAAa,aAAA;AAC1E,EAAA,MAAM,gBAAgB,KAAA,IAAS,OAAA,CAAQ,KAAK,aAAA,GACxC,OAAA,CAAQ,IAAI,aAAA,GACZ,sBAAA;AACJ,EAAA,MAAM,SAAS,OAAO,MAAA,KAAW,WAAA,GAC5B,MAAA,CAAe,wBAAwB,aAAA,GACxC,aAAA;AACJ,EAAA,MAAM,MAAA,GAAS,OAAO,MAAA,KAAW,WAAA,GAAe,OAAe,oBAAA,GAAuB,MAAA;AACtF,EAAA,OAAO,EAAE,QAAQ,MAAA,EAAO;AAC1B;AAEO,SAAS,YAAA,CAAa;AAAA,EAC3B,MAAA,EAAQ,UAAA;AAAA,EACR,MAAA,EAAQ,UAAA;AAAA,EACR,SAAA,EAAW,aAAA;AAAA,EACX,QAAA,GAAW,cAAA;AAAA,EACX,MAAA,GAAS,IAAA;AAAA,EACT,WAAA,GAAc,IAAA;AAAA,EACd,KAAA,GAAQ;AACV,CAAA,EAAsB;AACpB,EAAA,MAAM,WAAWC,sBAAA,EAAY;AAC7B,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIN,cAAAA,CAA0B,EAAE,CAAA;AAC5D,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAIA,cAAAA,CAAmB,EAAE,CAAA;AACjE,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,IAAIA,cAAAA,iBAAsB,IAAI,KAAK,CAAA;AACjF,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAS,KAAK,CAAA;AAGhD,EAAAO,eAAA,CAAU,MAAM;AACd,IAAA,eAAe,YAAA,GAAe;AAC5B,MAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,EAAc,MAAA,EAAQ,YAAA,KAAiB,YAAA,EAAa;AACpE,MAAA,MAAM,SAAS,UAAA,IAAc,YAAA;AAC7B,MAAA,MAAM,SAAS,UAAA,IAAc,YAAA;AAE7B,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,gCAAgC,CAAA;AACxD,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,YAAYC,qCAAA,EAAqB;AACvC,MAAA,MAAM,MAAM,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,CAAO,SAAS,IAAA,GAAO,EAAA;AAEnE,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,MAAMC,2BAAA;AAAA,UACrB,CAAA,EAAG,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,4BAAA,EAA+B,kBAAA,CAAmB,GAAG,CAAC,CAAA,WAAA,EAAc,kBAAA,CAAmB,SAAS,CAAC,CAAA,CAAA;AAAA,UAC7H,EAAC;AAAA,UACD,EAAE,MAAA;AAAO,SACX;AAEA,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,kCAAA,EAAoC,SAAS,UAAU,CAAA;AAChF,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,QAAA,MAAM,eAAe,IAAA,CAAK,IAAA,EAAM,QAAA,IAAY,IAAA,CAAK,YAAY,EAAC;AAC9D,QAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,2BAAA,EAA6B,YAAY,CAAA;AAChE,QAAA,WAAA,CAAY,YAAY,CAAA;AAAA,MAC1B,SAAS,KAAA,EAAO;AACd,QAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,kCAAA,EAAoC,KAAK,CAAA;AAAA,MACpE;AAAA,IACF;AAEA,IAAA,YAAA,EAAa;AAAA,EACf,CAAA,EAAG,CAAC,UAAA,EAAY,UAAA,EAAY,KAAK,CAAC,CAAA;AAGlC,EAAAF,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,WAAA,EAAa;AAClB,IAAA,MAAM,KACJ,OAAO,mBAAA,KAAwB,cAC3B,mBAAA,CAAoB,MAAM,aAAa,IAAI,CAAA,EAAG,EAAE,OAAA,EAAS,GAAA,EAAM,CAAA,GAC/D,UAAA,CAAW,MAAM,YAAA,CAAa,IAAI,GAAG,CAAC,CAAA;AAC5C,IAAA,OAAO,MAAM;AACX,MAAA,OAAO,uBAAuB,WAAA,GAAc,kBAAA,CAAmB,EAAY,CAAA,GAAI,aAAa,EAAE,CAAA;AAAA,IAChG,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAGhB,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAS,MAAA,EAAQ;AAEtB,IAAA,MAAM,YAAA,GAAe,CAAC,OAAA,KAAoC;AAExD,MAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,OAAA,CAAQ,EAAE,GAAG,OAAO,KAAA;AAG9C,MAAA,IAAI,OAAA,CAAQ,WAAW,KAAA,EAAO;AAC5B,QAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAQ,GAAI,QAAQ,SAAA,CAAU,KAAA;AAE/C,QAAA,IAAI,OAAA,EAAS,KAAK,CAAA,CAAA,KAAK,SAAA,CAAU,UAAU,CAAC,CAAC,GAAG,OAAO,KAAA;AACvD,QAAA,IAAI,OAAA,IAAW,CAAC,OAAA,CAAQ,IAAA,CAAK,CAAA,CAAA,KAAK,UAAU,QAAA,EAAU,CAAC,CAAC,CAAA,EAAG,OAAO,KAAA;AAAA,MACpE;AAGA,MAAA,IAAI,OAAA,CAAQ,WAAW,OAAA,EAAS;AAC9B,QAAA,MAAM,SAAS,aAAA,EAAc;AAC7B,QAAA,IAAI,CAAC,OAAA,CAAQ,SAAA,CAAU,QAAQ,QAAA,CAAS,MAAM,GAAG,OAAO,KAAA;AAAA,MAC1D;AAGA,MAAA,IAAI,OAAA,CAAQ,SAAS,SAAA,EAAW;AAC9B,QAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,QAAQ,OAAA,CAAQ,SAAA;AACvC,QAAA,MAAM,GAAA,GAAM,CAAA,QAAA,EAAW,OAAA,CAAQ,EAAE,CAAA,CAAA;AAEjC,QAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,UAAA,IAAI,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA,EAAG,OAAO,KAAA;AAAA,QACxC,CAAA,MAAA,IAAW,SAAS,kBAAA,EAAoB;AACtC,UAAA,IAAI,cAAA,CAAe,OAAA,CAAQ,GAAG,CAAA,EAAG,OAAO,KAAA;AAAA,QAC1C,CAAA,MAAA,IAAW,IAAA,KAAS,cAAA,IAAkB,IAAA,EAAM;AAC1C,UAAA,MAAM,SAAA,GAAY,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAC1C,UAAA,IAAI,SAAA,EAAW;AACb,YAAA,MAAM,UAAU,IAAA,CAAK,GAAA,EAAI,GAAI,QAAA,CAAS,WAAW,EAAE,CAAA;AACnD,YAAA,IAAI,UAAU,IAAA,GAAO,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,KAAM,OAAO,KAAA;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAGA,IAAA,MAAM,QAAA,GAAW,QAAA,CAAS,MAAA,CAAO,YAAY,CAAA;AAE7C,IAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,6BAAA,EAA+B,QAAQ,CAAA;AAK9D,IAAA,MAAM,QAAA,GAAW,CAAC,EAAA,KAAe;AAC/B,MAAA,iBAAA,CAAkB,CAAA,IAAA,KAAS,IAAA,CAAK,QAAA,CAAS,EAAE,CAAA,GAAI,OAAO,CAAC,GAAG,IAAA,EAAM,EAAE,CAAE,CAAA;AAAA,IACtE,CAAA;AAKA,IAAA,MAAM,WAA8B,EAAC;AAErC,IAAA,QAAA,CAAS,QAAQ,CAAA,OAAA,KAAW;AAC1B,MAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AAExB,MAAA,IAAI,OAAA,EAAS,IAAA,KAAS,WAAA,IAAe,CAAC,SAAS,IAAA,EAAM;AACnD,QAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AAAA,MACrB,CAAA,MAAA,IAAW,OAAA,EAAS,IAAA,KAAS,OAAA,IAAW,QAAQ,KAAA,EAAO;AACrD,QAAA,MAAM,KAAA,GAAQ,WAAW,MAAM,QAAA,CAAS,QAAQ,EAAE,CAAA,EAAG,OAAA,CAAQ,KAAA,GAAQ,GAAI,CAAA;AACzE,QAAA,QAAA,CAAS,IAAA,CAAK,MAAM,YAAA,CAAa,KAAK,CAAC,CAAA;AAAA,MACzC,CAAA,MAAA,IAAW,OAAA,EAAS,IAAA,KAAS,aAAA,EAAe;AAC1C,QAAA,MAAM,gBAAA,GAAmB,CAAC,CAAA,KAAkB;AAC1C,UAAA,IAAI,CAAA,CAAE,UAAU,EAAA,EAAI;AAClB,YAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AACnB,YAAA,QAAA,CAAS,mBAAA,CAAoB,cAAc,gBAAgB,CAAA;AAAA,UAC7D;AAAA,QACF,CAAA;AACA,QAAA,QAAA,CAAS,gBAAA,CAAiB,cAAc,gBAAgB,CAAA;AACxD,QAAA,QAAA,CAAS,KAAK,MAAM,QAAA,CAAS,mBAAA,CAAoB,YAAA,EAAc,gBAAgB,CAAC,CAAA;AAAA,MAClF,CAAA,MAAA,IAAW,OAAA,EAAS,IAAA,KAAS,QAAA,IAAY,QAAQ,gBAAA,EAAkB;AACjE,QAAA,MAAM,eAAe,MAAM;AACzB,UAAA,MAAM,gBAAiB,MAAA,CAAO,OAAA,IAAW,SAAS,IAAA,CAAK,YAAA,GAAe,OAAO,WAAA,CAAA,GAAgB,GAAA;AAC7F,UAAA,IAAI,aAAA,KAAkB,OAAA,CAAQ,gBAAA,IAAoB,EAAA,CAAA,EAAK;AACrD,YAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AACnB,YAAA,MAAA,CAAO,mBAAA,CAAoB,UAAU,YAAY,CAAA;AAAA,UACnD;AAAA,QACF,CAAA;AACA,QAAA,MAAA,CAAO,iBAAiB,QAAA,EAAU,YAAA,EAAc,EAAE,OAAA,EAAS,MAAM,CAAA;AACjE,QAAA,QAAA,CAAS,KAAK,MAAM,MAAA,CAAO,mBAAA,CAAoB,QAAA,EAAU,YAAY,CAAC,CAAA;AAAA,MACxE;AAAA,IACF,CAAC,CAAA;AAED,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,OAAA,CAAQ,CAAA,EAAA,KAAM,EAAA,EAAI,CAAA;AAAA,IAC7B,CAAA;AAAA,EACF,GAAG,CAAC,QAAA,EAAU,QAAA,EAAU,iBAAA,EAAmB,KAAK,CAAC,CAAA;AAEjD,EAAA,MAAM,aAAA,GAAgBG,iBAAA,CAAY,CAAC,SAAA,KAAsB;AACvD,IAAA,oBAAA,CAAqB,CAAA,IAAA,yBAAY,GAAA,CAAI,CAAC,GAAG,IAAA,EAAM,SAAS,CAAC,CAAC,CAAA;AAC1D,IAAA,iBAAA,CAAkB,UAAQ,IAAA,CAAK,MAAA,CAAO,CAAA,EAAA,KAAM,EAAA,KAAO,SAAS,CAAC,CAAA;AAG7D,IAAA,MAAM,UAAU,QAAA,CAAS,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,CAAE,OAAO,SAAS,CAAA;AACrD,IAAA,IAAI,OAAA,EAAS,SAAS,SAAA,EAAW;AAC/B,MAAA,MAAM,GAAA,GAAM,WAAW,SAAS,CAAA,CAAA;AAChC,MAAA,IAAI,OAAA,CAAQ,OAAA,CAAQ,SAAA,CAAU,IAAA,KAAS,kBAAA,EAAoB;AACzD,QAAA,cAAA,CAAe,OAAA,CAAQ,KAAK,MAAM,CAAA;AAAA,MACpC,CAAA,MAAO;AACL,QAAA,YAAA,CAAa,QAAQ,GAAA,EAAK,IAAA,CAAK,GAAA,EAAI,CAAE,UAAU,CAAA;AAAA,MACjD;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAKb,EAAA,IAAI,OAAO,QAAA,KAAa,WAAA,EAAa,OAAO,IAAA;AAE5C,EAAA,OAAOC,yBAAA,CAAS,YAAA;AAAA,oBACdR,gBAAAS,mBAAA,EAAA,EACG,QAAA,EAAA;AAAA,MAAA,cAAA,CAAe,IAAI,CAAA,SAAA,KAAa;AAC/B,QAAA,MAAM,UAAU,QAAA,CAAS,IAAA,CAAK,CAAA,CAAA,KAAK,CAAA,CAAE,OAAO,SAAS,CAAA;AACrD,QAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,QAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,EAAc,MAAA,EAAQ,YAAA,KAAiB,YAAA,EAAa;AACpE,QAAA,uBACEX,cAAAA;AAAA,UAAC,qBAAA;AAAA,UAAA;AAAA,YAEC,OAAA;AAAA,YACA,SAAA,EAAW,MAAM,aAAA,CAAc,OAAA,CAAQ,EAAE,CAAA;AAAA,YACzC,MAAA;AAAA,YACA,QAAQ,UAAA,IAAc,YAAA;AAAA,YACtB,QAAQ,UAAA,IAAc;AAAA,WAAA;AAAA,UALjB,OAAA,CAAQ;AAAA,SAMf;AAAA,MAEJ,CAAC,CAAA;AAAA,MAGA,WAAA,IAAe,6BACdA,cAAAA;AAAA,QAAC,cAAA;AAAA,QAAA;AAAA,UACC,WAAW,aAAA,IAAiB,MAAA;AAAA,UAC5B,MAAA,EAAQ;AAAA,YACN,QAAA;AAAA,YACA,WAAA,EAAa;AAAA;AAAA;AACf;AAAA;AACF,KAAA,EAEJ,CAAA;AAAA,IACA,QAAA,CAAS;AAAA,GACX;AACF;AAMA,SAAS,gBAAA,CACP,MAAA,EACA,MAAA,EACA,QAAA,EACA,IAAA,EACA;AACA,EAAA,IAAI,CAAC,MAAA,EAAQ;AACb,EAAA,MAAM,YAAY,OAAO,YAAA,KAAiB,cACtC,YAAA,CAAa,OAAA,CAAQ,SAAS,CAAA,GAC9B,IAAA;AACJ,EAAAQ,2BAAA,CAAW,CAAA,EAAG,OAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,eAAA,EAAkB,QAAQ,CAAA,CAAA,EAAI;AAAA,IACnE,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,GAAG,IAAA,EAAM,SAAA,EAAW,OAAA,EAAS,MAAA,CAAO,QAAA,CAAS,IAAA,EAAM,CAAA;AAAA,IAC1E,SAAA,EAAW;AAAA,GACb,EAAG,EAAE,MAAA,EAAQ,OAAA,EAAS,GAAG,CAAA,CAAE,MAAM,MAAM;AAAA,EAAC,CAAC,CAAA;AAC3C;AAEA,SAAS,kBAAA,CACP,MAAA,EACA,KAAA,EACA,OAAA,EACA,QACA,MAAA,EACA;AAEA,EAAA,gBAAA,CAAiB,MAAA,EAAQ,QAAQ,OAAA,EAAS;AAAA,IACxC,WAAW,OAAA,CAAQ,EAAA;AAAA,IACnB,QAAQ,MAAA,CAAO;AAAA,GAChB,CAAA;AAED,EAAA,QAAQ,OAAO,MAAA;AAAQ,IACrB,KAAK,UAAA;AACH,MAAA,IAAI,MAAA,CAAO,GAAA,EAAK,MAAA,CAAO,QAAA,CAAS,OAAO,MAAA,CAAO,GAAA;AAC9C,MAAA;AAAA,IACF,KAAK,UAAA;AACH,MAAA,IAAI,OAAO,GAAA,EAAK,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,KAAK,QAAQ,CAAA;AAChD,MAAA;AAAA,IACF,KAAK,aAAA;AAAA,IACL,KAAK,aAAA;AACH,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,oBAAA,EAAsB;AAAA,QACzD,MAAA,EAAQ,EAAE,MAAA,EAAQ,MAAA,CAAO,UAAU,MAAA,CAAO,GAAA,EAAK,SAAA,EAAW,OAAA,CAAQ,EAAA;AAAG,OACtE,CAAC,CAAA;AACF,MAAA;AAAA,IACF,KAAK,kBAAA;AACH,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,mBAAA,EAAqB;AAAA,QACxD,MAAA,EAAQ,EAAE,MAAA,EAAQ,SAAA,EAAW,QAAQ,EAAA;AAAG,OACzC,CAAC,CAAA;AACF,MAAA;AAAA,IACF;AACE,MAAA,MAAA,CAAO,aAAA,CAAc,IAAI,WAAA,CAAY,eAAA,EAAiB;AAAA,QACpD,MAAA,EAAQ,EAAE,MAAA,EAAQ,SAAA,EAAW,QAAQ,EAAA;AAAG,OACzC,CAAC,CAAA;AACF,MAAA;AAAA;AAEN;AAGA,SAAS,qBAAA,CAAsB;AAAA,EAC7B,OAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAMG;AAED,EAAA,MAAM,YAAA,GAAeI,aAAuB,IAAI,CAAA;AAChD,EAAA,MAAM,oBAAA,GAAuBA,aAAO,KAAK,CAAA;AAEzC,EAAAN,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,KAAK,YAAA,CAAa,OAAA;AACxB,IAAA,IAAI,CAAC,EAAA,IAAM,oBAAA,CAAqB,OAAA,EAAS;AAEzC,IAAA,MAAM,WAAW,IAAI,oBAAA;AAAA,MACnB,CAAC,CAAC,KAAK,CAAA,KAAM;AACX,QAAA,IAAI,KAAA,CAAM,cAAA,IAAkB,CAAC,oBAAA,CAAqB,OAAA,EAAS;AACzD,UAAA,oBAAA,CAAqB,OAAA,GAAU,IAAA;AAC/B,UAAA,gBAAA,CAAiB,QAAQ,MAAA,EAAQ,YAAA,EAAc,EAAE,SAAA,EAAW,OAAA,CAAQ,IAAI,CAAA;AACxE,UAAA,QAAA,CAAS,UAAA,EAAW;AAAA,QACtB;AAAA,MACF,CAAA;AAAA,MACA,EAAE,WAAW,GAAA;AAAI,KACnB;AACA,IAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AACnB,IAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,EACnC,GAAG,CAAC,MAAA,EAAQ,MAAA,EAAQ,OAAA,CAAQ,EAAE,CAAC,CAAA;AAE/B,EAAA,MAAM,QAAA,GAAWG,iBAAA;AAAA,IACf,CAAC,QAAsB,IAAA,KAAkB;AACvC,MAAA,kBAAA,CAAmB,MAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAAA,IAC1D,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,MAAA,EAAQ,MAAM;AAAA,GAC1B;AAGA,EAAA,IAAI,QAAQ,WAAA,EAAa;AAEvB,IAAA,IAAI,OAAA,CAAQ,SAAS,OAAA,EAAS;AAC5B,MAAA,uBACET,cAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,YAAA;AAAA,UACL,uBAAqB,OAAA,CAAQ,EAAA;AAAA,UAC7B,KAAA,EAAO;AAAA,YACL,QAAA,EAAU,OAAA;AAAA,YACV,GAAA,EAAK,CAAA;AAAA,YACL,IAAA,EAAM,CAAA;AAAA,YACN,KAAA,EAAO,CAAA;AAAA,YACP,MAAA,EAAQ,CAAA;AAAA,YACR,eAAA,EAAiB,iBAAA;AAAA,YACjB,OAAA,EAAS,MAAA;AAAA,YACT,UAAA,EAAY,QAAA;AAAA,YACZ,cAAA,EAAgB,QAAA;AAAA,YAChB;AAAA,WACF;AAAA,UACA,OAAA,EAAS,SAAA;AAAA,UAET,QAAA,kBAAAA,eAAC,KAAA,EAAA,EAAI,OAAA,EAAS,OAAK,CAAA,CAAE,eAAA,IACnB,QAAA,kBAAAA,cAAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,QAAQ,OAAA,CAAQ,WAAA;AAAA,cAChB,OAAA,EAAS,SAAA;AAAA,cACT;AAAA;AAAA,WACF,EACF;AAAA;AAAA,OACF;AAAA,IAEJ;AAEA,IAAA,IAAI,OAAA,CAAQ,SAAS,KAAA,EAAO;AAC1B,MAAA,uBACEA,cAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,YAAA;AAAA,UACL,uBAAqB,OAAA,CAAQ,EAAA;AAAA,UAC7B,KAAA,EAAO;AAAA,YACL,QAAA,EAAU,OAAA;AAAA,YACV,GAAA,EAAK,CAAA;AAAA,YACL,IAAA,EAAM,CAAA;AAAA,YACN,KAAA,EAAO,CAAA;AAAA,YACP;AAAA,WACF;AAAA,UAEA,QAAA,kBAAAA,cAAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,QAAQ,OAAA,CAAQ,WAAA;AAAA,cAChB,OAAA,EAAS,SAAA;AAAA,cACT;AAAA;AAAA;AACF;AAAA,OACF;AAAA,IAEJ;AAEA,IAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,OAAA,IAAW,OAAA,CAAQ,SAAS,UAAA,EAAY;AAC3D,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,MAAA,EAAQ,QAAA,IAAY,cAAA;AAC7C,MAAA,MAAM,cAAA,GAAsD;AAAA,QAC1D,cAAA,EAAgB,EAAE,MAAA,EAAQ,EAAA,EAAI,OAAO,EAAA,EAAG;AAAA,QACxC,aAAA,EAAe,EAAE,MAAA,EAAQ,EAAA,EAAI,MAAM,EAAA,EAAG;AAAA,QACtC,WAAA,EAAa,EAAE,GAAA,EAAK,EAAA,EAAI,OAAO,EAAA,EAAG;AAAA,QAClC,UAAA,EAAY,EAAE,GAAA,EAAK,EAAA,EAAI,MAAM,EAAA;AAAG,OAClC;AAEA,MAAA,uBACEA,cAAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,YAAA;AAAA,UACL,uBAAqB,OAAA,CAAQ,EAAA;AAAA,UAC7B,KAAA,EAAO;AAAA,YACL,QAAA,EAAU,OAAA;AAAA,YACV,MAAA;AAAA,YACA,GAAG,eAAe,QAAQ;AAAA,WAC5B;AAAA,UAEA,QAAA,kBAAAA,cAAAA;AAAA,YAAC,cAAA;AAAA,YAAA;AAAA,cACC,QAAQ,OAAA,CAAQ,WAAA;AAAA,cAChB,OAAA,EAAS,SAAA;AAAA,cACT;AAAA;AAAA;AACF;AAAA,OACF;AAAA,IAEJ;AAGA,IAAA,uBACEA,eAAC,KAAA,EAAA,EAAI,GAAA,EAAK,cAAc,qBAAA,EAAqB,OAAA,CAAQ,IACnD,QAAA,kBAAAA,cAAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,QAAQ,OAAA,CAAQ,WAAA;AAAA,QAChB,OAAA,EAAS,SAAA;AAAA,QACT;AAAA;AAAA,KACF,EACF,CAAA;AAAA,EAEJ;AAGA,EAAA,IAAI,OAAA,CAAQ,SAAS,OAAA,EAAS;AAC5B,IAAA,uBACEA,cAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO;AAAA,UACL,QAAA,EAAU,OAAA;AAAA,UACV,GAAA,EAAK,CAAA;AAAA,UACL,IAAA,EAAM,CAAA;AAAA,UACN,KAAA,EAAO,CAAA;AAAA,UACP,MAAA,EAAQ,CAAA;AAAA,UACR,eAAA,EAAiB,iBAAA;AAAA,UACjB,OAAA,EAAS,MAAA;AAAA,UACT,UAAA,EAAY,QAAA;AAAA,UACZ,cAAA,EAAgB,QAAA;AAAA,UAChB;AAAA,SACF;AAAA,QACA,OAAA,EAAS,SAAA;AAAA,QAET,QAAA,kBAAAE,eAAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO;AAAA,cACL,eAAA,EAAiB,uBAAA;AAAA,cACjB,OAAA,EAAS,EAAA;AAAA,cACT,YAAA,EAAc,CAAA;AAAA,cACd,QAAA,EAAU,GAAA;AAAA,cACV,KAAA,EAAO;AAAA,aACT;AAAA,YACA,OAAA,EAAS,CAAA,CAAA,KAAK,CAAA,CAAE,eAAA,EAAgB;AAAA,YAEhC,QAAA,EAAA;AAAA,8BAAAF,cAAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBACC,OAAA,EAAS,SAAA;AAAA,kBACT,KAAA,EAAO;AAAA,oBACL,QAAA,EAAU,UAAA;AAAA,oBACV,GAAA,EAAK,CAAA;AAAA,oBACL,KAAA,EAAO,CAAA;AAAA,oBACP,UAAA,EAAY,MAAA;AAAA,oBACZ,MAAA,EAAQ,MAAA;AAAA,oBACR,QAAA,EAAU,EAAA;AAAA,oBACV,MAAA,EAAQ;AAAA,mBACV;AAAA,kBACD,QAAA,EAAA;AAAA;AAAA,eAED;AAAA,cACC,OAAA,CAAQ,QAAQ,KAAA,oBAASA,eAAC,IAAA,EAAA,EAAI,QAAA,EAAA,OAAA,CAAQ,OAAO,KAAA,EAAM,CAAA;AAAA,cACnD,OAAA,CAAQ,QAAQ,OAAA,oBAAWA,eAAC,GAAA,EAAA,EAAG,QAAA,EAAA,OAAA,CAAQ,OAAO,OAAA,EAAQ;AAAA;AAAA;AAAA;AACzD;AAAA,KACF;AAAA,EAEJ;AAGA,EAAA,IAAI,OAAA,CAAQ,SAAS,KAAA,EAAO;AAC1B,IAAA,uBACEE,eAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO;AAAA,UACL,QAAA,EAAU,OAAA;AAAA,UACV,GAAA,EAAK,CAAA;AAAA,UACL,IAAA,EAAM,CAAA;AAAA,UACN,KAAA,EAAO,CAAA;AAAA,UACP,eAAA,EAAiB,OAAA,CAAQ,MAAA,EAAQ,eAAA,IAAmB,4BAAA;AAAA,UACpD,KAAA,EAAO,OAAA,CAAQ,MAAA,EAAQ,SAAA,IAAa,uBAAA;AAAA,UACpC,OAAA,EAAS,WAAA;AAAA,UACT,OAAA,EAAS,MAAA;AAAA,UACT,UAAA,EAAY,QAAA;AAAA,UACZ,cAAA,EAAgB,QAAA;AAAA,UAChB,GAAA,EAAK,EAAA;AAAA,UACL;AAAA,SACF;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAAF,cAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,OAAA,CAAQ,MAAA,EAAQ,OAAA,EAAQ,CAAA;AAAA,0BAC/BA,cAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAAS,SAAA;AAAA,cACT,KAAA,EAAO;AAAA,gBACL,UAAA,EAAY,MAAA;AAAA,gBACZ,MAAA,EAAQ,MAAA;AAAA,gBACR,KAAA,EAAO,SAAA;AAAA,gBACP,QAAA,EAAU,EAAA;AAAA,gBACV,MAAA,EAAQ;AAAA,eACV;AAAA,cACD,QAAA,EAAA;AAAA;AAAA;AAED;AAAA;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,SAAA,CAAU,UAAkB,OAAA,EAA0B;AAC7D,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG;AACzB,IAAA,OAAO,SAAS,UAAA,CAAW,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AAAA,EACjD;AACA,EAAA,OAAO,QAAA,KAAa,OAAA;AACtB;AAEA,SAAS,aAAA,GAAiD;AACxD,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,SAAA;AAC1C,EAAA,MAAM,KAAK,SAAA,CAAU,SAAA;AACrB,EAAA,IAAI,4BAAA,CAA6B,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,QAAA;AAClD,EAAA,IAAI,4DAAA,CAA6D,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,QAAA;AAClF,EAAA,OAAO,SAAA;AACT","file":"chunk-4NTMIU6V.js","sourcesContent":["/**\n * @sonordev/site-kit/engage - Design Renderer\n * \n * Renders design_json from Engage Studio as React components.\n * This is the runtime renderer that converts the visual builder's\n * JSON structure into actual React elements.\n */\n\n'use client'\n\nimport React, { createElement, CSSProperties, MouseEvent, useState } from 'react'\n\n// ============================================\n// Types\n// ============================================\n\nexport interface DesignNode {\n id: string\n type: string\n name: string\n children?: DesignNode[]\n props?: Record<string, any>\n style?: CSSProperties\n}\n\nexport interface DesignDocument {\n id: string\n type: string\n name: string\n children: DesignNode[]\n style?: CSSProperties\n props?: Record<string, any>\n}\n\nexport interface DesignRendererProps {\n design: DesignDocument\n onClose?: () => void\n onAction?: (action: ActionConfig, node: DesignNode) => void\n context?: EngageContext\n}\n\nexport interface ActionConfig {\n action: string\n url?: string\n newTab?: boolean\n target?: string\n text?: string\n productId?: string\n formId?: string\n}\n\nexport interface EngageContext {\n // Site-Kit context data that can be bound to elements\n user?: {\n name?: string\n email?: string\n isLoggedIn?: boolean\n }\n cart?: {\n itemCount?: number\n total?: number\n }\n page?: {\n url?: string\n title?: string\n }\n // Custom data from the page\n [key: string]: any\n}\n\n// ============================================\n// Action Handlers\n// ============================================\n\nfunction handleAction(\n action: ActionConfig,\n node: DesignNode,\n onClose?: () => void,\n onAction?: (action: ActionConfig, node: DesignNode) => void,\n): void {\n if (!action?.action || action.action === 'none') return\n\n // Let parent handle custom actions\n if (onAction) {\n onAction(action, node)\n }\n\n switch (action.action) {\n case 'link':\n if (action.url) {\n if (action.newTab) {\n window.open(action.url, '_blank', 'noopener,noreferrer')\n } else {\n window.location.href = action.url\n }\n }\n break\n\n case 'scroll':\n if (action.target) {\n const element = document.querySelector(action.target)\n element?.scrollIntoView({ behavior: 'smooth' })\n }\n break\n\n case 'close':\n onClose?.()\n break\n\n case 'copy':\n if (action.text) {\n navigator.clipboard.writeText(action.text).catch(console.error)\n }\n break\n\n case 'share':\n if (navigator.share) {\n navigator.share({\n title: document.title,\n url: window.location.href,\n }).catch(console.error)\n }\n break\n\n case 'download':\n if (action.url) {\n const a = document.createElement('a')\n a.href = action.url\n a.download = ''\n a.click()\n }\n break\n\n // Commerce actions - these should be handled by onAction callback\n case 'add_to_cart':\n case 'checkout':\n case 'book':\n case 'submit_form':\n case 'open_form':\n // Handled by parent via onAction\n break\n }\n}\n\n// ============================================\n// Animation Styles\n// ============================================\n\nconst animationKeyframes = `\n@keyframes engageFadeIn { from { opacity: 0; } to { opacity: 1; } }\n@keyframes engageFadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes engageFadeInDown { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes engageSlideInLeft { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes engageSlideInRight { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes engageSlideInUp { from { opacity: 0; transform: translateY(100%); } to { opacity: 1; transform: translateY(0); } }\n@keyframes engageScaleIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }\n@keyframes engageBounceIn { 0% { opacity: 0; transform: scale(0.3); } 50% { transform: scale(1.05); } 70% { transform: scale(0.9); } 100% { opacity: 1; transform: scale(1); } }\n`\n\nfunction getAnimationStyle(animation?: string, delay?: number, duration?: number): CSSProperties {\n if (!animation || animation === 'none') return {}\n \n const animationMap: Record<string, string> = {\n fadeIn: 'engageFadeIn',\n fadeInUp: 'engageFadeInUp',\n fadeInDown: 'engageFadeInDown',\n slideInLeft: 'engageSlideInLeft',\n slideInRight: 'engageSlideInRight',\n slideInUp: 'engageSlideInUp',\n scaleIn: 'engageScaleIn',\n bounceIn: 'engageBounceIn',\n }\n \n const animationName = animationMap[animation]\n if (!animationName) return {}\n \n return {\n animation: `${animationName} ${duration || 300}ms ease-out ${delay || 0}ms forwards`,\n opacity: 0, // Start invisible, animation will show it\n }\n}\n\n// ============================================\n// Node Renderer\n// ============================================\n\ninterface NodeRendererProps {\n node: DesignNode\n onClose?: () => void\n onAction?: (action: ActionConfig, node: DesignNode) => void\n context?: EngageContext\n}\n\nfunction NodeRenderer({ node, onClose, onAction, context }: NodeRendererProps): React.ReactElement | null {\n const [isHovered, setIsHovered] = useState(false)\n const { type, props = {}, style = {}, children } = node\n\n // Build styles with hover effects\n const computedStyle: CSSProperties = { ...style }\n \n // Apply animation\n if (props.animation) {\n Object.assign(computedStyle, getAnimationStyle(\n props.animation,\n props.animationDelay,\n props.animationDuration\n ))\n }\n \n // Apply hover effects\n if (isHovered) {\n if (props.hoverScale && props.hoverScale !== 'none') {\n computedStyle.transform = `scale(${props.hoverScale})`\n computedStyle.transition = 'transform 0.2s ease'\n }\n if (props.hoverShadow && props.hoverShadow !== 'none') {\n const shadowMap: Record<string, string> = {\n sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',\n md: '0 4px 6px -1px rgb(0 0 0 / 0.1)',\n lg: '0 10px 15px -3px rgb(0 0 0 / 0.1)',\n }\n computedStyle.boxShadow = shadowMap[props.hoverShadow]\n }\n }\n\n // Event handlers\n const eventHandlers: Record<string, (e: MouseEvent) => void> = {\n onMouseEnter: () => setIsHovered(true),\n onMouseLeave: () => setIsHovered(false),\n }\n \n // Click handler\n if (props.onClick) {\n eventHandlers.onClick = (e: MouseEvent) => {\n e.preventDefault()\n handleAction(props.onClick, node, onClose, onAction)\n }\n computedStyle.cursor = 'pointer'\n }\n\n // Render children recursively\n const renderedChildren = children?.map((child) => (\n <NodeRenderer\n key={child.id}\n node={child}\n onClose={onClose}\n onAction={onAction}\n context={context}\n />\n ))\n\n // Render based on type\n switch (type) {\n case 'Container':\n case 'Box':\n case 'Section':\n return (\n <div style={computedStyle} {...eventHandlers}>\n {renderedChildren}\n </div>\n )\n\n case 'Text':\n return (\n <p style={computedStyle} {...eventHandlers}>\n {resolveText(props.text, context)}\n </p>\n )\n\n case 'Heading':\n const HeadingTag = `h${props.level || 2}` as keyof React.JSX.IntrinsicElements\n return createElement(\n HeadingTag,\n { style: computedStyle, ...eventHandlers },\n resolveText(props.text, context)\n )\n\n case 'Button':\n case 'BookingButton':\n case 'BuyNow':\n case 'AddToCart':\n case 'EventRSVP':\n return (\n <button\n style={computedStyle}\n {...eventHandlers}\n type=\"button\"\n >\n {resolveText(props.text || props.label, context) || 'Button'}\n </button>\n )\n\n case 'Image':\n return (\n <img\n src={props.src}\n alt={props.alt || ''}\n style={computedStyle}\n {...eventHandlers}\n />\n )\n\n case 'Link':\n return (\n <a\n href={props.href || '#'}\n target={props.newTab ? '_blank' : undefined}\n rel={props.newTab ? 'noopener noreferrer' : undefined}\n style={computedStyle}\n {...eventHandlers}\n >\n {resolveText(props.text, context) || renderedChildren}\n </a>\n )\n\n case 'Input':\n return (\n <input\n type={props.inputType || 'text'}\n placeholder={props.placeholder}\n style={computedStyle}\n {...eventHandlers}\n />\n )\n\n case 'Divider':\n return <hr style={{ border: 'none', borderTop: '1px solid var(--sk-border, #e5e7eb)', ...computedStyle }} />\n\n case 'Spacer':\n return <div style={{ ...computedStyle, width: props.width, height: props.height }} />\n\n case 'Icon':\n // Simple emoji/text icon rendering\n return (\n <span style={computedStyle} {...eventHandlers}>\n {props.icon || '★'}\n </span>\n )\n\n case 'FormEmbed':\n // For form embeds, we need to render the form from Forms module\n // This would integrate with the ManagedForm component\n return (\n <div \n style={computedStyle} \n data-engage-form={props.form_id}\n {...eventHandlers}\n >\n {/* ManagedForm would be rendered here by the parent */}\n <div style={{ padding: '16px', background: 'var(--sk-bg-elevated, #f5f5f5)', borderRadius: '8px', textAlign: 'center' }}>\n Form: {props.form_id || 'Not configured'}\n </div>\n </div>\n )\n\n case 'ProductCard':\n case 'EventCard':\n // Product/event cards need data binding from Commerce\n return (\n <div \n style={computedStyle} \n data-engage-offering={props.offering_id}\n {...eventHandlers}\n >\n {renderedChildren}\n </div>\n )\n\n default:\n // Unknown type - render as div with children\n console.warn(`[DesignRenderer] Unknown node type: ${type}`)\n return (\n <div style={computedStyle} {...eventHandlers}>\n {renderedChildren}\n </div>\n )\n }\n}\n\n// ============================================\n// Text Resolution (Data Bindings)\n// ============================================\n\nfunction resolveText(text: string | undefined, context?: EngageContext): string {\n if (!text) return ''\n if (!context) return text\n \n // Replace {{variable}} patterns with context values\n return text.replace(/\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g, (match, path) => {\n const value = getNestedValue(context, path)\n return value !== undefined ? String(value) : match\n })\n}\n\nfunction getNestedValue(obj: Record<string, any>, path: string): any {\n return path.split('.').reduce((acc, key) => acc?.[key], obj)\n}\n\n// ============================================\n// Main Component\n// ============================================\n\nexport function DesignRenderer({\n design,\n onClose,\n onAction,\n context,\n}: DesignRendererProps): React.ReactElement {\n // Inject animation keyframes\n React.useEffect(() => {\n if (typeof document === 'undefined') return\n \n const styleId = 'engage-design-renderer-animations'\n if (!document.getElementById(styleId)) {\n const styleSheet = document.createElement('style')\n styleSheet.id = styleId\n styleSheet.textContent = animationKeyframes\n document.head.appendChild(styleSheet)\n }\n }, [])\n\n // Render the root container\n const rootStyle: CSSProperties = {\n ...design.style,\n }\n\n return (\n <div style={rootStyle} data-engage-design={design.id}>\n {design.children?.map((node) => (\n <NodeRenderer\n key={node.id}\n node={node}\n onClose={onClose}\n onAction={onAction}\n context={context}\n />\n ))}\n </div>\n )\n}\n\nexport default DesignRenderer\n","/**\n * @sonordev/site-kit/engage - Engage Widget\n * \n * Loads and renders engagement widgets (popups, nudges, bars, chat) via Portal API\n * Supports both legacy config-based rendering and new design_json from Engage Studio\n */\n\n'use client'\n\nimport React, { useEffect, useRef, useState, useCallback } from 'react'\nimport ReactDOM from 'react-dom'\nimport dynamic from 'next/dynamic'\nimport { usePathname } from 'next/navigation'\nimport type { EngageElement } from './types'\nimport { getOrCreateVisitorId } from '../shared/identity'\nimport { sonorFetch } from '../shared/sonorFetch'\nimport { DesignRenderer, type ActionConfig, type DesignDocument } from './DesignRenderer'\n\n// ChatWidget pulls react-markdown (and lazily socket.io) — keep it out of the\n// engage chunk entirely and only download it when the idle-gated `chatReady`\n// flips and the widget actually renders.\nconst LazyChatWidget = dynamic(\n () => import('./ChatWidget').then(m => ({ default: m.ChatWidget })),\n { ssr: false },\n)\n\ninterface EngageWidgetProps {\n apiUrl?: string\n apiKey?: string\n projectId?: string\n position?: 'bottom-right' | 'bottom-left'\n zIndex?: number\n chatEnabled?: boolean\n debug?: boolean\n}\n\nfunction getApiConfig() {\n const isDev = typeof process !== 'undefined' && process.env?.NODE_ENV === 'development'\n const defaultApiUrl = isDev && process.env?.SONOR_API_URL\n ? process.env.SONOR_API_URL\n : 'https://api.sonor.io'\n const apiUrl = typeof window !== 'undefined'\n ? (window as any).__SITE_KIT_API_URL__ || defaultApiUrl\n : defaultApiUrl\n const apiKey = typeof window !== 'undefined' ? (window as any).__SITE_KIT_API_KEY__ : undefined\n return { apiUrl, apiKey }\n}\n\nexport function EngageWidget({\n apiUrl: propApiUrl,\n apiKey: propApiKey,\n projectId: propProjectId,\n position = 'bottom-right',\n zIndex = 9999,\n chatEnabled = true,\n debug = false,\n}: EngageWidgetProps) {\n const pathname = usePathname()\n const [elements, setElements] = useState<EngageElement[]>([])\n const [activeElements, setActiveElements] = useState<string[]>([])\n const [dismissedElements, setDismissedElements] = useState<Set<string>>(new Set())\n const [chatReady, setChatReady] = useState(false)\n \n // Load elements from API (GET /engage/widget/elements)\n useEffect(() => {\n async function loadElements() {\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n const apiUrl = propApiUrl || globalApiUrl\n const apiKey = propApiKey || globalApiKey\n \n if (!apiKey) {\n if (debug) console.warn('[Engage] No API key configured')\n return\n }\n \n // Shared identity (_sk_vid) — same visitor ID as Analytics & Signal\n const visitorId = getOrCreateVisitorId()\n const url = typeof window !== 'undefined' ? window.location.href : ''\n \n try {\n const response = await sonorFetch(\n `${apiUrl.replace(/\\/$/, '')}/engage/widget/elements?url=${encodeURIComponent(url)}&visitorId=${encodeURIComponent(visitorId)}`,\n {},\n { apiKey },\n )\n \n if (!response.ok) {\n if (debug) console.error('[Engage] Error loading elements:', response.statusText)\n return\n }\n \n const json = await response.json()\n const elementsList = json.data?.elements ?? json.elements ?? []\n if (debug) console.log('[Engage] Loaded elements:', elementsList)\n setElements(elementsList)\n } catch (error) {\n if (debug) console.error('[Engage] Error loading elements:', error)\n }\n }\n \n loadElements()\n }, [propApiUrl, propApiKey, debug])\n\n // Defer ChatWidget until the browser is idle (reduces main-thread blocking)\n useEffect(() => {\n if (!chatEnabled) return\n const id =\n typeof requestIdleCallback !== 'undefined'\n ? requestIdleCallback(() => setChatReady(true), { timeout: 3000 })\n : setTimeout(() => setChatReady(true), 1)\n return () => {\n typeof cancelIdleCallback !== 'undefined' ? cancelIdleCallback(id as number) : clearTimeout(id)\n }\n }, [chatEnabled])\n \n // Check targeting and trigger for each element\n useEffect(() => {\n if (!elements.length) return\n \n const checkElement = (element: EngageElement): boolean => {\n // Check if dismissed\n if (dismissedElements.has(element.id)) return false\n \n // Check page targeting\n if (element.targeting?.pages) {\n const { include, exclude } = element.targeting.pages\n \n if (exclude?.some(p => matchPath(pathname, p))) return false\n if (include && !include.some(p => matchPath(pathname, p))) return false\n }\n \n // Check device targeting\n if (element.targeting?.devices) {\n const device = getDeviceType()\n if (!element.targeting.devices.includes(device)) return false\n }\n \n // Check frequency capping\n if (element.trigger?.frequency) {\n const { type, days } = element.trigger.frequency\n const key = `_engage_${element.id}`\n \n if (type === 'once') {\n if (localStorage.getItem(key)) return false\n } else if (type === 'once-per-session') {\n if (sessionStorage.getItem(key)) return false\n } else if (type === 'every-n-days' && days) {\n const lastShown = localStorage.getItem(key)\n if (lastShown) {\n const elapsed = Date.now() - parseInt(lastShown, 10)\n if (elapsed < days * 24 * 60 * 60 * 1000) return false\n }\n }\n }\n \n return true\n }\n \n // Filter elements that pass targeting\n const eligible = elements.filter(checkElement)\n\n if (debug) console.log('[Engage] Eligible elements:', eligible)\n\n // Dedupe on add: this effect re-runs when dismissedElements changes, so a\n // still-eligible immediate element would otherwise be pushed again\n // (duplicate ids → duplicate keys → double render).\n const activate = (id: string) => {\n setActiveElements(prev => (prev.includes(id) ? prev : [...prev, id]))\n }\n\n // Every timer/listener registered here is torn down on cleanup — the old\n // version leaked delay timeouts and exit-intent/scroll listeners on each\n // effect re-run and on unmount.\n const cleanups: Array<() => void> = []\n\n eligible.forEach(element => {\n const trigger = element.trigger\n\n if (trigger?.type === 'immediate' || !trigger?.type) {\n activate(element.id)\n } else if (trigger?.type === 'delay' && trigger.delay) {\n const timer = setTimeout(() => activate(element.id), trigger.delay * 1000)\n cleanups.push(() => clearTimeout(timer))\n } else if (trigger?.type === 'exit-intent') {\n const handleMouseLeave = (e: MouseEvent) => {\n if (e.clientY < 10) {\n activate(element.id)\n document.removeEventListener('mouseleave', handleMouseLeave)\n }\n }\n document.addEventListener('mouseleave', handleMouseLeave)\n cleanups.push(() => document.removeEventListener('mouseleave', handleMouseLeave))\n } else if (trigger?.type === 'scroll' && trigger.scrollPercentage) {\n const handleScroll = () => {\n const scrollPercent = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100\n if (scrollPercent >= (trigger.scrollPercentage || 50)) {\n activate(element.id)\n window.removeEventListener('scroll', handleScroll)\n }\n }\n window.addEventListener('scroll', handleScroll, { passive: true })\n cleanups.push(() => window.removeEventListener('scroll', handleScroll))\n }\n })\n\n return () => {\n cleanups.forEach(fn => fn())\n }\n }, [elements, pathname, dismissedElements, debug])\n \n const handleDismiss = useCallback((elementId: string) => {\n setDismissedElements(prev => new Set([...prev, elementId]))\n setActiveElements(prev => prev.filter(id => id !== elementId))\n \n // Record dismissal in storage\n const element = elements.find(e => e.id === elementId)\n if (element?.trigger?.frequency) {\n const key = `_engage_${elementId}`\n if (element.trigger.frequency.type === 'once-per-session') {\n sessionStorage.setItem(key, 'true')\n } else {\n localStorage.setItem(key, Date.now().toString())\n }\n }\n }, [elements])\n \n // Render active elements + chat widget\n // Use portal to document.body so widgets always land inside <body>,\n // even when SiteKitLayout wraps <body> (common in root layouts)\n if (typeof document === 'undefined') return null\n\n return ReactDOM.createPortal(\n <>\n {activeElements.map(elementId => {\n const element = elements.find(e => e.id === elementId)\n if (!element) return null\n\n const { apiUrl: globalApiUrl, apiKey: globalApiKey } = getApiConfig()\n return (\n <EngageElementRenderer\n key={element.id}\n element={element}\n onDismiss={() => handleDismiss(element.id)}\n zIndex={zIndex}\n apiUrl={propApiUrl || globalApiUrl}\n apiKey={propApiKey || globalApiKey}\n />\n )\n })}\n\n {/* Chat Widget - deferred until idle; chunk downloads on first render */}\n {chatEnabled && chatReady && (\n <LazyChatWidget\n projectId={propProjectId ?? undefined}\n config={{\n position,\n buttonColor: '#2563eb', // Default blue-600 (AA on white), overridden by --sk-primary CSS var or API brand_primary\n }}\n />\n )}\n </>,\n document.body,\n )\n}\n\n// ============================================\n// Action Handler + Tracking\n// ============================================\n\nfunction trackEngageEvent(\n apiUrl: string,\n apiKey: string | undefined,\n endpoint: 'impression' | 'click',\n data: Record<string, unknown>\n) {\n if (!apiKey) return\n const visitorId = typeof localStorage !== 'undefined'\n ? localStorage.getItem('_sk_vid')\n : null\n sonorFetch(`${apiUrl.replace(/\\/$/, '')}/engage/widget/${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ ...data, visitorId, pageUrl: window.location.href }),\n keepalive: true,\n }, { apiKey, retries: 0 }).catch(() => {})\n}\n\nfunction handleEngageAction(\n action: ActionConfig,\n _node: unknown,\n element: EngageElement,\n apiUrl: string,\n apiKey: string | undefined\n) {\n // Track click\n trackEngageEvent(apiUrl, apiKey, 'click', {\n elementId: element.id,\n action: action.action,\n })\n\n switch (action.action) {\n case 'navigate':\n if (action.url) window.location.href = action.url\n break\n case 'open-url':\n if (action.url) window.open(action.url, '_blank')\n break\n case 'submit-form':\n case 'submit_form':\n window.dispatchEvent(new CustomEvent('engage:submit-form', {\n detail: { formId: action.formId || action.url, elementId: element.id },\n }))\n break\n case 'track-conversion':\n window.dispatchEvent(new CustomEvent('engage:conversion', {\n detail: { action, elementId: element.id },\n }))\n break\n default:\n window.dispatchEvent(new CustomEvent('engage:action', {\n detail: { action, elementId: element.id },\n }))\n break\n }\n}\n\n// Helper components\nfunction EngageElementRenderer({\n element,\n onDismiss,\n zIndex,\n apiUrl,\n apiKey,\n}: {\n element: EngageElement\n onDismiss: () => void\n zIndex: number\n apiUrl: string\n apiKey: string | undefined\n}) {\n // Impression tracking via IntersectionObserver\n const containerRef = useRef<HTMLDivElement>(null)\n const impressionTrackedRef = useRef(false)\n\n useEffect(() => {\n const el = containerRef.current\n if (!el || impressionTrackedRef.current) return\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting && !impressionTrackedRef.current) {\n impressionTrackedRef.current = true\n trackEngageEvent(apiUrl, apiKey, 'impression', { elementId: element.id })\n observer.disconnect()\n }\n },\n { threshold: 0.5 }\n )\n observer.observe(el)\n return () => observer.disconnect()\n }, [apiUrl, apiKey, element.id])\n\n const onAction = useCallback(\n (action: ActionConfig, node: unknown) => {\n handleEngageAction(action, node, element, apiUrl, apiKey)\n },\n [element, apiUrl, apiKey]\n )\n\n // If element has design_json from Engage Studio, use DesignRenderer\n if (element.design_json) {\n // Wrap in appropriate container based on element type\n if (element.type === 'popup') {\n return (\n <div\n ref={containerRef}\n data-engage-element={element.id}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0,0,0,0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex,\n }}\n onClick={onDismiss}\n >\n <div onClick={e => e.stopPropagation()}>\n <DesignRenderer\n design={element.design_json}\n onClose={onDismiss}\n onAction={onAction}\n />\n </div>\n </div>\n )\n }\n\n if (element.type === 'bar') {\n return (\n <div\n ref={containerRef}\n data-engage-element={element.id}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n zIndex,\n }}\n >\n <DesignRenderer\n design={element.design_json}\n onClose={onDismiss}\n onAction={onAction}\n />\n </div>\n )\n }\n\n if (element.type === 'nudge' || element.type === 'slide-in') {\n const position = element.config?.position || 'bottom-right'\n const positionStyles: Record<string, React.CSSProperties> = {\n 'bottom-right': { bottom: 20, right: 20 },\n 'bottom-left': { bottom: 20, left: 20 },\n 'top-right': { top: 20, right: 20 },\n 'top-left': { top: 20, left: 20 },\n }\n\n return (\n <div\n ref={containerRef}\n data-engage-element={element.id}\n style={{\n position: 'fixed',\n zIndex,\n ...positionStyles[position],\n }}\n >\n <DesignRenderer\n design={element.design_json}\n onClose={onDismiss}\n onAction={onAction}\n />\n </div>\n )\n }\n\n // Default: render design_json directly\n return (\n <div ref={containerRef} data-engage-element={element.id}>\n <DesignRenderer\n design={element.design_json}\n onClose={onDismiss}\n onAction={onAction}\n />\n </div>\n )\n }\n\n // Legacy: Simple popup rendering for elements without design_json\n if (element.type === 'popup') {\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0,0,0,0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex,\n }}\n onClick={onDismiss}\n >\n <div\n style={{\n backgroundColor: 'var(--sk-bg, #ffffff)',\n padding: 24,\n borderRadius: 8,\n maxWidth: 500,\n width: '90%',\n }}\n onClick={e => e.stopPropagation()}\n >\n <button\n onClick={onDismiss}\n style={{\n position: 'absolute',\n top: 8,\n right: 8,\n background: 'none',\n border: 'none',\n fontSize: 24,\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n {element.config?.title && <h2>{element.config.title}</h2>}\n {element.config?.message && <p>{element.config.message}</p>}\n </div>\n </div>\n )\n }\n \n // Bar/banner rendering\n if (element.type === 'bar') {\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n backgroundColor: element.config?.backgroundColor || 'var(--sk-primary, #2563eb)',\n color: element.config?.textColor || 'var(--sk-bg, #ffffff)',\n padding: '12px 24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 16,\n zIndex,\n }}\n >\n <span>{element.config?.message}</span>\n <button\n onClick={onDismiss}\n style={{\n background: 'none',\n border: 'none',\n color: 'inherit',\n fontSize: 20,\n cursor: 'pointer',\n }}\n >\n ×\n </button>\n </div>\n )\n }\n \n return null\n}\n\n// Utilities\nfunction matchPath(pathname: string, pattern: string): boolean {\n if (pattern.endsWith('*')) {\n return pathname.startsWith(pattern.slice(0, -1))\n }\n return pathname === pattern\n}\n\nfunction getDeviceType(): 'desktop' | 'mobile' | 'tablet' {\n if (typeof window === 'undefined') return 'desktop'\n const ua = navigator.userAgent\n if (/tablet|ipad|playbook|silk/i.test(ua)) return 'tablet'\n if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return 'mobile'\n return 'desktop'\n}\n"]}
|
|
@@ -5,7 +5,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
5
5
|
|
|
6
6
|
// src/signal/SignalBridge.tsx
|
|
7
7
|
var LazySignalCore = dynamic(
|
|
8
|
-
() => import('./SignalCore-
|
|
8
|
+
() => import('./SignalCore-4B4RNYLV.mjs').then((m) => ({ default: m.SignalCore })),
|
|
9
9
|
{ ssr: false }
|
|
10
10
|
);
|
|
11
11
|
var SignalContext = createContext(null);
|
|
@@ -116,5 +116,5 @@ function useSignalExperiment(experimentId) {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
export { SignalBridge, useSignal, useSignalConfig, useSignalEvent, useSignalExperiment, useSignalOutcome };
|
|
119
|
-
//# sourceMappingURL=chunk-
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
119
|
+
//# sourceMappingURL=chunk-57QV6NIY.mjs.map
|
|
120
|
+
//# sourceMappingURL=chunk-57QV6NIY.mjs.map
|