@dsaplatform/content-sdk 1.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/README.md +148 -0
- package/dist/index.d.mts +369 -0
- package/dist/index.d.ts +369 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -0
- package/dist/server.d.mts +154 -0
- package/dist/server.d.ts +154 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +2 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# @dsaplatform/content-sdk
|
|
2
|
+
|
|
3
|
+
React SDK for **DSA Content Operating System** — fetch and render SEO-optimized content from a central content engine on any Next.js or React site.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @dsaplatform/content-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start — Next.js App Router (SSR)
|
|
12
|
+
|
|
13
|
+
### 1. Server-side data fetching in `app/blog/[slug]/page.tsx`
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { fetchArticleBySlug, fetchRelatedArticles, generateArticleMetadata } from '@dsaplatform/content-sdk/server';
|
|
17
|
+
|
|
18
|
+
const config = {
|
|
19
|
+
apiUrl: process.env.CONTENT_ENGINE_URL!,
|
|
20
|
+
apiKey: process.env.CONTENT_API_KEY!,
|
|
21
|
+
cacheStrategy: 'revalidate' as const,
|
|
22
|
+
revalidateSeconds: 3600,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export async function generateMetadata({ params }: { params: { slug: string } }) {
|
|
26
|
+
const article = await fetchArticleBySlug(config, params.slug);
|
|
27
|
+
return generateArticleMetadata(article, 'https://yoursite.com');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default async function BlogPost({ params }: { params: { slug: string } }) {
|
|
31
|
+
const article = await fetchArticleBySlug(config, params.slug);
|
|
32
|
+
const related = await fetchRelatedArticles(config, params.slug, 3);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<ArticlePageWrapper article={article} related={related} />
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Client component for rendering
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
'use client';
|
|
44
|
+
import { ArticlePage, SeoMetaBridge } from '@dsaplatform/content-sdk';
|
|
45
|
+
|
|
46
|
+
export function ArticlePageWrapper({ article, related }) {
|
|
47
|
+
return (
|
|
48
|
+
<>
|
|
49
|
+
<SeoMetaBridge article={article} siteUrl="https://yoursite.com" />
|
|
50
|
+
<ArticlePage
|
|
51
|
+
article={article}
|
|
52
|
+
showFaq
|
|
53
|
+
showTableOfContents
|
|
54
|
+
showRelated
|
|
55
|
+
relatedArticles={related}
|
|
56
|
+
onRelatedClick={(slug) => window.location.href = `/blog/${slug}`}
|
|
57
|
+
/>
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. Article listing in `app/blog/page.tsx`
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { fetchArticleList } from '@dsaplatform/content-sdk/server';
|
|
67
|
+
import { ArticleFeed } from '@dsaplatform/content-sdk';
|
|
68
|
+
|
|
69
|
+
export default async function BlogIndex() {
|
|
70
|
+
const { items } = await fetchArticleList(config, { page: 1, per_page: 12 });
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<ArticleFeed
|
|
74
|
+
articles={items}
|
|
75
|
+
layout="grid"
|
|
76
|
+
columns={3}
|
|
77
|
+
onArticleClick={(slug) => `/blog/${slug}`}
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Client-Side Hooks (SPA / CSR)
|
|
84
|
+
|
|
85
|
+
Wrap your app with the provider:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import { DsaContentProvider } from '@dsaplatform/content-sdk';
|
|
89
|
+
|
|
90
|
+
<DsaContentProvider config={{ apiUrl: '...', apiKey: '...' }}>
|
|
91
|
+
<App />
|
|
92
|
+
</DsaContentProvider>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Then use hooks anywhere:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { useArticles, useArticle, useRelatedArticles, useCategories } from '@dsaplatform/content-sdk';
|
|
99
|
+
|
|
100
|
+
function BlogList() {
|
|
101
|
+
const { articles, loading, pagination } = useArticles({ page: 1, per_page: 10 });
|
|
102
|
+
if (loading) return <p>Loading...</p>;
|
|
103
|
+
return <ArticleFeed articles={articles} />;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function BlogPost({ slug }: { slug: string }) {
|
|
107
|
+
const { article, loading } = useArticle(slug);
|
|
108
|
+
const { articles: related } = useRelatedArticles(slug, 3);
|
|
109
|
+
if (loading || !article) return <p>Loading...</p>;
|
|
110
|
+
return <ArticlePage article={article} showRelated relatedArticles={related} />;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Components
|
|
115
|
+
|
|
116
|
+
| Component | Description |
|
|
117
|
+
|-----------|-------------|
|
|
118
|
+
| `ArticleFeed` | Grid/list of article cards |
|
|
119
|
+
| `ArticlePage` | Full article with TOC, FAQ, related |
|
|
120
|
+
| `FaqBlock` | FAQ section with Schema.org markup |
|
|
121
|
+
| `RelatedArticles` | Related articles widget |
|
|
122
|
+
| `SeoMetaBridge` | JSON-LD structured data |
|
|
123
|
+
|
|
124
|
+
## Server Helpers
|
|
125
|
+
|
|
126
|
+
| Function | Description |
|
|
127
|
+
|----------|-------------|
|
|
128
|
+
| `fetchArticleBySlug(config, slug)` | Get one article |
|
|
129
|
+
| `fetchArticleList(config, filters?)` | Paginated article list |
|
|
130
|
+
| `fetchRelatedArticles(config, slug, limit?)` | Related articles |
|
|
131
|
+
| `fetchCategories(config)` | Pillar/cluster tree |
|
|
132
|
+
| `fetchSitemap(config)` | All published slugs |
|
|
133
|
+
| `generateArticleMetadata(article, siteUrl?)` | Next.js Metadata object |
|
|
134
|
+
|
|
135
|
+
## Configuration
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
interface DsaContentConfig {
|
|
139
|
+
apiUrl: string; // Content Engine URL
|
|
140
|
+
apiKey: string; // Site's public API key
|
|
141
|
+
cacheStrategy?: 'no-cache' | 'force-cache' | 'revalidate';
|
|
142
|
+
revalidateSeconds?: number; // ISR interval
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SDK Configuration for DSA Content Engine
|
|
6
|
+
*/
|
|
7
|
+
interface DsaContentConfig {
|
|
8
|
+
/** Content Engine API URL (e.g., "https://content.example.com") */
|
|
9
|
+
apiUrl: string;
|
|
10
|
+
/** Site's public API key for authentication */
|
|
11
|
+
apiKey: string;
|
|
12
|
+
/** Cache strategy for Next.js ISR */
|
|
13
|
+
cacheStrategy?: 'no-cache' | 'force-cache' | 'revalidate';
|
|
14
|
+
/** Revalidation interval in seconds (for ISR) */
|
|
15
|
+
revalidateSeconds?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Full article response from Content Engine
|
|
19
|
+
*/
|
|
20
|
+
interface Article {
|
|
21
|
+
id: string;
|
|
22
|
+
title: string;
|
|
23
|
+
slug: string;
|
|
24
|
+
excerpt: string | null;
|
|
25
|
+
content_html: string;
|
|
26
|
+
content_json: any | null;
|
|
27
|
+
h1: string | null;
|
|
28
|
+
meta_title: string | null;
|
|
29
|
+
meta_description: string | null;
|
|
30
|
+
canonical_url?: string | null;
|
|
31
|
+
target_keyword: string | null;
|
|
32
|
+
secondary_keywords: string[];
|
|
33
|
+
headings: ArticleHeading[];
|
|
34
|
+
faq: FaqItem[];
|
|
35
|
+
internal_links: InternalLink[];
|
|
36
|
+
schema_json: any | null;
|
|
37
|
+
featured_image_url: string | null;
|
|
38
|
+
featured_image_alt: string | null;
|
|
39
|
+
publish_status: string;
|
|
40
|
+
published_at: string | null;
|
|
41
|
+
updated_at?: string | null;
|
|
42
|
+
word_count: number | null;
|
|
43
|
+
reading_time_minutes: number | null;
|
|
44
|
+
seo_score: number | null;
|
|
45
|
+
pillar_name?: string;
|
|
46
|
+
cluster_name?: string;
|
|
47
|
+
content_type?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Abbreviated article for lists
|
|
51
|
+
*/
|
|
52
|
+
interface ArticleListItem {
|
|
53
|
+
id: string;
|
|
54
|
+
title: string;
|
|
55
|
+
slug: string;
|
|
56
|
+
excerpt: string | null;
|
|
57
|
+
featured_image_url: string | null;
|
|
58
|
+
featured_image_alt: string | null;
|
|
59
|
+
published_at: string | null;
|
|
60
|
+
pillar_name?: string;
|
|
61
|
+
cluster_name?: string;
|
|
62
|
+
content_type?: string;
|
|
63
|
+
reading_time_minutes: number | null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Article heading (from H1-H6 tags)
|
|
67
|
+
*/
|
|
68
|
+
interface ArticleHeading {
|
|
69
|
+
level: number;
|
|
70
|
+
text: string;
|
|
71
|
+
id: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* FAQ item
|
|
75
|
+
*/
|
|
76
|
+
interface FaqItem {
|
|
77
|
+
question: string;
|
|
78
|
+
answer: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Internal link reference
|
|
82
|
+
*/
|
|
83
|
+
interface InternalLink {
|
|
84
|
+
slug: string;
|
|
85
|
+
anchor_text: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Category with clusters
|
|
89
|
+
*/
|
|
90
|
+
interface Category {
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
description: string | null;
|
|
94
|
+
article_count: number;
|
|
95
|
+
clusters: ClusterInfo[];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Cluster information
|
|
99
|
+
*/
|
|
100
|
+
interface ClusterInfo {
|
|
101
|
+
id: string;
|
|
102
|
+
name: string;
|
|
103
|
+
description: string | null;
|
|
104
|
+
article_count: number;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Paginated response
|
|
108
|
+
*/
|
|
109
|
+
interface PaginatedResponse<T> {
|
|
110
|
+
items: T[];
|
|
111
|
+
total: number;
|
|
112
|
+
page: number;
|
|
113
|
+
per_page: number;
|
|
114
|
+
total_pages: number;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Filters for article list queries
|
|
118
|
+
*/
|
|
119
|
+
interface ArticleFilters {
|
|
120
|
+
page?: number;
|
|
121
|
+
per_page?: number;
|
|
122
|
+
pillar?: string;
|
|
123
|
+
cluster?: string;
|
|
124
|
+
content_type?: string;
|
|
125
|
+
search?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Sitemap entry
|
|
129
|
+
*/
|
|
130
|
+
interface SitemapEntry {
|
|
131
|
+
slug: string;
|
|
132
|
+
title: string;
|
|
133
|
+
published_at: string;
|
|
134
|
+
updated_at: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Hook state for async data fetching
|
|
138
|
+
*/
|
|
139
|
+
interface UseArticlesState {
|
|
140
|
+
articles: ArticleListItem[];
|
|
141
|
+
loading: boolean;
|
|
142
|
+
error: Error | null;
|
|
143
|
+
pagination: {
|
|
144
|
+
page: number;
|
|
145
|
+
per_page: number;
|
|
146
|
+
total: number;
|
|
147
|
+
total_pages: number;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Hook state for single article
|
|
152
|
+
*/
|
|
153
|
+
interface UseArticleState {
|
|
154
|
+
article: Article | null;
|
|
155
|
+
loading: boolean;
|
|
156
|
+
error: Error | null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Hook state for article list (related articles, etc.)
|
|
160
|
+
*/
|
|
161
|
+
interface UseArticleListState {
|
|
162
|
+
articles: ArticleListItem[];
|
|
163
|
+
loading: boolean;
|
|
164
|
+
error: Error | null;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Hook state for categories
|
|
168
|
+
*/
|
|
169
|
+
interface UseCategoriesState {
|
|
170
|
+
categories: Category[];
|
|
171
|
+
loading: boolean;
|
|
172
|
+
error: Error | null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* ContentClient — HTTP client for DSA Content Engine Public API.
|
|
177
|
+
* Works in both Node.js (SSR) and browser environments.
|
|
178
|
+
*/
|
|
179
|
+
declare class ContentClient {
|
|
180
|
+
private apiUrl;
|
|
181
|
+
private apiKey;
|
|
182
|
+
private cacheStrategy;
|
|
183
|
+
private revalidateSeconds?;
|
|
184
|
+
constructor(config: DsaContentConfig);
|
|
185
|
+
private request;
|
|
186
|
+
/** Get paginated list of published articles */
|
|
187
|
+
getArticles(filters?: ArticleFilters): Promise<PaginatedResponse<ArticleListItem>>;
|
|
188
|
+
/** Get a single article by slug */
|
|
189
|
+
getArticleBySlug(slug: string): Promise<Article>;
|
|
190
|
+
/** Get related articles for a given slug */
|
|
191
|
+
getRelatedArticles(slug: string, limit?: number): Promise<ArticleListItem[]>;
|
|
192
|
+
/** Get all categories (pillars + clusters) with article counts */
|
|
193
|
+
getCategories(): Promise<Category[]>;
|
|
194
|
+
/** Get sitemap data for all published articles */
|
|
195
|
+
getSitemap(): Promise<SitemapEntry[]>;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
interface DsaContentProviderProps {
|
|
199
|
+
config: DsaContentConfig;
|
|
200
|
+
children: React.ReactNode;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Wrap your app (or a subtree) with DsaContentProvider to enable
|
|
204
|
+
* the useDsaContent() hook and all data-fetching hooks.
|
|
205
|
+
*
|
|
206
|
+
* ```tsx
|
|
207
|
+
* <DsaContentProvider config={{ apiUrl: "...", apiKey: "..." }}>
|
|
208
|
+
* <App />
|
|
209
|
+
* </DsaContentProvider>
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
declare function DsaContentProvider({ config, children }: DsaContentProviderProps): react_jsx_runtime.JSX.Element;
|
|
213
|
+
/**
|
|
214
|
+
* Access the ContentClient instance from context.
|
|
215
|
+
* Must be called inside a DsaContentProvider.
|
|
216
|
+
*/
|
|
217
|
+
declare function useDsaContent(): ContentClient;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Fetch a paginated list of published articles.
|
|
221
|
+
*
|
|
222
|
+
* ```tsx
|
|
223
|
+
* const { articles, loading, error, pagination } = useArticles({ page: 1, per_page: 10 });
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
declare function useArticles(filters?: ArticleFilters): UseArticlesState & {
|
|
227
|
+
refetch: () => void;
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Fetch a single article by slug.
|
|
231
|
+
*
|
|
232
|
+
* ```tsx
|
|
233
|
+
* const { article, loading, error } = useArticle("my-article-slug");
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
declare function useArticle(slug: string | undefined): UseArticleState & {
|
|
237
|
+
refetch: () => void;
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Fetch related articles for a given slug.
|
|
241
|
+
*
|
|
242
|
+
* ```tsx
|
|
243
|
+
* const { articles, loading } = useRelatedArticles("my-article-slug", 4);
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
declare function useRelatedArticles(slug: string | undefined, limit?: number): UseArticleListState & {
|
|
247
|
+
refetch: () => void;
|
|
248
|
+
};
|
|
249
|
+
/**
|
|
250
|
+
* Fetch all categories (pillars + clusters).
|
|
251
|
+
*
|
|
252
|
+
* ```tsx
|
|
253
|
+
* const { categories, loading } = useCategories();
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
declare function useCategories(): UseCategoriesState & {
|
|
257
|
+
refetch: () => void;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
interface ArticleFeedProps {
|
|
261
|
+
articles: ArticleListItem[];
|
|
262
|
+
layout?: 'grid' | 'list';
|
|
263
|
+
columns?: 1 | 2 | 3;
|
|
264
|
+
showExcerpt?: boolean;
|
|
265
|
+
showImage?: boolean;
|
|
266
|
+
showMeta?: boolean;
|
|
267
|
+
onArticleClick?: (slug: string) => void;
|
|
268
|
+
className?: string;
|
|
269
|
+
renderArticle?: (article: ArticleListItem) => React.ReactNode;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Renders a grid or list of article cards.
|
|
273
|
+
*
|
|
274
|
+
* ```tsx
|
|
275
|
+
* <ArticleFeed articles={articles} layout="grid" columns={3} onArticleClick={(slug) => router.push(`/blog/${slug}`)} />
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
declare function ArticleFeed({ articles, layout, columns, showExcerpt, showImage, showMeta, onArticleClick, className, renderArticle, }: ArticleFeedProps): react_jsx_runtime.JSX.Element;
|
|
279
|
+
|
|
280
|
+
interface ArticlePageProps {
|
|
281
|
+
article: Article;
|
|
282
|
+
showFaq?: boolean;
|
|
283
|
+
showTableOfContents?: boolean;
|
|
284
|
+
showMeta?: boolean;
|
|
285
|
+
showRelated?: boolean;
|
|
286
|
+
relatedArticles?: ArticleListItem[];
|
|
287
|
+
onRelatedClick?: (slug: string) => void;
|
|
288
|
+
className?: string;
|
|
289
|
+
components?: {
|
|
290
|
+
H1?: React.ComponentType<{
|
|
291
|
+
children: React.ReactNode;
|
|
292
|
+
}>;
|
|
293
|
+
Toc?: React.ComponentType<{
|
|
294
|
+
headings: Article['headings'];
|
|
295
|
+
}>;
|
|
296
|
+
Faq?: React.ComponentType<{
|
|
297
|
+
items: FaqItem[];
|
|
298
|
+
}>;
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Renders a full article page with optional TOC, FAQ, and related articles.
|
|
303
|
+
*
|
|
304
|
+
* ```tsx
|
|
305
|
+
* <ArticlePage article={article} showTableOfContents showFaq />
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
declare function ArticlePage({ article, showFaq, showTableOfContents, showMeta, showRelated, relatedArticles, onRelatedClick, className, components, }: ArticlePageProps): react_jsx_runtime.JSX.Element;
|
|
309
|
+
|
|
310
|
+
interface FaqBlockProps {
|
|
311
|
+
items: FaqItem[];
|
|
312
|
+
collapsible?: boolean;
|
|
313
|
+
defaultOpen?: boolean;
|
|
314
|
+
className?: string;
|
|
315
|
+
title?: string;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* FAQ block with optional collapse behavior and Schema.org FAQPage markup.
|
|
319
|
+
*
|
|
320
|
+
* ```tsx
|
|
321
|
+
* <FaqBlock items={article.faq} collapsible />
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
declare function FaqBlock({ items, collapsible, defaultOpen, className, title, }: FaqBlockProps): react_jsx_runtime.JSX.Element | null;
|
|
325
|
+
|
|
326
|
+
interface RelatedArticlesProps {
|
|
327
|
+
articles: ArticleListItem[];
|
|
328
|
+
title?: string;
|
|
329
|
+
limit?: number;
|
|
330
|
+
onArticleClick?: (slug: string) => void;
|
|
331
|
+
className?: string;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Related articles widget.
|
|
335
|
+
*
|
|
336
|
+
* ```tsx
|
|
337
|
+
* <RelatedArticles articles={related} onArticleClick={(slug) => router.push(`/blog/${slug}`)} />
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
declare function RelatedArticles({ articles, title, limit, onArticleClick, className, }: RelatedArticlesProps): react_jsx_runtime.JSX.Element | null;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Generate Next.js App Router Metadata object from an Article.
|
|
344
|
+
* Use in page.tsx generateMetadata():
|
|
345
|
+
*
|
|
346
|
+
* ```ts
|
|
347
|
+
* import { generateArticleMetadata } from "@dsa/content-sdk/server";
|
|
348
|
+
*
|
|
349
|
+
* export async function generateMetadata({ params }) {
|
|
350
|
+
* const article = await fetchArticleBySlug(config, params.slug);
|
|
351
|
+
* return generateArticleMetadata(article, "https://example.com");
|
|
352
|
+
* }
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
declare function generateArticleMetadata(article: Article, siteUrl?: string): Record<string, any>;
|
|
356
|
+
/**
|
|
357
|
+
* Renders JSON-LD structured data for an article.
|
|
358
|
+
* Include this component in your article page layout for SEO.
|
|
359
|
+
*
|
|
360
|
+
* ```tsx
|
|
361
|
+
* <SeoMetaBridge article={article} siteUrl="https://example.com" />
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
declare function SeoMetaBridge({ article, siteUrl, }: {
|
|
365
|
+
article: Article;
|
|
366
|
+
siteUrl?: string;
|
|
367
|
+
}): react_jsx_runtime.JSX.Element;
|
|
368
|
+
|
|
369
|
+
export { type Article, ArticleFeed, type ArticleFeedProps, type ArticleFilters, type ArticleHeading, type ArticleListItem, ArticlePage, type ArticlePageProps, type Category, type ClusterInfo, ContentClient, type DsaContentConfig, DsaContentProvider, type DsaContentProviderProps, FaqBlock, type FaqBlockProps, type FaqItem, type InternalLink, type PaginatedResponse, RelatedArticles, type RelatedArticlesProps, SeoMetaBridge, type SitemapEntry, type UseArticleListState, type UseArticleState, type UseArticlesState, type UseCategoriesState, generateArticleMetadata, useArticle, useArticles, useCategories, useDsaContent, useRelatedArticles };
|