@zlooks.cn/blog-server 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/dist/blog/blog-application.d.ts +153 -0
- package/dist/blog/blog-application.d.ts.map +1 -0
- package/dist/blog/blog-application.js +115 -0
- package/dist/blog/blog-application.js.map +1 -0
- package/dist/blog/comment-client-metadata.d.ts +19 -0
- package/dist/blog/comment-client-metadata.d.ts.map +1 -0
- package/dist/blog/comment-client-metadata.js +78 -0
- package/dist/blog/comment-client-metadata.js.map +1 -0
- package/dist/blog/errors.d.ts +12 -0
- package/dist/blog/errors.d.ts.map +1 -0
- package/dist/blog/errors.js +21 -0
- package/dist/blog/errors.js.map +1 -0
- package/dist/blog/micro-user-directory.d.ts +11 -0
- package/dist/blog/micro-user-directory.d.ts.map +1 -0
- package/dist/blog/micro-user-directory.js +18 -0
- package/dist/blog/micro-user-directory.js.map +1 -0
- package/dist/blog/post-content-audit.d.ts +34 -0
- package/dist/blog/post-content-audit.d.ts.map +1 -0
- package/dist/blog/post-content-audit.js +190 -0
- package/dist/blog/post-content-audit.js.map +1 -0
- package/dist/blog/post-view-cache.d.ts +15 -0
- package/dist/blog/post-view-cache.d.ts.map +1 -0
- package/dist/blog/post-view-cache.js +23 -0
- package/dist/blog/post-view-cache.js.map +1 -0
- package/dist/blog/public-blog-micro.d.ts +291 -0
- package/dist/blog/public-blog-micro.d.ts.map +1 -0
- package/dist/blog/public-blog-micro.js +71 -0
- package/dist/blog/public-blog-micro.js.map +1 -0
- package/dist/blog/public-blog-service.d.ts +104 -0
- package/dist/blog/public-blog-service.d.ts.map +1 -0
- package/dist/blog/public-blog-service.js +341 -0
- package/dist/blog/public-blog-service.js.map +1 -0
- package/dist/browser-api/dispatch-stream.d.ts +5 -0
- package/dist/browser-api/dispatch-stream.d.ts.map +1 -0
- package/dist/browser-api/dispatch-stream.js +4 -0
- package/dist/browser-api/dispatch-stream.js.map +1 -0
- package/dist/browser-api/dispatcher.d.ts +15 -0
- package/dist/browser-api/dispatcher.d.ts.map +1 -0
- package/dist/browser-api/dispatcher.js +145 -0
- package/dist/browser-api/dispatcher.js.map +1 -0
- package/dist/browser-api/provider-publisher.d.ts +24 -0
- package/dist/browser-api/provider-publisher.d.ts.map +1 -0
- package/dist/browser-api/provider-publisher.js +107 -0
- package/dist/browser-api/provider-publisher.js.map +1 -0
- package/dist/command/index.d.ts +3 -0
- package/dist/command/index.d.ts.map +1 -0
- package/dist/command/index.js +24 -0
- package/dist/command/index.js.map +1 -0
- package/dist/config/schema.d.ts +25 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +19 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/contracts/identity.d.ts +2 -0
- package/dist/contracts/identity.d.ts.map +1 -0
- package/dist/contracts/identity.js +2 -0
- package/dist/contracts/identity.js.map +1 -0
- package/dist/contracts/mcp.d.ts +69 -0
- package/dist/contracts/mcp.d.ts.map +1 -0
- package/dist/contracts/mcp.js +41 -0
- package/dist/contracts/mcp.js.map +1 -0
- package/dist/contracts/public-api.d.ts +3 -0
- package/dist/contracts/public-api.d.ts.map +1 -0
- package/dist/contracts/public-api.js +2 -0
- package/dist/contracts/public-api.js.map +1 -0
- package/dist/mcp/blog-prompts.d.ts +135 -0
- package/dist/mcp/blog-prompts.d.ts.map +1 -0
- package/dist/mcp/blog-prompts.js +107 -0
- package/dist/mcp/blog-prompts.js.map +1 -0
- package/dist/mcp/blog-provider.d.ts +4 -0
- package/dist/mcp/blog-provider.d.ts.map +1 -0
- package/dist/mcp/blog-provider.js +27 -0
- package/dist/mcp/blog-provider.js.map +1 -0
- package/dist/mcp/blog-theme-authoring-prompt.d.ts +19 -0
- package/dist/mcp/blog-theme-authoring-prompt.d.ts.map +1 -0
- package/dist/mcp/blog-theme-authoring-prompt.js +171 -0
- package/dist/mcp/blog-theme-authoring-prompt.js.map +1 -0
- package/dist/mcp/category-tools.d.ts +45 -0
- package/dist/mcp/category-tools.d.ts.map +1 -0
- package/dist/mcp/category-tools.js +14 -0
- package/dist/mcp/category-tools.js.map +1 -0
- package/dist/mcp/comment-tools.d.ts +44 -0
- package/dist/mcp/comment-tools.d.ts.map +1 -0
- package/dist/mcp/comment-tools.js +15 -0
- package/dist/mcp/comment-tools.js.map +1 -0
- package/dist/mcp/friend-link-tools.d.ts +63 -0
- package/dist/mcp/friend-link-tools.d.ts.map +1 -0
- package/dist/mcp/friend-link-tools.js +16 -0
- package/dist/mcp/friend-link-tools.js.map +1 -0
- package/dist/mcp/page-tools.d.ts +67 -0
- package/dist/mcp/page-tools.d.ts.map +1 -0
- package/dist/mcp/page-tools.js +36 -0
- package/dist/mcp/page-tools.js.map +1 -0
- package/dist/mcp/post-tools.d.ts +114 -0
- package/dist/mcp/post-tools.d.ts.map +1 -0
- package/dist/mcp/post-tools.js +122 -0
- package/dist/mcp/post-tools.js.map +1 -0
- package/dist/mcp/tag-tools.d.ts +37 -0
- package/dist/mcp/tag-tools.d.ts.map +1 -0
- package/dist/mcp/tag-tools.js +14 -0
- package/dist/mcp/tag-tools.js.map +1 -0
- package/dist/mcp/theme-tools.d.ts +16 -0
- package/dist/mcp/theme-tools.d.ts.map +1 -0
- package/dist/mcp/theme-tools.js +71 -0
- package/dist/mcp/theme-tools.js.map +1 -0
- package/dist/mcp/tool-descriptions.d.ts +5 -0
- package/dist/mcp/tool-descriptions.d.ts.map +1 -0
- package/dist/mcp/tool-descriptions.js +51 -0
- package/dist/mcp/tool-descriptions.js.map +1 -0
- package/dist/mcp/tool-support.d.ts +242 -0
- package/dist/mcp/tool-support.d.ts.map +1 -0
- package/dist/mcp/tool-support.js +127 -0
- package/dist/mcp/tool-support.js.map +1 -0
- package/dist/messages/browser/dispatch.msg.d.ts +3 -0
- package/dist/messages/browser/dispatch.msg.d.ts.map +1 -0
- package/dist/messages/browser/dispatch.msg.js +9 -0
- package/dist/messages/browser/dispatch.msg.js.map +1 -0
- package/dist/messages/public/categories/list.msg.d.ts +3 -0
- package/dist/messages/public/categories/list.msg.d.ts.map +1 -0
- package/dist/messages/public/categories/list.msg.js +8 -0
- package/dist/messages/public/categories/list.msg.js.map +1 -0
- package/dist/messages/public/comments/list.msg.d.ts +3 -0
- package/dist/messages/public/comments/list.msg.d.ts.map +1 -0
- package/dist/messages/public/comments/list.msg.js +8 -0
- package/dist/messages/public/comments/list.msg.js.map +1 -0
- package/dist/messages/public/comments/recent.msg.d.ts +3 -0
- package/dist/messages/public/comments/recent.msg.d.ts.map +1 -0
- package/dist/messages/public/comments/recent.msg.js +8 -0
- package/dist/messages/public/comments/recent.msg.js.map +1 -0
- package/dist/messages/public/friend-links/list.msg.d.ts +3 -0
- package/dist/messages/public/friend-links/list.msg.d.ts.map +1 -0
- package/dist/messages/public/friend-links/list.msg.js +8 -0
- package/dist/messages/public/friend-links/list.msg.js.map +1 -0
- package/dist/messages/public/pages/list.msg.d.ts +3 -0
- package/dist/messages/public/pages/list.msg.d.ts.map +1 -0
- package/dist/messages/public/pages/list.msg.js +8 -0
- package/dist/messages/public/pages/list.msg.js.map +1 -0
- package/dist/messages/public/pages/read.msg.d.ts +3 -0
- package/dist/messages/public/pages/read.msg.d.ts.map +1 -0
- package/dist/messages/public/pages/read.msg.js +8 -0
- package/dist/messages/public/pages/read.msg.js.map +1 -0
- package/dist/messages/public/posts/archive.msg.d.ts +3 -0
- package/dist/messages/public/posts/archive.msg.d.ts.map +1 -0
- package/dist/messages/public/posts/archive.msg.js +8 -0
- package/dist/messages/public/posts/archive.msg.js.map +1 -0
- package/dist/messages/public/posts/connections.msg.d.ts +3 -0
- package/dist/messages/public/posts/connections.msg.d.ts.map +1 -0
- package/dist/messages/public/posts/connections.msg.js +8 -0
- package/dist/messages/public/posts/connections.msg.js.map +1 -0
- package/dist/messages/public/posts/list.msg.d.ts +3 -0
- package/dist/messages/public/posts/list.msg.d.ts.map +1 -0
- package/dist/messages/public/posts/list.msg.js +8 -0
- package/dist/messages/public/posts/list.msg.js.map +1 -0
- package/dist/messages/public/posts/open.msg.d.ts +3 -0
- package/dist/messages/public/posts/open.msg.d.ts.map +1 -0
- package/dist/messages/public/posts/open.msg.js +8 -0
- package/dist/messages/public/posts/open.msg.js.map +1 -0
- package/dist/messages/public/posts/read.msg.d.ts +3 -0
- package/dist/messages/public/posts/read.msg.d.ts.map +1 -0
- package/dist/messages/public/posts/read.msg.js +8 -0
- package/dist/messages/public/posts/read.msg.js.map +1 -0
- package/dist/messages/public/tags/list.msg.d.ts +3 -0
- package/dist/messages/public/tags/list.msg.d.ts.map +1 -0
- package/dist/messages/public/tags/list.msg.js +8 -0
- package/dist/messages/public/tags/list.msg.js.map +1 -0
- package/dist/migrations/index.d.ts +3 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +2 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/persistence/category-store.d.ts +23 -0
- package/dist/persistence/category-store.d.ts.map +1 -0
- package/dist/persistence/category-store.js +86 -0
- package/dist/persistence/category-store.js.map +1 -0
- package/dist/persistence/comment-store.d.ts +41 -0
- package/dist/persistence/comment-store.d.ts.map +1 -0
- package/dist/persistence/comment-store.js +146 -0
- package/dist/persistence/comment-store.js.map +1 -0
- package/dist/persistence/entities.d.ts +103 -0
- package/dist/persistence/entities.d.ts.map +1 -0
- package/dist/persistence/entities.js +188 -0
- package/dist/persistence/entities.js.map +1 -0
- package/dist/persistence/friend-link-store.d.ts +26 -0
- package/dist/persistence/friend-link-store.d.ts.map +1 -0
- package/dist/persistence/friend-link-store.js +80 -0
- package/dist/persistence/friend-link-store.js.map +1 -0
- package/dist/persistence/page-store.d.ts +35 -0
- package/dist/persistence/page-store.d.ts.map +1 -0
- package/dist/persistence/page-store.js +125 -0
- package/dist/persistence/page-store.js.map +1 -0
- package/dist/persistence/post-engagement-store.d.ts +23 -0
- package/dist/persistence/post-engagement-store.d.ts.map +1 -0
- package/dist/persistence/post-engagement-store.js +85 -0
- package/dist/persistence/post-engagement-store.js.map +1 -0
- package/dist/persistence/post-store.d.ts +87 -0
- package/dist/persistence/post-store.d.ts.map +1 -0
- package/dist/persistence/post-store.js +465 -0
- package/dist/persistence/post-store.js.map +1 -0
- package/dist/persistence/tag-store.d.ts +21 -0
- package/dist/persistence/tag-store.d.ts.map +1 -0
- package/dist/persistence/tag-store.js +82 -0
- package/dist/persistence/tag-store.js.map +1 -0
- package/dist/services/application.service.d.ts +4 -0
- package/dist/services/application.service.d.ts.map +1 -0
- package/dist/services/application.service.js +22 -0
- package/dist/services/application.service.js.map +1 -0
- package/dist/services/blog-runtime.service.d.ts +10 -0
- package/dist/services/blog-runtime.service.d.ts.map +1 -0
- package/dist/services/blog-runtime.service.js +32 -0
- package/dist/services/blog-runtime.service.js.map +1 -0
- package/dist/services/blog.boot.d.ts +6 -0
- package/dist/services/blog.boot.d.ts.map +1 -0
- package/dist/services/blog.boot.js +13 -0
- package/dist/services/blog.boot.js.map +1 -0
- package/dist/services/browser-api-provider.service.d.ts +4 -0
- package/dist/services/browser-api-provider.service.d.ts.map +1 -0
- package/dist/services/browser-api-provider.service.js +25 -0
- package/dist/services/browser-api-provider.service.js.map +1 -0
- package/dist/services/config.service.d.ts +3 -0
- package/dist/services/config.service.d.ts.map +1 -0
- package/dist/services/config.service.js +22 -0
- package/dist/services/config.service.js.map +1 -0
- package/dist/services/database.service.d.ts +3 -0
- package/dist/services/database.service.d.ts.map +1 -0
- package/dist/services/database.service.js +16 -0
- package/dist/services/database.service.js.map +1 -0
- package/dist/services/logger.service.d.ts +4 -0
- package/dist/services/logger.service.d.ts.map +1 -0
- package/dist/services/logger.service.js +8 -0
- package/dist/services/logger.service.js.map +1 -0
- package/dist/services/mcp-provider.service.d.ts +3 -0
- package/dist/services/mcp-provider.service.d.ts.map +1 -0
- package/dist/services/mcp-provider.service.js +17 -0
- package/dist/services/mcp-provider.service.js.map +1 -0
- package/dist/services/redis.service.d.ts +4 -0
- package/dist/services/redis.service.d.ts.map +1 -0
- package/dist/services/redis.service.js +18 -0
- package/dist/services/redis.service.js.map +1 -0
- package/dist/services/theme-control.service.d.ts +4 -0
- package/dist/services/theme-control.service.d.ts.map +1 -0
- package/dist/services/theme-control.service.js +53 -0
- package/dist/services/theme-control.service.js.map +1 -0
- package/dist/themes/theme-catalog.d.ts +40 -0
- package/dist/themes/theme-catalog.d.ts.map +1 -0
- package/dist/themes/theme-catalog.js +164 -0
- package/dist/themes/theme-catalog.js.map +1 -0
- package/dist/themes/theme-control.d.ts +16 -0
- package/dist/themes/theme-control.d.ts.map +1 -0
- package/dist/themes/theme-control.js +57 -0
- package/dist/themes/theme-control.js.map +1 -0
- package/dist/themes/theme-discovery-runtime.d.ts +41 -0
- package/dist/themes/theme-discovery-runtime.d.ts.map +1 -0
- package/dist/themes/theme-discovery-runtime.js +109 -0
- package/dist/themes/theme-discovery-runtime.js.map +1 -0
- package/dist/themes/theme-generation-store.d.ts +14 -0
- package/dist/themes/theme-generation-store.d.ts.map +1 -0
- package/dist/themes/theme-generation-store.js +49 -0
- package/dist/themes/theme-generation-store.js.map +1 -0
- package/dist/themes/theme-selection-publisher.d.ts +28 -0
- package/dist/themes/theme-selection-publisher.d.ts.map +1 -0
- package/dist/themes/theme-selection-publisher.js +92 -0
- package/dist/themes/theme-selection-publisher.js.map +1 -0
- package/dist/themes/theme-selection-store.d.ts +22 -0
- package/dist/themes/theme-selection-store.d.ts.map +1 -0
- package/dist/themes/theme-selection-store.js +84 -0
- package/dist/themes/theme-selection-store.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { toString } from 'mdast-util-to-string';
|
|
2
|
+
import remarkParse from 'remark-parse';
|
|
3
|
+
import { unified } from 'unified';
|
|
4
|
+
import { visit } from 'unist-util-visit';
|
|
5
|
+
const MEANINGLESS_IMAGE_ALT = new Set(['image', 'img', 'photo', 'picture', '图片', '图像', '照片', '截图']);
|
|
6
|
+
const BROAD_TAXONOMY_NAMES = new Set([
|
|
7
|
+
'general', 'misc', 'miscellaneous', 'uncategorized',
|
|
8
|
+
'其他', '其它', '内容', '文章', '未分类', '默认',
|
|
9
|
+
]);
|
|
10
|
+
const HIDDEN_HTML_PATTERN = /(?:display\s*:\s*none|visibility\s*:\s*hidden|font-size\s*:\s*0|opacity\s*:\s*0)/iu;
|
|
11
|
+
const RAW_H1_PATTERN = /<\s*h1(?:\s|>)/iu;
|
|
12
|
+
const RECOMMENDED_TAG_LIMIT = 5;
|
|
13
|
+
const RECOMMENDED_TAG_NAME_LENGTH = 20;
|
|
14
|
+
export const POST_CONTENT_AUDIT_FINDING_LIMIT = 200;
|
|
15
|
+
export function auditPostContent(input) {
|
|
16
|
+
const tree = unified().use(remarkParse).parse(input.content);
|
|
17
|
+
const findings = [
|
|
18
|
+
...auditTitle(input.title),
|
|
19
|
+
...auditSummary(input.summary, input.title),
|
|
20
|
+
...auditMarkdown(tree),
|
|
21
|
+
...(input.taxonomy ? auditTaxonomy(input.taxonomy) : []),
|
|
22
|
+
];
|
|
23
|
+
const blocks = findings.filter((finding) => finding.severity === 'block');
|
|
24
|
+
const advice = findings.filter((finding) => finding.severity !== 'block');
|
|
25
|
+
return {
|
|
26
|
+
publishable: findings.every((finding) => finding.severity !== 'block'),
|
|
27
|
+
findings: [...blocks, ...advice].slice(0, POST_CONTENT_AUDIT_FINDING_LIMIT),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function auditTaxonomy(taxonomy) {
|
|
31
|
+
const findings = [];
|
|
32
|
+
const categoryName = normalizeText(taxonomy.category.name);
|
|
33
|
+
if (BROAD_TAXONOMY_NAMES.has(categoryName)) {
|
|
34
|
+
findings.push(finding('CATEGORY_TOO_BROAD', 'warning', 'category', '文章分类名称过于宽泛', '选择能够稳定概括文章主题的分类'));
|
|
35
|
+
}
|
|
36
|
+
if (!taxonomy.tags.length) {
|
|
37
|
+
findings.push(finding('TAGS_MISSING', 'info', 'tags', '文章没有设置标签', '需要建立主题关联时添加一至五个准确标签'));
|
|
38
|
+
return findings;
|
|
39
|
+
}
|
|
40
|
+
if (taxonomy.tags.length > RECOMMENDED_TAG_LIMIT) {
|
|
41
|
+
findings.push(finding('TAGS_TOO_MANY', 'warning', 'tags', '文章标签较多,可能分散主题', '保留一至五个最能代表文章主题的标签'));
|
|
42
|
+
}
|
|
43
|
+
const names = new Set();
|
|
44
|
+
for (const tag of taxonomy.tags) {
|
|
45
|
+
const name = tag.name.trim();
|
|
46
|
+
const normalized = normalizeText(name);
|
|
47
|
+
if ([...name].length > RECOMMENDED_TAG_NAME_LENGTH) {
|
|
48
|
+
findings.push(finding('TAG_TOO_LONG', 'warning', 'tags', '存在名称过长或句子化的标签', '将标签缩短为清晰的主题短语'));
|
|
49
|
+
}
|
|
50
|
+
if (BROAD_TAXONOMY_NAMES.has(normalized)) {
|
|
51
|
+
findings.push(finding('TAG_TOO_BROAD', 'warning', 'tags', '存在含义过于宽泛的标签', '改用能够描述具体主题的标签'));
|
|
52
|
+
}
|
|
53
|
+
if (normalized && normalized === categoryName) {
|
|
54
|
+
findings.push(finding('TAG_DUPLICATES_CATEGORY', 'warning', 'tags', '标签与文章分类重复', '删除重复标签或选择更具体的主题标签'));
|
|
55
|
+
}
|
|
56
|
+
if (normalized && names.has(normalized)) {
|
|
57
|
+
findings.push(finding('TAG_NORMALIZED_DUPLICATE', 'warning', 'tags', '存在大小写或字符形式不同但含义相同的标签', '合并重复标签并保留统一名称'));
|
|
58
|
+
}
|
|
59
|
+
if (normalized)
|
|
60
|
+
names.add(normalized);
|
|
61
|
+
}
|
|
62
|
+
return findings;
|
|
63
|
+
}
|
|
64
|
+
function auditTitle(title) {
|
|
65
|
+
const value = title.trim();
|
|
66
|
+
const length = [...value].length;
|
|
67
|
+
if (length < 4)
|
|
68
|
+
return [finding('TITLE_TOO_SHORT', 'warning', 'title', '标题过短,可能无法清楚表达文章主题', '使用准确、完整的一句话标题')];
|
|
69
|
+
const chineseLength = [...value.matchAll(/[\p{Script=Han}]/gu)].length;
|
|
70
|
+
const tooLong = chineseLength > length / 2 ? length > 30 : length > 60;
|
|
71
|
+
return tooLong
|
|
72
|
+
? [finding('TITLE_TOO_LONG', 'warning', 'title', '标题可能在搜索结果中被截断', '缩短标题并把核心主题放在前面')]
|
|
73
|
+
: [];
|
|
74
|
+
}
|
|
75
|
+
function auditSummary(summary, title) {
|
|
76
|
+
const value = summary?.trim() ?? '';
|
|
77
|
+
if (!value)
|
|
78
|
+
return [finding('SUMMARY_MISSING', 'warning', 'summary', '文章没有独立摘要', '用一句话概括正文核心内容')];
|
|
79
|
+
const length = [...value].length;
|
|
80
|
+
const findings = [];
|
|
81
|
+
if (length < 30)
|
|
82
|
+
findings.push(finding('SUMMARY_TOO_SHORT', 'warning', 'summary', '摘要可能不足以概括正文', '补充文章解决的问题和主要内容'));
|
|
83
|
+
if (length > 80)
|
|
84
|
+
findings.push(finding('SUMMARY_TOO_LONG', 'warning', 'summary', '摘要过长,可能在搜索结果中被截断', '将摘要压缩到约 40 至 60 个中文字符'));
|
|
85
|
+
if (normalizeText(value) === normalizeText(title))
|
|
86
|
+
findings.push(finding('SUMMARY_DUPLICATES_TITLE', 'warning', 'summary', '摘要与标题相同,没有提供额外信息', '补充正文的核心结论或适用场景'));
|
|
87
|
+
return findings;
|
|
88
|
+
}
|
|
89
|
+
function auditMarkdown(tree) {
|
|
90
|
+
const findings = [];
|
|
91
|
+
const visibleText = collectVisibleText(tree);
|
|
92
|
+
if (!visibleText)
|
|
93
|
+
findings.push(finding('CONTENT_EMPTY', 'block', 'content', '正文没有有效可见内容', '补充文章正文'));
|
|
94
|
+
if ([...visibleText].length < 300)
|
|
95
|
+
findings.push(finding('CONTENT_TOO_SHORT', 'warning', 'content', '正文内容较少,可能无法充分回答读者问题', '确认内容已经完整覆盖主题'));
|
|
96
|
+
auditHeadings(tree, findings);
|
|
97
|
+
auditParagraphs(tree, findings);
|
|
98
|
+
auditImages(tree, findings);
|
|
99
|
+
auditLinks(tree, findings);
|
|
100
|
+
auditRawHtml(tree, findings);
|
|
101
|
+
return findings;
|
|
102
|
+
}
|
|
103
|
+
function collectVisibleText(tree) {
|
|
104
|
+
const values = [];
|
|
105
|
+
visit(tree, (node) => {
|
|
106
|
+
if (node.type === 'text' || node.type === 'code' || node.type === 'inlineCode')
|
|
107
|
+
values.push(node.value);
|
|
108
|
+
if (node.type === 'image' && node.alt)
|
|
109
|
+
values.push(node.alt);
|
|
110
|
+
});
|
|
111
|
+
return values.join(' ').trim();
|
|
112
|
+
}
|
|
113
|
+
function auditHeadings(tree, findings) {
|
|
114
|
+
const headings = [];
|
|
115
|
+
visit(tree, 'heading', (heading) => headings.push(heading));
|
|
116
|
+
const first = headings[0];
|
|
117
|
+
if (first && first.depth !== 1 && first.depth !== 2) {
|
|
118
|
+
findings.push(finding('CONTENT_HEADING_START', 'block', 'content', '正文的第一个标题必须是 H2', '将第一个正文标题改为二级标题', first));
|
|
119
|
+
}
|
|
120
|
+
let previousDepth;
|
|
121
|
+
const titles = new Set();
|
|
122
|
+
for (const heading of headings) {
|
|
123
|
+
const title = toString(heading).trim();
|
|
124
|
+
if (heading.depth === 1)
|
|
125
|
+
findings.push(finding('CONTENT_H1_FORBIDDEN', 'block', 'content', '主题已经生成文章 H1,正文不能再包含 H1', '将一级标题改为 H2 或删除', heading));
|
|
126
|
+
if (!title)
|
|
127
|
+
findings.push(finding('CONTENT_EMPTY_HEADING', 'block', 'content', '正文包含空标题', '填写标题文字或删除该标题', heading));
|
|
128
|
+
if (previousDepth !== undefined && heading.depth > previousDepth + 1)
|
|
129
|
+
findings.push(finding('HEADING_LEVEL_SKIPPED', 'warning', 'content', '正文标题层级发生跳跃', '按 H2、H3、H4 的顺序组织标题', heading));
|
|
130
|
+
const normalized = normalizeText(title);
|
|
131
|
+
if (normalized && titles.has(normalized))
|
|
132
|
+
findings.push(finding('HEADING_DUPLICATED', 'warning', 'content', '正文中存在重复的小标题', '使用不同标题明确各章节内容', heading));
|
|
133
|
+
titles.add(normalized);
|
|
134
|
+
previousDepth = heading.depth;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function auditParagraphs(tree, findings) {
|
|
138
|
+
visit(tree, 'paragraph', (paragraph) => {
|
|
139
|
+
if ([...toString(paragraph).trim()].length > 300) {
|
|
140
|
+
findings.push(finding('PARAGRAPH_TOO_LONG', 'warning', 'content', '单个段落过长,阅读负担较大', '将段落拆分为更短的逻辑单元', paragraph));
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function auditImages(tree, findings) {
|
|
145
|
+
visit(tree, 'image', (image) => {
|
|
146
|
+
const alt = image.alt?.trim() ?? '';
|
|
147
|
+
if (!alt)
|
|
148
|
+
findings.push(finding('IMAGE_ALT_MISSING', 'warning', 'content', '正文图片缺少替代文本', '使用简短文字描述图片内容', image));
|
|
149
|
+
if (alt && MEANINGLESS_IMAGE_ALT.has(alt.toLocaleLowerCase()))
|
|
150
|
+
findings.push(finding('IMAGE_ALT_MEANINGLESS', 'warning', 'content', '图片替代文本没有描述具体内容', '说明图片展示的对象或信息', image));
|
|
151
|
+
if (!isSafeContentUrl(image.url))
|
|
152
|
+
findings.push(finding('CONTENT_IMAGE_SOURCE_INVALID', 'block', 'content', '正文图片地址无效或使用了不允许的协议', '改用 HTTPS 或站内相对图片地址', image));
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
function auditLinks(tree, findings) {
|
|
156
|
+
visit(tree, 'link', (link) => {
|
|
157
|
+
if (!isSafeContentUrl(link.url))
|
|
158
|
+
findings.push(finding('CONTENT_LINK_INVALID', 'block', 'content', '正文链接地址无效或使用了不允许的协议', '改用 HTTPS、邮件或站内相对地址', link));
|
|
159
|
+
const text = toString(link).trim().toLocaleLowerCase();
|
|
160
|
+
if (['点击这里', '点这里', '详情', '更多', 'click here', 'here'].includes(text))
|
|
161
|
+
findings.push(finding('LINK_TEXT_MEANINGLESS', 'warning', 'content', '链接文字没有说明目标内容', '使用能描述目标页面的链接文字', link));
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function auditRawHtml(tree, findings) {
|
|
165
|
+
visit(tree, 'html', (html) => {
|
|
166
|
+
if (RAW_H1_PATTERN.test(html.value))
|
|
167
|
+
findings.push(finding('CONTENT_H1_FORBIDDEN', 'block', 'content', '主题已经生成文章 H1,正文不能再包含 H1', '删除 HTML H1 或改为 H2', html));
|
|
168
|
+
if (HIDDEN_HTML_PATTERN.test(html.value))
|
|
169
|
+
findings.push(finding('CONTENT_HIDDEN_KEYWORDS', 'block', 'content', '正文包含隐藏内容样式', '删除隐藏文本并自然表达主题', html));
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function isSafeContentUrl(value) {
|
|
173
|
+
const url = value.trim();
|
|
174
|
+
if (!url)
|
|
175
|
+
return false;
|
|
176
|
+
if (/^(?:#|\/|\.\.?\/)/u.test(url))
|
|
177
|
+
return true;
|
|
178
|
+
return /^(?:https?:|mailto:)/iu.test(url);
|
|
179
|
+
}
|
|
180
|
+
function finding(ruleId, severity, field, message, suggestion, node) {
|
|
181
|
+
const location = node?.position?.start;
|
|
182
|
+
return {
|
|
183
|
+
ruleId, severity, source: 'project', field, message, suggestion,
|
|
184
|
+
...(location ? { location: { line: location.line, column: location.column } } : {}),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function normalizeText(value) {
|
|
188
|
+
return value.normalize('NFKC').toLocaleLowerCase().replace(/[\p{P}\p{S}\s]+/gu, '');
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=post-content-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-content-audit.js","sourceRoot":"","sources":["../../src/blog/post-content-audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface PostViewDedupeRedis {
|
|
2
|
+
get(key: string): Promise<string | null>;
|
|
3
|
+
set(key: string, value: string, mode: 'PX', durationMs: number): Promise<unknown>;
|
|
4
|
+
}
|
|
5
|
+
export interface PostViewDedupeCache {
|
|
6
|
+
hasRecent(postId: string, subjectHash: string, now: Date, windowMs: number): Promise<boolean>;
|
|
7
|
+
remember(postId: string, subjectHash: string, countedAt: Date, now: Date, windowMs: number): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare class RedisPostViewDedupeCache implements PostViewDedupeCache {
|
|
10
|
+
private readonly redis;
|
|
11
|
+
constructor(redis: PostViewDedupeRedis);
|
|
12
|
+
hasRecent(postId: string, subjectHash: string, now: Date, windowMs: number): Promise<boolean>;
|
|
13
|
+
remember(postId: string, subjectHash: string, countedAt: Date, now: Date, windowMs: number): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=post-view-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-view-cache.d.ts","sourceRoot":"","sources":["../../src/blog/post-view-cache.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnF;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CACP,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,IAAI,EACT,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,IAAI,EACf,GAAG,EAAE,IAAI,EACT,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,qBAAa,wBAAyB,YAAW,mBAAmB;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAzC,YAAoC,KAAK,EAAE,mBAAmB,EAAI;IAErD,SAAS,CACpB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,IAAI,EACT,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAOlB;IAEY,QAAQ,CACnB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,IAAI,EACf,GAAG,EAAE,IAAI,EACT,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAIf;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class RedisPostViewDedupeCache {
|
|
2
|
+
redis;
|
|
3
|
+
constructor(redis) {
|
|
4
|
+
this.redis = redis;
|
|
5
|
+
}
|
|
6
|
+
async hasRecent(postId, subjectHash, now, windowMs) {
|
|
7
|
+
const value = await this.redis.get(key(postId, subjectHash));
|
|
8
|
+
if (!value)
|
|
9
|
+
return false;
|
|
10
|
+
const countedAt = Date.parse(value);
|
|
11
|
+
return Number.isFinite(countedAt)
|
|
12
|
+
&& countedAt <= now.getTime()
|
|
13
|
+
&& countedAt >= now.getTime() - windowMs;
|
|
14
|
+
}
|
|
15
|
+
async remember(postId, subjectHash, countedAt, now, windowMs) {
|
|
16
|
+
const remaining = countedAt.getTime() + windowMs - now.getTime();
|
|
17
|
+
if (remaining <= 0)
|
|
18
|
+
return;
|
|
19
|
+
await this.redis.set(key(postId, subjectHash), countedAt.toISOString(), 'PX', remaining);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const key = (postId, subjectHash) => `view:${postId}:${subjectHash}`;
|
|
23
|
+
//# sourceMappingURL=post-view-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-view-cache.js","sourceRoot":"","sources":["../../src/blog/post-view-cache.ts"],"names":[],"mappings":"AAqBA,MAAM,OAAO,wBAAwB;IACC,KAAK;IAAzC,YAAoC,KAA0B;qBAA1B,KAAK;IAAwB,CAAC;IAE3D,KAAK,CAAC,SAAS,CACpB,MAAc,EACd,WAAmB,EACnB,GAAS,EACT,QAAgB;QAEhB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;eAC5B,SAAS,IAAI,GAAG,CAAC,OAAO,EAAE;eAC1B,SAAS,IAAI,GAAG,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC;IAC7C,CAAC;IAEM,KAAK,CAAC,QAAQ,CACnB,MAAc,EACd,WAAmB,EACnB,SAAe,EACf,GAAS,EACT,QAAgB;QAEhB,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,GAAG,QAAQ,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;QACjE,IAAI,SAAS,IAAI,CAAC;YAAE,OAAO;QAC3B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,SAAS,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAC3F,CAAC;CACF;AAED,MAAM,GAAG,GAAG,CAAC,MAAc,EAAE,WAAmB,EAAE,EAAE,CAAC,QAAQ,MAAM,IAAI,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import type { InvocationContext } from '@hile/context';
|
|
2
|
+
import type { PublicBlogService } from './public-blog-service.js';
|
|
3
|
+
type PublicBlogReadPort = Pick<PublicBlogService, 'listPosts' | 'listPostArchive' | 'readPost' | 'openPost' | 'readPostConnections' | 'listComments' | 'listRecentComments' | 'listCategories' | 'listTags' | 'listFriendLinks' | 'listPages' | 'readPage'>;
|
|
4
|
+
export declare class PublicBlogMicroService {
|
|
5
|
+
private readonly blog;
|
|
6
|
+
constructor(blog: PublicBlogReadPort);
|
|
7
|
+
listPosts(input: unknown, signal?: AbortSignal): Promise<Readonly<{
|
|
8
|
+
items: readonly Readonly<{
|
|
9
|
+
id: string;
|
|
10
|
+
category: Readonly<{
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
slug: string;
|
|
14
|
+
description: string | null;
|
|
15
|
+
sortOrder: number;
|
|
16
|
+
}>;
|
|
17
|
+
title: string;
|
|
18
|
+
slug: string;
|
|
19
|
+
summary: string | null;
|
|
20
|
+
coverUrl: string | null;
|
|
21
|
+
publishedAt: string;
|
|
22
|
+
updatedAt: string;
|
|
23
|
+
tags: readonly Readonly<{
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
slug: string;
|
|
27
|
+
}>[];
|
|
28
|
+
}>[];
|
|
29
|
+
nextCursor: string | null;
|
|
30
|
+
total: number;
|
|
31
|
+
}>>;
|
|
32
|
+
listPostArchive(input: unknown, signal?: AbortSignal): Promise<Readonly<{
|
|
33
|
+
items: readonly Readonly<{
|
|
34
|
+
id: string;
|
|
35
|
+
category: Readonly<{
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
slug: string;
|
|
39
|
+
description: string | null;
|
|
40
|
+
sortOrder: number;
|
|
41
|
+
}>;
|
|
42
|
+
title: string;
|
|
43
|
+
slug: string;
|
|
44
|
+
summary: string | null;
|
|
45
|
+
coverUrl: string | null;
|
|
46
|
+
publishedAt: string;
|
|
47
|
+
updatedAt: string;
|
|
48
|
+
tags: readonly Readonly<{
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
slug: string;
|
|
52
|
+
}>[];
|
|
53
|
+
}>[];
|
|
54
|
+
months: readonly Readonly<{
|
|
55
|
+
year: number;
|
|
56
|
+
month: number;
|
|
57
|
+
count: number;
|
|
58
|
+
}>[];
|
|
59
|
+
nextCursor: string | null;
|
|
60
|
+
total: number;
|
|
61
|
+
}>>;
|
|
62
|
+
readPost(input: unknown, signal?: AbortSignal): Promise<Readonly<{
|
|
63
|
+
found: false;
|
|
64
|
+
}> | Readonly<{
|
|
65
|
+
found: true;
|
|
66
|
+
post: Readonly<{
|
|
67
|
+
id: string;
|
|
68
|
+
category: Readonly<{
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
slug: string;
|
|
72
|
+
description: string | null;
|
|
73
|
+
sortOrder: number;
|
|
74
|
+
}>;
|
|
75
|
+
title: string;
|
|
76
|
+
slug: string;
|
|
77
|
+
summary: string | null;
|
|
78
|
+
coverUrl: string | null;
|
|
79
|
+
publishedAt: string;
|
|
80
|
+
updatedAt: string;
|
|
81
|
+
tags: readonly Readonly<{
|
|
82
|
+
id: string;
|
|
83
|
+
name: string;
|
|
84
|
+
slug: string;
|
|
85
|
+
}>[];
|
|
86
|
+
content: string;
|
|
87
|
+
}>;
|
|
88
|
+
}>>;
|
|
89
|
+
openPost(input: unknown, invocation: InvocationContext): Promise<Readonly<{
|
|
90
|
+
found: false;
|
|
91
|
+
}> | Readonly<{
|
|
92
|
+
found: true;
|
|
93
|
+
post: Readonly<{
|
|
94
|
+
id: string;
|
|
95
|
+
category: Readonly<{
|
|
96
|
+
id: string;
|
|
97
|
+
name: string;
|
|
98
|
+
slug: string;
|
|
99
|
+
description: string | null;
|
|
100
|
+
sortOrder: number;
|
|
101
|
+
}>;
|
|
102
|
+
title: string;
|
|
103
|
+
slug: string;
|
|
104
|
+
summary: string | null;
|
|
105
|
+
coverUrl: string | null;
|
|
106
|
+
publishedAt: string;
|
|
107
|
+
updatedAt: string;
|
|
108
|
+
tags: readonly Readonly<{
|
|
109
|
+
id: string;
|
|
110
|
+
name: string;
|
|
111
|
+
slug: string;
|
|
112
|
+
}>[];
|
|
113
|
+
content: string;
|
|
114
|
+
}>;
|
|
115
|
+
engagement: Readonly<{
|
|
116
|
+
viewCount: number;
|
|
117
|
+
likeCount: number;
|
|
118
|
+
viewerState: "anonymous" | "liked" | "not-liked" | "unavailable";
|
|
119
|
+
}>;
|
|
120
|
+
}>>;
|
|
121
|
+
readPostConnections(input: unknown, signal?: AbortSignal): Promise<Readonly<{
|
|
122
|
+
found: false;
|
|
123
|
+
}> | Readonly<{
|
|
124
|
+
found: true;
|
|
125
|
+
connections: Readonly<{
|
|
126
|
+
previousPost: Readonly<{
|
|
127
|
+
id: string;
|
|
128
|
+
category: Readonly<{
|
|
129
|
+
id: string;
|
|
130
|
+
name: string;
|
|
131
|
+
slug: string;
|
|
132
|
+
description: string | null;
|
|
133
|
+
sortOrder: number;
|
|
134
|
+
}>;
|
|
135
|
+
title: string;
|
|
136
|
+
slug: string;
|
|
137
|
+
summary: string | null;
|
|
138
|
+
coverUrl: string | null;
|
|
139
|
+
publishedAt: string;
|
|
140
|
+
updatedAt: string;
|
|
141
|
+
tags: readonly Readonly<{
|
|
142
|
+
id: string;
|
|
143
|
+
name: string;
|
|
144
|
+
slug: string;
|
|
145
|
+
}>[];
|
|
146
|
+
}> | null;
|
|
147
|
+
nextPost: Readonly<{
|
|
148
|
+
id: string;
|
|
149
|
+
category: Readonly<{
|
|
150
|
+
id: string;
|
|
151
|
+
name: string;
|
|
152
|
+
slug: string;
|
|
153
|
+
description: string | null;
|
|
154
|
+
sortOrder: number;
|
|
155
|
+
}>;
|
|
156
|
+
title: string;
|
|
157
|
+
slug: string;
|
|
158
|
+
summary: string | null;
|
|
159
|
+
coverUrl: string | null;
|
|
160
|
+
publishedAt: string;
|
|
161
|
+
updatedAt: string;
|
|
162
|
+
tags: readonly Readonly<{
|
|
163
|
+
id: string;
|
|
164
|
+
name: string;
|
|
165
|
+
slug: string;
|
|
166
|
+
}>[];
|
|
167
|
+
}> | null;
|
|
168
|
+
relatedPosts: readonly Readonly<{
|
|
169
|
+
id: string;
|
|
170
|
+
category: Readonly<{
|
|
171
|
+
id: string;
|
|
172
|
+
name: string;
|
|
173
|
+
slug: string;
|
|
174
|
+
description: string | null;
|
|
175
|
+
sortOrder: number;
|
|
176
|
+
}>;
|
|
177
|
+
title: string;
|
|
178
|
+
slug: string;
|
|
179
|
+
summary: string | null;
|
|
180
|
+
coverUrl: string | null;
|
|
181
|
+
publishedAt: string;
|
|
182
|
+
updatedAt: string;
|
|
183
|
+
tags: readonly Readonly<{
|
|
184
|
+
id: string;
|
|
185
|
+
name: string;
|
|
186
|
+
slug: string;
|
|
187
|
+
}>[];
|
|
188
|
+
}>[];
|
|
189
|
+
}>;
|
|
190
|
+
}>>;
|
|
191
|
+
listComments(input: unknown, invocation: InvocationContext): Promise<Readonly<{
|
|
192
|
+
found: false;
|
|
193
|
+
}> | Readonly<{
|
|
194
|
+
found: true;
|
|
195
|
+
comments: Readonly<{
|
|
196
|
+
items: readonly Readonly<{
|
|
197
|
+
id: string;
|
|
198
|
+
postId: string;
|
|
199
|
+
user: Readonly<{
|
|
200
|
+
id: string;
|
|
201
|
+
displayName: string | null;
|
|
202
|
+
avatar: string | null;
|
|
203
|
+
homepage: string | null;
|
|
204
|
+
bio: string | null;
|
|
205
|
+
}>;
|
|
206
|
+
content: string;
|
|
207
|
+
replyContent: string | null;
|
|
208
|
+
repliedAt: string | null;
|
|
209
|
+
createdAt: string;
|
|
210
|
+
location: string | null;
|
|
211
|
+
client: string | null;
|
|
212
|
+
pendingReview?: true | undefined;
|
|
213
|
+
}>[];
|
|
214
|
+
nextCursor: string | null;
|
|
215
|
+
}>;
|
|
216
|
+
}>>;
|
|
217
|
+
listRecentComments(input: unknown, invocation: InvocationContext): Promise<readonly Readonly<{
|
|
218
|
+
comment: Readonly<{
|
|
219
|
+
id: string;
|
|
220
|
+
postId: string;
|
|
221
|
+
user: Readonly<{
|
|
222
|
+
id: string;
|
|
223
|
+
displayName: string | null;
|
|
224
|
+
avatar: string | null;
|
|
225
|
+
homepage: string | null;
|
|
226
|
+
bio: string | null;
|
|
227
|
+
}>;
|
|
228
|
+
content: string;
|
|
229
|
+
replyContent: string | null;
|
|
230
|
+
repliedAt: string | null;
|
|
231
|
+
createdAt: string;
|
|
232
|
+
location: string | null;
|
|
233
|
+
client: string | null;
|
|
234
|
+
pendingReview?: true | undefined;
|
|
235
|
+
}>;
|
|
236
|
+
post: Readonly<{
|
|
237
|
+
id: string;
|
|
238
|
+
title: string;
|
|
239
|
+
slug: string;
|
|
240
|
+
}>;
|
|
241
|
+
}>[]>;
|
|
242
|
+
listCategories(input: unknown, signal?: AbortSignal): Promise<readonly Readonly<{
|
|
243
|
+
id: string;
|
|
244
|
+
name: string;
|
|
245
|
+
slug: string;
|
|
246
|
+
description: string | null;
|
|
247
|
+
sortOrder: number;
|
|
248
|
+
postCount: number;
|
|
249
|
+
}>[]>;
|
|
250
|
+
listTags(input: unknown, signal?: AbortSignal): Promise<readonly Readonly<{
|
|
251
|
+
id: string;
|
|
252
|
+
name: string;
|
|
253
|
+
slug: string;
|
|
254
|
+
}>[]>;
|
|
255
|
+
listFriendLinks(input: unknown, signal?: AbortSignal): Promise<readonly Readonly<{
|
|
256
|
+
id: string;
|
|
257
|
+
name: string;
|
|
258
|
+
url: string;
|
|
259
|
+
description: string | null;
|
|
260
|
+
logoUrl: string | null;
|
|
261
|
+
sortOrder: number;
|
|
262
|
+
}>[]>;
|
|
263
|
+
listPages(input: unknown, signal?: AbortSignal): Promise<readonly Readonly<{
|
|
264
|
+
id: string;
|
|
265
|
+
title: string;
|
|
266
|
+
slug: string;
|
|
267
|
+
summary: string;
|
|
268
|
+
position: "navigation" | "sidebar" | null;
|
|
269
|
+
sortOrder: number;
|
|
270
|
+
publishedAt: string;
|
|
271
|
+
updatedAt: string;
|
|
272
|
+
}>[]>;
|
|
273
|
+
readPage(input: unknown, signal?: AbortSignal): Promise<Readonly<{
|
|
274
|
+
found: false;
|
|
275
|
+
}> | Readonly<{
|
|
276
|
+
found: true;
|
|
277
|
+
page: Readonly<{
|
|
278
|
+
id: string;
|
|
279
|
+
title: string;
|
|
280
|
+
slug: string;
|
|
281
|
+
summary: string;
|
|
282
|
+
position: "navigation" | "sidebar" | null;
|
|
283
|
+
sortOrder: number;
|
|
284
|
+
publishedAt: string;
|
|
285
|
+
updatedAt: string;
|
|
286
|
+
content: string;
|
|
287
|
+
}>;
|
|
288
|
+
}>>;
|
|
289
|
+
}
|
|
290
|
+
export {};
|
|
291
|
+
//# sourceMappingURL=public-blog-micro.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-blog-micro.d.ts","sourceRoot":"","sources":["../../src/blog/public-blog-micro.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,KAAK,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,EAC5C,WAAW,GACX,iBAAiB,GACjB,UAAU,GACV,UAAU,GACV,qBAAqB,GACrB,cAAc,GACd,oBAAoB,GACpB,gBAAgB,GAChB,UAAU,GACV,iBAAiB,GACjB,WAAW,GACX,UAAU,CAAC,CAAC;AAEhB,qBAAa,sBAAsB;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAxC,YAAoC,IAAI,EAAE,kBAAkB,EAAI;IAEnD,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;QAS1D;IAEY,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAGhE;IAEY,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;QAIzD;IAEY,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAQlE;IAEY,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAUpE;IAEY,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;QAUtE;IAEY,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;UAK5E;IAEY,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;UAG/D;IAEY,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;UAGzD;IAEY,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;UAGhE;IAEY,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;;;UAG1D;IAEY,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;;;;;;;;;QAIzD;CACF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { blogCategoryListSchema, blogCommentListInputSchema, blogRecentCommentListInputSchema, blogRecentCommentListSchema, blogEmptyRequestSchema, blogFriendLinkListSchema, blogPageListInputSchema, blogPageListSchema, blogReadPageInputSchema, blogReadPageResponseSchema, blogListCommentsResponseSchema, blogPostListInputSchema, blogPostListSchema, blogPostArchiveInputSchema, blogPostArchiveSchema, blogPostConnectionsInputSchema, blogReadPostConnectionsResponseSchema, blogReadPostInputSchema, blogOpenPostResponseSchema, blogReadPostResponseSchema, blogTagListSchema, } from '@zlooks.cn/blog-schema';
|
|
2
|
+
export class PublicBlogMicroService {
|
|
3
|
+
blog;
|
|
4
|
+
constructor(blog) {
|
|
5
|
+
this.blog = blog;
|
|
6
|
+
}
|
|
7
|
+
async listPosts(input, signal) {
|
|
8
|
+
const request = blogPostListInputSchema.parse(input);
|
|
9
|
+
return blogPostListSchema.parse(await this.blog.listPosts({
|
|
10
|
+
limit: request.limit,
|
|
11
|
+
...(request.cursor ? { cursor: request.cursor } : {}),
|
|
12
|
+
...(request.page ? { page: request.page } : {}),
|
|
13
|
+
...(request.categorySlug ? { category: request.categorySlug } : {}),
|
|
14
|
+
...(request.tagSlug ? { tag: request.tagSlug } : {}),
|
|
15
|
+
}, signal));
|
|
16
|
+
}
|
|
17
|
+
async listPostArchive(input, signal) {
|
|
18
|
+
const request = blogPostArchiveInputSchema.parse(input);
|
|
19
|
+
return blogPostArchiveSchema.parse(await this.blog.listPostArchive(request, signal));
|
|
20
|
+
}
|
|
21
|
+
async readPost(input, signal) {
|
|
22
|
+
const request = blogReadPostInputSchema.parse(input);
|
|
23
|
+
const post = await this.blog.readPost(request.slug, signal);
|
|
24
|
+
return blogReadPostResponseSchema.parse(post ? { found: true, post } : { found: false });
|
|
25
|
+
}
|
|
26
|
+
async openPost(input, invocation) {
|
|
27
|
+
const request = blogReadPostInputSchema.parse(input);
|
|
28
|
+
const opened = await this.blog.openPost(request.slug, invocation.context, invocation.signal);
|
|
29
|
+
return blogOpenPostResponseSchema.parse(opened ? { found: true, ...opened } : { found: false });
|
|
30
|
+
}
|
|
31
|
+
async readPostConnections(input, signal) {
|
|
32
|
+
const request = blogPostConnectionsInputSchema.parse(input);
|
|
33
|
+
const connections = await this.blog.readPostConnections(request.slug, request.relatedLimit, signal);
|
|
34
|
+
return blogReadPostConnectionsResponseSchema.parse(connections ? { found: true, connections } : { found: false });
|
|
35
|
+
}
|
|
36
|
+
async listComments(input, invocation) {
|
|
37
|
+
const request = blogCommentListInputSchema.parse(input);
|
|
38
|
+
const comments = await this.blog.listComments(request.postSlug, {
|
|
39
|
+
limit: request.limit,
|
|
40
|
+
...(request.cursor ? { cursor: request.cursor } : {}),
|
|
41
|
+
order: request.order ?? 'desc',
|
|
42
|
+
}, invocation.context, invocation.signal);
|
|
43
|
+
return blogListCommentsResponseSchema.parse(comments ? { found: true, comments } : { found: false });
|
|
44
|
+
}
|
|
45
|
+
async listRecentComments(input, invocation) {
|
|
46
|
+
const request = blogRecentCommentListInputSchema.parse(input);
|
|
47
|
+
return blogRecentCommentListSchema.parse(await this.blog.listRecentComments(request.limit, invocation.context, invocation.signal));
|
|
48
|
+
}
|
|
49
|
+
async listCategories(input, signal) {
|
|
50
|
+
blogEmptyRequestSchema.parse(input);
|
|
51
|
+
return blogCategoryListSchema.parse(await this.blog.listCategories(signal));
|
|
52
|
+
}
|
|
53
|
+
async listTags(input, signal) {
|
|
54
|
+
blogEmptyRequestSchema.parse(input);
|
|
55
|
+
return blogTagListSchema.parse(await this.blog.listTags(signal));
|
|
56
|
+
}
|
|
57
|
+
async listFriendLinks(input, signal) {
|
|
58
|
+
blogEmptyRequestSchema.parse(input);
|
|
59
|
+
return blogFriendLinkListSchema.parse(await this.blog.listFriendLinks(signal));
|
|
60
|
+
}
|
|
61
|
+
async listPages(input, signal) {
|
|
62
|
+
const request = blogPageListInputSchema.parse(input);
|
|
63
|
+
return blogPageListSchema.parse(await this.blog.listPages(request.position, signal));
|
|
64
|
+
}
|
|
65
|
+
async readPage(input, signal) {
|
|
66
|
+
const request = blogReadPageInputSchema.parse(input);
|
|
67
|
+
const page = await this.blog.readPage(request.slug, signal);
|
|
68
|
+
return blogReadPageResponseSchema.parse(page ? { found: true, page } : { found: false });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=public-blog-micro.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-blog-micro.js","sourceRoot":"","sources":["../../src/blog/public-blog-micro.ts"],"names":[],"mappings":"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"}
|