@jmp-technologies/analytics 0.1.27 → 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 (84) hide show
  1. package/dist/astro/client.cjs +226 -9
  2. package/dist/astro/client.cjs.map +1 -1
  3. package/dist/astro/client.d.cts +2 -2
  4. package/dist/astro/client.d.ts +2 -2
  5. package/dist/astro/client.js +2 -2
  6. package/dist/astro/content.cjs +253 -13
  7. package/dist/astro/content.cjs.map +1 -1
  8. package/dist/astro/content.d.cts +10 -3
  9. package/dist/astro/content.d.ts +10 -3
  10. package/dist/astro/content.js +5 -3
  11. package/dist/astro/integration.cjs +228 -10
  12. package/dist/astro/integration.cjs.map +1 -1
  13. package/dist/astro/integration.js +3 -3
  14. package/dist/astro/middleware.cjs +2 -1
  15. package/dist/astro/middleware.cjs.map +1 -1
  16. package/dist/astro/middleware.d.cts +2 -2
  17. package/dist/astro/middleware.d.ts +2 -2
  18. package/dist/astro/middleware.js +2 -2
  19. package/dist/astro/register.cjs +228 -10
  20. package/dist/astro/register.cjs.map +1 -1
  21. package/dist/astro/register.js +3 -3
  22. package/dist/{chunk-A4RRTY5D.js → chunk-AIFJ7DVO.js} +3 -2
  23. package/dist/{chunk-A4RRTY5D.js.map → chunk-AIFJ7DVO.js.map} +1 -1
  24. package/dist/{chunk-PG3IOI5O.js → chunk-FS4BZ7DR.js} +27 -6
  25. package/dist/chunk-FS4BZ7DR.js.map +1 -0
  26. package/dist/{chunk-UVYF33XE.js → chunk-GTPKRBFR.js} +230 -11
  27. package/dist/chunk-GTPKRBFR.js.map +1 -0
  28. package/dist/{chunk-HODG4NJQ.js → chunk-HFLU7HQE.js} +2 -2
  29. package/dist/{chunk-FNWE2DT5.js → chunk-LLTB7ZFC.js} +2 -2
  30. package/dist/{chunk-DNYJF7BG.js → chunk-LTPLLPOR.js} +3 -3
  31. package/dist/{chunk-KZ4WVDGL.js → chunk-ZEC22LFP.js} +3 -3
  32. package/dist/{create-jmp-analytics-DpG5Hdl5.d.ts → create-jmp-analytics-BeuuU6as.d.ts} +1 -1
  33. package/dist/{create-jmp-analytics-D4Qw_d6o.d.cts → create-jmp-analytics-Ce2CrhhR.d.cts} +1 -1
  34. package/dist/index.cjs +232 -10
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +5 -5
  37. package/dist/index.d.ts +5 -5
  38. package/dist/index.js +6 -2
  39. package/dist/next/content.cjs +253 -13
  40. package/dist/next/content.cjs.map +1 -1
  41. package/dist/next/content.d.cts +3 -3
  42. package/dist/next/content.d.ts +3 -3
  43. package/dist/next/content.js +5 -3
  44. package/dist/next/content.js.map +1 -1
  45. package/dist/next/instrumentation.cjs +228 -10
  46. package/dist/next/instrumentation.cjs.map +1 -1
  47. package/dist/next/instrumentation.js +2 -2
  48. package/dist/next/landing-pages.cjs +228 -12
  49. package/dist/next/landing-pages.cjs.map +1 -1
  50. package/dist/next/landing-pages.d.cts +2 -3
  51. package/dist/next/landing-pages.d.ts +2 -3
  52. package/dist/next/landing-pages.js +3 -5
  53. package/dist/next/landing-pages.js.map +1 -1
  54. package/dist/next/middleware.cjs +2 -1
  55. package/dist/next/middleware.cjs.map +1 -1
  56. package/dist/next/middleware.d.cts +2 -2
  57. package/dist/next/middleware.d.ts +2 -2
  58. package/dist/next/middleware.js +2 -2
  59. package/dist/next/site-root-server.cjs +228 -10
  60. package/dist/next/site-root-server.cjs.map +1 -1
  61. package/dist/next/site-root-server.js +4 -4
  62. package/dist/next.cjs +226 -9
  63. package/dist/next.cjs.map +1 -1
  64. package/dist/next.d.cts +3 -3
  65. package/dist/next.d.ts +3 -3
  66. package/dist/next.js +4 -4
  67. package/dist/react.cjs +226 -9
  68. package/dist/react.cjs.map +1 -1
  69. package/dist/react.d.cts +2 -2
  70. package/dist/react.d.ts +2 -2
  71. package/dist/react.js +3 -3
  72. package/dist/{site-config-CJqYnZm7.d.cts → site-config-B4uEj4xX.d.ts} +22 -2
  73. package/dist/{site-config-UTzDG-UG.d.ts → site-config-DIFmnwqv.d.cts} +22 -2
  74. package/dist/{track-page-view-tX0Magkd.d.cts → track-page-view-Bv0BAvxG.d.cts} +1 -1
  75. package/dist/{track-page-view-CMAqyhD_.d.ts → track-page-view-CkgIp9-j.d.ts} +1 -1
  76. package/dist/{types-B-111Wht.d.cts → types-B2iP79lb.d.cts} +59 -1
  77. package/dist/{types-B-111Wht.d.ts → types-B2iP79lb.d.ts} +59 -1
  78. package/package.json +1 -1
  79. package/dist/chunk-PG3IOI5O.js.map +0 -1
  80. package/dist/chunk-UVYF33XE.js.map +0 -1
  81. /package/dist/{chunk-HODG4NJQ.js.map → chunk-HFLU7HQE.js.map} +0 -0
  82. /package/dist/{chunk-FNWE2DT5.js.map → chunk-LLTB7ZFC.js.map} +0 -0
  83. /package/dist/{chunk-DNYJF7BG.js.map → chunk-LTPLLPOR.js.map} +0 -0
  84. /package/dist/{chunk-KZ4WVDGL.js.map → chunk-ZEC22LFP.js.map} +0 -0
