@jmp-technologies/analytics 0.1.25 → 0.1.27
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/README.md +43 -0
- package/bin/jmp-init.mjs +34 -0
- package/dist/astro/client.cjs +103 -0
- package/dist/astro/client.cjs.map +1 -1
- package/dist/astro/client.d.cts +2 -2
- package/dist/astro/client.d.ts +2 -2
- package/dist/astro/client.js +5 -3
- package/dist/astro/client.js.map +1 -1
- package/dist/astro/content.cjs +271 -1
- package/dist/astro/content.cjs.map +1 -1
- package/dist/astro/content.d.cts +9 -3
- package/dist/astro/content.d.ts +9 -3
- package/dist/astro/content.js +10 -3
- package/dist/astro/integration.cjs +56 -10
- package/dist/astro/integration.cjs.map +1 -1
- package/dist/astro/integration.js +4 -3
- package/dist/astro/integration.js.map +1 -1
- package/dist/astro/middleware.cjs.map +1 -1
- package/dist/astro/middleware.d.cts +2 -2
- package/dist/astro/middleware.d.ts +2 -2
- package/dist/astro/middleware.js +2 -2
- package/dist/astro/register.cjs +56 -10
- package/dist/astro/register.cjs.map +1 -1
- package/dist/astro/register.js +4 -3
- package/dist/{chunk-MOX7RJUU.js → chunk-A4RRTY5D.js} +1 -1
- package/dist/{chunk-MOX7RJUU.js.map → chunk-A4RRTY5D.js.map} +1 -1
- package/dist/{chunk-L67PVZYL.js → chunk-DNYJF7BG.js} +3 -24
- package/dist/chunk-DNYJF7BG.js.map +1 -0
- package/dist/{chunk-5GORAM7J.js → chunk-FNWE2DT5.js} +2 -2
- package/dist/{chunk-7MLPSL6T.js → chunk-HODG4NJQ.js} +2 -2
- package/dist/{chunk-OLWCYWVB.js → chunk-KZ4WVDGL.js} +3 -3
- package/dist/{chunk-AJ33NQVZ.js → chunk-PG3IOI5O.js} +42 -3
- package/dist/chunk-PG3IOI5O.js.map +1 -0
- package/dist/chunk-TCZ6TC2L.js +149 -0
- package/dist/chunk-TCZ6TC2L.js.map +1 -0
- package/dist/{chunk-VRDPVKAN.js → chunk-UVYF33XE.js} +213 -157
- package/dist/chunk-UVYF33XE.js.map +1 -0
- package/dist/chunk-YCVHRMM6.js +28 -0
- package/dist/chunk-YCVHRMM6.js.map +1 -0
- package/dist/{create-jmp-analytics-ClLOMb9p.d.cts → create-jmp-analytics-D4Qw_d6o.d.cts} +1 -1
- package/dist/{create-jmp-analytics-COxo3-yg.d.ts → create-jmp-analytics-DpG5Hdl5.d.ts} +1 -1
- package/dist/index.cjs +213 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22 -7
- package/dist/index.d.ts +22 -7
- package/dist/index.js +19 -3
- package/dist/next/content.cjs +274 -1
- package/dist/next/content.cjs.map +1 -1
- package/dist/next/content.d.cts +7 -4
- package/dist/next/content.d.ts +7 -4
- package/dist/next/content.js +13 -3
- package/dist/next/content.js.map +1 -1
- package/dist/next/instrumentation.cjs +56 -10
- package/dist/next/instrumentation.cjs.map +1 -1
- package/dist/next/instrumentation.js +3 -2
- package/dist/next/instrumentation.js.map +1 -1
- package/dist/next/landing-capture-script-server.cjs +61 -0
- package/dist/next/landing-capture-script-server.cjs.map +1 -0
- package/dist/next/landing-capture-script-server.d.cts +14 -0
- package/dist/next/landing-capture-script-server.d.ts +14 -0
- package/dist/next/landing-capture-script-server.js +8 -0
- package/dist/next/landing-capture-script-server.js.map +1 -0
- package/dist/next/landing-pages.cjs +659 -0
- package/dist/next/landing-pages.cjs.map +1 -0
- package/dist/next/landing-pages.d.cts +104 -0
- package/dist/next/landing-pages.d.ts +104 -0
- package/dist/next/landing-pages.js +299 -0
- package/dist/next/landing-pages.js.map +1 -0
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.d.cts +2 -2
- package/dist/next/middleware.d.ts +2 -2
- package/dist/next/middleware.js +2 -2
- package/dist/next/site-root-server.cjs +159 -23
- package/dist/next/site-root-server.cjs.map +1 -1
- package/dist/next/site-root-server.js +9 -4
- package/dist/next/site-root-server.js.map +1 -1
- package/dist/next.cjs +152 -70
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +7 -15
- package/dist/next.d.ts +7 -15
- package/dist/next.js +7 -7
- package/dist/react.cjs +103 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +4 -3
- package/dist/{site-config-BSMVyUjk.d.ts → site-config-CJqYnZm7.d.cts} +6 -3
- package/dist/{site-config-8TTHIW6w.d.cts → site-config-UTzDG-UG.d.ts} +6 -3
- package/dist/{track-page-view-DtxbdM5q.d.ts → track-page-view-CMAqyhD_.d.ts} +1 -1
- package/dist/{track-page-view-BweavmXz.d.cts → track-page-view-tX0Magkd.d.cts} +1 -1
- package/dist/{types-Bk0ST1aH.d.ts → types-B-111Wht.d.cts} +52 -5
- package/dist/{types-Bk0ST1aH.d.cts → types-B-111Wht.d.ts} +52 -5
- package/docs/astro-integration.md +1 -1
- package/package.json +16 -2
- package/dist/chunk-AJ33NQVZ.js.map +0 -1
- package/dist/chunk-L67PVZYL.js.map +0 -1
- package/dist/chunk-VRDPVKAN.js.map +0 -1
- /package/dist/{chunk-5GORAM7J.js.map → chunk-FNWE2DT5.js.map} +0 -0
- /package/dist/{chunk-7MLPSL6T.js.map → chunk-HODG4NJQ.js.map} +0 -0
- /package/dist/{chunk-OLWCYWVB.js.map → chunk-KZ4WVDGL.js.map} +0 -0
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/next/landing-pages.tsx
|
|
31
|
+
var landing_pages_exports = {};
|
|
32
|
+
__export(landing_pages_exports, {
|
|
33
|
+
JMP_LANDING_HUB: () => JMP_LANDING_HUB,
|
|
34
|
+
JmpLandingDetailPage: () => JmpLandingDetailPage,
|
|
35
|
+
JmpLandingIndexPage: () => JmpLandingIndexPage,
|
|
36
|
+
absoluteJmpSiteUrl: () => absoluteJmpSiteUrl,
|
|
37
|
+
buildJmpLandingIndexMetadata: () => buildJmpLandingIndexMetadata,
|
|
38
|
+
buildJmpLandingMetadata: () => buildJmpLandingMetadata,
|
|
39
|
+
buildJmpLandingSitemapRoutes: () => buildJmpLandingSitemapRoutes,
|
|
40
|
+
filterJmpLandingPagesForDefaultLocale: () => filterJmpLandingPagesForDefaultLocale,
|
|
41
|
+
filterJmpLandingPagesForLocalizedRoutes: () => filterJmpLandingPagesForLocalizedRoutes,
|
|
42
|
+
generateJmpLandingStaticParams: () => generateJmpLandingStaticParams,
|
|
43
|
+
generateJmpLocalizedLandingStaticParams: () => generateJmpLocalizedLandingStaticParams,
|
|
44
|
+
jmpBreadcrumbListJsonLd: () => jmpBreadcrumbListJsonLd,
|
|
45
|
+
jmpLandingKindSegment: () => jmpLandingKindSegment,
|
|
46
|
+
jmpLocalizedLandingStaticParams: () => jmpLocalizedLandingStaticParams,
|
|
47
|
+
plainTextFromMarkdown: () => plainTextFromMarkdown,
|
|
48
|
+
resolveJmpSiteUrl: () => resolveJmpSiteUrl
|
|
49
|
+
});
|
|
50
|
+
module.exports = __toCommonJS(landing_pages_exports);
|
|
51
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
52
|
+
var import_navigation = require("next/navigation");
|
|
53
|
+
|
|
54
|
+
// src/landing-capture.ts
|
|
55
|
+
var LANDING_REFERER_COOKIE_MAX_AGE_SEC = 30 * 60;
|
|
56
|
+
|
|
57
|
+
// src/constants.ts
|
|
58
|
+
var JMP_ANALYTICS_SDK_VERSION = "0.1.26";
|
|
59
|
+
|
|
60
|
+
// src/http.ts
|
|
61
|
+
function responseLooksLikeHtml(body) {
|
|
62
|
+
const s = body.trimStart();
|
|
63
|
+
return s.startsWith("<!") || s.toLowerCase().startsWith("<html") || s.startsWith("<") && /<html[\s>]/i.test(s.slice(0, 500));
|
|
64
|
+
}
|
|
65
|
+
function normalizeBaseUrl(baseUrl) {
|
|
66
|
+
return baseUrl.replace(/\/$/, "");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/content/fetch.ts
|
|
70
|
+
async function getContent(config, path) {
|
|
71
|
+
const text = await getContentText(config, path);
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(text);
|
|
74
|
+
} catch {
|
|
75
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
76
|
+
const url = `${baseUrl}${path}`;
|
|
77
|
+
throw new Error(`JMP content HTTP 200 \u2014 ${url} returned invalid JSON.`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function getContentText(config, path) {
|
|
81
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
82
|
+
const resolvedFetch = config.fetchImpl ?? (typeof globalThis !== "undefined" && globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
83
|
+
if (!resolvedFetch) {
|
|
84
|
+
throw new Error("JMP content: fetch is not available; pass fetchImpl in config");
|
|
85
|
+
}
|
|
86
|
+
const url = `${baseUrl}${path}`;
|
|
87
|
+
if (config.debug) {
|
|
88
|
+
console.debug("[@jmp-technologies/analytics]", "GET", url);
|
|
89
|
+
}
|
|
90
|
+
const res = await resolvedFetch(url, {
|
|
91
|
+
method: "GET",
|
|
92
|
+
headers: {
|
|
93
|
+
"X-JMP-Tracking-Key": config.trackingKey
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const text = await res.text();
|
|
97
|
+
if (!res.ok) {
|
|
98
|
+
if (responseLooksLikeHtml(text)) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`JMP content HTTP ${res.status} \u2014 ${url} returned HTML (not the JSON API). Set baseUrl to your JMP Analytics dashboard origin.`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
let parsed = {};
|
|
104
|
+
try {
|
|
105
|
+
parsed = JSON.parse(text);
|
|
106
|
+
} catch {
|
|
107
|
+
parsed = { error: text };
|
|
108
|
+
}
|
|
109
|
+
throw new Error(
|
|
110
|
+
[`JMP content HTTP ${res.status}`, parsed.error, parsed.hint].filter(Boolean).join(" \u2014 ")
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return text;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/content/wrapper-discovery.ts
|
|
117
|
+
var WRAPPER_SLOT_ORDER = [
|
|
118
|
+
"blog",
|
|
119
|
+
"faq",
|
|
120
|
+
"contact",
|
|
121
|
+
"trust",
|
|
122
|
+
"trust.summary",
|
|
123
|
+
"trust.testimonials",
|
|
124
|
+
"trust.reviews",
|
|
125
|
+
"trust.stats",
|
|
126
|
+
"trust.logos",
|
|
127
|
+
"trust.credentials"
|
|
128
|
+
];
|
|
129
|
+
var discovered = /* @__PURE__ */ new Set();
|
|
130
|
+
var syncTimer = null;
|
|
131
|
+
var pendingSyncConfig = null;
|
|
132
|
+
var reportedDedupeKeys = /* @__PURE__ */ new Set();
|
|
133
|
+
var syncHandler = null;
|
|
134
|
+
function markContentWrapper(slot) {
|
|
135
|
+
const normalized = slot.trim().toLowerCase();
|
|
136
|
+
if (!normalized) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
discovered.add(normalized);
|
|
140
|
+
}
|
|
141
|
+
function getDiscoveredContentWrappers() {
|
|
142
|
+
return sortWrapperSlots([...discovered]);
|
|
143
|
+
}
|
|
144
|
+
function resolveContentWrappersForReport(config) {
|
|
145
|
+
const explicit = config.contentWrappers ?? [];
|
|
146
|
+
const auto = getDiscoveredContentWrappers();
|
|
147
|
+
if (config.contentWrapperMode === "manual") {
|
|
148
|
+
return sortWrapperSlots([...explicit]);
|
|
149
|
+
}
|
|
150
|
+
if (config.contentWrapperMode === "explicit-only") {
|
|
151
|
+
return sortWrapperSlots([...explicit]);
|
|
152
|
+
}
|
|
153
|
+
const merged = /* @__PURE__ */ new Set([...explicit, ...auto]);
|
|
154
|
+
return sortWrapperSlots([...merged]);
|
|
155
|
+
}
|
|
156
|
+
function hasReportedContentWrappers(dedupeKey) {
|
|
157
|
+
return reportedDedupeKeys.has(dedupeKey);
|
|
158
|
+
}
|
|
159
|
+
function rememberReportedContentWrappers(dedupeKey) {
|
|
160
|
+
reportedDedupeKeys.add(dedupeKey);
|
|
161
|
+
}
|
|
162
|
+
function setContentWrapperSyncHandler(handler) {
|
|
163
|
+
syncHandler = handler;
|
|
164
|
+
}
|
|
165
|
+
function scheduleContentWrapperSync(config) {
|
|
166
|
+
if (!syncHandler) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
pendingSyncConfig = config;
|
|
170
|
+
if (syncTimer) {
|
|
171
|
+
clearTimeout(syncTimer);
|
|
172
|
+
}
|
|
173
|
+
syncTimer = setTimeout(() => {
|
|
174
|
+
syncTimer = null;
|
|
175
|
+
const cfg = pendingSyncConfig;
|
|
176
|
+
pendingSyncConfig = null;
|
|
177
|
+
if (!cfg || !syncHandler) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
void syncHandler(cfg).catch(() => {
|
|
181
|
+
});
|
|
182
|
+
}, 750);
|
|
183
|
+
}
|
|
184
|
+
function sortWrapperSlots(slots) {
|
|
185
|
+
const order = new Map(WRAPPER_SLOT_ORDER.map((slot, index) => [slot, index]));
|
|
186
|
+
return [...new Set(slots)].sort((a, b) => {
|
|
187
|
+
const ai = order.get(a) ?? 999;
|
|
188
|
+
const bi = order.get(b) ?? 999;
|
|
189
|
+
if (ai !== bi) {
|
|
190
|
+
return ai - bi;
|
|
191
|
+
}
|
|
192
|
+
return a.localeCompare(b);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/content/api.ts
|
|
197
|
+
function afterContentWrapperUse(config) {
|
|
198
|
+
scheduleContentWrapperSync(config);
|
|
199
|
+
}
|
|
200
|
+
async function getJmpLandingPages(config, filters) {
|
|
201
|
+
const params = new URLSearchParams();
|
|
202
|
+
if (filters?.kind) {
|
|
203
|
+
params.set("kind", filters.kind);
|
|
204
|
+
}
|
|
205
|
+
if (filters?.locale) {
|
|
206
|
+
params.set("locale", filters.locale);
|
|
207
|
+
}
|
|
208
|
+
const query = params.toString();
|
|
209
|
+
const data = await getContent(
|
|
210
|
+
config,
|
|
211
|
+
`/api/content/landing-pages${query ? `?${query}` : ""}`
|
|
212
|
+
);
|
|
213
|
+
markContentWrapper("landing");
|
|
214
|
+
afterContentWrapperUse(config);
|
|
215
|
+
return data.pages;
|
|
216
|
+
}
|
|
217
|
+
async function getJmpLandingPageDetail(config, kind, slug, locale) {
|
|
218
|
+
const params = new URLSearchParams();
|
|
219
|
+
if (locale) {
|
|
220
|
+
params.set("locale", locale);
|
|
221
|
+
}
|
|
222
|
+
const query = params.toString();
|
|
223
|
+
try {
|
|
224
|
+
const detail = await getContent(
|
|
225
|
+
config,
|
|
226
|
+
`/api/content/landing-pages/${encodeURIComponent(kind)}/${encodeURIComponent(slug)}${query ? `?${query}` : ""}`
|
|
227
|
+
);
|
|
228
|
+
markContentWrapper("landing");
|
|
229
|
+
afterContentWrapperUse(config);
|
|
230
|
+
return detail;
|
|
231
|
+
} catch (error) {
|
|
232
|
+
if (error instanceof Error && error.message.includes("HTTP 404")) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function registerJmpContentWrappers(config) {
|
|
239
|
+
const wrappers = resolveContentWrappersForReport(config);
|
|
240
|
+
if (!wrappers.length) {
|
|
241
|
+
return { ok: false, skipped: true };
|
|
242
|
+
}
|
|
243
|
+
const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(",")}`;
|
|
244
|
+
if (hasReportedContentWrappers(dedupeKey)) {
|
|
245
|
+
return { ok: true, wrappers };
|
|
246
|
+
}
|
|
247
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
248
|
+
const resolvedFetch = config.fetchImpl ?? (typeof globalThis !== "undefined" && globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
249
|
+
if (!resolvedFetch) {
|
|
250
|
+
throw new Error(
|
|
251
|
+
"JMP content wrappers: fetch is not available; pass fetchImpl in config"
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
const url = `${baseUrl}/api/content/capabilities`;
|
|
255
|
+
if (config.debug) {
|
|
256
|
+
console.debug("[@jmp-technologies/analytics]", "POST", url, { wrappers });
|
|
257
|
+
}
|
|
258
|
+
const res = await resolvedFetch(url, {
|
|
259
|
+
method: "POST",
|
|
260
|
+
headers: {
|
|
261
|
+
"Content-Type": "application/json",
|
|
262
|
+
"X-JMP-Tracking-Key": config.trackingKey
|
|
263
|
+
},
|
|
264
|
+
body: JSON.stringify({
|
|
265
|
+
wrappers,
|
|
266
|
+
sdkVersion: JMP_ANALYTICS_SDK_VERSION
|
|
267
|
+
})
|
|
268
|
+
});
|
|
269
|
+
const text = await res.text();
|
|
270
|
+
if (!res.ok) {
|
|
271
|
+
let parsed = {};
|
|
272
|
+
try {
|
|
273
|
+
parsed = JSON.parse(text);
|
|
274
|
+
} catch {
|
|
275
|
+
parsed = { error: text };
|
|
276
|
+
}
|
|
277
|
+
throw new Error(
|
|
278
|
+
[`JMP content wrappers HTTP ${res.status}`, parsed.error, parsed.hint].filter(Boolean).join(" \u2014 ")
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
rememberReportedContentWrappers(dedupeKey);
|
|
282
|
+
const data = JSON.parse(text);
|
|
283
|
+
return { ok: true, wrappers: data.wrappers ?? wrappers };
|
|
284
|
+
}
|
|
285
|
+
setContentWrapperSyncHandler(registerJmpContentWrappers);
|
|
286
|
+
|
|
287
|
+
// src/env-public.ts
|
|
288
|
+
function firstDefined(...values) {
|
|
289
|
+
for (const v of values) {
|
|
290
|
+
if (v) return v;
|
|
291
|
+
}
|
|
292
|
+
return void 0;
|
|
293
|
+
}
|
|
294
|
+
function readJmpPublicEnvFromProcessEnv() {
|
|
295
|
+
if (typeof process === "undefined" || !process.env) {
|
|
296
|
+
return {};
|
|
297
|
+
}
|
|
298
|
+
const { env } = process;
|
|
299
|
+
const analyticsUrl = firstDefined(
|
|
300
|
+
env.NEXT_PUBLIC_JMP_ANALYTICS_URL,
|
|
301
|
+
env.PUBLIC_JMP_ANALYTICS_URL
|
|
302
|
+
);
|
|
303
|
+
const trackingKey = firstDefined(
|
|
304
|
+
env.NEXT_PUBLIC_JMP_TRACKING_KEY,
|
|
305
|
+
env.PUBLIC_JMP_TRACKING_KEY
|
|
306
|
+
);
|
|
307
|
+
const requireConsentRaw = firstDefined(
|
|
308
|
+
env.NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT,
|
|
309
|
+
env.PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT
|
|
310
|
+
);
|
|
311
|
+
const autoContactRaw = firstDefined(
|
|
312
|
+
env.NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS,
|
|
313
|
+
env.PUBLIC_JMP_AUTO_CONTACT_LINKS
|
|
314
|
+
);
|
|
315
|
+
return {
|
|
316
|
+
analyticsUrl,
|
|
317
|
+
trackingKey,
|
|
318
|
+
requireConsent: requireConsentRaw === "true",
|
|
319
|
+
autoContactLinks: autoContactRaw === "true"
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function readJmpPublicEnvFromProcess(overrides) {
|
|
323
|
+
const fromEnv = readJmpPublicEnvFromProcessEnv();
|
|
324
|
+
return {
|
|
325
|
+
analyticsUrl: firstDefined(overrides?.analyticsUrl, fromEnv.analyticsUrl),
|
|
326
|
+
trackingKey: firstDefined(overrides?.trackingKey, fromEnv.trackingKey),
|
|
327
|
+
requireConsent: overrides?.requireConsent ?? fromEnv.requireConsent,
|
|
328
|
+
autoContactLinks: overrides?.autoContactLinks ?? fromEnv.autoContactLinks
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/site-config.ts
|
|
333
|
+
var registeredSite = null;
|
|
334
|
+
function getJmpSiteDefinition() {
|
|
335
|
+
return registeredSite;
|
|
336
|
+
}
|
|
337
|
+
function getJmpContentConfig() {
|
|
338
|
+
const { analyticsUrl, trackingKey } = readJmpPublicEnvFromProcess();
|
|
339
|
+
if (!analyticsUrl || !trackingKey) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
const site = getJmpSiteDefinition();
|
|
343
|
+
return {
|
|
344
|
+
baseUrl: analyticsUrl,
|
|
345
|
+
trackingKey,
|
|
346
|
+
contentWrappers: site?.contentWrappers ?? void 0
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/content/site-content.ts
|
|
351
|
+
async function loadLandingPages(filters) {
|
|
352
|
+
const c = getJmpContentConfig();
|
|
353
|
+
if (!c) {
|
|
354
|
+
return [];
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
return await getJmpLandingPages(c, filters);
|
|
358
|
+
} catch {
|
|
359
|
+
return [];
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async function loadLandingPageDetail(kind, slug, locale) {
|
|
363
|
+
const c = getJmpContentConfig();
|
|
364
|
+
if (!c) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
return await getJmpLandingPageDetail(c, kind, slug, locale);
|
|
369
|
+
} catch {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/landing-pages/hub.ts
|
|
375
|
+
var JMP_LANDING_HUB = {
|
|
376
|
+
location: {
|
|
377
|
+
title: "Areas we serve",
|
|
378
|
+
path: "/areas",
|
|
379
|
+
description: "Local pages for cities and regions we work in.",
|
|
380
|
+
breadcrumb: "Areas",
|
|
381
|
+
segment: "areas"
|
|
382
|
+
},
|
|
383
|
+
service: {
|
|
384
|
+
title: "Services",
|
|
385
|
+
path: "/services",
|
|
386
|
+
description: "What we offer and how we help.",
|
|
387
|
+
breadcrumb: "Services",
|
|
388
|
+
segment: "services"
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
function jmpLandingKindSegment(kind) {
|
|
392
|
+
return JMP_LANDING_HUB[kind].segment;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// src/landing-pages/utils.ts
|
|
396
|
+
function plainTextFromMarkdown(input, maxLength = 5e3) {
|
|
397
|
+
return input.replace(/[#*_`[\]]/g, "").trim().slice(0, maxLength);
|
|
398
|
+
}
|
|
399
|
+
function resolveJmpSiteUrl(override) {
|
|
400
|
+
const fromArg = override?.trim().replace(/\/$/, "");
|
|
401
|
+
if (fromArg) return fromArg;
|
|
402
|
+
const fromConfig = getJmpSiteDefinition()?.siteUrl?.trim().replace(/\/$/, "");
|
|
403
|
+
return fromConfig || null;
|
|
404
|
+
}
|
|
405
|
+
function absoluteJmpSiteUrl(path, siteUrl) {
|
|
406
|
+
const base = resolveJmpSiteUrl(siteUrl);
|
|
407
|
+
if (!base) {
|
|
408
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
409
|
+
}
|
|
410
|
+
const normalized = path.startsWith("/") ? path : `/${path}`;
|
|
411
|
+
return `${base}${normalized}`;
|
|
412
|
+
}
|
|
413
|
+
function filterJmpLandingPagesForDefaultLocale(pages, kind) {
|
|
414
|
+
const segment = jmpLandingKindSegment(kind);
|
|
415
|
+
return pages.filter((page) => {
|
|
416
|
+
const parts = page.path.split("/").filter(Boolean);
|
|
417
|
+
return parts[0] === segment;
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
function filterJmpLandingPagesForLocalizedRoutes(pages, kind) {
|
|
421
|
+
const segment = jmpLandingKindSegment(kind);
|
|
422
|
+
return pages.filter((page) => {
|
|
423
|
+
const parts = page.path.split("/").filter(Boolean);
|
|
424
|
+
return parts.length >= 3 && parts[1] === segment;
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
function jmpLocalizedLandingStaticParams(pages, kind) {
|
|
428
|
+
const segment = jmpLandingKindSegment(kind);
|
|
429
|
+
return filterJmpLandingPagesForLocalizedRoutes(pages, kind).map((page) => {
|
|
430
|
+
const [locale, , slug] = page.path.split("/").filter(Boolean);
|
|
431
|
+
return { locale, slug };
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/landing-pages/json-ld.ts
|
|
436
|
+
function jmpBreadcrumbListJsonLd(items, siteUrl) {
|
|
437
|
+
return {
|
|
438
|
+
"@context": "https://schema.org",
|
|
439
|
+
"@type": "BreadcrumbList",
|
|
440
|
+
itemListElement: items.map((item, index) => ({
|
|
441
|
+
"@type": "ListItem",
|
|
442
|
+
position: index + 1,
|
|
443
|
+
name: item.name,
|
|
444
|
+
item: absoluteJmpSiteUrl(item.path, siteUrl)
|
|
445
|
+
}))
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/landing-pages/static-params.ts
|
|
450
|
+
async function generateJmpLandingStaticParams(kind) {
|
|
451
|
+
const pages = await loadLandingPages({ kind });
|
|
452
|
+
return filterJmpLandingPagesForDefaultLocale(pages, kind).map((page) => ({
|
|
453
|
+
slug: page.slug
|
|
454
|
+
}));
|
|
455
|
+
}
|
|
456
|
+
async function generateJmpLocalizedLandingStaticParams(kind) {
|
|
457
|
+
const pages = await loadLandingPages({ kind });
|
|
458
|
+
return jmpLocalizedLandingStaticParams(pages, kind);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// src/landing-pages/sitemap.ts
|
|
462
|
+
function buildJmpLandingSitemapRoutes(entries, options) {
|
|
463
|
+
const { siteUrl, changeFrequency = "monthly" } = options;
|
|
464
|
+
const defaultPriority = {
|
|
465
|
+
location: 0.7,
|
|
466
|
+
service: 0.68
|
|
467
|
+
};
|
|
468
|
+
return entries.map((entry) => {
|
|
469
|
+
const priority = options.priorityByKind?.[entry.kind] ?? defaultPriority[entry.kind];
|
|
470
|
+
const languages = entry.alternates.length > 0 ? Object.fromEntries(
|
|
471
|
+
entry.alternates.map((alt) => [
|
|
472
|
+
alt.locale,
|
|
473
|
+
absoluteJmpSiteUrl(alt.path, siteUrl)
|
|
474
|
+
])
|
|
475
|
+
) : void 0;
|
|
476
|
+
return {
|
|
477
|
+
url: absoluteJmpSiteUrl(entry.path, siteUrl),
|
|
478
|
+
lastModified: entry.updated_at ? new Date(entry.updated_at) : void 0,
|
|
479
|
+
changeFrequency,
|
|
480
|
+
priority,
|
|
481
|
+
alternates: languages ? { languages } : void 0
|
|
482
|
+
};
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/next/landing-pages.tsx
|
|
487
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
488
|
+
async function buildJmpLandingMetadata({
|
|
489
|
+
kind,
|
|
490
|
+
slug,
|
|
491
|
+
locale,
|
|
492
|
+
siteUrl
|
|
493
|
+
}) {
|
|
494
|
+
const detail = await loadLandingPageDetail(kind, slug, locale);
|
|
495
|
+
if (!detail) {
|
|
496
|
+
return { title: "Not found" };
|
|
497
|
+
}
|
|
498
|
+
const { page, alternates } = detail;
|
|
499
|
+
const title = page.seo_title?.trim() || page.title;
|
|
500
|
+
const description = page.meta_description?.trim() || page.excerpt?.trim() || plainTextFromMarkdown(page.body, 160) || page.title;
|
|
501
|
+
const languages = {};
|
|
502
|
+
for (const alt of alternates) {
|
|
503
|
+
languages[alt.locale] = absoluteJmpSiteUrl(alt.path, siteUrl);
|
|
504
|
+
}
|
|
505
|
+
const canonical = absoluteJmpSiteUrl(page.path, siteUrl);
|
|
506
|
+
return {
|
|
507
|
+
title,
|
|
508
|
+
description,
|
|
509
|
+
alternates: {
|
|
510
|
+
canonical,
|
|
511
|
+
languages: Object.keys(languages).length > 0 ? languages : void 0
|
|
512
|
+
},
|
|
513
|
+
openGraph: {
|
|
514
|
+
title,
|
|
515
|
+
description,
|
|
516
|
+
type: "website",
|
|
517
|
+
url: canonical
|
|
518
|
+
},
|
|
519
|
+
twitter: {
|
|
520
|
+
card: "summary",
|
|
521
|
+
title,
|
|
522
|
+
description
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function buildJmpLandingIndexMetadata(kind, siteUrl) {
|
|
527
|
+
const hub = JMP_LANDING_HUB[kind];
|
|
528
|
+
return {
|
|
529
|
+
title: hub.title,
|
|
530
|
+
description: hub.description,
|
|
531
|
+
alternates: {
|
|
532
|
+
canonical: absoluteJmpSiteUrl(hub.path, siteUrl)
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function DefaultJsonLd({
|
|
537
|
+
data,
|
|
538
|
+
id
|
|
539
|
+
}) {
|
|
540
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: data.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
541
|
+
"script",
|
|
542
|
+
{
|
|
543
|
+
type: "application/ld+json",
|
|
544
|
+
dangerouslySetInnerHTML: { __html: JSON.stringify(item) }
|
|
545
|
+
},
|
|
546
|
+
`${id}-${index}`
|
|
547
|
+
)) });
|
|
548
|
+
}
|
|
549
|
+
function DefaultBreadcrumbs({
|
|
550
|
+
items,
|
|
551
|
+
LinkComponent
|
|
552
|
+
}) {
|
|
553
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem", listStyle: "none", padding: 0 }, children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
|
|
554
|
+
index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", children: " / " }) : null,
|
|
555
|
+
index < items.length - 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkComponent, { href: item.path, children: item.name }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: item.name })
|
|
556
|
+
] }, item.path)) }) });
|
|
557
|
+
}
|
|
558
|
+
function resolveComponents(components) {
|
|
559
|
+
const LinkComponent = components?.Link ?? import_link.default;
|
|
560
|
+
return {
|
|
561
|
+
Link: LinkComponent,
|
|
562
|
+
renderBody: components?.renderBody ?? ((body) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("article", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { style: { whiteSpace: "pre-wrap", fontFamily: "inherit" }, children: body }) })),
|
|
563
|
+
renderBreadcrumbs: components?.renderBreadcrumbs ?? ((items) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultBreadcrumbs, { items, LinkComponent })),
|
|
564
|
+
renderJsonLd: components?.renderJsonLd ?? ((data, id) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultJsonLd, { data, id }))
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
async function JmpLandingDetailPage({
|
|
568
|
+
kind,
|
|
569
|
+
slug,
|
|
570
|
+
locale,
|
|
571
|
+
siteUrl,
|
|
572
|
+
components,
|
|
573
|
+
className,
|
|
574
|
+
classNames
|
|
575
|
+
}) {
|
|
576
|
+
const detail = await loadLandingPageDetail(kind, slug, locale);
|
|
577
|
+
if (!detail) {
|
|
578
|
+
(0, import_navigation.notFound)();
|
|
579
|
+
}
|
|
580
|
+
const ui = resolveComponents(components);
|
|
581
|
+
const resolvedSiteUrl = resolveJmpSiteUrl(siteUrl) ?? void 0;
|
|
582
|
+
const { page, schema_json_ld } = detail;
|
|
583
|
+
const hub = JMP_LANDING_HUB[kind];
|
|
584
|
+
const displayTitle = page.headline?.trim() || page.title;
|
|
585
|
+
const breadcrumbItems = [
|
|
586
|
+
{ name: "Home", path: "/" },
|
|
587
|
+
{ name: hub.breadcrumb, path: hub.path },
|
|
588
|
+
{ name: page.title, path: page.path }
|
|
589
|
+
];
|
|
590
|
+
const related = filterJmpLandingPagesForDefaultLocale(
|
|
591
|
+
await loadLandingPages({ kind }),
|
|
592
|
+
kind
|
|
593
|
+
).filter((item) => item.id !== page.id && item.locale === page.locale);
|
|
594
|
+
const jsonLdBlocks = [
|
|
595
|
+
...schema_json_ld ?? [],
|
|
596
|
+
jmpBreadcrumbListJsonLd(breadcrumbItems, resolvedSiteUrl)
|
|
597
|
+
];
|
|
598
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className, children: [
|
|
599
|
+
ui.renderJsonLd(jsonLdBlocks, `jmp-landing-${page.id}-ld-json`),
|
|
600
|
+
ui.renderBreadcrumbs(breadcrumbItems),
|
|
601
|
+
page.excerpt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: classNames?.excerpt, children: page.excerpt }) : null,
|
|
602
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: classNames?.title, children: displayTitle }),
|
|
603
|
+
page.body ? ui.renderBody(page.body) : null,
|
|
604
|
+
related.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
|
|
605
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h2", { className: classNames?.relatedTitle, children: [
|
|
606
|
+
"More ",
|
|
607
|
+
hub.breadcrumb.toLowerCase()
|
|
608
|
+
] }),
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: classNames?.list, children: related.slice(0, 8).map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: classNames?.listItem, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ui.Link, { href: item.path, children: item.title }) }, item.id)) })
|
|
610
|
+
] }) : null
|
|
611
|
+
] });
|
|
612
|
+
}
|
|
613
|
+
async function JmpLandingIndexPage({
|
|
614
|
+
kind,
|
|
615
|
+
siteUrl,
|
|
616
|
+
components,
|
|
617
|
+
className,
|
|
618
|
+
classNames
|
|
619
|
+
}) {
|
|
620
|
+
const ui = resolveComponents(components);
|
|
621
|
+
const hub = JMP_LANDING_HUB[kind];
|
|
622
|
+
const pages = filterJmpLandingPagesForDefaultLocale(
|
|
623
|
+
await loadLandingPages({ kind }),
|
|
624
|
+
kind
|
|
625
|
+
);
|
|
626
|
+
const breadcrumbItems = [
|
|
627
|
+
{ name: "Home", path: "/" },
|
|
628
|
+
{ name: hub.breadcrumb, path: hub.path }
|
|
629
|
+
];
|
|
630
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className, children: [
|
|
631
|
+
ui.renderBreadcrumbs(breadcrumbItems),
|
|
632
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: classNames?.title, children: hub.title }),
|
|
633
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: classNames?.hubDescription, children: hub.description }),
|
|
634
|
+
pages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: classNames?.list, children: pages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: classNames?.listItem, children: [
|
|
635
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ui.Link, { href: page.path, children: page.title }),
|
|
636
|
+
page.excerpt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: classNames?.excerpt, children: page.excerpt }) : null
|
|
637
|
+
] }, page.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: classNames?.emptyState, children: "Pages will appear here once published in the JMP dashboard." })
|
|
638
|
+
] });
|
|
639
|
+
}
|
|
640
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
641
|
+
0 && (module.exports = {
|
|
642
|
+
JMP_LANDING_HUB,
|
|
643
|
+
JmpLandingDetailPage,
|
|
644
|
+
JmpLandingIndexPage,
|
|
645
|
+
absoluteJmpSiteUrl,
|
|
646
|
+
buildJmpLandingIndexMetadata,
|
|
647
|
+
buildJmpLandingMetadata,
|
|
648
|
+
buildJmpLandingSitemapRoutes,
|
|
649
|
+
filterJmpLandingPagesForDefaultLocale,
|
|
650
|
+
filterJmpLandingPagesForLocalizedRoutes,
|
|
651
|
+
generateJmpLandingStaticParams,
|
|
652
|
+
generateJmpLocalizedLandingStaticParams,
|
|
653
|
+
jmpBreadcrumbListJsonLd,
|
|
654
|
+
jmpLandingKindSegment,
|
|
655
|
+
jmpLocalizedLandingStaticParams,
|
|
656
|
+
plainTextFromMarkdown,
|
|
657
|
+
resolveJmpSiteUrl
|
|
658
|
+
});
|
|
659
|
+
//# sourceMappingURL=landing-pages.cjs.map
|