@jmp-technologies/analytics 0.1.35 → 0.1.36

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 (95) hide show
  1. package/dist/astro/client.cjs +1 -1
  2. package/dist/astro/client.cjs.map +1 -1
  3. package/dist/astro/client.d.cts +18 -0
  4. package/dist/astro/client.d.ts +18 -0
  5. package/dist/astro/client.js +1 -1
  6. package/dist/astro/content.cjs +1 -1
  7. package/dist/astro/content.cjs.map +1 -1
  8. package/dist/astro/content.d.cts +53 -0
  9. package/dist/astro/content.d.ts +53 -0
  10. package/dist/astro/content.js +2 -2
  11. package/dist/astro/integration.cjs +1 -1
  12. package/dist/astro/integration.cjs.map +1 -1
  13. package/dist/astro/integration.d.cts +36 -0
  14. package/dist/astro/integration.d.ts +36 -0
  15. package/dist/astro/integration.js +2 -2
  16. package/dist/astro/middleware.d.cts +19 -0
  17. package/dist/astro/middleware.d.ts +19 -0
  18. package/dist/astro/register.cjs +1 -1
  19. package/dist/astro/register.cjs.map +1 -1
  20. package/dist/astro/register.d.cts +7 -0
  21. package/dist/astro/register.d.ts +7 -0
  22. package/dist/astro/register.js +2 -2
  23. package/dist/{chunk-VUCOCFVE.js → chunk-3ZEMXII6.js} +2 -2
  24. package/dist/{chunk-4ZUW24F6.js → chunk-AGGLRTUQ.js} +2 -2
  25. package/dist/{chunk-G322JCI3.js → chunk-NAQU6RAE.js} +2 -2
  26. package/dist/{chunk-3ET7F6MZ.js → chunk-RNZTKIC6.js} +2 -2
  27. package/dist/chunk-RNZTKIC6.js.map +1 -0
  28. package/dist/{chunk-6SMPRPQ3.js → chunk-YFG3AQ35.js} +2 -2
  29. package/dist/chunk-YFG3AQ35.js.map +1 -0
  30. package/dist/create-jmp-analytics-Bz0-K0Af.d.cts +69 -0
  31. package/dist/create-jmp-analytics-DRjrlWUn.d.ts +69 -0
  32. package/dist/env-public-B6Y0DG68.d.cts +14 -0
  33. package/dist/env-public-B6Y0DG68.d.ts +14 -0
  34. package/dist/index.cjs +1 -1
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +110 -0
  37. package/dist/index.d.ts +110 -0
  38. package/dist/index.js +1 -1
  39. package/dist/landing-capture-C8pyZWuF.d.cts +4 -0
  40. package/dist/landing-capture-C8pyZWuF.d.ts +4 -0
  41. package/dist/next/content.cjs +1 -1
  42. package/dist/next/content.cjs.map +1 -1
  43. package/dist/next/content.d.cts +23 -0
  44. package/dist/next/content.d.ts +23 -0
  45. package/dist/next/content.js +2 -2
  46. package/dist/next/google-tag.d.cts +17 -0
  47. package/dist/next/google-tag.d.ts +17 -0
  48. package/dist/next/instrumentation.cjs +1 -1
  49. package/dist/next/instrumentation.cjs.map +1 -1
  50. package/dist/next/instrumentation.d.cts +7 -0
  51. package/dist/next/instrumentation.d.ts +7 -0
  52. package/dist/next/instrumentation.js +1 -1
  53. package/dist/next/landing-capture-script-server.d.cts +14 -0
  54. package/dist/next/landing-capture-script-server.d.ts +14 -0
  55. package/dist/next/landing-pages.cjs +1 -1
  56. package/dist/next/landing-pages.cjs.map +1 -1
  57. package/dist/next/landing-pages.d.cts +92 -0
  58. package/dist/next/landing-pages.d.ts +92 -0
  59. package/dist/next/landing-pages.js +2 -2
  60. package/dist/next/locations.cjs +1 -1
  61. package/dist/next/locations.cjs.map +1 -1
  62. package/dist/next/locations.d.cts +55 -0
  63. package/dist/next/locations.d.ts +55 -0
  64. package/dist/next/locations.js +2 -2
  65. package/dist/next/middleware.d.cts +10 -0
  66. package/dist/next/middleware.d.ts +10 -0
  67. package/dist/next/site-root-server.cjs +1 -1
  68. package/dist/next/site-root-server.cjs.map +1 -1
  69. package/dist/next/site-root-server.d.cts +24 -0
  70. package/dist/next/site-root-server.d.ts +24 -0
  71. package/dist/next/site-root-server.js +3 -3
  72. package/dist/next.cjs +1 -1
  73. package/dist/next.cjs.map +1 -1
  74. package/dist/next.d.cts +50 -0
  75. package/dist/next.d.ts +50 -0
  76. package/dist/next.js +3 -3
  77. package/dist/react.cjs +1 -1
  78. package/dist/react.cjs.map +1 -1
  79. package/dist/react.d.cts +22 -0
  80. package/dist/react.d.ts +22 -0
  81. package/dist/react.js +2 -2
  82. package/dist/site-config-BxEmJxBB.d.ts +74 -0
  83. package/dist/site-config-Cgq67uQ1.d.cts +74 -0
  84. package/dist/track-page-view-74Su6lQY.d.ts +12 -0
  85. package/dist/track-page-view-BCX1Dsfk.d.cts +12 -0
  86. package/dist/types-yNgoakwk.d.cts +397 -0
  87. package/dist/types-yNgoakwk.d.ts +397 -0
  88. package/dist/utils-BLoWWfSw.d.ts +15 -0
  89. package/dist/utils-UPTIdK1D.d.cts +15 -0
  90. package/package.json +3 -2
  91. package/dist/chunk-3ET7F6MZ.js.map +0 -1
  92. package/dist/chunk-6SMPRPQ3.js.map +0 -1
  93. /package/dist/{chunk-VUCOCFVE.js.map → chunk-3ZEMXII6.js.map} +0 -0
  94. /package/dist/{chunk-4ZUW24F6.js.map → chunk-AGGLRTUQ.js.map} +0 -0
  95. /package/dist/{chunk-G322JCI3.js.map → chunk-NAQU6RAE.js.map} +0 -0