@@ -24,6 +24,7 @@ __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,
@@ -53,6 +54,209 @@ function normalizeBaseUrl(baseUrl) {
53
54
  return baseUrl.replace(/\/$/, "");
54
55
  }
55
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
+
56
260
  // src/content/fetch.ts
57
261
  async function getContent(config, path) {
58
262
  const text = await getContentText(config, path);
@@ -167,16 +371,22 @@ function inferTrustWrapperSlots(bundle) {
167
371
  function getDiscoveredContentWrappers() {
168
372
  return sortWrapperSlots([...discovered]);
169
373
  }
374
+ function resolveContentManifestForReport(config) {
375
+ return normalizeJmpContentManifest(config.contentManifest);
376
+ }
170
377
  function resolveContentWrappersForReport(config) {
171
378
  const explicit = config.contentWrappers ?? [];
172
379
  const auto = getDiscoveredContentWrappers();
380
+ const fromManifest = inferWrapperSlotsFromManifest(
381
+ resolveContentManifestForReport(config)
382
+ );
173
383
  if (config.contentWrapperMode === "manual") {
174
- return sortWrapperSlots([...explicit]);
384
+ return sortWrapperSlots([...explicit, ...fromManifest]);
175
385
  }
176
386
  if (config.contentWrapperMode === "explicit-only") {
177
- return sortWrapperSlots([...explicit]);
387
+ return sortWrapperSlots([...explicit, ...fromManifest]);
178
388
  }
179
- const merged = /* @__PURE__ */ new Set([...explicit, ...auto]);
389
+ const merged = /* @__PURE__ */ new Set([...explicit, ...auto, ...fromManifest]);
180
390
  return sortWrapperSlots([...merged]);
181
391
  }
182
392
  function hasReportedContentWrappers(dedupeKey) {
@@ -324,7 +534,8 @@ async function registerJmpContentWrappers(config) {
324
534
  if (!wrappers.length) {
325
535
  return { ok: false, skipped: true };
326
536
  }
327
- const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(",")}`;
537
+ const manifest = resolveContentManifestForReport(config);
538
+ const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(",")}:${stableJmpManifestFingerprint(manifest)}`;
328
539
  if (hasReportedContentWrappers(dedupeKey)) {
329
540
  return { ok: true, wrappers };
330
541
  }
@@ -337,7 +548,17 @@ async function registerJmpContentWrappers(config) {
337
548
  }
338
549
  const url = `${baseUrl}/api/content/capabilities`;
339
550
  if (config.debug) {
340
- 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;
341
562
  }
342
563
  const res = await resolvedFetch(url, {
343
564
  method: "POST",
@@ -345,10 +566,7 @@ async function registerJmpContentWrappers(config) {
345
566
  "Content-Type": "application/json",
346
567
  "X-JMP-Tracking-Key": config.trackingKey
347
568
  },
348
- body: JSON.stringify({
349
- wrappers,
350
- sdkVersion: JMP_ANALYTICS_SDK_VERSION
351
- })
569
+ body: JSON.stringify(body)
352
570
  });
353
571
  const text = await res.text();
354
572
  if (!res.ok) {
@@ -427,7 +645,8 @@ function getJmpContentConfig() {
427
645
  return {
428
646
  baseUrl: analyticsUrl,
429
647
  trackingKey,
430
- contentWrappers: site?.contentWrappers ?? void 0
648
+ contentWrappers: site?.contentWrappers ?? void 0,
649
+ contentManifest: site?.contentManifest ?? void 0
431
650
  };
432
651
  }
433
652
 
@@ -437,7 +656,8 @@ var DEFAULT_EXTRA_KEYS = {
437
656
  dashboardDemoUrl: ["dashboard-demo-url", "sample-dashboard-url"],
438
657
  profilePhotoSrc: ["profile-photo-url", "profile_photo_url"],
439
658
  hours: ["hours", "business-hours"],
440
- 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"]
441
661
  };
442
662
  function sortBlogPosts(posts) {
443
663
  return [...posts].sort((a, b) => {
@@ -488,7 +708,13 @@ function resolveSiteContact(profile) {
488
708
  ...site?.contactExtraKeys
489
709
  };
490
710
  const email = profile?.email?.trim() || fallback.email || "";
491
- 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
+ };
492
718
  const phone = profile?.phone?.trim() || fallback.phone || null;
493
719
  return {
494
720
  displayName: profile?.display_name?.trim() || profile?.name?.trim() || fallback.displayName || "",
@@ -496,8 +722,12 @@ function resolveSiteContact(profile) {
496
722
  dashboardDemoUrl: readProfileExtra(profile, extraKeys.dashboardDemoUrl ?? []) || fallback.dashboardDemoUrl || "",
497
723
  profilePhotoSrc: readProfileExtra(profile, extraKeys.profilePhotoSrc ?? []) || fallback.profilePhotoSrc || "",
498
724
  email,
499
- linkedin,
725
+ linkedin: social.linkedin,
726
+ social,
500
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,
501
731
  hours: readProfileExtra(profile, extraKeys.hours ?? []) || fallback.hours || null,
502
732
  serviceArea: readProfileExtra(profile, extraKeys.serviceArea ?? []) || fallback.serviceArea || null,
503
733
  privacyUrl: profile?.legal?.privacy_policy_url?.trim() || fallback.privacyUrl || "/privacy",
@@ -512,6 +742,15 @@ async function getResolvedSiteContact() {
512
742
  const profile = await loadSiteProfile();
513
743
  return resolveSiteContact(profile);
514
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
+ }
515
754
  async function loadBlogPosts() {
516
755
  const c = getJmpContentConfig();
517
756
  if (!c) {
@@ -632,6 +871,7 @@ var loadTrustBundle2 = (0, import_react.cache)(loadTrustBundle);
632
871
  filterFeaturedTrustQuotes,
633
872
  getJmpContentConfig,
634
873
  getResolvedSiteContact,
874
+ listResolvedSocialUrls,
635
875
  loadBlogPost,
636
876
  loadBlogPosts,
637
877
  loadFaqBySlug,