@sonordev/site-kit 2.8.2 → 3.0.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 (117) hide show
  1. package/dist/EngageWidget-LRE4VD7O.js +14 -0
  2. package/dist/{EngageWidget-JIXUBG47.js.map → EngageWidget-LRE4VD7O.js.map} +1 -1
  3. package/dist/EngageWidget-OAOLB6ED.mjs +5 -0
  4. package/dist/{EngageWidget-4W5EM4UO.mjs.map → EngageWidget-OAOLB6ED.mjs.map} +1 -1
  5. package/dist/blog/index.js +2 -1
  6. package/dist/blog/index.js.map +1 -1
  7. package/dist/blog/index.mjs +2 -1
  8. package/dist/blog/index.mjs.map +1 -1
  9. package/dist/chunk-2FEQ6TYD.mjs +37 -0
  10. package/dist/chunk-2FEQ6TYD.mjs.map +1 -0
  11. package/dist/{chunk-5SQ4NRPH.mjs → chunk-3AEOGV6V.mjs} +6 -4
  12. package/dist/chunk-3AEOGV6V.mjs.map +1 -0
  13. package/dist/chunk-662YHKWW.mjs +10 -0
  14. package/dist/chunk-662YHKWW.mjs.map +1 -0
  15. package/dist/{chunk-MNOVPHL6.mjs → chunk-72MRAYAS.mjs} +19 -14
  16. package/dist/chunk-72MRAYAS.mjs.map +1 -0
  17. package/dist/{chunk-5QLM6LZ2.mjs → chunk-APRAGA5G.mjs} +3 -3
  18. package/dist/{chunk-5QLM6LZ2.mjs.map → chunk-APRAGA5G.mjs.map} +1 -1
  19. package/dist/{chunk-MWE2HRPU.js → chunk-D5XTX5EB.js} +19 -14
  20. package/dist/chunk-D5XTX5EB.js.map +1 -0
  21. package/dist/{chunk-HANRPNKG.js → chunk-FMI65E5Y.js} +3 -3
  22. package/dist/{chunk-HANRPNKG.js.map → chunk-FMI65E5Y.js.map} +1 -1
  23. package/dist/{chunk-SLJJJWMV.js → chunk-FPU2QPO4.js} +338 -33
  24. package/dist/chunk-FPU2QPO4.js.map +1 -0
  25. package/dist/{chunk-PKUTYMN7.js → chunk-J25JPU77.js} +2 -2
  26. package/dist/chunk-J25JPU77.js.map +1 -0
  27. package/dist/chunk-J7QI3GDX.js +12 -0
  28. package/dist/chunk-J7QI3GDX.js.map +1 -0
  29. package/dist/chunk-MLJXELPA.js +693 -0
  30. package/dist/chunk-MLJXELPA.js.map +1 -0
  31. package/dist/{chunk-L7XPPFSS.mjs → chunk-QDKQZ5XH.mjs} +2 -2
  32. package/dist/chunk-QDKQZ5XH.mjs.map +1 -0
  33. package/dist/{chunk-IAV32YHL.mjs → chunk-RV45YMBJ.mjs} +338 -33
  34. package/dist/chunk-RV45YMBJ.mjs.map +1 -0
  35. package/dist/chunk-TCVHI3JP.mjs +686 -0
  36. package/dist/chunk-TCVHI3JP.mjs.map +1 -0
  37. package/dist/{chunk-PAF5IGGF.js → chunk-XNUPJC6R.js} +6 -4
  38. package/dist/chunk-XNUPJC6R.js.map +1 -0
  39. package/dist/chunk-YBKALLBH.js +46 -0
  40. package/dist/chunk-YBKALLBH.js.map +1 -0
  41. package/dist/engage/index.d.mts +2 -2
  42. package/dist/engage/index.d.ts +2 -2
  43. package/dist/engage/index.js +5 -4
  44. package/dist/engage/index.js.map +1 -1
  45. package/dist/engage/index.mjs +2 -1
  46. package/dist/engage/index.mjs.map +1 -1
  47. package/dist/forms/index.js +19 -683
  48. package/dist/forms/index.js.map +1 -1
  49. package/dist/forms/index.mjs +4 -676
  50. package/dist/forms/index.mjs.map +1 -1
  51. package/dist/index.d.mts +2 -2
  52. package/dist/index.d.ts +2 -2
  53. package/dist/layout/client.js +2 -2
  54. package/dist/layout/client.mjs +1 -1
  55. package/dist/layout/index.js +5 -5
  56. package/dist/layout/index.mjs +2 -2
  57. package/dist/llms/index.d.mts +18 -4
  58. package/dist/llms/index.d.ts +18 -4
  59. package/dist/llms/index.js +26 -51
  60. package/dist/llms/index.js.map +1 -1
  61. package/dist/llms/index.mjs +16 -41
  62. package/dist/llms/index.mjs.map +1 -1
  63. package/dist/middleware/index.d.mts +62 -1
  64. package/dist/middleware/index.d.ts +62 -1
  65. package/dist/middleware/index.js +105 -0
  66. package/dist/middleware/index.js.map +1 -1
  67. package/dist/middleware/index.mjs +103 -1
  68. package/dist/middleware/index.mjs.map +1 -1
  69. package/dist/seo/index.d.mts +10 -205
  70. package/dist/seo/index.d.ts +10 -205
  71. package/dist/seo/index.js +16 -15
  72. package/dist/seo/index.js.map +1 -1
  73. package/dist/seo/index.mjs +7 -6
  74. package/dist/seo/index.mjs.map +1 -1
  75. package/dist/seo/server.d.mts +2 -106
  76. package/dist/seo/server.d.ts +2 -106
  77. package/dist/seo/server.js +56 -197
  78. package/dist/seo/server.js.map +1 -1
  79. package/dist/seo/server.mjs +2 -183
  80. package/dist/seo/server.mjs.map +1 -1
  81. package/dist/server-l6LMNvF1.d.ts +360 -0
  82. package/dist/server-mX5At_6x.d.mts +360 -0
  83. package/dist/sitemap/index.d.mts +1 -1
  84. package/dist/sitemap/index.d.ts +1 -1
  85. package/dist/sitemap/index.js +2 -2
  86. package/dist/sitemap/index.mjs +1 -1
  87. package/dist/slots/contract.d.mts +83 -0
  88. package/dist/slots/contract.d.ts +83 -0
  89. package/dist/slots/contract.js +41 -0
  90. package/dist/slots/contract.js.map +1 -0
  91. package/dist/slots/contract.mjs +4 -0
  92. package/dist/slots/contract.mjs.map +1 -0
  93. package/dist/slots/index.d.mts +104 -0
  94. package/dist/slots/index.d.ts +104 -0
  95. package/dist/slots/index.js +186 -0
  96. package/dist/slots/index.js.map +1 -0
  97. package/dist/slots/index.mjs +146 -0
  98. package/dist/slots/index.mjs.map +1 -0
  99. package/dist/{types-DYyIAgQg.d.ts → types-DPsbBKiu.d.mts} +1 -1
  100. package/dist/{types-DYyIAgQg.d.mts → types-DPsbBKiu.d.ts} +1 -1
  101. package/dist/{types-BnCwwUX3.d.mts → types-D_1iUxOQ.d.mts} +18 -1
  102. package/dist/{types-BnCwwUX3.d.ts → types-D_1iUxOQ.d.ts} +18 -1
  103. package/dist/{types-J7Z_FqmV.d.mts → types-DhCAWUmd.d.mts} +8 -0
  104. package/dist/{types-0NuBL1Gg.d.ts → types-xcP_owwn.d.ts} +8 -0
  105. package/package.json +11 -1
  106. package/dist/EngageWidget-4W5EM4UO.mjs +0 -4
  107. package/dist/EngageWidget-JIXUBG47.js +0 -13
  108. package/dist/chunk-5SQ4NRPH.mjs.map +0 -1
  109. package/dist/chunk-IAV32YHL.mjs.map +0 -1
  110. package/dist/chunk-L7XPPFSS.mjs.map +0 -1
  111. package/dist/chunk-MNOVPHL6.mjs.map +0 -1
  112. package/dist/chunk-MWE2HRPU.js.map +0 -1
  113. package/dist/chunk-PAF5IGGF.js.map +0 -1
  114. package/dist/chunk-PKUTYMN7.js.map +0 -1
  115. package/dist/chunk-SLJJJWMV.js.map +0 -1
  116. package/dist/routing-C7gmHWm9.d.ts +0 -163
  117. package/dist/routing-trNzR1Pz.d.mts +0 -163
