@uptrademedia/site-kit 1.0.5 → 1.0.8

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 (169) hide show
  1. package/dist/analytics/index.js +7 -7
  2. package/dist/analytics/index.mjs +3 -3
  3. package/dist/api-QUIPJJCX.js +77 -0
  4. package/dist/api-QUIPJJCX.js.map +1 -0
  5. package/dist/api-V3BA5PMX.mjs +4 -0
  6. package/dist/api-V3BA5PMX.mjs.map +1 -0
  7. package/dist/blog/index.d.mts +2 -2
  8. package/dist/blog/index.d.ts +2 -2
  9. package/dist/blog/index.js +40 -6
  10. package/dist/blog/index.js.map +1 -1
  11. package/dist/blog/index.mjs +40 -6
  12. package/dist/blog/index.mjs.map +1 -1
  13. package/dist/blog/server.d.mts +3 -2
  14. package/dist/blog/server.d.ts +3 -2
  15. package/dist/blog/server.js +13 -6
  16. package/dist/blog/server.js.map +1 -1
  17. package/dist/blog/server.mjs +13 -6
  18. package/dist/blog/server.mjs.map +1 -1
  19. package/dist/{chunk-FKVJOT2F.mjs → chunk-42EXHJTC.mjs} +196 -7
  20. package/dist/chunk-42EXHJTC.mjs.map +1 -0
  21. package/dist/{scanner-AZV5I6US.mjs → chunk-44OMJFCG.mjs} +354 -14
  22. package/dist/chunk-44OMJFCG.mjs.map +1 -0
  23. package/dist/chunk-4TGJYNHV.js +981 -0
  24. package/dist/chunk-4TGJYNHV.js.map +1 -0
  25. package/dist/chunk-4XPGGLVP.mjs +53 -0
  26. package/dist/{chunk-NYKRE2FL.mjs.map → chunk-4XPGGLVP.mjs.map} +1 -1
  27. package/dist/{generators-TO2FKJR6.mjs → chunk-6ONUXZDO.mjs} +26 -9
  28. package/dist/chunk-6ONUXZDO.mjs.map +1 -0
  29. package/dist/chunk-CG53ASWX.mjs +729 -0
  30. package/dist/chunk-CG53ASWX.mjs.map +1 -0
  31. package/dist/{scanner-ETJAMIT7.js → chunk-DERI27QC.js} +448 -102
  32. package/dist/chunk-DERI27QC.js.map +1 -0
  33. package/dist/chunk-DYM5ML2V.mjs +1518 -0
  34. package/dist/chunk-DYM5ML2V.mjs.map +1 -0
  35. package/dist/chunk-FLZZOX44.js +1526 -0
  36. package/dist/chunk-FLZZOX44.js.map +1 -0
  37. package/dist/{chunk-7H6I3ECV.mjs → chunk-FQVGK746.mjs} +63 -3
  38. package/dist/chunk-FQVGK746.mjs.map +1 -0
  39. package/dist/{chunk-GQ6ZOU2N.mjs → chunk-JGQPAXTL.mjs} +4 -4
  40. package/dist/{chunk-GQ6ZOU2N.mjs.map → chunk-JGQPAXTL.mjs.map} +1 -1
  41. package/dist/{chunk-V3F5J6CV.js → chunk-JUEVN4Q4.js} +196 -7
  42. package/dist/chunk-JUEVN4Q4.js.map +1 -0
  43. package/dist/chunk-KKMGTT7F.mjs +968 -0
  44. package/dist/chunk-KKMGTT7F.mjs.map +1 -0
  45. package/dist/{chunk-XQJX252G.mjs → chunk-MB3WR5KJ.mjs} +28 -18
  46. package/dist/chunk-MB3WR5KJ.mjs.map +1 -0
  47. package/dist/{chunk-2IHTEKHU.mjs → chunk-QD5CN2OI.mjs} +16 -7
  48. package/dist/chunk-QD5CN2OI.mjs.map +1 -0
  49. package/dist/{chunk-SBVEYCSV.js → chunk-QQB4FO4Q.js} +7 -7
  50. package/dist/{chunk-SBVEYCSV.js.map → chunk-QQB4FO4Q.js.map} +1 -1
  51. package/dist/{generators-YZWIGHCO.js → chunk-S2GXR5HY.js} +26 -9
  52. package/dist/chunk-S2GXR5HY.js.map +1 -0
  53. package/dist/{chunk-O2OHHBUD.js → chunk-TDK7DLCH.js} +30 -20
  54. package/dist/chunk-TDK7DLCH.js.map +1 -0
  55. package/dist/{chunk-QP5NCO2E.js → chunk-VDI7KYME.js} +67 -2
  56. package/dist/chunk-VDI7KYME.js.map +1 -0
  57. package/dist/chunk-VOR53RUR.js +753 -0
  58. package/dist/chunk-VOR53RUR.js.map +1 -0
  59. package/dist/{chunk-GAJLEDRD.js → chunk-ZKJ7JKFV.js} +16 -7
  60. package/dist/chunk-ZKJ7JKFV.js.map +1 -0
  61. package/dist/chunk-ZSMWDLMK.js +63 -0
  62. package/dist/{chunk-EQCVQC35.js.map → chunk-ZSMWDLMK.js.map} +1 -1
  63. package/dist/cli/index.js +37269 -0
  64. package/dist/cli/index.js.map +1 -0
  65. package/dist/cli/index.mjs +37233 -0
  66. package/dist/cli/index.mjs.map +1 -0
  67. package/dist/commerce/index.js +1 -1
  68. package/dist/commerce/index.mjs +1 -1
  69. package/dist/commerce/server.d.mts +12 -3
  70. package/dist/commerce/server.d.ts +12 -3
  71. package/dist/commerce/server.js +71 -70
  72. package/dist/commerce/server.js.map +1 -1
  73. package/dist/commerce/server.mjs +71 -70
  74. package/dist/commerce/server.mjs.map +1 -1
  75. package/dist/engage/index.d.mts +6 -4
  76. package/dist/engage/index.d.ts +6 -4
  77. package/dist/engage/index.js +8 -4
  78. package/dist/engage/index.mjs +2 -2
  79. package/dist/forms/index.js +1 -1
  80. package/dist/forms/index.mjs +1 -1
  81. package/dist/generators-5EU4PTVF.js +33 -0
  82. package/dist/generators-5EU4PTVF.js.map +1 -0
  83. package/dist/generators-TYPILCWD.mjs +4 -0
  84. package/dist/generators-TYPILCWD.mjs.map +1 -0
  85. package/dist/images/index.js +11 -11
  86. package/dist/images/index.mjs +4 -4
  87. package/dist/index.d.mts +154 -5
  88. package/dist/index.d.ts +154 -5
  89. package/dist/index.js +940 -24
  90. package/dist/index.js.map +1 -1
  91. package/dist/index.mjs +819 -7
  92. package/dist/index.mjs.map +1 -1
  93. package/dist/llms/index.d.mts +657 -0
  94. package/dist/llms/index.d.ts +657 -0
  95. package/dist/llms/index.js +101 -0
  96. package/dist/llms/index.js.map +1 -0
  97. package/dist/llms/index.mjs +4 -0
  98. package/dist/llms/index.mjs.map +1 -0
  99. package/dist/migrator-ARLHUNB3.mjs +4 -0
  100. package/dist/migrator-ARLHUNB3.mjs.map +1 -0
  101. package/dist/migrator-VZLBH3VY.js +37 -0
  102. package/dist/migrator-VZLBH3VY.js.map +1 -0
  103. package/dist/redirects/index.js +1 -1
  104. package/dist/redirects/index.mjs +1 -1
  105. package/dist/reputation/index.js +1 -1
  106. package/dist/reputation/index.mjs +1 -1
  107. package/dist/{routing-BWjUF7lp.d.ts → routing-CF91y6NO.d.ts} +1 -1
  108. package/dist/{routing-CgmRi9tD.d.mts → routing-CIOFpFCB.d.mts} +1 -1
  109. package/dist/scanner-7ZMUM2P5.mjs +4 -0
  110. package/dist/scanner-7ZMUM2P5.mjs.map +1 -0
  111. package/dist/scanner-OY7UF3WA.js +53 -0
  112. package/dist/scanner-OY7UF3WA.js.map +1 -0
  113. package/dist/seo/index.d.mts +267 -7
  114. package/dist/seo/index.d.ts +267 -7
  115. package/dist/seo/index.js +433 -24
  116. package/dist/seo/index.js.map +1 -1
  117. package/dist/seo/index.mjs +401 -11
  118. package/dist/seo/index.mjs.map +1 -1
  119. package/dist/seo/server.d.mts +11 -4
  120. package/dist/seo/server.d.ts +11 -4
  121. package/dist/seo/server.js +17 -17
  122. package/dist/seo/server.mjs +3 -3
  123. package/dist/setup/client.js +1 -1
  124. package/dist/setup/client.mjs +1 -1
  125. package/dist/setup/index.js +3 -3
  126. package/dist/setup/index.mjs +2 -2
  127. package/dist/setup/server.js +3 -3
  128. package/dist/setup/server.mjs +2 -2
  129. package/dist/sitemap/index.js +2 -2
  130. package/dist/sitemap/index.js.map +1 -1
  131. package/dist/sitemap/index.mjs +2 -2
  132. package/dist/sitemap/index.mjs.map +1 -1
  133. package/dist/{types-C0pJGfbH.d.mts → types-D6FHAVWX.d.mts} +99 -3
  134. package/dist/{types-C0pJGfbH.d.ts → types-D6FHAVWX.d.ts} +99 -3
  135. package/dist/{types-BN4OwtCO.d.mts → types-DI0jnhjJ.d.mts} +2 -0
  136. package/dist/{types-BN4OwtCO.d.ts → types-DI0jnhjJ.d.ts} +2 -0
  137. package/dist/{types-BmzutFwy.d.ts → types-j8X4vUhB.d.mts} +19 -2
  138. package/dist/{types-BmzutFwy.d.mts → types-j8X4vUhB.d.ts} +19 -2
  139. package/dist/{web-vitals-BH55V7EJ.js → web-vitals-444RLW3B.js} +11 -11
  140. package/dist/{web-vitals-BH55V7EJ.js.map → web-vitals-444RLW3B.js.map} +1 -1
  141. package/dist/{web-vitals-RJYPWAR3.mjs → web-vitals-KPICZIEF.mjs} +3 -3
  142. package/dist/{web-vitals-RJYPWAR3.mjs.map → web-vitals-KPICZIEF.mjs.map} +1 -1
  143. package/package.json +17 -10
  144. package/dist/api-N35S3EES.js +0 -57
  145. package/dist/api-N35S3EES.js.map +0 -1
  146. package/dist/api-SYBTK7Z7.mjs +0 -4
  147. package/dist/api-SYBTK7Z7.mjs.map +0 -1
  148. package/dist/chunk-2IHTEKHU.mjs.map +0 -1
  149. package/dist/chunk-7H6I3ECV.mjs.map +0 -1
  150. package/dist/chunk-BGJLOJ7T.mjs +0 -605
  151. package/dist/chunk-BGJLOJ7T.mjs.map +0 -1
  152. package/dist/chunk-EQCVQC35.js +0 -35
  153. package/dist/chunk-FKVJOT2F.mjs.map +0 -1
  154. package/dist/chunk-GAJLEDRD.js.map +0 -1
  155. package/dist/chunk-NYKRE2FL.mjs +0 -31
  156. package/dist/chunk-O2OHHBUD.js.map +0 -1
  157. package/dist/chunk-QAYJV4KK.js +0 -608
  158. package/dist/chunk-QAYJV4KK.js.map +0 -1
  159. package/dist/chunk-QP5NCO2E.js.map +0 -1
  160. package/dist/chunk-V3F5J6CV.js.map +0 -1
  161. package/dist/chunk-XQJX252G.mjs.map +0 -1
  162. package/dist/generators-TO2FKJR6.mjs.map +0 -1
  163. package/dist/generators-YZWIGHCO.js.map +0 -1
  164. package/dist/migrator-V6KS75EA.mjs +0 -265
  165. package/dist/migrator-V6KS75EA.mjs.map +0 -1
  166. package/dist/migrator-XKM7YQCY.js +0 -272
  167. package/dist/migrator-XKM7YQCY.js.map +0 -1
  168. package/dist/scanner-AZV5I6US.mjs.map +0 -1
  169. package/dist/scanner-ETJAMIT7.js.map +0 -1
