@jmp-technologies/analytics 0.1.26 → 0.1.30

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.
Files changed (86) hide show
  1. package/README.md +43 -0
  2. package/bin/jmp-init.mjs +34 -0
  3. package/dist/astro/client.cjs +227 -10
  4. package/dist/astro/client.cjs.map +1 -1
  5. package/dist/astro/client.d.cts +2 -2
  6. package/dist/astro/client.d.ts +2 -2
  7. package/dist/astro/client.js +2 -2
  8. package/dist/astro/content.cjs +340 -14
  9. package/dist/astro/content.cjs.map +1 -1
  10. package/dist/astro/content.d.cts +16 -3
  11. package/dist/astro/content.d.ts +16 -3
  12. package/dist/astro/content.js +11 -3
  13. package/dist/astro/integration.cjs +229 -11
  14. package/dist/astro/integration.cjs.map +1 -1
  15. package/dist/astro/integration.js +3 -3
  16. package/dist/astro/middleware.cjs +2 -1
  17. package/dist/astro/middleware.cjs.map +1 -1
  18. package/dist/astro/middleware.d.cts +2 -2
  19. package/dist/astro/middleware.d.ts +2 -2
  20. package/dist/astro/middleware.js +2 -2
  21. package/dist/astro/register.cjs +229 -11
  22. package/dist/astro/register.cjs.map +1 -1
  23. package/dist/astro/register.js +3 -3
  24. package/dist/{chunk-A4RRTY5D.js → chunk-AIFJ7DVO.js} +3 -2
  25. package/dist/{chunk-A4RRTY5D.js.map → chunk-AIFJ7DVO.js.map} +1 -1
  26. package/dist/{chunk-TFHOTBOL.js → chunk-FS4BZ7DR.js} +66 -6
  27. package/dist/chunk-FS4BZ7DR.js.map +1 -0
  28. package/dist/{chunk-RCOHQAGL.js → chunk-GTPKRBFR.js} +284 -12
  29. package/dist/chunk-GTPKRBFR.js.map +1 -0
  30. package/dist/{chunk-HODG4NJQ.js → chunk-HFLU7HQE.js} +2 -2
  31. package/dist/{chunk-WFTTIRDJ.js → chunk-LLTB7ZFC.js} +2 -2
  32. package/dist/{chunk-PKGUBYZR.js → chunk-LTPLLPOR.js} +3 -3
  33. package/dist/{chunk-XQZOGWF2.js → chunk-ZEC22LFP.js} +3 -3
  34. package/dist/{create-jmp-analytics-JKAsJAWb.d.ts → create-jmp-analytics-BeuuU6as.d.ts} +1 -1
  35. package/dist/{create-jmp-analytics-Mau-oxji.d.cts → create-jmp-analytics-Ce2CrhhR.d.cts} +1 -1
  36. package/dist/index.cjs +289 -11
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +16 -7
  39. package/dist/index.d.ts +16 -7
  40. package/dist/index.js +12 -2
  41. package/dist/next/content.cjs +343 -14
  42. package/dist/next/content.cjs.map +1 -1
  43. package/dist/next/content.d.cts +8 -5
  44. package/dist/next/content.d.ts +8 -5
  45. package/dist/next/content.js +14 -3
  46. package/dist/next/content.js.map +1 -1
  47. package/dist/next/instrumentation.cjs +229 -11
  48. package/dist/next/instrumentation.cjs.map +1 -1
  49. package/dist/next/instrumentation.js +2 -2
  50. package/dist/next/landing-pages.cjs +875 -0
  51. package/dist/next/landing-pages.cjs.map +1 -0
  52. package/dist/next/landing-pages.d.cts +103 -0
  53. package/dist/next/landing-pages.d.ts +103 -0
  54. package/dist/next/landing-pages.js +297 -0
  55. package/dist/next/landing-pages.js.map +1 -0
  56. package/dist/next/middleware.cjs +2 -1
  57. package/dist/next/middleware.cjs.map +1 -1
  58. package/dist/next/middleware.d.cts +2 -2
  59. package/dist/next/middleware.d.ts +2 -2
  60. package/dist/next/middleware.js +2 -2
  61. package/dist/next/site-root-server.cjs +229 -11
  62. package/dist/next/site-root-server.cjs.map +1 -1
  63. package/dist/next/site-root-server.js +4 -4
  64. package/dist/next.cjs +227 -10
  65. package/dist/next.cjs.map +1 -1
  66. package/dist/next.d.cts +3 -3
  67. package/dist/next.d.ts +3 -3
  68. package/dist/next.js +4 -4
  69. package/dist/react.cjs +227 -10
  70. package/dist/react.cjs.map +1 -1
  71. package/dist/react.d.cts +2 -2
  72. package/dist/react.d.ts +2 -2
  73. package/dist/react.js +3 -3
  74. package/dist/{site-config-CXUdGLqw.d.cts → site-config-B4uEj4xX.d.ts} +22 -2
  75. package/dist/{site-config-w_Db9YSk.d.ts → site-config-DIFmnwqv.d.cts} +22 -2
  76. package/dist/{track-page-view-CkuSYuco.d.cts → track-page-view-Bv0BAvxG.d.cts} +1 -1
  77. package/dist/{track-page-view-QRSk8vap.d.ts → track-page-view-CkgIp9-j.d.ts} +1 -1
  78. package/dist/{types-C1eq8E5u.d.ts → types-B2iP79lb.d.cts} +99 -2
  79. package/dist/{types-C1eq8E5u.d.cts → types-B2iP79lb.d.ts} +99 -2
  80. package/package.json +11 -2
  81. package/dist/chunk-RCOHQAGL.js.map +0 -1
  82. package/dist/chunk-TFHOTBOL.js.map +0 -1
  83. /package/dist/{chunk-HODG4NJQ.js.map → chunk-HFLU7HQE.js.map} +0 -0
  84. /package/dist/{chunk-WFTTIRDJ.js.map → chunk-LLTB7ZFC.js.map} +0 -0
  85. /package/dist/{chunk-PKGUBYZR.js.map → chunk-LTPLLPOR.js.map} +0 -0
  86. /package/dist/{chunk-XQZOGWF2.js.map → chunk-ZEC22LFP.js.map} +0 -0
