@jmp-technologies/analytics 0.1.27 → 0.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/astro/client.cjs +256 -11
- 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 +2 -2
- package/dist/astro/content.cjs +308 -13
- package/dist/astro/content.cjs.map +1 -1
- package/dist/astro/content.d.cts +12 -3
- package/dist/astro/content.d.ts +12 -3
- package/dist/astro/content.js +9 -3
- package/dist/astro/integration.cjs +228 -10
- package/dist/astro/integration.cjs.map +1 -1
- package/dist/astro/integration.js +3 -3
- package/dist/astro/middleware.cjs +2 -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 +228 -10
- package/dist/astro/register.cjs.map +1 -1
- package/dist/astro/register.js +3 -3
- package/dist/{chunk-KZ4WVDGL.js → chunk-7623G3XL.js} +3 -3
- package/dist/{chunk-A4RRTY5D.js → chunk-AIFJ7DVO.js} +3 -2
- package/dist/{chunk-A4RRTY5D.js.map → chunk-AIFJ7DVO.js.map} +1 -1
- package/dist/{chunk-YCVHRMM6.js → chunk-G5BMWPQ6.js} +2 -3
- package/dist/{chunk-YCVHRMM6.js.map → chunk-G5BMWPQ6.js.map} +1 -1
- package/dist/{chunk-HODG4NJQ.js → chunk-HFLU7HQE.js} +2 -2
- package/dist/{chunk-PG3IOI5O.js → chunk-HKMDWTA2.js} +53 -6
- package/dist/chunk-HKMDWTA2.js.map +1 -0
- package/dist/{chunk-DNYJF7BG.js → chunk-KPTMZQCY.js} +3 -3
- package/dist/{chunk-FNWE2DT5.js → chunk-NDSPSAWQ.js} +18 -8
- package/dist/chunk-NDSPSAWQ.js.map +1 -0
- package/dist/{chunk-UVYF33XE.js → chunk-NI7R6QZQ.js} +293 -13
- package/dist/chunk-NI7R6QZQ.js.map +1 -0
- package/dist/chunk-RI3KKDPX.js +75 -0
- package/dist/chunk-RI3KKDPX.js.map +1 -0
- package/dist/{create-jmp-analytics-D4Qw_d6o.d.cts → create-jmp-analytics-D1dUsqCQ.d.cts} +1 -2
- package/dist/{create-jmp-analytics-DpG5Hdl5.d.ts → create-jmp-analytics-htx2oOEf.d.ts} +1 -2
- package/dist/index.cjs +295 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/index.js +10 -2
- package/dist/next/content.cjs +310 -13
- package/dist/next/content.cjs.map +1 -1
- package/dist/next/content.d.cts +7 -5
- package/dist/next/content.d.ts +7 -5
- package/dist/next/content.js +11 -3
- package/dist/next/content.js.map +1 -1
- package/dist/next/instrumentation.cjs +228 -10
- package/dist/next/instrumentation.cjs.map +1 -1
- package/dist/next/instrumentation.js +2 -2
- package/dist/next/landing-capture-script-server.cjs +1 -2
- package/dist/next/landing-capture-script-server.cjs.map +1 -1
- package/dist/next/landing-capture-script-server.js +1 -1
- package/dist/next/landing-pages.cjs +228 -12
- package/dist/next/landing-pages.cjs.map +1 -1
- package/dist/next/landing-pages.d.cts +4 -16
- package/dist/next/landing-pages.d.ts +4 -16
- package/dist/next/landing-pages.js +13 -67
- package/dist/next/landing-pages.js.map +1 -1
- package/dist/next/locations.cjs +737 -0
- package/dist/next/locations.cjs.map +1 -0
- package/dist/next/locations.d.cts +55 -0
- package/dist/next/locations.d.ts +55 -0
- package/dist/next/locations.js +158 -0
- package/dist/next/locations.js.map +1 -0
- package/dist/next/middleware.cjs +2 -1
- 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 +259 -14
- package/dist/next/site-root-server.cjs.map +1 -1
- package/dist/next/site-root-server.js +5 -5
- package/dist/next.cjs +270 -17
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +3 -3
- package/dist/next.d.ts +3 -3
- package/dist/next.js +4 -4
- package/dist/react.cjs +389 -136
- 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 +3 -3
- package/dist/{site-config-UTzDG-UG.d.ts → site-config-B7USGGzu.d.cts} +22 -2
- package/dist/{site-config-CJqYnZm7.d.cts → site-config-C4bcUoLI.d.ts} +22 -2
- package/dist/{track-page-view-tX0Magkd.d.cts → track-page-view-C4TbbULE.d.cts} +1 -1
- package/dist/{track-page-view-CMAqyhD_.d.ts → track-page-view-RiB-xgIx.d.ts} +1 -1
- package/dist/{types-B-111Wht.d.ts → types-DRljY1Yy.d.cts} +92 -2
- package/dist/{types-B-111Wht.d.cts → types-DRljY1Yy.d.ts} +92 -2
- package/dist/utils-BajG58pj.d.cts +15 -0
- package/dist/utils-CHT3SQFv.d.ts +15 -0
- package/package.json +7 -2
- package/dist/chunk-FNWE2DT5.js.map +0 -1
- package/dist/chunk-PG3IOI5O.js.map +0 -1
- package/dist/chunk-UVYF33XE.js.map +0 -1
- /package/dist/{chunk-KZ4WVDGL.js.map → chunk-7623G3XL.js.map} +0 -0
- /package/dist/{chunk-HODG4NJQ.js.map → chunk-HFLU7HQE.js.map} +0 -0
- /package/dist/{chunk-DNYJF7BG.js.map → chunk-KPTMZQCY.js.map} +0 -0
|
@@ -0,0 +1,737 @@
|
|
|
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/locations.tsx
|
|
31
|
+
var locations_exports = {};
|
|
32
|
+
__export(locations_exports, {
|
|
33
|
+
JmpLocationDetailPage: () => JmpLocationDetailPage,
|
|
34
|
+
JmpLocationHubPage: () => JmpLocationHubPage,
|
|
35
|
+
buildJmpLocationHubMetadata: () => buildJmpLocationHubMetadata,
|
|
36
|
+
buildJmpLocationMetadata: () => buildJmpLocationMetadata,
|
|
37
|
+
buildJmpLocationSitemapRoutes: () => buildJmpLocationSitemapRoutes,
|
|
38
|
+
generateJmpLocationStaticParams: () => generateJmpLocationStaticParams,
|
|
39
|
+
plainTextFromMarkdown: () => plainTextFromMarkdown,
|
|
40
|
+
resolveJmpSiteUrl: () => resolveJmpSiteUrl
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(locations_exports);
|
|
43
|
+
var import_link = __toESM(require("next/link"), 1);
|
|
44
|
+
var import_navigation = require("next/navigation");
|
|
45
|
+
|
|
46
|
+
// src/landing-capture.ts
|
|
47
|
+
var LANDING_REFERER_COOKIE_MAX_AGE_SEC = 30 * 60;
|
|
48
|
+
|
|
49
|
+
// src/constants.ts
|
|
50
|
+
var JMP_ANALYTICS_SDK_VERSION = "0.1.26";
|
|
51
|
+
|
|
52
|
+
// src/http.ts
|
|
53
|
+
function responseLooksLikeHtml(body) {
|
|
54
|
+
const s = body.trimStart();
|
|
55
|
+
return s.startsWith("<!") || s.toLowerCase().startsWith("<html") || s.startsWith("<") && /<html[\s>]/i.test(s.slice(0, 500));
|
|
56
|
+
}
|
|
57
|
+
function normalizeBaseUrl(baseUrl) {
|
|
58
|
+
return baseUrl.replace(/\/$/, "");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/content/manifest.ts
|
|
62
|
+
var JMP_CONTENT_MANIFEST_VERSION = 1;
|
|
63
|
+
var TRUST_SECTIONS = /* @__PURE__ */ new Set([
|
|
64
|
+
"summary",
|
|
65
|
+
"testimonials",
|
|
66
|
+
"reviews",
|
|
67
|
+
"stats",
|
|
68
|
+
"logos",
|
|
69
|
+
"credentials"
|
|
70
|
+
]);
|
|
71
|
+
function normalizeKey(value) {
|
|
72
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
73
|
+
}
|
|
74
|
+
function isValidExtraKey(key) {
|
|
75
|
+
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(key);
|
|
76
|
+
}
|
|
77
|
+
var MAX_EXTERNAL_ADMIN_LINKS = 10;
|
|
78
|
+
var MAX_EXTERNAL_ADMIN_LINK_LABEL_LENGTH = 80;
|
|
79
|
+
var EXTERNAL_ADMIN_LINK_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
80
|
+
function tryNormalizeHttpUrl(input) {
|
|
81
|
+
if (typeof input !== "string" || !input.trim()) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const url = new URL(input.trim());
|
|
86
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return url.toString().replace(/\/$/, "");
|
|
90
|
+
} catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function normalizeShopifyExternalSource(shopify) {
|
|
95
|
+
if (!shopify || typeof shopify !== "object") {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const adminUrl = tryNormalizeHttpUrl(shopify.adminUrl);
|
|
99
|
+
const storeUrl = tryNormalizeHttpUrl(shopify.storeUrl);
|
|
100
|
+
if (!adminUrl && !storeUrl) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
...adminUrl ? { adminUrl } : {},
|
|
105
|
+
...storeUrl ? { storeUrl } : {}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function normalizeExternalAdminLinkEntries(links) {
|
|
109
|
+
if (!Array.isArray(links)) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
113
|
+
const out = [];
|
|
114
|
+
for (const raw of links) {
|
|
115
|
+
if (!raw || typeof raw !== "object" || out.length >= MAX_EXTERNAL_ADMIN_LINKS) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const id = typeof raw.id === "string" ? raw.id.trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") : "";
|
|
119
|
+
const label = typeof raw.label === "string" ? raw.label.trim().slice(0, MAX_EXTERNAL_ADMIN_LINK_LABEL_LENGTH) : "";
|
|
120
|
+
const url = tryNormalizeHttpUrl(raw.url);
|
|
121
|
+
if (!id || !label || !url || !EXTERNAL_ADMIN_LINK_ID_PATTERN.test(id) || seenIds.has(id)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
seenIds.add(id);
|
|
125
|
+
out.push({ id, label, url });
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
function normalizeExternalSources(externalSources) {
|
|
130
|
+
if (!externalSources || typeof externalSources !== "object") {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const studioUrl = tryNormalizeHttpUrl(externalSources.sanity?.studioUrl);
|
|
134
|
+
const shopify = normalizeShopifyExternalSource(externalSources.shopify);
|
|
135
|
+
const links = normalizeExternalAdminLinkEntries(externalSources.links);
|
|
136
|
+
if (!studioUrl && !shopify && links.length === 0) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
...studioUrl ? { sanity: { studioUrl } } : {},
|
|
141
|
+
...shopify ? { shopify } : {},
|
|
142
|
+
...links.length > 0 ? { links } : {}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function normalizeJmpContentManifest(input) {
|
|
146
|
+
if (!input || typeof input !== "object") {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
const routes = normalizeRoutes(input.routes);
|
|
150
|
+
const externalSources = normalizeExternalSources(input.externalSources);
|
|
151
|
+
const trust = normalizeTrust(input.trust);
|
|
152
|
+
const contact = normalizeContact(input.contact);
|
|
153
|
+
if (routes.length === 0 && !externalSources && !trust && !contact) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
version: JMP_CONTENT_MANIFEST_VERSION,
|
|
158
|
+
...routes.length > 0 ? { routes } : {},
|
|
159
|
+
...externalSources ? { externalSources } : {},
|
|
160
|
+
...trust ? { trust } : {},
|
|
161
|
+
...contact ? { contact } : {}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function normalizeRoutes(routes) {
|
|
165
|
+
if (!Array.isArray(routes)) {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
const seen = /* @__PURE__ */ new Set();
|
|
169
|
+
const out = [];
|
|
170
|
+
for (const raw of routes) {
|
|
171
|
+
if (!raw || typeof raw !== "object") continue;
|
|
172
|
+
const wrapper = typeof raw.wrapper === "string" ? raw.wrapper.trim().toLowerCase() : "";
|
|
173
|
+
const pattern = typeof raw.pattern === "string" ? raw.pattern.trim() : "";
|
|
174
|
+
if (!wrapper || !pattern) continue;
|
|
175
|
+
const dedupe = `${wrapper}:${pattern}`;
|
|
176
|
+
if (seen.has(dedupe)) continue;
|
|
177
|
+
seen.add(dedupe);
|
|
178
|
+
out.push({
|
|
179
|
+
wrapper,
|
|
180
|
+
pattern,
|
|
181
|
+
...typeof raw.index === "string" && raw.index.trim() ? { index: raw.index.trim() } : {},
|
|
182
|
+
...typeof raw.label === "string" && raw.label.trim() ? { label: raw.label.trim() } : {}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
function normalizeTrust(trust) {
|
|
188
|
+
if (!trust || typeof trust !== "object") return null;
|
|
189
|
+
const blocks = normalizeTrustBlocks(trust.blocks);
|
|
190
|
+
const labels = normalizeTrustLabels(trust.labels);
|
|
191
|
+
const mergeTestimonialsReviews = trust.mergeTestimonialsReviews === true;
|
|
192
|
+
if (blocks.length === 0 && !labels && !mergeTestimonialsReviews) return null;
|
|
193
|
+
return {
|
|
194
|
+
...blocks.length > 0 ? { blocks } : {},
|
|
195
|
+
...labels ? { labels } : {},
|
|
196
|
+
...mergeTestimonialsReviews ? { mergeTestimonialsReviews: true } : {}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function normalizeTrustBlocks(blocks) {
|
|
200
|
+
if (!Array.isArray(blocks)) return [];
|
|
201
|
+
const seen = /* @__PURE__ */ new Set();
|
|
202
|
+
const out = [];
|
|
203
|
+
for (const raw of blocks) {
|
|
204
|
+
if (!raw || typeof raw !== "object") continue;
|
|
205
|
+
const section = typeof raw.section === "string" ? raw.section.trim().toLowerCase() : "";
|
|
206
|
+
if (!TRUST_SECTIONS.has(section) || seen.has(section)) continue;
|
|
207
|
+
seen.add(section);
|
|
208
|
+
out.push({
|
|
209
|
+
section,
|
|
210
|
+
...typeof raw.label === "string" && raw.label.trim() ? { label: raw.label.trim() } : {}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
function normalizeTrustLabels(labels) {
|
|
216
|
+
if (!labels || typeof labels !== "object") return null;
|
|
217
|
+
const out = {};
|
|
218
|
+
for (const [key, value] of Object.entries(labels)) {
|
|
219
|
+
if (TRUST_SECTIONS.has(key) && typeof value === "string" && value.trim()) {
|
|
220
|
+
out[key] = value.trim();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
224
|
+
}
|
|
225
|
+
function normalizeContact(contact) {
|
|
226
|
+
if (!contact || typeof contact !== "object") return null;
|
|
227
|
+
const extras = normalizeContactExtras(contact.extras);
|
|
228
|
+
return extras.length > 0 ? { extras } : null;
|
|
229
|
+
}
|
|
230
|
+
function normalizeContactExtras(extras) {
|
|
231
|
+
if (!Array.isArray(extras)) return [];
|
|
232
|
+
const seen = /* @__PURE__ */ new Set();
|
|
233
|
+
const out = [];
|
|
234
|
+
for (const raw of extras) {
|
|
235
|
+
if (!raw || typeof raw !== "object") continue;
|
|
236
|
+
const label = typeof raw.label === "string" ? raw.label.trim() : "";
|
|
237
|
+
const key = normalizeKey(
|
|
238
|
+
typeof raw.key === "string" && raw.key.trim() ? raw.key : label
|
|
239
|
+
);
|
|
240
|
+
if (!key || !label || !isValidExtraKey(key) || seen.has(key)) continue;
|
|
241
|
+
seen.add(key);
|
|
242
|
+
out.push({ key, label });
|
|
243
|
+
}
|
|
244
|
+
return out;
|
|
245
|
+
}
|
|
246
|
+
function stableJmpManifestFingerprint(manifest) {
|
|
247
|
+
return manifest ? JSON.stringify(manifest) : "";
|
|
248
|
+
}
|
|
249
|
+
function inferWrapperSlotsFromManifest(manifest) {
|
|
250
|
+
const slots = /* @__PURE__ */ new Set();
|
|
251
|
+
for (const route of manifest?.routes ?? []) {
|
|
252
|
+
slots.add(route.wrapper);
|
|
253
|
+
}
|
|
254
|
+
for (const block of manifest?.trust?.blocks ?? []) {
|
|
255
|
+
slots.add(`trust.${block.section}`);
|
|
256
|
+
slots.add("trust");
|
|
257
|
+
}
|
|
258
|
+
if (manifest?.contact?.extras?.length) {
|
|
259
|
+
slots.add("contact");
|
|
260
|
+
}
|
|
261
|
+
return [...slots];
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/content/fetch.ts
|
|
265
|
+
async function getContent(config, path) {
|
|
266
|
+
const text = await getContentText(config, path);
|
|
267
|
+
try {
|
|
268
|
+
return JSON.parse(text);
|
|
269
|
+
} catch {
|
|
270
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
271
|
+
const url = `${baseUrl}${path}`;
|
|
272
|
+
throw new Error(`JMP content HTTP 200 \u2014 ${url} returned invalid JSON.`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async function getContentText(config, path) {
|
|
276
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
277
|
+
const resolvedFetch = config.fetchImpl ?? (typeof globalThis !== "undefined" && globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
278
|
+
if (!resolvedFetch) {
|
|
279
|
+
throw new Error("JMP content: fetch is not available; pass fetchImpl in config");
|
|
280
|
+
}
|
|
281
|
+
const url = `${baseUrl}${path}`;
|
|
282
|
+
if (config.debug) {
|
|
283
|
+
console.debug("[@jmp-technologies/analytics]", "GET", url);
|
|
284
|
+
}
|
|
285
|
+
const res = await resolvedFetch(url, {
|
|
286
|
+
method: "GET",
|
|
287
|
+
headers: {
|
|
288
|
+
"X-JMP-Tracking-Key": config.trackingKey
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
const text = await res.text();
|
|
292
|
+
if (!res.ok) {
|
|
293
|
+
if (responseLooksLikeHtml(text)) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
`JMP content HTTP ${res.status} \u2014 ${url} returned HTML (not the JSON API). Set baseUrl to your JMP Analytics dashboard origin.`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
let parsed = {};
|
|
299
|
+
try {
|
|
300
|
+
parsed = JSON.parse(text);
|
|
301
|
+
} catch {
|
|
302
|
+
parsed = { error: text };
|
|
303
|
+
}
|
|
304
|
+
throw new Error(
|
|
305
|
+
[`JMP content HTTP ${res.status}`, parsed.error, parsed.hint].filter(Boolean).join(" \u2014 ")
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
return text;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/content/wrapper-discovery.ts
|
|
312
|
+
var WRAPPER_SLOT_ORDER = [
|
|
313
|
+
"blog",
|
|
314
|
+
"faq",
|
|
315
|
+
"contact",
|
|
316
|
+
"trust",
|
|
317
|
+
"trust.summary",
|
|
318
|
+
"trust.testimonials",
|
|
319
|
+
"trust.reviews",
|
|
320
|
+
"trust.stats",
|
|
321
|
+
"trust.logos",
|
|
322
|
+
"trust.credentials"
|
|
323
|
+
];
|
|
324
|
+
var discovered = /* @__PURE__ */ new Set();
|
|
325
|
+
var syncTimer = null;
|
|
326
|
+
var pendingSyncConfig = null;
|
|
327
|
+
var reportedDedupeKeys = /* @__PURE__ */ new Set();
|
|
328
|
+
var syncHandler = null;
|
|
329
|
+
function markContentWrapper(slot) {
|
|
330
|
+
const normalized = slot.trim().toLowerCase();
|
|
331
|
+
if (!normalized) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
discovered.add(normalized);
|
|
335
|
+
}
|
|
336
|
+
function getDiscoveredContentWrappers() {
|
|
337
|
+
return sortWrapperSlots([...discovered]);
|
|
338
|
+
}
|
|
339
|
+
function resolveContentManifestForReport(config) {
|
|
340
|
+
return normalizeJmpContentManifest(config.contentManifest);
|
|
341
|
+
}
|
|
342
|
+
function resolveContentWrappersForReport(config) {
|
|
343
|
+
const explicit = config.contentWrappers ?? [];
|
|
344
|
+
const auto = getDiscoveredContentWrappers();
|
|
345
|
+
const fromManifest = inferWrapperSlotsFromManifest(
|
|
346
|
+
resolveContentManifestForReport(config)
|
|
347
|
+
);
|
|
348
|
+
if (config.contentWrapperMode === "manual") {
|
|
349
|
+
return sortWrapperSlots([...explicit, ...fromManifest]);
|
|
350
|
+
}
|
|
351
|
+
if (config.contentWrapperMode === "explicit-only") {
|
|
352
|
+
return sortWrapperSlots([...explicit, ...fromManifest]);
|
|
353
|
+
}
|
|
354
|
+
const merged = /* @__PURE__ */ new Set([...explicit, ...auto, ...fromManifest]);
|
|
355
|
+
return sortWrapperSlots([...merged]);
|
|
356
|
+
}
|
|
357
|
+
function hasReportedContentWrappers(dedupeKey) {
|
|
358
|
+
return reportedDedupeKeys.has(dedupeKey);
|
|
359
|
+
}
|
|
360
|
+
function rememberReportedContentWrappers(dedupeKey) {
|
|
361
|
+
reportedDedupeKeys.add(dedupeKey);
|
|
362
|
+
}
|
|
363
|
+
function setContentWrapperSyncHandler(handler) {
|
|
364
|
+
syncHandler = handler;
|
|
365
|
+
}
|
|
366
|
+
function scheduleContentWrapperSync(config) {
|
|
367
|
+
if (!syncHandler) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
pendingSyncConfig = config;
|
|
371
|
+
if (syncTimer) {
|
|
372
|
+
clearTimeout(syncTimer);
|
|
373
|
+
}
|
|
374
|
+
syncTimer = setTimeout(() => {
|
|
375
|
+
syncTimer = null;
|
|
376
|
+
const cfg = pendingSyncConfig;
|
|
377
|
+
pendingSyncConfig = null;
|
|
378
|
+
if (!cfg || !syncHandler) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
void syncHandler(cfg).catch(() => {
|
|
382
|
+
});
|
|
383
|
+
}, 750);
|
|
384
|
+
}
|
|
385
|
+
function sortWrapperSlots(slots) {
|
|
386
|
+
const order = new Map(WRAPPER_SLOT_ORDER.map((slot, index) => [slot, index]));
|
|
387
|
+
return [...new Set(slots)].sort((a, b) => {
|
|
388
|
+
const ai = order.get(a) ?? 999;
|
|
389
|
+
const bi = order.get(b) ?? 999;
|
|
390
|
+
if (ai !== bi) {
|
|
391
|
+
return ai - bi;
|
|
392
|
+
}
|
|
393
|
+
return a.localeCompare(b);
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/content/api.ts
|
|
398
|
+
function afterContentWrapperUse(config) {
|
|
399
|
+
scheduleContentWrapperSync(config);
|
|
400
|
+
}
|
|
401
|
+
async function getJmpLocations(config) {
|
|
402
|
+
const data = await getContent(
|
|
403
|
+
config,
|
|
404
|
+
"/api/content/locations"
|
|
405
|
+
);
|
|
406
|
+
markContentWrapper("locations");
|
|
407
|
+
afterContentWrapperUse(config);
|
|
408
|
+
return data.locations;
|
|
409
|
+
}
|
|
410
|
+
async function getJmpLocationDetail(config, slug) {
|
|
411
|
+
const normalized = slug.trim();
|
|
412
|
+
if (!normalized) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
const detail = await getContent(
|
|
417
|
+
config,
|
|
418
|
+
`/api/content/locations/${encodeURIComponent(normalized)}`
|
|
419
|
+
);
|
|
420
|
+
markContentWrapper("locations");
|
|
421
|
+
afterContentWrapperUse(config);
|
|
422
|
+
return detail;
|
|
423
|
+
} catch (error) {
|
|
424
|
+
if (error instanceof Error && error.message.includes("HTTP 404")) {
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
async function registerJmpContentWrappers(config) {
|
|
431
|
+
const wrappers = resolveContentWrappersForReport(config);
|
|
432
|
+
if (!wrappers.length) {
|
|
433
|
+
return { ok: false, skipped: true };
|
|
434
|
+
}
|
|
435
|
+
const manifest = resolveContentManifestForReport(config);
|
|
436
|
+
const dedupeKey = `${config.trackingKey}:${[...wrappers].sort().join(",")}:${stableJmpManifestFingerprint(manifest)}`;
|
|
437
|
+
if (hasReportedContentWrappers(dedupeKey)) {
|
|
438
|
+
return { ok: true, wrappers };
|
|
439
|
+
}
|
|
440
|
+
const baseUrl = normalizeBaseUrl(config.baseUrl);
|
|
441
|
+
const resolvedFetch = config.fetchImpl ?? (typeof globalThis !== "undefined" && globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
|
|
442
|
+
if (!resolvedFetch) {
|
|
443
|
+
throw new Error(
|
|
444
|
+
"JMP content wrappers: fetch is not available; pass fetchImpl in config"
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
const url = `${baseUrl}/api/content/capabilities`;
|
|
448
|
+
if (config.debug) {
|
|
449
|
+
console.debug("[@jmp-technologies/analytics]", "POST", url, {
|
|
450
|
+
wrappers,
|
|
451
|
+
manifest
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
const body = {
|
|
455
|
+
wrappers,
|
|
456
|
+
sdkVersion: JMP_ANALYTICS_SDK_VERSION
|
|
457
|
+
};
|
|
458
|
+
if (manifest) {
|
|
459
|
+
body.manifest = manifest;
|
|
460
|
+
}
|
|
461
|
+
const res = await resolvedFetch(url, {
|
|
462
|
+
method: "POST",
|
|
463
|
+
headers: {
|
|
464
|
+
"Content-Type": "application/json",
|
|
465
|
+
"X-JMP-Tracking-Key": config.trackingKey
|
|
466
|
+
},
|
|
467
|
+
body: JSON.stringify(body)
|
|
468
|
+
});
|
|
469
|
+
const text = await res.text();
|
|
470
|
+
if (!res.ok) {
|
|
471
|
+
let parsed = {};
|
|
472
|
+
try {
|
|
473
|
+
parsed = JSON.parse(text);
|
|
474
|
+
} catch {
|
|
475
|
+
parsed = { error: text };
|
|
476
|
+
}
|
|
477
|
+
throw new Error(
|
|
478
|
+
[`JMP content wrappers HTTP ${res.status}`, parsed.error, parsed.hint].filter(Boolean).join(" \u2014 ")
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
rememberReportedContentWrappers(dedupeKey);
|
|
482
|
+
const data = JSON.parse(text);
|
|
483
|
+
return { ok: true, wrappers: data.wrappers ?? wrappers };
|
|
484
|
+
}
|
|
485
|
+
setContentWrapperSyncHandler(registerJmpContentWrappers);
|
|
486
|
+
|
|
487
|
+
// src/env-public.ts
|
|
488
|
+
function firstDefined(...values) {
|
|
489
|
+
for (const v of values) {
|
|
490
|
+
if (v) return v;
|
|
491
|
+
}
|
|
492
|
+
return void 0;
|
|
493
|
+
}
|
|
494
|
+
function readJmpPublicEnvFromProcessEnv() {
|
|
495
|
+
if (typeof process === "undefined" || !process.env) {
|
|
496
|
+
return {};
|
|
497
|
+
}
|
|
498
|
+
const { env } = process;
|
|
499
|
+
const analyticsUrl = firstDefined(
|
|
500
|
+
env.NEXT_PUBLIC_JMP_ANALYTICS_URL,
|
|
501
|
+
env.PUBLIC_JMP_ANALYTICS_URL
|
|
502
|
+
);
|
|
503
|
+
const trackingKey = firstDefined(
|
|
504
|
+
env.NEXT_PUBLIC_JMP_TRACKING_KEY,
|
|
505
|
+
env.PUBLIC_JMP_TRACKING_KEY
|
|
506
|
+
);
|
|
507
|
+
const requireConsentRaw = firstDefined(
|
|
508
|
+
env.NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT,
|
|
509
|
+
env.PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT
|
|
510
|
+
);
|
|
511
|
+
const autoContactRaw = firstDefined(
|
|
512
|
+
env.NEXT_PUBLIC_JMP_AUTO_CONTACT_LINKS,
|
|
513
|
+
env.PUBLIC_JMP_AUTO_CONTACT_LINKS
|
|
514
|
+
);
|
|
515
|
+
return {
|
|
516
|
+
analyticsUrl,
|
|
517
|
+
trackingKey,
|
|
518
|
+
requireConsent: requireConsentRaw === "true",
|
|
519
|
+
autoContactLinks: autoContactRaw === "true"
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function readJmpPublicEnvFromProcess(overrides) {
|
|
523
|
+
const fromEnv = readJmpPublicEnvFromProcessEnv();
|
|
524
|
+
return {
|
|
525
|
+
analyticsUrl: firstDefined(overrides?.analyticsUrl, fromEnv.analyticsUrl),
|
|
526
|
+
trackingKey: firstDefined(overrides?.trackingKey, fromEnv.trackingKey),
|
|
527
|
+
requireConsent: overrides?.requireConsent ?? fromEnv.requireConsent,
|
|
528
|
+
autoContactLinks: overrides?.autoContactLinks ?? fromEnv.autoContactLinks
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// src/site-config.ts
|
|
533
|
+
var registeredSite = null;
|
|
534
|
+
function getJmpSiteDefinition() {
|
|
535
|
+
return registeredSite;
|
|
536
|
+
}
|
|
537
|
+
function getJmpContentConfig() {
|
|
538
|
+
const { analyticsUrl, trackingKey } = readJmpPublicEnvFromProcess();
|
|
539
|
+
if (!analyticsUrl || !trackingKey) {
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
const site = getJmpSiteDefinition();
|
|
543
|
+
return {
|
|
544
|
+
baseUrl: analyticsUrl,
|
|
545
|
+
trackingKey,
|
|
546
|
+
contentWrappers: site?.contentWrappers ?? void 0,
|
|
547
|
+
contentManifest: site?.contentManifest ?? void 0
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// src/content/site-content.ts
|
|
552
|
+
async function loadLocations() {
|
|
553
|
+
const c = getJmpContentConfig();
|
|
554
|
+
if (!c) {
|
|
555
|
+
return [];
|
|
556
|
+
}
|
|
557
|
+
try {
|
|
558
|
+
return await getJmpLocations(c);
|
|
559
|
+
} catch {
|
|
560
|
+
return [];
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
async function loadLocationDetail(slug) {
|
|
564
|
+
const c = getJmpContentConfig();
|
|
565
|
+
if (!c) {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
try {
|
|
569
|
+
return await getJmpLocationDetail(c, slug);
|
|
570
|
+
} catch {
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// src/landing-pages/utils.ts
|
|
576
|
+
function plainTextFromMarkdown(input, maxLength = 5e3) {
|
|
577
|
+
return input.replace(/[#*_`[\]]/g, "").trim().slice(0, maxLength);
|
|
578
|
+
}
|
|
579
|
+
function resolveJmpSiteUrl(override) {
|
|
580
|
+
const fromArg = override?.trim().replace(/\/$/, "");
|
|
581
|
+
if (fromArg) return fromArg;
|
|
582
|
+
const fromConfig = getJmpSiteDefinition()?.siteUrl?.trim().replace(/\/$/, "");
|
|
583
|
+
return fromConfig || null;
|
|
584
|
+
}
|
|
585
|
+
function absoluteJmpSiteUrl(path, siteUrl) {
|
|
586
|
+
const base = resolveJmpSiteUrl(siteUrl);
|
|
587
|
+
if (!base) {
|
|
588
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
589
|
+
}
|
|
590
|
+
const normalized = path.startsWith("/") ? path : `/${path}`;
|
|
591
|
+
return `${base}${normalized}`;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/next/locations.tsx
|
|
595
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
596
|
+
function DefaultJsonLd({
|
|
597
|
+
data,
|
|
598
|
+
id
|
|
599
|
+
}) {
|
|
600
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: data.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
601
|
+
"script",
|
|
602
|
+
{
|
|
603
|
+
type: "application/ld+json",
|
|
604
|
+
dangerouslySetInnerHTML: { __html: JSON.stringify(item) }
|
|
605
|
+
},
|
|
606
|
+
`${id}-${index}`
|
|
607
|
+
)) });
|
|
608
|
+
}
|
|
609
|
+
function resolveComponents(components) {
|
|
610
|
+
const LinkComponent = components?.Link ?? import_link.default;
|
|
611
|
+
return {
|
|
612
|
+
Link: LinkComponent,
|
|
613
|
+
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 }) })),
|
|
614
|
+
renderJsonLd: components?.renderJsonLd ?? ((data, id) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultJsonLd, { data, id }))
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
function locationCanonicalUrl(location, siteUrl) {
|
|
618
|
+
return absoluteJmpSiteUrl(location.path, siteUrl);
|
|
619
|
+
}
|
|
620
|
+
async function generateJmpLocationStaticParams() {
|
|
621
|
+
const locations = await loadLocations();
|
|
622
|
+
return locations.map((location) => ({ slug: location.slug }));
|
|
623
|
+
}
|
|
624
|
+
async function buildJmpLocationMetadata({
|
|
625
|
+
slug,
|
|
626
|
+
siteUrl
|
|
627
|
+
}) {
|
|
628
|
+
const detail = await loadLocationDetail(slug);
|
|
629
|
+
if (!detail) {
|
|
630
|
+
return { title: "Not found" };
|
|
631
|
+
}
|
|
632
|
+
const { location } = detail;
|
|
633
|
+
const title = location.seo_title?.trim() || location.name;
|
|
634
|
+
const description = location.meta_description?.trim() || location.excerpt?.trim() || plainTextFromMarkdown(location.body, 160) || location.name;
|
|
635
|
+
const canonical = locationCanonicalUrl(location, siteUrl);
|
|
636
|
+
return {
|
|
637
|
+
title,
|
|
638
|
+
description,
|
|
639
|
+
alternates: { canonical },
|
|
640
|
+
openGraph: {
|
|
641
|
+
title,
|
|
642
|
+
description,
|
|
643
|
+
type: "website",
|
|
644
|
+
url: canonical
|
|
645
|
+
},
|
|
646
|
+
twitter: {
|
|
647
|
+
card: "summary",
|
|
648
|
+
title,
|
|
649
|
+
description
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function buildJmpLocationHubMetadata(siteUrl) {
|
|
654
|
+
const canonical = absoluteJmpSiteUrl("/contact", siteUrl);
|
|
655
|
+
return {
|
|
656
|
+
title: "Contact",
|
|
657
|
+
description: "Find our office locations, phone numbers, and hours.",
|
|
658
|
+
alternates: { canonical }
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
function buildJmpLocationSitemapRoutes(locations, options = {}) {
|
|
662
|
+
const changeFrequency = options.changeFrequency ?? "monthly";
|
|
663
|
+
const hub = {
|
|
664
|
+
url: absoluteJmpSiteUrl("/contact", options.siteUrl),
|
|
665
|
+
changeFrequency,
|
|
666
|
+
priority: 0.8
|
|
667
|
+
};
|
|
668
|
+
const detailRoutes = locations.map((location) => ({
|
|
669
|
+
url: absoluteJmpSiteUrl(location.path, options.siteUrl),
|
|
670
|
+
lastModified: location.updated_at ? new Date(location.updated_at) : void 0,
|
|
671
|
+
changeFrequency,
|
|
672
|
+
priority: location.is_primary ? 0.75 : 0.65
|
|
673
|
+
}));
|
|
674
|
+
return [hub, ...detailRoutes];
|
|
675
|
+
}
|
|
676
|
+
async function JmpLocationHubPage({
|
|
677
|
+
components,
|
|
678
|
+
className,
|
|
679
|
+
classNames
|
|
680
|
+
}) {
|
|
681
|
+
const locations = await loadLocations();
|
|
682
|
+
const { Link: LinkComponent } = resolveComponents(components);
|
|
683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className, children: [
|
|
684
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: classNames?.title, children: "Contact" }),
|
|
685
|
+
locations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: classNames?.emptyState, children: "Add office locations in the JMP dashboard (Content \u2192 Locations)." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: classNames?.list, children: locations.map((location) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: classNames?.listItem, children: [
|
|
686
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkComponent, { href: location.path, children: location.name }),
|
|
687
|
+
location.phone ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: location.phone }) : null,
|
|
688
|
+
location.address ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: location.address }) : null
|
|
689
|
+
] }, location.id)) })
|
|
690
|
+
] });
|
|
691
|
+
}
|
|
692
|
+
async function JmpLocationDetailPage({
|
|
693
|
+
slug,
|
|
694
|
+
siteUrl,
|
|
695
|
+
components,
|
|
696
|
+
className,
|
|
697
|
+
classNames
|
|
698
|
+
}) {
|
|
699
|
+
const detail = await loadLocationDetail(slug);
|
|
700
|
+
if (!detail) {
|
|
701
|
+
(0, import_navigation.notFound)();
|
|
702
|
+
}
|
|
703
|
+
const { location, schema_json_ld } = detail;
|
|
704
|
+
const { Link: LinkComponent, renderBody, renderJsonLd } = resolveComponents(components);
|
|
705
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className, children: [
|
|
706
|
+
schema_json_ld && schema_json_ld.length > 0 ? renderJsonLd(schema_json_ld, "jmp-location-jsonld") : null,
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkComponent, { href: "/contact", children: "All locations" }) }),
|
|
708
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: classNames?.title, children: location.name }),
|
|
709
|
+
location.excerpt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: classNames?.excerpt, children: location.excerpt }) : null,
|
|
710
|
+
location.phone ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
|
|
711
|
+
"Phone:",
|
|
712
|
+
" ",
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: `tel:${location.phone.replace(/[^\d+]/g, "")}`, children: location.phone })
|
|
714
|
+
] }) : null,
|
|
715
|
+
location.email ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
|
|
716
|
+
"Email: ",
|
|
717
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: `mailto:${location.email}`, children: location.email })
|
|
718
|
+
] }) : null,
|
|
719
|
+
location.address ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: location.address }) : null,
|
|
720
|
+
location.hours ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: location.hours }) : null,
|
|
721
|
+
location.google_maps_url ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: location.google_maps_url, children: "Directions" }) }) : null,
|
|
722
|
+
location.body.trim() ? renderBody(location.body) : null,
|
|
723
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkComponent, { href: "/contact", children: "All locations" }) })
|
|
724
|
+
] });
|
|
725
|
+
}
|
|
726
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
727
|
+
0 && (module.exports = {
|
|
728
|
+
JmpLocationDetailPage,
|
|
729
|
+
JmpLocationHubPage,
|
|
730
|
+
buildJmpLocationHubMetadata,
|
|
731
|
+
buildJmpLocationMetadata,
|
|
732
|
+
buildJmpLocationSitemapRoutes,
|
|
733
|
+
generateJmpLocationStaticParams,
|
|
734
|
+
plainTextFromMarkdown,
|
|
735
|
+
resolveJmpSiteUrl
|
|
736
|
+
});
|
|
737
|
+
//# sourceMappingURL=locations.cjs.map
|