@sonordev/site-kit 1.3.0 → 1.3.2

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 (63) hide show
  1. package/dist/{chunk-SQSBAPWA.mjs → chunk-3QKTOTWS.mjs} +5 -5
  2. package/dist/chunk-3QKTOTWS.mjs.map +1 -0
  3. package/dist/{chunk-BFJDUTXK.js → chunk-5NXUENL3.js} +3 -3
  4. package/dist/{chunk-BFJDUTXK.js.map → chunk-5NXUENL3.js.map} +1 -1
  5. package/dist/{chunk-6TFGPXXK.mjs → chunk-5TTTX6NN.mjs} +2 -2
  6. package/dist/{chunk-6TFGPXXK.mjs.map → chunk-5TTTX6NN.mjs.map} +1 -1
  7. package/dist/{chunk-44GSXYHJ.mjs → chunk-J4K335PQ.mjs} +3 -3
  8. package/dist/{chunk-44GSXYHJ.mjs.map → chunk-J4K335PQ.mjs.map} +1 -1
  9. package/dist/chunk-JB6I5PYV.js +939 -0
  10. package/dist/chunk-JB6I5PYV.js.map +1 -0
  11. package/dist/{chunk-7ROZJDXE.js → chunk-JKPJ2QCC.js} +2 -2
  12. package/dist/{chunk-7ROZJDXE.js.map → chunk-JKPJ2QCC.js.map} +1 -1
  13. package/dist/{chunk-JMNSED4O.mjs → chunk-KMLCQYEV.mjs} +3 -3
  14. package/dist/{chunk-JMNSED4O.mjs.map → chunk-KMLCQYEV.mjs.map} +1 -1
  15. package/dist/{chunk-YIL674PV.js → chunk-LTTTIJPN.js} +5 -5
  16. package/dist/{chunk-YIL674PV.js.map → chunk-LTTTIJPN.js.map} +1 -1
  17. package/dist/{chunk-742WMKQC.js → chunk-NZHVGBAF.js} +2 -2
  18. package/dist/{chunk-742WMKQC.js.map → chunk-NZHVGBAF.js.map} +1 -1
  19. package/dist/{chunk-RMOL4TZ6.js → chunk-PJKHCYI5.js} +5 -5
  20. package/dist/chunk-PJKHCYI5.js.map +1 -0
  21. package/dist/{chunk-47Y3YSES.mjs → chunk-QBFTBORL.mjs} +2 -2
  22. package/dist/{chunk-47Y3YSES.mjs.map → chunk-QBFTBORL.mjs.map} +1 -1
  23. package/dist/{chunk-2RHO4KSK.mjs → chunk-RJTBSSZB.mjs} +4 -4
  24. package/dist/{chunk-2RHO4KSK.mjs.map → chunk-RJTBSSZB.mjs.map} +1 -1
  25. package/dist/{chunk-CFEOOJUT.js → chunk-RRBBMEDL.js} +7 -7
  26. package/dist/{chunk-CFEOOJUT.js.map → chunk-RRBBMEDL.js.map} +1 -1
  27. package/dist/chunk-W2TZYAUL.mjs +925 -0
  28. package/dist/chunk-W2TZYAUL.mjs.map +1 -0
  29. package/dist/cli/index.js +1 -1
  30. package/dist/cli/index.mjs +1 -1
  31. package/dist/index.js +60 -938
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.mjs +3 -917
  34. package/dist/index.mjs.map +1 -1
  35. package/dist/layout/client.js +2 -2
  36. package/dist/layout/client.mjs +1 -1
  37. package/dist/layout/index.js +6 -6
  38. package/dist/layout/index.mjs +3 -3
  39. package/dist/llms/index.js +12 -12
  40. package/dist/llms/index.mjs +2 -2
  41. package/dist/seo/index.js +41 -53
  42. package/dist/seo/index.js.map +1 -1
  43. package/dist/seo/index.mjs +6 -18
  44. package/dist/seo/index.mjs.map +1 -1
  45. package/dist/seo/server.js +4 -4
  46. package/dist/seo/server.mjs +2 -2
  47. package/dist/{server-api-HTSLBT6F.mjs → server-api-FCTEQOTK.mjs} +3 -3
  48. package/dist/{server-api-HTSLBT6F.mjs.map → server-api-FCTEQOTK.mjs.map} +1 -1
  49. package/dist/{server-api-C5JXIROA.js → server-api-SYINXTN7.js} +21 -21
  50. package/dist/{server-api-C5JXIROA.js.map → server-api-SYINXTN7.js.map} +1 -1
  51. package/dist/setup/index.js +2 -2
  52. package/dist/setup/index.mjs +1 -1
  53. package/dist/setup/server.js +2 -2
  54. package/dist/setup/server.mjs +1 -1
  55. package/dist/sitemap/index.js +2 -2
  56. package/dist/sitemap/index.mjs +1 -1
  57. package/dist/sync/index.js +63 -0
  58. package/dist/sync/index.js.map +1 -0
  59. package/dist/sync/index.mjs +4 -0
  60. package/dist/sync/index.mjs.map +1 -0
  61. package/package.json +6 -1
  62. package/dist/chunk-RMOL4TZ6.js.map +0 -1
  63. package/dist/chunk-SQSBAPWA.mjs.map +0 -1
@@ -14,7 +14,7 @@ function getProjectIdFromKey(apiKey) {
14
14
  const match = apiKey.match(/^(?:sonor|uptrade)_([0-9a-f-]{36})_/);
15
15
  return match ? match[1] : null;
16
16
  }
