@jmp-technologies/analytics 0.1.18 → 0.1.19
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/dist/{chunk-W7CQ5VG2.js → chunk-EPNF76VK.js} +2 -2
- package/dist/{chunk-SOHYQ5GT.js → chunk-GB37RVJJ.js} +61 -32
- package/dist/chunk-GB37RVJJ.js.map +1 -0
- package/dist/index.cjs +63 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -24
- package/dist/index.d.ts +45 -24
- package/dist/index.js +7 -3
- package/dist/next/content.cjs +322 -0
- package/dist/next/content.cjs.map +1 -0
- package/dist/next/content.d.cts +37 -0
- package/dist/next/content.d.ts +37 -0
- package/dist/next/content.js +172 -0
- package/dist/next/content.js.map +1 -0
- package/dist/next/instrumentation.cjs +131 -0
- package/dist/next/instrumentation.cjs.map +1 -0
- package/dist/next/instrumentation.d.cts +7 -0
- package/dist/next/instrumentation.d.ts +7 -0
- package/dist/next/instrumentation.js +18 -0
- package/dist/next/instrumentation.js.map +1 -0
- package/dist/next/middleware.cjs +147 -0
- package/dist/next/middleware.cjs.map +1 -0
- package/dist/next/middleware.d.cts +13 -0
- package/dist/next/middleware.d.ts +13 -0
- package/dist/next/middleware.js +22 -0
- package/dist/next/middleware.js.map +1 -0
- package/dist/next.cjs +31 -6
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +11 -2
- package/dist/next.d.ts +11 -2
- package/dist/next.js +17 -3
- package/dist/next.js.map +1 -1
- package/dist/react.cjs +20 -6
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +2 -2
- package/package.json +17 -2
- package/dist/chunk-SOHYQ5GT.js.map +0 -1
- /package/dist/{chunk-W7CQ5VG2.js.map → chunk-EPNF76VK.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getOrCreateJmpAnalyticsFromBrowserEnv
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GB37RVJJ.js";
|
|
4
4
|
|
|
5
5
|
// src/react.tsx
|
|
6
6
|
import { useMemo } from "react";
|
|
@@ -52,4 +52,4 @@ export {
|
|
|
52
52
|
JmpTrackedTelLink,
|
|
53
53
|
JmpTrackedMailtoLink
|
|
54
54
|
};
|
|
55
|
-
//# sourceMappingURL=chunk-
|
|
55
|
+
//# sourceMappingURL=chunk-EPNF76VK.js.map
|
|
@@ -259,8 +259,40 @@ function classifyContactHref(href) {
|
|
|
259
259
|
return null;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
// src/site-config.ts
|
|
263
|
+
var registeredSite = null;
|
|
264
|
+
function readNextPublicEnv(key) {
|
|
265
|
+
if (typeof process === "undefined" || !process.env) return void 0;
|
|
266
|
+
const v = key === "NEXT_PUBLIC_JMP_ANALYTICS_URL" ? process.env.NEXT_PUBLIC_JMP_ANALYTICS_URL : process.env.NEXT_PUBLIC_JMP_TRACKING_KEY;
|
|
267
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
268
|
+
}
|
|
269
|
+
function getServerConfigFromEnv() {
|
|
270
|
+
const baseUrl = readNextPublicEnv("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
271
|
+
const trackingKey = readNextPublicEnv("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
272
|
+
if (!baseUrl || !trackingKey) return null;
|
|
273
|
+
return { baseUrl, trackingKey };
|
|
274
|
+
}
|
|
275
|
+
function defineJmpSite(definition) {
|
|
276
|
+
registeredSite = definition;
|
|
277
|
+
return definition;
|
|
278
|
+
}
|
|
279
|
+
function getJmpSiteDefinition() {
|
|
280
|
+
return registeredSite;
|
|
281
|
+
}
|
|
282
|
+
function getJmpContentConfig() {
|
|
283
|
+
const fromEnv = getServerConfigFromEnv();
|
|
284
|
+
if (!fromEnv) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
const site = getJmpSiteDefinition();
|
|
288
|
+
return {
|
|
289
|
+
...fromEnv,
|
|
290
|
+
contentWrappers: site?.contentWrappers ?? fromEnv.contentWrappers
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
262
294
|
// src/index.ts
|
|
263
|
-
var JMP_ANALYTICS_SDK_VERSION = "0.1.
|
|
295
|
+
var JMP_ANALYTICS_SDK_VERSION = "0.1.19";
|
|
264
296
|
var JMP_TRACKING_CONSENT_STORAGE_KEY = "jmp_analytics_consent_v1";
|
|
265
297
|
var moduleTrackingConsentGranted = true;
|
|
266
298
|
var trackingConsentListeners = /* @__PURE__ */ new Set();
|
|
@@ -840,11 +872,6 @@ function resolveContentWrappersFromConfig(config) {
|
|
|
840
872
|
if (config.contentWrappers?.length) {
|
|
841
873
|
return [...config.contentWrappers];
|
|
842
874
|
}
|
|
843
|
-
if (config.trustSlots?.length) {
|
|
844
|
-
return config.trustSlots.map(
|
|
845
|
-
(slot) => `trust.${slot}`
|
|
846
|
-
);
|
|
847
|
-
}
|
|
848
875
|
return [];
|
|
849
876
|
}
|
|
850
877
|
async function registerJmpContentWrappers(config) {
|
|
@@ -894,18 +921,6 @@ async function registerJmpContentWrappers(config) {
|
|
|
894
921
|
const data = JSON.parse(text);
|
|
895
922
|
return { ok: true, wrappers: data.wrappers ?? wrappers };
|
|
896
923
|
}
|
|
897
|
-
async function registerJmpTrustCapabilities(config) {
|
|
898
|
-
const result = await registerJmpContentWrappers(config);
|
|
899
|
-
if (!result.ok) {
|
|
900
|
-
return result;
|
|
901
|
-
}
|
|
902
|
-
const slots = result.wrappers.filter((w) => w === "trust" || w.startsWith("trust.")).map((w) => w === "trust" ? "summary" : w.slice("trust.".length)).filter(
|
|
903
|
-
(s) => ["summary", "testimonials", "reviews", "stats", "logos", "credentials"].includes(
|
|
904
|
-
s
|
|
905
|
-
)
|
|
906
|
-
);
|
|
907
|
-
return { ok: true, slots };
|
|
908
|
-
}
|
|
909
924
|
function createJmpContentClient(config) {
|
|
910
925
|
return {
|
|
911
926
|
getBlogPosts: () => getJmpBlogPosts(config),
|
|
@@ -914,9 +929,7 @@ function createJmpContentClient(config) {
|
|
|
914
929
|
getTrustBundle: () => getJmpTrustBundle(config),
|
|
915
930
|
getSiteProfile: () => getJmpSiteProfile(config),
|
|
916
931
|
getRobotsTxt: () => getJmpRobotsTxt(config),
|
|
917
|
-
registerContentWrappers: () => registerJmpContentWrappers(config)
|
|
918
|
-
/** @deprecated Use registerContentWrappers */
|
|
919
|
-
registerTrustCapabilities: () => registerJmpTrustCapabilities(config)
|
|
932
|
+
registerContentWrappers: () => registerJmpContentWrappers(config)
|
|
920
933
|
};
|
|
921
934
|
}
|
|
922
935
|
async function getContent(config, path) {
|
|
@@ -965,17 +978,31 @@ async function getContentText(config, path) {
|
|
|
965
978
|
return text;
|
|
966
979
|
}
|
|
967
980
|
var DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS = 800;
|
|
968
|
-
function
|
|
981
|
+
function readNextPublicEnv2(key) {
|
|
969
982
|
if (typeof process === "undefined" || !process.env) return void 0;
|
|
970
|
-
|
|
983
|
+
let v;
|
|
984
|
+
switch (key) {
|
|
985
|
+
case "NEXT_PUBLIC_JMP_ANALYTICS_URL":
|
|
986
|
+
v = process.env.NEXT_PUBLIC_JMP_ANALYTICS_URL;
|
|
987
|
+
break;
|
|
988
|
+
case "NEXT_PUBLIC_JMP_TRACKING_KEY":
|
|
989
|
+
v = process.env.NEXT_PUBLIC_JMP_TRACKING_KEY;
|
|
990
|
+
break;
|
|
991
|
+
case "NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT":
|
|
992
|
+
v = process.env.NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT;
|
|
993
|
+
break;
|
|
994
|
+
case "NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS":
|
|
995
|
+
v = process.env.NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS;
|
|
996
|
+
break;
|
|
997
|
+
}
|
|
971
998
|
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
972
999
|
}
|
|
973
1000
|
function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
|
|
974
|
-
const baseUrl =
|
|
975
|
-
const trackingKey =
|
|
1001
|
+
const baseUrl = readNextPublicEnv2("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
1002
|
+
const trackingKey = readNextPublicEnv2("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
976
1003
|
if (!baseUrl || !trackingKey) return null;
|
|
977
|
-
const requireConsentFromEnv =
|
|
978
|
-
const autoTrackContactLinksFromEnv =
|
|
1004
|
+
const requireConsentFromEnv = readNextPublicEnv2("NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT") === "true";
|
|
1005
|
+
const autoTrackContactLinksFromEnv = readNextPublicEnv2("NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS") === "true";
|
|
979
1006
|
return {
|
|
980
1007
|
baseUrl,
|
|
981
1008
|
trackingKey,
|
|
@@ -986,14 +1013,14 @@ function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
|
|
|
986
1013
|
};
|
|
987
1014
|
}
|
|
988
1015
|
function getJmpServerContentConfigFromEnv(overrides) {
|
|
989
|
-
const baseUrl =
|
|
990
|
-
const trackingKey =
|
|
1016
|
+
const baseUrl = readNextPublicEnv2("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
1017
|
+
const trackingKey = readNextPublicEnv2("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
991
1018
|
if (!baseUrl || !trackingKey) return null;
|
|
992
1019
|
return { baseUrl, trackingKey, ...overrides };
|
|
993
1020
|
}
|
|
994
1021
|
function isJmpBrowserAnalyticsEnvConfigured() {
|
|
995
1022
|
return Boolean(
|
|
996
|
-
|
|
1023
|
+
readNextPublicEnv2("NEXT_PUBLIC_JMP_ANALYTICS_URL") && readNextPublicEnv2("NEXT_PUBLIC_JMP_TRACKING_KEY")
|
|
997
1024
|
);
|
|
998
1025
|
}
|
|
999
1026
|
function isJmpServerContentEnvConfigured() {
|
|
@@ -1018,6 +1045,9 @@ export {
|
|
|
1018
1045
|
buildLandingCaptureInlineScript,
|
|
1019
1046
|
BOOKING_LINK_HOSTS,
|
|
1020
1047
|
classifyContactHref,
|
|
1048
|
+
defineJmpSite,
|
|
1049
|
+
getJmpSiteDefinition,
|
|
1050
|
+
getJmpContentConfig,
|
|
1021
1051
|
JMP_ANALYTICS_SDK_VERSION,
|
|
1022
1052
|
JMP_TRACKING_CONSENT_STORAGE_KEY,
|
|
1023
1053
|
isJmpTrackingConsentGranted,
|
|
@@ -1032,7 +1062,6 @@ export {
|
|
|
1032
1062
|
getJmpSiteProfile,
|
|
1033
1063
|
getJmpRobotsTxt,
|
|
1034
1064
|
registerJmpContentWrappers,
|
|
1035
|
-
registerJmpTrustCapabilities,
|
|
1036
1065
|
createJmpContentClient,
|
|
1037
1066
|
DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
|
|
1038
1067
|
getJmpBrowserAnalyticsConfigFromEnv,
|
|
@@ -1042,4 +1071,4 @@ export {
|
|
|
1042
1071
|
getOrCreateJmpAnalyticsFromBrowserEnv,
|
|
1043
1072
|
createJmpContentClientFromServerEnv
|
|
1044
1073
|
};
|
|
1045
|
-
//# sourceMappingURL=chunk-
|
|
1074
|
+
//# sourceMappingURL=chunk-GB37RVJJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/landing-capture.ts","../src/contact-link-classifier.ts","../src/site-config.ts","../src/index.ts"],"sourcesContent":["/** First-party landing attribution captured before React / useEffect (sessionStorage). */\n\nexport const JMP_SESSION_ID_KEY = \"jmp_analytics_sid\"\nexport const JMP_LANDING_REFERER_KEY = \"jmp_analytics_landing_referer\"\n/** Cross-subdomain landing referrer (www ↔ apex share sessionStorage origins). */\nexport const JMP_LANDING_REFERER_COOKIE = \"jmp_lr\"\nexport const JMP_UTM_SESSION_KEY = \"jmp_analytics_utm\"\n\nconst LANDING_REFERER_COOKIE_MAX_AGE_SEC = 30 * 60\n\nexport const JMP_UTM_PARAM_KEYS = [\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n \"utm_content\",\n \"utm_term\",\n] as const\n\nfunction refererHostFromUrl(referer: string): string | null {\n const trimmed = referer.trim()\n try {\n return new URL(trimmed).hostname.replace(/^www\\./i, \"\").toLowerCase()\n } catch {\n try {\n return new URL(`https://${trimmed}`).hostname\n .replace(/^www\\./i, \"\")\n .toLowerCase()\n } catch {\n return null\n }\n }\n}\n\nexport function isExternalReferrerUrl(\n referer: string,\n siteHostname: string\n): boolean {\n const refHost = refererHostFromUrl(referer)\n if (!refHost) {\n return false\n }\n const site = siteHostname.replace(/^www\\./i, \"\").toLowerCase()\n return refHost !== site && !refHost.endsWith(`.${site}`)\n}\n\n/** Apex hostname used for `Domain=.example.com` cookies (www + apex). */\nexport function registrableSiteDomain(siteHostname: string): string | null {\n const site = siteHostname.replace(/^www\\./i, \"\").toLowerCase()\n if (!site || site === \"localhost\" || site.endsWith(\".local\")) {\n return null\n }\n if (!site.includes(\".\")) {\n return null\n }\n return site\n}\n\nexport function readLandingRefererCookie(siteHostname: string): string | null {\n if (typeof document === \"undefined\") {\n return null\n }\n\n const apex = registrableSiteDomain(siteHostname)\n if (!apex) {\n return null\n }\n\n const prefix = `${JMP_LANDING_REFERER_COOKIE}=`\n for (const part of document.cookie.split(\";\")) {\n const trimmed = part.trim()\n if (!trimmed.startsWith(prefix)) {\n continue\n }\n try {\n const value = decodeURIComponent(trimmed.slice(prefix.length)).trim()\n return value.length > 0 ? value : null\n } catch {\n return null\n }\n }\n\n return null\n}\n\nexport function writeLandingRefererCookie(\n referer: string,\n siteHostname: string\n): void {\n if (typeof document === \"undefined\") {\n return\n }\n\n const apex = registrableSiteDomain(siteHostname)\n if (!apex) {\n return\n }\n\n const value = encodeURIComponent(referer.trim().slice(0, 2048))\n const secure =\n typeof window !== \"undefined\" && window.location.protocol === \"https:\"\n ? \"; Secure\"\n : \"\"\n\n document.cookie = `${JMP_LANDING_REFERER_COOKIE}=${value}; Domain=.${apex}; Path=/; Max-Age=${LANDING_REFERER_COOKIE_MAX_AGE_SEC}; SameSite=Lax${secure}`\n}\n\nexport function captureLandingAttribution(siteHostname: string): {\n landingReferer: string | null\n utm: Record<string, string>\n} {\n if (typeof document === \"undefined\" || typeof window === \"undefined\") {\n return { landingReferer: null, utm: {} }\n }\n\n let landingReferer: string | null = null\n let utm: Record<string, string> = {}\n\n try {\n const storedReferer =\n sessionStorage.getItem(JMP_LANDING_REFERER_KEY)?.trim() || null\n const cookieReferer = readLandingRefererCookie(siteHostname)\n const preservedReferer = storedReferer || cookieReferer\n const currentReferer = document.referrer?.trim() || null\n\n if (\n currentReferer &&\n isExternalReferrerUrl(currentReferer, siteHostname)\n ) {\n sessionStorage.setItem(JMP_LANDING_REFERER_KEY, currentReferer)\n writeLandingRefererCookie(currentReferer, siteHostname)\n landingReferer = currentReferer\n } else if (preservedReferer) {\n landingReferer = preservedReferer\n if (!storedReferer) {\n sessionStorage.setItem(JMP_LANDING_REFERER_KEY, preservedReferer)\n }\n }\n\n const params = new URLSearchParams(window.location.search)\n const rawUtm = sessionStorage.getItem(JMP_UTM_SESSION_KEY)\n if (rawUtm) {\n const parsed = JSON.parse(rawUtm) as unknown\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n utm = parsed as Record<string, string>\n }\n }\n\n let updated = false\n for (const key of JMP_UTM_PARAM_KEYS) {\n const value = params.get(key)?.trim()\n if (value) {\n utm[key] = value\n updated = true\n }\n }\n\n if (updated) {\n sessionStorage.setItem(JMP_UTM_SESSION_KEY, JSON.stringify(utm))\n }\n } catch {\n }\n\n return { landingReferer, utm }\n}\n\nexport function getOrCreateSessionIdFromStorage(): string | undefined {\n if (typeof window === \"undefined\" || !globalThis.crypto?.randomUUID) {\n return undefined\n }\n try {\n let id = sessionStorage.getItem(JMP_SESSION_ID_KEY)\n if (!id) {\n id = crypto.randomUUID()\n sessionStorage.setItem(JMP_SESSION_ID_KEY, id)\n }\n return id\n } catch {\n return undefined\n }\n}\n\n/** Inline script for Next.js `beforeInteractive` — capture referrer/UTM only (no network). */\nexport function buildLandingCaptureInlineScript(): string {\n const cookieMaxAge = String(LANDING_REFERER_COOKIE_MAX_AGE_SEC)\n\n return `(function(){try{var h=location.hostname;var ref=document.referrer||'';function rh(u){try{return new URL(u).hostname.replace(/^www\\\\./i,'').toLowerCase()}catch(e){try{return new URL('https://'+u).hostname.replace(/^www\\\\./i,'').toLowerCase()}catch(e2){return null}}}function ext(r){var x=rh(r);if(!x)return false;var s=h.replace(/^www\\\\./i,'').toLowerCase();return x!==s&&x.slice(-('.'+s).length)!==('.'+s)}function apexDom(hn){var s=hn.replace(/^www\\\\./i,'').toLowerCase();if(!s||s==='localhost'||/\\\\.local$/i.test(s)||s.indexOf('.')<0)return null;return s}function readCk(hn){var apex=apexDom(hn);if(!apex)return '';var pre='${JMP_LANDING_REFERER_COOKIE}=';var parts=document.cookie.split(';');for(var i=0;i<parts.length;i++){var t=parts[i].trim();if(t.indexOf(pre)===0){try{return decodeURIComponent(t.slice(pre.length)).trim()}catch(e){return ''}}}return ''}function writeCk(r,hn){var apex=apexDom(hn);if(!apex)return;var sec=location.protocol==='https:'?'; Secure':'';document.cookie='${JMP_LANDING_REFERER_COOKIE}='+encodeURIComponent(r.slice(0,2048))+'; Domain=.'+apex+'; Path=/; Max-Age=${cookieMaxAge}; SameSite=Lax'+sec}var stored=sessionStorage.getItem('${JMP_LANDING_REFERER_KEY}')||'';var ck=readCk(h);var preserved=stored||ck;var lr='';if(ref&&ext(ref)){sessionStorage.setItem('${JMP_LANDING_REFERER_KEY}',ref);writeCk(ref,h);lr=ref}else{lr=preserved||'';if(lr&&!stored)sessionStorage.setItem('${JMP_LANDING_REFERER_KEY}',lr)}var sid=sessionStorage.getItem('${JMP_SESSION_ID_KEY}');if(!sid&&crypto&&crypto.randomUUID){sid=crypto.randomUUID();sessionStorage.setItem('${JMP_SESSION_ID_KEY}',sid)}try{var sp=new URLSearchParams(location.search);var utm={};var updated=false;['utm_source','utm_medium','utm_campaign','utm_content','utm_term'].forEach(function(n){var v=sp.get(n);if(v){utm[n]=v;updated=true}});if(updated)sessionStorage.setItem('${JMP_UTM_SESSION_KEY}',JSON.stringify(utm))}catch(e){}}catch(e){}})();`\n}\n","/**\n * Classify outbound contact links for auto-tracking.\n *\n * Keep channel set in sync with `lib/ingest/contact-click.ts` on the dashboard side.\n *\n * Channels detected from `href` alone (no widget / iframe detection):\n *\n * - `call` — `tel:` (delegates to existing `trackCallClick`)\n * - `email` — `mailto:` (delegates to existing `trackEmailClick`)\n * - `sms` — `sms:` / `smsto:`\n * - `whatsapp` — `wa.me`, `api.whatsapp.com`, `whatsapp.com/send`\n * - `maps` — Google Maps, Apple Maps, `maps.app.goo.gl`, `geo:`\n * - `booking` — fixed allowlist of common scheduling hosts (see {@link BOOKING_LINK_HOSTS})\n *\n * `linkHost` returned in `contact_click` results is the hostname only — never the full URL\n * (avoids leaking phone numbers in `tel:`/`sms:` URLs and PII-laden booking query strings).\n */\n\nexport type ContactLinkChannel = \"sms\" | \"whatsapp\" | \"maps\" | \"booking\"\n\nexport type ClassifiedContactLink =\n | { kind: \"call\" }\n | { kind: \"email\" }\n | { kind: \"contact_click\"; channel: ContactLinkChannel; linkHost: string | null }\n\n/** v1 booking hosts (~80%+ SMB coverage). Add hosts here when a client uses something rare. */\nexport const BOOKING_LINK_HOSTS = [\n \"calendly.com\",\n \"cal.com\",\n \"acuityscheduling.com\",\n \"calendar.google.com\",\n \"calendar.app.google\",\n \"bookings.microsoft.com\",\n \"outlook.office.com\",\n \"outlook.office365.com\",\n \"book.ms\",\n \"setmore.com\",\n \"simplybook.me\",\n \"oncehub.com\",\n \"scheduleonce.com\",\n \"youcanbook.me\",\n \"savvycal.com\",\n \"tidycal.com\",\n \"zohobookings.com\",\n \"square.site\",\n \"squareup.com\",\n \"meetings.hubspot.com\",\n \"jobber.com\",\n \"housecallpro.com\",\n \"servicetitan.com\",\n \"thryv.com\",\n \"honeybook.com\",\n \"dubsado.com\",\n \"fresha.com\",\n \"booksy.com\",\n \"vagaro.com\",\n \"mindbodyonline.com\",\n \"mindbody.io\",\n \"janeapp.com\",\n \"cliniko.com\",\n \"practicebetter.io\",\n] as const\n\nconst WHATSAPP_HOSTS = [\"wa.me\", \"api.whatsapp.com\", \"whatsapp.com\"] as const\n\nexport function hostnameMatches(host: string, pattern: string): boolean {\n const h = host.toLowerCase()\n const p = pattern.toLowerCase()\n return h === p || h.endsWith(`.${p}`)\n}\n\nfunction isMapsHost(host: string, pathname: string): boolean {\n if (hostnameMatches(host, \"maps.apple.com\")) {\n return true\n }\n if (hostnameMatches(host, \"maps.app.goo.gl\")) {\n return true\n }\n if (hostnameMatches(host, \"google.com\") || hostnameMatches(host, \"google.co\")) {\n return pathname === \"/maps\" || pathname.startsWith(\"/maps/\") || pathname.startsWith(\"/local\")\n }\n return false\n}\n\nfunction isWhatsAppHost(host: string, pathname: string): boolean {\n for (const pattern of WHATSAPP_HOSTS) {\n if (!hostnameMatches(host, pattern)) {\n continue\n }\n if (pattern === \"whatsapp.com\") {\n return pathname.startsWith(\"/send\")\n }\n return true\n }\n return false\n}\n\nfunction isBookingHost(host: string): boolean {\n for (const pattern of BOOKING_LINK_HOSTS) {\n if (hostnameMatches(host, pattern)) {\n return true\n }\n }\n return false\n}\n\n/** Returns `null` when the link should not be tracked as a contact link. */\nexport function classifyContactHref(href: string): ClassifiedContactLink | null {\n const raw = href.trim()\n if (!raw || raw.startsWith(\"#\") || raw.startsWith(\"javascript:\")) {\n return null\n }\n\n const lower = raw.toLowerCase()\n\n if (lower.startsWith(\"tel:\")) {\n return { kind: \"call\" }\n }\n if (lower.startsWith(\"mailto:\")) {\n return { kind: \"email\" }\n }\n if (lower.startsWith(\"sms:\") || lower.startsWith(\"smsto:\")) {\n return { kind: \"contact_click\", channel: \"sms\", linkHost: null }\n }\n if (lower.startsWith(\"geo:\")) {\n return { kind: \"contact_click\", channel: \"maps\", linkHost: null }\n }\n\n // Skip anchors/relative paths that aren't a known contact scheme.\n if (raw.startsWith(\"/\") || raw.startsWith(\"?\")) {\n return null\n }\n\n let url: URL\n try {\n url = new URL(raw)\n } catch {\n return null\n }\n\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n return null\n }\n\n const host = url.hostname.toLowerCase()\n const pathname = url.pathname.toLowerCase()\n\n if (isWhatsAppHost(host, pathname)) {\n return { kind: \"contact_click\", channel: \"whatsapp\", linkHost: host }\n }\n if (isMapsHost(host, pathname)) {\n return { kind: \"contact_click\", channel: \"maps\", linkHost: host }\n }\n if (isBookingHost(host)) {\n return { kind: \"contact_click\", channel: \"booking\", linkHost: host }\n }\n\n return null\n}\n","import type { JmpContentConfig, JmpContentWrapper } from \"./index\"\n\n/** Per-site values used when the dashboard profile is missing or fields are empty. */\nexport type JmpSiteContactFallback = {\n displayName?: string\n founderName?: string\n email?: string\n phone?: string | null\n linkedin?: string | null\n hours?: string | null\n serviceArea?: string | null\n dashboardDemoUrl?: string\n profilePhotoSrc?: string\n privacyUrl?: string\n termsUrl?: string\n}\n\nexport type JmpSiteDefinition = {\n /** Content tabs this site uses — reported via instrumentation capabilities. */\n contentWrappers: JmpContentWrapper[]\n /**\n * Public site origin (no trailing slash), e.g. `https://example.com`.\n * Used to resolve relative profile image paths in structured data.\n */\n siteUrl?: string\n contactFallback?: JmpSiteContactFallback\n /**\n * `extras` keys to read from the dashboard site profile (hyphenated keys from admin).\n */\n contactExtraKeys?: {\n founderName?: readonly string[]\n dashboardDemoUrl?: readonly string[]\n profilePhotoSrc?: readonly string[]\n hours?: readonly string[]\n serviceArea?: readonly string[]\n }\n}\n\nlet registeredSite: JmpSiteDefinition | null = null\n\nfunction readNextPublicEnv(\n key:\n | \"NEXT_PUBLIC_JMP_ANALYTICS_URL\"\n | \"NEXT_PUBLIC_JMP_TRACKING_KEY\"\n): string | undefined {\n if (typeof process === \"undefined\" || !process.env) return undefined\n\n const v =\n key === \"NEXT_PUBLIC_JMP_ANALYTICS_URL\"\n ? process.env.NEXT_PUBLIC_JMP_ANALYTICS_URL\n : process.env.NEXT_PUBLIC_JMP_TRACKING_KEY\n\n return typeof v === \"string\" && v.length > 0 ? v : undefined\n}\n\nfunction getServerConfigFromEnv(): JmpContentConfig | null {\n const baseUrl = readNextPublicEnv(\"NEXT_PUBLIC_JMP_ANALYTICS_URL\")\n const trackingKey = readNextPublicEnv(\"NEXT_PUBLIC_JMP_TRACKING_KEY\")\n if (!baseUrl || !trackingKey) return null\n return { baseUrl, trackingKey }\n}\n\n/**\n * Register site-specific JMP integration options once (typically from `jmp.config.ts`).\n * Call at module load time before server content or instrumentation runs.\n */\nexport function defineJmpSite(definition: JmpSiteDefinition): JmpSiteDefinition {\n registeredSite = definition\n return definition\n}\n\nexport function getJmpSiteDefinition(): JmpSiteDefinition | null {\n return registeredSite\n}\n\n/** Server content + lead config: env vars + wrappers from {@link defineJmpSite}. */\nexport function getJmpContentConfig(): JmpContentConfig | null {\n const fromEnv = getServerConfigFromEnv()\n if (!fromEnv) {\n return null\n }\n const site = getJmpSiteDefinition()\n return {\n ...fromEnv,\n contentWrappers: site?.contentWrappers ?? fromEnv.contentWrappers,\n }\n}\n","import {\n captureLandingAttribution,\n getOrCreateSessionIdFromStorage,\n JMP_UTM_PARAM_KEYS,\n} from \"./landing-capture\"\nimport {\n classifyContactHref,\n type ContactLinkChannel,\n} from \"./contact-link-classifier\"\n\nexport { buildLandingCaptureInlineScript } from \"./landing-capture\"\nexport {\n classifyContactHref,\n BOOKING_LINK_HOSTS,\n} from \"./contact-link-classifier\"\nexport type {\n ContactLinkChannel,\n ClassifiedContactLink,\n} from \"./contact-link-classifier\"\n\n/** Published package version — sent with capabilities for admin readiness. */\nexport const JMP_ANALYTICS_SDK_VERSION = \"0.1.19\"\n\n/** `localStorage` key when {@link JmpAnalyticsConfig.requireConsent} is enabled. */\nexport const JMP_TRACKING_CONSENT_STORAGE_KEY = \"jmp_analytics_consent_v1\"\n\nlet moduleTrackingConsentGranted = true\nconst trackingConsentListeners = new Set<() => void>()\n\nfunction readStoredTrackingConsent(): boolean {\n if (typeof window === \"undefined\") {\n return false\n }\n try {\n return (\n localStorage.getItem(JMP_TRACKING_CONSENT_STORAGE_KEY) === \"granted\"\n )\n } catch {\n return false\n }\n}\n\n/** Whether analytics events may be sent (after CMP / cookie banner). */\nexport function isJmpTrackingConsentGranted(): boolean {\n return moduleTrackingConsentGranted\n}\n\n/** Subscribe to consent changes (for React `useSyncExternalStore`). */\nexport function subscribeJmpTrackingConsent(listener: () => void): () => void {\n trackingConsentListeners.add(listener)\n return () => {\n trackingConsentListeners.delete(listener)\n }\n}\n\n/**\n * Grant or deny analytics. Persists in `localStorage` when `requireConsent` is used.\n * Call from your cookie banner before tracking runs.\n */\nexport function setJmpTrackingConsent(granted: boolean): void {\n if (moduleTrackingConsentGranted === granted) {\n return\n }\n moduleTrackingConsentGranted = granted\n if (typeof window !== \"undefined\") {\n try {\n localStorage.setItem(\n JMP_TRACKING_CONSENT_STORAGE_KEY,\n granted ? \"granted\" : \"denied\"\n )\n } catch {\n }\n if (granted) {\n captureLandingAttribution(window.location.hostname)\n }\n }\n for (const listener of trackingConsentListeners) {\n listener()\n }\n}\n\nexport type JmpEventType =\n | \"page_view\"\n | \"form_submit\"\n | \"call_click\"\n | \"email_click\"\n | \"contact_click\"\n\nexport type JmpAnalyticsConfig = {\n /** Dashboard origin, e.g. https://analytics.example.com (no trailing slash) */\n baseUrl: string\n /** Per-website key from JMP admin */\n trackingKey: string\n /** Log requests to console */\n debug?: boolean\n /** Override fetch (tests, React Native) */\n fetchImpl?: typeof fetch\n /**\n * Suppress duplicate `page_view` for the same path within this window (ms).\n * Helps with React Strict Mode double-mount; typical: 500–1000.\n */\n pageViewDedupeMs?: number\n /**\n * When true, no events are sent until {@link setJmpTrackingConsent}(true).\n * Pair with your cookie banner; see `NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT`.\n */\n requireConsent?: boolean\n /**\n * When true, register a single delegated `click` listener that classifies links\n * (SMS, WhatsApp, maps, scheduling) and records them via {@link trackContactClick}.\n *\n * Off by default — pair with privacy disclosure / consent before enabling.\n * `tel:` / `mailto:` continue to use {@link trackCallClick} / {@link trackEmailClick}.\n *\n * Opt out per-link with `data-jmp-no-track` on an `<a>` (or an ancestor).\n */\n autoTrackContactLinks?: boolean\n}\n\nexport type JmpContentConfig = Pick<\n JmpAnalyticsConfig,\n \"baseUrl\" | \"trackingKey\" | \"debug\" | \"fetchImpl\"\n> & {\n /**\n * Content wrappers wired in this site's template (blog, faq, trust.*, contact).\n * Reported via POST /api/content/capabilities so unused dashboard tabs stay hidden.\n * Call {@link registerJmpContentWrappers} at startup / deploy.\n */\n contentWrappers?: JmpContentWrapper[]\n}\n\n/** Top-level and trust sub-wrappers the client can declare. */\nexport type JmpContentWrapper =\n | \"blog\"\n | \"faq\"\n | \"contact\"\n | \"trust\"\n | \"trust.summary\"\n | \"trust.testimonials\"\n | \"trust.reviews\"\n | \"trust.stats\"\n | \"trust.logos\"\n | \"trust.credentials\"\n\nexport type JmpBlogPost = {\n id: string\n title: string\n slug: string\n excerpt: string | null\n body: string\n seo_title: string | null\n meta_description: string | null\n featured_image_url: string | null\n published_at: string | null\n updated_at: string\n}\n\nexport type JmpFaqItem = {\n id: string\n slug: string\n question: string\n answer: string\n category?: string | null\n sort_order: number\n updated_at: string\n}\n\nexport type JmpTrustSummary = {\n google_rating: number | null\n google_review_count: number | null\n google_reviews_url: string | null\n yelp_url: string | null\n trustpilot_url: string | null\n disclaimer: string | null\n}\n\nexport type JmpTestimonial = {\n id: string\n slug: string\n body: string\n author_name: string\n author_descriptor: string | null\n location: string | null\n /** 1–10 (half-star steps on a 5-star scale; 10 = 5.0 stars). */\n rating: number | null\n image_url: string | null\n video_url: string | null\n /** Optional topic or service line (e.g. roofing). */\n category: string | null\n /** Site section key — filter like FAQ `category` (e.g. testimonials, reviews). */\n placement: string | null\n source: string | null\n /** Optional link to the original review on Google, Yelp, etc. */\n source_url: string | null\n featured: boolean\n sort_order: number\n updated_at: string\n}\n\nexport type JmpTrustStat = {\n id: string\n slug: string\n label: string\n value: string\n sort_order: number\n updated_at: string\n}\n\nexport type JmpPartnerLogo = {\n id: string\n slug: string\n name: string\n image_url: string | null\n link_url: string | null\n sort_order: number\n updated_at: string\n}\n\nexport type JmpCredential = {\n id: string\n slug: string\n title: string\n issuer: string | null\n year: string | null\n image_url: string | null\n category: string | null\n sort_order: number\n updated_at: string\n}\n\nexport type JmpTrustBundle = {\n summary: JmpTrustSummary\n testimonials: JmpTestimonial[]\n stats: JmpTrustStat[]\n logos: JmpPartnerLogo[]\n credentials: JmpCredential[]\n}\n\nexport type JmpSiteProfile = {\n name: string\n display_name: string | null\n email: string | null\n phone: string | null\n address: string | null\n hours: string | null\n service_area: string | null\n google_maps_url: string | null\n social: {\n linkedin: string | null\n instagram: string | null\n facebook: string | null\n x: string | null\n youtube: string | null\n }\n cta: {\n label: string | null\n url: string | null\n }\n legal: {\n privacy_policy_url: string | null\n terms_url: string | null\n }\n /** Developer-defined keys; values filled by the client. */\n extras: Record<string, string | null>\n}\n\nexport type TrackPageViewOptions = {\n path?: string\n source?: string\n device?: string\n country?: string\n metadata?: Record<string, unknown>\n}\n\nexport type TrackLeadOptions = {\n /** Path where the lead was submitted, e.g. /contact */\n path?: string\n name?: string\n email?: string\n phone?: string\n company?: string\n website?: string\n subject?: string\n message?: string\n /**\n * Optional flexible metadata for dynamic lead forms.\n * Prefer the normalized envelope (formId/formVersion/answers/derived/attribution),\n * but unknown keys are also accepted by the API.\n */\n metadata?: LeadMetadata\n /**\n * Optional session id (from createJmpAnalytics internal session) if your app wants to pass it explicitly.\n * Most callers should omit this.\n */\n sessionId?: string\n}\n\nexport type LeadMetadataValue =\n | string\n | number\n | boolean\n | null\n | undefined\n | LeadMetadataValue[]\n | { [key: string]: LeadMetadataValue }\n\nexport type LeadMetadata = {\n formId?: string\n formVersion?: string\n leadKind?: string\n answers?: Record<string, LeadMetadataValue>\n derived?: Record<string, LeadMetadataValue>\n attribution?: {\n utm_source?: string\n utm_medium?: string\n utm_campaign?: string\n utm_content?: string\n utm_term?: string\n gclid?: string\n fbclid?: string\n msclkid?: string\n ttclid?: string\n [key: string]: LeadMetadataValue | undefined\n }\n tags?: string[]\n [key: string]: LeadMetadataValue | undefined\n}\n\nexport type JmpServerRequestLike = {\n url?: string\n headers:\n | Pick<Headers, \"get\">\n | Record<string, string | string[] | undefined | null>\n}\n\nexport type TrackServerPageViewOptions = {\n request?: JmpServerRequestLike\n /** Overrides request URL path. Use pathname + search when possible. */\n path?: string\n /** Original visitor user agent. Useful when not passing `request`. */\n userAgent?: string | null\n /** Original visitor referrer. Useful when not passing `request`. */\n referer?: string | null\n metadata?: Record<string, unknown>\n sessionId?: string\n}\n\nfunction captureAndGetLandingReferer(): string | null {\n if (typeof window === \"undefined\") {\n return null\n }\n return captureLandingAttribution(window.location.hostname).landingReferer\n}\n\nfunction mergeSessionUtms(metadata: Record<string, unknown>) {\n if (typeof window === \"undefined\") {\n return\n }\n const { utm } = captureLandingAttribution(window.location.hostname)\n for (const key of JMP_UTM_PARAM_KEYS) {\n if (metadata[key] === undefined && utm[key]) {\n metadata[key] = utm[key]\n }\n }\n}\n\nfunction splitPathAndSearch(pathInput: string): { pathname: string; search: string } {\n const qIndex = pathInput.indexOf(\"?\")\n if (qIndex === -1) {\n return { pathname: pathInput || \"/\", search: \"\" }\n }\n return {\n pathname: pathInput.slice(0, qIndex) || \"/\",\n search: pathInput.slice(qIndex + 1),\n }\n}\n\n/** CDN / Next.js often return HTML error pages; API errors are JSON */\nfunction responseLooksLikeHtml(body: string) {\n const s = body.trimStart()\n return (\n s.startsWith(\"<!\") ||\n s.toLowerCase().startsWith(\"<html\") ||\n (s.startsWith(\"<\") && /<html[\\s>]/i.test(s.slice(0, 500)))\n )\n}\n\nfunction normalizeBaseUrl(baseUrl: string) {\n return baseUrl.replace(/\\/$/, \"\")\n}\n\nfunction getHeader(\n headers: JmpServerRequestLike[\"headers\"] | undefined,\n key: string\n): string | null {\n if (!headers) {\n return null\n }\n if (typeof (headers as Pick<Headers, \"get\">).get === \"function\") {\n return (headers as Pick<Headers, \"get\">).get(key)\n }\n const record = headers as Record<string, string | string[] | undefined | null>\n const direct = record[key] ?? record[key.toLowerCase()]\n if (Array.isArray(direct)) {\n return direct[0] ?? null\n }\n return direct ?? null\n}\n\nfunction pathFromRequestUrl(url: string | undefined): string {\n if (!url) {\n return \"/\"\n }\n try {\n const u = new URL(url)\n return `${u.pathname}${u.search}`\n } catch {\n return url.startsWith(\"/\") ? url : \"/\"\n }\n}\n\nfunction inferDevice(): string {\n if (typeof window === \"undefined\") {\n return \"unknown\"\n }\n return window.innerWidth < 768 ? \"mobile\" : \"desktop\"\n}\n\n/**\n * Create a tracker instance. Safe to call once per app and reuse.\n */\nexport function createJmpAnalytics(config: JmpAnalyticsConfig) {\n const baseUrl = normalizeBaseUrl(config.baseUrl)\n const resolvedFetch =\n config.fetchImpl ??\n (typeof globalThis !== \"undefined\" && globalThis.fetch\n ? globalThis.fetch.bind(globalThis)\n : undefined)\n\n if (!resolvedFetch) {\n throw new Error(\n \"createJmpAnalytics: fetch is not available; pass fetchImpl in config\"\n )\n }\n\n const fetchFn: typeof fetch = resolvedFetch\n\n moduleTrackingConsentGranted = config.requireConsent\n ? readStoredTrackingConsent()\n : true\n\n function canSend(): boolean {\n return moduleTrackingConsentGranted\n }\n\n let lastDedupePath = \"\"\n let lastDedupeAt = 0\n\n async function send(body: Record<string, unknown>) {\n if (!canSend()) {\n return\n }\n\n const url = `${baseUrl}/api/events`\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-JMP-Tracking-Key\": config.trackingKey,\n }\n\n if (body.type === \"page_view\" && typeof window !== \"undefined\") {\n const landingReferer = captureAndGetLandingReferer()\n if (landingReferer) {\n headers[\"X-JMP-Visitor-Referer\"] = landingReferer\n }\n }\n\n const sid = getOrCreateSessionIdFromStorage()\n const payload = { ...body, ...(sid ? { sessionId: sid } : {}) }\n\n if (config.debug) {\n console.debug(\"[@jmp-technologies/analytics]\", \"POST\", url, payload)\n }\n\n const res = await fetchFn(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n keepalive: true,\n })\n\n if (!res.ok) {\n const text = await res.text()\n if (responseLooksLikeHtml(text)) {\n throw new Error(\n `JMP Analytics HTTP ${res.status} — ${url} returned HTML (not the JSON API). ` +\n `Set baseUrl / NEXT_PUBLIC_JMP_ANALYTICS_URL to your JMP Analytics dashboard origin (the deployment that includes POST /api/events), ` +\n `not a marketing or client site unless that codebase ships the same API route.`\n )\n }\n let parsed: {\n error?: string\n code?: string\n hint?: string\n expectedDomain?: string\n } = {}\n try {\n parsed = JSON.parse(text) as typeof parsed\n } catch {\n parsed = { error: text }\n }\n const detail = parsed.error ?? text\n const segments = [\n `JMP Analytics HTTP ${res.status}`,\n parsed.code ? `[${parsed.code}]` : null,\n detail,\n parsed.hint ? `Hint: ${parsed.hint}` : null,\n parsed.expectedDomain\n ? `Domain in JMP admin: ${parsed.expectedDomain}`\n : null,\n ].filter(Boolean) as string[]\n const message = segments.join(\" — \")\n if (config.debug) {\n console.debug(\"[@jmp-technologies/analytics]\", \"error response\", {\n status: res.status,\n ...parsed,\n raw: text,\n })\n }\n throw new Error(message)\n }\n }\n\n async function sendLead(body: Record<string, unknown>) {\n if (!canSend()) {\n return\n }\n\n const url = `${baseUrl}/api/leads`\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-JMP-Tracking-Key\": config.trackingKey,\n }\n\n const sid = getOrCreateSessionIdFromStorage()\n const payload = { ...body, ...(sid ? { sessionId: sid } : {}) }\n\n if (config.debug) {\n console.debug(\"[@jmp-technologies/analytics]\", \"POST\", url, payload)\n }\n\n const res = await fetchFn(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n keepalive: true,\n })\n\n if (!res.ok) {\n const text = await res.text()\n if (responseLooksLikeHtml(text)) {\n throw new Error(\n `JMP Analytics HTTP ${res.status} — ${url} returned HTML (not the JSON API). ` +\n `Set baseUrl / NEXT_PUBLIC_JMP_ANALYTICS_URL to your JMP Analytics dashboard origin (the deployment that includes POST /api/leads).`\n )\n }\n let parsed: {\n error?: string\n code?: string\n hint?: string\n expectedDomain?: string\n } = {}\n try {\n parsed = JSON.parse(text) as typeof parsed\n } catch {\n parsed = { error: text }\n }\n const detail = parsed.error ?? text\n const segments = [\n `JMP Analytics HTTP ${res.status}`,\n parsed.code ? `[${parsed.code}]` : null,\n detail,\n parsed.hint ? `Hint: ${parsed.hint}` : null,\n parsed.expectedDomain\n ? `Domain in JMP admin: ${parsed.expectedDomain}`\n : null,\n ].filter(Boolean) as string[]\n const message = segments.join(\" — \")\n if (config.debug) {\n console.debug(\"[@jmp-technologies/analytics]\", \"error response\", {\n status: res.status,\n ...parsed,\n raw: text,\n })\n }\n throw new Error(message)\n }\n }\n\n function shouldDedupePageView(path: string): boolean {\n const ms = config.pageViewDedupeMs ?? 0\n if (ms <= 0 || typeof window === \"undefined\") {\n return false\n }\n const now = Date.now()\n if (path === lastDedupePath && now - lastDedupeAt < ms) {\n return true\n }\n lastDedupePath = path\n lastDedupeAt = now\n return false\n }\n\n function trackPageView(options?: TrackPageViewOptions) {\n if (!canSend()) {\n return Promise.resolve()\n }\n\n const pathFromOptions = options?.path?.trim()\n let pathname = \"/\"\n let search = \"\"\n\n if (pathFromOptions) {\n const split = splitPathAndSearch(pathFromOptions)\n pathname = split.pathname\n search = split.search\n } else if (typeof window !== \"undefined\") {\n pathname = window.location.pathname\n search = window.location.search.replace(/^\\?/, \"\")\n }\n\n if (!search && typeof window !== \"undefined\") {\n search = window.location.search.replace(/^\\?/, \"\")\n }\n\n const path = search ? `${pathname}?${search}` : pathname\n\n if (shouldDedupePageView(pathname)) {\n return Promise.resolve()\n }\n\n const metadata: Record<string, unknown> =\n options?.metadata && typeof options.metadata === \"object\"\n ? { ...options.metadata }\n : {}\n\n if (typeof window !== \"undefined\") {\n metadata.pageHostname = window.location.hostname\n const params = new URLSearchParams(\n search ? `?${search}` : window.location.search\n )\n for (const key of JMP_UTM_PARAM_KEYS) {\n const v = params.get(key)\n if (v && metadata[key] === undefined) {\n metadata[key] = v\n }\n }\n mergeSessionUtms(metadata)\n const landingReferer = captureAndGetLandingReferer()\n if (landingReferer && metadata.referer === undefined) {\n metadata.referer = landingReferer\n }\n }\n\n return send({\n type: \"page_view\",\n path: path || \"/\",\n device: options?.device ?? inferDevice(),\n country: options?.country,\n metadata,\n })\n }\n\n function trackFormSubmit(\n path: string,\n metadata?: Record<string, unknown>\n ) {\n return send({\n type: \"form_submit\",\n path: path || \"/\",\n metadata: metadata ?? {},\n })\n }\n\n function trackCallClick(\n path: string,\n metadata?: Record<string, unknown>\n ) {\n return send({\n type: \"call_click\",\n path: path || \"/\",\n metadata: metadata ?? {},\n })\n }\n\n function trackEmailClick(\n path: string,\n metadata?: Record<string, unknown>\n ) {\n return send({\n type: \"email_click\",\n path: path || \"/\",\n metadata: metadata ?? {},\n })\n }\n\n function trackContactClick(\n path: string,\n options: {\n channel: ContactLinkChannel\n linkHost?: string | null\n metadata?: Record<string, unknown>\n }\n ) {\n const metadata: Record<string, unknown> = {\n ...(options.metadata && typeof options.metadata === \"object\"\n ? options.metadata\n : {}),\n channel: options.channel,\n }\n if (options.linkHost) {\n metadata.linkHost = options.linkHost\n }\n return send({\n type: \"contact_click\",\n path: path || \"/\",\n metadata,\n })\n }\n\n function trackLead(options?: TrackLeadOptions) {\n const path =\n options?.path ??\n (typeof window !== \"undefined\" ? window.location.pathname : \"/\")\n\n const body: Record<string, unknown> = { path: path || \"/\" }\n if (options?.name) body.name = options.name\n if (options?.email) body.email = options.email\n if (options?.phone) body.phone = options.phone\n if (options?.company) body.company = options.company\n if (options?.website) body.website = options.website\n if (options?.subject) body.subject = options.subject\n if (options?.message) body.message = options.message\n if (options?.metadata && typeof options.metadata === \"object\") {\n body.metadata = options.metadata\n }\n if (options?.sessionId) body.sessionId = options.sessionId\n\n return sendLead(body)\n }\n\n function track(\n type: JmpEventType,\n payload: {\n path: string\n metadata?: Record<string, unknown>\n source?: string\n device?: string\n country?: string\n }\n ) {\n if (type === \"page_view\") {\n return trackPageView({\n path: payload.path,\n source: payload.source,\n device: payload.device,\n country: payload.country,\n metadata: payload.metadata,\n })\n }\n if (type === \"form_submit\") {\n return trackFormSubmit(payload.path, payload.metadata)\n }\n if (type === \"call_click\") {\n return trackCallClick(payload.path, payload.metadata)\n }\n if (type === \"email_click\") {\n return trackEmailClick(payload.path, payload.metadata)\n }\n const meta = payload.metadata ?? {}\n const channel = typeof meta.channel === \"string\" ? meta.channel : \"\"\n const linkHost =\n typeof meta.linkHost === \"string\" ? (meta.linkHost as string) : null\n if (\n channel !== \"sms\" &&\n channel !== \"whatsapp\" &&\n channel !== \"maps\" &&\n channel !== \"booking\"\n ) {\n return Promise.resolve()\n }\n return trackContactClick(payload.path, {\n channel: channel as ContactLinkChannel,\n linkHost,\n metadata: meta,\n })\n }\n\n /**\n * Fire `page_view` on browser back/forward and when `history.pushState` /\n * `replaceState` are used (many SPAs). Call once after creating the tracker.\n * Returns an unsubscribe function.\n */\n function subscribeToSpaNavigation(): () => void {\n if (typeof window === \"undefined\") {\n return () => {}\n }\n\n let lastPath = window.location.pathname\n\n const run = () => {\n const path = window.location.pathname\n if (path !== lastPath) {\n lastPath = path\n void trackPageView({ path })\n }\n }\n\n window.addEventListener(\"popstate\", run)\n\n const push = history.pushState.bind(history)\n const replace = history.replaceState.bind(history)\n\n history.pushState = (...args: Parameters<History[\"pushState\"]>) => {\n const r = push(...args)\n queueMicrotask(run)\n return r\n }\n history.replaceState = (...args: Parameters<History[\"replaceState\"]>) => {\n const r = replace(...args)\n queueMicrotask(run)\n return r\n }\n\n return () => {\n window.removeEventListener(\"popstate\", run)\n history.pushState = push\n history.replaceState = replace\n }\n }\n\n let lastContactClickKey = \"\"\n let lastContactClickAt = 0\n\n /**\n * Capture-phase `click` listener that classifies outgoing links and records\n * the corresponding contact event. Returns an unsubscribe function. Safe to\n * call only in the browser; no-op on the server.\n */\n function subscribeContactLinkAutoTrack(): () => void {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return () => {}\n }\n\n const handler = (event: MouseEvent) => {\n if (!canSend()) {\n return\n }\n const target = event.target\n if (!(target instanceof Element)) {\n return\n }\n const anchor = target.closest(\"a[href]\")\n if (!(anchor instanceof HTMLAnchorElement)) {\n return\n }\n if (anchor.closest(\"[data-jmp-no-track]\")) {\n return\n }\n\n const href = anchor.getAttribute(\"href\") ?? \"\"\n const classified = classifyContactHref(href)\n if (!classified) {\n return\n }\n\n const path = window.location.pathname\n\n if (classified.kind === \"call\") {\n if (dedupeContactClick(`call_click:${path}`)) {\n return\n }\n void trackCallClick(path)\n return\n }\n if (classified.kind === \"email\") {\n if (dedupeContactClick(`email_click:${path}`)) {\n return\n }\n void trackEmailClick(path)\n return\n }\n if (dedupeContactClick(`contact_click:${classified.channel}:${path}`)) {\n return\n }\n void trackContactClick(path, {\n channel: classified.channel,\n linkHost: classified.linkHost,\n })\n }\n\n document.addEventListener(\"click\", handler, { capture: true })\n return () => {\n document.removeEventListener(\"click\", handler, { capture: true } as EventListenerOptions)\n }\n }\n\n function dedupeContactClick(key: string): boolean {\n const now = Date.now()\n if (key === lastContactClickKey && now - lastContactClickAt < 1000) {\n return true\n }\n lastContactClickKey = key\n lastContactClickAt = now\n return false\n }\n\n if (typeof window !== \"undefined\" && canSend()) {\n captureLandingAttribution(window.location.hostname)\n }\n\n if (\n typeof window !== \"undefined\" &&\n config.autoTrackContactLinks &&\n canSend()\n ) {\n subscribeContactLinkAutoTrack()\n }\n\n return {\n track,\n trackPageView,\n trackFormSubmit,\n trackCallClick,\n trackEmailClick,\n trackContactClick,\n trackLead,\n subscribeToSpaNavigation,\n subscribeContactLinkAutoTrack,\n setTrackingConsent: setJmpTrackingConsent,\n isTrackingConsentGranted: isJmpTrackingConsentGranted,\n }\n}\n\nexport type JmpAnalytics = ReturnType<typeof createJmpAnalytics>\n\nexport async function trackJmpServerPageView(\n config: JmpContentConfig,\n options: TrackServerPageViewOptions = {}\n): Promise<void> {\n const baseUrl = normalizeBaseUrl(config.baseUrl)\n const resolvedFetch =\n config.fetchImpl ??\n (typeof globalThis !== \"undefined\" && globalThis.fetch\n ? globalThis.fetch.bind(globalThis)\n : undefined)\n\n if (!resolvedFetch) {\n throw new Error(\"JMP server analytics: fetch is not available; pass fetchImpl in config\")\n }\n\n const visitorUserAgent =\n options.userAgent ?? getHeader(options.request?.headers, \"user-agent\")\n const visitorReferer =\n options.referer ?? getHeader(options.request?.headers, \"referer\")\n const path = options.path ?? pathFromRequestUrl(options.request?.url)\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-JMP-Tracking-Key\": config.trackingKey,\n }\n if (visitorUserAgent) {\n headers[\"X-JMP-Visitor-User-Agent\"] = visitorUserAgent\n }\n if (visitorReferer) {\n headers[\"X-JMP-Visitor-Referer\"] = visitorReferer\n }\n\n const payload: Record<string, unknown> = {\n type: \"page_view\",\n path: path || \"/\",\n metadata:\n options.metadata && typeof options.metadata === \"object\"\n ? options.metadata\n : {},\n }\n if (options.sessionId) {\n payload.sessionId = options.sessionId\n }\n\n const url = `${baseUrl}/api/events`\n if (config.debug) {\n console.debug(\"[@jmp-technologies/analytics]\", \"POST\", url, payload)\n }\n\n const res = await resolvedFetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(payload),\n })\n\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`JMP server analytics HTTP ${res.status} — ${text}`)\n }\n}\n\nexport async function getJmpBlogPosts(\n config: JmpContentConfig\n): Promise<JmpBlogPost[]> {\n const data = await getContent<{ posts: JmpBlogPost[] }>(\n config,\n \"/api/content/blog\"\n )\n return data.posts\n}\n\nexport async function getJmpBlogPost(\n config: JmpContentConfig,\n slug: string\n): Promise<JmpBlogPost | null> {\n try {\n const data = await getContent<{ post: JmpBlogPost }>(\n config,\n `/api/content/blog/${encodeURIComponent(slug)}`\n )\n return data.post\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"HTTP 404\")) {\n return null\n }\n throw error\n }\n}\n\nexport async function getJmpFaqs(\n config: JmpContentConfig\n): Promise<JmpFaqItem[]> {\n const data = await getContent<{ faqs: JmpFaqItem[] }>(\n config,\n \"/api/content/faqs\"\n )\n return data.faqs\n}\n\nexport async function getJmpTrustBundle(\n config: JmpContentConfig\n): Promise<JmpTrustBundle> {\n return getContent<JmpTrustBundle>(config, \"/api/content/trust\")\n}\n\nexport async function getJmpSiteProfile(\n config: JmpContentConfig\n): Promise<JmpSiteProfile> {\n const data = await getContent<{ site: JmpSiteProfile }>(\n config,\n \"/api/content/site\"\n )\n return data.site\n}\n\nexport async function getJmpRobotsTxt(config: JmpContentConfig): Promise<string> {\n return getContentText(config, \"/api/content/robots\")\n}\n\nconst registeredContentWrappers = new Set<string>()\n\nfunction resolveContentWrappersFromConfig(\n config: JmpContentConfig\n): string[] {\n if (config.contentWrappers?.length) {\n return [...config.contentWrappers]\n }\n return []\n}\n\n/**\n * Tell the JMP dashboard which content wrappers this site wires (blog, faq, trust.*, contact).\n * Safe to call on every cold start; dedupes by tracking key + wrapper list.\n */\nexport async function registerJmpContentWrappers(\n config: JmpContentConfig\n): Promise<\n { ok: true; wrappers: string[] } | { ok: false; skipped: true }\n> {\n const wrappers = resolveContentWrappersFromConfig(config)\n if (!wrappers.length) {\n return { ok: false, skipped: true }\n }\n\n const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(\",\")}`\n if (registeredContentWrappers.has(dedupeKey)) {\n return { ok: true, wrappers }\n }\n\n const baseUrl = normalizeBaseUrl(config.baseUrl)\n const resolvedFetch =\n config.fetchImpl ??\n (typeof globalThis !== \"undefined\" && globalThis.fetch\n ? globalThis.fetch.bind(globalThis)\n : undefined)\n\n if (!resolvedFetch) {\n throw new Error(\n \"JMP content wrappers: fetch is not available; pass fetchImpl in config\"\n )\n }\n\n const url = `${baseUrl}/api/content/capabilities`\n if (config.debug) {\n console.debug(\"[@jmp-technologies/analytics]\", \"POST\", url, { wrappers })\n }\n\n const res = await resolvedFetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-JMP-Tracking-Key\": config.trackingKey,\n },\n body: JSON.stringify({\n wrappers,\n sdkVersion: JMP_ANALYTICS_SDK_VERSION,\n }),\n })\n\n const text = await res.text()\n if (!res.ok) {\n let parsed: { error?: string; hint?: string } = {}\n try {\n parsed = JSON.parse(text) as typeof parsed\n } catch {\n parsed = { error: text }\n }\n throw new Error(\n [`JMP content wrappers HTTP ${res.status}`, parsed.error, parsed.hint]\n .filter(Boolean)\n .join(\" — \")\n )\n }\n\n registeredContentWrappers.add(dedupeKey)\n const data = JSON.parse(text) as { wrappers?: string[] }\n return { ok: true, wrappers: data.wrappers ?? wrappers }\n}\n\nexport function createJmpContentClient(config: JmpContentConfig) {\n return {\n getBlogPosts: () => getJmpBlogPosts(config),\n getBlogPost: (slug: string) => getJmpBlogPost(config, slug),\n getFaqs: () => getJmpFaqs(config),\n getTrustBundle: () => getJmpTrustBundle(config),\n getSiteProfile: () => getJmpSiteProfile(config),\n getRobotsTxt: () => getJmpRobotsTxt(config),\n registerContentWrappers: () => registerJmpContentWrappers(config),\n }\n}\n\nasync function getContent<T>(\n config: JmpContentConfig,\n path: string\n): Promise<T> {\n const text = await getContentText(config, path)\n\n try {\n return JSON.parse(text) as T\n } catch {\n const baseUrl = normalizeBaseUrl(config.baseUrl)\n const url = `${baseUrl}${path}`\n throw new Error(`JMP content HTTP 200 — ${url} returned invalid JSON.`)\n }\n}\n\nasync function getContentText(\n config: JmpContentConfig,\n path: string\n): Promise<string> {\n const baseUrl = normalizeBaseUrl(config.baseUrl)\n const resolvedFetch =\n config.fetchImpl ??\n (typeof globalThis !== \"undefined\" && globalThis.fetch\n ? globalThis.fetch.bind(globalThis)\n : undefined)\n\n if (!resolvedFetch) {\n throw new Error(\"JMP content: fetch is not available; pass fetchImpl in config\")\n }\n\n const url = `${baseUrl}${path}`\n\n if (config.debug) {\n console.debug(\"[@jmp-technologies/analytics]\", \"GET\", url)\n }\n\n const res = await resolvedFetch(url, {\n method: \"GET\",\n headers: {\n \"X-JMP-Tracking-Key\": config.trackingKey,\n },\n })\n\n const text = await res.text()\n\n if (!res.ok) {\n if (responseLooksLikeHtml(text)) {\n throw new Error(\n `JMP content HTTP ${res.status} — ${url} returned HTML (not the JSON API). ` +\n `Set baseUrl to your JMP Analytics dashboard origin.`\n )\n }\n\n let parsed: { error?: string; hint?: string } = {}\n try {\n parsed = JSON.parse(text) as typeof parsed\n } catch {\n parsed = { error: text }\n }\n\n throw new Error(\n [`JMP content HTTP ${res.status}`, parsed.error, parsed.hint]\n .filter(Boolean)\n .join(\" — \")\n )\n }\n\n return text\n}\n\n/** Default `pageViewDedupeMs` when resolving browser config from env (Strict Mode / SPA). */\nexport const DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS = 800\n\n/**\n * Read a known `NEXT_PUBLIC_*` var. Uses static `process.env.NEXT_PUBLIC_*` access so\n * Next.js can inline values into the client bundle (dynamic `process.env[key]` does not).\n */\nfunction readNextPublicEnv(\n key:\n | \"NEXT_PUBLIC_JMP_ANALYTICS_URL\"\n | \"NEXT_PUBLIC_JMP_TRACKING_KEY\"\n | \"NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT\"\n | \"NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS\"\n): string | undefined {\n if (typeof process === \"undefined\" || !process.env) return undefined\n\n let v: string | undefined\n switch (key) {\n case \"NEXT_PUBLIC_JMP_ANALYTICS_URL\":\n v = process.env.NEXT_PUBLIC_JMP_ANALYTICS_URL\n break\n case \"NEXT_PUBLIC_JMP_TRACKING_KEY\":\n v = process.env.NEXT_PUBLIC_JMP_TRACKING_KEY\n break\n case \"NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT\":\n v = process.env.NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT\n break\n case \"NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS\":\n v = process.env.NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS\n break\n }\n\n return typeof v === \"string\" && v.length > 0 ? v : undefined\n}\n\n/**\n * Browser / client bundle: reads **only** `NEXT_PUBLIC_*` vars.\n * Use for `createJmpAnalytics` on the client. Returns `null` if incomplete.\n */\nexport function getJmpBrowserAnalyticsConfigFromEnv(\n overrides?: Partial<JmpAnalyticsConfig>\n): JmpAnalyticsConfig | null {\n const baseUrl = readNextPublicEnv(\"NEXT_PUBLIC_JMP_ANALYTICS_URL\")\n const trackingKey = readNextPublicEnv(\"NEXT_PUBLIC_JMP_TRACKING_KEY\")\n if (!baseUrl || !trackingKey) return null\n const requireConsentFromEnv =\n readNextPublicEnv(\"NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT\") === \"true\"\n const autoTrackContactLinksFromEnv =\n readNextPublicEnv(\"NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS\") === \"true\"\n return {\n baseUrl,\n trackingKey,\n pageViewDedupeMs: DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,\n ...overrides,\n requireConsent: overrides?.requireConsent ?? requireConsentFromEnv,\n autoTrackContactLinks:\n overrides?.autoTrackContactLinks ?? autoTrackContactLinksFromEnv,\n }\n}\n\n/**\n * Server / Node (SSR, Route Handlers, `getStaticProps`, etc.):\n * Same **`NEXT_PUBLIC_*`** vars as the browser (`NEXT_PUBLIC_JMP_ANALYTICS_URL` +\n * `NEXT_PUBLIC_JMP_TRACKING_KEY`). Next.js injects these on the server for RSC/fetches.\n * Returns `null` if incomplete.\n */\nexport function getJmpServerContentConfigFromEnv(\n overrides?: Partial<JmpContentConfig>\n): JmpContentConfig | null {\n const baseUrl = readNextPublicEnv(\"NEXT_PUBLIC_JMP_ANALYTICS_URL\")\n const trackingKey = readNextPublicEnv(\"NEXT_PUBLIC_JMP_TRACKING_KEY\")\n if (!baseUrl || !trackingKey) return null\n return { baseUrl, trackingKey, ...overrides }\n}\n\nexport function isJmpBrowserAnalyticsEnvConfigured(): boolean {\n return Boolean(\n readNextPublicEnv(\"NEXT_PUBLIC_JMP_ANALYTICS_URL\") &&\n readNextPublicEnv(\"NEXT_PUBLIC_JMP_TRACKING_KEY\")\n )\n}\n\nexport function isJmpServerContentEnvConfigured(): boolean {\n return isJmpBrowserAnalyticsEnvConfigured()\n}\n\nlet jmpAnalyticsBrowserSingleton: JmpAnalytics | null = null\n\n/**\n * One `JmpAnalytics` instance per browser tab (module singleton). Safe for page views and events.\n * Returns `null` on the server or when public env vars are missing.\n */\nexport function getOrCreateJmpAnalyticsFromBrowserEnv(\n overrides?: Partial<JmpAnalyticsConfig>\n): JmpAnalytics | null {\n if (typeof window === \"undefined\") return null\n if (jmpAnalyticsBrowserSingleton) return jmpAnalyticsBrowserSingleton\n const config = getJmpBrowserAnalyticsConfigFromEnv(overrides)\n if (!config) return null\n jmpAnalyticsBrowserSingleton = createJmpAnalytics(config)\n return jmpAnalyticsBrowserSingleton\n}\n\nexport type JmpContentClient = ReturnType<typeof createJmpContentClient>\n\n/**\n * `createJmpContentClient` using server env resolution. Returns `null` if env is incomplete.\n */\nexport function createJmpContentClientFromServerEnv(\n overrides?: Partial<JmpContentConfig>\n): JmpContentClient | null {\n const config = getJmpServerContentConfigFromEnv(overrides)\n if (!config) return null\n return createJmpContentClient(config)\n}\n\nexport {\n defineJmpSite,\n getJmpSiteDefinition,\n getJmpContentConfig,\n type JmpSiteDefinition,\n type JmpSiteContactFallback,\n} from \"./site-config\"\n"],"mappings":";AAEO,IAAM,qBAAqB;AAC3B,IAAM,0BAA0B;AAEhC,IAAM,6BAA6B;AACnC,IAAM,sBAAsB;AAEnC,IAAM,qCAAqC,KAAK;AAEzC,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,mBAAmB,SAAgC;AAC1D,QAAM,UAAU,QAAQ,KAAK;AAC7B,MAAI;AACF,WAAO,IAAI,IAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,EAAE,EAAE,YAAY;AAAA,EACtE,QAAQ;AACN,QAAI;AACF,aAAO,IAAI,IAAI,WAAW,OAAO,EAAE,EAAE,SAClC,QAAQ,WAAW,EAAE,EACrB,YAAY;AAAA,IACjB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,sBACd,SACA,cACS;AACT,QAAM,UAAU,mBAAmB,OAAO;AAC1C,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,QAAM,OAAO,aAAa,QAAQ,WAAW,EAAE,EAAE,YAAY;AAC7D,SAAO,YAAY,QAAQ,CAAC,QAAQ,SAAS,IAAI,IAAI,EAAE;AACzD;AAGO,SAAS,sBAAsB,cAAqC;AACzE,QAAM,OAAO,aAAa,QAAQ,WAAW,EAAE,EAAE,YAAY;AAC7D,MAAI,CAAC,QAAQ,SAAS,eAAe,KAAK,SAAS,QAAQ,GAAG;AAC5D,WAAO;AAAA,EACT;AACA,MAAI,CAAC,KAAK,SAAS,GAAG,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,yBAAyB,cAAqC;AAC5E,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,sBAAsB,YAAY;AAC/C,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,GAAG,0BAA0B;AAC5C,aAAW,QAAQ,SAAS,OAAO,MAAM,GAAG,GAAG;AAC7C,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAQ,WAAW,MAAM,GAAG;AAC/B;AAAA,IACF;AACA,QAAI;AACF,YAAM,QAAQ,mBAAmB,QAAQ,MAAM,OAAO,MAAM,CAAC,EAAE,KAAK;AACpE,aAAO,MAAM,SAAS,IAAI,QAAQ;AAAA,IACpC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,0BACd,SACA,cACM;AACN,MAAI,OAAO,aAAa,aAAa;AACnC;AAAA,EACF;AAEA,QAAM,OAAO,sBAAsB,YAAY;AAC/C,MAAI,CAAC,MAAM;AACT;AAAA,EACF;AAEA,QAAM,QAAQ,mBAAmB,QAAQ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;AAC9D,QAAM,SACJ,OAAO,WAAW,eAAe,OAAO,SAAS,aAAa,WAC1D,aACA;AAEN,WAAS,SAAS,GAAG,0BAA0B,IAAI,KAAK,aAAa,IAAI,qBAAqB,kCAAkC,iBAAiB,MAAM;AACzJ;AAEO,SAAS,0BAA0B,cAGxC;AACA,MAAI,OAAO,aAAa,eAAe,OAAO,WAAW,aAAa;AACpE,WAAO,EAAE,gBAAgB,MAAM,KAAK,CAAC,EAAE;AAAA,EACzC;AAEA,MAAI,iBAAgC;AACpC,MAAI,MAA8B,CAAC;AAEnC,MAAI;AACF,UAAM,gBACJ,eAAe,QAAQ,uBAAuB,GAAG,KAAK,KAAK;AAC7D,UAAM,gBAAgB,yBAAyB,YAAY;AAC3D,UAAM,mBAAmB,iBAAiB;AAC1C,UAAM,iBAAiB,SAAS,UAAU,KAAK,KAAK;AAEpD,QACE,kBACA,sBAAsB,gBAAgB,YAAY,GAClD;AACA,qBAAe,QAAQ,yBAAyB,cAAc;AAC9D,gCAA0B,gBAAgB,YAAY;AACtD,uBAAiB;AAAA,IACnB,WAAW,kBAAkB;AAC3B,uBAAiB;AACjB,UAAI,CAAC,eAAe;AAClB,uBAAe,QAAQ,yBAAyB,gBAAgB;AAAA,MAClE;AAAA,IACF;AAEA,UAAM,SAAS,IAAI,gBAAgB,OAAO,SAAS,MAAM;AACzD,UAAM,SAAS,eAAe,QAAQ,mBAAmB;AACzD,QAAI,QAAQ;AACV,YAAM,SAAS,KAAK,MAAM,MAAM;AAChC,UAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClE,cAAM;AAAA,MACR;AAAA,IACF;AAEA,QAAI,UAAU;AACd,eAAW,OAAO,oBAAoB;AACpC,YAAM,QAAQ,OAAO,IAAI,GAAG,GAAG,KAAK;AACpC,UAAI,OAAO;AACT,YAAI,GAAG,IAAI;AACX,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,QAAI,SAAS;AACX,qBAAe,QAAQ,qBAAqB,KAAK,UAAU,GAAG,CAAC;AAAA,IACjE;AAAA,EACF,QAAQ;AAAA,EACR;AAEA,SAAO,EAAE,gBAAgB,IAAI;AAC/B;AAEO,SAAS,kCAAsD;AACpE,MAAI,OAAO,WAAW,eAAe,CAAC,WAAW,QAAQ,YAAY;AACnE,WAAO;AAAA,EACT;AACA,MAAI;AACF,QAAI,KAAK,eAAe,QAAQ,kBAAkB;AAClD,QAAI,CAAC,IAAI;AACP,WAAK,OAAO,WAAW;AACvB,qBAAe,QAAQ,oBAAoB,EAAE;AAAA,IAC/C;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,kCAA0C;AACxD,QAAM,eAAe,OAAO,kCAAkC;AAE9D,SAAO,qnBAAqnB,0BAA0B,iVAAiV,0BAA0B,+EAA+E,YAAY,0DAA0D,uBAAuB,wGAAwG,uBAAuB,6FAA6F,uBAAuB,yCAAyC,kBAAkB,0FAA0F,kBAAkB,iQAAiQ,mBAAmB;AAC71D;;;AChKO,IAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,iBAAiB,CAAC,SAAS,oBAAoB,cAAc;AAE5D,SAAS,gBAAgB,MAAc,SAA0B;AACtE,QAAM,IAAI,KAAK,YAAY;AAC3B,QAAM,IAAI,QAAQ,YAAY;AAC9B,SAAO,MAAM,KAAK,EAAE,SAAS,IAAI,CAAC,EAAE;AACtC;AAEA,SAAS,WAAW,MAAc,UAA2B;AAC3D,MAAI,gBAAgB,MAAM,gBAAgB,GAAG;AAC3C,WAAO;AAAA,EACT;AACA,MAAI,gBAAgB,MAAM,iBAAiB,GAAG;AAC5C,WAAO;AAAA,EACT;AACA,MAAI,gBAAgB,MAAM,YAAY,KAAK,gBAAgB,MAAM,WAAW,GAAG;AAC7E,WAAO,aAAa,WAAW,SAAS,WAAW,QAAQ,KAAK,SAAS,WAAW,QAAQ;AAAA,EAC9F;AACA,SAAO;AACT;AAEA,SAAS,eAAe,MAAc,UAA2B;AAC/D,aAAW,WAAW,gBAAgB;AACpC,QAAI,CAAC,gBAAgB,MAAM,OAAO,GAAG;AACnC;AAAA,IACF;AACA,QAAI,YAAY,gBAAgB;AAC9B,aAAO,SAAS,WAAW,OAAO;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,cAAc,MAAuB;AAC5C,aAAW,WAAW,oBAAoB;AACxC,QAAI,gBAAgB,MAAM,OAAO,GAAG;AAClC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,oBAAoB,MAA4C;AAC9E,QAAM,MAAM,KAAK,KAAK;AACtB,MAAI,CAAC,OAAO,IAAI,WAAW,GAAG,KAAK,IAAI,WAAW,aAAa,GAAG;AAChE,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,IAAI,YAAY;AAE9B,MAAI,MAAM,WAAW,MAAM,GAAG;AAC5B,WAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AACA,MAAI,MAAM,WAAW,SAAS,GAAG;AAC/B,WAAO,EAAE,MAAM,QAAQ;AAAA,EACzB;AACA,MAAI,MAAM,WAAW,MAAM,KAAK,MAAM,WAAW,QAAQ,GAAG;AAC1D,WAAO,EAAE,MAAM,iBAAiB,SAAS,OAAO,UAAU,KAAK;AAAA,EACjE;AACA,MAAI,MAAM,WAAW,MAAM,GAAG;AAC5B,WAAO,EAAE,MAAM,iBAAiB,SAAS,QAAQ,UAAU,KAAK;AAAA,EAClE;AAGA,MAAI,IAAI,WAAW,GAAG,KAAK,IAAI,WAAW,GAAG,GAAG;AAC9C,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,GAAG;AAAA,EACnB,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,aAAa,WAAW,IAAI,aAAa,UAAU;AACzD,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,IAAI,SAAS,YAAY;AACtC,QAAM,WAAW,IAAI,SAAS,YAAY;AAE1C,MAAI,eAAe,MAAM,QAAQ,GAAG;AAClC,WAAO,EAAE,MAAM,iBAAiB,SAAS,YAAY,UAAU,KAAK;AAAA,EACtE;AACA,MAAI,WAAW,MAAM,QAAQ,GAAG;AAC9B,WAAO,EAAE,MAAM,iBAAiB,SAAS,QAAQ,UAAU,KAAK;AAAA,EAClE;AACA,MAAI,cAAc,IAAI,GAAG;AACvB,WAAO,EAAE,MAAM,iBAAiB,SAAS,WAAW,UAAU,KAAK;AAAA,EACrE;AAEA,SAAO;AACT;;;ACxHA,IAAI,iBAA2C;AAE/C,SAAS,kBACP,KAGoB;AACpB,MAAI,OAAO,YAAY,eAAe,CAAC,QAAQ,IAAK,QAAO;AAE3D,QAAM,IACJ,QAAQ,kCACJ,QAAQ,IAAI,gCACZ,QAAQ,IAAI;AAElB,SAAO,OAAO,MAAM,YAAY,EAAE,SAAS,IAAI,IAAI;AACrD;AAEA,SAAS,yBAAkD;AACzD,QAAM,UAAU,kBAAkB,+BAA+B;AACjE,QAAM,cAAc,kBAAkB,8BAA8B;AACpE,MAAI,CAAC,WAAW,CAAC,YAAa,QAAO;AACrC,SAAO,EAAE,SAAS,YAAY;AAChC;AAMO,SAAS,cAAc,YAAkD;AAC9E,mBAAiB;AACjB,SAAO;AACT;AAEO,SAAS,uBAAiD;AAC/D,SAAO;AACT;AAGO,SAAS,sBAA+C;AAC7D,QAAM,UAAU,uBAAuB;AACvC,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,QAAM,OAAO,qBAAqB;AAClC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,iBAAiB,MAAM,mBAAmB,QAAQ;AAAA,EACpD;AACF;;;ACjEO,IAAM,4BAA4B;AAGlC,IAAM,mCAAmC;AAEhD,IAAI,+BAA+B;AACnC,IAAM,2BAA2B,oBAAI,IAAgB;AAErD,SAAS,4BAAqC;AAC5C,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AACA,MAAI;AACF,WACE,aAAa,QAAQ,gCAAgC,MAAM;AAAA,EAE/D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,8BAAuC;AACrD,SAAO;AACT;AAGO,SAAS,4BAA4B,UAAkC;AAC5E,2BAAyB,IAAI,QAAQ;AACrC,SAAO,MAAM;AACX,6BAAyB,OAAO,QAAQ;AAAA,EAC1C;AACF;AAMO,SAAS,sBAAsB,SAAwB;AAC5D,MAAI,iCAAiC,SAAS;AAC5C;AAAA,EACF;AACA,iCAA+B;AAC/B,MAAI,OAAO,WAAW,aAAa;AACjC,QAAI;AACF,mBAAa;AAAA,QACX;AAAA,QACA,UAAU,YAAY;AAAA,MACxB;AAAA,IACF,QAAQ;AAAA,IACR;AACA,QAAI,SAAS;AACX,gCAA0B,OAAO,SAAS,QAAQ;AAAA,IACpD;AAAA,EACF;AACA,aAAW,YAAY,0BAA0B;AAC/C,aAAS;AAAA,EACX;AACF;AA4QA,SAAS,8BAA6C;AACpD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AACA,SAAO,0BAA0B,OAAO,SAAS,QAAQ,EAAE;AAC7D;AAEA,SAAS,iBAAiB,UAAmC;AAC3D,MAAI,OAAO,WAAW,aAAa;AACjC;AAAA,EACF;AACA,QAAM,EAAE,IAAI,IAAI,0BAA0B,OAAO,SAAS,QAAQ;AAClE,aAAW,OAAO,oBAAoB;AACpC,QAAI,SAAS,GAAG,MAAM,UAAa,IAAI,GAAG,GAAG;AAC3C,eAAS,GAAG,IAAI,IAAI,GAAG;AAAA,IACzB;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,WAAyD;AACnF,QAAM,SAAS,UAAU,QAAQ,GAAG;AACpC,MAAI,WAAW,IAAI;AACjB,WAAO,EAAE,UAAU,aAAa,KAAK,QAAQ,GAAG;AAAA,EAClD;AACA,SAAO;AAAA,IACL,UAAU,UAAU,MAAM,GAAG,MAAM,KAAK;AAAA,IACxC,QAAQ,UAAU,MAAM,SAAS,CAAC;AAAA,EACpC;AACF;AAGA,SAAS,sBAAsB,MAAc;AAC3C,QAAM,IAAI,KAAK,UAAU;AACzB,SACE,EAAE,WAAW,IAAI,KACjB,EAAE,YAAY,EAAE,WAAW,OAAO,KACjC,EAAE,WAAW,GAAG,KAAK,cAAc,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC;AAE5D;AAEA,SAAS,iBAAiB,SAAiB;AACzC,SAAO,QAAQ,QAAQ,OAAO,EAAE;AAClC;AAEA,SAAS,UACP,SACA,KACe;AACf,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,MAAI,OAAQ,QAAiC,QAAQ,YAAY;AAC/D,WAAQ,QAAiC,IAAI,GAAG;AAAA,EAClD;AACA,QAAM,SAAS;AACf,QAAM,SAAS,OAAO,GAAG,KAAK,OAAO,IAAI,YAAY,CAAC;AACtD,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OAAO,CAAC,KAAK;AAAA,EACtB;AACA,SAAO,UAAU;AACnB;AAEA,SAAS,mBAAmB,KAAiC;AAC3D,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,WAAO,GAAG,EAAE,QAAQ,GAAG,EAAE,MAAM;AAAA,EACjC,QAAQ;AACN,WAAO,IAAI,WAAW,GAAG,IAAI,MAAM;AAAA,EACrC;AACF;AAEA,SAAS,cAAsB;AAC7B,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AACA,SAAO,OAAO,aAAa,MAAM,WAAW;AAC9C;AAKO,SAAS,mBAAmB,QAA4B;AAC7D,QAAM,UAAU,iBAAiB,OAAO,OAAO;AAC/C,QAAM,gBACJ,OAAO,cACN,OAAO,eAAe,eAAe,WAAW,QAC7C,WAAW,MAAM,KAAK,UAAU,IAChC;AAEN,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAwB;AAE9B,iCAA+B,OAAO,iBAClC,0BAA0B,IAC1B;AAEJ,WAAS,UAAmB;AAC1B,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB;AACrB,MAAI,eAAe;AAEnB,iBAAe,KAAK,MAA+B;AACjD,QAAI,CAAC,QAAQ,GAAG;AACd;AAAA,IACF;AAEA,UAAM,MAAM,GAAG,OAAO;AACtB,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,sBAAsB,OAAO;AAAA,IAC/B;AAEA,QAAI,KAAK,SAAS,eAAe,OAAO,WAAW,aAAa;AAC9D,YAAM,iBAAiB,4BAA4B;AACnD,UAAI,gBAAgB;AAClB,gBAAQ,uBAAuB,IAAI;AAAA,MACrC;AAAA,IACF;AAEA,UAAM,MAAM,gCAAgC;AAC5C,UAAM,UAAU,EAAE,GAAG,MAAM,GAAI,MAAM,EAAE,WAAW,IAAI,IAAI,CAAC,EAAG;AAE9D,QAAI,OAAO,OAAO;AAChB,cAAQ,MAAM,iCAAiC,QAAQ,KAAK,OAAO;AAAA,IACrE;AAEA,UAAM,MAAM,MAAM,QAAQ,KAAK;AAAA,MAC7B,QAAQ;AAAA,MACR;AAAA,MACA,MAAM,KAAK,UAAU,OAAO;AAAA,MAC5B,WAAW;AAAA,IACb,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,sBAAsB,IAAI,GAAG;AAC/B,cAAM,IAAI;AAAA,UACR,sBAAsB,IAAI,MAAM,WAAM,GAAG;AAAA,QAG3C;AAAA,MACF;AACA,UAAI,SAKA,CAAC;AACL,UAAI;AACF,iBAAS,KAAK,MAAM,IAAI;AAAA,MAC1B,QAAQ;AACN,iBAAS,EAAE,OAAO,KAAK;AAAA,MACzB;AACA,YAAM,SAAS,OAAO,SAAS;AAC/B,YAAM,WAAW;AAAA,QACf,sBAAsB,IAAI,MAAM;AAAA,QAChC,OAAO,OAAO,IAAI,OAAO,IAAI,MAAM;AAAA,QACnC;AAAA,QACA,OAAO,OAAO,SAAS,OAAO,IAAI,KAAK;AAAA,QACvC,OAAO,iBACH,wBAAwB,OAAO,cAAc,KAC7C;AAAA,MACN,EAAE,OAAO,OAAO;AAChB,YAAM,UAAU,SAAS,KAAK,UAAK;AACnC,UAAI,OAAO,OAAO;AAChB,gBAAQ,MAAM,iCAAiC,kBAAkB;AAAA,UAC/D,QAAQ,IAAI;AAAA,UACZ,GAAG;AAAA,UACH,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AACA,YAAM,IAAI,MAAM,OAAO;AAAA,IACzB;AAAA,EACF;AAEA,iBAAe,SAAS,MAA+B;AACrD,QAAI,CAAC,QAAQ,GAAG;AACd;AAAA,IACF;AAEA,UAAM,MAAM,GAAG,OAAO;AACtB,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,sBAAsB,OAAO;AAAA,IAC/B;AAEA,UAAM,MAAM,gCAAgC;AAC5C,UAAM,UAAU,EAAE,GAAG,MAAM,GAAI,MAAM,EAAE,WAAW,IAAI,IAAI,CAAC,EAAG;AAE9D,QAAI,OAAO,OAAO;AAChB,cAAQ,MAAM,iCAAiC,QAAQ,KAAK,OAAO;AAAA,IACrE;AAEA,UAAM,MAAM,MAAM,QAAQ,KAAK;AAAA,MAC7B,QAAQ;AAAA,MACR;AAAA,MACA,MAAM,KAAK,UAAU,OAAO;AAAA,MAC5B,WAAW;AAAA,IACb,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAI,sBAAsB,IAAI,GAAG;AAC/B,cAAM,IAAI;AAAA,UACR,sBAAsB,IAAI,MAAM,WAAM,GAAG;AAAA,QAE3C;AAAA,MACF;AACA,UAAI,SAKA,CAAC;AACL,UAAI;AACF,iBAAS,KAAK,MAAM,IAAI;AAAA,MAC1B,QAAQ;AACN,iBAAS,EAAE,OAAO,KAAK;AAAA,MACzB;AACA,YAAM,SAAS,OAAO,SAAS;AAC/B,YAAM,WAAW;AAAA,QACf,sBAAsB,IAAI,MAAM;AAAA,QAChC,OAAO,OAAO,IAAI,OAAO,IAAI,MAAM;AAAA,QACnC;AAAA,QACA,OAAO,OAAO,SAAS,OAAO,IAAI,KAAK;AAAA,QACvC,OAAO,iBACH,wBAAwB,OAAO,cAAc,KAC7C;AAAA,MACN,EAAE,OAAO,OAAO;AAChB,YAAM,UAAU,SAAS,KAAK,UAAK;AACnC,UAAI,OAAO,OAAO;AAChB,gBAAQ,MAAM,iCAAiC,kBAAkB;AAAA,UAC/D,QAAQ,IAAI;AAAA,UACZ,GAAG;AAAA,UACH,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AACA,YAAM,IAAI,MAAM,OAAO;AAAA,IACzB;AAAA,EACF;AAEA,WAAS,qBAAqB,MAAuB;AACnD,UAAM,KAAK,OAAO,oBAAoB;AACtC,QAAI,MAAM,KAAK,OAAO,WAAW,aAAa;AAC5C,aAAO;AAAA,IACT;AACA,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,SAAS,kBAAkB,MAAM,eAAe,IAAI;AACtD,aAAO;AAAA,IACT;AACA,qBAAiB;AACjB,mBAAe;AACf,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,SAAgC;AACrD,QAAI,CAAC,QAAQ,GAAG;AACd,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAEA,UAAM,kBAAkB,SAAS,MAAM,KAAK;AAC5C,QAAI,WAAW;AACf,QAAI,SAAS;AAEb,QAAI,iBAAiB;AACnB,YAAM,QAAQ,mBAAmB,eAAe;AAChD,iBAAW,MAAM;AACjB,eAAS,MAAM;AAAA,IACjB,WAAW,OAAO,WAAW,aAAa;AACxC,iBAAW,OAAO,SAAS;AAC3B,eAAS,OAAO,SAAS,OAAO,QAAQ,OAAO,EAAE;AAAA,IACnD;AAEA,QAAI,CAAC,UAAU,OAAO,WAAW,aAAa;AAC5C,eAAS,OAAO,SAAS,OAAO,QAAQ,OAAO,EAAE;AAAA,IACnD;AAEA,UAAM,OAAO,SAAS,GAAG,QAAQ,IAAI,MAAM,KAAK;AAEhD,QAAI,qBAAqB,QAAQ,GAAG;AAClC,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAEA,UAAM,WACJ,SAAS,YAAY,OAAO,QAAQ,aAAa,WAC7C,EAAE,GAAG,QAAQ,SAAS,IACtB,CAAC;AAEP,QAAI,OAAO,WAAW,aAAa;AACjC,eAAS,eAAe,OAAO,SAAS;AACxC,YAAM,SAAS,IAAI;AAAA,QACjB,SAAS,IAAI,MAAM,KAAK,OAAO,SAAS;AAAA,MAC1C;AACA,iBAAW,OAAO,oBAAoB;AACpC,cAAM,IAAI,OAAO,IAAI,GAAG;AACxB,YAAI,KAAK,SAAS,GAAG,MAAM,QAAW;AACpC,mBAAS,GAAG,IAAI;AAAA,QAClB;AAAA,MACF;AACA,uBAAiB,QAAQ;AACzB,YAAM,iBAAiB,4BAA4B;AACnD,UAAI,kBAAkB,SAAS,YAAY,QAAW;AACpD,iBAAS,UAAU;AAAA,MACrB;AAAA,IACF;AAEA,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,QAAQ,SAAS,UAAU,YAAY;AAAA,MACvC,SAAS,SAAS;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,gBACP,MACA,UACA;AACA,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,UAAU,YAAY,CAAC;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,WAAS,eACP,MACA,UACA;AACA,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,UAAU,YAAY,CAAC;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,WAAS,gBACP,MACA,UACA;AACA,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,UAAU,YAAY,CAAC;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,WAAS,kBACP,MACA,SAKA;AACA,UAAM,WAAoC;AAAA,MACxC,GAAI,QAAQ,YAAY,OAAO,QAAQ,aAAa,WAChD,QAAQ,WACR,CAAC;AAAA,MACL,SAAS,QAAQ;AAAA,IACnB;AACA,QAAI,QAAQ,UAAU;AACpB,eAAS,WAAW,QAAQ;AAAA,IAC9B;AACA,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,UAAU,SAA4B;AAC7C,UAAM,OACJ,SAAS,SACR,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW;AAE9D,UAAM,OAAgC,EAAE,MAAM,QAAQ,IAAI;AAC1D,QAAI,SAAS,KAAM,MAAK,OAAO,QAAQ;AACvC,QAAI,SAAS,MAAO,MAAK,QAAQ,QAAQ;AACzC,QAAI,SAAS,MAAO,MAAK,QAAQ,QAAQ;AACzC,QAAI,SAAS,QAAS,MAAK,UAAU,QAAQ;AAC7C,QAAI,SAAS,QAAS,MAAK,UAAU,QAAQ;AAC7C,QAAI,SAAS,QAAS,MAAK,UAAU,QAAQ;AAC7C,QAAI,SAAS,QAAS,MAAK,UAAU,QAAQ;AAC7C,QAAI,SAAS,YAAY,OAAO,QAAQ,aAAa,UAAU;AAC7D,WAAK,WAAW,QAAQ;AAAA,IAC1B;AACA,QAAI,SAAS,UAAW,MAAK,YAAY,QAAQ;AAEjD,WAAO,SAAS,IAAI;AAAA,EACtB;AAEA,WAAS,MACP,MACA,SAOA;AACA,QAAI,SAAS,aAAa;AACxB,aAAO,cAAc;AAAA,QACnB,MAAM,QAAQ;AAAA,QACd,QAAQ,QAAQ;AAAA,QAChB,QAAQ,QAAQ;AAAA,QAChB,SAAS,QAAQ;AAAA,QACjB,UAAU,QAAQ;AAAA,MACpB,CAAC;AAAA,IACH;AACA,QAAI,SAAS,eAAe;AAC1B,aAAO,gBAAgB,QAAQ,MAAM,QAAQ,QAAQ;AAAA,IACvD;AACA,QAAI,SAAS,cAAc;AACzB,aAAO,eAAe,QAAQ,MAAM,QAAQ,QAAQ;AAAA,IACtD;AACA,QAAI,SAAS,eAAe;AAC1B,aAAO,gBAAgB,QAAQ,MAAM,QAAQ,QAAQ;AAAA,IACvD;AACA,UAAM,OAAO,QAAQ,YAAY,CAAC;AAClC,UAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;AAClE,UAAM,WACJ,OAAO,KAAK,aAAa,WAAY,KAAK,WAAsB;AAClE,QACE,YAAY,SACZ,YAAY,cACZ,YAAY,UACZ,YAAY,WACZ;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB;AACA,WAAO,kBAAkB,QAAQ,MAAM;AAAA,MACrC;AAAA,MACA;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAOA,WAAS,2BAAuC;AAC9C,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,QAAI,WAAW,OAAO,SAAS;AAE/B,UAAM,MAAM,MAAM;AAChB,YAAM,OAAO,OAAO,SAAS;AAC7B,UAAI,SAAS,UAAU;AACrB,mBAAW;AACX,aAAK,cAAc,EAAE,KAAK,CAAC;AAAA,MAC7B;AAAA,IACF;AAEA,WAAO,iBAAiB,YAAY,GAAG;AAEvC,UAAM,OAAO,QAAQ,UAAU,KAAK,OAAO;AAC3C,UAAM,UAAU,QAAQ,aAAa,KAAK,OAAO;AAEjD,YAAQ,YAAY,IAAI,SAA2C;AACjE,YAAM,IAAI,KAAK,GAAG,IAAI;AACtB,qBAAe,GAAG;AAClB,aAAO;AAAA,IACT;AACA,YAAQ,eAAe,IAAI,SAA8C;AACvE,YAAM,IAAI,QAAQ,GAAG,IAAI;AACzB,qBAAe,GAAG;AAClB,aAAO;AAAA,IACT;AAEA,WAAO,MAAM;AACX,aAAO,oBAAoB,YAAY,GAAG;AAC1C,cAAQ,YAAY;AACpB,cAAQ,eAAe;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,sBAAsB;AAC1B,MAAI,qBAAqB;AAOzB,WAAS,gCAA4C;AACnD,QAAI,OAAO,WAAW,eAAe,OAAO,aAAa,aAAa;AACpE,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,UAAM,UAAU,CAAC,UAAsB;AACrC,UAAI,CAAC,QAAQ,GAAG;AACd;AAAA,MACF;AACA,YAAM,SAAS,MAAM;AACrB,UAAI,EAAE,kBAAkB,UAAU;AAChC;AAAA,MACF;AACA,YAAM,SAAS,OAAO,QAAQ,SAAS;AACvC,UAAI,EAAE,kBAAkB,oBAAoB;AAC1C;AAAA,MACF;AACA,UAAI,OAAO,QAAQ,qBAAqB,GAAG;AACzC;AAAA,MACF;AAEA,YAAM,OAAO,OAAO,aAAa,MAAM,KAAK;AAC5C,YAAM,aAAa,oBAAoB,IAAI;AAC3C,UAAI,CAAC,YAAY;AACf;AAAA,MACF;AAEA,YAAM,OAAO,OAAO,SAAS;AAE7B,UAAI,WAAW,SAAS,QAAQ;AAC9B,YAAI,mBAAmB,cAAc,IAAI,EAAE,GAAG;AAC5C;AAAA,QACF;AACA,aAAK,eAAe,IAAI;AACxB;AAAA,MACF;AACA,UAAI,WAAW,SAAS,SAAS;AAC/B,YAAI,mBAAmB,eAAe,IAAI,EAAE,GAAG;AAC7C;AAAA,QACF;AACA,aAAK,gBAAgB,IAAI;AACzB;AAAA,MACF;AACA,UAAI,mBAAmB,iBAAiB,WAAW,OAAO,IAAI,IAAI,EAAE,GAAG;AACrE;AAAA,MACF;AACA,WAAK,kBAAkB,MAAM;AAAA,QAC3B,SAAS,WAAW;AAAA,QACpB,UAAU,WAAW;AAAA,MACvB,CAAC;AAAA,IACH;AAEA,aAAS,iBAAiB,SAAS,SAAS,EAAE,SAAS,KAAK,CAAC;AAC7D,WAAO,MAAM;AACX,eAAS,oBAAoB,SAAS,SAAS,EAAE,SAAS,KAAK,CAAyB;AAAA,IAC1F;AAAA,EACF;AAEA,WAAS,mBAAmB,KAAsB;AAChD,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,QAAQ,uBAAuB,MAAM,qBAAqB,KAAM;AAClE,aAAO;AAAA,IACT;AACA,0BAAsB;AACtB,yBAAqB;AACrB,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,eAAe,QAAQ,GAAG;AAC9C,8BAA0B,OAAO,SAAS,QAAQ;AAAA,EACpD;AAEA,MACE,OAAO,WAAW,eAClB,OAAO,yBACP,QAAQ,GACR;AACA,kCAA8B;AAAA,EAChC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB;AAAA,IACpB,0BAA0B;AAAA,EAC5B;AACF;AAIA,eAAsB,uBACpB,QACA,UAAsC,CAAC,GACxB;AACf,QAAM,UAAU,iBAAiB,OAAO,OAAO;AAC/C,QAAM,gBACJ,OAAO,cACN,OAAO,eAAe,eAAe,WAAW,QAC7C,WAAW,MAAM,KAAK,UAAU,IAChC;AAEN,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,wEAAwE;AAAA,EAC1F;AAEA,QAAM,mBACJ,QAAQ,aAAa,UAAU,QAAQ,SAAS,SAAS,YAAY;AACvE,QAAM,iBACJ,QAAQ,WAAW,UAAU,QAAQ,SAAS,SAAS,SAAS;AAClE,QAAM,OAAO,QAAQ,QAAQ,mBAAmB,QAAQ,SAAS,GAAG;AAEpE,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,sBAAsB,OAAO;AAAA,EAC/B;AACA,MAAI,kBAAkB;AACpB,YAAQ,0BAA0B,IAAI;AAAA,EACxC;AACA,MAAI,gBAAgB;AAClB,YAAQ,uBAAuB,IAAI;AAAA,EACrC;AAEA,QAAM,UAAmC;AAAA,IACvC,MAAM;AAAA,IACN,MAAM,QAAQ;AAAA,IACd,UACE,QAAQ,YAAY,OAAO,QAAQ,aAAa,WAC5C,QAAQ,WACR,CAAC;AAAA,EACT;AACA,MAAI,QAAQ,WAAW;AACrB,YAAQ,YAAY,QAAQ;AAAA,EAC9B;AAEA,QAAM,MAAM,GAAG,OAAO;AACtB,MAAI,OAAO,OAAO;AAChB,YAAQ,MAAM,iCAAiC,QAAQ,KAAK,OAAO;AAAA,EACrE;AAEA,QAAM,MAAM,MAAM,cAAc,KAAK;AAAA,IACnC,QAAQ;AAAA,IACR;AAAA,IACA,MAAM,KAAK,UAAU,OAAO;AAAA,EAC9B,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,IAAI,MAAM,6BAA6B,IAAI,MAAM,WAAM,IAAI,EAAE;AAAA,EACrE;AACF;AAEA,eAAsB,gBACpB,QACwB;AACxB,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACA,SAAO,KAAK;AACd;AAEA,eAAsB,eACpB,QACA,MAC6B;AAC7B,MAAI;AACF,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA,qBAAqB,mBAAmB,IAAI,CAAC;AAAA,IAC/C;AACA,WAAO,KAAK;AAAA,EACd,SAAS,OAAO;AACd,QAAI,iBAAiB,SAAS,MAAM,QAAQ,SAAS,UAAU,GAAG;AAChE,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,WACpB,QACuB;AACvB,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACA,SAAO,KAAK;AACd;AAEA,eAAsB,kBACpB,QACyB;AACzB,SAAO,WAA2B,QAAQ,oBAAoB;AAChE;AAEA,eAAsB,kBACpB,QACyB;AACzB,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACA,SAAO,KAAK;AACd;AAEA,eAAsB,gBAAgB,QAA2C;AAC/E,SAAO,eAAe,QAAQ,qBAAqB;AACrD;AAEA,IAAM,4BAA4B,oBAAI,IAAY;AAElD,SAAS,iCACP,QACU;AACV,MAAI,OAAO,iBAAiB,QAAQ;AAClC,WAAO,CAAC,GAAG,OAAO,eAAe;AAAA,EACnC;AACA,SAAO,CAAC;AACV;AAMA,eAAsB,2BACpB,QAGA;AACA,QAAM,WAAW,iCAAiC,MAAM;AACxD,MAAI,CAAC,SAAS,QAAQ;AACpB,WAAO,EAAE,IAAI,OAAO,SAAS,KAAK;AAAA,EACpC;AAEA,QAAM,YAAY,GAAG,OAAO,WAAW,IAAI,CAAC,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC;AACzE,MAAI,0BAA0B,IAAI,SAAS,GAAG;AAC5C,WAAO,EAAE,IAAI,MAAM,SAAS;AAAA,EAC9B;AAEA,QAAM,UAAU,iBAAiB,OAAO,OAAO;AAC/C,QAAM,gBACJ,OAAO,cACN,OAAO,eAAe,eAAe,WAAW,QAC7C,WAAW,MAAM,KAAK,UAAU,IAChC;AAEN,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,GAAG,OAAO;AACtB,MAAI,OAAO,OAAO;AAChB,YAAQ,MAAM,iCAAiC,QAAQ,KAAK,EAAE,SAAS,CAAC;AAAA,EAC1E;AAEA,QAAM,MAAM,MAAM,cAAc,KAAK;AAAA,IACnC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,sBAAsB,OAAO;AAAA,IAC/B;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,YAAY;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AAED,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,SAA4C,CAAC;AACjD,QAAI;AACF,eAAS,KAAK,MAAM,IAAI;AAAA,IAC1B,QAAQ;AACN,eAAS,EAAE,OAAO,KAAK;AAAA,IACzB;AACA,UAAM,IAAI;AAAA,MACR,CAAC,6BAA6B,IAAI,MAAM,IAAI,OAAO,OAAO,OAAO,IAAI,EAClE,OAAO,OAAO,EACd,KAAK,UAAK;AAAA,IACf;AAAA,EACF;AAEA,4BAA0B,IAAI,SAAS;AACvC,QAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,SAAO,EAAE,IAAI,MAAM,UAAU,KAAK,YAAY,SAAS;AACzD;AAEO,SAAS,uBAAuB,QAA0B;AAC/D,SAAO;AAAA,IACL,cAAc,MAAM,gBAAgB,MAAM;AAAA,IAC1C,aAAa,CAAC,SAAiB,eAAe,QAAQ,IAAI;AAAA,IAC1D,SAAS,MAAM,WAAW,MAAM;AAAA,IAChC,gBAAgB,MAAM,kBAAkB,MAAM;AAAA,IAC9C,gBAAgB,MAAM,kBAAkB,MAAM;AAAA,IAC9C,cAAc,MAAM,gBAAgB,MAAM;AAAA,IAC1C,yBAAyB,MAAM,2BAA2B,MAAM;AAAA,EAClE;AACF;AAEA,eAAe,WACb,QACA,MACY;AACZ,QAAM,OAAO,MAAM,eAAe,QAAQ,IAAI;AAE9C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,UAAM,UAAU,iBAAiB,OAAO,OAAO;AAC/C,UAAM,MAAM,GAAG,OAAO,GAAG,IAAI;AAC7B,UAAM,IAAI,MAAM,+BAA0B,GAAG,yBAAyB;AAAA,EACxE;AACF;AAEA,eAAe,eACb,QACA,MACiB;AACjB,QAAM,UAAU,iBAAiB,OAAO,OAAO;AAC/C,QAAM,gBACJ,OAAO,cACN,OAAO,eAAe,eAAe,WAAW,QAC7C,WAAW,MAAM,KAAK,UAAU,IAChC;AAEN,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,+DAA+D;AAAA,EACjF;AAEA,QAAM,MAAM,GAAG,OAAO,GAAG,IAAI;AAE7B,MAAI,OAAO,OAAO;AAChB,YAAQ,MAAM,iCAAiC,OAAO,GAAG;AAAA,EAC3D;AAEA,QAAM,MAAM,MAAM,cAAc,KAAK;AAAA,IACnC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,sBAAsB,OAAO;AAAA,IAC/B;AAAA,EACF,CAAC;AAED,QAAM,OAAO,MAAM,IAAI,KAAK;AAE5B,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,sBAAsB,IAAI,GAAG;AAC/B,YAAM,IAAI;AAAA,QACR,oBAAoB,IAAI,MAAM,WAAM,GAAG;AAAA,MAEzC;AAAA,IACF;AAEA,QAAI,SAA4C,CAAC;AACjD,QAAI;AACF,eAAS,KAAK,MAAM,IAAI;AAAA,IAC1B,QAAQ;AACN,eAAS,EAAE,OAAO,KAAK;AAAA,IACzB;AAEA,UAAM,IAAI;AAAA,MACR,CAAC,oBAAoB,IAAI,MAAM,IAAI,OAAO,OAAO,OAAO,IAAI,EACzD,OAAO,OAAO,EACd,KAAK,UAAK;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AACT;AAGO,IAAM,0CAA0C;AAMvD,SAASA,mBACP,KAKoB;AACpB,MAAI,OAAO,YAAY,eAAe,CAAC,QAAQ,IAAK,QAAO;AAE3D,MAAI;AACJ,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,UAAI,QAAQ,IAAI;AAChB;AAAA,IACF,KAAK;AACH,UAAI,QAAQ,IAAI;AAChB;AAAA,IACF,KAAK;AACH,UAAI,QAAQ,IAAI;AAChB;AAAA,IACF,KAAK;AACH,UAAI,QAAQ,IAAI;AAChB;AAAA,EACJ;AAEA,SAAO,OAAO,MAAM,YAAY,EAAE,SAAS,IAAI,IAAI;AACrD;AAMO,SAAS,oCACd,WAC2B;AAC3B,QAAM,UAAUA,mBAAkB,+BAA+B;AACjE,QAAM,cAAcA,mBAAkB,8BAA8B;AACpE,MAAI,CAAC,WAAW,CAAC,YAAa,QAAO;AACrC,QAAM,wBACJA,mBAAkB,2CAA2C,MAAM;AACrE,QAAM,+BACJA,mBAAkB,oCAAoC,MAAM;AAC9D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB,GAAG;AAAA,IACH,gBAAgB,WAAW,kBAAkB;AAAA,IAC7C,uBACE,WAAW,yBAAyB;AAAA,EACxC;AACF;AAQO,SAAS,iCACd,WACyB;AACzB,QAAM,UAAUA,mBAAkB,+BAA+B;AACjE,QAAM,cAAcA,mBAAkB,8BAA8B;AACpE,MAAI,CAAC,WAAW,CAAC,YAAa,QAAO;AACrC,SAAO,EAAE,SAAS,aAAa,GAAG,UAAU;AAC9C;AAEO,SAAS,qCAA8C;AAC5D,SAAO;AAAA,IACLA,mBAAkB,+BAA+B,KAC/CA,mBAAkB,8BAA8B;AAAA,EACpD;AACF;AAEO,SAAS,kCAA2C;AACzD,SAAO,mCAAmC;AAC5C;AAEA,IAAI,+BAAoD;AAMjD,SAAS,sCACd,WACqB;AACrB,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,MAAI,6BAA8B,QAAO;AACzC,QAAM,SAAS,oCAAoC,SAAS;AAC5D,MAAI,CAAC,OAAQ,QAAO;AACpB,iCAA+B,mBAAmB,MAAM;AACxD,SAAO;AACT;AAOO,SAAS,oCACd,WACyB;AACzB,QAAM,SAAS,iCAAiC,SAAS;AACzD,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,uBAAuB,MAAM;AACtC;","names":["readNextPublicEnv"]}
|
package/dist/index.cjs
CHANGED
|
@@ -29,12 +29,15 @@ __export(index_exports, {
|
|
|
29
29
|
createJmpAnalytics: () => createJmpAnalytics,
|
|
30
30
|
createJmpContentClient: () => createJmpContentClient,
|
|
31
31
|
createJmpContentClientFromServerEnv: () => createJmpContentClientFromServerEnv,
|
|
32
|
+
defineJmpSite: () => defineJmpSite,
|
|
32
33
|
getJmpBlogPost: () => getJmpBlogPost,
|
|
33
34
|
getJmpBlogPosts: () => getJmpBlogPosts,
|
|
34
35
|
getJmpBrowserAnalyticsConfigFromEnv: () => getJmpBrowserAnalyticsConfigFromEnv,
|
|
36
|
+
getJmpContentConfig: () => getJmpContentConfig,
|
|
35
37
|
getJmpFaqs: () => getJmpFaqs,
|
|
36
38
|
getJmpRobotsTxt: () => getJmpRobotsTxt,
|
|
37
39
|
getJmpServerContentConfigFromEnv: () => getJmpServerContentConfigFromEnv,
|
|
40
|
+
getJmpSiteDefinition: () => getJmpSiteDefinition,
|
|
38
41
|
getJmpSiteProfile: () => getJmpSiteProfile,
|
|
39
42
|
getJmpTrustBundle: () => getJmpTrustBundle,
|
|
40
43
|
getOrCreateJmpAnalyticsFromBrowserEnv: () => getOrCreateJmpAnalyticsFromBrowserEnv,
|
|
@@ -42,7 +45,6 @@ __export(index_exports, {
|
|
|
42
45
|
isJmpServerContentEnvConfigured: () => isJmpServerContentEnvConfigured,
|
|
43
46
|
isJmpTrackingConsentGranted: () => isJmpTrackingConsentGranted,
|
|
44
47
|
registerJmpContentWrappers: () => registerJmpContentWrappers,
|
|
45
|
-
registerJmpTrustCapabilities: () => registerJmpTrustCapabilities,
|
|
46
48
|
setJmpTrackingConsent: () => setJmpTrackingConsent,
|
|
47
49
|
subscribeJmpTrackingConsent: () => subscribeJmpTrackingConsent,
|
|
48
50
|
trackJmpServerPageView: () => trackJmpServerPageView
|
|
@@ -310,8 +312,40 @@ function classifyContactHref(href) {
|
|
|
310
312
|
return null;
|
|
311
313
|
}
|
|
312
314
|
|
|
315
|
+
// src/site-config.ts
|
|
316
|
+
var registeredSite = null;
|
|
317
|
+
function readNextPublicEnv(key) {
|
|
318
|
+
if (typeof process === "undefined" || !process.env) return void 0;
|
|
319
|
+
const v = key === "NEXT_PUBLIC_JMP_ANALYTICS_URL" ? process.env.NEXT_PUBLIC_JMP_ANALYTICS_URL : process.env.NEXT_PUBLIC_JMP_TRACKING_KEY;
|
|
320
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
321
|
+
}
|
|
322
|
+
function getServerConfigFromEnv() {
|
|
323
|
+
const baseUrl = readNextPublicEnv("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
324
|
+
const trackingKey = readNextPublicEnv("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
325
|
+
if (!baseUrl || !trackingKey) return null;
|
|
326
|
+
return { baseUrl, trackingKey };
|
|
327
|
+
}
|
|
328
|
+
function defineJmpSite(definition) {
|
|
329
|
+
registeredSite = definition;
|
|
330
|
+
return definition;
|
|
331
|
+
}
|
|
332
|
+
function getJmpSiteDefinition() {
|
|
333
|
+
return registeredSite;
|
|
334
|
+
}
|
|
335
|
+
function getJmpContentConfig() {
|
|
336
|
+
const fromEnv = getServerConfigFromEnv();
|
|
337
|
+
if (!fromEnv) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
const site = getJmpSiteDefinition();
|
|
341
|
+
return {
|
|
342
|
+
...fromEnv,
|
|
343
|
+
contentWrappers: site?.contentWrappers ?? fromEnv.contentWrappers
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
313
347
|
// src/index.ts
|
|
314
|
-
var JMP_ANALYTICS_SDK_VERSION = "0.1.
|
|
348
|
+
var JMP_ANALYTICS_SDK_VERSION = "0.1.19";
|
|
315
349
|
var JMP_TRACKING_CONSENT_STORAGE_KEY = "jmp_analytics_consent_v1";
|
|
316
350
|
var moduleTrackingConsentGranted = true;
|
|
317
351
|
var trackingConsentListeners = /* @__PURE__ */ new Set();
|
|
@@ -891,11 +925,6 @@ function resolveContentWrappersFromConfig(config) {
|
|
|
891
925
|
if (config.contentWrappers?.length) {
|
|
892
926
|
return [...config.contentWrappers];
|
|
893
927
|
}
|
|
894
|
-
if (config.trustSlots?.length) {
|
|
895
|
-
return config.trustSlots.map(
|
|
896
|
-
(slot) => `trust.${slot}`
|
|
897
|
-
);
|
|
898
|
-
}
|
|
899
928
|
return [];
|
|
900
929
|
}
|
|
901
930
|
async function registerJmpContentWrappers(config) {
|
|
@@ -945,18 +974,6 @@ async function registerJmpContentWrappers(config) {
|
|
|
945
974
|
const data = JSON.parse(text);
|
|
946
975
|
return { ok: true, wrappers: data.wrappers ?? wrappers };
|
|
947
976
|
}
|
|
948
|
-
async function registerJmpTrustCapabilities(config) {
|
|
949
|
-
const result = await registerJmpContentWrappers(config);
|
|
950
|
-
if (!result.ok) {
|
|
951
|
-
return result;
|
|
952
|
-
}
|
|
953
|
-
const slots = result.wrappers.filter((w) => w === "trust" || w.startsWith("trust.")).map((w) => w === "trust" ? "summary" : w.slice("trust.".length)).filter(
|
|
954
|
-
(s) => ["summary", "testimonials", "reviews", "stats", "logos", "credentials"].includes(
|
|
955
|
-
s
|
|
956
|
-
)
|
|
957
|
-
);
|
|
958
|
-
return { ok: true, slots };
|
|
959
|
-
}
|
|
960
977
|
function createJmpContentClient(config) {
|
|
961
978
|
return {
|
|
962
979
|
getBlogPosts: () => getJmpBlogPosts(config),
|
|
@@ -965,9 +982,7 @@ function createJmpContentClient(config) {
|
|
|
965
982
|
getTrustBundle: () => getJmpTrustBundle(config),
|
|
966
983
|
getSiteProfile: () => getJmpSiteProfile(config),
|
|
967
984
|
getRobotsTxt: () => getJmpRobotsTxt(config),
|
|
968
|
-
registerContentWrappers: () => registerJmpContentWrappers(config)
|
|
969
|
-
/** @deprecated Use registerContentWrappers */
|
|
970
|
-
registerTrustCapabilities: () => registerJmpTrustCapabilities(config)
|
|
985
|
+
registerContentWrappers: () => registerJmpContentWrappers(config)
|
|
971
986
|
};
|
|
972
987
|
}
|
|
973
988
|
async function getContent(config, path) {
|
|
@@ -1016,17 +1031,31 @@ async function getContentText(config, path) {
|
|
|
1016
1031
|
return text;
|
|
1017
1032
|
}
|
|
1018
1033
|
var DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS = 800;
|
|
1019
|
-
function
|
|
1034
|
+
function readNextPublicEnv2(key) {
|
|
1020
1035
|
if (typeof process === "undefined" || !process.env) return void 0;
|
|
1021
|
-
|
|
1036
|
+
let v;
|
|
1037
|
+
switch (key) {
|
|
1038
|
+
case "NEXT_PUBLIC_JMP_ANALYTICS_URL":
|
|
1039
|
+
v = process.env.NEXT_PUBLIC_JMP_ANALYTICS_URL;
|
|
1040
|
+
break;
|
|
1041
|
+
case "NEXT_PUBLIC_JMP_TRACKING_KEY":
|
|
1042
|
+
v = process.env.NEXT_PUBLIC_JMP_TRACKING_KEY;
|
|
1043
|
+
break;
|
|
1044
|
+
case "NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT":
|
|
1045
|
+
v = process.env.NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT;
|
|
1046
|
+
break;
|
|
1047
|
+
case "NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS":
|
|
1048
|
+
v = process.env.NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS;
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1022
1051
|
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
1023
1052
|
}
|
|
1024
1053
|
function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
|
|
1025
|
-
const baseUrl =
|
|
1026
|
-
const trackingKey =
|
|
1054
|
+
const baseUrl = readNextPublicEnv2("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
1055
|
+
const trackingKey = readNextPublicEnv2("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
1027
1056
|
if (!baseUrl || !trackingKey) return null;
|
|
1028
|
-
const requireConsentFromEnv =
|
|
1029
|
-
const autoTrackContactLinksFromEnv =
|
|
1057
|
+
const requireConsentFromEnv = readNextPublicEnv2("NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT") === "true";
|
|
1058
|
+
const autoTrackContactLinksFromEnv = readNextPublicEnv2("NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS") === "true";
|
|
1030
1059
|
return {
|
|
1031
1060
|
baseUrl,
|
|
1032
1061
|
trackingKey,
|
|
@@ -1037,14 +1066,14 @@ function getJmpBrowserAnalyticsConfigFromEnv(overrides) {
|
|
|
1037
1066
|
};
|
|
1038
1067
|
}
|
|
1039
1068
|
function getJmpServerContentConfigFromEnv(overrides) {
|
|
1040
|
-
const baseUrl =
|
|
1041
|
-
const trackingKey =
|
|
1069
|
+
const baseUrl = readNextPublicEnv2("NEXT_PUBLIC_JMP_ANALYTICS_URL");
|
|
1070
|
+
const trackingKey = readNextPublicEnv2("NEXT_PUBLIC_JMP_TRACKING_KEY");
|
|
1042
1071
|
if (!baseUrl || !trackingKey) return null;
|
|
1043
1072
|
return { baseUrl, trackingKey, ...overrides };
|
|
1044
1073
|
}
|
|
1045
1074
|
function isJmpBrowserAnalyticsEnvConfigured() {
|
|
1046
1075
|
return Boolean(
|
|
1047
|
-
|
|
1076
|
+
readNextPublicEnv2("NEXT_PUBLIC_JMP_ANALYTICS_URL") && readNextPublicEnv2("NEXT_PUBLIC_JMP_TRACKING_KEY")
|
|
1048
1077
|
);
|
|
1049
1078
|
}
|
|
1050
1079
|
function isJmpServerContentEnvConfigured() {
|
|
@@ -1075,12 +1104,15 @@ function createJmpContentClientFromServerEnv(overrides) {
|
|
|
1075
1104
|
createJmpAnalytics,
|
|
1076
1105
|
createJmpContentClient,
|
|
1077
1106
|
createJmpContentClientFromServerEnv,
|
|
1107
|
+
defineJmpSite,
|
|
1078
1108
|
getJmpBlogPost,
|
|
1079
1109
|
getJmpBlogPosts,
|
|
1080
1110
|
getJmpBrowserAnalyticsConfigFromEnv,
|
|
1111
|
+
getJmpContentConfig,
|
|
1081
1112
|
getJmpFaqs,
|
|
1082
1113
|
getJmpRobotsTxt,
|
|
1083
1114
|
getJmpServerContentConfigFromEnv,
|
|
1115
|
+
getJmpSiteDefinition,
|
|
1084
1116
|
getJmpSiteProfile,
|
|
1085
1117
|
getJmpTrustBundle,
|
|
1086
1118
|
getOrCreateJmpAnalyticsFromBrowserEnv,
|
|
@@ -1088,7 +1120,6 @@ function createJmpContentClientFromServerEnv(overrides) {
|
|
|
1088
1120
|
isJmpServerContentEnvConfigured,
|
|
1089
1121
|
isJmpTrackingConsentGranted,
|
|
1090
1122
|
registerJmpContentWrappers,
|
|
1091
|
-
registerJmpTrustCapabilities,
|
|
1092
1123
|
setJmpTrackingConsent,
|
|
1093
1124
|
subscribeJmpTrackingConsent,
|
|
1094
1125
|
trackJmpServerPageView
|