@stackonward/cms-client 0.0.1
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 +9 -0
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/dist/index.d.mts +86 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.mjs +221 -0
- package/dist/routes.d.mts +54 -0
- package/dist/routes.d.ts +54 -0
- package/dist/routes.mjs +148 -0
- package/dist/types.d.mts +311 -0
- package/dist/types.d.ts +311 -0
- package/dist/types.mjs +1 -0
- package/dist/webhook.d.mts +10 -0
- package/dist/webhook.d.ts +10 -0
- package/dist/webhook.mjs +14 -0
- package/package.json +74 -0
package/dist/routes.mjs
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
const DEFAULT_ROUTE_RESOURCES = {
|
|
2
|
+
index: "/",
|
|
3
|
+
category: "/{category_slug}",
|
|
4
|
+
article: "/{category_slug}/{slug}",
|
|
5
|
+
author: "/authors/{slug}"
|
|
6
|
+
};
|
|
7
|
+
function trimSlashes(value) {
|
|
8
|
+
return value.replace(/^\/+|\/+$/g, "");
|
|
9
|
+
}
|
|
10
|
+
function normalizePath(path) {
|
|
11
|
+
const clean = path.split("?")[0]?.split("#")[0] ?? "";
|
|
12
|
+
const withSlash = clean.startsWith("/") ? clean : `/${clean}`;
|
|
13
|
+
const collapsed = withSlash.replace(/\/{2,}/g, "/");
|
|
14
|
+
if (collapsed.length > 1) return collapsed.replace(/\/+$/g, "");
|
|
15
|
+
return collapsed;
|
|
16
|
+
}
|
|
17
|
+
function encodePathValue(value) {
|
|
18
|
+
return encodeURIComponent(String(value));
|
|
19
|
+
}
|
|
20
|
+
function isPlainObject(value) {
|
|
21
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22
|
+
}
|
|
23
|
+
function isStringRecord(value) {
|
|
24
|
+
if (!isPlainObject(value)) return false;
|
|
25
|
+
return Object.values(value).every((item) => typeof item === "string");
|
|
26
|
+
}
|
|
27
|
+
function localePrefix(locale, policy) {
|
|
28
|
+
if (!locale) return "";
|
|
29
|
+
if (locale === policy.defaultLocale && !policy.includeDefaultLocale) return "";
|
|
30
|
+
const prefix = policy.prefixes[locale] ?? locale.toLowerCase();
|
|
31
|
+
return `/${trimSlashes(prefix)}`;
|
|
32
|
+
}
|
|
33
|
+
function mergeResources(resources) {
|
|
34
|
+
return {
|
|
35
|
+
...DEFAULT_ROUTE_RESOURCES,
|
|
36
|
+
...resources ?? {}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function resolveRoutePolicy(config) {
|
|
40
|
+
const routes = config?.routes ?? {};
|
|
41
|
+
const defaultLocale = routes.locale?.defaultLocale ?? config?.defaultLocale ?? "en";
|
|
42
|
+
const prefixes = {
|
|
43
|
+
...config?.localePrefixes ?? {},
|
|
44
|
+
...routes.locale?.prefixes ?? {}
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
resources: mergeResources(routes.resources),
|
|
48
|
+
sourceResources: mergeResources(routes.sourceResources),
|
|
49
|
+
locale: {
|
|
50
|
+
defaultLocale,
|
|
51
|
+
prefixes,
|
|
52
|
+
includeDefaultLocale: routes.locale?.includeDefaultLocale ?? false
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function buildRoutePath(policy, resource, params = {}, options = {}) {
|
|
57
|
+
const resolvedPolicy = resolveRoutePolicy({ routes: policy });
|
|
58
|
+
const pattern = resolvedPolicy.resources[resource];
|
|
59
|
+
if (!pattern) {
|
|
60
|
+
throw new Error(`CMS route pattern is not configured for resource '${resource}'`);
|
|
61
|
+
}
|
|
62
|
+
const path = normalizePath(
|
|
63
|
+
pattern.replace(/\{(\w+)\}/g, (_, key) => {
|
|
64
|
+
const value = params[key];
|
|
65
|
+
if (value === void 0 || value === null || value === "") {
|
|
66
|
+
throw new Error(`CMS route parameter '${key}' is required for resource '${resource}'`);
|
|
67
|
+
}
|
|
68
|
+
return encodePathValue(value);
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
if (!options.includeLocale) return path;
|
|
72
|
+
return normalizePath(`${localePrefix(String(params.locale ?? ""), resolvedPolicy.locale)}${path}`);
|
|
73
|
+
}
|
|
74
|
+
function buildRouteUrl(baseUrl, policy, resource, params = {}, options = {}) {
|
|
75
|
+
const path = buildRoutePath(policy ?? {}, resource, params, options);
|
|
76
|
+
const normalizedBaseUrl = baseUrl.replace(/\/+$/g, "");
|
|
77
|
+
return normalizedBaseUrl ? `${normalizedBaseUrl}${path}` : path;
|
|
78
|
+
}
|
|
79
|
+
function isRoutePolicy(value) {
|
|
80
|
+
if (!isPlainObject(value)) return false;
|
|
81
|
+
const { locale, resources, sourceResources } = value;
|
|
82
|
+
if (resources !== void 0 && !isStringRecord(resources)) return false;
|
|
83
|
+
if (sourceResources !== void 0 && !isStringRecord(sourceResources)) return false;
|
|
84
|
+
if (locale !== void 0) {
|
|
85
|
+
if (!isPlainObject(locale)) return false;
|
|
86
|
+
if (locale.defaultLocale !== void 0 && typeof locale.defaultLocale !== "string") return false;
|
|
87
|
+
if (locale.includeDefaultLocale !== void 0 && typeof locale.includeDefaultLocale !== "boolean") {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (locale.prefixes !== void 0 && !isStringRecord(locale.prefixes)) return false;
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
function hasCustomArticleRoute(policy) {
|
|
95
|
+
return resolveRoutePolicy({ routes: policy ?? void 0 }).resources.article !== DEFAULT_ROUTE_RESOURCES.article;
|
|
96
|
+
}
|
|
97
|
+
function formatRoutePolicy(policy) {
|
|
98
|
+
return JSON.stringify(resolveRoutePolicy({ routes: policy ?? void 0 }), null, 2);
|
|
99
|
+
}
|
|
100
|
+
function extractRouteParams(pattern, path) {
|
|
101
|
+
const keys = [];
|
|
102
|
+
const source = normalizePath(pattern);
|
|
103
|
+
let expression = "^";
|
|
104
|
+
for (let index = 0; index < source.length; index++) {
|
|
105
|
+
const char = source[index];
|
|
106
|
+
if (char === "{") {
|
|
107
|
+
const closeIndex = source.indexOf("}", index);
|
|
108
|
+
if (closeIndex > index) {
|
|
109
|
+
const key = source.slice(index + 1, closeIndex);
|
|
110
|
+
keys.push(key);
|
|
111
|
+
expression += "([^/]+)";
|
|
112
|
+
index = closeIndex;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
expression += char.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
117
|
+
}
|
|
118
|
+
expression += "$";
|
|
119
|
+
const match = normalizePath(path).match(new RegExp(expression));
|
|
120
|
+
if (!match) return null;
|
|
121
|
+
const params = {};
|
|
122
|
+
for (let index = 0; index < keys.length; index++) {
|
|
123
|
+
const raw = match[index + 1];
|
|
124
|
+
if (raw) params[keys[index]] = decodeURIComponent(raw);
|
|
125
|
+
}
|
|
126
|
+
return params;
|
|
127
|
+
}
|
|
128
|
+
function extractSourceRouteParams(policy, resource, path) {
|
|
129
|
+
const resolvedPolicy = resolveRoutePolicy({ routes: policy });
|
|
130
|
+
const candidates = [
|
|
131
|
+
resolvedPolicy.sourceResources[resource],
|
|
132
|
+
resolvedPolicy.resources[resource],
|
|
133
|
+
DEFAULT_ROUTE_RESOURCES[resource]
|
|
134
|
+
].filter((pattern) => Boolean(pattern));
|
|
135
|
+
for (const pattern of candidates) {
|
|
136
|
+
const params = extractRouteParams(pattern, path);
|
|
137
|
+
if (params) return params;
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
function mergeRouteParams(left, right) {
|
|
142
|
+
return {
|
|
143
|
+
...left ?? {},
|
|
144
|
+
...right ?? {}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export { DEFAULT_ROUTE_RESOURCES, buildRoutePath, buildRouteUrl, extractRouteParams, extractSourceRouteParams, formatRoutePolicy, hasCustomArticleRoute, isRoutePolicy, mergeRouteParams, resolveRoutePolicy };
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { RoutePolicy } from './routes.mjs';
|
|
2
|
+
export { BuildRoutePathOptions, ResolvedRouteLocalePolicy, ResolvedRoutePolicy, RouteLocalePolicy, RouteParams, RoutePolicyConfig, RouteResourceDefaults, RouteResources } from './routes.mjs';
|
|
3
|
+
|
|
4
|
+
/** 作者社交链接 */
|
|
5
|
+
interface AuthorSocialLink {
|
|
6
|
+
kind?: string;
|
|
7
|
+
label: string;
|
|
8
|
+
href: string;
|
|
9
|
+
handle?: string;
|
|
10
|
+
}
|
|
11
|
+
/** 作者资料统计项 */
|
|
12
|
+
interface AuthorProfileStat {
|
|
13
|
+
label: string;
|
|
14
|
+
value: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
}
|
|
17
|
+
/** 作者资料问答项 */
|
|
18
|
+
interface AuthorProfileQuestion {
|
|
19
|
+
label?: string;
|
|
20
|
+
text: string;
|
|
21
|
+
}
|
|
22
|
+
/** 作者资料内容分区 */
|
|
23
|
+
interface AuthorProfileSection {
|
|
24
|
+
key: string;
|
|
25
|
+
eyebrow: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
paragraphs?: string[];
|
|
28
|
+
questions?: AuthorProfileQuestion[];
|
|
29
|
+
}
|
|
30
|
+
/** 作者资料行动入口 */
|
|
31
|
+
interface AuthorProfileCta {
|
|
32
|
+
label: string;
|
|
33
|
+
href: string;
|
|
34
|
+
title?: string;
|
|
35
|
+
description?: string;
|
|
36
|
+
}
|
|
37
|
+
/** 作者资料内容 */
|
|
38
|
+
interface AuthorProfile {
|
|
39
|
+
eyebrow?: string;
|
|
40
|
+
role?: string;
|
|
41
|
+
role_line?: string;
|
|
42
|
+
lede?: string;
|
|
43
|
+
socials?: AuthorSocialLink[];
|
|
44
|
+
stats?: AuthorProfileStat[];
|
|
45
|
+
sections?: AuthorProfileSection[];
|
|
46
|
+
tags?: string[];
|
|
47
|
+
cta?: AuthorProfileCta;
|
|
48
|
+
}
|
|
49
|
+
/** 作者信息 (Go: delivery.DeliveryAuthorResponse) */
|
|
50
|
+
interface Author {
|
|
51
|
+
id: number;
|
|
52
|
+
locale: string;
|
|
53
|
+
display_name: string;
|
|
54
|
+
slug: string;
|
|
55
|
+
avatar_url?: string;
|
|
56
|
+
bio?: string;
|
|
57
|
+
seo_meta?: Partial<SeoMeta>;
|
|
58
|
+
og_meta?: Partial<OgMeta>;
|
|
59
|
+
twitter_meta?: Partial<TwitterMeta>;
|
|
60
|
+
available_locales?: string[];
|
|
61
|
+
localized_slugs?: Record<string, string>;
|
|
62
|
+
profile?: AuthorProfile;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** 多语言字符串 (Go: domain.LocalizedString = map[string]string) */
|
|
66
|
+
type LocalizedString = Record<string, string>;
|
|
67
|
+
/** 分页元信息 (Go: response.PaginationMeta) */
|
|
68
|
+
interface PaginationMeta {
|
|
69
|
+
page: number;
|
|
70
|
+
page_size: number;
|
|
71
|
+
total: number;
|
|
72
|
+
total_pages: number;
|
|
73
|
+
}
|
|
74
|
+
/** 分页响应 (Go: response.Paginated[T]) */
|
|
75
|
+
interface Paginated<T> {
|
|
76
|
+
data: T[];
|
|
77
|
+
pagination: PaginationMeta;
|
|
78
|
+
}
|
|
79
|
+
/** 列表响应 (Go: response.NewList[T]) */
|
|
80
|
+
type ListResponse<T> = Paginated<T>;
|
|
81
|
+
/** 分页查询参数 */
|
|
82
|
+
interface PaginationParams {
|
|
83
|
+
page?: number;
|
|
84
|
+
page_size?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 文章详情 (Go: delivery.DeliveryArticleResponse) */
|
|
88
|
+
interface ArticleDetail {
|
|
89
|
+
slug: string;
|
|
90
|
+
title: string;
|
|
91
|
+
excerpt?: string;
|
|
92
|
+
content_html: string;
|
|
93
|
+
content_json?: unknown;
|
|
94
|
+
featured_image_url?: string;
|
|
95
|
+
featured_image_alt?: string;
|
|
96
|
+
category?: string;
|
|
97
|
+
tags: string[];
|
|
98
|
+
authors: Author[];
|
|
99
|
+
related_article_ids?: number[];
|
|
100
|
+
comment_count: number;
|
|
101
|
+
is_comment_enabled: boolean;
|
|
102
|
+
published_at: string | null;
|
|
103
|
+
last_published_at: string | null;
|
|
104
|
+
word_count: number;
|
|
105
|
+
reading_time_minutes: number;
|
|
106
|
+
seo_meta?: SeoMeta;
|
|
107
|
+
og_meta?: OgMeta;
|
|
108
|
+
twitter_meta?: TwitterMeta;
|
|
109
|
+
json_ld: unknown;
|
|
110
|
+
locale: string;
|
|
111
|
+
available_locales: string[];
|
|
112
|
+
localized_slugs?: Record<string, string>;
|
|
113
|
+
}
|
|
114
|
+
/** 文章列表项 (Go: delivery.DeliveryArticleListItem) */
|
|
115
|
+
interface ArticleListItem {
|
|
116
|
+
slug: string;
|
|
117
|
+
title: string;
|
|
118
|
+
excerpt?: string;
|
|
119
|
+
featured_image_url?: string;
|
|
120
|
+
featured_image_alt?: string;
|
|
121
|
+
published_at: string | null;
|
|
122
|
+
last_published_at?: string | null;
|
|
123
|
+
reading_time_minutes: number;
|
|
124
|
+
category_slug?: string;
|
|
125
|
+
is_pinned: boolean;
|
|
126
|
+
tags: string[];
|
|
127
|
+
authors: Author[];
|
|
128
|
+
}
|
|
129
|
+
/** 文章列表查询参数 */
|
|
130
|
+
interface ArticleListParams extends PaginationParams {
|
|
131
|
+
locale?: string;
|
|
132
|
+
category_id?: number;
|
|
133
|
+
category_slug?: string;
|
|
134
|
+
tag?: string;
|
|
135
|
+
is_pinned?: boolean;
|
|
136
|
+
sort_by?: string;
|
|
137
|
+
sort_order?: 'asc' | 'desc';
|
|
138
|
+
}
|
|
139
|
+
/** 文章搜索查询参数 */
|
|
140
|
+
interface ArticleSearchParams extends PaginationParams {
|
|
141
|
+
locale?: string;
|
|
142
|
+
q: string;
|
|
143
|
+
}
|
|
144
|
+
/** 文章搜索结果项 */
|
|
145
|
+
interface ArticleSearchResultItem {
|
|
146
|
+
article_id: number;
|
|
147
|
+
title: string;
|
|
148
|
+
excerpt?: string;
|
|
149
|
+
slug: string;
|
|
150
|
+
score: number;
|
|
151
|
+
category_slug?: string;
|
|
152
|
+
featured_image_url?: string;
|
|
153
|
+
featured_image_alt?: string;
|
|
154
|
+
published_at?: string | null;
|
|
155
|
+
last_published_at?: string | null;
|
|
156
|
+
reading_time_minutes?: number;
|
|
157
|
+
tags?: string[];
|
|
158
|
+
authors?: Author[];
|
|
159
|
+
}
|
|
160
|
+
/** SEO 元信息 */
|
|
161
|
+
interface SeoMeta {
|
|
162
|
+
title: string | null;
|
|
163
|
+
description: string | null;
|
|
164
|
+
keywords: string | null;
|
|
165
|
+
robots: string | null;
|
|
166
|
+
canonical_url: string | null;
|
|
167
|
+
}
|
|
168
|
+
/** Open Graph 元信息 */
|
|
169
|
+
interface OgMeta {
|
|
170
|
+
title: string | null;
|
|
171
|
+
description: string | null;
|
|
172
|
+
image: string | null;
|
|
173
|
+
url: string | null;
|
|
174
|
+
type: string | null;
|
|
175
|
+
}
|
|
176
|
+
/** Twitter Card 元信息 */
|
|
177
|
+
interface TwitterMeta {
|
|
178
|
+
card: string | null;
|
|
179
|
+
title: string | null;
|
|
180
|
+
description: string | null;
|
|
181
|
+
image: string | null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** 本地化 SEO 元信息 */
|
|
185
|
+
type LocalizedSeoMetaMap = Record<string, Partial<SeoMeta>>;
|
|
186
|
+
/** 本地化 Open Graph 元信息 */
|
|
187
|
+
type LocalizedOgMetaMap = Record<string, Partial<OgMeta>>;
|
|
188
|
+
/** 本地化 Twitter Card 元信息 */
|
|
189
|
+
type LocalizedTwitterMetaMap = Record<string, Partial<TwitterMeta>>;
|
|
190
|
+
/** 分类树节点 (Go: delivery.CategoryNodeResponse) */
|
|
191
|
+
interface CategoryNode {
|
|
192
|
+
id: number;
|
|
193
|
+
slug: string;
|
|
194
|
+
name: LocalizedString;
|
|
195
|
+
description: LocalizedString;
|
|
196
|
+
seo_meta?: LocalizedSeoMetaMap;
|
|
197
|
+
og_meta?: LocalizedOgMetaMap;
|
|
198
|
+
twitter_meta?: LocalizedTwitterMetaMap;
|
|
199
|
+
article_count: number;
|
|
200
|
+
article_counts?: Record<string, number>;
|
|
201
|
+
children?: CategoryNode[];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** 评论树节点 (Go: delivery.CommentTreeResponse) */
|
|
205
|
+
interface Comment {
|
|
206
|
+
id: number;
|
|
207
|
+
author_name: string;
|
|
208
|
+
author_url?: string;
|
|
209
|
+
content_html: string;
|
|
210
|
+
is_pinned: boolean;
|
|
211
|
+
like_count: number;
|
|
212
|
+
created_at: string;
|
|
213
|
+
children?: Comment[];
|
|
214
|
+
}
|
|
215
|
+
/** 发表评论请求 */
|
|
216
|
+
interface CreateCommentPayload {
|
|
217
|
+
author_name: string;
|
|
218
|
+
author_email: string;
|
|
219
|
+
content: string;
|
|
220
|
+
parent_id?: number;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** 重定向规则 (Go: delivery.RedirectRuleResponse) */
|
|
224
|
+
type RedirectMatchType = 'exact' | 'prefix' | 'regex';
|
|
225
|
+
interface RedirectRule {
|
|
226
|
+
source_path: string;
|
|
227
|
+
destination_path: string;
|
|
228
|
+
status_code: number;
|
|
229
|
+
match_type: RedirectMatchType;
|
|
230
|
+
priority: number;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** 文章系列 (Go: delivery.DeliverySeriesResponse) */
|
|
234
|
+
interface Series {
|
|
235
|
+
title: string;
|
|
236
|
+
slug: string;
|
|
237
|
+
description: string | null;
|
|
238
|
+
cover_image_url: string | null;
|
|
239
|
+
articles: ArticleListItem[];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
type SiteDeliveryMode = 'isr' | 'static';
|
|
243
|
+
type SiteDomainType = 'alias' | 'preview' | 'primary';
|
|
244
|
+
interface SiteDomain {
|
|
245
|
+
scheme: 'http' | 'https';
|
|
246
|
+
host: string;
|
|
247
|
+
port?: number;
|
|
248
|
+
base_path: string;
|
|
249
|
+
domain_type: SiteDomainType;
|
|
250
|
+
}
|
|
251
|
+
interface SiteConfig {
|
|
252
|
+
site_code: string;
|
|
253
|
+
product_code: string;
|
|
254
|
+
site_name: string;
|
|
255
|
+
delivery_mode: SiteDeliveryMode;
|
|
256
|
+
canonical_base_url: string;
|
|
257
|
+
domains: SiteDomain[];
|
|
258
|
+
sitemap_path: string;
|
|
259
|
+
route_policy: RoutePolicy;
|
|
260
|
+
updated_at: string;
|
|
261
|
+
}
|
|
262
|
+
interface SiteConfigQuery {
|
|
263
|
+
site_code?: string;
|
|
264
|
+
host?: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Hreflang 条目 (Go: delivery.HreflangEntry) */
|
|
268
|
+
interface HreflangEntry {
|
|
269
|
+
lang: string;
|
|
270
|
+
href: string;
|
|
271
|
+
route_params?: Record<string, string | number | boolean | null | undefined>;
|
|
272
|
+
}
|
|
273
|
+
/** Sitemap 图片条目 */
|
|
274
|
+
interface SitemapImageEntry {
|
|
275
|
+
loc: string;
|
|
276
|
+
title?: string;
|
|
277
|
+
}
|
|
278
|
+
/** Sitemap 视频条目(Google Video Sitemap 扩展) */
|
|
279
|
+
interface SitemapVideoEntry {
|
|
280
|
+
thumbnail_loc: string;
|
|
281
|
+
title: string;
|
|
282
|
+
description: string;
|
|
283
|
+
content_loc?: string;
|
|
284
|
+
player_loc?: string;
|
|
285
|
+
publication_date: string;
|
|
286
|
+
}
|
|
287
|
+
/** Sitemap 条目 (Go: delivery.SitemapEntryResponse) */
|
|
288
|
+
interface SitemapEntry {
|
|
289
|
+
loc: string;
|
|
290
|
+
resource_type?: string;
|
|
291
|
+
route_params?: Record<string, string | number | boolean | null | undefined>;
|
|
292
|
+
last_mod: string;
|
|
293
|
+
change_freq: string;
|
|
294
|
+
priority: number;
|
|
295
|
+
hreflang?: HreflangEntry[];
|
|
296
|
+
images?: SitemapImageEntry[];
|
|
297
|
+
videos?: SitemapVideoEntry[];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Webhook 事件类型 */
|
|
301
|
+
type WebhookEventType = 'article.published' | 'article.unpublished' | 'article.updated' | 'article.archived' | 'redirect.changed' | 'comment.approved';
|
|
302
|
+
/** ISR 重验证请求体 */
|
|
303
|
+
interface RevalidatePayload {
|
|
304
|
+
event: WebhookEventType;
|
|
305
|
+
slug: string;
|
|
306
|
+
locale: string;
|
|
307
|
+
category_slug?: string;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export { RoutePolicy };
|
|
311
|
+
export type { ArticleDetail, ArticleListItem, ArticleListParams, ArticleSearchParams, ArticleSearchResultItem, Author, AuthorProfile, AuthorProfileCta, AuthorProfileQuestion, AuthorProfileSection, AuthorProfileStat, AuthorSocialLink, CategoryNode, Comment, CreateCommentPayload, HreflangEntry, ListResponse, LocalizedOgMetaMap, LocalizedSeoMetaMap, LocalizedString, LocalizedTwitterMetaMap, OgMeta, Paginated, PaginationMeta, PaginationParams, RedirectMatchType, RedirectRule, RevalidatePayload, SeoMeta, Series, SiteConfig, SiteConfigQuery, SiteDeliveryMode, SiteDomain, SiteDomainType, SitemapEntry, SitemapImageEntry, SitemapVideoEntry, TwitterMeta, WebhookEventType };
|