@sonordev/site-kit 3.6.3 → 3.8.0

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 (208) hide show
  1. package/agent-manifest.json +1 -1
  2. package/dist/AnalyticsProvider-4KMGMQVD.js +31 -0
  3. package/dist/{AnalyticsProvider-ZJHOU5HI.js.map → AnalyticsProvider-4KMGMQVD.js.map} +1 -1
  4. package/dist/AnalyticsProvider-M4BFCRKM.mjs +10 -0
  5. package/dist/{AnalyticsProvider-X243YBPQ.mjs.map → AnalyticsProvider-M4BFCRKM.mjs.map} +1 -1
  6. package/dist/ChatWidget-I6YFEKW6.js +19 -0
  7. package/dist/{ChatWidget-NRQBBRLK.js.map → ChatWidget-I6YFEKW6.js.map} +1 -1
  8. package/dist/ChatWidget-IV3LIMLK.mjs +10 -0
  9. package/dist/{ChatWidget-L5E73JUY.mjs.map → ChatWidget-IV3LIMLK.mjs.map} +1 -1
  10. package/dist/EngageWidget-AWVB35ZM.mjs +9 -0
  11. package/dist/{EngageWidget-X7UIQUPC.mjs.map → EngageWidget-AWVB35ZM.mjs.map} +1 -1
  12. package/dist/EngageWidget-TQW76BUU.js +18 -0
  13. package/dist/{EngageWidget-HLBJE4ZB.js.map → EngageWidget-TQW76BUU.js.map} +1 -1
  14. package/dist/{SignalCore-G6MAO72R.mjs → SignalCore-4FUGFP5E.mjs} +5 -5
  15. package/dist/{SignalCore-G6MAO72R.mjs.map → SignalCore-4FUGFP5E.mjs.map} +1 -1
  16. package/dist/{SignalCore-CWDC45EQ.js → SignalCore-VX7ZL5HE.js} +11 -11
  17. package/dist/{SignalCore-CWDC45EQ.js.map → SignalCore-VX7ZL5HE.js.map} +1 -1
  18. package/dist/SitemapSync-CXDEUYM2.mjs +8 -0
  19. package/dist/{SitemapSync-QAMSDAF7.mjs.map → SitemapSync-CXDEUYM2.mjs.map} +1 -1
  20. package/dist/SitemapSync-XRH577AB.js +17 -0
  21. package/dist/{SitemapSync-FWWORZOF.js.map → SitemapSync-XRH577AB.js.map} +1 -1
  22. package/dist/analytics/index.js +12 -12
  23. package/dist/analytics/index.mjs +5 -5
  24. package/dist/blog/server-ui.js +6 -6
  25. package/dist/blog/server-ui.js.map +1 -1
  26. package/dist/blog/server-ui.mjs +5 -5
  27. package/dist/blog/server-ui.mjs.map +1 -1
  28. package/dist/blog/server.d.mts +20 -1
  29. package/dist/blog/server.d.ts +20 -1
  30. package/dist/blog/server.js +43 -39
  31. package/dist/blog/server.mjs +1 -1
  32. package/dist/{chunk-KYYSS5L7.mjs → chunk-2LQGFCEA.mjs} +3 -3
  33. package/dist/{chunk-KYYSS5L7.mjs.map → chunk-2LQGFCEA.mjs.map} +1 -1
  34. package/dist/{chunk-PVRE3PYC.js → chunk-2WMLHR72.js} +4 -4
  35. package/dist/{chunk-PVRE3PYC.js.map → chunk-2WMLHR72.js.map} +1 -1
  36. package/dist/{chunk-VZF3NFCY.js → chunk-5GJ6V7FI.js} +7 -7
  37. package/dist/{chunk-VZF3NFCY.js.map → chunk-5GJ6V7FI.js.map} +1 -1
  38. package/dist/{chunk-3MYZS6PD.js → chunk-77CIIDE6.js} +15 -3
  39. package/dist/chunk-77CIIDE6.js.map +1 -0
  40. package/dist/{chunk-WQXSILFH.mjs → chunk-7UKIAZ6E.mjs} +12 -5
  41. package/dist/chunk-7UKIAZ6E.mjs.map +1 -0
  42. package/dist/{chunk-FYCFUYPQ.js → chunk-A2FHTQGB.js} +3 -3
  43. package/dist/{chunk-FYCFUYPQ.js.map → chunk-A2FHTQGB.js.map} +1 -1
  44. package/dist/{chunk-ZQ2JTDPC.js → chunk-ATOUXWFR.js} +15 -15
  45. package/dist/{chunk-ZQ2JTDPC.js.map → chunk-ATOUXWFR.js.map} +1 -1
  46. package/dist/{chunk-T3ARA52J.js → chunk-BB2C5JUA.js} +4 -4
  47. package/dist/{chunk-T3ARA52J.js.map → chunk-BB2C5JUA.js.map} +1 -1
  48. package/dist/{chunk-VOYRWPE3.mjs → chunk-BVOUZL2S.mjs} +3 -3
  49. package/dist/{chunk-VOYRWPE3.mjs.map → chunk-BVOUZL2S.mjs.map} +1 -1
  50. package/dist/{chunk-OYT6SFLM.js → chunk-D4V37TBD.js} +5 -5
  51. package/dist/{chunk-OYT6SFLM.js.map → chunk-D4V37TBD.js.map} +1 -1
  52. package/dist/{chunk-6B3DEFHU.mjs → chunk-DGFHYNQY.mjs} +3 -3
  53. package/dist/{chunk-6B3DEFHU.mjs.map → chunk-DGFHYNQY.mjs.map} +1 -1
  54. package/dist/{chunk-KEGWCBLW.mjs → chunk-GH5RO5OW.mjs} +3 -3
  55. package/dist/{chunk-KEGWCBLW.mjs.map → chunk-GH5RO5OW.mjs.map} +1 -1
  56. package/dist/{chunk-XHJXIAAW.js → chunk-GSOLN2FC.js} +5 -5
  57. package/dist/{chunk-XHJXIAAW.js.map → chunk-GSOLN2FC.js.map} +1 -1
  58. package/dist/{chunk-ATG4FJY6.js → chunk-H6AU3WKF.js} +35 -3
  59. package/dist/chunk-H6AU3WKF.js.map +1 -0
  60. package/dist/{chunk-IJR3ATI5.mjs → chunk-HQB24QUN.mjs} +4 -4
  61. package/dist/{chunk-IJR3ATI5.mjs.map → chunk-HQB24QUN.mjs.map} +1 -1
  62. package/dist/{chunk-DEVPKGCD.mjs → chunk-HQJS7VWB.mjs} +3 -3
  63. package/dist/{chunk-DEVPKGCD.mjs.map → chunk-HQJS7VWB.mjs.map} +1 -1
  64. package/dist/{chunk-QR7CMR3W.js → chunk-I5KJ5YFU.js} +15 -15
  65. package/dist/{chunk-QR7CMR3W.js.map → chunk-I5KJ5YFU.js.map} +1 -1
  66. package/dist/chunk-JVT6CUNN.mjs +6 -0
  67. package/dist/{chunk-JYM4I57K.mjs.map → chunk-JVT6CUNN.mjs.map} +1 -1
  68. package/dist/{chunk-EDQXJFH2.mjs → chunk-JXN6OCFB.mjs} +3 -3
  69. package/dist/{chunk-EDQXJFH2.mjs.map → chunk-JXN6OCFB.mjs.map} +1 -1
  70. package/dist/chunk-JXT2WWXW.js +8 -0
  71. package/dist/{chunk-6ZDXUCAX.js.map → chunk-JXT2WWXW.js.map} +1 -1
  72. package/dist/{chunk-DCSNIU2V.js → chunk-MP6NHVHD.js} +6 -6
  73. package/dist/{chunk-DCSNIU2V.js.map → chunk-MP6NHVHD.js.map} +1 -1
  74. package/dist/{chunk-7KIXGDUP.js → chunk-MRVO3QO3.js} +22 -15
  75. package/dist/chunk-MRVO3QO3.js.map +1 -0
  76. package/dist/{chunk-O3WBS4VY.js → chunk-NEV2OEBF.js} +9 -9
  77. package/dist/{chunk-O3WBS4VY.js.map → chunk-NEV2OEBF.js.map} +1 -1
  78. package/dist/{chunk-2O2PZII5.mjs → chunk-OLQBP2JQ.mjs} +4 -4
  79. package/dist/{chunk-2O2PZII5.mjs.map → chunk-OLQBP2JQ.mjs.map} +1 -1
  80. package/dist/{chunk-6BIPAKL4.mjs → chunk-OVIDFJIK.mjs} +15 -4
  81. package/dist/chunk-OVIDFJIK.mjs.map +1 -0
  82. package/dist/{chunk-GUXB3QH7.mjs → chunk-PA7ENTUZ.mjs} +41 -9
  83. package/dist/chunk-PA7ENTUZ.mjs.map +1 -0
  84. package/dist/{chunk-PUH6YPZY.mjs → chunk-PEFC5T7R.mjs} +8 -8
  85. package/dist/{chunk-PUH6YPZY.mjs.map → chunk-PEFC5T7R.mjs.map} +1 -1
  86. package/dist/{chunk-H23ZT2I2.mjs → chunk-PENNTSJE.mjs} +35 -3
  87. package/dist/chunk-PENNTSJE.mjs.map +1 -0
  88. package/dist/{chunk-GR4YKNFX.js → chunk-Q6KS7FMY.js} +13 -13
  89. package/dist/{chunk-GR4YKNFX.js.map → chunk-Q6KS7FMY.js.map} +1 -1
  90. package/dist/{chunk-PHLJDLRA.mjs → chunk-R26NFTOR.mjs} +3 -3
  91. package/dist/{chunk-PHLJDLRA.mjs.map → chunk-R26NFTOR.mjs.map} +1 -1
  92. package/dist/{chunk-FJTER53S.mjs → chunk-RSFSXEV2.mjs} +4 -4
  93. package/dist/{chunk-FJTER53S.mjs.map → chunk-RSFSXEV2.mjs.map} +1 -1
  94. package/dist/{chunk-O4ILWMIB.js → chunk-S3J7MEOD.js} +8 -8
  95. package/dist/{chunk-O4ILWMIB.js.map → chunk-S3J7MEOD.js.map} +1 -1
  96. package/dist/{chunk-34IUDOBC.mjs → chunk-SP3MXF3A.mjs} +34 -5
  97. package/dist/chunk-SP3MXF3A.mjs.map +1 -0
  98. package/dist/{chunk-TYYTM4WC.js → chunk-TA6CENL3.js} +12 -12
  99. package/dist/{chunk-TYYTM4WC.js.map → chunk-TA6CENL3.js.map} +1 -1
  100. package/dist/{chunk-BS3P5PTY.mjs → chunk-TKP3YFNS.mjs} +3 -3
  101. package/dist/{chunk-BS3P5PTY.mjs.map → chunk-TKP3YFNS.mjs.map} +1 -1
  102. package/dist/{chunk-XAWB2HFQ.js → chunk-TMKLH6MY.js} +41 -8
  103. package/dist/chunk-TMKLH6MY.js.map +1 -0
  104. package/dist/{chunk-C7EVU7V7.js → chunk-ULY2QZWA.js} +4 -4
  105. package/dist/{chunk-C7EVU7V7.js.map → chunk-ULY2QZWA.js.map} +1 -1
  106. package/dist/{chunk-D74AZ6TM.js → chunk-V6CWHT6B.js} +9 -9
  107. package/dist/{chunk-D74AZ6TM.js.map → chunk-V6CWHT6B.js.map} +1 -1
  108. package/dist/{chunk-LSZ6CT6U.mjs → chunk-W5ZYM276.mjs} +3 -3
  109. package/dist/{chunk-LSZ6CT6U.mjs.map → chunk-W5ZYM276.mjs.map} +1 -1
  110. package/dist/{chunk-XS2COTTD.mjs → chunk-WYRUQCL4.mjs} +3 -3
  111. package/dist/{chunk-XS2COTTD.mjs.map → chunk-WYRUQCL4.mjs.map} +1 -1
  112. package/dist/{chunk-5OJ36D7M.js → chunk-XDQP4JQH.js} +14 -14
  113. package/dist/{chunk-5OJ36D7M.js.map → chunk-XDQP4JQH.js.map} +1 -1
  114. package/dist/{chunk-6T4NVCAT.js → chunk-XMBYDIV6.js} +40 -11
  115. package/dist/chunk-XMBYDIV6.js.map +1 -0
  116. package/dist/{chunk-FK342VJY.mjs → chunk-Y4V5TFHP.mjs} +4 -4
  117. package/dist/{chunk-FK342VJY.mjs.map → chunk-Y4V5TFHP.mjs.map} +1 -1
  118. package/dist/{chunk-EY2236OY.mjs → chunk-YUSX3NZA.mjs} +3 -3
  119. package/dist/{chunk-EY2236OY.mjs.map → chunk-YUSX3NZA.mjs.map} +1 -1
  120. package/dist/cli/index.js +2 -2
  121. package/dist/cli/index.mjs +1 -1
  122. package/dist/client/index.js +4 -4
  123. package/dist/client/index.mjs +3 -3
  124. package/dist/commerce/index.d.mts +1 -1
  125. package/dist/commerce/index.d.ts +1 -1
  126. package/dist/commerce/index.js +51 -51
  127. package/dist/commerce/index.mjs +6 -6
  128. package/dist/config/index.d.mts +1 -1
  129. package/dist/config/index.d.ts +1 -1
  130. package/dist/config/index.js +2 -2
  131. package/dist/config/index.mjs +1 -1
  132. package/dist/engage/index.js +9 -9
  133. package/dist/engage/index.mjs +6 -6
  134. package/dist/fleet/index.js +8 -8
  135. package/dist/fleet/index.mjs +4 -4
  136. package/dist/forms/index.js +13 -13
  137. package/dist/forms/index.mjs +5 -5
  138. package/dist/images/index.js +11 -11
  139. package/dist/images/index.mjs +4 -4
  140. package/dist/index.d.mts +1 -1
  141. package/dist/index.d.ts +1 -1
  142. package/dist/index.js +64 -64
  143. package/dist/index.mjs +10 -10
  144. package/dist/layout/client.js +8 -8
  145. package/dist/layout/client.mjs +7 -7
  146. package/dist/layout/index.js +10 -10
  147. package/dist/layout/index.mjs +8 -8
  148. package/dist/llms/contract.js +9 -9
  149. package/dist/llms/contract.mjs +1 -1
  150. package/dist/llms/index.d.mts +131 -40
  151. package/dist/llms/index.d.ts +131 -40
  152. package/dist/llms/index.js +125 -21
  153. package/dist/llms/index.js.map +1 -1
  154. package/dist/llms/index.mjs +102 -4
  155. package/dist/llms/index.mjs.map +1 -1
  156. package/dist/maps/index.js +5 -5
  157. package/dist/maps/index.mjs +3 -3
  158. package/dist/middleware/index.d.mts +2 -1
  159. package/dist/middleware/index.d.ts +2 -1
  160. package/dist/middleware/index.js +6 -2
  161. package/dist/middleware/index.js.map +1 -1
  162. package/dist/middleware/index.mjs +2 -1
  163. package/dist/middleware/index.mjs.map +1 -1
  164. package/dist/securityHeaders-CwsFdDcJ.d.mts +49 -0
  165. package/dist/securityHeaders-CwsFdDcJ.d.ts +49 -0
  166. package/dist/seo/client.js +5 -5
  167. package/dist/seo/client.mjs +4 -4
  168. package/dist/seo/index.js +7 -7
  169. package/dist/seo/index.mjs +5 -5
  170. package/dist/server/index.js +3 -3
  171. package/dist/server/index.mjs +2 -2
  172. package/dist/signal/index.js +11 -11
  173. package/dist/signal/index.mjs +2 -2
  174. package/dist/sitemap/index.d.mts +8 -1
  175. package/dist/sitemap/index.d.ts +8 -1
  176. package/dist/sitemap/index.js +5 -4
  177. package/dist/sitemap/index.js.map +1 -1
  178. package/dist/sitemap/index.mjs +4 -3
  179. package/dist/sitemap/index.mjs.map +1 -1
  180. package/dist/sync/index.js +16 -16
  181. package/dist/sync/index.mjs +4 -4
  182. package/dist/{useEventModal-qJfX_1XG.d.mts → useEventModal-DAAiArgM.d.mts} +9 -1
  183. package/dist/{useEventModal-CcxNZOvp.d.ts → useEventModal-ZQX19_4k.d.ts} +9 -1
  184. package/dist/{types-xcP_owwn.d.ts → writeLLMsTxt-BFaNr4re.d.ts} +53 -1
  185. package/dist/{types-DhCAWUmd.d.mts → writeLLMsTxt-SpMdyHQT.d.mts} +53 -1
  186. package/package.json +1 -1
  187. package/dist/AnalyticsProvider-X243YBPQ.mjs +0 -10
  188. package/dist/AnalyticsProvider-ZJHOU5HI.js +0 -31
  189. package/dist/ChatWidget-L5E73JUY.mjs +0 -10
  190. package/dist/ChatWidget-NRQBBRLK.js +0 -19
  191. package/dist/EngageWidget-HLBJE4ZB.js +0 -18
  192. package/dist/EngageWidget-X7UIQUPC.mjs +0 -9
  193. package/dist/SitemapSync-FWWORZOF.js +0 -17
  194. package/dist/SitemapSync-QAMSDAF7.mjs +0 -8
  195. package/dist/chunk-34IUDOBC.mjs.map +0 -1
  196. package/dist/chunk-3MYZS6PD.js.map +0 -1
  197. package/dist/chunk-6BIPAKL4.mjs.map +0 -1
  198. package/dist/chunk-6T4NVCAT.js.map +0 -1
  199. package/dist/chunk-6ZDXUCAX.js +0 -8
  200. package/dist/chunk-7KIXGDUP.js.map +0 -1
  201. package/dist/chunk-ATG4FJY6.js.map +0 -1
  202. package/dist/chunk-GUXB3QH7.mjs.map +0 -1
  203. package/dist/chunk-H23ZT2I2.mjs.map +0 -1
  204. package/dist/chunk-JYM4I57K.mjs +0 -6
  205. package/dist/chunk-WQXSILFH.mjs.map +0 -1
  206. package/dist/chunk-XAWB2HFQ.js.map +0 -1
  207. package/dist/securityHeaders-nwZ6nP4g.d.mts +0 -24
  208. package/dist/securityHeaders-nwZ6nP4g.d.ts +0 -24
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SitemapSync.tsx"],"names":["sonorFetch","locToPath","isMalformedSitemapPath","inferPageType","useRef","useEffect"],"mappings":"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","file":"chunk-XHJXIAAW.js","sourcesContent":["/**\n * SitemapSync - Automatically sync sitemap.xml to Portal API\n *\n * Client-only component. Lives at package root so the main entry does not\n * pull in seo/ (and server-only code). For use in SiteKitProvider and\n * from @sonordev/site-kit/seo.\n *\n * @example\n * ```tsx\n * import { SitemapSync } from '@sonordev/site-kit'\n * // or\n * import { SitemapSync } from '@sonordev/site-kit/seo'\n * ```\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { sonorFetch } from './shared/sonorFetch'\n// Single source of truth for page-type inference + path normalization, shared\n// with createSitemap (build) and the register-sitemap CLI. Pure string logic,\n// safe in the browser.\nimport { inferPageType, locToPath, isMalformedSitemapPath } from './sitemap/shared'\n\ninterface SitemapSyncProps {\n /** Custom sitemap URL (defaults to /sitemap.xml) */\n sitemapUrl?: string\n /** How often to re-sync in minutes (0 = only on mount, default: 60) */\n syncInterval?: number\n /** Enable debug logging */\n debug?: boolean\n /**\n * Sync mode:\n * - 'additive' (default for runtime): adds/updates pages but never deletes existing ones\n * - 'full-replace': replaces the entire page set (use only for build-time sync via createSitemap)\n */\n mode?: 'additive' | 'full-replace'\n}\n\ninterface SitemapEntry {\n path: string\n lastmod?: string\n changefreq?: string\n priority?: number\n pageType?: string\n}\n\n/**\n * Per-browser-session sync throttle. Build-time sync (createSitemap) is the\n * canonical source of truth; runtime SitemapSync is only a safety net — so\n * re-registering the sitemap on every full page load of every visitor is pure\n * waste (fetch + DOMParser on the visitor's main thread, plus a write per\n * pageview against the API). Stamp the last successful sync in sessionStorage\n * and skip while inside the throttle window.\n */\nconst SYNC_STAMP_KEY = '_sk_sitemap_synced_at'\nconst SYNC_HASH_KEY = '_sk_sitemap_hash'\n\nfunction isRecentlySynced(throttleMinutes: number): boolean {\n try {\n const stamp = sessionStorage.getItem(SYNC_STAMP_KEY)\n if (!stamp) return false\n const elapsed = Date.now() - parseInt(stamp, 10)\n return elapsed >= 0 && elapsed < throttleMinutes * 60 * 1000\n } catch {\n return false // storage unavailable (private mode) — sync as before\n }\n}\n\nfunction stampSynced(): void {\n try {\n sessionStorage.setItem(SYNC_STAMP_KEY, Date.now().toString())\n } catch {\n /* storage unavailable — throttle simply won't apply */\n }\n}\n\n/**\n * Content-hash guard (localStorage, so it survives across sessions): the\n * sitemap of a static site only changes at deploy, so once ONE sync of a given\n * sitemap succeeded from this browser, re-POSTing the identical entry set is\n * pure API load. Hash the parsed entries; skip the POST when unchanged.\n * Keyed by sitemap URL so multiple SitemapSync instances don't collide.\n */\nfunction hashEntries(sitemapUrl: string, entries: SitemapEntry[]): string {\n const text = entries\n .map(e => `${e.path}|${e.lastmod ?? ''}|${e.changefreq ?? ''}|${e.priority ?? ''}`)\n .join('\\n')\n let hash = 0\n for (let i = 0; i < text.length; i++) {\n hash = ((hash << 5) - hash + text.charCodeAt(i)) | 0\n }\n return `${sitemapUrl}:${entries.length}:${hash.toString(16)}`\n}\n\nfunction isAlreadySyncedHash(hash: string): boolean {\n try {\n return localStorage.getItem(SYNC_HASH_KEY) === hash\n } catch {\n return false\n }\n}\n\nfunction storeSyncedHash(hash: string): void {\n try {\n localStorage.setItem(SYNC_HASH_KEY, hash)\n } catch {\n /* storage unavailable — guard simply won't apply */\n }\n}\n\nfunction getApiConfig() {\n if (typeof window === 'undefined') return { apiUrl: '', apiKey: '', site: '' }\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n const apiKey = (window as any).__SITE_KIT_API_KEY__ || ''\n // Sub-site host — set by SiteKitClientProviders from analytics.site config,\n // NEXT_PUBLIC_SITE_URL host, or window.location.host. Tagged on every\n // seo_pages row from this sitemap so the dashboard can scope the page tree\n // when one Sonor project hosts many sites.\n const site = (window as any).__SITE_KIT_SITE__ || window.location.host || ''\n return { apiUrl, apiKey, site }\n}\n\nasync function parseSitemap(sitemapUrl: string, debug: boolean): Promise<SitemapEntry[]> {\n try {\n const response = await sonorFetch(sitemapUrl)\n if (!response.ok) {\n if (debug) console.warn('[SitemapSync] Failed to fetch sitemap:', response.status)\n return []\n }\n\n const text = await response.text()\n const parser = new DOMParser()\n const doc = parser.parseFromString(text, 'application/xml')\n\n const parseError = doc.querySelector('parsererror')\n if (parseError) {\n if (debug) console.warn('[SitemapSync] Sitemap parse error:', parseError.textContent)\n return []\n }\n\n const urls = doc.querySelectorAll('url')\n const entries: SitemapEntry[] = []\n\n urls.forEach(url => {\n const loc = url.querySelector('loc')?.textContent?.trim()\n if (!loc) return\n\n const path = locToPath(loc)\n\n // Reject malformed paths (embedded domains, double protocols, etc.)\n if (isMalformedSitemapPath(path)) {\n if (debug) console.warn(`[SitemapSync] Skipping malformed path: ${path}`)\n return\n }\n\n const lastmod = url.querySelector('lastmod')?.textContent || undefined\n const changefreq = url.querySelector('changefreq')?.textContent || undefined\n const priorityStr = url.querySelector('priority')?.textContent\n const priority = priorityStr ? parseFloat(priorityStr) : undefined\n\n entries.push({ path, lastmod, changefreq, priority })\n })\n\n if (debug) {\n console.log(`[SitemapSync] Parsed ${entries.length} entries from sitemap`)\n }\n\n return entries\n } catch (error) {\n if (debug) console.error('[SitemapSync] Error parsing sitemap:', error)\n return []\n }\n}\n\nasync function syncToPortal(\n entries: SitemapEntry[],\n apiUrl: string,\n apiKey: string,\n site: string,\n debug: boolean,\n mode: 'additive' | 'full-replace' = 'additive'\n): Promise<{ success: boolean; created: number; updated: number }> {\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key configured')\n return { success: false, created: 0, updated: 0 }\n }\n\n if (entries.length === 0) {\n if (debug) console.log('[SitemapSync] No entries to sync')\n return { success: true, created: 0, updated: 0 }\n }\n\n try {\n // Registration is idempotent in both modes (same payload → same final\n // state), so retrying a timed-out attempt is safe.\n const response = await sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n entries: entries.map(e => ({\n path: e.path,\n priority: e.priority,\n changefreq: e.changefreq,\n pageType: inferPageType(e.path),\n })),\n mode,\n // Sub-site host — tagged on every seo_pages row so the dashboard\n // can scope the page tree to one microsite. Resolved by\n // SiteKitClientProviders (see __SITE_KIT_SITE__).\n ...(site ? { site } : {}),\n }),\n }, { apiKey })\n\n if (!response.ok) {\n if (debug) console.error('[SitemapSync] API error:', response.status, response.statusText)\n return { success: false, created: 0, updated: 0 }\n }\n\n const result = await response.json()\n\n if (debug) {\n console.log(`[SitemapSync] Synced: ${result.created} created, ${result.updated} updated`)\n }\n\n return {\n success: true,\n created: result.created || 0,\n updated: result.updated || 0,\n }\n } catch (error) {\n if (debug) console.error('[SitemapSync] Sync error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\nexport function SitemapSync({\n sitemapUrl = '/sitemap.xml',\n syncInterval = 60,\n debug = false,\n mode = 'additive',\n}: SitemapSyncProps) {\n const hasSyncedRef = useRef(false)\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n\n useEffect(() => {\n // Build-time sync via createSitemap is the canonical source of truth, but\n // it can fail during ISR revalidation (app/ dir unavailable on serverless).\n // Runtime SitemapSync in additive mode is a safe fallback — it adds/updates\n // pages that may be missing without ever deleting existing ones.\n // Full-replace is never safe at runtime — always force additive.\n const effectiveMode: 'additive' | 'full-replace' = 'additive'\n\n // Throttle window: reuse syncInterval when periodic syncing is on,\n // otherwise default to 60 minutes for the on-mount sync.\n const throttleMinutes = syncInterval > 0 ? syncInterval : 60\n\n const doSync = async () => {\n const { apiUrl, apiKey, site } = getApiConfig()\n\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key found')\n return\n }\n\n if (isRecentlySynced(throttleMinutes)) {\n if (debug) console.log('[SitemapSync] Skipped — synced within the last', throttleMinutes, 'min this session')\n return\n }\n\n if (debug) console.log('[SitemapSync] Starting sitemap sync...', site ? `(site: ${site})` : '')\n\n const entries = await parseSitemap(sitemapUrl, debug)\n\n if (entries.length > 0) {\n const hash = hashEntries(sitemapUrl, entries)\n if (isAlreadySyncedHash(hash)) {\n // This exact sitemap already synced from this browser — the server\n // state can't be improved by re-POSTing it. Stamp the session so we\n // don't even re-fetch/parse for the rest of the throttle window.\n stampSynced()\n if (debug) console.log('[SitemapSync] Skipped POST — sitemap unchanged since last successful sync')\n return\n }\n const result = await syncToPortal(entries, apiUrl, apiKey, site, debug, effectiveMode)\n if (result.success) {\n stampSynced()\n storeSyncedHash(hash)\n }\n }\n }\n\n if (!hasSyncedRef.current) {\n hasSyncedRef.current = true\n doSync()\n }\n\n if (syncInterval > 0) {\n intervalRef.current = setInterval(doSync, syncInterval * 60 * 1000)\n }\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [sitemapUrl, syncInterval, debug, mode])\n\n return null\n}\n"]}
1
+ {"version":3,"sources":["../src/SitemapSync.tsx"],"names":["sonorFetch","locToPath","isMalformedSitemapPath","inferPageType","useRef","useEffect"],"mappings":"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","file":"chunk-GSOLN2FC.js","sourcesContent":["/**\n * SitemapSync - Automatically sync sitemap.xml to Portal API\n *\n * Client-only component. Lives at package root so the main entry does not\n * pull in seo/ (and server-only code). For use in SiteKitProvider and\n * from @sonordev/site-kit/seo.\n *\n * @example\n * ```tsx\n * import { SitemapSync } from '@sonordev/site-kit'\n * // or\n * import { SitemapSync } from '@sonordev/site-kit/seo'\n * ```\n */\n\n'use client'\n\nimport { useEffect, useRef } from 'react'\nimport { sonorFetch } from './shared/sonorFetch'\n// Single source of truth for page-type inference + path normalization, shared\n// with createSitemap (build) and the register-sitemap CLI. Pure string logic,\n// safe in the browser.\nimport { inferPageType, locToPath, isMalformedSitemapPath } from './sitemap/shared'\n\ninterface SitemapSyncProps {\n /** Custom sitemap URL (defaults to /sitemap.xml) */\n sitemapUrl?: string\n /** How often to re-sync in minutes (0 = only on mount, default: 60) */\n syncInterval?: number\n /** Enable debug logging */\n debug?: boolean\n /**\n * Sync mode:\n * - 'additive' (default for runtime): adds/updates pages but never deletes existing ones\n * - 'full-replace': replaces the entire page set (use only for build-time sync via createSitemap)\n */\n mode?: 'additive' | 'full-replace'\n}\n\ninterface SitemapEntry {\n path: string\n lastmod?: string\n changefreq?: string\n priority?: number\n pageType?: string\n}\n\n/**\n * Per-browser-session sync throttle. Build-time sync (createSitemap) is the\n * canonical source of truth; runtime SitemapSync is only a safety net — so\n * re-registering the sitemap on every full page load of every visitor is pure\n * waste (fetch + DOMParser on the visitor's main thread, plus a write per\n * pageview against the API). Stamp the last successful sync in sessionStorage\n * and skip while inside the throttle window.\n */\nconst SYNC_STAMP_KEY = '_sk_sitemap_synced_at'\nconst SYNC_HASH_KEY = '_sk_sitemap_hash'\n\nfunction isRecentlySynced(throttleMinutes: number): boolean {\n try {\n const stamp = sessionStorage.getItem(SYNC_STAMP_KEY)\n if (!stamp) return false\n const elapsed = Date.now() - parseInt(stamp, 10)\n return elapsed >= 0 && elapsed < throttleMinutes * 60 * 1000\n } catch {\n return false // storage unavailable (private mode) — sync as before\n }\n}\n\nfunction stampSynced(): void {\n try {\n sessionStorage.setItem(SYNC_STAMP_KEY, Date.now().toString())\n } catch {\n /* storage unavailable — throttle simply won't apply */\n }\n}\n\n/**\n * Content-hash guard (localStorage, so it survives across sessions): the\n * sitemap of a static site only changes at deploy, so once ONE sync of a given\n * sitemap succeeded from this browser, re-POSTing the identical entry set is\n * pure API load. Hash the parsed entries; skip the POST when unchanged.\n * Keyed by sitemap URL so multiple SitemapSync instances don't collide.\n */\nfunction hashEntries(sitemapUrl: string, entries: SitemapEntry[]): string {\n const text = entries\n .map(e => `${e.path}|${e.lastmod ?? ''}|${e.changefreq ?? ''}|${e.priority ?? ''}`)\n .join('\\n')\n let hash = 0\n for (let i = 0; i < text.length; i++) {\n hash = ((hash << 5) - hash + text.charCodeAt(i)) | 0\n }\n return `${sitemapUrl}:${entries.length}:${hash.toString(16)}`\n}\n\nfunction isAlreadySyncedHash(hash: string): boolean {\n try {\n return localStorage.getItem(SYNC_HASH_KEY) === hash\n } catch {\n return false\n }\n}\n\nfunction storeSyncedHash(hash: string): void {\n try {\n localStorage.setItem(SYNC_HASH_KEY, hash)\n } catch {\n /* storage unavailable — guard simply won't apply */\n }\n}\n\nfunction getApiConfig() {\n if (typeof window === 'undefined') return { apiUrl: '', apiKey: '', site: '' }\n\n const apiUrl = (window as any).__SITE_KIT_API_URL__ || 'https://api.sonor.io'\n const apiKey = (window as any).__SITE_KIT_API_KEY__ || ''\n // Sub-site host — set by SiteKitClientProviders from analytics.site config,\n // NEXT_PUBLIC_SITE_URL host, or window.location.host. Tagged on every\n // seo_pages row from this sitemap so the dashboard can scope the page tree\n // when one Sonor project hosts many sites.\n const site = (window as any).__SITE_KIT_SITE__ || window.location.host || ''\n return { apiUrl, apiKey, site }\n}\n\nasync function parseSitemap(sitemapUrl: string, debug: boolean): Promise<SitemapEntry[]> {\n try {\n const response = await sonorFetch(sitemapUrl)\n if (!response.ok) {\n if (debug) console.warn('[SitemapSync] Failed to fetch sitemap:', response.status)\n return []\n }\n\n const text = await response.text()\n const parser = new DOMParser()\n const doc = parser.parseFromString(text, 'application/xml')\n\n const parseError = doc.querySelector('parsererror')\n if (parseError) {\n if (debug) console.warn('[SitemapSync] Sitemap parse error:', parseError.textContent)\n return []\n }\n\n const urls = doc.querySelectorAll('url')\n const entries: SitemapEntry[] = []\n\n urls.forEach(url => {\n const loc = url.querySelector('loc')?.textContent?.trim()\n if (!loc) return\n\n const path = locToPath(loc)\n\n // Reject malformed paths (embedded domains, double protocols, etc.)\n if (isMalformedSitemapPath(path)) {\n if (debug) console.warn(`[SitemapSync] Skipping malformed path: ${path}`)\n return\n }\n\n const lastmod = url.querySelector('lastmod')?.textContent || undefined\n const changefreq = url.querySelector('changefreq')?.textContent || undefined\n const priorityStr = url.querySelector('priority')?.textContent\n const priority = priorityStr ? parseFloat(priorityStr) : undefined\n\n entries.push({ path, lastmod, changefreq, priority })\n })\n\n if (debug) {\n console.log(`[SitemapSync] Parsed ${entries.length} entries from sitemap`)\n }\n\n return entries\n } catch (error) {\n if (debug) console.error('[SitemapSync] Error parsing sitemap:', error)\n return []\n }\n}\n\nasync function syncToPortal(\n entries: SitemapEntry[],\n apiUrl: string,\n apiKey: string,\n site: string,\n debug: boolean,\n mode: 'additive' | 'full-replace' = 'additive'\n): Promise<{ success: boolean; created: number; updated: number }> {\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key configured')\n return { success: false, created: 0, updated: 0 }\n }\n\n if (entries.length === 0) {\n if (debug) console.log('[SitemapSync] No entries to sync')\n return { success: true, created: 0, updated: 0 }\n }\n\n try {\n // Registration is idempotent in both modes (same payload → same final\n // state), so retrying a timed-out attempt is safe.\n const response = await sonorFetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n entries: entries.map(e => ({\n path: e.path,\n priority: e.priority,\n changefreq: e.changefreq,\n pageType: inferPageType(e.path),\n })),\n mode,\n // Sub-site host — tagged on every seo_pages row so the dashboard\n // can scope the page tree to one microsite. Resolved by\n // SiteKitClientProviders (see __SITE_KIT_SITE__).\n ...(site ? { site } : {}),\n }),\n }, { apiKey })\n\n if (!response.ok) {\n if (debug) console.error('[SitemapSync] API error:', response.status, response.statusText)\n return { success: false, created: 0, updated: 0 }\n }\n\n const result = await response.json()\n\n if (debug) {\n console.log(`[SitemapSync] Synced: ${result.created} created, ${result.updated} updated`)\n }\n\n return {\n success: true,\n created: result.created || 0,\n updated: result.updated || 0,\n }\n } catch (error) {\n if (debug) console.error('[SitemapSync] Sync error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\nexport function SitemapSync({\n sitemapUrl = '/sitemap.xml',\n syncInterval = 60,\n debug = false,\n mode = 'additive',\n}: SitemapSyncProps) {\n const hasSyncedRef = useRef(false)\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n\n useEffect(() => {\n // Build-time sync via createSitemap is the canonical source of truth, but\n // it can fail during ISR revalidation (app/ dir unavailable on serverless).\n // Runtime SitemapSync in additive mode is a safe fallback — it adds/updates\n // pages that may be missing without ever deleting existing ones.\n // Full-replace is never safe at runtime — always force additive.\n const effectiveMode: 'additive' | 'full-replace' = 'additive'\n\n // Throttle window: reuse syncInterval when periodic syncing is on,\n // otherwise default to 60 minutes for the on-mount sync.\n const throttleMinutes = syncInterval > 0 ? syncInterval : 60\n\n const doSync = async () => {\n const { apiUrl, apiKey, site } = getApiConfig()\n\n if (!apiKey) {\n if (debug) console.warn('[SitemapSync] No API key found')\n return\n }\n\n if (isRecentlySynced(throttleMinutes)) {\n if (debug) console.log('[SitemapSync] Skipped — synced within the last', throttleMinutes, 'min this session')\n return\n }\n\n if (debug) console.log('[SitemapSync] Starting sitemap sync...', site ? `(site: ${site})` : '')\n\n const entries = await parseSitemap(sitemapUrl, debug)\n\n if (entries.length > 0) {\n const hash = hashEntries(sitemapUrl, entries)\n if (isAlreadySyncedHash(hash)) {\n // This exact sitemap already synced from this browser — the server\n // state can't be improved by re-POSTing it. Stamp the session so we\n // don't even re-fetch/parse for the rest of the throttle window.\n stampSynced()\n if (debug) console.log('[SitemapSync] Skipped POST — sitemap unchanged since last successful sync')\n return\n }\n const result = await syncToPortal(entries, apiUrl, apiKey, site, debug, effectiveMode)\n if (result.success) {\n stampSynced()\n storeSyncedHash(hash)\n }\n }\n }\n\n if (!hasSyncedRef.current) {\n hasSyncedRef.current = true\n doSync()\n }\n\n if (syncInterval > 0) {\n intervalRef.current = setInterval(doSync, syncInterval * 60 * 1000)\n }\n\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current)\n }\n }\n }, [sitemapUrl, syncInterval, debug, mode])\n\n return null\n}\n"]}
@@ -51,6 +51,36 @@ function sanitizePrimaryLanguageTag(raw) {
51
51
  if (!/^[\w-]{2,20}$/.test(s)) return null;
52
52
  return s;
53
53
  }
54
+ function isEmittableReviewNode(node) {
55
+ const author = node.author;
56
+ if (typeof author === "string") return author.trim().length > 0;
57
+ if (Array.isArray(author)) {
58
+ return author.some((a) => isEmittableReviewNode({ author: a }));
59
+ }
60
+ if (author && typeof author === "object") {
61
+ const name = author.name;
62
+ return typeof name === "string" && name.trim().length > 0;
63
+ }
64
+ return false;
65
+ }
66
+ var DROP = /* @__PURE__ */ Symbol("drop-invalid-review");
67
+ function stripInvalidReviewNodes(value) {
68
+ if (Array.isArray(value)) {
69
+ return value.map((v) => stripInvalidReviewNodes(v)).filter((v) => v !== DROP);
70
+ }
71
+ if (value && typeof value === "object") {
72
+ const src = value;
73
+ if (src["@type"] === "Review" && !isEmittableReviewNode(src)) return DROP;
74
+ const out = {};
75
+ for (const key of Object.keys(src)) {
76
+ const child = stripInvalidReviewNodes(src[key]);
77
+ if (child === DROP) continue;
78
+ out[key] = child;
79
+ }
80
+ return out;
81
+ }
82
+ return value;
83
+ }
54
84
  function pickManagedLlmSchemaForJsonLd(schema) {
55
85
  if (!schema || typeof schema !== "object") return null;
56
86
  const out = {};
@@ -58,7 +88,9 @@ function pickManagedLlmSchemaForJsonLd(schema) {
58
88
  for (const key of Object.keys(schema)) {
59
89
  if (omitFromJsonLd.has(key)) continue;
60
90
  if (MANAGED_LLM_SCHEMA_KNOWN_KEYS.has(key)) {
61
- out[key] = schema[key];
91
+ const value = stripInvalidReviewNodes(schema[key]);
92
+ if (value === DROP) continue;
93
+ out[key] = value;
62
94
  }
63
95
  }
64
96
  return Object.keys(out).length ? out : null;
@@ -72,5 +104,5 @@ exports.pickManagedLlmSchemaForJsonLd = pickManagedLlmSchemaForJsonLd;
72
104
  exports.sanitizeLlmsDisclaimerLine = sanitizeLlmsDisclaimerLine;
73
105
  exports.sanitizeLlmsPublicSummary = sanitizeLlmsPublicSummary;
74
106
  exports.sanitizePrimaryLanguageTag = sanitizePrimaryLanguageTag;
75
- //# sourceMappingURL=chunk-ATG4FJY6.js.map
76
- //# sourceMappingURL=chunk-ATG4FJY6.js.map
107
+ //# sourceMappingURL=chunk-H6AU3WKF.js.map
108
+ //# sourceMappingURL=chunk-H6AU3WKF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/llms/contract.ts"],"names":[],"mappings":"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","file":"chunk-H6AU3WKF.js","sourcesContent":["/**\n * GEO / AEO contract — shared shape for Sonor API, Signal API, and site-kit.\n * Bump LLM_GEO_CONTRACT_VERSION when making breaking changes to public payloads.\n *\n * Server code (Nest) should import from `@sonordev/site-kit/llms/contract` only.\n *\n * @see LLM_GEO_CONTRACT.md in this folder\n */\n\n/** Increment when public LLMs payload shape changes incompatibly. */\nexport const LLM_GEO_CONTRACT_VERSION = 1 as const\n\n/** Max length for llms_public_summary (plain text, single line in llms.txt link notes). */\nexport const LLMS_PUBLIC_SUMMARY_MAX_LENGTH = 400\n\n/** Max length for optional llms.txt blockquote disclaimer line. */\nexport const LLMS_DISCLAIMER_MAX_LENGTH = 280\n\n/**\n * Optional keys we allow inside managed_llm_schema JSON from Portal.\n * Values outside this set should not be relied on by consumers; strip unknown keys when emitting JSON-LD.\n */\nexport const MANAGED_LLM_SCHEMA_KNOWN_KEYS = new Set([\n '@context',\n '@type',\n 'name',\n 'description',\n 'url',\n 'keywords',\n 'audience',\n 'about',\n 'mainEntity',\n 'isPartOf',\n 'speakable',\n 'additionalType',\n])\n\nexport interface LLMsPayloadMeta {\n /** Contract version for this payload (matches LLM_GEO_CONTRACT_VERSION when current). */\n contract_version: number\n /** ISO 8601 — best-effort freshness for the project’s SEO data. */\n last_updated?: string | null\n /** BCP 47 tag for primary public content (e.g. from project settings). */\n primary_language?: string | null\n /** Optional single-line, public-safe note in the llms.txt blockquote (e.g. scope / not legal advice). */\n llms_disclaimer?: string | null\n}\n\n/**\n * Public-safe summary for llms.txt `[title](url): notes` — never CRM-only or internal copy.\n */\nexport function sanitizeLlmsPublicSummary(raw: unknown): string | null {\n if (raw === null || raw === undefined) return null\n if (typeof raw !== 'string') return null\n let s = raw.trim().replace(/\\s+/g, ' ')\n // Avoid breaking markdown list lines / JSON-LD leakage\n s = s.replace(/[\\[\\]\\r\\n]/g, ' ').replace(/\\s+/g, ' ').trim()\n if (s.length > LLMS_PUBLIC_SUMMARY_MAX_LENGTH) {\n s = `${s.slice(0, LLMS_PUBLIC_SUMMARY_MAX_LENGTH - 1).trimEnd()}…`\n }\n // Drop obvious email / tel patterns (PII guardrail — not exhaustive)\n if (/\\b[\\w.%+-]+@[\\w.-]+\\.[A-Za-z]{2,}\\b/.test(s)) return null\n if (/\\b\\+?\\d[\\d\\s().-]{8,}\\b/.test(s)) return null\n if (s.length < 8) return null\n return s\n}\n\n/**\n * Single line for llms.txt blockquote disclaimer — shorter min length than link notes.\n */\nexport function sanitizeLlmsDisclaimerLine(raw: unknown): string | null {\n if (raw === null || raw === undefined) return null\n if (typeof raw !== 'string') return null\n let s = raw.trim().replace(/\\s+/g, ' ')\n s = s.replace(/[\\[\\]\\r\\n]/g, ' ').replace(/\\s+/g, ' ').trim()\n if (s.length > LLMS_DISCLAIMER_MAX_LENGTH) {\n s = `${s.slice(0, LLMS_DISCLAIMER_MAX_LENGTH - 1).trimEnd()}…`\n }\n if (/\\b[\\w.%+-]+@[\\w.-]+\\.[A-Za-z]{2,}\\b/.test(s)) return null\n if (/\\b\\+?\\d[\\d\\s().-]{8,}\\b/.test(s)) return null\n if (s.length < 3) return null\n return s\n}\n\n/** Normalize BCP 47 tag for display (no quotes). */\nexport function sanitizePrimaryLanguageTag(raw: unknown): string | null {\n if (raw === null || raw === undefined) return null\n if (typeof raw !== 'string') return null\n const s = raw.trim()\n if (!/^[\\w-]{2,20}$/.test(s)) return null\n return s\n}\n\n/**\n * Google requires `author` on every Review node and treats its absence as a\n * CRITICAL error that suppresses review rich results for the whole page.\n * Generated schema has shipped Review nodes carrying only `reviewBody` and\n * `itemReviewed` — editorial prose about a client, not an attributed review —\n * so they are invalid markup AND self-serving-review-policy risk.\n *\n * Single source of truth for \"is this Review node safe to emit as JSON-LD\".\n * An author must resolve to a non-empty name; a bare `{\"@type\":\"Review\"}` and\n * `author: {}` both fail.\n */\nfunction isEmittableReviewNode(node: Record<string, unknown>): boolean {\n const author = node.author\n if (typeof author === 'string') return author.trim().length > 0\n if (Array.isArray(author)) {\n return author.some((a) => isEmittableReviewNode({ author: a }))\n }\n if (author && typeof author === 'object') {\n const name = (author as Record<string, unknown>).name\n return typeof name === 'string' && name.trim().length > 0\n }\n return false\n}\n\n/**\n * Recursively drop Review nodes that cannot be emitted (see above), wherever\n * they sit: array entry, object-valued key, or the value handed in. Returns\n * DROP for a node the caller must remove; everything else is passed through\n * structurally unchanged.\n */\nconst DROP = Symbol('drop-invalid-review')\n\nfunction stripInvalidReviewNodes(value: unknown): unknown | typeof DROP {\n if (Array.isArray(value)) {\n return value\n .map((v) => stripInvalidReviewNodes(v))\n .filter((v) => v !== DROP)\n }\n if (value && typeof value === 'object') {\n const src = value as Record<string, unknown>\n if (src['@type'] === 'Review' && !isEmittableReviewNode(src)) return DROP\n const out: Record<string, unknown> = {}\n for (const key of Object.keys(src)) {\n const child = stripInvalidReviewNodes(src[key])\n if (child === DROP) continue\n out[key] = child\n }\n return out\n }\n return value\n}\n\n/** Pick JSON-LD-safe subset of managed_llm_schema for script injection. */\nexport function pickManagedLlmSchemaForJsonLd(\n schema: Record<string, unknown> | null | undefined,\n): Record<string, unknown> | null {\n if (!schema || typeof schema !== 'object') return null\n const out: Record<string, unknown> = {}\n const omitFromJsonLd = new Set(['llms_public_summary'])\n for (const key of Object.keys(schema)) {\n if (omitFromJsonLd.has(key)) continue\n if (MANAGED_LLM_SCHEMA_KNOWN_KEYS.has(key)) {\n const value = stripInvalidReviewNodes(schema[key])\n if (value === DROP) continue\n out[key] = value\n }\n }\n return Object.keys(out).length ? out : null\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
- import { useForm } from './chunk-PHLJDLRA.mjs';
3
- import { sonorFetch } from './chunk-FJTER53S.mjs';
2
+ import { useForm } from './chunk-R26NFTOR.mjs';
3
+ import { sonorFetch } from './chunk-RSFSXEV2.mjs';
4
4
  import { useState, useRef, useEffect, useCallback } from 'react';
5
5
  import ReactMarkdown from 'react-markdown';
6
6
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -1605,5 +1605,5 @@ function ChatWidget({ projectId: propProjectId, config, apiUrl: propApiUrl, sign
1605
1605
  }
1606
1606
 
1607
1607
  export { ChatWidget };
1608
- //# sourceMappingURL=chunk-IJR3ATI5.mjs.map
1609
- //# sourceMappingURL=chunk-IJR3ATI5.mjs.map
1608
+ //# sourceMappingURL=chunk-HQB24QUN.mjs.map
1609
+ //# sourceMappingURL=chunk-HQB24QUN.mjs.map