17
- async function secureApiPost(endpoint, body = {}) {
17
+ async function secureApiPost(endpoint, body = {}, revalidate = 86400) {
18
18
  const { apiUrl, apiKey } = getSecureApiConfig();
19
19
  try {
20
20
  const response = await fetch(`${apiUrl}${endpoint}`, {
@@ -24,8 +24,8 @@ async function secureApiPost(endpoint, body = {}) {
24
24
  "x-api-key": apiKey
25
25
  },
26
26
  body: JSON.stringify(body),
27
- next: { revalidate: 60 }
28
- // Cache for 60 seconds
27
+ next: { revalidate }
28
+ // 24h default SEO data rarely changes; Portal can on-demand revalidate
29
29
  });
30
30
  if (!response.ok) {
31
31
  let detail = response.statusText;
@@ -198,5 +198,5 @@ var getVisibilitySummary = cache(async () => {
198
198
  });
199
199
 
200
200
  export { ensureMetadata, getABTest, getContentBlock, getEntities, getEntityEnhancedSchema, getFAQData, getInternalLinks, getManagedScripts, getPrimaryEntity, getRedirectData, getRobotsData, getSEOPageData, getSchemaMarkups, getSitemapEntries, getVisibilityScore, getVisibilitySummary, recordABImpression, registerSitemap };
201
- //# sourceMappingURL=chunk-SQSBAPWA.mjs.map
202
- //# sourceMappingURL=chunk-SQSBAPWA.mjs.map
201
+ //# sourceMappingURL=chunk-3QKTOTWS.mjs.map
202
+ //# sourceMappingURL=chunk-3QKTOTWS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/seo/server-api.ts"],"names":[],"mappings":"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","file":"chunk-3QKTOTWS.mjs","sourcesContent":["/**\n * @sonordev/site-kit/seo - Server-Only API Functions\n * \n * SECURITY: These functions use private environment variables\n * and should ONLY be imported in server-side code (RSC, API routes, server actions).\n * \n * DO NOT import this file in client components or it will expose API keys.\n */\n\nimport { cache } from 'react'\nimport 'server-only' // This ensures the module can only be imported server-side\n\n// ============================================\n// Server-Only API Config\n// ============================================\n\n/**\n * Config for portal API calls. Project is resolved by the portal from the API key;\n * sites never send or read project ID.\n */\nfunction getSecureApiConfig() {\n const apiUrl = process.env.SONOR_API_URL || process.env.UPTRADE_API_URL || process.env.NEXT_PUBLIC_UPTRADE_API_URL || 'https://api.sonor.io'\n const apiKey = process.env.SONOR_API_KEY || process.env.UPTRADE_API_KEY || process.env.NEXT_PUBLIC_UPTRADE_API_KEY || ''\n\n if (!apiKey) {\n throw new Error('@sonordev/seo: SONOR_API_KEY (or UPTRADE_API_KEY) environment variable is required for server-side SEO functions')\n }\n\n return { apiUrl, apiKey }\n}\n\n/** Derive project ID from API key for Signal API only (format: sonor_{uuid}_{secret} or uptrade_{uuid}_{secret}). Not used for portal. */\nfunction getProjectIdFromKey(apiKey: string): string | null {\n const match = apiKey.match(/^(?:sonor|uptrade)_([0-9a-f-]{36})_/)\n return match ? match[1] : null\n}\n\nasync function secureApiPost<T>(endpoint: string, body: Record<string, any> = {}, revalidate = 86400): Promise<T | null> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n\n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify(body),\n next: { revalidate }, // 24h default — SEO data rarely changes; Portal can on-demand revalidate\n })\n\n if (!response.ok) {\n let detail = response.statusText\n try {\n const err = await response.json().catch(() => ({}))\n if (err?.message) detail = err.message\n } catch {\n /* ignore */\n }\n console.error(`@sonordev/seo: API error ${response.status} ${endpoint}: ${detail}`)\n return null\n }\n\n return await response.json()\n } catch (error) {\n console.error('@sonordev/seo: Network error:', error)\n return null\n }\n}\n\nasync function secureApiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 86400 },\n })\n\n if (!response.ok) {\n console.error(`@sonordev/seo: API error ${response.status}: ${response.statusText}`)\n return null\n }\n \n return await response.json()\n } catch (error) {\n console.error('@sonordev/seo: Network error:', error)\n return null\n }\n}\n\n// ============================================\n// Secure Cached Data Fetchers\n// ============================================\n\n/**\n * Fetch SEO page data - cached per request\n * @server-only\n */\nexport const getSEOPageData = cache(async (path: string) => {\n const result = await secureApiPost<{ page: any; project: any }>('/api/public/seo/page', { path })\n return {\n page: result?.page || null,\n project: result?.project || null,\n }\n})\n\n/**\n * Fetch schema markups for a page - cached per request\n * @server-only\n */\nexport const getSchemaMarkups = cache(async (\n path: string,\n options?: { includeTypes?: string[]; excludeTypes?: string[] }\n) => {\n const result = await secureApiPost<{ schemas: any[] }>('/api/public/seo/schemas', {\n path,\n includeTypes: options?.includeTypes,\n excludeTypes: options?.excludeTypes,\n })\n return result?.schemas || []\n})\n\n/**\n * Fetch FAQ data for a page - cached per request\n * @server-only\n */\nexport const getFAQData = cache(async (path: string) => {\n const result = await secureApiPost<{ faq: any }>('/api/public/seo/faq', { path })\n return result?.faq || null\n})\n\n/**\n * Fetch internal links for a page - cached per request\n * @server-only\n */\nexport const getInternalLinks = cache(async (\n sourcePath: string,\n options?: { position?: string; limit?: number }\n) => {\n const result = await secureApiPost<{ links: any[] }>('/api/public/seo/internal-links', {\n sourcePath,\n position: options?.position,\n limit: options?.limit,\n })\n return result?.links || []\n})\n\n/**\n * Fetch content block - cached per request\n * @server-only\n */\nexport const getContentBlock = cache(async (path: string, section: string) => {\n const result = await secureApiPost<{ content: any }>('/api/public/seo/content', { path, section })\n return result?.content || null\n})\n\n/**\n * Fetch A/B test and determine variant - cached per request\n * @server-only\n */\nexport const getABTest = cache(async (path: string, field: string) => {\n const result = await secureApiPost<{ test: any }>('/api/public/seo/ab-test', { path, field })\n return result?.test || null\n})\n\n/**\n * Record A/B test impression\n * @server-only\n */\nexport async function recordABImpression(\n testId: string,\n variant: 'a' | 'b',\n sessionId?: string\n): Promise<void> {\n await secureApiPost('/api/public/seo/ab-impression', { testId, variant, sessionId })\n}\n\n/**\n * Fetch redirect for a path - cached per request\n * @server-only\n */\nexport const getRedirectData = cache(async (path: string) => {\n const result = await secureApiPost<{ redirect: any }>('/api/public/seo/redirect', { path })\n return result?.redirect || null\n})\n\n/**\n * Fetch managed scripts - cached per request\n * @server-only\n */\nexport const getManagedScripts = cache(async (position: string, currentPath?: string) => {\n const result = await secureApiPost<{ scripts: any[] }>('/api/public/seo/scripts', {\n position,\n currentPath,\n })\n return result?.scripts || []\n})\n\n/**\n * Fetch robots directive for a page - cached per request\n * @server-only\n */\nexport const getRobotsData = cache(async (path: string) => {\n const result = await secureApiPost<{ page: any }>('/api/public/seo/page', { path })\n return result?.page?.managed_robots || null\n})\n\n/**\n * Fetch sitemap entries - cached per request\n * @server-only\n */\nexport const getSitemapEntries = cache(async (options?: { publishedOnly?: boolean }) => {\n const result = await secureApiPost<{ entries: any[] }>('/api/public/seo/sitemap', {\n publishedOnly: options?.publishedOnly,\n })\n return result?.entries || []\n})\n\n/**\n * Register/sync sitemap entries from the client site\n * Call this at build time to populate seo_pages from your sitemap.xml\n * @server-only\n * \n * @example\n * ```ts\n * // scripts/register-sitemap.ts (run at build time)\n * import { registerSitemap } from '@sonordev/seo/server'\n * \n * await registerSitemap([\n * { path: '/', priority: 1.0, changefreq: 'daily' },\n * { path: '/about', priority: 0.8, changefreq: 'weekly' },\n * ])\n * ```\n */\nexport async function registerSitemap(\n entries: Array<{\n path: string\n title?: string\n priority?: number\n changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'\n }>\n): Promise<{ success: boolean; created: number; updated: number }> {\n const { apiUrl, apiKey } = getSecureApiConfig()\n\n try {\n const response = await fetch(`${apiUrl}/api/public/seo/register-sitemap`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify({ entries }),\n })\n \n if (!response.ok) {\n console.error(`@sonordev/seo: Sitemap registration failed: ${response.statusText}`)\n return { success: false, created: 0, updated: 0 }\n }\n \n return await response.json()\n } catch (error) {\n console.error('@sonordev/seo: Sitemap registration error:', error)\n return { success: false, created: 0, updated: 0 }\n }\n}\n\n// ============================================\n// Signal-Powered Metadata Fallback\n// ============================================\n\n/**\n * Ensure metadata exists for a page by triggering Signal AI optimization.\n * If the page has no managed_title or managed_meta_description, Signal will\n * generate them and save to the database via Portal proxy.\n *\n * Idempotent — returns existing metadata if already populated.\n * @server-only\n */\nexport const ensureMetadata = cache(async (path: string): Promise<{\n managed_title?: string\n managed_meta_description?: string\n managed_keywords?: string[]\n managed_schema?: Record<string, unknown>\n} | null> => {\n return secureApiPost('/api/public/seo/ensure-metadata', { path })\n})\n\n// ============================================\n// AI Visibility & Entity Graph API (Signal)\n// ============================================\n\nfunction getSignalApiConfig() {\n const apiUrl = process.env.SONOR_SIGNAL_URL || process.env.SIGNAL_API_URL || process.env.NEXT_PUBLIC_SIGNAL_API_URL || 'https://signal.sonor.io'\n const apiKey = process.env.SONOR_API_KEY || process.env.UPTRADE_API_KEY || ''\n return { apiUrl, apiKey }\n}\n\nasync function signalApiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getSignalApiConfig()\n \n if (!apiKey) {\n return null\n }\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 300 }, // Cache for 5 minutes\n })\n \n if (!response.ok) {\n return null\n }\n \n const result = await response.json()\n return result?.data || result\n } catch (error) {\n console.error('@sonordev/seo: Signal API error:', error)\n return null\n }\n}\n\n/**\n * Entity types for the knowledge graph\n */\nexport type EntityType = \n | 'organization'\n | 'person'\n | 'service'\n | 'product'\n | 'location'\n | 'concept'\n | 'credential'\n\n/**\n * Entity from the knowledge graph\n */\nexport interface SEOEntity {\n id: string\n project_id: string\n entity_type: EntityType\n name: string\n slug: string\n properties: Record<string, unknown>\n knows_about: string[]\n same_as: string[]\n schema_type?: string\n is_primary: boolean\n}\n\n/**\n * Fetch entities for a project - cached per request\n * Returns the entity graph for enhanced schema markup\n * @server-only\n */\nexport const getEntities = cache(async (\n options?: { type?: EntityType }\n): Promise<SEOEntity[]> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return []\n let endpoint = `/skills/seo/entities/${projectId}`\n if (options?.type) {\n endpoint += `?type=${options.type}`\n }\n const result = await signalApiGet<SEOEntity[]>(endpoint)\n return result || []\n})\n\n/**\n * Fetch primary entity (the business) - cached per request\n * @server-only\n */\nexport const getPrimaryEntity = cache(async (): Promise<SEOEntity | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n return signalApiGet<SEOEntity>(`/skills/seo/entities/${projectId}/primary`)\n})\n\n/**\n * Fetch entity-enhanced schema for a page\n * Returns Organization schema with knowsAbout, areaServed, employee, etc.\n * @server-only\n */\nexport const getEntityEnhancedSchema = cache(async (pagePath: string): Promise<object[]> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return []\n const result = await signalApiGet<{ schemas: object[] }>(\n `/skills/seo/schema/${projectId}/entity-enhanced?pagePath=${encodeURIComponent(pagePath)}`\n )\n return result?.schemas || []\n})\n\n/**\n * Get AI visibility score for a page\n * @server-only\n */\nexport const getVisibilityScore = cache(async (\n pagePath: string\n): Promise<{\n overall_score: number\n entity_coverage: number\n answer_density: number\n chunk_readability: number\n authority_signals: number\n schema_completeness: number\n} | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n const result = await signalApiGet<any[]>(`/skills/seo/visibility/${projectId}`)\n if (!result) return null\n return result.find(s => s.page_path === pagePath) || null\n})\n\n/**\n * Get AI visibility summary for project\n * @server-only\n */\nexport const getVisibilitySummary = cache(async (): Promise<{\n overall_score: number\n total_entities: number\n pages_analyzed: number\n top_recommendations: Array<{ priority: string; type: string; message: string }>\n} | null> => {\n const { apiKey } = getSecureApiConfig()\n const projectId = getProjectIdFromKey(apiKey)\n if (!projectId) return null\n return signalApiGet(`/skills/seo/visibility/${projectId}/summary`)\n})\n"]}
@@ -165,7 +165,7 @@ async function generateLLMsTxt(options) {
165
165
  }
166
166
  if (includeEntities) {
167
167
  try {
168
- const { getEntities, getPrimaryEntity } = await import('./server-api-C5JXIROA.js');
168
+ const { getEntities, getPrimaryEntity } = await import('./server-api-SYINXTN7.js');
169
169
  const [entities, primaryEntity] = await Promise.all([
170
170
  getEntities().then((e) => e.slice(0, maxEntities)),
171
171
  getPrimaryEntity()
@@ -386,5 +386,5 @@ exports.getOptimizedLLMsTxt = getOptimizedLLMsTxt;
386
386
  exports.getPageSummaries = getPageSummaries;
387
387
  exports.getServices = getServices;
388
388
  exports.writeLLMsTxtToPublic = writeLLMsTxtToPublic;
389
- //# sourceMappingURL=chunk-BFJDUTXK.js.map
390
- //# sourceMappingURL=chunk-BFJDUTXK.js.map
389
+ //# sourceMappingURL=chunk-5NXUENL3.js.map
390
+ //# sourceMappingURL=chunk-5NXUENL3.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/llms/api.ts","../src/llms/generateLLMsTxt.ts","../src/llms/writeLLMsTxt.ts"],"names":["cache","join","existsSync","mkdirSync","writeFileSync"],"mappings":"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","file":"chunk-BFJDUTXK.js","sourcesContent":["/**\n * @sonordev/site-kit/llms - API Functions\n * \n * Data fetching for LLM visibility content.\n * Pulls from Signal knowledge base and project data.\n */\n\nimport { cache } from 'react'\nimport type { LLMsDataResponse, LLMBusinessInfo, LLMContactInfo, LLMService, LLMFAQItem, LLMPageSummary } from './types'\n\n// ============================================\n// API Config\n// ============================================\n\nfunction getApiConfig() {\n // Use site-kit globals if available, otherwise fall back to env vars\n const apiUrl = (typeof window !== 'undefined' && (window as any).__SITE_KIT_API_URL__)\n || process.env.SONOR_API_URL\n || process.env.UPTRADE_API_URL\n || process.env.NEXT_PUBLIC_UPTRADE_API_URL\n || 'https://api.sonor.io'\n\n const apiKey = (typeof window !== 'undefined' && (window as any).__SITE_KIT_API_KEY__)\n || process.env.SONOR_API_KEY\n || process.env.UPTRADE_API_KEY\n || process.env.NEXT_PUBLIC_UPTRADE_API_KEY\n || ''\n \n return { apiUrl, apiKey }\n}\n\nasync function apiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getApiConfig()\n \n if (!apiKey) {\n console.error('@sonordev/llms: No API key configured. Set SONOR_API_KEY.')\n return null\n }\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 3600 }, // Next.js fetch cache\n } as RequestInit)\n \n if (!response.ok) {\n console.error(`@sonordev/llms: API error: ${response.statusText}`)\n return null\n }\n \n return await response.json()\n } catch (error) {\n console.error('@sonordev/llms: Network error:', error)\n return null\n }\n}\n\n// ============================================\n// Cached Data Fetchers\n// ============================================\n\n/**\n * Fetch all LLM visibility data for a project - cached per request\n * This is the main data source for llms.txt generation\n * \n * @param projectId - Optional project ID (API key identifies project if omitted)\n */\nexport const getLLMsData = cache(async (\n projectId?: string\n): Promise<LLMsDataResponse | null> => {\n return apiGet<LLMsDataResponse>(`/api/public/llms/data`)\n})\n\n/**\n * Fetch business info only - cached per request\n */\nexport const getBusinessInfo = cache(async (\n projectId?: string\n): Promise<LLMBusinessInfo | null> => {\n const result = await apiGet<{ business: LLMBusinessInfo }>(`/api/public/llms/business`)\n return result?.business || null\n})\n\n/**\n * Fetch services list - cached per request\n */\nexport const getServices = cache(async (\n projectId?: string\n): Promise<LLMService[]> => {\n const result = await apiGet<{ services: LLMService[] }>(`/api/public/llms/services`)\n return result?.services || []\n})\n\n/**\n * Fetch FAQ items - cached per request\n */\nexport const getFAQItems = cache(async (\n projectId?: string,\n limit?: number\n): Promise<LLMFAQItem[]> => {\n const endpoint = limit \n ? `/api/public/llms/faq?limit=${limit}`\n : '/api/public/llms/faq'\n const result = await apiGet<{ faq: LLMFAQItem[] }>(endpoint)\n return result?.faq || []\n})\n\n/**\n * Fetch page summaries for sitemap - cached per request\n */\nexport const getPageSummaries = cache(async (\n projectId?: string,\n limit?: number\n): Promise<LLMPageSummary[]> => {\n const endpoint = limit \n ? `/api/public/llms/pages?limit=${limit}`\n : '/api/public/llms/pages'\n const result = await apiGet<{ pages: LLMPageSummary[] }>(endpoint)\n return result?.pages || []\n})\n\n/**\n * Fetch AI-optimized llms.txt markdown from Portal API (build-time)\n * Used by writeLLMsTxtToPublic for static file generation\n */\nexport async function getOptimizedLLMsTxt(options?: {\n full?: boolean\n apiUrl?: string\n apiKey?: string\n}): Promise<string | null> {\n const apiUrl = options?.apiUrl\n || (typeof process !== 'undefined' && (process.env?.SONOR_API_URL || process.env?.UPTRADE_API_URL || process.env?.NEXT_PUBLIC_UPTRADE_API_URL))\n || 'https://api.sonor.io'\n const apiKey = options?.apiKey\n || (typeof process !== 'undefined' && (process.env?.SONOR_API_KEY || process.env?.UPTRADE_API_KEY || process.env?.NEXT_PUBLIC_UPTRADE_API_KEY))\n || ''\n\n if (!apiKey) {\n console.error('@sonordev/llms: No API key configured for getOptimizedLLMsTxt')\n return null\n }\n\n const endpoint = options?.full ? '/api/public/llms/txt?full=true' : '/api/public/llms/txt'\n\n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'text/plain',\n 'x-api-key': apiKey,\n },\n })\n\n if (!response.ok) {\n console.error(`@sonordev/llms: Optimized txt API error: ${response.status} ${response.statusText}`)\n return null\n }\n\n return await response.text()\n } catch (error) {\n console.error('@sonordev/llms: Failed to fetch optimized llms.txt:', error)\n return null\n }\n}\n","/**\n * @sonordev/site-kit/llms - llms.txt Generator\n * \n * Generates llms.txt content following the llms.txt specification.\n * https://llmstxt.org/\n * \n * The llms.txt file provides a markdown-formatted overview of a website\n * specifically designed for LLM consumption. It helps AI systems understand\n * what a business does, what services it offers, and how to answer questions.\n */\n\nimport { getLLMsData } from './api'\nimport type {\n GenerateLLMSTxtOptions,\n LLMSTxtContent,\n LLMsDataResponse,\n LLMBusinessInfo,\n LLMContactInfo,\n LLMService,\n LLMFAQItem,\n LLMPageSummary\n} from './types'\nimport type { SEOEntity } from '../seo/types'\n\n/**\n * Merge Portal data with local data. Portal fields take precedence; local fills gaps when Portal is empty.\n */\nfunction mergeLLMsData(\n portal: Partial<LLMsDataResponse> | null,\n local: LLMsDataResponse | null\n): LLMsDataResponse | null {\n if (!local) return portal as LLMsDataResponse | null\n if (!portal) return local\n return {\n business: portal.business ?? local.business,\n contact: portal.contact ?? local.contact,\n services: (portal.services?.length ? portal.services : local.services) ?? [],\n faq: (portal.faq?.length ? portal.faq : local.faq) ?? [],\n pages: (portal.pages?.length ? portal.pages : local.pages) ?? [],\n }\n}\n\n/**\n * Generate llms.txt content from Portal data\n * \n * @example\n * ```ts\n * // app/llms.txt/route.ts\n * import { generateLLMsTxt } from '@sonordev/site-kit/llms'\n * \n * export async function GET() {\n * const { markdown } = await generateLLMsTxt({\n * projectId: process.env.UPTRADE_PROJECT_ID!\n * })\n * \n * return new Response(markdown, {\n * headers: { 'Content-Type': 'text/plain; charset=utf-8' }\n * })\n * }\n * ```\n */\nexport async function generateLLMsTxt(\n options: GenerateLLMSTxtOptions\n): Promise<LLMSTxtContent> {\n const {\n projectId,\n getLocalData,\n includeBusinessInfo = true,\n includeServices = true,\n includeFAQ = true,\n includePages = true,\n includeContact = true,\n includeEntities = true,\n maxFAQItems = 20,\n maxPages = 50,\n maxEntities = 50,\n customSections = [],\n } = options\n\n // Fetch from Portal first\n let data = await getLLMsData(projectId)\n\n // Use local data when Portal returns null or empty services\n const useLocal = getLocalData && (!data || !data.services?.length)\n if (useLocal && getLocalData) {\n try {\n const local = await getLocalData()\n data = mergeLLMsData(data ?? null, local)\n } catch (err) {\n console.warn('[site-kit] getLocalData failed:', err)\n }\n }\n \n if (!data) {\n // Return minimal content if no data\n return {\n markdown: '# Website\\n\\n> Information not available.',\n metadata: {\n generated_at: new Date().toISOString(),\n project_id: projectId || '',\n sections: [],\n }\n }\n }\n\n const sections: string[] = []\n const sectionNames: string[] = []\n\n // ========================================\n // Header Section (H1 + blockquote summary)\n // ========================================\n if (includeBusinessInfo && data.business) {\n const header = generateHeaderSection(data.business)\n sections.push(header)\n sectionNames.push('header')\n }\n\n // ========================================\n // About Section\n // ========================================\n if (includeBusinessInfo && data.business?.description) {\n const about = generateAboutSection(data.business)\n sections.push(about)\n sectionNames.push('about')\n }\n\n // ========================================\n // Services Section\n // ========================================\n if (includeServices && data.services?.length > 0) {\n const services = generateServicesSection(data.services)\n sections.push(services)\n sectionNames.push('services')\n }\n\n // ========================================\n // Contact Section\n // ========================================\n if (includeContact && data.contact) {\n const contact = generateContactSection(data.contact)\n sections.push(contact)\n sectionNames.push('contact')\n }\n\n // ========================================\n // FAQ Section\n // ========================================\n if (includeFAQ && data.faq?.length > 0) {\n const faq = generateFAQSection(data.faq.slice(0, maxFAQItems))\n sections.push(faq)\n sectionNames.push('faq')\n }\n\n // ========================================\n // Pages Section (sitemap-like index)\n // ========================================\n if (includePages && data.pages?.length > 0) {\n const pages = generatePagesSection(data.pages.slice(0, maxPages), data.business?.website || '')\n sections.push(pages)\n sectionNames.push('pages')\n }\n\n // ========================================\n // Knowledge Graph / Entity Section\n // ========================================\n if (includeEntities) {\n try {\n // Dynamic import to avoid pulling server-only code when not needed\n const { getEntities, getPrimaryEntity } = await import('../seo/server-api')\n const [entities, primaryEntity] = await Promise.all([\n getEntities().then(e => e.slice(0, maxEntities)),\n getPrimaryEntity(),\n ])\n if (entities.length > 0 || primaryEntity) {\n const entitySection = generateEntitySection(entities, primaryEntity, false)\n sections.push(entitySection)\n sectionNames.push('knowledge-graph')\n }\n } catch {\n // Entity graph unavailable (e.g., no Signal API) — skip silently\n }\n }\n\n // ========================================\n // Custom Sections\n // ========================================\n for (const custom of customSections) {\n sections.push(`## ${custom.title}\\n\\n${custom.content}`)\n sectionNames.push(custom.title.toLowerCase().replace(/\\s+/g, '-'))\n }\n\n return {\n markdown: sections.join('\\n\\n---\\n\\n'),\n metadata: {\n generated_at: new Date().toISOString(),\n project_id: projectId || '',\n sections: sectionNames,\n }\n }\n}\n\n/**\n * Generate llms-full.txt with comprehensive knowledge dump\n * Use this for AI systems that can handle larger context\n */\nexport async function generateLLMsFullTxt(\n options: GenerateLLMSTxtOptions\n): Promise<LLMSTxtContent> {\n return generateLLMsTxt({\n ...options,\n includeBusinessInfo: true,\n includeServices: true,\n includeFAQ: true,\n includePages: true,\n includeContact: true,\n includeEntities: true,\n maxFAQItems: 100,\n maxPages: 200,\n maxEntities: 200,\n })\n}\n\n// ============================================\n// Section Generators\n// ============================================\n\nfunction generateHeaderSection(business: LLMBusinessInfo): string {\n const lines: string[] = []\n \n // H1 with business name\n lines.push(`# ${business.name}`)\n lines.push('')\n \n // Blockquote summary (per llms.txt spec)\n const summary = business.tagline || business.description.split('.')[0]\n lines.push(`> ${summary}`)\n \n if (business.industry) {\n lines.push('')\n lines.push(`**Industry:** ${business.industry}`)\n }\n \n if (business.service_area) {\n lines.push(`**Service Area:** ${business.service_area}`)\n }\n \n if (business.website) {\n lines.push(`**Website:** ${business.website}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateAboutSection(business: LLMBusinessInfo): string {\n const lines: string[] = []\n \n lines.push('## About')\n lines.push('')\n lines.push(business.description)\n \n if (business.founded) {\n lines.push('')\n lines.push(`Established: ${business.founded}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateServicesSection(services: LLMService[]): string {\n const lines: string[] = []\n \n lines.push('## Services')\n lines.push('')\n \n for (const service of services) {\n if (service.url) {\n lines.push(`- **[${service.name}](${service.url})**: ${service.description}`)\n } else {\n lines.push(`- **${service.name}**: ${service.description}`)\n }\n }\n\n return lines.join('\\n')\n}\n\nfunction generateContactSection(contact: LLMContactInfo): string {\n const lines: string[] = []\n \n lines.push('## Contact Information')\n lines.push('')\n \n if (contact.phone) {\n lines.push(`- **Phone:** ${contact.phone}`)\n }\n if (contact.email) {\n lines.push(`- **Email:** ${contact.email}`)\n }\n if (contact.address || contact.city) {\n const addressParts = [\n contact.address,\n contact.city,\n contact.state,\n contact.postal_code,\n contact.country\n ].filter(Boolean)\n lines.push(`- **Address:** ${addressParts.join(', ')}`)\n }\n if (contact.hours) {\n lines.push(`- **Hours:** ${contact.hours}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateFAQSection(faq: LLMFAQItem[]): string {\n const lines: string[] = []\n \n lines.push('## Frequently Asked Questions')\n lines.push('')\n \n for (const item of faq) {\n lines.push(`### ${item.question}`)\n lines.push('')\n lines.push(item.answer)\n lines.push('')\n }\n\n return lines.join('\\n').trim()\n}\n\nfunction generatePagesSection(pages: LLMPageSummary[], baseUrl: string): string {\n const lines: string[] = []\n \n lines.push('## Site Pages')\n lines.push('')\n \n for (const page of pages) {\n const url = page.path.startsWith('http') ? page.path : `${baseUrl}${page.path}`\n if (page.description) {\n lines.push(`- [${page.title}](${url}): ${page.description}`)\n } else {\n lines.push(`- [${page.title}](${url})`)\n }\n }\n\n return lines.join('\\n')\n}\n\nfunction generateEntitySection(\n entities: SEOEntity[],\n primaryEntity: SEOEntity | null,\n detailed: boolean\n): string {\n const lines: string[] = []\n\n lines.push('## Knowledge Graph')\n lines.push('')\n\n // Primary entity first\n if (primaryEntity) {\n lines.push(`### ${primaryEntity.name} (Primary)`)\n lines.push('')\n lines.push(`- **Type:** ${primaryEntity.entity_type}`)\n if (primaryEntity.schema_type) {\n lines.push(`- **Schema:** ${primaryEntity.schema_type}`)\n }\n if (detailed && primaryEntity.knows_about?.length) {\n lines.push(`- **Knows About:** ${primaryEntity.knows_about.join(', ')}`)\n }\n if (detailed && primaryEntity.same_as?.length) {\n lines.push(`- **Same As:** ${primaryEntity.same_as.join(', ')}`)\n }\n lines.push('')\n }\n\n // Group remaining entities by type\n const grouped = new Map<string, SEOEntity[]>()\n for (const entity of entities) {\n if (primaryEntity && entity.id === primaryEntity.id) continue\n const type = entity.entity_type\n if (!grouped.has(type)) grouped.set(type, [])\n grouped.get(type)!.push(entity)\n }\n\n for (const [type, group] of grouped) {\n const label = type.charAt(0).toUpperCase() + type.slice(1) + 's'\n lines.push(`### ${label}`)\n lines.push('')\n for (const entity of group) {\n if (detailed) {\n lines.push(`- **${entity.name}**`)\n if (entity.knows_about?.length) {\n lines.push(` - Knows About: ${entity.knows_about.join(', ')}`)\n }\n if (entity.same_as?.length) {\n lines.push(` - Same As: ${entity.same_as.join(', ')}`)\n }\n } else {\n lines.push(`- ${entity.name}`)\n }\n }\n lines.push('')\n }\n\n return lines.join('\\n').trim()\n}\n\nexport default generateLLMsTxt\n","/**\n * @sonordev/site-kit/llms - Build-Time Write\n *\n * Fetches AI-optimized llms.txt from Portal API and writes to public/llms.txt\n * at build time. Integrates with sitemap flow when optimizedLLMsTxt is enabled.\n */\n\nimport { writeFileSync, mkdirSync, existsSync } from 'fs'\nimport { join } from 'path'\nimport { getOptimizedLLMsTxt } from './api'\nimport { generateLLMsTxt, generateLLMsFullTxt } from './generateLLMsTxt'\nimport type { LLMsDataResponse } from './types'\n\nexport interface WriteLLMsTxtOptions {\n /** Output directory (default: public, relative to cwd) */\n outputDir?: string\n /** Write llms-full.txt as well */\n full?: boolean\n /** Portal API URL */\n apiUrl?: string\n /** Portal API key */\n apiKey?: string\n /** Fallback to non-optimized when API fails */\n fallbackToLocal?: boolean\n /** When Portal returns empty services/faq/pages, use this to supply local site data */\n getLocalData?: () => Promise<LLMsDataResponse | null>\n}\n\n/**\n * Fetch optimized llms.txt from Portal and write to public/llms.txt\n * Called at build time after sitemap sync (when optimizedLLMsTxt is enabled)\n */\nexport async function writeLLMsTxtToPublic(\n options: WriteLLMsTxtOptions = {}\n): Promise<{ success: boolean; path: string; optimized: boolean }> {\n const {\n outputDir = 'public',\n full = false,\n apiUrl,\n apiKey,\n fallbackToLocal = true,\n getLocalData,\n } = options\n\n const cwd = typeof process !== 'undefined' ? process.cwd() : '.'\n const outPath = join(cwd, outputDir)\n const llmsPath = join(outPath, 'llms.txt')\n const llmsFullPath = join(outPath, 'llms-full.txt')\n\n // Ensure output directory exists\n if (!existsSync(outPath)) {\n mkdirSync(outPath, { recursive: true })\n }\n\n const apiOptions = { apiUrl, apiKey }\n\n // Fetch optimized content\n let markdown = await getOptimizedLLMsTxt({ ...apiOptions, full: false })\n let optimized = !!markdown\n\n if (!markdown && fallbackToLocal) {\n console.warn('[site-kit] Optimized llms.txt unavailable, using local generation')\n const result = await generateLLMsTxt({ getLocalData })\n markdown = result.markdown\n }\n\n if (!markdown) {\n console.error('[site-kit] Failed to generate llms.txt')\n return { success: false, path: llmsPath, optimized: false }\n }\n\n writeFileSync(llmsPath, markdown, 'utf-8')\n console.log(`[site-kit] Wrote llms.txt to ${llmsPath}`)\n\n if (full) {\n let fullMarkdown = await getOptimizedLLMsTxt({ ...apiOptions, full: true })\n if (!fullMarkdown && fallbackToLocal) {\n const result = await generateLLMsFullTxt({ getLocalData })\n fullMarkdown = result.markdown\n }\n if (fullMarkdown) {\n writeFileSync(llmsFullPath, fullMarkdown, 'utf-8')\n console.log(`[site-kit] Wrote llms-full.txt to ${llmsFullPath}`)\n }\n }\n\n return { success: true, path: llmsPath, optimized }\n}\n"]}
1
+ {"version":3,"sources":["../src/llms/api.ts","../src/llms/generateLLMsTxt.ts","../src/llms/writeLLMsTxt.ts"],"names":["cache","join","existsSync","mkdirSync","writeFileSync"],"mappings":"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","file":"chunk-5NXUENL3.js","sourcesContent":["/**\n * @sonordev/site-kit/llms - API Functions\n * \n * Data fetching for LLM visibility content.\n * Pulls from Signal knowledge base and project data.\n */\n\nimport { cache } from 'react'\nimport type { LLMsDataResponse, LLMBusinessInfo, LLMContactInfo, LLMService, LLMFAQItem, LLMPageSummary } from './types'\n\n// ============================================\n// API Config\n// ============================================\n\nfunction getApiConfig() {\n // Use site-kit globals if available, otherwise fall back to env vars\n const apiUrl = (typeof window !== 'undefined' && (window as any).__SITE_KIT_API_URL__)\n || process.env.SONOR_API_URL\n || process.env.UPTRADE_API_URL\n || process.env.NEXT_PUBLIC_UPTRADE_API_URL\n || 'https://api.sonor.io'\n\n const apiKey = (typeof window !== 'undefined' && (window as any).__SITE_KIT_API_KEY__)\n || process.env.SONOR_API_KEY\n || process.env.UPTRADE_API_KEY\n || process.env.NEXT_PUBLIC_UPTRADE_API_KEY\n || ''\n \n return { apiUrl, apiKey }\n}\n\nasync function apiGet<T>(endpoint: string): Promise<T | null> {\n const { apiUrl, apiKey } = getApiConfig()\n \n if (!apiKey) {\n console.error('@sonordev/llms: No API key configured. Set SONOR_API_KEY.')\n return null\n }\n \n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n next: { revalidate: 3600 }, // Next.js fetch cache\n } as RequestInit)\n \n if (!response.ok) {\n console.error(`@sonordev/llms: API error: ${response.statusText}`)\n return null\n }\n \n return await response.json()\n } catch (error) {\n console.error('@sonordev/llms: Network error:', error)\n return null\n }\n}\n\n// ============================================\n// Cached Data Fetchers\n// ============================================\n\n/**\n * Fetch all LLM visibility data for a project - cached per request\n * This is the main data source for llms.txt generation\n * \n * @param projectId - Optional project ID (API key identifies project if omitted)\n */\nexport const getLLMsData = cache(async (\n projectId?: string\n): Promise<LLMsDataResponse | null> => {\n return apiGet<LLMsDataResponse>(`/api/public/llms/data`)\n})\n\n/**\n * Fetch business info only - cached per request\n */\nexport const getBusinessInfo = cache(async (\n projectId?: string\n): Promise<LLMBusinessInfo | null> => {\n const result = await apiGet<{ business: LLMBusinessInfo }>(`/api/public/llms/business`)\n return result?.business || null\n})\n\n/**\n * Fetch services list - cached per request\n */\nexport const getServices = cache(async (\n projectId?: string\n): Promise<LLMService[]> => {\n const result = await apiGet<{ services: LLMService[] }>(`/api/public/llms/services`)\n return result?.services || []\n})\n\n/**\n * Fetch FAQ items - cached per request\n */\nexport const getFAQItems = cache(async (\n projectId?: string,\n limit?: number\n): Promise<LLMFAQItem[]> => {\n const endpoint = limit \n ? `/api/public/llms/faq?limit=${limit}`\n : '/api/public/llms/faq'\n const result = await apiGet<{ faq: LLMFAQItem[] }>(endpoint)\n return result?.faq || []\n})\n\n/**\n * Fetch page summaries for sitemap - cached per request\n */\nexport const getPageSummaries = cache(async (\n projectId?: string,\n limit?: number\n): Promise<LLMPageSummary[]> => {\n const endpoint = limit \n ? `/api/public/llms/pages?limit=${limit}`\n : '/api/public/llms/pages'\n const result = await apiGet<{ pages: LLMPageSummary[] }>(endpoint)\n return result?.pages || []\n})\n\n/**\n * Fetch AI-optimized llms.txt markdown from Portal API (build-time)\n * Used by writeLLMsTxtToPublic for static file generation\n */\nexport async function getOptimizedLLMsTxt(options?: {\n full?: boolean\n apiUrl?: string\n apiKey?: string\n}): Promise<string | null> {\n const apiUrl = options?.apiUrl\n || (typeof process !== 'undefined' && (process.env?.SONOR_API_URL || process.env?.UPTRADE_API_URL || process.env?.NEXT_PUBLIC_UPTRADE_API_URL))\n || 'https://api.sonor.io'\n const apiKey = options?.apiKey\n || (typeof process !== 'undefined' && (process.env?.SONOR_API_KEY || process.env?.UPTRADE_API_KEY || process.env?.NEXT_PUBLIC_UPTRADE_API_KEY))\n || ''\n\n if (!apiKey) {\n console.error('@sonordev/llms: No API key configured for getOptimizedLLMsTxt')\n return null\n }\n\n const endpoint = options?.full ? '/api/public/llms/txt?full=true' : '/api/public/llms/txt'\n\n try {\n const response = await fetch(`${apiUrl}${endpoint}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'text/plain',\n 'x-api-key': apiKey,\n },\n })\n\n if (!response.ok) {\n console.error(`@sonordev/llms: Optimized txt API error: ${response.status} ${response.statusText}`)\n return null\n }\n\n return await response.text()\n } catch (error) {\n console.error('@sonordev/llms: Failed to fetch optimized llms.txt:', error)\n return null\n }\n}\n","/**\n * @sonordev/site-kit/llms - llms.txt Generator\n * \n * Generates llms.txt content following the llms.txt specification.\n * https://llmstxt.org/\n * \n * The llms.txt file provides a markdown-formatted overview of a website\n * specifically designed for LLM consumption. It helps AI systems understand\n * what a business does, what services it offers, and how to answer questions.\n */\n\nimport { getLLMsData } from './api'\nimport type {\n GenerateLLMSTxtOptions,\n LLMSTxtContent,\n LLMsDataResponse,\n LLMBusinessInfo,\n LLMContactInfo,\n LLMService,\n LLMFAQItem,\n LLMPageSummary\n} from './types'\nimport type { SEOEntity } from '../seo/types'\n\n/**\n * Merge Portal data with local data. Portal fields take precedence; local fills gaps when Portal is empty.\n */\nfunction mergeLLMsData(\n portal: Partial<LLMsDataResponse> | null,\n local: LLMsDataResponse | null\n): LLMsDataResponse | null {\n if (!local) return portal as LLMsDataResponse | null\n if (!portal) return local\n return {\n business: portal.business ?? local.business,\n contact: portal.contact ?? local.contact,\n services: (portal.services?.length ? portal.services : local.services) ?? [],\n faq: (portal.faq?.length ? portal.faq : local.faq) ?? [],\n pages: (portal.pages?.length ? portal.pages : local.pages) ?? [],\n }\n}\n\n/**\n * Generate llms.txt content from Portal data\n * \n * @example\n * ```ts\n * // app/llms.txt/route.ts\n * import { generateLLMsTxt } from '@sonordev/site-kit/llms'\n * \n * export async function GET() {\n * const { markdown } = await generateLLMsTxt({\n * projectId: process.env.UPTRADE_PROJECT_ID!\n * })\n * \n * return new Response(markdown, {\n * headers: { 'Content-Type': 'text/plain; charset=utf-8' }\n * })\n * }\n * ```\n */\nexport async function generateLLMsTxt(\n options: GenerateLLMSTxtOptions\n): Promise<LLMSTxtContent> {\n const {\n projectId,\n getLocalData,\n includeBusinessInfo = true,\n includeServices = true,\n includeFAQ = true,\n includePages = true,\n includeContact = true,\n includeEntities = true,\n maxFAQItems = 20,\n maxPages = 50,\n maxEntities = 50,\n customSections = [],\n } = options\n\n // Fetch from Portal first\n let data = await getLLMsData(projectId)\n\n // Use local data when Portal returns null or empty services\n const useLocal = getLocalData && (!data || !data.services?.length)\n if (useLocal && getLocalData) {\n try {\n const local = await getLocalData()\n data = mergeLLMsData(data ?? null, local)\n } catch (err) {\n console.warn('[site-kit] getLocalData failed:', err)\n }\n }\n \n if (!data) {\n // Return minimal content if no data\n return {\n markdown: '# Website\\n\\n> Information not available.',\n metadata: {\n generated_at: new Date().toISOString(),\n project_id: projectId || '',\n sections: [],\n }\n }\n }\n\n const sections: string[] = []\n const sectionNames: string[] = []\n\n // ========================================\n // Header Section (H1 + blockquote summary)\n // ========================================\n if (includeBusinessInfo && data.business) {\n const header = generateHeaderSection(data.business)\n sections.push(header)\n sectionNames.push('header')\n }\n\n // ========================================\n // About Section\n // ========================================\n if (includeBusinessInfo && data.business?.description) {\n const about = generateAboutSection(data.business)\n sections.push(about)\n sectionNames.push('about')\n }\n\n // ========================================\n // Services Section\n // ========================================\n if (includeServices && data.services?.length > 0) {\n const services = generateServicesSection(data.services)\n sections.push(services)\n sectionNames.push('services')\n }\n\n // ========================================\n // Contact Section\n // ========================================\n if (includeContact && data.contact) {\n const contact = generateContactSection(data.contact)\n sections.push(contact)\n sectionNames.push('contact')\n }\n\n // ========================================\n // FAQ Section\n // ========================================\n if (includeFAQ && data.faq?.length > 0) {\n const faq = generateFAQSection(data.faq.slice(0, maxFAQItems))\n sections.push(faq)\n sectionNames.push('faq')\n }\n\n // ========================================\n // Pages Section (sitemap-like index)\n // ========================================\n if (includePages && data.pages?.length > 0) {\n const pages = generatePagesSection(data.pages.slice(0, maxPages), data.business?.website || '')\n sections.push(pages)\n sectionNames.push('pages')\n }\n\n // ========================================\n // Knowledge Graph / Entity Section\n // ========================================\n if (includeEntities) {\n try {\n // Dynamic import to avoid pulling server-only code when not needed\n const { getEntities, getPrimaryEntity } = await import('../seo/server-api')\n const [entities, primaryEntity] = await Promise.all([\n getEntities().then(e => e.slice(0, maxEntities)),\n getPrimaryEntity(),\n ])\n if (entities.length > 0 || primaryEntity) {\n const entitySection = generateEntitySection(entities, primaryEntity, false)\n sections.push(entitySection)\n sectionNames.push('knowledge-graph')\n }\n } catch {\n // Entity graph unavailable (e.g., no Signal API) — skip silently\n }\n }\n\n // ========================================\n // Custom Sections\n // ========================================\n for (const custom of customSections) {\n sections.push(`## ${custom.title}\\n\\n${custom.content}`)\n sectionNames.push(custom.title.toLowerCase().replace(/\\s+/g, '-'))\n }\n\n return {\n markdown: sections.join('\\n\\n---\\n\\n'),\n metadata: {\n generated_at: new Date().toISOString(),\n project_id: projectId || '',\n sections: sectionNames,\n }\n }\n}\n\n/**\n * Generate llms-full.txt with comprehensive knowledge dump\n * Use this for AI systems that can handle larger context\n */\nexport async function generateLLMsFullTxt(\n options: GenerateLLMSTxtOptions\n): Promise<LLMSTxtContent> {\n return generateLLMsTxt({\n ...options,\n includeBusinessInfo: true,\n includeServices: true,\n includeFAQ: true,\n includePages: true,\n includeContact: true,\n includeEntities: true,\n maxFAQItems: 100,\n maxPages: 200,\n maxEntities: 200,\n })\n}\n\n// ============================================\n// Section Generators\n// ============================================\n\nfunction generateHeaderSection(business: LLMBusinessInfo): string {\n const lines: string[] = []\n \n // H1 with business name\n lines.push(`# ${business.name}`)\n lines.push('')\n \n // Blockquote summary (per llms.txt spec)\n const summary = business.tagline || business.description.split('.')[0]\n lines.push(`> ${summary}`)\n \n if (business.industry) {\n lines.push('')\n lines.push(`**Industry:** ${business.industry}`)\n }\n \n if (business.service_area) {\n lines.push(`**Service Area:** ${business.service_area}`)\n }\n \n if (business.website) {\n lines.push(`**Website:** ${business.website}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateAboutSection(business: LLMBusinessInfo): string {\n const lines: string[] = []\n \n lines.push('## About')\n lines.push('')\n lines.push(business.description)\n \n if (business.founded) {\n lines.push('')\n lines.push(`Established: ${business.founded}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateServicesSection(services: LLMService[]): string {\n const lines: string[] = []\n \n lines.push('## Services')\n lines.push('')\n \n for (const service of services) {\n if (service.url) {\n lines.push(`- **[${service.name}](${service.url})**: ${service.description}`)\n } else {\n lines.push(`- **${service.name}**: ${service.description}`)\n }\n }\n\n return lines.join('\\n')\n}\n\nfunction generateContactSection(contact: LLMContactInfo): string {\n const lines: string[] = []\n \n lines.push('## Contact Information')\n lines.push('')\n \n if (contact.phone) {\n lines.push(`- **Phone:** ${contact.phone}`)\n }\n if (contact.email) {\n lines.push(`- **Email:** ${contact.email}`)\n }\n if (contact.address || contact.city) {\n const addressParts = [\n contact.address,\n contact.city,\n contact.state,\n contact.postal_code,\n contact.country\n ].filter(Boolean)\n lines.push(`- **Address:** ${addressParts.join(', ')}`)\n }\n if (contact.hours) {\n lines.push(`- **Hours:** ${contact.hours}`)\n }\n\n return lines.join('\\n')\n}\n\nfunction generateFAQSection(faq: LLMFAQItem[]): string {\n const lines: string[] = []\n \n lines.push('## Frequently Asked Questions')\n lines.push('')\n \n for (const item of faq) {\n lines.push(`### ${item.question}`)\n lines.push('')\n lines.push(item.answer)\n lines.push('')\n }\n\n return lines.join('\\n').trim()\n}\n\nfunction generatePagesSection(pages: LLMPageSummary[], baseUrl: string): string {\n const lines: string[] = []\n \n lines.push('## Site Pages')\n lines.push('')\n \n for (const page of pages) {\n const url = page.path.startsWith('http') ? page.path : `${baseUrl}${page.path}`\n if (page.description) {\n lines.push(`- [${page.title}](${url}): ${page.description}`)\n } else {\n lines.push(`- [${page.title}](${url})`)\n }\n }\n\n return lines.join('\\n')\n}\n\nfunction generateEntitySection(\n entities: SEOEntity[],\n primaryEntity: SEOEntity | null,\n detailed: boolean\n): string {\n const lines: string[] = []\n\n lines.push('## Knowledge Graph')\n lines.push('')\n\n // Primary entity first\n if (primaryEntity) {\n lines.push(`### ${primaryEntity.name} (Primary)`)\n lines.push('')\n lines.push(`- **Type:** ${primaryEntity.entity_type}`)\n if (primaryEntity.schema_type) {\n lines.push(`- **Schema:** ${primaryEntity.schema_type}`)\n }\n if (detailed && primaryEntity.knows_about?.length) {\n lines.push(`- **Knows About:** ${primaryEntity.knows_about.join(', ')}`)\n }\n if (detailed && primaryEntity.same_as?.length) {\n lines.push(`- **Same As:** ${primaryEntity.same_as.join(', ')}`)\n }\n lines.push('')\n }\n\n // Group remaining entities by type\n const grouped = new Map<string, SEOEntity[]>()\n for (const entity of entities) {\n if (primaryEntity && entity.id === primaryEntity.id) continue\n const type = entity.entity_type\n if (!grouped.has(type)) grouped.set(type, [])\n grouped.get(type)!.push(entity)\n }\n\n for (const [type, group] of grouped) {\n const label = type.charAt(0).toUpperCase() + type.slice(1) + 's'\n lines.push(`### ${label}`)\n lines.push('')\n for (const entity of group) {\n if (detailed) {\n lines.push(`- **${entity.name}**`)\n if (entity.knows_about?.length) {\n lines.push(` - Knows About: ${entity.knows_about.join(', ')}`)\n }\n if (entity.same_as?.length) {\n lines.push(` - Same As: ${entity.same_as.join(', ')}`)\n }\n } else {\n lines.push(`- ${entity.name}`)\n }\n }\n lines.push('')\n }\n\n return lines.join('\\n').trim()\n}\n\nexport default generateLLMsTxt\n","/**\n * @sonordev/site-kit/llms - Build-Time Write\n *\n * Fetches AI-optimized llms.txt from Portal API and writes to public/llms.txt\n * at build time. Integrates with sitemap flow when optimizedLLMsTxt is enabled.\n */\n\nimport { writeFileSync, mkdirSync, existsSync } from 'fs'\nimport { join } from 'path'\nimport { getOptimizedLLMsTxt } from './api'\nimport { generateLLMsTxt, generateLLMsFullTxt } from './generateLLMsTxt'\nimport type { LLMsDataResponse } from './types'\n\nexport interface WriteLLMsTxtOptions {\n /** Output directory (default: public, relative to cwd) */\n outputDir?: string\n /** Write llms-full.txt as well */\n full?: boolean\n /** Portal API URL */\n apiUrl?: string\n /** Portal API key */\n apiKey?: string\n /** Fallback to non-optimized when API fails */\n fallbackToLocal?: boolean\n /** When Portal returns empty services/faq/pages, use this to supply local site data */\n getLocalData?: () => Promise<LLMsDataResponse | null>\n}\n\n/**\n * Fetch optimized llms.txt from Portal and write to public/llms.txt\n * Called at build time after sitemap sync (when optimizedLLMsTxt is enabled)\n */\nexport async function writeLLMsTxtToPublic(\n options: WriteLLMsTxtOptions = {}\n): Promise<{ success: boolean; path: string; optimized: boolean }> {\n const {\n outputDir = 'public',\n full = false,\n apiUrl,\n apiKey,\n fallbackToLocal = true,\n getLocalData,\n } = options\n\n const cwd = typeof process !== 'undefined' ? process.cwd() : '.'\n const outPath = join(cwd, outputDir)\n const llmsPath = join(outPath, 'llms.txt')\n const llmsFullPath = join(outPath, 'llms-full.txt')\n\n // Ensure output directory exists\n if (!existsSync(outPath)) {\n mkdirSync(outPath, { recursive: true })\n }\n\n const apiOptions = { apiUrl, apiKey }\n\n // Fetch optimized content\n let markdown = await getOptimizedLLMsTxt({ ...apiOptions, full: false })\n let optimized = !!markdown\n\n if (!markdown && fallbackToLocal) {\n console.warn('[site-kit] Optimized llms.txt unavailable, using local generation')\n const result = await generateLLMsTxt({ getLocalData })\n markdown = result.markdown\n }\n\n if (!markdown) {\n console.error('[site-kit] Failed to generate llms.txt')\n return { success: false, path: llmsPath, optimized: false }\n }\n\n writeFileSync(llmsPath, markdown, 'utf-8')\n console.log(`[site-kit] Wrote llms.txt to ${llmsPath}`)\n\n if (full) {\n let fullMarkdown = await getOptimizedLLMsTxt({ ...apiOptions, full: true })\n if (!fullMarkdown && fallbackToLocal) {\n const result = await generateLLMsFullTxt({ getLocalData })\n fullMarkdown = result.markdown\n }\n if (fullMarkdown) {\n writeFileSync(llmsFullPath, fullMarkdown, 'utf-8')\n console.log(`[site-kit] Wrote llms-full.txt to ${llmsFullPath}`)\n }\n }\n\n return { success: true, path: llmsPath, optimized }\n}\n"]}
@@ -152,5 +152,5 @@ function SiteKitClientProviders({
152
152
  }
153
153
 
154
154
  export { SiteKitClientProviders };
155
- //# sourceMappingURL=chunk-6TFGPXXK.mjs.map
156
- //# sourceMappingURL=chunk-6TFGPXXK.mjs.map
155
+ //# sourceMappingURL=chunk-5TTTX6NN.mjs.map
156
+ //# sourceMappingURL=chunk-5TTTX6NN.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shared/identity.tsx","../src/layout/SiteKitClientProviders.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-6TFGPXXK.mjs","sourcesContent":["/**\n * @sonordev/site-kit/shared — Unified Identity Management\n *\n * Single source of truth for visitor and session IDs across\n * Analytics, Signal, and Engage modules.\n *\n * Storage keys:\n * localStorage: _uptrade_vid (visitor ID, persists ~forever)\n * sessionStorage: _uptrade_sid (session ID, per-tab)\n * sessionStorage: _uptrade_stime (last activity timestamp for timeout)\n */\n\n'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\n\n// ============================================\n// ID Generation\n// ============================================\n\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)\n })\n}\n\n/**\n * Get or create a persistent visitor ID.\n * Stored in localStorage under `_uptrade_vid`.\n */\nexport function getOrCreateVisitorId(): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_vid'\n let visitorId = localStorage.getItem(key)\n\n if (!visitorId) {\n visitorId = generateId()\n localStorage.setItem(key, visitorId)\n }\n\n return visitorId\n}\n\n/**\n * Get or create a session ID with inactivity timeout.\n * Stored in sessionStorage under `_uptrade_sid`.\n * Session expires after `timeoutMinutes` of inactivity (default 30).\n */\nexport function getOrCreateSessionId(timeoutMinutes = 30): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_sid'\n const timeKey = '_uptrade_stime'\n const now = Date.now()\n const timeoutMs = timeoutMinutes * 60 * 1000\n\n const existingSession = sessionStorage.getItem(key)\n const lastActivity = sessionStorage.getItem(timeKey)\n\n if (existingSession && lastActivity) {\n const elapsed = now - parseInt(lastActivity, 10)\n if (elapsed < timeoutMs) {\n // Session still active — refresh timestamp\n sessionStorage.setItem(timeKey, now.toString())\n return existingSession\n }\n }\n\n // New session (first visit or timeout expired)\n const newSession = generateId()\n sessionStorage.setItem(key, newSession)\n sessionStorage.setItem(timeKey, now.toString())\n return newSession\n}\n\n// ============================================\n// React Context\n// ============================================\n\nexport interface SiteKitIdentity {\n visitorId: string\n sessionId: string\n}\n\nconst SiteKitIdentityContext = createContext<SiteKitIdentity | null>(null)\n\nexport interface SiteKitIdentityProviderProps {\n visitorId: string\n sessionId: string\n children: React.ReactNode\n}\n\nexport function SiteKitIdentityProvider({\n visitorId,\n sessionId,\n children,\n}: SiteKitIdentityProviderProps) {\n const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId])\n\n return (\n <SiteKitIdentityContext.Provider value={value}>\n {children}\n </SiteKitIdentityContext.Provider>\n )\n}\n\n/**\n * Access the shared visitor/session identity.\n * Falls back to generating IDs directly if used outside of SiteKitIdentityProvider.\n */\nexport function useSiteKitIdentity(): SiteKitIdentity {\n const context = useContext(SiteKitIdentityContext)\n if (context) return context\n\n // Fallback for standalone usage outside SiteKitLayout\n return {\n visitorId: getOrCreateVisitorId(),\n sessionId: getOrCreateSessionId(),\n }\n}\n","'use client'\n\n/**\n * SiteKitClientProviders — Client Island\n *\n * This is the 'use client' boundary for SiteKitLayout.\n * It composes the client-only providers (Analytics, Engage, Signal, SitemapSync)\n * that require React context or browser APIs.\n *\n * All modules are lazy-loaded via next/dynamic so their JS is only downloaded\n * when the feature is enabled — keeping the initial bundle lightweight.\n *\n * All modules share a unified identity (visitor ID + session ID) via\n * SiteKitIdentityProvider, ensuring consistent tracking across Analytics,\n * Signal, and Engage.\n *\n * Props are passed down from the server-side SiteKitLayout component,\n * which reads env vars at render time.\n */\n\nimport React, { Suspense, useCallback, useRef, useState, type ReactNode } from 'react'\nimport dynamic from 'next/dynamic'\nimport {\n SiteKitIdentityProvider,\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\n// Lazy-load feature modules — JS only downloaded when feature is enabled\nconst LazyAnalyticsProvider = dynamic(\n () => import('../analytics/AnalyticsProvider').then(m => ({ default: m.AnalyticsProvider })),\n { ssr: false },\n)\nconst LazyEngageWidget = dynamic(\n () => import('../engage/EngageWidget').then(m => ({ default: m.EngageWidget })),\n { ssr: false },\n)\nconst LazySignalBridge = dynamic(\n () => import('../signal/SignalBridge').then(m => ({ default: m.SignalBridge })),\n { ssr: false },\n)\nconst LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n\nexport interface SiteKitClientProvidersProps {\n children: ReactNode\n apiKey: string\n apiUrl: string\n projectId?: string\n analytics?: boolean | AnalyticsConfig\n engage?: boolean | EngageConfig\n signal?: boolean | SignalConfig\n sitemapSync?: boolean\n debug?: boolean\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // Set window globals for modules that still read from them\n if (typeof window !== 'undefined') {\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = apiKey\n ;(window as any).__SITE_KIT_DEBUG__ = debug\n }\n\n // Unified identity — single source of truth for all modules\n const [visitorId] = useState(() => getOrCreateVisitorId())\n const [sessionId] = useState(() => getOrCreateSessionId())\n\n // Page metadata bridge: Analytics writes, Signal reads\n const pageMetadataRef = useRef<Record<string, unknown> | null>(null)\n const onPageMetadata = useCallback((metadata: Record<string, unknown>) => {\n pageMetadataRef.current = metadata\n }, [])\n\n let content = <>{children}</>\n\n // Wrap with SignalBridge if enabled\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <LazySignalBridge\n enabled\n realtime={signalConfig.realtime !== false}\n experiments={signalConfig.experiments !== false}\n behaviorTracking={signalConfig.behaviorTracking !== false}\n visitorId={visitorId}\n sessionId={sessionId}\n pageMetadataRef={pageMetadataRef}\n >\n {content}\n </LazySignalBridge>\n )\n }\n\n // Wrap with Analytics if enabled\n if (analytics) {\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n content = (\n <Suspense fallback={null}>\n <LazyAnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n >\n {content}\n </LazyAnalyticsProvider>\n </Suspense>\n )\n }\n\n // Add Engage widget if enabled (renders alongside, doesn't wrap)\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n content = (\n <>\n {content}\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n <LazySitemapSync debug={debug} />\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/shared/identity.tsx","../src/layout/SiteKitClientProviders.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-5TTTX6NN.mjs","sourcesContent":["/**\n * @sonordev/site-kit/shared — Unified Identity Management\n *\n * Single source of truth for visitor and session IDs across\n * Analytics, Signal, and Engage modules.\n *\n * Storage keys:\n * localStorage: _uptrade_vid (visitor ID, persists ~forever)\n * sessionStorage: _uptrade_sid (session ID, per-tab)\n * sessionStorage: _uptrade_stime (last activity timestamp for timeout)\n */\n\n'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\n\n// ============================================\n// ID Generation\n// ============================================\n\nfunction generateId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID()\n }\n // Fallback for older environments\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)\n })\n}\n\n/**\n * Get or create a persistent visitor ID.\n * Stored in localStorage under `_uptrade_vid`.\n */\nexport function getOrCreateVisitorId(): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_vid'\n let visitorId = localStorage.getItem(key)\n\n if (!visitorId) {\n visitorId = generateId()\n localStorage.setItem(key, visitorId)\n }\n\n return visitorId\n}\n\n/**\n * Get or create a session ID with inactivity timeout.\n * Stored in sessionStorage under `_uptrade_sid`.\n * Session expires after `timeoutMinutes` of inactivity (default 30).\n */\nexport function getOrCreateSessionId(timeoutMinutes = 30): string {\n if (typeof window === 'undefined') return ''\n\n const key = '_uptrade_sid'\n const timeKey = '_uptrade_stime'\n const now = Date.now()\n const timeoutMs = timeoutMinutes * 60 * 1000\n\n const existingSession = sessionStorage.getItem(key)\n const lastActivity = sessionStorage.getItem(timeKey)\n\n if (existingSession && lastActivity) {\n const elapsed = now - parseInt(lastActivity, 10)\n if (elapsed < timeoutMs) {\n // Session still active — refresh timestamp\n sessionStorage.setItem(timeKey, now.toString())\n return existingSession\n }\n }\n\n // New session (first visit or timeout expired)\n const newSession = generateId()\n sessionStorage.setItem(key, newSession)\n sessionStorage.setItem(timeKey, now.toString())\n return newSession\n}\n\n// ============================================\n// React Context\n// ============================================\n\nexport interface SiteKitIdentity {\n visitorId: string\n sessionId: string\n}\n\nconst SiteKitIdentityContext = createContext<SiteKitIdentity | null>(null)\n\nexport interface SiteKitIdentityProviderProps {\n visitorId: string\n sessionId: string\n children: React.ReactNode\n}\n\nexport function SiteKitIdentityProvider({\n visitorId,\n sessionId,\n children,\n}: SiteKitIdentityProviderProps) {\n const value = useMemo(() => ({ visitorId, sessionId }), [visitorId, sessionId])\n\n return (\n <SiteKitIdentityContext.Provider value={value}>\n {children}\n </SiteKitIdentityContext.Provider>\n )\n}\n\n/**\n * Access the shared visitor/session identity.\n * Falls back to generating IDs directly if used outside of SiteKitIdentityProvider.\n */\nexport function useSiteKitIdentity(): SiteKitIdentity {\n const context = useContext(SiteKitIdentityContext)\n if (context) return context\n\n // Fallback for standalone usage outside SiteKitLayout\n return {\n visitorId: getOrCreateVisitorId(),\n sessionId: getOrCreateSessionId(),\n }\n}\n","'use client'\n\n/**\n * SiteKitClientProviders — Client Island\n *\n * This is the 'use client' boundary for SiteKitLayout.\n * It composes the client-only providers (Analytics, Engage, Signal, SitemapSync)\n * that require React context or browser APIs.\n *\n * All modules are lazy-loaded via next/dynamic so their JS is only downloaded\n * when the feature is enabled — keeping the initial bundle lightweight.\n *\n * All modules share a unified identity (visitor ID + session ID) via\n * SiteKitIdentityProvider, ensuring consistent tracking across Analytics,\n * Signal, and Engage.\n *\n * Props are passed down from the server-side SiteKitLayout component,\n * which reads env vars at render time.\n */\n\nimport React, { Suspense, useCallback, useRef, useState, type ReactNode } from 'react'\nimport dynamic from 'next/dynamic'\nimport {\n SiteKitIdentityProvider,\n getOrCreateVisitorId,\n getOrCreateSessionId,\n} from '../shared/identity'\nimport type { AnalyticsConfig, EngageConfig, SignalConfig } from './types'\n\n// Lazy-load feature modules — JS only downloaded when feature is enabled\nconst LazyAnalyticsProvider = dynamic(\n () => import('../analytics/AnalyticsProvider').then(m => ({ default: m.AnalyticsProvider })),\n { ssr: false },\n)\nconst LazyEngageWidget = dynamic(\n () => import('../engage/EngageWidget').then(m => ({ default: m.EngageWidget })),\n { ssr: false },\n)\nconst LazySignalBridge = dynamic(\n () => import('../signal/SignalBridge').then(m => ({ default: m.SignalBridge })),\n { ssr: false },\n)\nconst LazySitemapSync = dynamic(\n () => import('../SitemapSync').then(m => ({ default: m.SitemapSync })),\n { ssr: false },\n)\n\nexport interface SiteKitClientProvidersProps {\n children: ReactNode\n apiKey: string\n apiUrl: string\n projectId?: string\n analytics?: boolean | AnalyticsConfig\n engage?: boolean | EngageConfig\n signal?: boolean | SignalConfig\n sitemapSync?: boolean\n debug?: boolean\n}\n\nexport function SiteKitClientProviders({\n children,\n apiKey,\n apiUrl,\n projectId,\n analytics = true,\n engage = true,\n signal = false,\n sitemapSync = true,\n debug = false,\n}: SiteKitClientProvidersProps) {\n // Set window globals for modules that still read from them\n if (typeof window !== 'undefined') {\n ;(window as any).__SITE_KIT_API_URL__ = apiUrl\n ;(window as any).__SITE_KIT_API_KEY__ = apiKey\n ;(window as any).__SITE_KIT_DEBUG__ = debug\n }\n\n // Unified identity — single source of truth for all modules\n const [visitorId] = useState(() => getOrCreateVisitorId())\n const [sessionId] = useState(() => getOrCreateSessionId())\n\n // Page metadata bridge: Analytics writes, Signal reads\n const pageMetadataRef = useRef<Record<string, unknown> | null>(null)\n const onPageMetadata = useCallback((metadata: Record<string, unknown>) => {\n pageMetadataRef.current = metadata\n }, [])\n\n let content = <>{children}</>\n\n // Wrap with SignalBridge if enabled\n if (signal) {\n const signalConfig: SignalConfig =\n typeof signal === 'object' ? signal : {}\n content = (\n <LazySignalBridge\n enabled\n realtime={signalConfig.realtime !== false}\n experiments={signalConfig.experiments !== false}\n behaviorTracking={signalConfig.behaviorTracking !== false}\n visitorId={visitorId}\n sessionId={sessionId}\n pageMetadataRef={pageMetadataRef}\n >\n {content}\n </LazySignalBridge>\n )\n }\n\n // Wrap with Analytics if enabled\n if (analytics) {\n const analyticsConfig: AnalyticsConfig =\n typeof analytics === 'object' ? analytics : {}\n content = (\n <Suspense fallback={null}>\n <LazyAnalyticsProvider\n apiUrl={apiUrl}\n apiKey={apiKey}\n trackPageViews={analyticsConfig.trackPageViews !== false}\n trackWebVitals={analyticsConfig.trackWebVitals !== false}\n trackScrollDepth={analyticsConfig.trackScrollDepth !== false}\n trackClicks={analyticsConfig.trackClicks !== false}\n debug={debug}\n externalVisitorId={visitorId}\n externalSessionId={sessionId}\n onPageMetadata={onPageMetadata}\n >\n {content}\n </LazyAnalyticsProvider>\n </Suspense>\n )\n }\n\n // Add Engage widget if enabled (renders alongside, doesn't wrap)\n if (engage) {\n const engageConfig: EngageConfig =\n typeof engage === 'object' ? engage : {}\n content = (\n <>\n {content}\n <LazyEngageWidget\n apiUrl={apiUrl}\n apiKey={apiKey}\n projectId={projectId}\n position={engageConfig.position || 'bottom-right'}\n chatEnabled={engageConfig.chatEnabled !== false}\n />\n </>\n )\n }\n\n // Add SitemapSync if enabled\n if (sitemapSync) {\n content = (\n <>\n {content}\n <LazySitemapSync debug={debug} />\n </>\n )\n }\n\n return (\n <SiteKitIdentityProvider visitorId={visitorId} sessionId={sessionId}>\n {content}\n </SiteKitIdentityProvider>\n )\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { getManagedScripts } from './chunk-SQSBAPWA.mjs';
1
+ import { getManagedScripts } from './chunk-3QKTOTWS.mjs';
2
2
  import { Suspense } from 'react';
3
3
  import { jsx, Fragment } from 'react/jsx-runtime';
4
4
 
@@ -50,5 +50,5 @@ function ManagedNoScripts(props) {
50
50
  }
51
51
 
52
52
  export { ManagedNoScripts, ManagedScripts };
53
- //# sourceMappingURL=chunk-44GSXYHJ.mjs.map
54
- //# sourceMappingURL=chunk-44GSXYHJ.mjs.map
53
+ //# sourceMappingURL=chunk-J4K335PQ.mjs.map
54
+ //# sourceMappingURL=chunk-J4K335PQ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/seo/ManagedScripts.tsx"],"names":[],"mappings":";;;;AAwCA,eAAe,mBAAA,CAAoB;AAAA,EACjC,QAAA;AAAA,EACA;AACF,CAAA,EAA4D;AAC1D,EAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,QAAA,EAAU,IAAI,CAAA;AAEtD,EAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,uBACE,GAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAA0B;AACtC,IAAA,IAAI,MAAA,CAAO,gBAAgB,UAAA,EAAY;AAGrC,MAAA,MAAM,KAAA,GAAiC;AAAA,QACrC,KAAK,MAAA,CAAO,EAAA;AAAA,QACZ,KAAK,MAAA,CAAO,GAAA;AAAA,QACZ,KAAA,EAAO,IAAA;AAAA,QACP,GAAI,MAAA,CAAO,KAAA,IAAS,EAAE,OAAO,IAAA,EAAK;AAAA,QAClC,GAAG,MAAA,CAAO;AAAA,OACZ;AAEA,MAAA,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAQ,GAAG,KAAA,EAAO,CAAA;AAAA,IAC5B;AAGA,IAAA,uBACE,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QAEC,KAAA,EAAK,IAAA;AAAA,QACL,uBAAA,EAAyB,EAAE,MAAA,EAAQ,MAAA,CAAO,WAAW,EAAA,EAAG;AAAA,QACvD,GAAG,MAAA,CAAO;AAAA,OAAA;AAAA,MAHN,MAAA,CAAO;AAAA,KAId;AAAA,EAEJ,CAAC,CAAA,EACH,CAAA;AAEJ;AAOA,eAAe,qBAAA,CAAsB;AAAA,EACnC;AACF,CAAA,EAGuC;AACrC,EAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,YAAA,EAAc,IAAI,CAAA;AAG1D,EAAA,MAAM,kBAAkB,OAAA,CACrB,MAAA,CAAO,CAAC,CAAA,KAAqB,EAAE,UAAA,EAAY,QAAQ,CAAA,CACnD,GAAA,CAAI,CAAC,CAAA,KAAqB,CAAA,CAAE,YAAY,QAAQ,CAAA,CAChD,KAAK,EAAE,CAAA;AAEV,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,2BACG,UAAA,EAAA,EAAS,uBAAA,EAAyB,EAAE,MAAA,EAAQ,iBAAgB,EAAG,CAAA;AAEpE;AAEO,SAAS,eAAe,KAAA,EAAgD;AAC7E,EAAA,uBACE,GAAA,CAAC,YAAS,QAAA,EAAU,IAAA,EAClB,8BAAC,mBAAA,EAAA,EAAqB,GAAG,OAAO,CAAA,EAClC,CAAA;AAEJ;AAEO,SAAS,iBAAiB,KAAA,EAAkE;AACjG,EAAA,uBACE,GAAA,CAAC,YAAS,QAAA,EAAU,IAAA,EAClB,8BAAC,qBAAA,EAAA,EAAuB,GAAG,OAAO,CAAA,EACpC,CAAA;AAEJ","file":"chunk-44GSXYHJ.mjs","sourcesContent":["import * as React from 'react'\nimport { Suspense } from 'react'\nimport { getManagedScripts } from './server-api'\nimport type { ManagedScriptsProps, ManagedScript } from './types'\n\n/**\n * ManagedScripts - Server Component for injecting tracking/analytics scripts\n * \n * Fetches scripts from Portal and renders them in the appropriate position\n * \n * @example\n * ```tsx\n * // app/layout.tsx\n * import { ManagedScripts } from '@sonordev/seo'\n * \n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <head>\n * <ManagedScripts \n * projectId={process.env.UPTRADE_PROJECT_ID!}\n * position=\"head\"\n * />\n * </head>\n * <body>\n * <ManagedScripts \n * projectId={process.env.UPTRADE_PROJECT_ID!}\n * position=\"body-start\"\n * />\n * {children}\n * <ManagedScripts \n * projectId={process.env.UPTRADE_PROJECT_ID!}\n * position=\"body-end\"\n * />\n * </body>\n * </html>\n * )\n * }\n * ```\n */\nasync function ManagedScriptsAsync({\n position,\n path,\n}: ManagedScriptsProps): Promise<React.ReactElement | null> {\n const scripts = await getManagedScripts(position, path)\n\n if (!scripts.length) {\n return null\n }\n\n return (\n <>\n {scripts.map((script: ManagedScript) => {\n if (script.script_type === 'external') {\n // External script with src. Always include async so React 19 allows\n // rendering outside the main document (body-start/body-end).\n const attrs: Record<string, unknown> = {\n key: script.id,\n src: script.src,\n async: true,\n ...(script.defer && { defer: true }),\n ...script.attributes,\n }\n\n return <script {...attrs} />\n }\n\n // Inline script — add async so React 19 doesn't treat it as sync outside document\n return (\n <script\n key={script.id}\n async\n dangerouslySetInnerHTML={{ __html: script.content || '' }}\n {...script.attributes}\n />\n )\n })}\n </>\n )\n}\n\n/**\n * NoScript fallback component\n * \n * Use for adding noscript content (like Google Tag Manager noscript)\n */\nasync function ManagedNoScriptsAsync({\n path,\n}: {\n projectId?: string\n path?: string\n}): Promise<React.ReactElement | null> {\n const scripts = await getManagedScripts('body-start', path)\n\n // Filter scripts that have noscript content\n const noscriptContent = scripts\n .filter((s: ManagedScript) => s.attributes?.noscript)\n .map((s: ManagedScript) => s.attributes?.noscript)\n .join('')\n\n if (!noscriptContent) {\n return null\n }\n\n return (\n <noscript dangerouslySetInnerHTML={{ __html: noscriptContent }} />\n )\n}\n\nexport function ManagedScripts(props: ManagedScriptsProps): React.ReactElement {\n return (\n <Suspense fallback={null}>\n <ManagedScriptsAsync {...props} />\n </Suspense>\n )\n}\n\nexport function ManagedNoScripts(props: { projectId?: string; path?: string }): React.ReactElement {\n return (\n <Suspense fallback={null}>\n <ManagedNoScriptsAsync {...props} />\n </Suspense>\n )\n}\n\nexport default ManagedScripts\n"]}
1
+ {"version":3,"sources":["../src/seo/ManagedScripts.tsx"],"names":[],"mappings":";;;;AAwCA,eAAe,mBAAA,CAAoB;AAAA,EACjC,QAAA;AAAA,EACA;AACF,CAAA,EAA4D;AAC1D,EAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,QAAA,EAAU,IAAI,CAAA;AAEtD,EAAA,IAAI,CAAC,QAAQ,MAAA,EAAQ;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,uBACE,GAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAA0B;AACtC,IAAA,IAAI,MAAA,CAAO,gBAAgB,UAAA,EAAY;AAGrC,MAAA,MAAM,KAAA,GAAiC;AAAA,QACrC,KAAK,MAAA,CAAO,EAAA;AAAA,QACZ,KAAK,MAAA,CAAO,GAAA;AAAA,QACZ,KAAA,EAAO,IAAA;AAAA,QACP,GAAI,MAAA,CAAO,KAAA,IAAS,EAAE,OAAO,IAAA,EAAK;AAAA,QAClC,GAAG,MAAA,CAAO;AAAA,OACZ;AAEA,MAAA,uBAAO,GAAA,CAAC,QAAA,EAAA,EAAQ,GAAG,KAAA,EAAO,CAAA;AAAA,IAC5B;AAGA,IAAA,uBACE,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QAEC,KAAA,EAAK,IAAA;AAAA,QACL,uBAAA,EAAyB,EAAE,MAAA,EAAQ,MAAA,CAAO,WAAW,EAAA,EAAG;AAAA,QACvD,GAAG,MAAA,CAAO;AAAA,OAAA;AAAA,MAHN,MAAA,CAAO;AAAA,KAId;AAAA,EAEJ,CAAC,CAAA,EACH,CAAA;AAEJ;AAOA,eAAe,qBAAA,CAAsB;AAAA,EACnC;AACF,CAAA,EAGuC;AACrC,EAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,YAAA,EAAc,IAAI,CAAA;AAG1D,EAAA,MAAM,kBAAkB,OAAA,CACrB,MAAA,CAAO,CAAC,CAAA,KAAqB,EAAE,UAAA,EAAY,QAAQ,CAAA,CACnD,GAAA,CAAI,CAAC,CAAA,KAAqB,CAAA,CAAE,YAAY,QAAQ,CAAA,CAChD,KAAK,EAAE,CAAA;AAEV,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,2BACG,UAAA,EAAA,EAAS,uBAAA,EAAyB,EAAE,MAAA,EAAQ,iBAAgB,EAAG,CAAA;AAEpE;AAEO,SAAS,eAAe,KAAA,EAAgD;AAC7E,EAAA,uBACE,GAAA,CAAC,YAAS,QAAA,EAAU,IAAA,EAClB,8BAAC,mBAAA,EAAA,EAAqB,GAAG,OAAO,CAAA,EAClC,CAAA;AAEJ;AAEO,SAAS,iBAAiB,KAAA,EAAkE;AACjG,EAAA,uBACE,GAAA,CAAC,YAAS,QAAA,EAAU,IAAA,EAClB,8BAAC,qBAAA,EAAA,EAAuB,GAAG,OAAO,CAAA,EACpC,CAAA;AAEJ","file":"chunk-J4K335PQ.mjs","sourcesContent":["import * as React from 'react'\nimport { Suspense } from 'react'\nimport { getManagedScripts } from './server-api'\nimport type { ManagedScriptsProps, ManagedScript } from './types'\n\n/**\n * ManagedScripts - Server Component for injecting tracking/analytics scripts\n * \n * Fetches scripts from Portal and renders them in the appropriate position\n * \n * @example\n * ```tsx\n * // app/layout.tsx\n * import { ManagedScripts } from '@sonordev/seo'\n * \n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <head>\n * <ManagedScripts \n * projectId={process.env.UPTRADE_PROJECT_ID!}\n * position=\"head\"\n * />\n * </head>\n * <body>\n * <ManagedScripts \n * projectId={process.env.UPTRADE_PROJECT_ID!}\n * position=\"body-start\"\n * />\n * {children}\n * <ManagedScripts \n * projectId={process.env.UPTRADE_PROJECT_ID!}\n * position=\"body-end\"\n * />\n * </body>\n * </html>\n * )\n * }\n * ```\n */\nasync function ManagedScriptsAsync({\n position,\n path,\n}: ManagedScriptsProps): Promise<React.ReactElement | null> {\n const scripts = await getManagedScripts(position, path)\n\n if (!scripts.length) {\n return null\n }\n\n return (\n <>\n {scripts.map((script: ManagedScript) => {\n if (script.script_type === 'external') {\n // External script with src. Always include async so React 19 allows\n // rendering outside the main document (body-start/body-end).\n const attrs: Record<string, unknown> = {\n key: script.id,\n src: script.src,\n async: true,\n ...(script.defer && { defer: true }),\n ...script.attributes,\n }\n\n return <script {...attrs} />\n }\n\n // Inline script — add async so React 19 doesn't treat it as sync outside document\n return (\n <script\n key={script.id}\n async\n dangerouslySetInnerHTML={{ __html: script.content || '' }}\n {...script.attributes}\n />\n )\n })}\n </>\n )\n}\n\n/**\n * NoScript fallback component\n * \n * Use for adding noscript content (like Google Tag Manager noscript)\n */\nasync function ManagedNoScriptsAsync({\n path,\n}: {\n projectId?: string\n path?: string\n}): Promise<React.ReactElement | null> {\n const scripts = await getManagedScripts('body-start', path)\n\n // Filter scripts that have noscript content\n const noscriptContent = scripts\n .filter((s: ManagedScript) => s.attributes?.noscript)\n .map((s: ManagedScript) => s.attributes?.noscript)\n .join('')\n\n if (!noscriptContent) {\n return null\n }\n\n return (\n <noscript dangerouslySetInnerHTML={{ __html: noscriptContent }} />\n )\n}\n\nexport function ManagedScripts(props: ManagedScriptsProps): React.ReactElement {\n return (\n <Suspense fallback={null}>\n <ManagedScriptsAsync {...props} />\n </Suspense>\n )\n}\n\nexport function ManagedNoScripts(props: { projectId?: string; path?: string }): React.ReactElement {\n return (\n <Suspense fallback={null}>\n <ManagedNoScriptsAsync {...props} />\n </Suspense>\n )\n}\n\nexport default ManagedScripts\n"]}