@vigilkids/cms-client 0.1.3 → 0.2.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/CHANGELOG.md +45 -0
- package/README.md +155 -14
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.mjs +49 -10
- package/dist/types.d.mts +33 -1
- package/dist/types.d.ts +33 -1
- package/package.json +4 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.2.0] - 2026-06-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added `searchArticles` for published article search through the CMS Public API.
|
|
13
|
+
- Added `ArticleSearchParams` and `ArticleSearchResultItem` public types.
|
|
14
|
+
- Added article list sorting parameters through `ArticleListParams.sort_by` and `ArticleListParams.sort_order`.
|
|
15
|
+
- Added sitemap route metadata, hreflang route parameters, and `SitemapImageEntry` image metadata types.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Included `CHANGELOG.md` in the published package contents.
|
|
20
|
+
|
|
21
|
+
## [0.1.2] - 2026-03-26
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- `last_published_at` field to `ArticleListItem` type (aligns with backend `DeliveryArticleListItem`)
|
|
26
|
+
|
|
27
|
+
## [0.1.0] - 2026-03-23
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- ESLint flat config (`@antfu/eslint-config`) + Prettier
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Codebase formatted with Prettier (singleQuote, no semi, printWidth 100)
|
|
36
|
+
|
|
37
|
+
## [0.0.1] - 2025-03-23
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- CMS API client with typed request/response interfaces
|
|
42
|
+
- Article delivery API (getBySlug, list, categories, sitemap)
|
|
43
|
+
- Preview token validation
|
|
44
|
+
- Webhook payload types for content events
|
|
45
|
+
- TypeScript-first with full type exports
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @vigilkids/cms-client
|
|
2
2
|
|
|
3
|
-
TypeScript
|
|
3
|
+
Framework-agnostic TypeScript client for the OneX CMS Public API. It provides a typed fetch-based client for published CMS content, sitemap data, redirects, comments, authors, series, and server-side webhook signature verification.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -8,36 +8,177 @@ TypeScript HTTP client for the OneX CMS delivery API. Framework-agnostic — wor
|
|
|
8
8
|
pnpm add @vigilkids/cms-client
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
The `baseUrl` must point at the CMS Public API root that serves `/articles`, `/search`, `/sitemap`, and the other delivery endpoints.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createCmsClient } from '@vigilkids/cms-client'
|
|
17
|
+
|
|
18
|
+
export const cms = createCmsClient({
|
|
19
|
+
baseUrl: 'https://api.example.com/api/v1/cms',
|
|
20
|
+
productCode: 'example-product',
|
|
21
|
+
defaultLocale: 'en',
|
|
22
|
+
timeout: 10_000,
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| Option | Required | Description |
|
|
27
|
+
|--------|----------|-------------|
|
|
28
|
+
| `baseUrl` | Yes | CMS Public API base URL. |
|
|
29
|
+
| `productCode` | No | Adds `X-Product-Code` to each request. |
|
|
30
|
+
| `defaultLocale` | No | Locale automatically added to GET requests when no locale is provided. Defaults to `en`. |
|
|
31
|
+
| `previewToken` | No | Adds `X-Preview-Token` to each request. |
|
|
32
|
+
| `fetch` | No | Custom fetch-compatible implementation. Defaults to `globalThis.fetch`. |
|
|
33
|
+
| `timeout` | No | Request timeout in milliseconds. Defaults to `10000`. |
|
|
34
|
+
| `headers` | No | Additional request headers merged into each request. |
|
|
35
|
+
|
|
36
|
+
## Articles
|
|
37
|
+
|
|
38
|
+
Use `getArticles`, `getArticle`, and `searchArticles` for published article delivery.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { createCmsClient } from '@vigilkids/cms-client'
|
|
42
|
+
|
|
43
|
+
const cms = createCmsClient({
|
|
44
|
+
baseUrl: 'https://api.example.com/api/v1/cms',
|
|
45
|
+
defaultLocale: 'en',
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
export async function loadArticles(): Promise<void> {
|
|
49
|
+
const articlePage = await cms.getArticles({
|
|
50
|
+
page: 1,
|
|
51
|
+
page_size: 10,
|
|
52
|
+
sort_by: 'last_published_at',
|
|
53
|
+
sort_order: 'desc',
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const article = await cms.getArticle('getting-started', 'en')
|
|
57
|
+
|
|
58
|
+
const searchPage = await cms.searchArticles({
|
|
59
|
+
q: 'privacy',
|
|
60
|
+
locale: 'en',
|
|
61
|
+
page: 1,
|
|
62
|
+
page_size: 5,
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
console.log(articlePage.pagination.total, article.title, searchPage.data.length)
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Related article and taxonomy helpers are available when the consuming app needs more content context.
|
|
12
70
|
|
|
13
71
|
```typescript
|
|
14
72
|
import { createCmsClient } from '@vigilkids/cms-client'
|
|
15
73
|
|
|
16
74
|
const cms = createCmsClient({
|
|
17
|
-
baseUrl: 'https://api.example.com',
|
|
18
|
-
|
|
75
|
+
baseUrl: 'https://api.example.com/api/v1/cms',
|
|
76
|
+
defaultLocale: 'en',
|
|
19
77
|
})
|
|
20
78
|
|
|
21
|
-
|
|
22
|
-
const
|
|
79
|
+
export async function loadArticleContext(slug: string): Promise<void> {
|
|
80
|
+
const related = await cms.getRelatedArticles(slug, { limit: 3, locale: 'en' })
|
|
81
|
+
const categories = await cms.getCategories()
|
|
23
82
|
|
|
24
|
-
|
|
25
|
-
|
|
83
|
+
console.log(related.map(article => article.slug), categories.length)
|
|
84
|
+
}
|
|
26
85
|
```
|
|
27
86
|
|
|
87
|
+
## Sitemap
|
|
88
|
+
|
|
89
|
+
Use `getSitemap` to retrieve CMS-managed sitemap entries, including optional route parameters, hreflang entries, and image metadata.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import type { SitemapEntry } from '@vigilkids/cms-client'
|
|
93
|
+
import { createCmsClient } from '@vigilkids/cms-client'
|
|
94
|
+
|
|
95
|
+
const cms = createCmsClient({
|
|
96
|
+
baseUrl: 'https://api.example.com/api/v1/cms',
|
|
97
|
+
defaultLocale: 'en',
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
export async function loadSitemap(): Promise<SitemapEntry[]> {
|
|
101
|
+
const entries = await cms.getSitemap('en')
|
|
102
|
+
return entries.filter(entry => entry.loc.startsWith('https://'))
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Webhook Verification
|
|
107
|
+
|
|
108
|
+
Import webhook helpers from the webhook entry point. Verification uses HMAC-SHA256 and expects a signature formatted as `sha256=<hex>`.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import type { RevalidatePayload } from '@vigilkids/cms-client'
|
|
112
|
+
import { verifyWebhookSignature } from '@vigilkids/cms-client/webhook'
|
|
113
|
+
|
|
114
|
+
export function parseCmsWebhook(
|
|
115
|
+
rawBody: string,
|
|
116
|
+
signature: string,
|
|
117
|
+
secret: string,
|
|
118
|
+
): RevalidatePayload {
|
|
119
|
+
const verified = verifyWebhookSignature({
|
|
120
|
+
rawBody,
|
|
121
|
+
signature,
|
|
122
|
+
secret,
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
if (!verified) {
|
|
126
|
+
throw new Error('Invalid CMS webhook signature')
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return JSON.parse(rawBody) as RevalidatePayload
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Client Methods
|
|
134
|
+
|
|
135
|
+
| Area | Methods |
|
|
136
|
+
|------|---------|
|
|
137
|
+
| Articles | `getArticles`, `getArticle`, `getRelatedArticles`, `searchArticles` |
|
|
138
|
+
| Authors | `getAuthorsPage`, `getAuthors`, `getAuthor`, `getAuthorArticlesPage`, `getAuthorArticles` |
|
|
139
|
+
| Categories | `getCategories` |
|
|
140
|
+
| Comments | `getComments`, `createComment` |
|
|
141
|
+
| Sitemap, redirects, series | `getSitemap`, `getRedirects`, `getSeries` |
|
|
142
|
+
|
|
28
143
|
## Exports
|
|
29
144
|
|
|
30
145
|
| Entry Point | Import | Content |
|
|
31
146
|
|-------------|--------|---------|
|
|
32
|
-
| Main | `@vigilkids/cms-client` |
|
|
33
|
-
| Types | `@vigilkids/cms-client/types` |
|
|
34
|
-
| Webhook | `@vigilkids/cms-client/webhook` |
|
|
147
|
+
| Main | `@vigilkids/cms-client` | `CmsClient`, `createCmsClient`, `CmsApiError`, `CmsClientConfig`, and all public request/response types |
|
|
148
|
+
| Types | `@vigilkids/cms-client/types` | Public CMS request/response type definitions |
|
|
149
|
+
| Webhook | `@vigilkids/cms-client/webhook` | `verifyWebhookSignature` and `VerifyWebhookOptions` |
|
|
150
|
+
|
|
151
|
+
## Error Handling
|
|
152
|
+
|
|
153
|
+
`CmsApiError` is thrown for non-2xx API responses.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { CmsApiError, createCmsClient } from '@vigilkids/cms-client'
|
|
157
|
+
|
|
158
|
+
const cms = createCmsClient({
|
|
159
|
+
baseUrl: 'https://api.example.com/api/v1/cms',
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
export async function loadRequiredArticle(slug: string): Promise<string> {
|
|
163
|
+
try {
|
|
164
|
+
const article = await cms.getArticle(slug)
|
|
165
|
+
return article.title
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (error instanceof CmsApiError && error.isNotFound) {
|
|
169
|
+
return 'Article not found'
|
|
170
|
+
}
|
|
171
|
+
throw error
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
35
175
|
|
|
36
176
|
## Compatibility
|
|
37
177
|
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
178
|
+
- ESM package.
|
|
179
|
+
- Main client requires a fetch-compatible runtime. Node.js 18+ provides `globalThis.fetch`; other runtimes can pass `fetch` in the client configuration.
|
|
180
|
+
- `@vigilkids/cms-client/webhook` uses Node.js `crypto` and `Buffer`, so signature verification should run in a server runtime.
|
|
181
|
+
- TypeScript declarations are included with the package.
|
|
41
182
|
|
|
42
183
|
## License
|
|
43
184
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ArticleListParams, Paginated, ArticleListItem, ArticleDetail, PaginationParams, Author, CategoryNode, Comment, CreateCommentPayload, SitemapEntry, RedirectRule, Series } from './types.mjs';
|
|
2
|
-
export { HreflangEntry, ListResponse, LocalizedString, OgMeta, PaginationMeta, RevalidatePayload, SeoMeta, TwitterMeta, WebhookEventType } from './types.mjs';
|
|
1
|
+
import { ArticleListParams, Paginated, ArticleListItem, ArticleDetail, ArticleSearchParams, ArticleSearchResultItem, PaginationParams, Author, CategoryNode, Comment, CreateCommentPayload, SitemapEntry, RedirectRule, Series } from './types.mjs';
|
|
2
|
+
export { HreflangEntry, ListResponse, LocalizedString, OgMeta, PaginationMeta, RevalidatePayload, SeoMeta, SitemapImageEntry, TwitterMeta, WebhookEventType } from './types.mjs';
|
|
3
3
|
|
|
4
4
|
/** CMS 客户端配置 */
|
|
5
5
|
interface CmsClientConfig {
|
|
@@ -33,6 +33,8 @@ declare class CmsClient {
|
|
|
33
33
|
limit?: number;
|
|
34
34
|
locale?: string;
|
|
35
35
|
}): Promise<ArticleListItem[]>;
|
|
36
|
+
/** 搜索已发布文章 */
|
|
37
|
+
searchArticles(params: ArticleSearchParams): Promise<Paginated<ArticleSearchResultItem>>;
|
|
36
38
|
/** 获取作者分页列表 */
|
|
37
39
|
getAuthorsPage(options?: {
|
|
38
40
|
locale?: string;
|
|
@@ -84,5 +86,5 @@ declare class CmsApiError extends Error {
|
|
|
84
86
|
get isUnauthorized(): boolean;
|
|
85
87
|
}
|
|
86
88
|
|
|
87
|
-
export { ArticleDetail, ArticleListItem, ArticleListParams, Author, CategoryNode, CmsApiError, CmsClient, Comment, CreateCommentPayload, Paginated, PaginationParams, RedirectRule, Series, SitemapEntry, createCmsClient };
|
|
89
|
+
export { ArticleDetail, ArticleListItem, ArticleListParams, ArticleSearchParams, ArticleSearchResultItem, Author, CategoryNode, CmsApiError, CmsClient, Comment, CreateCommentPayload, Paginated, PaginationParams, RedirectRule, Series, SitemapEntry, createCmsClient };
|
|
88
90
|
export type { CmsClientConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ArticleListParams, Paginated, ArticleListItem, ArticleDetail, PaginationParams, Author, CategoryNode, Comment, CreateCommentPayload, SitemapEntry, RedirectRule, Series } from './types.js';
|
|
2
|
-
export { HreflangEntry, ListResponse, LocalizedString, OgMeta, PaginationMeta, RevalidatePayload, SeoMeta, TwitterMeta, WebhookEventType } from './types.js';
|
|
1
|
+
import { ArticleListParams, Paginated, ArticleListItem, ArticleDetail, ArticleSearchParams, ArticleSearchResultItem, PaginationParams, Author, CategoryNode, Comment, CreateCommentPayload, SitemapEntry, RedirectRule, Series } from './types.js';
|
|
2
|
+
export { HreflangEntry, ListResponse, LocalizedString, OgMeta, PaginationMeta, RevalidatePayload, SeoMeta, SitemapImageEntry, TwitterMeta, WebhookEventType } from './types.js';
|
|
3
3
|
|
|
4
4
|
/** CMS 客户端配置 */
|
|
5
5
|
interface CmsClientConfig {
|
|
@@ -33,6 +33,8 @@ declare class CmsClient {
|
|
|
33
33
|
limit?: number;
|
|
34
34
|
locale?: string;
|
|
35
35
|
}): Promise<ArticleListItem[]>;
|
|
36
|
+
/** 搜索已发布文章 */
|
|
37
|
+
searchArticles(params: ArticleSearchParams): Promise<Paginated<ArticleSearchResultItem>>;
|
|
36
38
|
/** 获取作者分页列表 */
|
|
37
39
|
getAuthorsPage(options?: {
|
|
38
40
|
locale?: string;
|
|
@@ -84,5 +86,5 @@ declare class CmsApiError extends Error {
|
|
|
84
86
|
get isUnauthorized(): boolean;
|
|
85
87
|
}
|
|
86
88
|
|
|
87
|
-
export { ArticleDetail, ArticleListItem, ArticleListParams, Author, CategoryNode, CmsApiError, CmsClient, Comment, CreateCommentPayload, Paginated, PaginationParams, RedirectRule, Series, SitemapEntry, createCmsClient };
|
|
89
|
+
export { ArticleDetail, ArticleListItem, ArticleListParams, ArticleSearchParams, ArticleSearchResultItem, Author, CategoryNode, CmsApiError, CmsClient, Comment, CreateCommentPayload, Paginated, PaginationParams, RedirectRule, Series, SitemapEntry, createCmsClient };
|
|
88
90
|
export type { CmsClientConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -32,6 +32,23 @@ function parseApiErrorEnvelope(body) {
|
|
|
32
32
|
}
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
35
|
+
function normalizeListResponse(body, endpoint) {
|
|
36
|
+
if (Array.isArray(body)) {
|
|
37
|
+
return body;
|
|
38
|
+
}
|
|
39
|
+
if (typeof body === "object" && body !== null && "data" in body) {
|
|
40
|
+
const data = body.data;
|
|
41
|
+
if (Array.isArray(data)) {
|
|
42
|
+
return data;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
throw new CmsApiError(
|
|
46
|
+
500,
|
|
47
|
+
"INVALID_LIST_RESPONSE",
|
|
48
|
+
`CMS API returned invalid list response for ${endpoint}`,
|
|
49
|
+
body
|
|
50
|
+
);
|
|
51
|
+
}
|
|
35
52
|
class CmsClient {
|
|
36
53
|
config;
|
|
37
54
|
fetchFn;
|
|
@@ -54,12 +71,21 @@ class CmsClient {
|
|
|
54
71
|
}
|
|
55
72
|
/** 获取相关文章 */
|
|
56
73
|
async getRelatedArticles(slug, options) {
|
|
74
|
+
const endpoint = `/articles/${encodeURIComponent(slug)}/related`;
|
|
57
75
|
const result = await this.request(
|
|
58
76
|
"GET",
|
|
59
|
-
|
|
77
|
+
endpoint,
|
|
60
78
|
options
|
|
61
79
|
);
|
|
62
|
-
return result
|
|
80
|
+
return normalizeListResponse(result, endpoint);
|
|
81
|
+
}
|
|
82
|
+
/** 搜索已发布文章 */
|
|
83
|
+
async searchArticles(params) {
|
|
84
|
+
return this.request(
|
|
85
|
+
"GET",
|
|
86
|
+
"/search",
|
|
87
|
+
params
|
|
88
|
+
);
|
|
63
89
|
}
|
|
64
90
|
// ─── 作者 ───────────────────────────────────────────
|
|
65
91
|
/** 获取作者分页列表 */
|
|
@@ -69,7 +95,7 @@ class CmsClient {
|
|
|
69
95
|
/** 获取所有作者 */
|
|
70
96
|
async getAuthors(options) {
|
|
71
97
|
const result = await this.getAuthorsPage(options);
|
|
72
|
-
return result
|
|
98
|
+
return normalizeListResponse(result, "/authors");
|
|
73
99
|
}
|
|
74
100
|
/** 获取作者详情 */
|
|
75
101
|
async getAuthor(slug, locale) {
|
|
@@ -86,13 +112,19 @@ class CmsClient {
|
|
|
86
112
|
/** 获取作者的文章列表 */
|
|
87
113
|
async getAuthorArticles(slug, options) {
|
|
88
114
|
const result = await this.getAuthorArticlesPage(slug, options);
|
|
89
|
-
return
|
|
115
|
+
return normalizeListResponse(
|
|
116
|
+
result,
|
|
117
|
+
`/authors/${encodeURIComponent(slug)}/articles`
|
|
118
|
+
);
|
|
90
119
|
}
|
|
91
120
|
// ─── 分类 ───────────────────────────────────────────
|
|
92
121
|
/** 获取分类树 */
|
|
93
122
|
async getCategories() {
|
|
94
|
-
const result = await this.request(
|
|
95
|
-
|
|
123
|
+
const result = await this.request(
|
|
124
|
+
"GET",
|
|
125
|
+
"/categories"
|
|
126
|
+
);
|
|
127
|
+
return normalizeListResponse(result, "/categories");
|
|
96
128
|
}
|
|
97
129
|
// ─── 评论 ───────────────────────────────────────────
|
|
98
130
|
/** 获取文章评论树 */
|
|
@@ -111,13 +143,20 @@ class CmsClient {
|
|
|
111
143
|
// ─── Sitemap / 重定向 / 系列 ──────────────────────
|
|
112
144
|
/** 获取 Sitemap 条目 */
|
|
113
145
|
async getSitemap(locale) {
|
|
114
|
-
const result = await this.request(
|
|
115
|
-
|
|
146
|
+
const result = await this.request(
|
|
147
|
+
"GET",
|
|
148
|
+
"/sitemap",
|
|
149
|
+
{ locale }
|
|
150
|
+
);
|
|
151
|
+
return normalizeListResponse(result, "/sitemap");
|
|
116
152
|
}
|
|
117
153
|
/** 获取重定向规则 */
|
|
118
154
|
async getRedirects() {
|
|
119
|
-
const result = await this.request(
|
|
120
|
-
|
|
155
|
+
const result = await this.request(
|
|
156
|
+
"GET",
|
|
157
|
+
"/redirects"
|
|
158
|
+
);
|
|
159
|
+
return normalizeListResponse(result, "/redirects");
|
|
121
160
|
}
|
|
122
161
|
/** 获取文章系列 */
|
|
123
162
|
async getSeries(slug, locale) {
|
package/dist/types.d.mts
CHANGED
|
@@ -81,6 +81,29 @@ interface ArticleListParams extends PaginationParams {
|
|
|
81
81
|
category_slug?: string;
|
|
82
82
|
tag?: string;
|
|
83
83
|
is_pinned?: boolean;
|
|
84
|
+
sort_by?: string;
|
|
85
|
+
sort_order?: 'asc' | 'desc';
|
|
86
|
+
}
|
|
87
|
+
/** 文章搜索查询参数 */
|
|
88
|
+
interface ArticleSearchParams extends PaginationParams {
|
|
89
|
+
locale?: string;
|
|
90
|
+
q: string;
|
|
91
|
+
}
|
|
92
|
+
/** 文章搜索结果项 */
|
|
93
|
+
interface ArticleSearchResultItem {
|
|
94
|
+
article_id: number;
|
|
95
|
+
title: string;
|
|
96
|
+
excerpt?: string;
|
|
97
|
+
slug: string;
|
|
98
|
+
score: number;
|
|
99
|
+
category_slug?: string;
|
|
100
|
+
featured_image_url?: string;
|
|
101
|
+
featured_image_alt?: string;
|
|
102
|
+
published_at?: string | null;
|
|
103
|
+
last_published_at?: string | null;
|
|
104
|
+
reading_time_minutes?: number;
|
|
105
|
+
tags?: string[];
|
|
106
|
+
authors?: Author[];
|
|
84
107
|
}
|
|
85
108
|
/** SEO 元信息 */
|
|
86
109
|
interface SeoMeta {
|
|
@@ -157,14 +180,23 @@ interface Series {
|
|
|
157
180
|
interface HreflangEntry {
|
|
158
181
|
lang: string;
|
|
159
182
|
href: string;
|
|
183
|
+
route_params?: Record<string, string | number | boolean | null | undefined>;
|
|
184
|
+
}
|
|
185
|
+
/** Sitemap 图片条目 */
|
|
186
|
+
interface SitemapImageEntry {
|
|
187
|
+
loc: string;
|
|
188
|
+
title?: string;
|
|
160
189
|
}
|
|
161
190
|
/** Sitemap 条目 (Go: delivery.SitemapEntryResponse) */
|
|
162
191
|
interface SitemapEntry {
|
|
163
192
|
loc: string;
|
|
193
|
+
resource_type?: string;
|
|
194
|
+
route_params?: Record<string, string | number | boolean | null | undefined>;
|
|
164
195
|
last_mod: string;
|
|
165
196
|
change_freq: string;
|
|
166
197
|
priority: number;
|
|
167
198
|
hreflang?: HreflangEntry[];
|
|
199
|
+
images?: SitemapImageEntry[];
|
|
168
200
|
}
|
|
169
201
|
|
|
170
202
|
/** Webhook 事件类型 */
|
|
@@ -177,4 +209,4 @@ interface RevalidatePayload {
|
|
|
177
209
|
category_slug?: string;
|
|
178
210
|
}
|
|
179
211
|
|
|
180
|
-
export type { ArticleDetail, ArticleListItem, ArticleListParams, Author, CategoryNode, Comment, CreateCommentPayload, HreflangEntry, ListResponse, LocalizedString, OgMeta, Paginated, PaginationMeta, PaginationParams, RedirectRule, RevalidatePayload, SeoMeta, Series, SitemapEntry, TwitterMeta, WebhookEventType };
|
|
212
|
+
export type { ArticleDetail, ArticleListItem, ArticleListParams, ArticleSearchParams, ArticleSearchResultItem, Author, CategoryNode, Comment, CreateCommentPayload, HreflangEntry, ListResponse, LocalizedString, OgMeta, Paginated, PaginationMeta, PaginationParams, RedirectRule, RevalidatePayload, SeoMeta, Series, SitemapEntry, SitemapImageEntry, TwitterMeta, WebhookEventType };
|
package/dist/types.d.ts
CHANGED
|
@@ -81,6 +81,29 @@ interface ArticleListParams extends PaginationParams {
|
|
|
81
81
|
category_slug?: string;
|
|
82
82
|
tag?: string;
|
|
83
83
|
is_pinned?: boolean;
|
|
84
|
+
sort_by?: string;
|
|
85
|
+
sort_order?: 'asc' | 'desc';
|
|
86
|
+
}
|
|
87
|
+
/** 文章搜索查询参数 */
|
|
88
|
+
interface ArticleSearchParams extends PaginationParams {
|
|
89
|
+
locale?: string;
|
|
90
|
+
q: string;
|
|
91
|
+
}
|
|
92
|
+
/** 文章搜索结果项 */
|
|
93
|
+
interface ArticleSearchResultItem {
|
|
94
|
+
article_id: number;
|
|
95
|
+
title: string;
|
|
96
|
+
excerpt?: string;
|
|
97
|
+
slug: string;
|
|
98
|
+
score: number;
|
|
99
|
+
category_slug?: string;
|
|
100
|
+
featured_image_url?: string;
|
|
101
|
+
featured_image_alt?: string;
|
|
102
|
+
published_at?: string | null;
|
|
103
|
+
last_published_at?: string | null;
|
|
104
|
+
reading_time_minutes?: number;
|
|
105
|
+
tags?: string[];
|
|
106
|
+
authors?: Author[];
|
|
84
107
|
}
|
|
85
108
|
/** SEO 元信息 */
|
|
86
109
|
interface SeoMeta {
|
|
@@ -157,14 +180,23 @@ interface Series {
|
|
|
157
180
|
interface HreflangEntry {
|
|
158
181
|
lang: string;
|
|
159
182
|
href: string;
|
|
183
|
+
route_params?: Record<string, string | number | boolean | null | undefined>;
|
|
184
|
+
}
|
|
185
|
+
/** Sitemap 图片条目 */
|
|
186
|
+
interface SitemapImageEntry {
|
|
187
|
+
loc: string;
|
|
188
|
+
title?: string;
|
|
160
189
|
}
|
|
161
190
|
/** Sitemap 条目 (Go: delivery.SitemapEntryResponse) */
|
|
162
191
|
interface SitemapEntry {
|
|
163
192
|
loc: string;
|
|
193
|
+
resource_type?: string;
|
|
194
|
+
route_params?: Record<string, string | number | boolean | null | undefined>;
|
|
164
195
|
last_mod: string;
|
|
165
196
|
change_freq: string;
|
|
166
197
|
priority: number;
|
|
167
198
|
hreflang?: HreflangEntry[];
|
|
199
|
+
images?: SitemapImageEntry[];
|
|
168
200
|
}
|
|
169
201
|
|
|
170
202
|
/** Webhook 事件类型 */
|
|
@@ -177,4 +209,4 @@ interface RevalidatePayload {
|
|
|
177
209
|
category_slug?: string;
|
|
178
210
|
}
|
|
179
211
|
|
|
180
|
-
export type { ArticleDetail, ArticleListItem, ArticleListParams, Author, CategoryNode, Comment, CreateCommentPayload, HreflangEntry, ListResponse, LocalizedString, OgMeta, Paginated, PaginationMeta, PaginationParams, RedirectRule, RevalidatePayload, SeoMeta, Series, SitemapEntry, TwitterMeta, WebhookEventType };
|
|
212
|
+
export type { ArticleDetail, ArticleListItem, ArticleListParams, ArticleSearchParams, ArticleSearchResultItem, Author, CategoryNode, Comment, CreateCommentPayload, HreflangEntry, ListResponse, LocalizedString, OgMeta, Paginated, PaginationMeta, PaginationParams, RedirectRule, RevalidatePayload, SeoMeta, Series, SitemapEntry, SitemapImageEntry, TwitterMeta, WebhookEventType };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vigilkids/cms-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Framework-agnostic TypeScript client for OnEx CMS Public API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
|
-
"dist"
|
|
23
|
+
"dist",
|
|
24
|
+
"CHANGELOG.md"
|
|
24
25
|
],
|
|
25
26
|
"sideEffects": false,
|
|
26
27
|
"scripts": {
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
},
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|
|
37
|
-
"url": "git+https://github.com/
|
|
38
|
+
"url": "git+https://github.com/vigikids/onex.git",
|
|
38
39
|
"directory": "packages/cms-client"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|