@@ -0,0 +1,360 @@
1
+ import { G as GetManagedMetadataOptions, M as ManagedMetadataResult, l as GetABVariantOptions, k as ABTestResult, n as GetRedirectOptions, R as RedirectResult, q as GetRobotsOptions, p as RobotsDirective, s as GetSitemapEntriesOptions, r as SitemapEntry } from './types-DPsbBKiu.js';
2
+
3
+ /**
4
+ * @sonordev/site-kit/seo - Server-Only API Functions
5
+ *
6
+ * SECURITY: These functions use private environment variables
7
+ * and should ONLY be imported in server-side code (RSC, API routes, server actions).
8
+ *
9
+ * DO NOT import this file in client components or it will expose API keys.
10
+ */
11
+
12
+ /** Response shape for POST /api/public/seo/page-context */
13
+ type PageSeoContext = {
14
+ page: any | null;
15
+ schemas: any[];
16
+ project: {
17
+ id: string;
18
+ title?: string | null;
19
+ domain?: string | null;
20
+ logo_url?: string | null;
21
+ site_url?: string | null;
22
+ } | null;
23
+ };
24
+ /**
25
+ * Fetch SEO page data - cached per request
26
+ * @server-only
27
+ */
28
+ declare const getSEOPageData: (path: string) => Promise<{
29
+ page: any;
30
+ project: {
31
+ id: string;
32
+ title?: string | null;
33
+ domain?: string | null;
34
+ logo_url?: string | null;
35
+ site_url?: string | null;
36
+ } | null;
37
+ }>;
38
+ /**
39
+ * Fetch schema markups for a page - cached per request (shares loadPageSeoContext with getSEOPageData)
40
+ * @server-only
41
+ */
42
+ declare const getSchemaMarkups: (path: string, options?: {
43
+ includeTypes?: string[];
44
+ excludeTypes?: string[];
45
+ }) => Promise<any[]>;
46
+ /**
47
+ * Fetch FAQ data for a page - cached per request
48
+ * @server-only
49
+ */
50
+ declare const getFAQData: (path: string) => Promise<any>;
51
+ /**
52
+ * Fetch internal links for a page - cached per request
53
+ * @server-only
54
+ */
55
+ declare const getInternalLinks: (sourcePath: string, options?: {
56
+ position?: string;
57
+ limit?: number;
58
+ }) => Promise<any[]>;
59
+ /**
60
+ * Fetch content block - cached per request
61
+ * @server-only
62
+ */
63
+ declare const getContentBlock: (path: string, section: string) => Promise<any>;
64
+ /**
65
+ * Fetch A/B test and determine variant - cached per request
66
+ * @server-only
67
+ */
68
+ declare const getABTest: (path: string, field: string) => Promise<any>;
69
+ /**
70
+ * Record A/B test impression
71
+ * @server-only
72
+ */
73
+ declare function recordABImpression(testId: string, variant: 'a' | 'b', sessionId?: string): Promise<void>;
74
+ /**
75
+ * Fetch redirect for a path - cached per request
76
+ * @server-only
77
+ */
78
+ declare const getRedirectData: (path: string) => Promise<any>;
79
+ /**
80
+ * Fetch managed scripts - cached per request
81
+ * @server-only
82
+ */
83
+ declare const getManagedScripts: (position: string, currentPath?: string) => Promise<any[]>;
84
+ /**
85
+ * Fetch robots directive for a page - cached per request
86
+ * @server-only
87
+ */
88
+ declare const getRobotsData: (path: string) => Promise<any>;
89
+ /**
90
+ * Fetch sitemap entries - cached per request
91
+ * @server-only
92
+ */
93
+ declare const getSitemapEntries: (options?: {
94
+ publishedOnly?: boolean;
95
+ }) => Promise<any[]>;
96
+ /**
97
+ * Register/sync sitemap entries from the client site
98
+ * Call this at build time to populate seo_pages from your sitemap.xml
99
+ * @server-only
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * // scripts/register-sitemap.ts (run at build time)
104
+ * import { registerSitemap } from '@sonordev/seo/server'
105
+ *
106
+ * await registerSitemap([
107
+ * { path: '/', priority: 1.0, changefreq: 'daily' },
108
+ * { path: '/about', priority: 0.8, changefreq: 'weekly' },
109
+ * ])
110
+ * ```
111
+ */
112
+ declare function registerSitemap(entries: Array<{
113
+ path: string;
114
+ title?: string;
115
+ priority?: number;
116
+ changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
117
+ }>, options?: {
118
+ /**
119
+ * Sync mode:
120
+ * - 'full-replace': replaces the entire page set (default for build-time sync)
121
+ * - 'additive': adds/updates pages but never deletes existing ones
122
+ */
123
+ mode?: 'additive' | 'full-replace';
124
+ }): Promise<{
125
+ success: boolean;
126
+ created: number;
127
+ updated: number;
128
+ }>;
129
+ /**
130
+ * Entity types for the knowledge graph
131
+ */
132
+ type EntityType = 'organization' | 'person' | 'service' | 'product' | 'location' | 'concept' | 'credential';
133
+ /**
134
+ * Entity from the knowledge graph
135
+ */
136
+ interface SEOEntity {
137
+ id: string;
138
+ project_id: string;
139
+ entity_type: EntityType;
140
+ name: string;
141
+ slug: string;
142
+ properties: Record<string, unknown>;
143
+ knows_about: string[];
144
+ same_as: string[];
145
+ schema_type?: string;
146
+ is_primary: boolean;
147
+ }
148
+ /**
149
+ * Fetch entities for a project - cached per request
150
+ * Returns the entity graph for enhanced schema markup
151
+ * @server-only
152
+ */
153
+ declare const getEntities: (options?: {
154
+ type?: EntityType;
155
+ }) => Promise<SEOEntity[]>;
156
+ /**
157
+ * Fetch primary entity (the business) - cached per request
158
+ * @server-only
159
+ */
160
+ declare const getPrimaryEntity: () => Promise<SEOEntity | null>;
161
+ /**
162
+ * Fetch entity-enhanced schema for a page
163
+ * Returns Organization schema with knowsAbout, areaServed, employee, etc.
164
+ * @server-only
165
+ */
166
+ declare const getEntityEnhancedSchema: (pagePath: string) => Promise<object[]>;
167
+ /**
168
+ * Get AI visibility score for a page
169
+ * @server-only
170
+ */
171
+ declare const getVisibilityScore: (pagePath: string) => Promise<{
172
+ overall_score: number;
173
+ entity_coverage: number;
174
+ answer_density: number;
175
+ chunk_readability: number;
176
+ authority_signals: number;
177
+ schema_completeness: number;
178
+ } | null>;
179
+ /**
180
+ * Get AI visibility summary for project
181
+ * @server-only
182
+ */
183
+ declare const getVisibilitySummary: () => Promise<{
184
+ overall_score: number;
185
+ total_entities: number;
186
+ pages_analyzed: number;
187
+ top_recommendations: Array<{
188
+ priority: string;
189
+ type: string;
190
+ message: string;
191
+ }>;
192
+ } | null>;
193
+
194
+ /**
195
+ * Get managed metadata for a page
196
+ *
197
+ * Use in generateMetadata() to fetch Portal-managed SEO data
198
+ *
199
+ * @example
200
+ * ```tsx
201
+ * export async function generateMetadata({ params }) {
202
+ * return getManagedMetadata({
203
+ * path: `/services/${params.slug}`,
204
+ * fallback: {
205
+ * title: 'Our Services',
206
+ * description: 'Learn about our services'
207
+ * }
208
+ * })
209
+ * }
210
+ * ```
211
+ */
212
+ declare function getManagedMetadata(options: GetManagedMetadataOptions): Promise<ManagedMetadataResult>;
213
+ /**
214
+ * Get A/B test variant for a field
215
+ *
216
+ * @example
217
+ * ```tsx
218
+ * const variant = await getABVariant({
219
+ * path: '/pricing',
220
+ * field: 'title',
221
+ * sessionId: cookies().get('session_id')?.value
222
+ * })
223
+ *
224
+ * if (variant) {
225
+ * // Use variant.value instead of default
226
+ * }
227
+ * ```
228
+ */
229
+ declare function getABVariant(options: GetABVariantOptions): Promise<ABTestResult | null>;
230
+ /**
231
+ * Get managed metadata with A/B test support
232
+ *
233
+ * Automatically applies running A/B test variants to metadata
234
+ */
235
+ declare function getManagedMetadataWithAB(options: GetManagedMetadataOptions & {
236
+ sessionId?: string;
237
+ }): Promise<ManagedMetadataResult>;
238
+
239
+ /**
240
+ * Get redirect for a path if one exists
241
+ *
242
+ * Use in Next.js middleware to handle managed redirects
243
+ *
244
+ * @example
245
+ * ```tsx
246
+ * // middleware.ts
247
+ * import { getRedirect } from '@sonordev/seo'
248
+ *
249
+ * export async function middleware(request) {
250
+ * const redirect = await getRedirect({
251
+ * projectId: process.env.SONOR_PROJECT_ID!,
252
+ * path: request.nextUrl.pathname
253
+ * })
254
+ *
255
+ * if (redirect) {
256
+ * return NextResponse.redirect(redirect.destination, redirect.statusCode)
257
+ * }
258
+ * }
259
+ * ```
260
+ */
261
+ declare function getRedirect(options: GetRedirectOptions): Promise<RedirectResult | null>;
262
+ /**
263
+ * Get robots directive for a page
264
+ *
265
+ * @example
266
+ * ```tsx
267
+ * const robots = await getRobotsDirective({
268
+ * projectId: process.env.SONOR_PROJECT_ID!,
269
+ * path: '/private-page'
270
+ * })
271
+ *
272
+ * if (!robots.index) {
273
+ * // Page should not be indexed
274
+ * }
275
+ * ```
276
+ */
277
+ declare function getRobotsDirective(options: GetRobotsOptions): Promise<RobotsDirective>;
278
+ /**
279
+ * Get sitemap entries for a project
280
+ *
281
+ * Use in sitemap.ts to generate dynamic sitemap
282
+ *
283
+ * @example
284
+ * ```tsx
285
+ * // app/sitemap.ts
286
+ * import { generateSitemap } from '@sonordev/seo'
287
+ *
288
+ * export default async function sitemap() {
289
+ * return generateSitemap({
290
+ * projectId: process.env.SONOR_PROJECT_ID!,
291
+ * baseUrl: 'https://example.com',
292
+ * publishedOnly: true
293
+ * })
294
+ * }
295
+ * ```
296
+ */
297
+ declare function generateSitemap(options: GetSitemapEntriesOptions): Promise<SitemapEntry[]>;
298
+ /**
299
+ * Register local sitemap entries with Sonor
300
+ *
301
+ * Call this at build time to sync your local routes to seo_pages.
302
+ * This ensures analytics only tracks real pages.
303
+ *
304
+ * After registration, Signal AI will generate optimized meta titles
305
+ * and descriptions for pages that don't have managed meta yet.
306
+ *
307
+ * @example
308
+ * ```ts
309
+ * // scripts/register-sitemap.ts
310
+ * import { registerLocalSitemap } from '@sonordev/seo'
311
+ *
312
+ * // Option 1: Provide entries directly
313
+ * await registerLocalSitemap({
314
+ * entries: [
315
+ * { path: '/', title: 'Home', priority: 1.0 },
316
+ * { path: '/about', title: 'About Us', priority: 0.8 },
317
+ * ]
318
+ * })
319
+ *
320
+ * // Option 2: Auto-discover from Next.js app directory
321
+ * await registerLocalSitemap({ autoDiscover: true })
322
+ *
323
+ * // Option 3: Skip Signal AI meta optimization
324
+ * await registerLocalSitemap({ autoDiscover: true, optimize_meta: false })
325
+ * ```
326
+ */
327
+ declare function registerLocalSitemap(options: {
328
+ entries?: Array<{
329
+ path: string;
330
+ title?: string;
331
+ priority?: number;
332
+ changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
333
+ }>;
334
+ autoDiscover?: boolean;
335
+ /** Trigger Signal AI to generate optimized meta titles/descriptions (default: true) */
336
+ optimize_meta?: boolean;
337
+ /**
338
+ * Sync mode. Defaults to 'additive' for explicit entries (a partial list must
339
+ * never delete the rest of the site's pages) and 'full-replace' for
340
+ * autoDiscover (which enumerates the complete route set).
341
+ */
342
+ mode?: 'additive' | 'full-replace';
343
+ }): Promise<{
344
+ success: boolean;
345
+ created: number;
346
+ updated: number;
347
+ removed?: number;
348
+ meta_optimization?: {
349
+ triggered: boolean;
350
+ pages_queued: number;
351
+ } | null;
352
+ }>;
353
+ /**
354
+ * Check if a path should be indexed
355
+ *
356
+ * Quick helper to check indexability without full directive parsing
357
+ */
358
+ declare function isIndexable(projectId: string, path: string): Promise<boolean>;
359
+
360
+ export { type EntityType as E, type PageSeoContext as P, type SEOEntity as S, getManagedMetadataWithAB as a, getABVariant as b, getRedirect as c, getRobotsDirective as d, generateSitemap as e, getSEOPageData as f, getManagedMetadata as g, getSchemaMarkups as h, isIndexable as i, getFAQData as j, getInternalLinks as k, getContentBlock as l, getABTest as m, getRedirectData as n, getManagedScripts as o, getRobotsData as p, getSitemapEntries as q, recordABImpression as r, registerSitemap as s, getEntities as t, getPrimaryEntity as u, getEntityEnhancedSchema as v, getVisibilityScore as w, getVisibilitySummary as x, registerLocalSitemap as y };
@@ -0,0 +1,360 @@
1
+ import { G as GetManagedMetadataOptions, M as ManagedMetadataResult, l as GetABVariantOptions, k as ABTestResult, n as GetRedirectOptions, R as RedirectResult, q as GetRobotsOptions, p as RobotsDirective, s as GetSitemapEntriesOptions, r as SitemapEntry } from './types-DPsbBKiu.mjs';
2
+
3
+ /**
4
+ * @sonordev/site-kit/seo - Server-Only API Functions
5
+ *
6
+ * SECURITY: These functions use private environment variables
7
+ * and should ONLY be imported in server-side code (RSC, API routes, server actions).
8
+ *
9
+ * DO NOT import this file in client components or it will expose API keys.
10
+ */
11
+
12
+ /** Response shape for POST /api/public/seo/page-context */
13
+ type PageSeoContext = {
14
+ page: any | null;
15
+ schemas: any[];
16
+ project: {
17
+ id: string;
18
+ title?: string | null;
19
+ domain?: string | null;
20
+ logo_url?: string | null;
21
+ site_url?: string | null;
22
+ } | null;
23
+ };
24
+ /**
25
+ * Fetch SEO page data - cached per request
26
+ * @server-only
27
+ */
28
+ declare const getSEOPageData: (path: string) => Promise<{
29
+ page: any;
30
+ project: {
31
+ id: string;
32
+ title?: string | null;
33
+ domain?: string | null;
34
+ logo_url?: string | null;
35
+ site_url?: string | null;
36
+ } | null;
37
+ }>;
38
+ /**
39
+ * Fetch schema markups for a page - cached per request (shares loadPageSeoContext with getSEOPageData)
40
+ * @server-only
41
+ */
42
+ declare const getSchemaMarkups: (path: string, options?: {
43
+ includeTypes?: string[];
44
+ excludeTypes?: string[];
45
+ }) => Promise<any[]>;
46
+ /**
47
+ * Fetch FAQ data for a page - cached per request
48
+ * @server-only
49
+ */
50
+ declare const getFAQData: (path: string) => Promise<any>;
51
+ /**
52
+ * Fetch internal links for a page - cached per request
53
+ * @server-only
54
+ */
55
+ declare const getInternalLinks: (sourcePath: string, options?: {
56
+ position?: string;
57
+ limit?: number;
58
+ }) => Promise<any[]>;
59
+ /**
60
+ * Fetch content block - cached per request
61
+ * @server-only
62
+ */
63
+ declare const getContentBlock: (path: string, section: string) => Promise<any>;
64
+ /**
65
+ * Fetch A/B test and determine variant - cached per request
66
+ * @server-only
67
+ */
68
+ declare const getABTest: (path: string, field: string) => Promise<any>;
69
+ /**
70
+ * Record A/B test impression
71
+ * @server-only
72
+ */
73
+ declare function recordABImpression(testId: string, variant: 'a' | 'b', sessionId?: string): Promise<void>;
74
+ /**
75
+ * Fetch redirect for a path - cached per request
76
+ * @server-only
77
+ */
78
+ declare const getRedirectData: (path: string) => Promise<any>;
79
+ /**
80
+ * Fetch managed scripts - cached per request
81
+ * @server-only
82
+ */
83
+ declare const getManagedScripts: (position: string, currentPath?: string) => Promise<any[]>;
84
+ /**
85
+ * Fetch robots directive for a page - cached per request
86
+ * @server-only
87
+ */
88
+ declare const getRobotsData: (path: string) => Promise<any>;
89
+ /**
90
+ * Fetch sitemap entries - cached per request
91
+ * @server-only
92
+ */
93
+ declare const getSitemapEntries: (options?: {
94
+ publishedOnly?: boolean;
95
+ }) => Promise<any[]>;
96
+ /**
97
+ * Register/sync sitemap entries from the client site
98
+ * Call this at build time to populate seo_pages from your sitemap.xml
99
+ * @server-only
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * // scripts/register-sitemap.ts (run at build time)
104
+ * import { registerSitemap } from '@sonordev/seo/server'
105
+ *
106
+ * await registerSitemap([
107
+ * { path: '/', priority: 1.0, changefreq: 'daily' },
108
+ * { path: '/about', priority: 0.8, changefreq: 'weekly' },
109
+ * ])
110
+ * ```
111
+ */
112
+ declare function registerSitemap(entries: Array<{
113
+ path: string;
114
+ title?: string;
115
+ priority?: number;
116
+ changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
117
+ }>, options?: {
118
+ /**
119
+ * Sync mode:
120
+ * - 'full-replace': replaces the entire page set (default for build-time sync)
121
+ * - 'additive': adds/updates pages but never deletes existing ones
122
+ */
123
+ mode?: 'additive' | 'full-replace';
124
+ }): Promise<{
125
+ success: boolean;
126
+ created: number;
127
+ updated: number;
128
+ }>;
129
+ /**
130
+ * Entity types for the knowledge graph
131
+ */
132
+ type EntityType = 'organization' | 'person' | 'service' | 'product' | 'location' | 'concept' | 'credential';
133
+ /**
134
+ * Entity from the knowledge graph
135
+ */
136
+ interface SEOEntity {
137
+ id: string;
138
+ project_id: string;
139
+ entity_type: EntityType;
140
+ name: string;
141
+ slug: string;
142
+ properties: Record<string, unknown>;
143
+ knows_about: string[];
144
+ same_as: string[];
145
+ schema_type?: string;
146
+ is_primary: boolean;
147
+ }
148
+ /**
149
+ * Fetch entities for a project - cached per request
150
+ * Returns the entity graph for enhanced schema markup
151
+ * @server-only
152
+ */
153
+ declare const getEntities: (options?: {
154
+ type?: EntityType;
155
+ }) => Promise<SEOEntity[]>;
156
+ /**
157
+ * Fetch primary entity (the business) - cached per request
158
+ * @server-only
159
+ */
160
+ declare const getPrimaryEntity: () => Promise<SEOEntity | null>;
161
+ /**
162
+ * Fetch entity-enhanced schema for a page
163
+ * Returns Organization schema with knowsAbout, areaServed, employee, etc.
164
+ * @server-only
165
+ */
166
+ declare const getEntityEnhancedSchema: (pagePath: string) => Promise<object[]>;
167
+ /**
168
+ * Get AI visibility score for a page
169
+ * @server-only
170
+ */
171
+ declare const getVisibilityScore: (pagePath: string) => Promise<{
172
+ overall_score: number;
173
+ entity_coverage: number;
174
+ answer_density: number;
175
+ chunk_readability: number;
176
+ authority_signals: number;
177
+ schema_completeness: number;
178
+ } | null>;
179
+ /**
180
+ * Get AI visibility summary for project
181
+ * @server-only
182
+ */
183
+ declare const getVisibilitySummary: () => Promise<{
184
+ overall_score: number;
185
+ total_entities: number;
186
+ pages_analyzed: number;
187
+ top_recommendations: Array<{
188
+ priority: string;
189
+ type: string;
190
+ message: string;
191
+ }>;
192
+ } | null>;
193
+
194
+ /**
195
+ * Get managed metadata for a page
196
+ *
197
+ * Use in generateMetadata() to fetch Portal-managed SEO data
198
+ *
199
+ * @example
200
+ * ```tsx
201
+ * export async function generateMetadata({ params }) {
202
+ * return getManagedMetadata({
203
+ * path: `/services/${params.slug}`,
204
+ * fallback: {
205
+ * title: 'Our Services',
206
+ * description: 'Learn about our services'
207
+ * }
208
+ * })
209
+ * }
210
+ * ```
211
+ */
212
+ declare function getManagedMetadata(options: GetManagedMetadataOptions): Promise<ManagedMetadataResult>;
213
+ /**
214
+ * Get A/B test variant for a field
215
+ *
216
+ * @example
217
+ * ```tsx
218
+ * const variant = await getABVariant({
219
+ * path: '/pricing',
220
+ * field: 'title',
221
+ * sessionId: cookies().get('session_id')?.value
222
+ * })
223
+ *
224
+ * if (variant) {
225
+ * // Use variant.value instead of default
226
+ * }
227
+ * ```
228
+ */
229
+ declare function getABVariant(options: GetABVariantOptions): Promise<ABTestResult | null>;
230
+ /**
231
+ * Get managed metadata with A/B test support
232
+ *
233
+ * Automatically applies running A/B test variants to metadata
234
+ */
235
+ declare function getManagedMetadataWithAB(options: GetManagedMetadataOptions & {
236
+ sessionId?: string;
237
+ }): Promise<ManagedMetadataResult>;
238
+
239
+ /**
240
+ * Get redirect for a path if one exists
241
+ *
242
+ * Use in Next.js middleware to handle managed redirects
243
+ *
244
+ * @example
245
+ * ```tsx
246
+ * // middleware.ts
247
+ * import { getRedirect } from '@sonordev/seo'
248
+ *
249
+ * export async function middleware(request) {
250
+ * const redirect = await getRedirect({
251
+ * projectId: process.env.SONOR_PROJECT_ID!,
252
+ * path: request.nextUrl.pathname
253
+ * })
254
+ *
255
+ * if (redirect) {
256
+ * return NextResponse.redirect(redirect.destination, redirect.statusCode)
257
+ * }
258
+ * }
259
+ * ```
260
+ */
261
+ declare function getRedirect(options: GetRedirectOptions): Promise<RedirectResult | null>;
262
+ /**
263
+ * Get robots directive for a page
264
+ *
265
+ * @example
266
+ * ```tsx
267
+ * const robots = await getRobotsDirective({
268
+ * projectId: process.env.SONOR_PROJECT_ID!,
269
+ * path: '/private-page'
270
+ * })
271
+ *
272
+ * if (!robots.index) {
273
+ * // Page should not be indexed
274
+ * }
275
+ * ```
276
+ */
277
+ declare function getRobotsDirective(options: GetRobotsOptions): Promise<RobotsDirective>;
278
+ /**
279
+ * Get sitemap entries for a project
280
+ *
281
+ * Use in sitemap.ts to generate dynamic sitemap
282
+ *
283
+ * @example
284
+ * ```tsx
285
+ * // app/sitemap.ts
286
+ * import { generateSitemap } from '@sonordev/seo'
287
+ *
288
+ * export default async function sitemap() {
289
+ * return generateSitemap({
290
+ * projectId: process.env.SONOR_PROJECT_ID!,
291
+ * baseUrl: 'https://example.com',
292
+ * publishedOnly: true
293
+ * })
294
+ * }
295
+ * ```
296
+ */
297
+ declare function generateSitemap(options: GetSitemapEntriesOptions): Promise<SitemapEntry[]>;
298
+ /**
299
+ * Register local sitemap entries with Sonor
300
+ *
301
+ * Call this at build time to sync your local routes to seo_pages.
302
+ * This ensures analytics only tracks real pages.
303
+ *
304
+ * After registration, Signal AI will generate optimized meta titles
305
+ * and descriptions for pages that don't have managed meta yet.
306
+ *
307
+ * @example
308
+ * ```ts
309
+ * // scripts/register-sitemap.ts
310
+ * import { registerLocalSitemap } from '@sonordev/seo'
311
+ *
312
+ * // Option 1: Provide entries directly
313
+ * await registerLocalSitemap({
314
+ * entries: [
315
+ * { path: '/', title: 'Home', priority: 1.0 },
316
+ * { path: '/about', title: 'About Us', priority: 0.8 },
317
+ * ]
318
+ * })
319
+ *
320
+ * // Option 2: Auto-discover from Next.js app directory
321
+ * await registerLocalSitemap({ autoDiscover: true })
322
+ *
323
+ * // Option 3: Skip Signal AI meta optimization
324
+ * await registerLocalSitemap({ autoDiscover: true, optimize_meta: false })
325
+ * ```
326
+ */
327
+ declare function registerLocalSitemap(options: {
328
+ entries?: Array<{
329
+ path: string;
330
+ title?: string;
331
+ priority?: number;
332
+ changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
333
+ }>;
334
+ autoDiscover?: boolean;
335
+ /** Trigger Signal AI to generate optimized meta titles/descriptions (default: true) */
336
+ optimize_meta?: boolean;
337
+ /**
338
+ * Sync mode. Defaults to 'additive' for explicit entries (a partial list must
339
+ * never delete the rest of the site's pages) and 'full-replace' for
340
+ * autoDiscover (which enumerates the complete route set).
341
+ */
342
+ mode?: 'additive' | 'full-replace';
343
+ }): Promise<{
344
+ success: boolean;
345
+ created: number;
346
+ updated: number;
347
+ removed?: number;
348
+ meta_optimization?: {
349
+ triggered: boolean;
350
+ pages_queued: number;
351
+ } | null;
352
+ }>;
353
+ /**
354
+ * Check if a path should be indexed
355
+ *
356
+ * Quick helper to check indexability without full directive parsing
357
+ */
358
+ declare function isIndexable(projectId: string, path: string): Promise<boolean>;
359
+
360
+ export { type EntityType as E, type PageSeoContext as P, type SEOEntity as S, getManagedMetadataWithAB as a, getABVariant as b, getRedirect as c, getRobotsDirective as d, generateSitemap as e, getSEOPageData as f, getManagedMetadata as g, getSchemaMarkups as h, isIndexable as i, getFAQData as j, getInternalLinks as k, getContentBlock as l, getABTest as m, getRedirectData as n, getManagedScripts as o, getRobotsData as p, getSitemapEntries as q, recordABImpression as r, registerSitemap as s, getEntities as t, getPrimaryEntity as u, getEntityEnhancedSchema as v, getVisibilityScore as w, getVisibilitySummary as x, registerLocalSitemap as y };