@@ -0,0 +1,397 @@
1
+ type JmpTrustSection = "summary" | "testimonials" | "reviews" | "stats" | "logos" | "credentials";
2
+ type JmpContentRouteManifest = {
3
+ wrapper: string;
4
+ pattern: string;
5
+ index?: string;
6
+ label?: string;
7
+ };
8
+ type JmpTrustBlockManifest = {
9
+ section: JmpTrustSection;
10
+ label?: string;
11
+ };
12
+ type JmpContactExtraManifest = {
13
+ key: string;
14
+ label: string;
15
+ };
16
+ type JmpExternalSanitySourceManifest = {
17
+ studioUrl?: string;
18
+ };
19
+ type JmpExternalShopifySourceManifest = {
20
+ adminUrl?: string;
21
+ storeUrl?: string;
22
+ };
23
+ type JmpExternalAdminLinkManifest = {
24
+ id: string;
25
+ label: string;
26
+ url: string;
27
+ };
28
+ type JmpExternalSourcesManifest = {
29
+ sanity?: JmpExternalSanitySourceManifest;
30
+ shopify?: JmpExternalShopifySourceManifest;
31
+ links?: JmpExternalAdminLinkManifest[];
32
+ };
33
+ type JmpContentManifest = {
34
+ version?: number;
35
+ routes?: JmpContentRouteManifest[];
36
+ externalSources?: JmpExternalSourcesManifest;
37
+ trust?: {
38
+ blocks?: JmpTrustBlockManifest[];
39
+ labels?: Partial<Record<JmpTrustSection, string>>;
40
+ mergeTestimonialsReviews?: boolean;
41
+ };
42
+ contact?: {
43
+ extras?: JmpContactExtraManifest[];
44
+ };
45
+ };
46
+ declare function normalizeJmpContentManifest(input: JmpContentManifest | null | undefined): JmpContentManifest | null;
47
+ declare function stableJmpManifestFingerprint(manifest: JmpContentManifest | null): string;
48
+
49
+ type JmpEventType = "page_view" | "form_submit" | "call_click" | "email_click" | "contact_click";
50
+ type JmpAnalyticsConfig = {
51
+ /** Dashboard origin, e.g. https://analytics.example.com (no trailing slash) */
52
+ baseUrl: string;
53
+ /** Per-website key from JMP admin */
54
+ trackingKey: string;
55
+ /** Log requests to console */
56
+ debug?: boolean;
57
+ /** Override fetch (tests, React Native) */
58
+ fetchImpl?: typeof fetch;
59
+ /**
60
+ * Suppress duplicate `page_view` for the same path within this window (ms).
61
+ * Helps with React Strict Mode double-mount; typical: 500–1000.
62
+ */
63
+ pageViewDedupeMs?: number;
64
+ /**
65
+ * When true, no events are sent until {@link setJmpTrackingConsent}(true).
66
+ * Pair with your cookie banner; see `NEXT_PUBLIC_JMP_ANALYTICS_REQUIRE_CONSENT`.
67
+ */
68
+ requireConsent?: boolean;
69
+ /**
70
+ * When true, register a single delegated `click` listener that classifies links
71
+ * (SMS, WhatsApp, maps, scheduling) and records them via {@link trackContactClick}.
72
+ *
73
+ * Off by default — pair with privacy disclosure / consent before enabling.
74
+ * `tel:` / `mailto:` continue to use {@link trackCallClick} / {@link trackEmailClick}.
75
+ *
76
+ * Opt out per-link with `data-jmp-no-track` on an `<a>` (or an ancestor).
77
+ */
78
+ autoTrackContactLinks?: boolean;
79
+ };
80
+ type JmpContentWrapperReportMode = "auto" | "manual"
81
+ /** @deprecated Use manual — only report {@link JmpContentConfig.contentWrappers}. */
82
+ | "explicit-only";
83
+
84
+ type JmpContentConfig = Pick<JmpAnalyticsConfig, "baseUrl" | "trackingKey" | "debug" | "fetchImpl"> & {
85
+ /**
86
+ * Optional override list. By default wrappers are discovered when
87
+ * {@link getJmpBlogPosts}, {@link getJmpFaqs}, etc. run, then reported via
88
+ * POST /api/content/capabilities.
89
+ */
90
+ contentWrappers?: JmpContentWrapper[];
91
+ /**
92
+ * `auto` (default): union of discovered usage + `contentWrappers`.
93
+ * `manual`: only `contentWrappers`.
94
+ */
95
+ contentWrapperMode?: JmpContentWrapperReportMode;
96
+ /**
97
+ * How content is structured on this site (routes, trust block order, contact
98
+ * extras). Sent with POST /api/content/capabilities so the dashboard matches
99
+ * the live template.
100
+ */
101
+ contentManifest?: JmpContentManifest;
102
+ };
103
+ /** Top-level and trust sub-wrappers the client can declare. */
104
+ type JmpContentWrapper = "blog" | "faq" | "landing" | "locations" | "contact" | "trust" | "trust.summary" | "trust.testimonials" | "trust.reviews" | "trust.stats" | "trust.logos" | "trust.credentials";
105
+ type JmpBlogPost = {
106
+ id: string;
107
+ title: string;
108
+ slug: string;
109
+ locale: string;
110
+ translation_group_id?: string;
111
+ path?: string;
112
+ excerpt: string | null;
113
+ body: string;
114
+ seo_title: string | null;
115
+ meta_description: string | null;
116
+ featured_image_url: string | null;
117
+ author_name: string | null;
118
+ author_descriptor: string | null;
119
+ tags: string[];
120
+ published_at: string | null;
121
+ updated_at: string;
122
+ };
123
+ type JmpContentLocaleAlternate = {
124
+ locale: string;
125
+ slug: string;
126
+ path: string;
127
+ };
128
+ type JmpBlogPostDetail = {
129
+ post: JmpBlogPost;
130
+ alternates: JmpContentLocaleAlternate[];
131
+ };
132
+ type JmpFaqItem = {
133
+ id: string;
134
+ slug: string;
135
+ locale: string;
136
+ translation_group_id?: string;
137
+ path?: string;
138
+ question: string;
139
+ answer: string;
140
+ category?: string | null;
141
+ sort_order: number;
142
+ updated_at: string;
143
+ };
144
+ type JmpFaqItemDetail = {
145
+ faq: JmpFaqItem;
146
+ alternates: JmpContentLocaleAlternate[];
147
+ };
148
+ type JmpPopularPage = {
149
+ path: string;
150
+ views: number;
151
+ slug: string | null;
152
+ };
153
+ type JmpPopularPagesResult = {
154
+ pages: JmpPopularPage[];
155
+ days: number;
156
+ prefix: string | null;
157
+ limit: number;
158
+ };
159
+ type JmpLandingPageKind = "service" | "location";
160
+ type JmpLandingPage = {
161
+ id: string;
162
+ kind: JmpLandingPageKind;
163
+ locale: string;
164
+ slug: string;
165
+ translation_group_id: string;
166
+ title: string;
167
+ seo_title: string | null;
168
+ meta_description: string | null;
169
+ headline: string | null;
170
+ excerpt: string | null;
171
+ body: string;
172
+ featured_image_url: string | null;
173
+ location_label: string | null;
174
+ region_code: string | null;
175
+ service_category: string | null;
176
+ published_at: string | null;
177
+ updated_at: string;
178
+ path: string;
179
+ };
180
+ type JmpLandingPageAlternate = {
181
+ locale: string;
182
+ slug: string;
183
+ path: string;
184
+ };
185
+ type JmpLandingPageDetail = {
186
+ page: JmpLandingPage;
187
+ alternates: JmpLandingPageAlternate[];
188
+ schema_json_ld: Record<string, unknown>[] | null;
189
+ };
190
+ type JmpLandingPageSitemapEntry = {
191
+ kind: JmpLandingPageKind;
192
+ locale: string;
193
+ slug: string;
194
+ path: string;
195
+ updated_at: string;
196
+ alternates: JmpLandingPageAlternate[];
197
+ };
198
+ type JmpWebsiteLocation = {
199
+ id: string;
200
+ slug: string;
201
+ name: string;
202
+ is_primary: boolean;
203
+ sort_order: number;
204
+ address: string | null;
205
+ phone: string | null;
206
+ email: string | null;
207
+ hours: string | null;
208
+ google_maps_url: string | null;
209
+ geo: {
210
+ lat: number;
211
+ lng: number;
212
+ } | null;
213
+ seo_title: string | null;
214
+ meta_description: string | null;
215
+ excerpt: string | null;
216
+ body: string;
217
+ published_at: string | null;
218
+ updated_at: string;
219
+ /** Client contact detail route, e.g. /contact/logan */
220
+ path: string;
221
+ };
222
+ type JmpWebsiteLocationDetail = {
223
+ location: JmpWebsiteLocation;
224
+ schema_json_ld: Record<string, unknown>[] | null;
225
+ };
226
+ type JmpTrustSummary = {
227
+ google_rating: number | null;
228
+ google_review_count: number | null;
229
+ google_reviews_url: string | null;
230
+ /** Minimum Google star rating (1–5) imported during sync. */
231
+ google_reviews_min_stars?: number | null;
232
+ /** When false, synced reviews are saved as drafts for manual curation. */
233
+ google_reviews_auto_publish?: boolean | null;
234
+ yelp_url: string | null;
235
+ trustpilot_url: string | null;
236
+ disclaimer: string | null;
237
+ };
238
+ type JmpTestimonial = {
239
+ id: string;
240
+ slug: string;
241
+ body: string;
242
+ author_name: string;
243
+ author_descriptor: string | null;
244
+ location: string | null;
245
+ /** 1–10 (half-star steps on a 5-star scale; 10 = 5.0 stars). */
246
+ rating: number | null;
247
+ image_url: string | null;
248
+ video_url: string | null;
249
+ /** Optional topic or service line (e.g. roofing). */
250
+ category: string | null;
251
+ /** Site section key — filter like FAQ `category` (e.g. testimonials, reviews). */
252
+ placement: string | null;
253
+ source: string | null;
254
+ /** Optional link to the original review on Google, Yelp, etc. */
255
+ source_url: string | null;
256
+ featured: boolean;
257
+ sort_order: number;
258
+ updated_at: string;
259
+ };
260
+ type JmpTrustStat = {
261
+ id: string;
262
+ slug: string;
263
+ label: string;
264
+ value: string;
265
+ sort_order: number;
266
+ updated_at: string;
267
+ };
268
+ type JmpPartnerLogo = {
269
+ id: string;
270
+ slug: string;
271
+ name: string;
272
+ image_url: string | null;
273
+ link_url: string | null;
274
+ sort_order: number;
275
+ updated_at: string;
276
+ };
277
+ type JmpCredential = {
278
+ id: string;
279
+ slug: string;
280
+ title: string;
281
+ issuer: string | null;
282
+ year: string | null;
283
+ image_url: string | null;
284
+ category: string | null;
285
+ sort_order: number;
286
+ updated_at: string;
287
+ };
288
+ type JmpTrustBundle = {
289
+ summary: JmpTrustSummary;
290
+ testimonials: JmpTestimonial[];
291
+ stats: JmpTrustStat[];
292
+ logos: JmpPartnerLogo[];
293
+ credentials: JmpCredential[];
294
+ };
295
+ type JmpSiteProfile = {
296
+ name: string;
297
+ display_name: string | null;
298
+ email: string | null;
299
+ phone: string | null;
300
+ address: string | null;
301
+ hours: string | null;
302
+ service_area: string | null;
303
+ google_maps_url: string | null;
304
+ social: {
305
+ linkedin: string | null;
306
+ instagram: string | null;
307
+ facebook: string | null;
308
+ x: string | null;
309
+ youtube: string | null;
310
+ };
311
+ cta: {
312
+ label: string | null;
313
+ url: string | null;
314
+ };
315
+ legal: {
316
+ privacy_policy_url: string | null;
317
+ terms_url: string | null;
318
+ };
319
+ /** Developer-defined keys; values filled by the client. */
320
+ extras: Record<string, string | null>;
321
+ /** GA4 measurement ID from jmp-dashboard (null = no portal-managed GA tag). */
322
+ ga_measurement_id: string | null;
323
+ /** Site default locale (BCP 47). Omitted prefix on public URLs. */
324
+ default_locale?: string;
325
+ /** Locales this site may publish content in. */
326
+ enabled_locales?: string[];
327
+ };
328
+ type TrackPageViewOptions = {
329
+ path?: string;
330
+ source?: string;
331
+ device?: string;
332
+ country?: string;
333
+ metadata?: Record<string, unknown>;
334
+ };
335
+ type TrackLeadOptions = {
336
+ /** Path where the lead was submitted, e.g. /contact */
337
+ path?: string;
338
+ name?: string;
339
+ email?: string;
340
+ phone?: string;
341
+ company?: string;
342
+ website?: string;
343
+ subject?: string;
344
+ message?: string;
345
+ /**
346
+ * Optional flexible metadata for dynamic lead forms.
347
+ * Prefer the normalized envelope (formId/formVersion/answers/derived/attribution),
348
+ * but unknown keys are also accepted by the API.
349
+ */
350
+ metadata?: LeadMetadata;
351
+ /**
352
+ * Optional session id (from createJmpAnalytics internal session) if your app wants to pass it explicitly.
353
+ * Most callers should omit this.
354
+ */
355
+ sessionId?: string;
356
+ };
357
+ type LeadMetadataValue = string | number | boolean | null | undefined | LeadMetadataValue[] | {
358
+ [key: string]: LeadMetadataValue;
359
+ };
360
+ type LeadMetadata = {
361
+ formId?: string;
362
+ formVersion?: string;
363
+ leadKind?: string;
364
+ answers?: Record<string, LeadMetadataValue>;
365
+ derived?: Record<string, LeadMetadataValue>;
366
+ attribution?: {
367
+ utm_source?: string;
368
+ utm_medium?: string;
369
+ utm_campaign?: string;
370
+ utm_content?: string;
371
+ utm_term?: string;
372
+ gclid?: string;
373
+ fbclid?: string;
374
+ msclkid?: string;
375
+ ttclid?: string;
376
+ [key: string]: LeadMetadataValue | undefined;
377
+ };
378
+ tags?: string[];
379
+ [key: string]: LeadMetadataValue | undefined;
380
+ };
381
+ type JmpServerRequestLike = {
382
+ url?: string;
383
+ headers: Pick<Headers, "get"> | Record<string, string | string[] | undefined | null>;
384
+ };
385
+ type TrackServerPageViewOptions = {
386
+ request?: JmpServerRequestLike;
387
+ /** Overrides request URL path. Use pathname + search when possible. */
388
+ path?: string;
389
+ /** Original visitor user agent. Useful when not passing `request`. */
390
+ userAgent?: string | null;
391
+ /** Original visitor referrer. Useful when not passing `request`. */
392
+ referer?: string | null;
393
+ metadata?: Record<string, unknown>;
394
+ sessionId?: string;
395
+ };
396
+
397
+ export { type JmpPartnerLogo as A, type JmpPopularPage as B, type JmpTrustBlockManifest as C, type JmpTrustSection as D, type JmpTrustStat as E, type JmpTrustSummary as F, type LeadMetadataValue as G, normalizeJmpContentManifest as H, stableJmpManifestFingerprint as I, type JmpBlogPost as J, type LeadMetadata as L, type TrackPageViewOptions as T, type JmpFaqItem as a, type JmpLandingPage as b, type JmpLandingPageDetail as c, type JmpLandingPageKind as d, type JmpLandingPageSitemapEntry as e, type JmpPopularPagesResult as f, type JmpSiteProfile as g, type JmpTestimonial as h, type JmpTrustBundle as i, type JmpWebsiteLocation as j, type JmpWebsiteLocationDetail as k, type JmpContentWrapper as l, type JmpContentManifest as m, type JmpContentConfig as n, type JmpServerRequestLike as o, type JmpAnalyticsConfig as p, type JmpEventType as q, type TrackLeadOptions as r, type TrackServerPageViewOptions as s, type JmpBlogPostDetail as t, type JmpFaqItemDetail as u, type JmpContactExtraManifest as v, type JmpContentLocaleAlternate as w, type JmpContentRouteManifest as x, type JmpContentWrapperReportMode as y, type JmpCredential as z };
@@ -0,0 +1,15 @@
1
+ import { b as JmpLandingPage, d as JmpLandingPageKind } from './types-yNgoakwk.js';
2
+
3
+ /** Strip lightweight markdown for meta descriptions and schema text fields. */
4
+ declare function plainTextFromMarkdown(input: string, maxLength?: number): string;
5
+ declare function resolveJmpSiteUrl(override?: string): string | null;
6
+ declare function absoluteJmpSiteUrl(path: string, siteUrl?: string): string;
7
+ declare function filterJmpLandingPagesForDefaultLocale(pages: JmpLandingPage[], kind: JmpLandingPageKind): JmpLandingPage[];
8
+ /** Pages whose path is `/{locale}/{areas|services}/{slug}` (three+ segments). */
9
+ declare function filterJmpLandingPagesForLocalizedRoutes(pages: JmpLandingPage[], kind: JmpLandingPageKind): JmpLandingPage[];
10
+ declare function jmpLocalizedLandingStaticParams(pages: JmpLandingPage[], kind: JmpLandingPageKind): {
11
+ locale: string;
12
+ slug: string;
13
+ }[];
14
+
15
+ export { absoluteJmpSiteUrl as a, filterJmpLandingPagesForLocalizedRoutes as b, filterJmpLandingPagesForDefaultLocale as f, jmpLocalizedLandingStaticParams as j, plainTextFromMarkdown as p, resolveJmpSiteUrl as r };
@@ -0,0 +1,15 @@
1
+ import { b as JmpLandingPage, d as JmpLandingPageKind } from './types-yNgoakwk.cjs';
2
+
3
+ /** Strip lightweight markdown for meta descriptions and schema text fields. */
4
+ declare function plainTextFromMarkdown(input: string, maxLength?: number): string;
5
+ declare function resolveJmpSiteUrl(override?: string): string | null;
6
+ declare function absoluteJmpSiteUrl(path: string, siteUrl?: string): string;
7
+ declare function filterJmpLandingPagesForDefaultLocale(pages: JmpLandingPage[], kind: JmpLandingPageKind): JmpLandingPage[];
8
+ /** Pages whose path is `/{locale}/{areas|services}/{slug}` (three+ segments). */
9
+ declare function filterJmpLandingPagesForLocalizedRoutes(pages: JmpLandingPage[], kind: JmpLandingPageKind): JmpLandingPage[];
10
+ declare function jmpLocalizedLandingStaticParams(pages: JmpLandingPage[], kind: JmpLandingPageKind): {
11
+ locale: string;
12
+ slug: string;
13
+ }[];
14
+
15
+ export { absoluteJmpSiteUrl as a, filterJmpLandingPagesForLocalizedRoutes as b, filterJmpLandingPagesForDefaultLocale as f, jmpLocalizedLandingStaticParams as j, plainTextFromMarkdown as p, resolveJmpSiteUrl as r };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmp-technologies/analytics",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "JMP Analytics tracking plus blog, FAQ, trust content, and site contact profile for client websites",
5
5
  "license": "UNLICENSED",
