@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.
- package/dist/EngageWidget-LRE4VD7O.js +14 -0
- package/dist/{EngageWidget-JIXUBG47.js.map → EngageWidget-LRE4VD7O.js.map} +1 -1
- package/dist/EngageWidget-OAOLB6ED.mjs +5 -0
- package/dist/{EngageWidget-4W5EM4UO.mjs.map → EngageWidget-OAOLB6ED.mjs.map} +1 -1
- package/dist/blog/index.js +2 -1
- package/dist/blog/index.js.map +1 -1
- package/dist/blog/index.mjs +2 -1
- package/dist/blog/index.mjs.map +1 -1
- package/dist/chunk-2FEQ6TYD.mjs +37 -0
- package/dist/chunk-2FEQ6TYD.mjs.map +1 -0
- package/dist/{chunk-5SQ4NRPH.mjs → chunk-3AEOGV6V.mjs} +6 -4
- package/dist/chunk-3AEOGV6V.mjs.map +1 -0
- package/dist/chunk-662YHKWW.mjs +10 -0
- package/dist/chunk-662YHKWW.mjs.map +1 -0
- package/dist/{chunk-MNOVPHL6.mjs → chunk-72MRAYAS.mjs} +19 -14
- package/dist/chunk-72MRAYAS.mjs.map +1 -0
- package/dist/{chunk-5QLM6LZ2.mjs → chunk-APRAGA5G.mjs} +3 -3
- package/dist/{chunk-5QLM6LZ2.mjs.map → chunk-APRAGA5G.mjs.map} +1 -1
- package/dist/{chunk-MWE2HRPU.js → chunk-D5XTX5EB.js} +19 -14
- package/dist/chunk-D5XTX5EB.js.map +1 -0
- package/dist/{chunk-HANRPNKG.js → chunk-FMI65E5Y.js} +3 -3
- package/dist/{chunk-HANRPNKG.js.map → chunk-FMI65E5Y.js.map} +1 -1
- package/dist/{chunk-SLJJJWMV.js → chunk-FPU2QPO4.js} +338 -33
- package/dist/chunk-FPU2QPO4.js.map +1 -0
- package/dist/{chunk-PKUTYMN7.js → chunk-J25JPU77.js} +2 -2
- package/dist/chunk-J25JPU77.js.map +1 -0
- package/dist/chunk-J7QI3GDX.js +12 -0
- package/dist/chunk-J7QI3GDX.js.map +1 -0
- package/dist/chunk-MLJXELPA.js +693 -0
- package/dist/chunk-MLJXELPA.js.map +1 -0
- package/dist/{chunk-L7XPPFSS.mjs → chunk-QDKQZ5XH.mjs} +2 -2
- package/dist/chunk-QDKQZ5XH.mjs.map +1 -0
- package/dist/{chunk-IAV32YHL.mjs → chunk-RV45YMBJ.mjs} +338 -33
- package/dist/chunk-RV45YMBJ.mjs.map +1 -0
- package/dist/chunk-TCVHI3JP.mjs +686 -0
- package/dist/chunk-TCVHI3JP.mjs.map +1 -0
- package/dist/{chunk-PAF5IGGF.js → chunk-XNUPJC6R.js} +6 -4
- package/dist/chunk-XNUPJC6R.js.map +1 -0
- package/dist/chunk-YBKALLBH.js +46 -0
- package/dist/chunk-YBKALLBH.js.map +1 -0
- package/dist/engage/index.d.mts +2 -2
- package/dist/engage/index.d.ts +2 -2
- package/dist/engage/index.js +5 -4
- package/dist/engage/index.js.map +1 -1
- package/dist/engage/index.mjs +2 -1
- package/dist/engage/index.mjs.map +1 -1
- package/dist/forms/index.js +19 -683
- package/dist/forms/index.js.map +1 -1
- package/dist/forms/index.mjs +4 -676
- package/dist/forms/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/layout/client.js +2 -2
- package/dist/layout/client.mjs +1 -1
- package/dist/layout/index.js +5 -5
- package/dist/layout/index.mjs +2 -2
- package/dist/llms/index.d.mts +18 -4
- package/dist/llms/index.d.ts +18 -4
- package/dist/llms/index.js +26 -51
- package/dist/llms/index.js.map +1 -1
- package/dist/llms/index.mjs +16 -41
- package/dist/llms/index.mjs.map +1 -1
- package/dist/middleware/index.d.mts +62 -1
- package/dist/middleware/index.d.ts +62 -1
- package/dist/middleware/index.js +105 -0
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +103 -1
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/seo/index.d.mts +10 -205
- package/dist/seo/index.d.ts +10 -205
- package/dist/seo/index.js +16 -15
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +7 -6
- package/dist/seo/index.mjs.map +1 -1
- package/dist/seo/server.d.mts +2 -106
- package/dist/seo/server.d.ts +2 -106
- package/dist/seo/server.js +56 -197
- package/dist/seo/server.js.map +1 -1
- package/dist/seo/server.mjs +2 -183
- package/dist/seo/server.mjs.map +1 -1
- package/dist/server-l6LMNvF1.d.ts +360 -0
- package/dist/server-mX5At_6x.d.mts +360 -0
- package/dist/sitemap/index.d.mts +1 -1
- package/dist/sitemap/index.d.ts +1 -1
- package/dist/sitemap/index.js +2 -2
- package/dist/sitemap/index.mjs +1 -1
- package/dist/slots/contract.d.mts +83 -0
- package/dist/slots/contract.d.ts +83 -0
- package/dist/slots/contract.js +41 -0
- package/dist/slots/contract.js.map +1 -0
- package/dist/slots/contract.mjs +4 -0
- package/dist/slots/contract.mjs.map +1 -0
- package/dist/slots/index.d.mts +104 -0
- package/dist/slots/index.d.ts +104 -0
- package/dist/slots/index.js +186 -0
- package/dist/slots/index.js.map +1 -0
- package/dist/slots/index.mjs +146 -0
- package/dist/slots/index.mjs.map +1 -0
- package/dist/{types-DYyIAgQg.d.ts → types-DPsbBKiu.d.mts} +1 -1
- package/dist/{types-DYyIAgQg.d.mts → types-DPsbBKiu.d.ts} +1 -1
- package/dist/{types-BnCwwUX3.d.mts → types-D_1iUxOQ.d.mts} +18 -1
- package/dist/{types-BnCwwUX3.d.ts → types-D_1iUxOQ.d.ts} +18 -1
- package/dist/{types-J7Z_FqmV.d.mts → types-DhCAWUmd.d.mts} +8 -0
- package/dist/{types-0NuBL1Gg.d.ts → types-xcP_owwn.d.ts} +8 -0
- package/package.json +11 -1
- package/dist/EngageWidget-4W5EM4UO.mjs +0 -4
- package/dist/EngageWidget-JIXUBG47.js +0 -13
- package/dist/chunk-5SQ4NRPH.mjs.map +0 -1
- package/dist/chunk-IAV32YHL.mjs.map +0 -1
- package/dist/chunk-L7XPPFSS.mjs.map +0 -1
- package/dist/chunk-MNOVPHL6.mjs.map +0 -1
- package/dist/chunk-MWE2HRPU.js.map +0 -1
- package/dist/chunk-PAF5IGGF.js.map +0 -1
- package/dist/chunk-PKUTYMN7.js.map +0 -1
- package/dist/chunk-SLJJJWMV.js.map +0 -1
- package/dist/routing-C7gmHWm9.d.ts +0 -163
- 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 };
|