@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
@@ -35,7 +35,7 @@ __export(site_root_server_exports, {
35
35
  module.exports = __toCommonJS(site_root_server_exports);
36
36
 
37
37
  // src/constants.ts
38
- var JMP_ANALYTICS_SDK_VERSION = "0.1.25";
38
+ var JMP_ANALYTICS_SDK_VERSION = "0.1.26";
39
39
  var JMP_TRACKING_CONSENT_STORAGE_KEY = "jmp_analytics_consent_v1";
40
40
  var DEFAULT_JMP_BROWSER_PAGE_VIEW_DEDUPE_MS = 2500;
41
41
 
@@ -121,6 +121,209 @@ async function getContentText(config, path) {
121
121
  return text;
122
122
  }
123
123
 
124
+ // src/content/manifest.ts
125
+ var JMP_CONTENT_MANIFEST_VERSION = 1;
126
+ var TRUST_SECTIONS = /* @__PURE__ */ new Set([
127
+ "summary",
128
+ "testimonials",
129
+ "reviews",
130
+ "stats",
131
+ "logos",
132
+ "credentials"
133
+ ]);
134
+ function normalizeKey(value) {
135
+ return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
136
+ }
137
+ function isValidExtraKey(key) {
138
+ return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(key);
139
+ }
140
+ var MAX_EXTERNAL_ADMIN_LINKS = 10;
141
+ var MAX_EXTERNAL_ADMIN_LINK_LABEL_LENGTH = 80;
142
+ var EXTERNAL_ADMIN_LINK_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
143
+ function tryNormalizeHttpUrl(input) {
144
+ if (typeof input !== "string" || !input.trim()) {
145
+ return null;
146
+ }
147
+ try {
148
+ const url = new URL(input.trim());
149
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
150
+ return null;
151
+ }
152
+ return url.toString().replace(/\/$/, "");
153
+ } catch {
154
+ return null;
155
+ }
156
+ }
157
+ function normalizeShopifyExternalSource(shopify) {
158
+ if (!shopify || typeof shopify !== "object") {
159
+ return null;
160
+ }
161
+ const adminUrl = tryNormalizeHttpUrl(shopify.adminUrl);
162
+ const storeUrl = tryNormalizeHttpUrl(shopify.storeUrl);
163
+ if (!adminUrl && !storeUrl) {
164
+ return null;
165
+ }
166
+ return {
167
+ ...adminUrl ? { adminUrl } : {},
168
+ ...storeUrl ? { storeUrl } : {}
169
+ };
170
+ }
171
+ function normalizeExternalAdminLinkEntries(links) {
172
+ if (!Array.isArray(links)) {
173
+ return [];
174
+ }
175
+ const seenIds = /* @__PURE__ */ new Set();
176
+ const out = [];
177
+ for (const raw of links) {
178
+ if (!raw || typeof raw !== "object" || out.length >= MAX_EXTERNAL_ADMIN_LINKS) {
179
+ continue;
180
+ }
181
+ const id = typeof raw.id === "string" ? raw.id.trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") : "";
182
+ const label = typeof raw.label === "string" ? raw.label.trim().slice(0, MAX_EXTERNAL_ADMIN_LINK_LABEL_LENGTH) : "";
183
+ const url = tryNormalizeHttpUrl(raw.url);
184
+ if (!id || !label || !url || !EXTERNAL_ADMIN_LINK_ID_PATTERN.test(id) || seenIds.has(id)) {
185
+ continue;
186
+ }
187
+ seenIds.add(id);
188
+ out.push({ id, label, url });
189
+ }
190
+ return out;
191
+ }
192
+ function normalizeExternalSources(externalSources) {
193
+ if (!externalSources || typeof externalSources !== "object") {
194
+ return null;
195
+ }
196
+ const studioUrl = tryNormalizeHttpUrl(externalSources.sanity?.studioUrl);
197
+ const shopify = normalizeShopifyExternalSource(externalSources.shopify);
198
+ const links = normalizeExternalAdminLinkEntries(externalSources.links);
199
+ if (!studioUrl && !shopify && links.length === 0) {
200
+ return null;
201
+ }
202
+ return {
203
+ ...studioUrl ? { sanity: { studioUrl } } : {},
204
+ ...shopify ? { shopify } : {},
205
+ ...links.length > 0 ? { links } : {}
206
+ };
207
+ }
208
+ function normalizeJmpContentManifest(input) {
209
+ if (!input || typeof input !== "object") {
210
+ return null;
211
+ }
212
+ const routes = normalizeRoutes(input.routes);
213
+ const externalSources = normalizeExternalSources(input.externalSources);
214
+ const trust = normalizeTrust(input.trust);
215
+ const contact = normalizeContact(input.contact);
216
+ if (routes.length === 0 && !externalSources && !trust && !contact) {
217
+ return null;
218
+ }
219
+ return {
220
+ version: JMP_CONTENT_MANIFEST_VERSION,
221
+ ...routes.length > 0 ? { routes } : {},
222
+ ...externalSources ? { externalSources } : {},
223
+ ...trust ? { trust } : {},
224
+ ...contact ? { contact } : {}
225
+ };
226
+ }
227
+ function normalizeRoutes(routes) {
228
+ if (!Array.isArray(routes)) {
229
+ return [];
230
+ }
231
+ const seen = /* @__PURE__ */ new Set();
232
+ const out = [];
233
+ for (const raw of routes) {
234
+ if (!raw || typeof raw !== "object") continue;
235
+ const wrapper = typeof raw.wrapper === "string" ? raw.wrapper.trim().toLowerCase() : "";
236
+ const pattern = typeof raw.pattern === "string" ? raw.pattern.trim() : "";
237
+ if (!wrapper || !pattern) continue;
238
+ const dedupe = `${wrapper}:${pattern}`;
239
+ if (seen.has(dedupe)) continue;
240
+ seen.add(dedupe);
241
+ out.push({
242
+ wrapper,
243
+ pattern,
244
+ ...typeof raw.index === "string" && raw.index.trim() ? { index: raw.index.trim() } : {},
245
+ ...typeof raw.label === "string" && raw.label.trim() ? { label: raw.label.trim() } : {}
246
+ });
247
+ }
248
+ return out;
249
+ }
250
+ function normalizeTrust(trust) {
251
+ if (!trust || typeof trust !== "object") return null;
252
+ const blocks = normalizeTrustBlocks(trust.blocks);
253
+ const labels = normalizeTrustLabels(trust.labels);
254
+ const mergeTestimonialsReviews = trust.mergeTestimonialsReviews === true;
255
+ if (blocks.length === 0 && !labels && !mergeTestimonialsReviews) return null;
256
+ return {
257
+ ...blocks.length > 0 ? { blocks } : {},
258
+ ...labels ? { labels } : {},
259
+ ...mergeTestimonialsReviews ? { mergeTestimonialsReviews: true } : {}
260
+ };
261
+ }
262
+ function normalizeTrustBlocks(blocks) {
263
+ if (!Array.isArray(blocks)) return [];
264
+ const seen = /* @__PURE__ */ new Set();
265
+ const out = [];
266
+ for (const raw of blocks) {
267
+ if (!raw || typeof raw !== "object") continue;
268
+ const section = typeof raw.section === "string" ? raw.section.trim().toLowerCase() : "";
269
+ if (!TRUST_SECTIONS.has(section) || seen.has(section)) continue;
270
+ seen.add(section);
271
+ out.push({
272
+ section,
273
+ ...typeof raw.label === "string" && raw.label.trim() ? { label: raw.label.trim() } : {}
274
+ });
275
+ }
276
+ return out;
277
+ }
278
+ function normalizeTrustLabels(labels) {
279
+ if (!labels || typeof labels !== "object") return null;
280
+ const out = {};
281
+ for (const [key, value] of Object.entries(labels)) {
282
+ if (TRUST_SECTIONS.has(key) && typeof value === "string" && value.trim()) {
283
+ out[key] = value.trim();
284
+ }
285
+ }
286
+ return Object.keys(out).length > 0 ? out : null;
287
+ }
288
+ function normalizeContact(contact) {
289
+ if (!contact || typeof contact !== "object") return null;
290
+ const extras = normalizeContactExtras(contact.extras);
291
+ return extras.length > 0 ? { extras } : null;
292
+ }
293
+ function normalizeContactExtras(extras) {
294
+ if (!Array.isArray(extras)) return [];
295
+ const seen = /* @__PURE__ */ new Set();
296
+ const out = [];
297
+ for (const raw of extras) {
298
+ if (!raw || typeof raw !== "object") continue;
299
+ const label = typeof raw.label === "string" ? raw.label.trim() : "";
300
+ const key = normalizeKey(
301
+ typeof raw.key === "string" && raw.key.trim() ? raw.key : label
302
+ );
303
+ if (!key || !label || !isValidExtraKey(key) || seen.has(key)) continue;
304
+ seen.add(key);
305
+ out.push({ key, label });
306
+ }
307
+ return out;
308
+ }
309
+ function stableJmpManifestFingerprint(manifest) {
310
+ return manifest ? JSON.stringify(manifest) : "";
311
+ }
312
+ function inferWrapperSlotsFromManifest(manifest) {
313
+ const slots = /* @__PURE__ */ new Set();
314
+ for (const route of manifest?.routes ?? []) {
315
+ slots.add(route.wrapper);
316
+ }
317
+ for (const block of manifest?.trust?.blocks ?? []) {
318
+ slots.add(`trust.${block.section}`);
319
+ slots.add("trust");
320
+ }
321
+ if (manifest?.contact?.extras?.length) {
322
+ slots.add("contact");
323
+ }
324
+ return [...slots];
325
+ }
326
+
124
327
  // src/content/wrapper-discovery.ts
125
328
  var WRAPPER_SLOT_ORDER = [
126
329
  "blog",
@@ -149,16 +352,22 @@ function markContentWrapper(slot) {
149
352
  function getDiscoveredContentWrappers() {
150
353
  return sortWrapperSlots([...discovered]);
151
354
  }
355
+ function resolveContentManifestForReport(config) {
356
+ return normalizeJmpContentManifest(config.contentManifest);
357
+ }
152
358
  function resolveContentWrappersForReport(config) {
153
359
  const explicit = config.contentWrappers ?? [];
154
360
  const auto = getDiscoveredContentWrappers();
361
+ const fromManifest = inferWrapperSlotsFromManifest(
362
+ resolveContentManifestForReport(config)
363
+ );
155
364
  if (config.contentWrapperMode === "manual") {
156
- return sortWrapperSlots([...explicit]);
365
+ return sortWrapperSlots([...explicit, ...fromManifest]);
157
366
  }
158
367
  if (config.contentWrapperMode === "explicit-only") {
159
- return sortWrapperSlots([...explicit]);
368
+ return sortWrapperSlots([...explicit, ...fromManifest]);
160
369
  }
161
- const merged = /* @__PURE__ */ new Set([...explicit, ...auto]);
370
+ const merged = /* @__PURE__ */ new Set([...explicit, ...auto, ...fromManifest]);
162
371
  return sortWrapperSlots([...merged]);
163
372
  }
164
373
  function hasReportedContentWrappers(dedupeKey) {
@@ -219,7 +428,8 @@ async function registerJmpContentWrappers(config) {
219
428
  if (!wrappers.length) {
220
429
  return { ok: false, skipped: true };
221
430
  }
222
- const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(",")}`;
431
+ const manifest = resolveContentManifestForReport(config);
432
+ const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(",")}:${stableJmpManifestFingerprint(manifest)}`;
223
433
  if (hasReportedContentWrappers(dedupeKey)) {
224
434
  return { ok: true, wrappers };
225
435
  }
@@ -232,7 +442,17 @@ async function registerJmpContentWrappers(config) {
232
442
  }
233
443
  const url = `${baseUrl}/api/content/capabilities`;
234
444
  if (config.debug) {
235
- console.debug("[@jmp-technologies/analytics]", "POST", url, { wrappers });
445
+ console.debug("[@jmp-technologies/analytics]", "POST", url, {
446
+ wrappers,
447
+ manifest
448
+ });
449
+ }
450
+ const body = {
451
+ wrappers,
452
+ sdkVersion: JMP_ANALYTICS_SDK_VERSION
453
+ };
454
+ if (manifest) {
455
+ body.manifest = manifest;
236
456
  }
237
457
  const res = await resolvedFetch(url, {
238
458
  method: "POST",
@@ -240,10 +460,7 @@ async function registerJmpContentWrappers(config) {
240
460
  "Content-Type": "application/json",
241
461
  "X-JMP-Tracking-Key": config.trackingKey
242
462
  },
243
- body: JSON.stringify({
244
- wrappers,
245
- sdkVersion: JMP_ANALYTICS_SDK_VERSION
246
- })
463
+ body: JSON.stringify(body)
247
464
  });
248
465
  const text = await res.text();
249
466
  if (!res.ok) {
@@ -322,7 +539,8 @@ function getJmpContentConfig() {
322
539
  return {
323
540
  baseUrl: analyticsUrl,
324
541
  trackingKey,
325
- contentWrappers: site?.contentWrappers ?? void 0
542
+ contentWrappers: site?.contentWrappers ?? void 0,
543
+ contentManifest: site?.contentManifest ?? void 0
326
544
  };
327
545
  }
328
546