@@ -1,9 +1,200 @@
1
1
  export { SitemapSync } from '../chunk-WPSRS352.mjs';
2
- export { generateSitemap, getRedirect, getRobotsDirective, isIndexable } from '../chunk-GQ6ZOU2N.mjs';
3
- import { getSEOPageData, getABTest, recordABImpression, getSchemaMarkups, getFAQData, getInternalLinks, getContentBlock, getManagedScripts } from '../chunk-7H6I3ECV.mjs';
4
- import '../chunk-NYKRE2FL.mjs';
2
+ export { generateSitemap, getRedirect, getRobotsDirective, isIndexable } from '../chunk-JGQPAXTL.mjs';
3
+ import { getSchemaMarkups, getEntityEnhancedSchema, getFAQData, getInternalLinks, getContentBlock, getEntities, getManagedScripts } from '../chunk-FQVGK746.mjs';
4
+ import '../chunk-4XPGGLVP.mjs';
5
+ import { cache } from 'react';
6
+ import 'server-only';
5
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
8
 
9
+ function getSecureApiConfig() {
10
+ const apiUrl = process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com";
11
+ const apiKey = process.env.UPTRADE_API_KEY || "";
12
+ const projectId = process.env.UPTRADE_PROJECT_ID || "";
13
+ if (!apiKey) {
14
+ throw new Error("@uptrade/seo: UPTRADE_API_KEY environment variable is required for server-side SEO functions");
15
+ }
16
+ return { apiUrl, apiKey, projectId };
17
+ }
18
+ async function secureApiPost(endpoint, body = {}) {
19
+ const { apiUrl, apiKey } = getSecureApiConfig();
20
+ try {
21
+ const response = await fetch(`${apiUrl}${endpoint}`, {
22
+ method: "POST",
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ "x-api-key": apiKey
26
+ },
27
+ body: JSON.stringify(body),
28
+ next: { revalidate: 60 }
29
+ // Cache for 60 seconds
30
+ });
31
+ if (!response.ok) {
32
+ console.error(`@uptrade/seo: API error ${response.status}: ${response.statusText}`);
33
+ return null;
34
+ }
35
+ return await response.json();
36
+ } catch (error) {
37
+ console.error("@uptrade/seo: Network error:", error);
38
+ return null;
39
+ }
40
+ }
41
+ var getSEOPageData = cache(async (projectId, path) => {
42
+ const result = await secureApiPost("/api/public/seo/page", {
43
+ projectId,
44
+ path
45
+ });
46
+ return result?.page || null;
47
+ });
48
+ var getSchemaMarkups2 = cache(async (projectId, path, options) => {
49
+ const result = await secureApiPost("/api/public/seo/schemas", {
50
+ projectId,
51
+ path,
52
+ includeTypes: options?.includeTypes,
53
+ excludeTypes: options?.excludeTypes
54
+ });
55
+ return result?.schemas || [];
56
+ });
57
+ var getFAQData2 = cache(async (projectId, path) => {
58
+ const result = await secureApiPost("/api/public/seo/faq", {
59
+ projectId,
60
+ path
61
+ });
62
+ return result?.faq || null;
63
+ });
64
+ var getInternalLinks2 = cache(async (projectId, sourcePath, options) => {
65
+ const result = await secureApiPost("/api/public/seo/internal-links", {
66
+ projectId,
67
+ sourcePath,
68
+ position: options?.position,
69
+ limit: options?.limit
70
+ });
71
+ return result?.links || [];
72
+ });
73
+ var getContentBlock2 = cache(async (projectId, path, section) => {
74
+ const result = await secureApiPost("/api/public/seo/content", {
75
+ projectId,
76
+ path,
77
+ section
78
+ });
79
+ return result?.content || null;
80
+ });
81
+ var getABTest = cache(async (projectId, path, field) => {
82
+ const result = await secureApiPost("/api/public/seo/ab-test", {
83
+ projectId,
84
+ path,
85
+ field
86
+ });
87
+ return result?.test || null;
88
+ });
89
+ async function recordABImpression(testId, variant, sessionId) {
90
+ await secureApiPost("/api/public/seo/ab-impression", { testId, variant, sessionId });
91
+ }
92
+ var getRedirectData = cache(async (projectId, path) => {
93
+ const result = await secureApiPost("/api/public/seo/redirect", {
94
+ projectId,
95
+ path
96
+ });
97
+ return result?.redirect || null;
98
+ });
99
+ var getManagedScripts2 = cache(async (projectId, position, currentPath) => {
100
+ const result = await secureApiPost("/api/public/seo/scripts", {
101
+ projectId,
102
+ position,
103
+ currentPath
104
+ });
105
+ return result?.scripts || [];
106
+ });
107
+ var getRobotsData = cache(async (projectId, path) => {
108
+ const result = await secureApiPost("/api/public/seo/page", {
109
+ projectId,
110
+ path
111
+ });
112
+ return result?.page?.managed_robots || null;
113
+ });
114
+ var getSitemapEntries = cache(async (projectId, options) => {
115
+ const result = await secureApiPost("/api/public/seo/sitemap", {
116
+ projectId,
117
+ publishedOnly: options?.publishedOnly
118
+ });
119
+ return result?.entries || [];
120
+ });
121
+ async function registerSitemap(entries) {
122
+ const { apiUrl, apiKey, projectId } = getSecureApiConfig();
123
+ try {
124
+ const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {
125
+ method: "POST",
126
+ headers: {
127
+ "Content-Type": "application/json",
128
+ "x-api-key": apiKey
129
+ },
130
+ body: JSON.stringify({ projectId, entries })
131
+ });
132
+ if (!response.ok) {
133
+ console.error(`@uptrade/seo: Sitemap registration failed: ${response.statusText}`);
134
+ return { success: false, created: 0, updated: 0 };
135
+ }
136
+ return await response.json();
137
+ } catch (error) {
138
+ console.error("@uptrade/seo: Sitemap registration error:", error);
139
+ return { success: false, created: 0, updated: 0 };
140
+ }
141
+ }
142
+ function getSignalApiConfig() {
143
+ const apiUrl = process.env.SIGNAL_API_URL || process.env.NEXT_PUBLIC_SIGNAL_API_URL || "https://signal.uptrademedia.com";
144
+ const apiKey = process.env.UPTRADE_API_KEY || "";
145
+ return { apiUrl, apiKey };
146
+ }
147
+ async function signalApiGet(endpoint) {
148
+ const { apiUrl, apiKey } = getSignalApiConfig();
149
+ if (!apiKey) {
150
+ return null;
151
+ }
152
+ try {
153
+ const response = await fetch(`${apiUrl}${endpoint}`, {
154
+ method: "GET",
155
+ headers: {
156
+ "Content-Type": "application/json",
157
+ "x-api-key": apiKey
158
+ },
159
+ next: { revalidate: 300 }
160
+ // Cache for 5 minutes
161
+ });
162
+ if (!response.ok) {
163
+ return null;
164
+ }
165
+ const result = await response.json();
166
+ return result?.data || result;
167
+ } catch (error) {
168
+ console.error("@uptrade/seo: Signal API error:", error);
169
+ return null;
170
+ }
171
+ }
172
+ var getEntities2 = cache(async (projectId, options) => {
173
+ let endpoint = `/skills/seo/entities/${projectId}`;
174
+ if (options?.type) {
175
+ endpoint += `?type=${options.type}`;
176
+ }
177
+ const result = await signalApiGet(endpoint);
178
+ return result || [];
179
+ });
180
+ var getPrimaryEntity = cache(async (projectId) => {
181
+ return signalApiGet(`/skills/seo/entities/${projectId}/primary`);
182
+ });
183
+ var getEntityEnhancedSchema2 = cache(async (projectId, pagePath) => {
184
+ const result = await signalApiGet(
185
+ `/skills/seo/schema/${projectId}/entity-enhanced?pagePath=${encodeURIComponent(pagePath)}`
186
+ );
187
+ return result?.schemas || [];
188
+ });
189
+ var getVisibilityScore = cache(async (projectId, pagePath) => {
190
+ const result = await signalApiGet(`/skills/seo/visibility/${projectId}`);
191
+ if (!result) return null;
192
+ return result.find((s) => s.page_path === pagePath) || null;
193
+ });
194
+ var getVisibilitySummary = cache(async (projectId) => {
195
+ return signalApiGet(`/skills/seo/visibility/${projectId}/summary`);
196
+ });
197
+
7
198
  // src/seo/getManagedMetadata.ts
