@sonordev/site-kit 2.2.8 → 2.5.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 (132) hide show
  1. package/dist/SitemapSync-3ISOAVDT.mjs +4 -0
  2. package/dist/{SitemapSync-XGKC63TH.mjs.map → SitemapSync-3ISOAVDT.mjs.map} +1 -1
  3. package/dist/SitemapSync-4Y65CMUK.js +13 -0
  4. package/dist/{SitemapSync-TPA3GTGU.js.map → SitemapSync-4Y65CMUK.js.map} +1 -1
  5. package/dist/blog/index.d.mts +31 -3
  6. package/dist/blog/index.d.ts +31 -3
  7. package/dist/blog/index.js +194 -10
  8. package/dist/blog/index.js.map +1 -1
  9. package/dist/blog/index.mjs +183 -4
  10. package/dist/blog/index.mjs.map +1 -1
  11. package/dist/blog/server-ui.d.mts +1 -1
  12. package/dist/blog/server-ui.d.ts +1 -1
  13. package/dist/blog/server-ui.js +3 -3
  14. package/dist/blog/server-ui.mjs +1 -1
  15. package/dist/blog/server.d.mts +79 -7
  16. package/dist/blog/server.d.ts +79 -7
  17. package/dist/blog/server.js +64 -32
  18. package/dist/blog/server.mjs +1 -1
  19. package/dist/{chunk-WRCX2NKY.mjs → chunk-2NM6RGAV.mjs} +226 -22
  20. package/dist/chunk-2NM6RGAV.mjs.map +1 -0
  21. package/dist/chunk-5B4FABFK.js +28 -0
  22. package/dist/chunk-5B4FABFK.js.map +1 -0
  23. package/dist/{chunk-DTVZJPVM.mjs → chunk-5SQ4NRPH.mjs} +9 -2
  24. package/dist/chunk-5SQ4NRPH.mjs.map +1 -0
  25. package/dist/chunk-ATG4FJY6.js +76 -0
  26. package/dist/chunk-ATG4FJY6.js.map +1 -0
  27. package/dist/{chunk-F4VAOBJM.mjs → chunk-DV2BURIN.mjs} +3 -3
  28. package/dist/{chunk-F4VAOBJM.mjs.map → chunk-DV2BURIN.mjs.map} +1 -1
  29. package/dist/{chunk-GQKBGL2W.js → chunk-DZKX3GHL.js} +233 -21
  30. package/dist/chunk-DZKX3GHL.js.map +1 -0
  31. package/dist/{chunk-LNMI6OMN.js → chunk-F54HGPDM.js} +137 -4
  32. package/dist/chunk-F54HGPDM.js.map +1 -0
  33. package/dist/{chunk-DPO3ZPFK.js → chunk-GVDPTXN3.js} +3 -3
  34. package/dist/{chunk-DPO3ZPFK.js.map → chunk-GVDPTXN3.js.map} +1 -1
  35. package/dist/chunk-H23ZT2I2.mjs +67 -0
  36. package/dist/chunk-H23ZT2I2.mjs.map +1 -0
  37. package/dist/chunk-H4OBGC43.mjs +26 -0
  38. package/dist/chunk-H4OBGC43.mjs.map +1 -0
  39. package/dist/{chunk-UHMM22HX.js → chunk-JNXQX2R6.js} +7 -3
  40. package/dist/chunk-JNXQX2R6.js.map +1 -0
  41. package/dist/{chunk-Z6EHHJWU.mjs → chunk-MNOVPHL6.mjs} +230 -35
  42. package/dist/chunk-MNOVPHL6.mjs.map +1 -0
  43. package/dist/{chunk-ITPVKQB6.js → chunk-MWE2HRPU.js} +229 -34
  44. package/dist/chunk-MWE2HRPU.js.map +1 -0
  45. package/dist/{chunk-AWMEH65F.js → chunk-PAF5IGGF.js} +9 -2
  46. package/dist/chunk-PAF5IGGF.js.map +1 -0
  47. package/dist/{chunk-OOZCN7AF.mjs → chunk-T5UU7I4V.mjs} +137 -5
  48. package/dist/chunk-T5UU7I4V.mjs.map +1 -0
  49. package/dist/{chunk-PU5ULVL5.mjs → chunk-ZUCVEQZB.mjs} +7 -3
  50. package/dist/chunk-ZUCVEQZB.mjs.map +1 -0
  51. package/dist/cli/index.js +352 -78
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/cli/index.mjs +352 -78
  54. package/dist/cli/index.mjs.map +1 -1
  55. package/dist/config/index.d.mts +17 -0
  56. package/dist/config/index.d.ts +17 -0
  57. package/dist/config/index.js +43 -3
  58. package/dist/config/index.js.map +1 -1
  59. package/dist/config/index.mjs +43 -3
  60. package/dist/config/index.mjs.map +1 -1
  61. package/dist/forms/index.js +3 -1
  62. package/dist/forms/index.js.map +1 -1
  63. package/dist/forms/index.mjs +3 -1
  64. package/dist/forms/index.mjs.map +1 -1
  65. package/dist/index.d.mts +2 -2
  66. package/dist/index.d.ts +2 -2
  67. package/dist/layout/client.js +2 -2
  68. package/dist/layout/client.mjs +1 -1
  69. package/dist/layout/index.d.mts +6 -1
  70. package/dist/layout/index.d.ts +6 -1
  71. package/dist/layout/index.js +9 -5
  72. package/dist/layout/index.js.map +1 -1
  73. package/dist/layout/index.mjs +8 -4
  74. package/dist/layout/index.mjs.map +1 -1
  75. package/dist/llms/contract.d.mts +43 -0
  76. package/dist/llms/contract.d.ts +43 -0
  77. package/dist/llms/contract.js +41 -0
  78. package/dist/llms/contract.js.map +1 -0
  79. package/dist/llms/contract.mjs +4 -0
  80. package/dist/llms/contract.mjs.map +1 -0
  81. package/dist/llms/index.d.mts +67 -5
  82. package/dist/llms/index.d.ts +67 -5
  83. package/dist/llms/index.js +154 -36
  84. package/dist/llms/index.js.map +1 -1
  85. package/dist/llms/index.mjs +107 -27
  86. package/dist/llms/index.mjs.map +1 -1
  87. package/dist/middleware/index.d.mts +13 -1
  88. package/dist/middleware/index.d.ts +13 -1
  89. package/dist/middleware/index.js +11 -0
  90. package/dist/middleware/index.js.map +1 -1
  91. package/dist/middleware/index.mjs +11 -0
  92. package/dist/middleware/index.mjs.map +1 -1
  93. package/dist/{routing-ccNYbFLU.d.ts → routing-C7gmHWm9.d.ts} +1 -1
  94. package/dist/{routing-ebQln7wH.d.mts → routing-trNzR1Pz.d.mts} +1 -1
  95. package/dist/seo/client.js +2 -2
  96. package/dist/seo/client.mjs +1 -1
  97. package/dist/seo/index.d.mts +19 -4
  98. package/dist/seo/index.d.ts +19 -4
  99. package/dist/seo/index.js +51 -16
  100. package/dist/seo/index.js.map +1 -1
  101. package/dist/seo/index.mjs +43 -9
  102. package/dist/seo/index.mjs.map +1 -1
  103. package/dist/seo/server.d.mts +2 -2
  104. package/dist/seo/server.d.ts +2 -2
  105. package/dist/seo/server.js +5 -5
  106. package/dist/seo/server.mjs +1 -1
  107. package/dist/sitemap/index.d.mts +8 -1
  108. package/dist/sitemap/index.d.ts +8 -1
  109. package/dist/sitemap/index.js +35 -11
  110. package/dist/sitemap/index.js.map +1 -1
  111. package/dist/sitemap/index.mjs +34 -10
  112. package/dist/sitemap/index.mjs.map +1 -1
  113. package/dist/{types-BxzT7yhf.d.ts → types-0NuBL1Gg.d.ts} +34 -0
  114. package/dist/{types-DWMpAtGy.d.mts → types-5P5B9RgV.d.mts} +57 -1
  115. package/dist/{types-DWMpAtGy.d.ts → types-5P5B9RgV.d.ts} +57 -1
  116. package/dist/{types-CGkyylOa.d.mts → types-DYyIAgQg.d.mts} +2 -0
  117. package/dist/{types-CGkyylOa.d.ts → types-DYyIAgQg.d.ts} +2 -0
  118. package/dist/{types-BxzT7yhf.d.mts → types-J7Z_FqmV.d.mts} +34 -0
  119. package/package.json +15 -1
  120. package/scripts/postinstall.cjs +67 -0
  121. package/dist/SitemapSync-TPA3GTGU.js +0 -13
  122. package/dist/SitemapSync-XGKC63TH.mjs +0 -4
  123. package/dist/chunk-AWMEH65F.js.map +0 -1
  124. package/dist/chunk-DTVZJPVM.mjs.map +0 -1
  125. package/dist/chunk-GQKBGL2W.js.map +0 -1
  126. package/dist/chunk-ITPVKQB6.js.map +0 -1
  127. package/dist/chunk-LNMI6OMN.js.map +0 -1
  128. package/dist/chunk-OOZCN7AF.mjs.map +0 -1
  129. package/dist/chunk-PU5ULVL5.mjs.map +0 -1
  130. package/dist/chunk-UHMM22HX.js.map +0 -1
  131. package/dist/chunk-WRCX2NKY.mjs.map +0 -1
  132. package/dist/chunk-Z6EHHJWU.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { Metadata } from 'next';