package/dist/index.js CHANGED
@@ -12,6 +12,9 @@ import {
12
12
  getJmpBlogPosts,
13
13
  getJmpBrowserAnalyticsConfigFromEnv,
14
14
  getJmpFaqs,
15
+ getJmpLandingPageDetail,
16
+ getJmpLandingPageSitemap,
17
+ getJmpLandingPages,
15
18
  getJmpRobotsTxt,
16
19
  getJmpServerContentConfigFromEnv,
17
20
  getJmpSiteProfile,
@@ -22,11 +25,13 @@ import {
22
25
  isJmpServerContentEnvConfigured,
23
26
  isJmpTrackingConsentGranted,
24
27
  markContentWrapper,
28
+ normalizeJmpContentManifest,
25
29
  registerJmpContentWrappers,
26
30
  resetContentWrapperDiscoveryForTests,
27
31
  setJmpTrackingConsent,
32
+ stableJmpManifestFingerprint,
28
33
  subscribeJmpTrackingConsent
29
- } from "./chunk-RCOHQAGL.js";
34
+ } from "./chunk-GTPKRBFR.js";
30
35
  import {
31
36
  buildLandingCaptureInlineScript
32
37
  } from "./chunk-TCZ6TC2L.js";
@@ -36,7 +41,7 @@ import {
36
41
  getJmpSiteDefinition,
37
42
  readJmpPublicEnvFromProcess,
38
43
  trackJmpServerPageView
39
- } from "./chunk-A4RRTY5D.js";
44
+ } from "./chunk-AIFJ7DVO.js";
40
45
  export {
41
46
  BOOKING_LINK_HOSTS,
42
47
  DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS,
@@ -54,6 +59,9 @@ export {
54
59
  getJmpBrowserAnalyticsConfigFromEnv,
55
60
  getJmpContentConfig,
56
61
  getJmpFaqs,
62
+ getJmpLandingPageDetail,
63
+ getJmpLandingPageSitemap,
64
+ getJmpLandingPages,
57
65
  getJmpRobotsTxt,
58
66
  getJmpServerContentConfigFromEnv,
59
67
  getJmpSiteDefinition,
@@ -65,10 +73,12 @@ export {
65
73
  isJmpServerContentEnvConfigured,
66
74
  isJmpTrackingConsentGranted,
67
75
  markContentWrapper,
76
+ normalizeJmpContentManifest,
68
77
  readJmpPublicEnvFromProcess,
69
78
  registerJmpContentWrappers,
70
79
  resetContentWrapperDiscoveryForTests,
71
80
  setJmpTrackingConsent,
81
+ stableJmpManifestFingerprint,
72
82
  subscribeJmpTrackingConsent,
73
83
  trackJmpServerPageView
74
84
  };
@@ -24,10 +24,14 @@ __export(content_exports, {
24
24
  filterFeaturedTrustQuotes: () => filterFeaturedTrustQuotes2,
25
25
  getJmpContentConfig: () => getJmpContentConfig,
26
26
  getResolvedSiteContact: () => getResolvedSiteContact2,
27
+ listResolvedSocialUrls: () => listResolvedSocialUrls,
27
28
  loadBlogPost: () => loadBlogPost2,
28
29
  loadBlogPosts: () => loadBlogPosts2,
29
30
  loadFaqBySlug: () => loadFaqBySlug2,
30
31
  loadFaqs: () => loadFaqs2,
32
+ loadLandingPageDetail: () => loadLandingPageDetail2,
33
+ loadLandingPageSitemap: () => loadLandingPageSitemap2,
34
+ loadLandingPages: () => loadLandingPages2,
31
35
  loadSiteProfile: () => loadSiteProfile2,
32
36
  loadTrustBundle: () => loadTrustBundle2,
33
37
  resolveSiteContact: () => resolveSiteContact2
@@ -39,7 +43,7 @@ var import_react = require("react");
39
43
  var LANDING_REFERER_COOKIE_MAX_AGE_SEC = 30 * 60;
40
44
 
41
45
  // src/constants.ts
42
- var JMP_ANALYTICS_SDK_VERSION = "0.1.25";
46
+ var JMP_ANALYTICS_SDK_VERSION = "0.1.26";
43
47
 
44
48
  // src/http.ts
45
49
  function responseLooksLikeHtml(body) {
@@ -50,6 +54,209 @@ function normalizeBaseUrl(baseUrl) {
50
54
  return baseUrl.replace(/\/$/, "");
51
55
  }
52
56
 
57
+ // src/content/manifest.ts
58
+ var JMP_CONTENT_MANIFEST_VERSION = 1;
59
+ var TRUST_SECTIONS = /* @__PURE__ */ new Set([
60
+ "summary",
61
+ "testimonials",
62
+ "reviews",
63
+ "stats",
64
+ "logos",
65
+ "credentials"
66
+ ]);
67
+ function normalizeKey(value) {
68
+ return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
69
+ }
70
+ function isValidExtraKey(key) {
71
+ return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(key);
72
+ }
73
+ var MAX_EXTERNAL_ADMIN_LINKS = 10;
74
+ var MAX_EXTERNAL_ADMIN_LINK_LABEL_LENGTH = 80;
75
+ var EXTERNAL_ADMIN_LINK_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
76
+ function tryNormalizeHttpUrl(input) {
77
+ if (typeof input !== "string" || !input.trim()) {
78
+ return null;
79
+ }
80
+ try {
81
+ const url = new URL(input.trim());
82
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
83
+ return null;
84
+ }
85
+ return url.toString().replace(/\/$/, "");
86
+ } catch {
87
+ return null;
88
+ }
89
+ }
90
+ function normalizeShopifyExternalSource(shopify) {
91
+ if (!shopify || typeof shopify !== "object") {
92
+ return null;
93
+ }
94
+ const adminUrl = tryNormalizeHttpUrl(shopify.adminUrl);
95
+ const storeUrl = tryNormalizeHttpUrl(shopify.storeUrl);
96
+ if (!adminUrl && !storeUrl) {
97
+ return null;
98
+ }
99
+ return {
100
+ ...adminUrl ? { adminUrl } : {},
101
+ ...storeUrl ? { storeUrl } : {}
102
+ };
103
+ }
104
+ function normalizeExternalAdminLinkEntries(links) {
105
+ if (!Array.isArray(links)) {
106
+ return [];
107
+ }
108
+ const seenIds = /* @__PURE__ */ new Set();
109
+ const out = [];
110
+ for (const raw of links) {
111
+ if (!raw || typeof raw !== "object" || out.length >= MAX_EXTERNAL_ADMIN_LINKS) {
112
+ continue;
113
+ }
114
+ const id = typeof raw.id === "string" ? raw.id.trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") : "";
115
+ const label = typeof raw.label === "string" ? raw.label.trim().slice(0, MAX_EXTERNAL_ADMIN_LINK_LABEL_LENGTH) : "";
116
+ const url = tryNormalizeHttpUrl(raw.url);
117
+ if (!id || !label || !url || !EXTERNAL_ADMIN_LINK_ID_PATTERN.test(id) || seenIds.has(id)) {
118
+ continue;
119
+ }
120
+ seenIds.add(id);
121
+ out.push({ id, label, url });
122
+ }
123
+ return out;
124
+ }
125
+ function normalizeExternalSources(externalSources) {
126
+ if (!externalSources || typeof externalSources !== "object") {
127
+ return null;
128
+ }
129
+ const studioUrl = tryNormalizeHttpUrl(externalSources.sanity?.studioUrl);
130
+ const shopify = normalizeShopifyExternalSource(externalSources.shopify);
131
+ const links = normalizeExternalAdminLinkEntries(externalSources.links);
132
+ if (!studioUrl && !shopify && links.length === 0) {
133
+ return null;
134
+ }
135
+ return {
136
+ ...studioUrl ? { sanity: { studioUrl } } : {},
137
+ ...shopify ? { shopify } : {},
138
+ ...links.length > 0 ? { links } : {}
139
+ };
140
+ }
141
+ function normalizeJmpContentManifest(input) {
142
+ if (!input || typeof input !== "object") {
143
+ return null;
144
+ }
145
+ const routes = normalizeRoutes(input.routes);
146
+ const externalSources = normalizeExternalSources(input.externalSources);
147
+ const trust = normalizeTrust(input.trust);
148
+ const contact = normalizeContact(input.contact);
149
+ if (routes.length === 0 && !externalSources && !trust && !contact) {
150
+ return null;
151
+ }
152
+ return {
153
+ version: JMP_CONTENT_MANIFEST_VERSION,
154
+ ...routes.length > 0 ? { routes } : {},
155
+ ...externalSources ? { externalSources } : {},
156
+ ...trust ? { trust } : {},
157
+ ...contact ? { contact } : {}
158
+ };
159
+ }
160
+ function normalizeRoutes(routes) {
161
+ if (!Array.isArray(routes)) {
162
+ return [];
163
+ }
164
+ const seen = /* @__PURE__ */ new Set();
165
+ const out = [];
166
+ for (const raw of routes) {
167
+ if (!raw || typeof raw !== "object") continue;
168
+ const wrapper = typeof raw.wrapper === "string" ? raw.wrapper.trim().toLowerCase() : "";
169
+ const pattern = typeof raw.pattern === "string" ? raw.pattern.trim() : "";
170
+ if (!wrapper || !pattern) continue;
171
+ const dedupe = `${wrapper}:${pattern}`;
172
+ if (seen.has(dedupe)) continue;
173
+ seen.add(dedupe);
174
+ out.push({
175
+ wrapper,
176
+ pattern,
177
+ ...typeof raw.index === "string" && raw.index.trim() ? { index: raw.index.trim() } : {},
178
+ ...typeof raw.label === "string" && raw.label.trim() ? { label: raw.label.trim() } : {}
179
+ });
180
+ }
181
+ return out;
182
+ }
183
+ function normalizeTrust(trust) {
184
+ if (!trust || typeof trust !== "object") return null;
185
+ const blocks = normalizeTrustBlocks(trust.blocks);
186
+ const labels = normalizeTrustLabels(trust.labels);
187
+ const mergeTestimonialsReviews = trust.mergeTestimonialsReviews === true;
188
+ if (blocks.length === 0 && !labels && !mergeTestimonialsReviews) return null;
189
+ return {
190
+ ...blocks.length > 0 ? { blocks } : {},
191
+ ...labels ? { labels } : {},
192
+ ...mergeTestimonialsReviews ? { mergeTestimonialsReviews: true } : {}
193
+ };
194
+ }
195
+ function normalizeTrustBlocks(blocks) {
196
+ if (!Array.isArray(blocks)) return [];
197
+ const seen = /* @__PURE__ */ new Set();
198
+ const out = [];
199
+ for (const raw of blocks) {
200
+ if (!raw || typeof raw !== "object") continue;
201
+ const section = typeof raw.section === "string" ? raw.section.trim().toLowerCase() : "";
202
+ if (!TRUST_SECTIONS.has(section) || seen.has(section)) continue;
203
+ seen.add(section);
204
+ out.push({
205
+ section,
206
+ ...typeof raw.label === "string" && raw.label.trim() ? { label: raw.label.trim() } : {}
207
+ });
208
+ }
209
+ return out;
210
+ }
211
+ function normalizeTrustLabels(labels) {
212
+ if (!labels || typeof labels !== "object") return null;
213
+ const out = {};
214
+ for (const [key, value] of Object.entries(labels)) {
215
+ if (TRUST_SECTIONS.has(key) && typeof value === "string" && value.trim()) {
216
+ out[key] = value.trim();
217
+ }
218
+ }
219
+ return Object.keys(out).length > 0 ? out : null;
220
+ }
221
+ function normalizeContact(contact) {
222
+ if (!contact || typeof contact !== "object") return null;
223
+ const extras = normalizeContactExtras(contact.extras);
224
+ return extras.length > 0 ? { extras } : null;
225
+ }
226
+ function normalizeContactExtras(extras) {
227
+ if (!Array.isArray(extras)) return [];
228
+ const seen = /* @__PURE__ */ new Set();
229
+ const out = [];
230
+ for (const raw of extras) {
231
+ if (!raw || typeof raw !== "object") continue;
232
+ const label = typeof raw.label === "string" ? raw.label.trim() : "";
233
+ const key = normalizeKey(
234
+ typeof raw.key === "string" && raw.key.trim() ? raw.key : label
235
+ );
236
+ if (!key || !label || !isValidExtraKey(key) || seen.has(key)) continue;
237
+ seen.add(key);
238
+ out.push({ key, label });
239
+ }
240
+ return out;
241
+ }
242
+ function stableJmpManifestFingerprint(manifest) {
243
+ return manifest ? JSON.stringify(manifest) : "";
244
+ }
245
+ function inferWrapperSlotsFromManifest(manifest) {
246
+ const slots = /* @__PURE__ */ new Set();
247
+ for (const route of manifest?.routes ?? []) {
248
+ slots.add(route.wrapper);
249
+ }
250
+ for (const block of manifest?.trust?.blocks ?? []) {
251
+ slots.add(`trust.${block.section}`);
252
+ slots.add("trust");
253
+ }
254
+ if (manifest?.contact?.extras?.length) {
255
+ slots.add("contact");
256
+ }
257
+ return [...slots];
258
+ }
259
+
53
260
  // src/content/fetch.ts
54
261
  async function getContent(config, path) {
55
262
  const text = await getContentText(config, path);
@@ -164,16 +371,22 @@ function inferTrustWrapperSlots(bundle) {
164
371
  function getDiscoveredContentWrappers() {
165
372
  return sortWrapperSlots([...discovered]);
166
373
  }
374
+ function resolveContentManifestForReport(config) {
375
+ return normalizeJmpContentManifest(config.contentManifest);
376
+ }
167
377
  function resolveContentWrappersForReport(config) {
168
378
  const explicit = config.contentWrappers ?? [];
169
379
  const auto = getDiscoveredContentWrappers();
380
+ const fromManifest = inferWrapperSlotsFromManifest(
381
+ resolveContentManifestForReport(config)
382
+ );
170
383
  if (config.contentWrapperMode === "manual") {
171
- return sortWrapperSlots([...explicit]);
384
+ return sortWrapperSlots([...explicit, ...fromManifest]);
172
385
  }
173
386
  if (config.contentWrapperMode === "explicit-only") {
174
- return sortWrapperSlots([...explicit]);
387
+ return sortWrapperSlots([...explicit, ...fromManifest]);
175
388
  }
176
- const merged = /* @__PURE__ */ new Set([...explicit, ...auto]);
389
+ const merged = /* @__PURE__ */ new Set([...explicit, ...auto, ...fromManifest]);
177
390
  return sortWrapperSlots([...merged]);
178
391
  }
179
392
  function hasReportedContentWrappers(dedupeKey) {
@@ -254,6 +467,53 @@ async function getJmpFaqs(config) {
254
467
  afterContentWrapperUse(config);
255
468
  return data.faqs;
256
469
  }
470
+ async function getJmpLandingPages(config, filters) {
471
+ const params = new URLSearchParams();
472
+ if (filters?.kind) {
473
+ params.set("kind", filters.kind);
474
+ }
475
+ if (filters?.locale) {
476
+ params.set("locale", filters.locale);
477
+ }
478
+ const query = params.toString();
479
+ const data = await getContent(
480
+ config,
481
+ `/api/content/landing-pages${query ? `?${query}` : ""}`
482
+ );
483
+ markContentWrapper("landing");
484
+ afterContentWrapperUse(config);
485
+ return data.pages;
486
+ }
487
+ async function getJmpLandingPageDetail(config, kind, slug, locale) {
488
+ const params = new URLSearchParams();
489
+ if (locale) {
490
+ params.set("locale", locale);
491
+ }
492
+ const query = params.toString();
493
+ try {
494
+ const detail = await getContent(
495
+ config,
496
+ `/api/content/landing-pages/${encodeURIComponent(kind)}/${encodeURIComponent(slug)}${query ? `?${query}` : ""}`
497
+ );
498
+ markContentWrapper("landing");
499
+ afterContentWrapperUse(config);
500
+ return detail;
501
+ } catch (error) {
502
+ if (error instanceof Error && error.message.includes("HTTP 404")) {
503
+ return null;
504
+ }
505
+ throw error;
506
+ }
507
+ }
508
+ async function getJmpLandingPageSitemap(config) {
509
+ const data = await getContent(
510
+ config,
511
+ "/api/content/landing-pages/sitemap"
512
+ );
513
+ markContentWrapper("landing");
514
+ afterContentWrapperUse(config);
515
+ return data.entries;
516
+ }
257
517
  async function getJmpTrustBundle(config) {
258
518
  const bundle = await getContent(config, "/api/content/trust");
259
519
  markTrustBundleWrappers(bundle);
@@ -274,7 +534,8 @@ async function registerJmpContentWrappers(config) {
274
534
  if (!wrappers.length) {
275
535
  return { ok: false, skipped: true };
276
536
  }
277
- const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(",")}`;
537
+ const manifest = resolveContentManifestForReport(config);
538
+ const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(",")}:${stableJmpManifestFingerprint(manifest)}`;
278
539
  if (hasReportedContentWrappers(dedupeKey)) {
279
540
  return { ok: true, wrappers };
280
541
  }
@@ -287,7 +548,17 @@ async function registerJmpContentWrappers(config) {
287
548
  }
288
549
  const url = `${baseUrl}/api/content/capabilities`;
289
550
  if (config.debug) {
290
- console.debug("[@jmp-technologies/analytics]", "POST", url, { wrappers });
551
+ console.debug("[@jmp-technologies/analytics]", "POST", url, {
552
+ wrappers,
553
+ manifest
554
+ });
555
+ }
556
+ const body = {
557
+ wrappers,
558
+ sdkVersion: JMP_ANALYTICS_SDK_VERSION
559
+ };
560
+ if (manifest) {
561
+ body.manifest = manifest;
291
562
  }
292
563
  const res = await resolvedFetch(url, {
293
564
  method: "POST",
@@ -295,10 +566,7 @@ async function registerJmpContentWrappers(config) {
295
566
  "Content-Type": "application/json",
296
567
  "X-JMP-Tracking-Key": config.trackingKey
297
568
  },
298
- body: JSON.stringify({
299
- wrappers,
300
- sdkVersion: JMP_ANALYTICS_SDK_VERSION
301
- })
569
+ body: JSON.stringify(body)
302
570
  });
303
571
  const text = await res.text();
304
572
  if (!res.ok) {
@@ -377,7 +645,8 @@ function getJmpContentConfig() {
377
645
  return {
378
646
  baseUrl: analyticsUrl,
379
647
  trackingKey,
380
- contentWrappers: site?.contentWrappers ?? void 0
648
+ contentWrappers: site?.contentWrappers ?? void 0,
649
+ contentManifest: site?.contentManifest ?? void 0
381
650
  };
382
651
  }
383
652
 
@@ -387,7 +656,8 @@ var DEFAULT_EXTRA_KEYS = {
387
656
  dashboardDemoUrl: ["dashboard-demo-url", "sample-dashboard-url"],
388
657
  profilePhotoSrc: ["profile-photo-url", "profile_photo_url"],
389
658
  hours: ["hours", "business-hours"],
390
- serviceArea: ["service-area", "service_area", "service-area-text"]
659
+ serviceArea: ["service-area", "service_area", "service-area-text"],
660
+ googleMapsEmbedUrl: ["google-maps-embed-url", "google_maps_embed_url"]
391
661
  };
392
662
  function sortBlogPosts(posts) {
393
663
  return [...posts].sort((a, b) => {
@@ -438,7 +708,13 @@ function resolveSiteContact(profile) {
438
708
  ...site?.contactExtraKeys
439
709
  };
440
710
  const email = profile?.email?.trim() || fallback.email || "";
441
- const linkedin = profile?.social?.linkedin?.trim() || fallback.linkedin || null;
711
+ const social = {
712
+ linkedin: profile?.social?.linkedin?.trim() || fallback.linkedin || null,
713
+ instagram: profile?.social?.instagram?.trim() || fallback.instagram || null,
714
+ facebook: profile?.social?.facebook?.trim() || fallback.facebook || null,
715
+ x: profile?.social?.x?.trim() || fallback.x || null,
716
+ youtube: profile?.social?.youtube?.trim() || fallback.youtube || null
717
+ };
442
718
  const phone = profile?.phone?.trim() || fallback.phone || null;
443
719
  return {
444
720
  displayName: profile?.display_name?.trim() || profile?.name?.trim() || fallback.displayName || "",
@@ -446,8 +722,12 @@ function resolveSiteContact(profile) {
446
722
  dashboardDemoUrl: readProfileExtra(profile, extraKeys.dashboardDemoUrl ?? []) || fallback.dashboardDemoUrl || "",
447
723
  profilePhotoSrc: readProfileExtra(profile, extraKeys.profilePhotoSrc ?? []) || fallback.profilePhotoSrc || "",
448
724
  email,
449
- linkedin,
725
+ linkedin: social.linkedin,
726
+ social,
450
727
  phone,
728
+ address: profile?.address?.trim() || fallback.address || null,
729
+ googleMapsUrl: profile?.google_maps_url?.trim() || fallback.googleMapsUrl || null,
730
+ googleMapsEmbedUrl: readProfileExtra(profile, extraKeys.googleMapsEmbedUrl ?? []) || fallback.googleMapsEmbedUrl || null,
451
731
  hours: readProfileExtra(profile, extraKeys.hours ?? []) || fallback.hours || null,
452
732
  serviceArea: readProfileExtra(profile, extraKeys.serviceArea ?? []) || fallback.serviceArea || null,
453
733
  privacyUrl: profile?.legal?.privacy_policy_url?.trim() || fallback.privacyUrl || "/privacy",
@@ -462,6 +742,15 @@ async function getResolvedSiteContact() {
462
742
  const profile = await loadSiteProfile();
463
743
  return resolveSiteContact(profile);
464
744
  }
745
+ function listResolvedSocialUrls(social) {
746
+ return [
747
+ social.linkedin,
748
+ social.instagram,
749
+ social.facebook,
750
+ social.x,
751
+ social.youtube
752
+ ].filter((url) => Boolean(url));
753
+ }
465
754
  async function loadBlogPosts() {
466
755
  const c = getJmpContentConfig();
467
756
  if (!c) {
@@ -505,6 +794,39 @@ async function loadFaqBySlug(slug) {
505
794
  const items = await loadFaqs();
506
795
  return items.find((item) => item.slug === normalized || item.id === normalized) ?? null;
507
796
  }
797
+ async function loadLandingPages(filters) {
798
+ const c = getJmpContentConfig();
799
+ if (!c) {
800
+ return [];
801
+ }
802
+ try {
803
+ return await getJmpLandingPages(c, filters);
804
+ } catch {
805
+ return [];
806
+ }
807
+ }
808
+ async function loadLandingPageDetail(kind, slug, locale) {
809
+ const c = getJmpContentConfig();
810
+ if (!c) {
811
+ return null;
812
+ }
813
+ try {
814
+ return await getJmpLandingPageDetail(c, kind, slug, locale);
815
+ } catch {
816
+ return null;
817
+ }
818
+ }
819
+ async function loadLandingPageSitemap() {
820
+ const c = getJmpContentConfig();
821
+ if (!c) {
822
+ return [];
823
+ }
824
+ try {
825
+ return await getJmpLandingPageSitemap(c);
826
+ } catch {
827
+ return [];
828
+ }
829
+ }
508
830
  async function loadTrustBundle() {
509
831
  const c = getJmpContentConfig();
510
832
  if (!c) {
@@ -539,6 +861,9 @@ var loadBlogPosts2 = (0, import_react.cache)(loadBlogPosts);
539
861
  var loadBlogPost2 = (0, import_react.cache)(loadBlogPost);
540
862
  var loadFaqs2 = (0, import_react.cache)(loadFaqs);
541
863
  var loadFaqBySlug2 = loadFaqBySlug;
864
+ var loadLandingPages2 = (0, import_react.cache)(loadLandingPages);
865
+ var loadLandingPageDetail2 = loadLandingPageDetail;
866
+ var loadLandingPageSitemap2 = (0, import_react.cache)(loadLandingPageSitemap);
542
867
  var loadTrustBundle2 = (0, import_react.cache)(loadTrustBundle);
543
868
  // Annotate the CommonJS export names for ESM import in node:
544
869
  0 && (module.exports = {
@@ -546,10 +871,14 @@ var loadTrustBundle2 = (0, import_react.cache)(loadTrustBundle);
546
871
  filterFeaturedTrustQuotes,
547
872
  getJmpContentConfig,
548
873
  getResolvedSiteContact,
874
+ listResolvedSocialUrls,
549
875
  loadBlogPost,
550
876
  loadBlogPosts,
551
877
  loadFaqBySlug,
552
878
  loadFaqs,
879
+ loadLandingPageDetail,
880
+ loadLandingPageSitemap,
881
+ loadLandingPages,
553
882
  loadSiteProfile,
554
883
  loadTrustBundle,
555
884
  resolveSiteContact