8
199
  async function getManagedMetadata(options) {
9
200
  const { projectId, path, fallback = {}, overrides = {} } = options;
@@ -25,8 +216,8 @@ async function getManagedMetadata(options) {
25
216
  } else if (fallback.title) {
26
217
  metadata.title = fallback.title;
27
218
  }
28
- if (pageData.managed_description) {
29
- metadata.description = pageData.managed_description;
219
+ if (pageData.managed_meta_description || pageData.managed_description) {
220
+ metadata.description = pageData.managed_meta_description || pageData.managed_description;
30
221
  } else if (fallback.description) {
31
222
  metadata.description = fallback.description;
32
223
  }
@@ -45,7 +236,7 @@ async function getManagedMetadata(options) {
45
236
  };
46
237
  }
47
238
  const ogTitle = pageData.managed_og_title || pageData.managed_title;
48
- const ogDescription = pageData.managed_og_description || pageData.managed_description;
239
+ const ogDescription = pageData.managed_og_description || pageData.managed_meta_description || pageData.managed_description;
49
240
  const ogImage = pageData.managed_og_image;
50
241
  if (ogTitle || ogDescription || ogImage) {
51
242
  metadata.openGraph = {
@@ -115,21 +306,47 @@ async function getManagedMetadataWithAB(options) {
115
306
  }
116
307
  return metadata;
117
308
  }
309
+ var DEFAULT_SPEAKABLE_SELECTORS = [
310
+ "h1",
311
+ '[data-speakable="true"]',
312
+ ".page-summary",
313
+ ".key-points",
314
+ '.aeo-block[data-speakable="true"]'
315
+ ];
118
316
  async function ManagedSchema({
119
317
  projectId,
120
318
  path,
121
319
  additionalSchemas = [],
122
320
  includeTypes,
123
- excludeTypes
321
+ excludeTypes,
322
+ speakable,
323
+ pageType = "WebPage",
324
+ pageName,
325
+ pageUrl,
326
+ includeEntityGraph = false
124
327
  }) {
125
328
  const schemas = await getSchemaMarkups(projectId, path, {
126
329
  includeTypes,
127
330
  excludeTypes
128
331
  });
332
+ let entitySchemas = [];
333
+ if (includeEntityGraph) {
334
+ entitySchemas = await getEntityEnhancedSchema(projectId, path);
335
+ }
129
336
  const allSchemas = [
337
+ ...entitySchemas,
130
338
  ...schemas.map((s) => s.schema_json),
131
339
  ...additionalSchemas
132
340
  ];
341
+ if (speakable && pageName && pageUrl) {
342
+ const speakableSchema = createSpeakableWebPageSchema(
343
+ pageType,
344
+ pageName,
345
+ pageUrl,
346
+ typeof speakable === "object" ? speakable : void 0
347
+ );
348
+ allSchemas.push(speakableSchema);
349
+ }
133
350
  if (allSchemas.length === 0) {
134
351
  return null;
135
352
  }
@@ -158,6 +375,25 @@ function createSchema(type, data) {
158
375
  ...data
159
376
  };
160
377
  }
378
+ function createSpeakableWebPageSchema(type, name, url, speakable) {
379
+ const speakableSpec = {
380
+ "@type": "SpeakableSpecification"
381
+ };
382
+ if (speakable?.cssSelector?.length) {
383
+ speakableSpec.cssSelector = speakable.cssSelector;
384
+ } else if (speakable?.xpath?.length) {
385
+ speakableSpec.xpath = speakable.xpath;
386
+ } else {
387
+ speakableSpec.cssSelector = DEFAULT_SPEAKABLE_SELECTORS;
388
+ }
389
+ return {
390
+ "@context": "https://schema.org",
391
+ "@type": type,
392
+ name,
393
+ url,
394
+ speakable: speakableSpec
395
+ };
396
+ }
161
397
  function createBreadcrumbSchema(baseUrl, path, labels) {
162
398
  const segments = path.split("/").filter(Boolean);
163
399
  const items = segments.map((segment, index) => {
@@ -297,13 +533,46 @@ async function ManagedInternalLinks({
297
533
  function renderMarkdown(content) {
298
534
  return content.replace(/^### (.*$)/gim, "<h3>$1</h3>").replace(/^## (.*$)/gim, "<h2>$1</h2>").replace(/^# (.*$)/gim, "<h1>$1</h1>").replace(/\*\*(.*)\*\*/gim, "<strong>$1</strong>").replace(/\*(.*)\*/gim, "<em>$1</em>").replace(/\[(.*?)\]\((.*?)\)/gim, '<a href="$2">$1</a>').replace(/\n\n/gim, "</p><p>").replace(/^(.+)$/gim, "<p>$1</p>");
299
535
  }
536
+ function injectEntityAnnotations(html, entities) {
537
+ if (!entities.length) return html;
538
+ let annotatedHtml = html;
539
+ const sortedEntities = [...entities].sort((a, b) => b.name.length - a.name.length);
540
+ for (const entity of sortedEntities) {
541
+ if (entity.name.length < 3) continue;
542
+ const regex = new RegExp(
543
+ `(?<![\\w-])(?<!data-sonor-entity=")${escapeRegExp(entity.name)}(?![\\w-])`,
544
+ "gi"
545
+ );
546
+ const schemaType = getSchemaTypeForEntity(entity.entity_type);
547
+ annotatedHtml = annotatedHtml.replace(regex, (match) => {
548
+ return `<span class="aeo-entity aeo-entity-${entity.entity_type}" data-sonor-entity="${entity.id}" data-sonor-entity-type="${entity.entity_type}" data-sonor-entity-name="${entity.name}" itemscope itemtype="https://schema.org/${schemaType}"><span itemprop="name">${match}</span></span>`;
549
+ });
550
+ }
551
+ return annotatedHtml;
552
+ }
553
+ function escapeRegExp(string) {
554
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
555
+ }
556
+ function getSchemaTypeForEntity(entityType) {
557
+ const typeMap = {
558
+ organization: "Organization",
559
+ person: "Person",
560
+ service: "Service",
561
+ product: "Product",
562
+ location: "Place",
563
+ concept: "Thing",
564
+ credential: "EducationalOccupationalCredential"
565
+ };
566
+ return typeMap[entityType] || "Thing";
567
+ }
300
568
  async function ManagedContent({
301
569
  projectId,
302
570
  path,
303
571
  section,
304
572
  fallback,
305
573
  className,
306
- components = {}
574
+ components = {},
575
+ injectEntityAnnotations: shouldInjectEntities = false
307
576
  }) {
308
577
  const block = await getContentBlock(projectId, path, section);
309
578
  if (!block) {
@@ -312,18 +581,32 @@ async function ManagedContent({
312
581
  }
313
582
  return null;
314
583
  }
584
+ let entities = [];
585
+ if (shouldInjectEntities) {
586
+ try {
587
+ entities = await getEntities(projectId);
588
+ } catch (err) {
589
+ console.warn("@uptrade/seo: Failed to fetch entities for annotation:", err);
590
+ }
591
+ }
315
592
  const containerClass = className || `uptrade-content uptrade-content--${section}`;
593
+ const processHtml = (html) => {
594
+ if (shouldInjectEntities && entities.length > 0) {
595
+ return injectEntityAnnotations(html, entities);
596
+ }
597
+ return html;
598
+ };
316
599
  switch (block.content_type) {
317
600
  case "html":
318
601
  return /* @__PURE__ */ jsx(
319
602
  "div",
320
603
  {
321
604
  className: containerClass,
322
- dangerouslySetInnerHTML: { __html: block.content }
605
+ dangerouslySetInnerHTML: { __html: processHtml(block.content) }
323
606
  }
324
607
  );
325
608
  case "markdown":
326
- const htmlContent = renderMarkdown(block.content);
609
+ const htmlContent = processHtml(renderMarkdown(block.content));
327
610
  return /* @__PURE__ */ jsx(
328
611
  "div",
329
612
  {
@@ -405,7 +688,114 @@ async function ManagedNoScripts({
405
688
  }
406
689
  return /* @__PURE__ */ jsx("noscript", { dangerouslySetInnerHTML: { __html: noscriptContent } });
407
690
  }
691
+ function getApiConfig() {
692
+ const apiUrl = process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com";
693
+ return { apiUrl };
694
+ }
695
+ var getLocationSection = cache(async (projectId, path, section) => {
696
+ const { apiUrl } = getApiConfig();
697
+ try {
698
+ const response = await fetch(`${apiUrl}/api/public/seo/location-content`, {
699
+ method: "POST",
700
+ headers: { "Content-Type": "application/json" },
701
+ body: JSON.stringify({
702
+ project_id: projectId,
703
+ path,
704
+ section
705
+ }),
706
+ next: { revalidate: 3600 }
707
+ // Cache for 1 hour
708
+ });
709
+ if (!response.ok) {
710
+ console.error(`LocationPageContent: Failed to fetch section "${section}" for path "${path}"`);
711
+ return null;
712
+ }
713
+ const data = await response.json();
714
+ return data;
715
+ } catch (error) {
716
+ console.error("LocationPageContent: API error:", error);
717
+ return null;
718
+ }
719
+ });
720
+ function HeroRenderer({ data, className }) {
721
+ return /* @__PURE__ */ jsxs("section", { className: className || "location-hero", children: [
722
+ /* @__PURE__ */ jsx("h1", { children: data.title }),
723
+ data.subtitle && /* @__PURE__ */ jsx("p", { className: "subtitle", children: data.subtitle }),
724
+ data.stats && /* @__PURE__ */ jsx("div", { className: "stats-grid", children: data.stats.map((stat, i) => /* @__PURE__ */ jsxs("div", { className: "stat", children: [
725
+ /* @__PURE__ */ jsx("span", { className: "stat-value", children: stat.value }),
726
+ /* @__PURE__ */ jsx("span", { className: "stat-label", children: stat.label })
727
+ ] }, i)) }),
728
+ data.cta_text && data.cta_href && /* @__PURE__ */ jsx("a", { href: data.cta_href, className: "cta-button", children: data.cta_text })
729
+ ] });
730
+ }
731
+ function TextRenderer({ data, className }) {
732
+ if (data.html) {
733
+ return /* @__PURE__ */ jsx(
734
+ "section",
735
+ {
736
+ className: className || "location-text",
737
+ dangerouslySetInnerHTML: { __html: data.html }
738
+ }
739
+ );
740
+ }
741
+ return /* @__PURE__ */ jsxs("section", { className: className || "location-text", children: [
742
+ data.heading && /* @__PURE__ */ jsx("h2", { children: data.heading }),
743
+ data.paragraphs.map((p, i) => /* @__PURE__ */ jsx("p", { children: p }, i))
744
+ ] });
745
+ }
746
+ function ServicesGridRenderer({ data, className }) {
747
+ return /* @__PURE__ */ jsx("section", { className: className || "location-services-grid", children: /* @__PURE__ */ jsx("div", { className: "services-list", children: data.services.map((service, i) => /* @__PURE__ */ jsxs("a", { href: service.href, className: "service-card", children: [
748
+ service.icon && /* @__PURE__ */ jsx("span", { className: "service-icon", children: service.icon }),
749
+ /* @__PURE__ */ jsx("h3", { children: service.title }),
750
+ /* @__PURE__ */ jsx("p", { children: service.description })
751
+ ] }, i)) }) });
752
+ }
753
+ function DefaultRenderer({ data, className }) {
754
+ if (process.env.NODE_ENV === "development") {
755
+ return /* @__PURE__ */ jsx("section", { className, children: /* @__PURE__ */ jsx("pre", { style: { fontSize: "12px", background: "#f0f0f0", padding: "1rem" }, children: JSON.stringify(data, null, 2) }) });
756
+ }
757
+ if (typeof data.content === "string") {
758
+ return /* @__PURE__ */ jsx(
759
+ "section",
760
+ {
761
+ className,
762
+ dangerouslySetInnerHTML: { __html: data.content }
763
+ }
764
+ );
765
+ }
766
+ return null;
767
+ }
768
+ async function LocationPageContent({
769
+ projectId,
770
+ path,
771
+ section,
772
+ fallback = null,
773
+ className,
774
+ render
775
+ }) {
776
+ const data = await getLocationSection(projectId, path, section);
777
+ if (!data) {
778
+ return fallback;
779
+ }
780
+ if (render) {
781
+ return /* @__PURE__ */ jsx(Fragment, { children: render(data) });
782
+ }
783
+ switch (data.type) {
784
+ case "hero":
785
+ return /* @__PURE__ */ jsx(HeroRenderer, { data: data.content, className });
786
+ case "text":
787
+ case "intro":
788
+ case "about":
789
+ case "about_location":
790
+ return /* @__PURE__ */ jsx(TextRenderer, { data: data.content, className });
791
+ case "services_grid":
792
+ case "services":
793
+ return /* @__PURE__ */ jsx(ServicesGridRenderer, { data: data.content, className });
794
+ default:
795
+ return /* @__PURE__ */ jsx(DefaultRenderer, { data, className });
796
+ }
797
+ }
408
798
 
409
- export { ManagedContent, ManagedFAQ, ManagedInternalLinks, ManagedNoScripts, ManagedSchema, ManagedScripts, createBreadcrumbSchema, createSchema, ManagedSchema as default, getABVariant, getManagedContentData, getManagedMetadata, getManagedMetadataWithAB };
799
+ export { LocationPageContent, ManagedContent, ManagedFAQ, ManagedInternalLinks, ManagedNoScripts, ManagedSchema, ManagedScripts, createBreadcrumbSchema, createSchema, ManagedSchema as default, getABTest, getABVariant, getContentBlock2 as getContentBlock, getEntities2 as getEntities, getEntityEnhancedSchema2 as getEntityEnhancedSchema, getFAQData2 as getFAQData, getInternalLinks2 as getInternalLinks, getLocationSection, getManagedContentData, getManagedMetadata, getManagedMetadataWithAB, getManagedScripts2 as getManagedScripts, getPrimaryEntity, getRedirectData, getRobotsData, getSEOPageData, getSchemaMarkups2 as getSchemaMarkups, getSitemapEntries, getVisibilityScore, getVisibilitySummary, recordABImpression, registerSitemap };
410
800
  //# sourceMappingURL=index.mjs.map
411
801
  //# sourceMappingURL=index.mjs.map