6
6
  "keywords": [
@@ -112,7 +112,8 @@
112
112
  "access": "public"
113
113
  },
114
114
  "scripts": {
115
- "build": "tsup src/index.ts src/react.tsx src/next.tsx src/next/google-tag.tsx src/next/landing-capture-script-server.tsx src/next/site-root-server.tsx src/next/middleware.ts src/next/instrumentation.ts src/next/content.ts src/next/landing-pages.tsx src/next/locations.tsx src/astro/content.ts src/astro/client.ts src/astro/middleware.ts src/astro/register.ts src/astro/integration.ts --format esm,cjs --dts --clean --sourcemap --external react --external react-dom --external next"
115
+ "build": "tsup src/index.ts src/react.tsx src/next.tsx src/next/google-tag.tsx src/next/landing-capture-script-server.tsx src/next/site-root-server.tsx src/next/middleware.ts src/next/instrumentation.ts src/next/content.ts src/next/landing-pages.tsx src/next/locations.tsx src/astro/content.ts src/astro/client.ts src/astro/middleware.ts src/astro/register.ts src/astro/integration.ts --format esm,cjs --dts --clean --sourcemap --external react --external react-dom --external next",
116
+ "prepublishOnly": "npm run build"
116
117
  },
117
118
  "peerDependencies": {
118
119
  "next": ">=14",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/content/site-content.ts"],"sourcesContent":["import {\n getJmpBlogPost,\n getJmpBlogPosts,\n getJmpFaqs,\n getJmpLandingPageDetail,\n getJmpLandingPageSitemap,\n getJmpLandingPages,\n getJmpLocations,\n getJmpLocationDetail,\n getJmpPopularPages,\n getJmpSiteProfile,\n getJmpTrustBundle,\n type JmpBlogPost,\n type JmpFaqItem,\n type JmpLandingPage,\n type JmpLandingPageDetail,\n type JmpLandingPageKind,\n type JmpLandingPageSitemapEntry,\n type JmpPopularPagesResult,\n type JmpWebsiteLocation,\n type JmpWebsiteLocationDetail,\n type JmpSiteProfile,\n type JmpTestimonial,\n type JmpTrustBundle,\n} from \"../index\"\nimport {\n getJmpContentConfig,\n getJmpSiteDefinition,\n type JmpSiteSocialLinks,\n} from \"../site-config\"\n\nexport type {\n JmpBlogPost,\n JmpFaqItem,\n JmpLandingPage,\n JmpLandingPageDetail,\n JmpLandingPageKind,\n JmpLandingPageSitemapEntry,\n JmpWebsiteLocation,\n JmpWebsiteLocationDetail,\n JmpSiteProfile,\n JmpTestimonial,\n JmpTrustBundle,\n}\n\nexport { getJmpContentConfig } from \"../site-config\"\n\nexport type { JmpSiteSocialLinks } from \"../site-config\"\n\nexport type ResolvedSiteContact = {\n displayName: string\n email: string\n founderName: string\n dashboardDemoUrl: string\n profilePhotoSrc: string\n linkedin: string | null\n social: JmpSiteSocialLinks\n phone: string | null\n address: string | null\n googleMapsUrl: string | null\n googleMapsEmbedUrl: string | null\n hours: string | null\n serviceArea: string | null\n privacyUrl: string\n termsUrl: string\n cta: { label: string | null; url: string | null }\n}\n\nconst DEFAULT_EXTRA_KEYS = {\n founderName: [\"founder-name\", \"founder_name\"],\n dashboardDemoUrl: [\"dashboard-demo-url\", \"sample-dashboard-url\"],\n profilePhotoSrc: [\"profile-photo-url\", \"profile_photo_url\"],\n hours: [\"hours\", \"business-hours\"],\n serviceArea: [\"service-area\", \"service_area\", \"service-area-text\"],\n googleMapsEmbedUrl: [\"google-maps-embed-url\", \"google_maps_embed_url\"],\n} as const\n\nfunction sortBlogPosts(posts: JmpBlogPost[]): JmpBlogPost[] {\n return [...posts].sort((a, b) => {\n const da = a.published_at ?? a.updated_at\n const db = b.published_at ?? b.updated_at\n return db.localeCompare(da)\n })\n}\n\nfunction sortFaqs(items: JmpFaqItem[]): JmpFaqItem[] {\n return [...items].sort((a, b) => a.sort_order - b.sort_order)\n}\n\nfunction readProfileExtra(\n profile: JmpSiteProfile | null,\n keys: readonly string[],\n): string | null {\n for (const key of keys) {\n const value = profile?.extras?.[key]?.trim()\n if (value) {\n return value\n }\n }\n return null\n}\n\n/** Resolve a path or URL against {@link defineJmpSite}'s `siteUrl`. */\nexport function absoluteSiteAssetUrl(src: string): string {\n const trimmed = src.trim()\n if (trimmed.startsWith(\"http://\") || trimmed.startsWith(\"https://\")) {\n return trimmed\n }\n const siteUrl = getJmpSiteDefinition()?.siteUrl?.replace(/\\/$/, \"\")\n if (!siteUrl) {\n return trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`\n }\n return `${siteUrl}${trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`}`\n}\n\nexport async function loadSiteProfile(): Promise<JmpSiteProfile | null> {\n const config = getJmpContentConfig()\n if (!config) {\n return null\n }\n try {\n return await getJmpSiteProfile(config)\n } catch {\n return null\n }\n}\n\nexport function resolveSiteContact(profile: JmpSiteProfile | null): ResolvedSiteContact {\n const site = getJmpSiteDefinition()\n const fallback = site?.contactFallback ?? {}\n const extraKeys = {\n ...DEFAULT_EXTRA_KEYS,\n ...site?.contactExtraKeys,\n }\n\n const email = profile?.email?.trim() || fallback.email || \"\"\n const social: JmpSiteSocialLinks = {\n linkedin:\n profile?.social?.linkedin?.trim() || fallback.linkedin || null,\n instagram:\n profile?.social?.instagram?.trim() || fallback.instagram || null,\n facebook:\n profile?.social?.facebook?.trim() || fallback.facebook || null,\n x: profile?.social?.x?.trim() || fallback.x || null,\n youtube:\n profile?.social?.youtube?.trim() || fallback.youtube || null,\n }\n const phone = profile?.phone?.trim() || fallback.phone || null\n\n return {\n displayName:\n profile?.display_name?.trim() ||\n profile?.name?.trim() ||\n fallback.displayName ||\n \"\",\n founderName:\n readProfileExtra(profile, extraKeys.founderName ?? []) ||\n fallback.founderName ||\n \"\",\n dashboardDemoUrl:\n readProfileExtra(profile, extraKeys.dashboardDemoUrl ?? []) ||\n fallback.dashboardDemoUrl ||\n \"\",\n profilePhotoSrc:\n readProfileExtra(profile, extraKeys.profilePhotoSrc ?? []) ||\n fallback.profilePhotoSrc ||\n \"\",\n email,\n linkedin: social.linkedin,\n social,\n phone,\n address: profile?.address?.trim() || fallback.address || null,\n googleMapsUrl:\n profile?.google_maps_url?.trim() || fallback.googleMapsUrl || null,\n googleMapsEmbedUrl:\n readProfileExtra(profile, extraKeys.googleMapsEmbedUrl ?? []) ||\n fallback.googleMapsEmbedUrl ||\n null,\n hours:\n readProfileExtra(profile, extraKeys.hours ?? []) || fallback.hours || null,\n serviceArea:\n readProfileExtra(profile, extraKeys.serviceArea ?? []) ||\n fallback.serviceArea ||\n null,\n privacyUrl: profile?.legal?.privacy_policy_url?.trim() || fallback.privacyUrl || \"/privacy\",\n termsUrl: profile?.legal?.terms_url?.trim() || fallback.termsUrl || \"/terms\",\n cta: {\n label: profile?.cta?.label?.trim() || null,\n url: profile?.cta?.url?.trim() || null,\n },\n }\n}\n\nexport async function getResolvedSiteContact(): Promise<ResolvedSiteContact> {\n const profile = await loadSiteProfile()\n return resolveSiteContact(profile)\n}\n\n/** Non-null social profile URLs in a stable order for JSON-LD `sameAs`. */\nexport function listResolvedSocialUrls(social: JmpSiteSocialLinks): string[] {\n return [\n social.linkedin,\n social.instagram,\n social.facebook,\n social.x,\n social.youtube,\n ].filter((url): url is string => Boolean(url))\n}\n\nexport async function loadBlogPosts(locale?: string): Promise<JmpBlogPost[]> {\n const c = getJmpContentConfig()\n if (!c) {\n return []\n }\n try {\n const posts = await getJmpBlogPosts(c, locale ? { locale } : undefined)\n return sortBlogPosts(posts)\n } catch {\n return []\n }\n}\n\nexport async function loadBlogPost(\n slug: string,\n locale?: string\n): Promise<JmpBlogPost | null> {\n const c = getJmpContentConfig()\n if (!c) {\n return null\n }\n try {\n return await getJmpBlogPost(c, slug, locale)\n } catch {\n return null\n }\n}\n\nexport async function loadFaqs(locale?: string): Promise<JmpFaqItem[]> {\n const c = getJmpContentConfig()\n if (!c) {\n return []\n }\n try {\n const faqs = await getJmpFaqs(c, locale ? { locale } : undefined)\n return sortFaqs(faqs)\n } catch {\n return []\n }\n}\n\nexport async function loadFaqBySlug(\n slug: string,\n locale?: string\n): Promise<JmpFaqItem | null> {\n const normalized = slug.trim()\n if (!normalized) {\n return null\n }\n const items = await loadFaqs(locale)\n return (\n items.find((item) => item.slug === normalized || item.id === normalized) ?? null\n )\n}\n\nexport async function loadLandingPages(filters?: {\n kind?: JmpLandingPageKind\n locale?: string\n}): Promise<JmpLandingPage[]> {\n const c = getJmpContentConfig()\n if (!c) {\n return []\n }\n try {\n return await getJmpLandingPages(c, filters)\n } catch {\n return []\n }\n}\n\nexport async function loadLandingPageDetail(\n kind: JmpLandingPageKind,\n slug: string,\n locale?: string\n): Promise<JmpLandingPageDetail | null> {\n const c = getJmpContentConfig()\n if (!c) {\n return null\n }\n try {\n return await getJmpLandingPageDetail(c, kind, slug, locale)\n } catch {\n return null\n }\n}\n\nexport async function loadLandingPageSitemap(): Promise<JmpLandingPageSitemapEntry[]> {\n const c = getJmpContentConfig()\n if (!c) {\n return []\n }\n try {\n return await getJmpLandingPageSitemap(c)\n } catch {\n return []\n }\n}\n\nexport async function loadLocations(): Promise<JmpWebsiteLocation[]> {\n const c = getJmpContentConfig()\n if (!c) {\n return []\n }\n try {\n return await getJmpLocations(c)\n } catch {\n return []\n }\n}\n\nexport async function loadLocationDetail(\n slug: string\n): Promise<JmpWebsiteLocationDetail | null> {\n const c = getJmpContentConfig()\n if (!c) {\n return null\n }\n try {\n return await getJmpLocationDetail(c, slug)\n } catch {\n return null\n }\n}\n\nexport async function loadTrustBundle(): Promise<JmpTrustBundle | null> {\n const c = getJmpContentConfig()\n if (!c) {\n return null\n }\n try {\n return await getJmpTrustBundle(c)\n } catch {\n return null\n }\n}\n\nexport function filterFeaturedTrustQuotes(\n testimonials: JmpTestimonial[],\n placement: \"testimonials\" | \"reviews\",\n limit = 2,\n): JmpTestimonial[] {\n return testimonials\n .filter((item) => {\n if (!item.featured) {\n return false\n }\n const bucket = item.placement?.trim().toLowerCase()\n if (placement === \"reviews\") {\n return bucket === \"reviews\"\n }\n return !bucket || bucket === \"testimonials\"\n })\n .sort((a, b) => a.sort_order - b.sort_order)\n .slice(0, limit)\n}\n\nexport async function loadPopularPages(filters?: {\n prefix?: string\n days?: number\n limit?: number\n}): Promise<JmpPopularPagesResult | null> {\n const c = getJmpContentConfig()\n if (!c) {\n return null\n }\n try {\n return await getJmpPopularPages(c, filters)\n } catch {\n return null\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoEA,IAAM,qBAAqB;AAAA,EACzB,aAAa,CAAC,gBAAgB,cAAc;AAAA,EAC5C,kBAAkB,CAAC,sBAAsB,sBAAsB;AAAA,EAC/D,iBAAiB,CAAC,qBAAqB,mBAAmB;AAAA,EAC1D,OAAO,CAAC,SAAS,gBAAgB;AAAA,EACjC,aAAa,CAAC,gBAAgB,gBAAgB,mBAAmB;AAAA,EACjE,oBAAoB,CAAC,yBAAyB,uBAAuB;AACvE;AAEA,SAAS,cAAc,OAAqC;AAC1D,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC/B,UAAM,KAAK,EAAE,gBAAgB,EAAE;AAC/B,UAAM,KAAK,EAAE,gBAAgB,EAAE;AAC/B,WAAO,GAAG,cAAc,EAAE;AAAA,EAC5B,CAAC;AACH;AAEA,SAAS,SAAS,OAAmC;AACnD,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU;AAC9D;AAEA,SAAS,iBACP,SACA,MACe;AACf,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,SAAS,SAAS,GAAG,GAAG,KAAK;AAC3C,QAAI,OAAO;AACT,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,qBAAqB,KAAqB;AACxD,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,QAAQ,WAAW,SAAS,KAAK,QAAQ,WAAW,UAAU,GAAG;AACnE,WAAO;AAAA,EACT;AACA,QAAM,UAAU,qBAAqB,GAAG,SAAS,QAAQ,OAAO,EAAE;AAClE,MAAI,CAAC,SAAS;AACZ,WAAO,QAAQ,WAAW,GAAG,IAAI,UAAU,IAAI,OAAO;AAAA,EACxD;AACA,SAAO,GAAG,OAAO,GAAG,QAAQ,WAAW,GAAG,IAAI,UAAU,IAAI,OAAO,EAAE;AACvE;AAEA,eAAsB,kBAAkD;AACtE,QAAM,SAAS,oBAAoB;AACnC,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,MAAM,kBAAkB,MAAM;AAAA,EACvC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,mBAAmB,SAAqD;AACtF,QAAM,OAAO,qBAAqB;AAClC,QAAM,WAAW,MAAM,mBAAmB,CAAC;AAC3C,QAAM,YAAY;AAAA,IAChB,GAAG;AAAA,IACH,GAAG,MAAM;AAAA,EACX;AAEA,QAAM,QAAQ,SAAS,OAAO,KAAK,KAAK,SAAS,SAAS;AAC1D,QAAM,SAA6B;AAAA,IACjC,UACE,SAAS,QAAQ,UAAU,KAAK,KAAK,SAAS,YAAY;AAAA,IAC5D,WACE,SAAS,QAAQ,WAAW,KAAK,KAAK,SAAS,aAAa;AAAA,IAC9D,UACE,SAAS,QAAQ,UAAU,KAAK,KAAK,SAAS,YAAY;AAAA,IAC5D,GAAG,SAAS,QAAQ,GAAG,KAAK,KAAK,SAAS,KAAK;AAAA,IAC/C,SACE,SAAS,QAAQ,SAAS,KAAK,KAAK,SAAS,WAAW;AAAA,EAC5D;AACA,QAAM,QAAQ,SAAS,OAAO,KAAK,KAAK,SAAS,SAAS;AAE1D,SAAO;AAAA,IACL,aACE,SAAS,cAAc,KAAK,KAC5B,SAAS,MAAM,KAAK,KACpB,SAAS,eACT;AAAA,IACF,aACE,iBAAiB,SAAS,UAAU,eAAe,CAAC,CAAC,KACrD,SAAS,eACT;AAAA,IACF,kBACE,iBAAiB,SAAS,UAAU,oBAAoB,CAAC,CAAC,KAC1D,SAAS,oBACT;AAAA,IACF,iBACE,iBAAiB,SAAS,UAAU,mBAAmB,CAAC,CAAC,KACzD,SAAS,mBACT;AAAA,IACF;AAAA,IACA,UAAU,OAAO;AAAA,IACjB;AAAA,IACA;AAAA,IACA,SAAS,SAAS,SAAS,KAAK,KAAK,SAAS,WAAW;AAAA,IACzD,eACE,SAAS,iBAAiB,KAAK,KAAK,SAAS,iBAAiB;AAAA,IAChE,oBACE,iBAAiB,SAAS,UAAU,sBAAsB,CAAC,CAAC,KAC5D,SAAS,sBACT;AAAA,IACF,OACE,iBAAiB,SAAS,UAAU,SAAS,CAAC,CAAC,KAAK,SAAS,SAAS;AAAA,IACxE,aACE,iBAAiB,SAAS,UAAU,eAAe,CAAC,CAAC,KACrD,SAAS,eACT;AAAA,IACF,YAAY,SAAS,OAAO,oBAAoB,KAAK,KAAK,SAAS,cAAc;AAAA,IACjF,UAAU,SAAS,OAAO,WAAW,KAAK,KAAK,SAAS,YAAY;AAAA,IACpE,KAAK;AAAA,MACH,OAAO,SAAS,KAAK,OAAO,KAAK,KAAK;AAAA,MACtC,KAAK,SAAS,KAAK,KAAK,KAAK,KAAK;AAAA,IACpC;AAAA,EACF;AACF;AAEA,eAAsB,yBAAuD;AAC3E,QAAM,UAAU,MAAM,gBAAgB;AACtC,SAAO,mBAAmB,OAAO;AACnC;AAGO,SAAS,uBAAuB,QAAsC;AAC3E,SAAO;AAAA,IACL,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT,EAAE,OAAO,CAAC,QAAuB,QAAQ,GAAG,CAAC;AAC/C;AAEA,eAAsB,cAAc,QAAyC;AAC3E,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACF,UAAM,QAAQ,MAAM,gBAAgB,GAAG,SAAS,EAAE,OAAO,IAAI,MAAS;AACtE,WAAO,cAAc,KAAK;AAAA,EAC5B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,aACpB,MACA,QAC6B;AAC7B,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,MAAM,eAAe,GAAG,MAAM,MAAM;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,SAAS,QAAwC;AACrE,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACF,UAAM,OAAO,MAAM,WAAW,GAAG,SAAS,EAAE,OAAO,IAAI,MAAS;AAChE,WAAO,SAAS,IAAI;AAAA,EACtB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,cACpB,MACA,QAC4B;AAC5B,QAAM,aAAa,KAAK,KAAK;AAC7B,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,MAAM,SAAS,MAAM;AACnC,SACE,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,cAAc,KAAK,OAAO,UAAU,KAAK;AAEhF;AAEA,eAAsB,iBAAiB,SAGT;AAC5B,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACF,WAAO,MAAM,mBAAmB,GAAG,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,sBACpB,MACA,MACA,QACsC;AACtC,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,MAAM,wBAAwB,GAAG,MAAM,MAAM,MAAM;AAAA,EAC5D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,yBAAgE;AACpF,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACF,WAAO,MAAM,yBAAyB,CAAC;AAAA,EACzC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,gBAA+C;AACnE,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACF,WAAO,MAAM,gBAAgB,CAAC;AAAA,EAChC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,mBACpB,MAC0C;AAC1C,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,MAAM,qBAAqB,GAAG,IAAI;AAAA,EAC3C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,kBAAkD;AACtE,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,MAAM,kBAAkB,CAAC;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,0BACd,cACA,WACA,QAAQ,GACU;AAClB,SAAO,aACJ,OAAO,CAAC,SAAS;AAChB,QAAI,CAAC,KAAK,UAAU;AAClB,aAAO;AAAA,IACT;AACA,UAAM,SAAS,KAAK,WAAW,KAAK,EAAE,YAAY;AAClD,QAAI,cAAc,WAAW;AAC3B,aAAO,WAAW;AAAA,IACpB;AACA,WAAO,CAAC,UAAU,WAAW;AAAA,EAC/B,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU,EAC1C,MAAM,GAAG,KAAK;AACnB;AAEA,eAAsB,iBAAiB,SAIG;AACxC,QAAM,IAAI,oBAAoB;AAC9B,MAAI,CAAC,GAAG;AACN,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,MAAM,mBAAmB,GAAG,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}