2
- import { B as BlogPost, a as BlogAuthor } from '../types-DWMpAtGy.js';
2
+ import { B as BlogPost, T as TopicCluster, C as ClusterNavigation, a as BlogAuthor } from '../types-5P5B9RgV.js';
3
3
 
4
4
  /**
5
5
  * @sonordev/site-kit/blog/server
@@ -67,7 +67,9 @@ declare function getBlogPost(slug: string): Promise<BlogPost | null>;
67
67
  */
68
68
  declare function getAllBlogSlugs(): Promise<{
69
69
  slug: string;
70
+ id?: string;
70
71
  last_modified?: string;
72
+ article_type?: string;
71
73
  }[]>;
72
74
  /**
73
75
  * Fetch blog categories
@@ -186,7 +188,25 @@ declare function generateRssFeed(options: RssFeedOptions): Promise<string>;
186
188
  * Generate Atom feed XML
187
189
  */
188
190
  declare function generateAtomFeed(options: RssFeedOptions): Promise<string>;
189
- interface TopicCluster {
191
+ /**
192
+ * Fetch all active topic clusters for the project.
193
+ * Uses the real cluster data from Portal API (not heuristic-based).
194
+ */
195
+ declare function getTopicClusters(): Promise<TopicCluster[]>;
196
+ /**
197
+ * Fetch a single topic cluster with its pillar and support articles.
198
+ */
199
+ declare function getTopicCluster(slug: string): Promise<TopicCluster | null>;
200
+ /**
201
+ * Get cluster navigation context for a blog post.
202
+ * Returns the cluster name, pillar link, and sibling articles.
203
+ */
204
+ declare function getClusterNavigation(post: BlogPost): ClusterNavigation | null;
205
+ /**
206
+ * @deprecated Use getTopicCluster(slug) instead. This naive heuristic picks
207
+ * the longest post as pillar. Real cluster data is now managed in the Sonor dashboard.
208
+ */
209
+ declare function identifyTopicClusters(categorySlug: string): Promise<{
190
210
  pillar: BlogPost;
191
211
  supportingPosts: BlogPost[];
192
212
  internalLinks: Array<{
@@ -194,16 +214,68 @@ interface TopicCluster {
194
214
  to: string;
195
215
  anchor: string;
196
216
  }>;
197
- }
217
+ } | null>;
198
218
  /**
199
219
  * Fetch posts by category for topic cluster organization
200
220
  */
201
221
  declare function getPostsByCategory(categorySlug: string): Promise<BlogPost[]>;
202
222
  /**
203
- * Identify topic clusters based on category grouping
204
- * Assumes the longest/most comprehensive post is the pillar
223
+ * Generate ItemList schema for a cluster's pillar page.
224
+ * Wraps supporting posts as a structured list Google can parse.
205
225
  */
206
- declare function identifyTopicClusters(categorySlug: string): Promise<TopicCluster | null>;
226
+ declare function generateClusterItemListSchema(cluster: TopicCluster, options?: {
227
+ siteUrl?: string;
228
+ basePath?: string;
229
+ }): object;
230
+ /**
231
+ * Generate Article schema with cluster relationship (isPartOf / hasPart).
232
+ * - Support articles get `isPartOf` pointing to the pillar.
233
+ * - Pillar articles get `hasPart` listing all supports.
234
+ */
235
+ declare function generateClusterArticleSchema(post: BlogPost, cluster: TopicCluster, options?: {
236
+ siteUrl?: string;
237
+ basePath?: string;
238
+ siteName?: string;
239
+ logoUrl?: string;
240
+ }): object;
241
+ /**
242
+ * Generate BreadcrumbList schema for a cluster-linked post.
243
+ * Path: Home > Blog > Cluster > Article
244
+ */
245
+ declare function generateClusterBreadcrumbSchema(post: BlogPost, cluster: TopicCluster, options?: {
246
+ siteUrl?: string;
247
+ siteName?: string;
248
+ basePath?: string;
249
+ }): object;
250
+ /**
251
+ * Generate CollectionPage schema for a cluster landing page.
252
+ */
253
+ declare function generateClusterLandingSchema(cluster: TopicCluster, options?: {
254
+ siteUrl?: string;
255
+ basePath?: string;
256
+ siteName?: string;
257
+ }): object;
258
+ /**
259
+ * Generate metadata for a cluster landing page (Next.js generateMetadata).
260
+ */
261
+ declare function generateClusterPageMetadata(clusterSlug: string, options?: {
262
+ siteName?: string;
263
+ siteUrl?: string;
264
+ basePath?: string;
265
+ }): Promise<{
266
+ title?: undefined;
267
+ description?: undefined;
268
+ openGraph?: undefined;
269
+ } | {
270
+ title: string;
271
+ description: string;
272
+ openGraph: {
273
+ title: string;
274
+ description: string;
275
+ url: string;
276
+ type: string;
277
+ };
278
+ }>;
207
279
  /**
208
280
  * Generate "Related Insights" section data
209
281
  */
@@ -268,4 +340,4 @@ declare function generateAuthorSchema(author: BlogAuthor, options?: {
268
340
  siteName?: string;
269
341
  }): object;
270
342
 
271
- export { BlogPost as BlogPostRecord, type HowToStep, SEO_LIMITS, type SeoValidationResult, type TopicCluster, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getPostsByCategory, getRelatedInsights, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle };
343
+ export { BlogPost as BlogPostRecord, type HowToStep, SEO_LIMITS, type SeoValidationResult, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle };
@@ -1,133 +1,165 @@
1
1
  'use strict';
2
2
 
3
- var chunkGQKBGL2W_js = require('../chunk-GQKBGL2W.js');
3
+ var chunkDZKX3GHL_js = require('../chunk-DZKX3GHL.js');
4
4
  require('../chunk-ZSMWDLMK.js');
5
5
 
6
6
 
7
7
 
8
8
  Object.defineProperty(exports, "SEO_LIMITS", {
9
9
  enumerable: true,
10
- get: function () { return chunkGQKBGL2W_js.SEO_LIMITS; }
10
+ get: function () { return chunkDZKX3GHL_js.SEO_LIMITS; }
11
11
  });
12
12
  Object.defineProperty(exports, "generateAllBlogSchemas", {
13
13
  enumerable: true,
14
- get: function () { return chunkGQKBGL2W_js.generateAllBlogSchemas; }
14
+ get: function () { return chunkDZKX3GHL_js.generateAllBlogSchemas; }
15
15
  });
16
16
  Object.defineProperty(exports, "generateAtomFeed", {
17
17
  enumerable: true,
18
- get: function () { return chunkGQKBGL2W_js.generateAtomFeed; }
18
+ get: function () { return chunkDZKX3GHL_js.generateAtomFeed; }
19
19
  });
20
20
  Object.defineProperty(exports, "generateAuthorPageMetadata", {
21
21
  enumerable: true,
22
- get: function () { return chunkGQKBGL2W_js.generateAuthorPageMetadata; }
22
+ get: function () { return chunkDZKX3GHL_js.generateAuthorPageMetadata; }
23
23
  });
24
24
  Object.defineProperty(exports, "generateAuthorSchema", {
25
25
  enumerable: true,
26
- get: function () { return chunkGQKBGL2W_js.generateAuthorSchema; }
26
+ get: function () { return chunkDZKX3GHL_js.generateAuthorSchema; }
27
27
  });
28
28
  Object.defineProperty(exports, "generateAuthorStaticParams", {
29
29
  enumerable: true,
30
- get: function () { return chunkGQKBGL2W_js.generateAuthorStaticParams; }
30
+ get: function () { return chunkDZKX3GHL_js.generateAuthorStaticParams; }
31
31
  });
32
32
  Object.defineProperty(exports, "generateBlogCategoryMetadata", {
33
33
  enumerable: true,
34
- get: function () { return chunkGQKBGL2W_js.generateBlogCategoryMetadata; }
34
+ get: function () { return chunkDZKX3GHL_js.generateBlogCategoryMetadata; }
35
35
  });
36
36
  Object.defineProperty(exports, "generateBlogIndexMetadata", {
37
37
  enumerable: true,
38
- get: function () { return chunkGQKBGL2W_js.generateBlogIndexMetadata; }
38
+ get: function () { return chunkDZKX3GHL_js.generateBlogIndexMetadata; }
39
39
  });
40
40
  Object.defineProperty(exports, "generateBlogListSchema", {
41
41
  enumerable: true,
42
- get: function () { return chunkGQKBGL2W_js.generateBlogListSchema; }
42
+ get: function () { return chunkDZKX3GHL_js.generateBlogListSchema; }
43
43
  });
44
44
  Object.defineProperty(exports, "generateBlogPostMetadata", {
45
45
  enumerable: true,
46
- get: function () { return chunkGQKBGL2W_js.generateBlogPostMetadata; }
46
+ get: function () { return chunkDZKX3GHL_js.generateBlogPostMetadata; }
47
47
  });
48
48
  Object.defineProperty(exports, "generateBlogPostSchema", {
49
49
  enumerable: true,
50
- get: function () { return chunkGQKBGL2W_js.generateBlogPostSchema; }
50
+ get: function () { return chunkDZKX3GHL_js.generateBlogPostSchema; }
51
51
  });
52
52
  Object.defineProperty(exports, "generateBlogSitemap", {
53
53
  enumerable: true,
54
- get: function () { return chunkGQKBGL2W_js.generateBlogSitemap; }
54
+ get: function () { return chunkDZKX3GHL_js.generateBlogSitemap; }
55
55
  });
56
56
  Object.defineProperty(exports, "generateBlogStaticParams", {
57
57
  enumerable: true,
58
- get: function () { return chunkGQKBGL2W_js.generateBlogStaticParams; }
58
+ get: function () { return chunkDZKX3GHL_js.generateBlogStaticParams; }
59
59
  });
60
60
  Object.defineProperty(exports, "generateBreadcrumbSchema", {
61
61
  enumerable: true,
62
- get: function () { return chunkGQKBGL2W_js.generateBreadcrumbSchema; }
62
+ get: function () { return chunkDZKX3GHL_js.generateBreadcrumbSchema; }
63
63
  });
64
64
  Object.defineProperty(exports, "generateCategoryStaticParams", {
65
65
  enumerable: true,
66
- get: function () { return chunkGQKBGL2W_js.generateCategoryStaticParams; }
66
+ get: function () { return chunkDZKX3GHL_js.generateCategoryStaticParams; }
67
+ });
68
+ Object.defineProperty(exports, "generateClusterArticleSchema", {
69
+ enumerable: true,
70
+ get: function () { return chunkDZKX3GHL_js.generateClusterArticleSchema; }
71
+ });
72
+ Object.defineProperty(exports, "generateClusterBreadcrumbSchema", {
73
+ enumerable: true,
74
+ get: function () { return chunkDZKX3GHL_js.generateClusterBreadcrumbSchema; }
75
+ });
76
+ Object.defineProperty(exports, "generateClusterItemListSchema", {
77
+ enumerable: true,
78
+ get: function () { return chunkDZKX3GHL_js.generateClusterItemListSchema; }
79
+ });
80
+ Object.defineProperty(exports, "generateClusterLandingSchema", {
81
+ enumerable: true,
82
+ get: function () { return chunkDZKX3GHL_js.generateClusterLandingSchema; }
83
+ });
84
+ Object.defineProperty(exports, "generateClusterPageMetadata", {
85
+ enumerable: true,
86
+ get: function () { return chunkDZKX3GHL_js.generateClusterPageMetadata; }
67
87
  });
68
88
  Object.defineProperty(exports, "generateFaqSchema", {
69
89
  enumerable: true,
70
- get: function () { return chunkGQKBGL2W_js.generateFaqSchema; }
90
+ get: function () { return chunkDZKX3GHL_js.generateFaqSchema; }
71
91
  });
72
92
  Object.defineProperty(exports, "generateHowToSchema", {
73
93
  enumerable: true,
74
- get: function () { return chunkGQKBGL2W_js.generateHowToSchema; }
94
+ get: function () { return chunkDZKX3GHL_js.generateHowToSchema; }
75
95
  });
76
96
  Object.defineProperty(exports, "generateRssFeed", {
77
97
  enumerable: true,
78
- get: function () { return chunkGQKBGL2W_js.generateRssFeed; }
98
+ get: function () { return chunkDZKX3GHL_js.generateRssFeed; }
79
99
  });
80
100
  Object.defineProperty(exports, "getAllAuthorSlugs", {
81
101
  enumerable: true,
82
- get: function () { return chunkGQKBGL2W_js.getAllAuthorSlugs; }
102
+ get: function () { return chunkDZKX3GHL_js.getAllAuthorSlugs; }
83
103
  });
84
104
  Object.defineProperty(exports, "getAllBlogPosts", {
85
105
  enumerable: true,
86
- get: function () { return chunkGQKBGL2W_js.getAllBlogPosts; }
106
+ get: function () { return chunkDZKX3GHL_js.getAllBlogPosts; }
87
107
  });
88
108
  Object.defineProperty(exports, "getAllBlogSlugs", {
89
109
  enumerable: true,
90
- get: function () { return chunkGQKBGL2W_js.getAllBlogSlugs; }
110
+ get: function () { return chunkDZKX3GHL_js.getAllBlogSlugs; }
91
111
  });
92
112
  Object.defineProperty(exports, "getAuthorBySlug", {
93
113
  enumerable: true,
94
- get: function () { return chunkGQKBGL2W_js.getAuthorBySlug; }
114
+ get: function () { return chunkDZKX3GHL_js.getAuthorBySlug; }
95
115
  });
96
116
  Object.defineProperty(exports, "getAuthorPosts", {
97
117
  enumerable: true,
98
- get: function () { return chunkGQKBGL2W_js.getAuthorPosts; }
118
+ get: function () { return chunkDZKX3GHL_js.getAuthorPosts; }
99
119
  });
100
120
  Object.defineProperty(exports, "getBlogCategories", {
101
121
  enumerable: true,
102
- get: function () { return chunkGQKBGL2W_js.getBlogCategories; }
122
+ get: function () { return chunkDZKX3GHL_js.getBlogCategories; }
103
123
  });
104
124
  Object.defineProperty(exports, "getBlogPost", {
105
125
  enumerable: true,
106
- get: function () { return chunkGQKBGL2W_js.getBlogPost; }
126
+ get: function () { return chunkDZKX3GHL_js.getBlogPost; }
127
+ });
128
+ Object.defineProperty(exports, "getClusterNavigation", {
129
+ enumerable: true,
130
+ get: function () { return chunkDZKX3GHL_js.getClusterNavigation; }
107
131
  });
108
132
  Object.defineProperty(exports, "getPostsByCategory", {
109
133
  enumerable: true,
110
- get: function () { return chunkGQKBGL2W_js.getPostsByCategory; }
134
+ get: function () { return chunkDZKX3GHL_js.getPostsByCategory; }
111
135
  });
112
136
  Object.defineProperty(exports, "getRelatedInsights", {
113
137
  enumerable: true,
114
- get: function () { return chunkGQKBGL2W_js.getRelatedInsights; }
138
+ get: function () { return chunkDZKX3GHL_js.getRelatedInsights; }
139
+ });
140
+ Object.defineProperty(exports, "getTopicCluster", {
141
+ enumerable: true,
142
+ get: function () { return chunkDZKX3GHL_js.getTopicCluster; }
143
+ });
144
+ Object.defineProperty(exports, "getTopicClusters", {
145
+ enumerable: true,
146
+ get: function () { return chunkDZKX3GHL_js.getTopicClusters; }
115
147
  });
116
148
  Object.defineProperty(exports, "identifyTopicClusters", {
117
149
  enumerable: true,
118
- get: function () { return chunkGQKBGL2W_js.identifyTopicClusters; }
150
+ get: function () { return chunkDZKX3GHL_js.identifyTopicClusters; }
119
151
  });
120
152
  Object.defineProperty(exports, "validateBlogPostSeo", {
121
153
  enumerable: true,
122
- get: function () { return chunkGQKBGL2W_js.validateBlogPostSeo; }
154
+ get: function () { return chunkDZKX3GHL_js.validateBlogPostSeo; }
123
155
  });
124
156
  Object.defineProperty(exports, "validateMetaDescription", {
125
157
  enumerable: true,
126
- get: function () { return chunkGQKBGL2W_js.validateMetaDescription; }
158
+ get: function () { return chunkDZKX3GHL_js.validateMetaDescription; }
127
159
  });
128
160
  Object.defineProperty(exports, "validateSeoTitle", {
129
161
  enumerable: true,
130
- get: function () { return chunkGQKBGL2W_js.validateSeoTitle; }
162
+ get: function () { return chunkDZKX3GHL_js.validateSeoTitle; }
131
163
  });
132
164
  //# sourceMappingURL=server.js.map
133
165
  //# sourceMappingURL=server.js.map
@@ -1,4 +1,4 @@
1
- export { SEO_LIMITS, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getPostsByCategory, getRelatedInsights, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle } from '../chunk-WRCX2NKY.mjs';
1
+ export { SEO_LIMITS, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle } from '../chunk-2NM6RGAV.mjs';
2
2
  import '../chunk-4XPGGLVP.mjs';
3
3
  //# sourceMappingURL=server.mjs.map
4
4
  //# sourceMappingURL=server.mjs.map
@@ -261,6 +261,7 @@ async function generateCategoryStaticParams() {
261
261
  async function generateBlogSitemap(siteUrl) {
262
262
  const slugs = await getAllBlogSlugs();
263
263
  const categories = await getBlogCategories();
264
+ const clusters = await getTopicClusters();
264
265
  const entries = [
265
266
  // Blog index
266
267
  {
@@ -269,6 +270,13 @@ async function generateBlogSitemap(siteUrl) {
269
270
  priority: 0.8
270
271
  }
271
272
  ];
273
+ clusters.forEach((cluster) => {
274
+ entries.push({
275
+ url: `${siteUrl}/blog/cluster/${cluster.cluster_slug}`,
276
+ changeFrequency: "weekly",
277
+ priority: 0.8
278
+ });
279
+ });
272
280
  categories.forEach((cat) => {
273
281
  entries.push({
274
282
  url: `${siteUrl}/blog/category/${cat.slug}`,
@@ -277,11 +285,12 @@ async function generateBlogSitemap(siteUrl) {
277
285
  });
278
286
  });
279
287
  slugs.forEach((post) => {
288
+ const isPillar = post.article_type === "pillar";
280
289
  entries.push({
281
290
  url: `${siteUrl}/blog/${post.slug}`,
282
291
  lastModified: post.last_modified ? new Date(post.last_modified) : void 0,
283
- changeFrequency: "weekly",
284
- priority: 0.7
292
+ changeFrequency: isPillar ? "weekly" : "monthly",
293
+ priority: isPillar ? 0.9 : 0.7
285
294
  });
286
295
  });
287
296
  return entries;
@@ -534,23 +543,83 @@ async function generateAtomFeed(options) {
534
543
  atom += `</feed>`;
535
544
  return atom;
536
545
  }
537
- async function getPostsByCategory(categorySlug) {
546
+ async function getTopicClusters() {
538
547
  const { apiUrl, apiKey } = getConfig();
539
548
  if (!apiKey) return [];
540
549
  try {
541
- const response = await fetch(`${apiUrl}/public/blog/posts?category=${categorySlug}&limit=50`, {
550
+ const response = await fetch(`${apiUrl}/public/blog/clusters`, {
542
551
  headers: { "x-api-key": apiKey },
543
552
  next: { revalidate: 300 }
544
553
  });
545
554
  if (!response.ok) return [];
546
555
  const data = await response.json();
547
- return data.posts || [];
556
+ return (data.clusters || []).map((c) => ({
557
+ id: c.id,
558
+ cluster_name: c.cluster_name,
559
+ cluster_slug: c.cluster_slug,
560
+ core_topic: c.core_topic,
561
+ primary_entity: c.primary_entity,
562
+ industry: c.industry,
563
+ geo_target: c.geo_target,
564
+ commercial_goal: c.commercial_goal,
565
+ pillar_post_id: c.pillar_post_id,
566
+ target_service_page: c.target_service_page,
567
+ article_count: c.article_count,
568
+ pillar: null,
569
+ supports: [],
570
+ interlink_map: []
571
+ }));
548
572
  } catch (error) {
549
- console.error("[Blog] Error fetching category posts:", error);
573
+ console.error("[Blog] Error fetching topic clusters:", error);
550
574
  return [];
551
575
  }
552
576
  }
577
+ async function getTopicCluster(slug) {
578
+ const { apiUrl, apiKey } = getConfig();
579
+ if (!apiKey) return null;
580
+ try {
581
+ const response = await fetch(`${apiUrl}/public/blog/clusters/${slug}`, {
582
+ headers: { "x-api-key": apiKey },
583
+ next: { revalidate: 300 }
584
+ });
585
+ if (!response.ok) return null;
586
+ const data = await response.json();
587
+ return {
588
+ id: data.id,
589
+ cluster_name: data.cluster_name,
590
+ cluster_slug: data.cluster_slug,
591
+ core_topic: data.core_topic,
592
+ primary_entity: data.primary_entity,
593
+ industry: data.industry,
594
+ geo_target: data.geo_target,
595
+ commercial_goal: data.commercial_goal,
596
+ pillar_post_id: data.pillar?.id,
597
+ target_service_page: data.target_service_page,
598
+ article_count: data.article_count,
599
+ pillar: data.pillar || null,
600
+ supports: data.supports || [],
601
+ interlink_map: data.interlink_map || []
602
+ };
603
+ } catch (error) {
604
+ console.error("[Blog] Error fetching topic cluster:", error);
605
+ return null;
606
+ }
607
+ }
608
+ function getClusterNavigation(post) {
609
+ if (!post.cluster_id && !post.cluster_slug) return null;
610
+ const isPillar = post.article_type === "pillar";
611
+ return {
612
+ cluster_name: post.cluster_name || "",
613
+ cluster_slug: post.cluster_slug || "",
614
+ pillar: isPillar ? null : post.parent_pillar_slug ? { slug: post.parent_pillar_slug, title: post.parent_pillar_title || "" } : null,
615
+ siblings: post.sibling_articles || [],
616
+ is_pillar: isPillar
617
+ };
618
+ }
553
619
  async function identifyTopicClusters(categorySlug) {
620
+ console.warn(
621
+ "[Blog] identifyTopicClusters() is deprecated. Use getTopicCluster(slug) for real cluster data managed in the Sonor dashboard."
622
+ );
554
623
  const posts = await getPostsByCategory(categorySlug);
555
624
  if (posts.length < 3) return null;
556
625
  const sortedByLength = [...posts].sort((a, b) => (b.word_count || 0) - (a.word_count || 0));
@@ -558,23 +627,158 @@ async function identifyTopicClusters(categorySlug) {
558
627
  const supportingPosts = sortedByLength.slice(1);
559
628
  const internalLinks = [];
560
629
  for (const support of supportingPosts) {
561
- internalLinks.push({
562
- from: pillar.slug,
563
- to: support.slug,
564
- anchor: support.title
565
- });
630
+ internalLinks.push({ from: pillar.slug, to: support.slug, anchor: support.title });
631
+ internalLinks.push({ from: support.slug, to: pillar.slug, anchor: pillar.title });
566
632
  }
567
- for (const support of supportingPosts) {
568
- internalLinks.push({
569
- from: support.slug,
570
- to: pillar.slug,
571
- anchor: pillar.title
633
+ return { pillar, supportingPosts, internalLinks };
634
+ }
635
+ async function getPostsByCategory(categorySlug) {
636
+ const { apiUrl, apiKey } = getConfig();
637
+ if (!apiKey) return [];
638
+ try {
639
+ const response = await fetch(`${apiUrl}/public/blog/posts?category=${categorySlug}&limit=50`, {
640
+ headers: { "x-api-key": apiKey },
641
+ next: { revalidate: 300 }
572
642
  });
643
+ if (!response.ok) return [];
644
+ const data = await response.json();
645
+ return data.posts || [];
646
+ } catch (error) {
647
+ console.error("[Blog] Error fetching category posts:", error);
648
+ return [];
649
+ }
650
+ }
651
+ function generateClusterItemListSchema(cluster, options = {}) {
652
+ const { siteUrl = "", basePath = "/blog" } = options;
653
+ return {
654
+ "@context": "https://schema.org",
655
+ "@type": "ItemList",
656
+ name: cluster.cluster_name,
657
+ description: `Articles about ${cluster.core_topic}`,
658
+ numberOfItems: cluster.supports.length,
659
+ itemListElement: cluster.supports.map((post, i) => ({
660
+ "@type": "ListItem",
661
+ position: i + 1,
662
+ name: post.title,
663
+ url: `${siteUrl}${basePath}/${post.slug}`
664
+ }))
665
+ };
666
+ }
667
+ function generateClusterArticleSchema(post, cluster, options = {}) {
668
+ const { siteUrl = "", basePath = "/blog", siteName, logoUrl } = options;
669
+ const isPillar = post.article_type === "pillar";
670
+ const schema = {
671
+ "@context": "https://schema.org",
672
+ "@type": "Article",
673
+ headline: post.title,
674
+ description: post.excerpt || post.meta_description,
675
+ url: `${siteUrl}${basePath}/${post.slug}`,
676
+ datePublished: post.published_at,
677
+ dateModified: post.updated_at,
678
+ author: {
679
+ "@type": "Person",
680
+ name: typeof post.author === "string" ? post.author : post.author?.name
681
+ },
682
+ keywords: post.focus_keyphrase || post.keywords
683
+ };
684
+ if (post.featured_image) {
685
+ schema.image = {
686
+ "@type": "ImageObject",
687
+ url: post.featured_image,
688
+ width: post.featured_image_width || 1200,
689
+ height: post.featured_image_height || 630
690
+ };
573
691
  }
692
+ if (siteName || logoUrl) {
693
+ schema.publisher = {
694
+ "@type": "Organization",
695
+ name: siteName,
696
+ ...logoUrl && { logo: { "@type": "ImageObject", url: logoUrl } }
697
+ };
698
+ }
699
+ if (isPillar && cluster.supports.length > 0) {
700
+ schema.hasPart = cluster.supports.map((s) => ({
701
+ "@type": "Article",
702
+ headline: s.title,
703
+ url: `${siteUrl}${basePath}/${s.slug}`
704
+ }));
705
+ } else if (!isPillar && cluster.pillar) {
706
+ schema.isPartOf = {
707
+ "@type": "Article",
708
+ headline: cluster.pillar.title,
709
+ url: `${siteUrl}${basePath}/${cluster.pillar.slug}`
710
+ };
711
+ }
712
+ if (cluster.geo_target) {
713
+ schema.spatialCoverage = {
714
+ "@type": "Place",
715
+ name: cluster.geo_target
716
+ };
717
+ }
718
+ return schema;
719
+ }
720
+ function generateClusterBreadcrumbSchema(post, cluster, options = {}) {
721
+ const { siteUrl = "", siteName = "Home", basePath = "/blog" } = options;
722
+ const items = [
723
+ { "@type": "ListItem", position: 1, name: siteName, item: siteUrl },
724
+ { "@type": "ListItem", position: 2, name: "Blog", item: `${siteUrl}${basePath}` },
725
+ {
726
+ "@type": "ListItem",
727
+ position: 3,
728
+ name: cluster.cluster_name,
729
+ item: `${siteUrl}${basePath}/cluster/${cluster.cluster_slug}`
730
+ },
731
+ {
732
+ "@type": "ListItem",
733
+ position: 4,
734
+ name: post.title,
735
+ item: `${siteUrl}${basePath}/${post.slug}`
736
+ }
737
+ ];
738
+ return {
739
+ "@context": "https://schema.org",
740
+ "@type": "BreadcrumbList",
741
+ itemListElement: items
742
+ };
743
+ }
744
+ function generateClusterLandingSchema(cluster, options = {}) {
745
+ const { siteUrl = "", basePath = "/blog", siteName } = options;
746
+ return {
747
+ "@context": "https://schema.org",
748
+ "@type": "CollectionPage",
749
+ name: cluster.cluster_name,
750
+ description: `Comprehensive guide to ${cluster.core_topic}`,
751
+ url: `${siteUrl}${basePath}/cluster/${cluster.cluster_slug}`,
752
+ ...siteName && {
753
+ isPartOf: { "@type": "WebSite", name: siteName, url: siteUrl }
754
+ },
755
+ mainEntity: cluster.pillar ? {
756
+ "@type": "Article",
757
+ headline: cluster.pillar.title,
758
+ url: `${siteUrl}${basePath}/${cluster.pillar.slug}`
759
+ } : void 0,
760
+ hasPart: cluster.supports.map((s) => ({
761
+ "@type": "Article",
762
+ headline: s.title,
763
+ url: `${siteUrl}${basePath}/${s.slug}`
764
+ }))
765
+ };
766
+ }
767
+ async function generateClusterPageMetadata(clusterSlug, options = {}) {
768
+ const cluster = await getTopicCluster(clusterSlug);
769
+ if (!cluster) return {};
770
+ const { siteName = "", siteUrl = "", basePath = "/blog" } = options;
771
+ const title = `${cluster.cluster_name}${siteName ? ` | ${siteName}` : ""}`;
772
+ const description = `Comprehensive guide to ${cluster.core_topic}. ${cluster.article_count} articles covering everything you need to know.`;
574
773
  return {
575
- pillar,
576
- supportingPosts,
577
- internalLinks
774
+ title,
775
+ description,
776
+ openGraph: {
777
+ title,
778
+ description,
779
+ url: `${siteUrl}${basePath}/cluster/${cluster.cluster_slug}`,
780
+ type: "website"
781
+ }
578
782
  };
579
783
  }
580
784
  async function getRelatedInsights(currentSlug, options = {}) {
@@ -794,6 +998,6 @@ function generateAuthorSchema(author, options = {}) {
794
998
  return schema;
795
999
  }
796
1000
 
797
- export { SEO_LIMITS, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getPostsByCategory, getRelatedInsights, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle };
798
- //# sourceMappingURL=chunk-WRCX2NKY.mjs.map
799
- //# sourceMappingURL=chunk-WRCX2NKY.mjs.map
1001
+ export { SEO_LIMITS, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle };
1002
+ //# sourceMappingURL=chunk-2NM6RGAV.mjs.map
1003
+ //# sourceMappingURL=chunk-2NM6RGAV.mjs.map