@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.
Files changed (265) hide show
  1. package/dist/blog/blog-application.d.ts +153 -0
  2. package/dist/blog/blog-application.d.ts.map +1 -0
  3. package/dist/blog/blog-application.js +115 -0
  4. package/dist/blog/blog-application.js.map +1 -0
  5. package/dist/blog/comment-client-metadata.d.ts +19 -0
  6. package/dist/blog/comment-client-metadata.d.ts.map +1 -0
  7. package/dist/blog/comment-client-metadata.js +78 -0
  8. package/dist/blog/comment-client-metadata.js.map +1 -0
  9. package/dist/blog/errors.d.ts +12 -0
  10. package/dist/blog/errors.d.ts.map +1 -0
  11. package/dist/blog/errors.js +21 -0
  12. package/dist/blog/errors.js.map +1 -0
  13. package/dist/blog/micro-user-directory.d.ts +11 -0
  14. package/dist/blog/micro-user-directory.d.ts.map +1 -0
  15. package/dist/blog/micro-user-directory.js +18 -0
  16. package/dist/blog/micro-user-directory.js.map +1 -0
  17. package/dist/blog/post-content-audit.d.ts +34 -0
  18. package/dist/blog/post-content-audit.d.ts.map +1 -0
  19. package/dist/blog/post-content-audit.js +190 -0
  20. package/dist/blog/post-content-audit.js.map +1 -0
  21. package/dist/blog/post-view-cache.d.ts +15 -0
  22. package/dist/blog/post-view-cache.d.ts.map +1 -0
  23. package/dist/blog/post-view-cache.js +23 -0
  24. package/dist/blog/post-view-cache.js.map +1 -0
  25. package/dist/blog/public-blog-micro.d.ts +291 -0
  26. package/dist/blog/public-blog-micro.d.ts.map +1 -0
  27. package/dist/blog/public-blog-micro.js +71 -0
  28. package/dist/blog/public-blog-micro.js.map +1 -0
  29. package/dist/blog/public-blog-service.d.ts +104 -0
  30. package/dist/blog/public-blog-service.d.ts.map +1 -0
  31. package/dist/blog/public-blog-service.js +341 -0
  32. package/dist/blog/public-blog-service.js.map +1 -0
  33. package/dist/browser-api/dispatch-stream.d.ts +5 -0
  34. package/dist/browser-api/dispatch-stream.d.ts.map +1 -0
  35. package/dist/browser-api/dispatch-stream.js +4 -0
  36. package/dist/browser-api/dispatch-stream.js.map +1 -0
  37. package/dist/browser-api/dispatcher.d.ts +15 -0
  38. package/dist/browser-api/dispatcher.d.ts.map +1 -0
  39. package/dist/browser-api/dispatcher.js +145 -0
  40. package/dist/browser-api/dispatcher.js.map +1 -0
  41. package/dist/browser-api/provider-publisher.d.ts +24 -0
  42. package/dist/browser-api/provider-publisher.d.ts.map +1 -0
  43. package/dist/browser-api/provider-publisher.js +107 -0
  44. package/dist/browser-api/provider-publisher.js.map +1 -0
  45. package/dist/command/index.d.ts +3 -0
  46. package/dist/command/index.d.ts.map +1 -0
  47. package/dist/command/index.js +24 -0
  48. package/dist/command/index.js.map +1 -0
  49. package/dist/config/schema.d.ts +25 -0
  50. package/dist/config/schema.d.ts.map +1 -0
  51. package/dist/config/schema.js +19 -0
  52. package/dist/config/schema.js.map +1 -0
  53. package/dist/contracts/identity.d.ts +2 -0
  54. package/dist/contracts/identity.d.ts.map +1 -0
  55. package/dist/contracts/identity.js +2 -0
  56. package/dist/contracts/identity.js.map +1 -0
  57. package/dist/contracts/mcp.d.ts +69 -0
  58. package/dist/contracts/mcp.d.ts.map +1 -0
  59. package/dist/contracts/mcp.js +41 -0
  60. package/dist/contracts/mcp.js.map +1 -0
  61. package/dist/contracts/public-api.d.ts +3 -0
  62. package/dist/contracts/public-api.d.ts.map +1 -0
  63. package/dist/contracts/public-api.js +2 -0
  64. package/dist/contracts/public-api.js.map +1 -0
  65. package/dist/mcp/blog-prompts.d.ts +135 -0
  66. package/dist/mcp/blog-prompts.d.ts.map +1 -0
  67. package/dist/mcp/blog-prompts.js +107 -0
  68. package/dist/mcp/blog-prompts.js.map +1 -0
  69. package/dist/mcp/blog-provider.d.ts +4 -0
  70. package/dist/mcp/blog-provider.d.ts.map +1 -0
  71. package/dist/mcp/blog-provider.js +27 -0
  72. package/dist/mcp/blog-provider.js.map +1 -0
  73. package/dist/mcp/blog-theme-authoring-prompt.d.ts +19 -0
  74. package/dist/mcp/blog-theme-authoring-prompt.d.ts.map +1 -0
  75. package/dist/mcp/blog-theme-authoring-prompt.js +171 -0
  76. package/dist/mcp/blog-theme-authoring-prompt.js.map +1 -0
  77. package/dist/mcp/category-tools.d.ts +45 -0
  78. package/dist/mcp/category-tools.d.ts.map +1 -0
  79. package/dist/mcp/category-tools.js +14 -0
  80. package/dist/mcp/category-tools.js.map +1 -0
  81. package/dist/mcp/comment-tools.d.ts +44 -0
  82. package/dist/mcp/comment-tools.d.ts.map +1 -0
  83. package/dist/mcp/comment-tools.js +15 -0
  84. package/dist/mcp/comment-tools.js.map +1 -0
  85. package/dist/mcp/friend-link-tools.d.ts +63 -0
  86. package/dist/mcp/friend-link-tools.d.ts.map +1 -0
  87. package/dist/mcp/friend-link-tools.js +16 -0
  88. package/dist/mcp/friend-link-tools.js.map +1 -0
  89. package/dist/mcp/page-tools.d.ts +67 -0
  90. package/dist/mcp/page-tools.d.ts.map +1 -0
  91. package/dist/mcp/page-tools.js +36 -0
  92. package/dist/mcp/page-tools.js.map +1 -0
  93. package/dist/mcp/post-tools.d.ts +114 -0
  94. package/dist/mcp/post-tools.d.ts.map +1 -0
  95. package/dist/mcp/post-tools.js +122 -0
  96. package/dist/mcp/post-tools.js.map +1 -0
  97. package/dist/mcp/tag-tools.d.ts +37 -0
  98. package/dist/mcp/tag-tools.d.ts.map +1 -0
  99. package/dist/mcp/tag-tools.js +14 -0
  100. package/dist/mcp/tag-tools.js.map +1 -0
  101. package/dist/mcp/theme-tools.d.ts +16 -0
  102. package/dist/mcp/theme-tools.d.ts.map +1 -0
  103. package/dist/mcp/theme-tools.js +71 -0
  104. package/dist/mcp/theme-tools.js.map +1 -0
  105. package/dist/mcp/tool-descriptions.d.ts +5 -0
  106. package/dist/mcp/tool-descriptions.d.ts.map +1 -0
  107. package/dist/mcp/tool-descriptions.js +51 -0
  108. package/dist/mcp/tool-descriptions.js.map +1 -0
  109. package/dist/mcp/tool-support.d.ts +242 -0
  110. package/dist/mcp/tool-support.d.ts.map +1 -0
  111. package/dist/mcp/tool-support.js +127 -0
  112. package/dist/mcp/tool-support.js.map +1 -0
  113. package/dist/messages/browser/dispatch.msg.d.ts +3 -0
  114. package/dist/messages/browser/dispatch.msg.d.ts.map +1 -0
  115. package/dist/messages/browser/dispatch.msg.js +9 -0
  116. package/dist/messages/browser/dispatch.msg.js.map +1 -0
  117. package/dist/messages/public/categories/list.msg.d.ts +3 -0
  118. package/dist/messages/public/categories/list.msg.d.ts.map +1 -0
  119. package/dist/messages/public/categories/list.msg.js +8 -0
  120. package/dist/messages/public/categories/list.msg.js.map +1 -0
  121. package/dist/messages/public/comments/list.msg.d.ts +3 -0
  122. package/dist/messages/public/comments/list.msg.d.ts.map +1 -0
  123. package/dist/messages/public/comments/list.msg.js +8 -0
  124. package/dist/messages/public/comments/list.msg.js.map +1 -0
  125. package/dist/messages/public/comments/recent.msg.d.ts +3 -0
  126. package/dist/messages/public/comments/recent.msg.d.ts.map +1 -0
  127. package/dist/messages/public/comments/recent.msg.js +8 -0
  128. package/dist/messages/public/comments/recent.msg.js.map +1 -0
  129. package/dist/messages/public/friend-links/list.msg.d.ts +3 -0
  130. package/dist/messages/public/friend-links/list.msg.d.ts.map +1 -0
  131. package/dist/messages/public/friend-links/list.msg.js +8 -0
  132. package/dist/messages/public/friend-links/list.msg.js.map +1 -0
  133. package/dist/messages/public/pages/list.msg.d.ts +3 -0
  134. package/dist/messages/public/pages/list.msg.d.ts.map +1 -0
  135. package/dist/messages/public/pages/list.msg.js +8 -0
  136. package/dist/messages/public/pages/list.msg.js.map +1 -0
  137. package/dist/messages/public/pages/read.msg.d.ts +3 -0
  138. package/dist/messages/public/pages/read.msg.d.ts.map +1 -0
  139. package/dist/messages/public/pages/read.msg.js +8 -0
  140. package/dist/messages/public/pages/read.msg.js.map +1 -0
  141. package/dist/messages/public/posts/archive.msg.d.ts +3 -0
  142. package/dist/messages/public/posts/archive.msg.d.ts.map +1 -0
  143. package/dist/messages/public/posts/archive.msg.js +8 -0
  144. package/dist/messages/public/posts/archive.msg.js.map +1 -0
  145. package/dist/messages/public/posts/connections.msg.d.ts +3 -0
  146. package/dist/messages/public/posts/connections.msg.d.ts.map +1 -0
  147. package/dist/messages/public/posts/connections.msg.js +8 -0
  148. package/dist/messages/public/posts/connections.msg.js.map +1 -0
  149. package/dist/messages/public/posts/list.msg.d.ts +3 -0
  150. package/dist/messages/public/posts/list.msg.d.ts.map +1 -0
  151. package/dist/messages/public/posts/list.msg.js +8 -0
  152. package/dist/messages/public/posts/list.msg.js.map +1 -0
  153. package/dist/messages/public/posts/open.msg.d.ts +3 -0
  154. package/dist/messages/public/posts/open.msg.d.ts.map +1 -0
  155. package/dist/messages/public/posts/open.msg.js +8 -0
  156. package/dist/messages/public/posts/open.msg.js.map +1 -0
  157. package/dist/messages/public/posts/read.msg.d.ts +3 -0
  158. package/dist/messages/public/posts/read.msg.d.ts.map +1 -0
  159. package/dist/messages/public/posts/read.msg.js +8 -0
  160. package/dist/messages/public/posts/read.msg.js.map +1 -0
  161. package/dist/messages/public/tags/list.msg.d.ts +3 -0
  162. package/dist/messages/public/tags/list.msg.d.ts.map +1 -0
  163. package/dist/messages/public/tags/list.msg.js +8 -0
  164. package/dist/messages/public/tags/list.msg.js.map +1 -0
  165. package/dist/migrations/index.d.ts +3 -0
  166. package/dist/migrations/index.d.ts.map +1 -0
  167. package/dist/migrations/index.js +2 -0
  168. package/dist/migrations/index.js.map +1 -0
  169. package/dist/persistence/category-store.d.ts +23 -0
  170. package/dist/persistence/category-store.d.ts.map +1 -0
  171. package/dist/persistence/category-store.js +86 -0
  172. package/dist/persistence/category-store.js.map +1 -0
  173. package/dist/persistence/comment-store.d.ts +41 -0
  174. package/dist/persistence/comment-store.d.ts.map +1 -0
  175. package/dist/persistence/comment-store.js +146 -0
  176. package/dist/persistence/comment-store.js.map +1 -0
  177. package/dist/persistence/entities.d.ts +103 -0
  178. package/dist/persistence/entities.d.ts.map +1 -0
  179. package/dist/persistence/entities.js +188 -0
  180. package/dist/persistence/entities.js.map +1 -0
  181. package/dist/persistence/friend-link-store.d.ts +26 -0
  182. package/dist/persistence/friend-link-store.d.ts.map +1 -0
  183. package/dist/persistence/friend-link-store.js +80 -0
  184. package/dist/persistence/friend-link-store.js.map +1 -0
  185. package/dist/persistence/page-store.d.ts +35 -0
  186. package/dist/persistence/page-store.d.ts.map +1 -0
  187. package/dist/persistence/page-store.js +125 -0
  188. package/dist/persistence/page-store.js.map +1 -0
  189. package/dist/persistence/post-engagement-store.d.ts +23 -0
  190. package/dist/persistence/post-engagement-store.d.ts.map +1 -0
  191. package/dist/persistence/post-engagement-store.js +85 -0
  192. package/dist/persistence/post-engagement-store.js.map +1 -0
  193. package/dist/persistence/post-store.d.ts +87 -0
  194. package/dist/persistence/post-store.d.ts.map +1 -0
  195. package/dist/persistence/post-store.js +465 -0
  196. package/dist/persistence/post-store.js.map +1 -0
  197. package/dist/persistence/tag-store.d.ts +21 -0
  198. package/dist/persistence/tag-store.d.ts.map +1 -0
  199. package/dist/persistence/tag-store.js +82 -0
  200. package/dist/persistence/tag-store.js.map +1 -0
  201. package/dist/services/application.service.d.ts +4 -0
  202. package/dist/services/application.service.d.ts.map +1 -0
  203. package/dist/services/application.service.js +22 -0
  204. package/dist/services/application.service.js.map +1 -0
  205. package/dist/services/blog-runtime.service.d.ts +10 -0
  206. package/dist/services/blog-runtime.service.d.ts.map +1 -0
  207. package/dist/services/blog-runtime.service.js +32 -0
  208. package/dist/services/blog-runtime.service.js.map +1 -0
  209. package/dist/services/blog.boot.d.ts +6 -0
  210. package/dist/services/blog.boot.d.ts.map +1 -0
  211. package/dist/services/blog.boot.js +13 -0
  212. package/dist/services/blog.boot.js.map +1 -0
  213. package/dist/services/browser-api-provider.service.d.ts +4 -0
  214. package/dist/services/browser-api-provider.service.d.ts.map +1 -0
  215. package/dist/services/browser-api-provider.service.js +25 -0
  216. package/dist/services/browser-api-provider.service.js.map +1 -0
  217. package/dist/services/config.service.d.ts +3 -0
  218. package/dist/services/config.service.d.ts.map +1 -0
  219. package/dist/services/config.service.js +22 -0
  220. package/dist/services/config.service.js.map +1 -0
  221. package/dist/services/database.service.d.ts +3 -0
  222. package/dist/services/database.service.d.ts.map +1 -0
  223. package/dist/services/database.service.js +16 -0
  224. package/dist/services/database.service.js.map +1 -0
  225. package/dist/services/logger.service.d.ts +4 -0
  226. package/dist/services/logger.service.d.ts.map +1 -0
  227. package/dist/services/logger.service.js +8 -0
  228. package/dist/services/logger.service.js.map +1 -0
  229. package/dist/services/mcp-provider.service.d.ts +3 -0
  230. package/dist/services/mcp-provider.service.d.ts.map +1 -0
  231. package/dist/services/mcp-provider.service.js +17 -0
  232. package/dist/services/mcp-provider.service.js.map +1 -0
  233. package/dist/services/redis.service.d.ts +4 -0
  234. package/dist/services/redis.service.d.ts.map +1 -0
  235. package/dist/services/redis.service.js +18 -0
  236. package/dist/services/redis.service.js.map +1 -0
  237. package/dist/services/theme-control.service.d.ts +4 -0
  238. package/dist/services/theme-control.service.d.ts.map +1 -0
  239. package/dist/services/theme-control.service.js +53 -0
  240. package/dist/services/theme-control.service.js.map +1 -0
  241. package/dist/themes/theme-catalog.d.ts +40 -0
  242. package/dist/themes/theme-catalog.d.ts.map +1 -0
  243. package/dist/themes/theme-catalog.js +164 -0
  244. package/dist/themes/theme-catalog.js.map +1 -0
  245. package/dist/themes/theme-control.d.ts +16 -0
  246. package/dist/themes/theme-control.d.ts.map +1 -0
  247. package/dist/themes/theme-control.js +57 -0
  248. package/dist/themes/theme-control.js.map +1 -0
  249. package/dist/themes/theme-discovery-runtime.d.ts +41 -0
  250. package/dist/themes/theme-discovery-runtime.d.ts.map +1 -0
  251. package/dist/themes/theme-discovery-runtime.js +109 -0
  252. package/dist/themes/theme-discovery-runtime.js.map +1 -0
  253. package/dist/themes/theme-generation-store.d.ts +14 -0
  254. package/dist/themes/theme-generation-store.d.ts.map +1 -0
  255. package/dist/themes/theme-generation-store.js +49 -0
  256. package/dist/themes/theme-generation-store.js.map +1 -0
  257. package/dist/themes/theme-selection-publisher.d.ts +28 -0
  258. package/dist/themes/theme-selection-publisher.d.ts.map +1 -0
  259. package/dist/themes/theme-selection-publisher.js +92 -0
  260. package/dist/themes/theme-selection-publisher.js.map +1 -0
  261. package/dist/themes/theme-selection-store.d.ts +22 -0
  262. package/dist/themes/theme-selection-store.d.ts.map +1 -0
  263. package/dist/themes/theme-selection-store.js +84 -0
  264. package/dist/themes/theme-selection-store.js.map +1 -0
  265. package/package.json +74 -0
@@ -0,0 +1,153 @@
1
+ import type { DataSource } from 'typeorm';
2
+ import { type CategoryInput } from '../persistence/category-store.js';
3
+ import { type FriendLinkInput } from '../persistence/friend-link-store.js';
4
+ import { type PostInput } from '../persistence/post-store.js';
5
+ import { type PageInput } from '../persistence/page-store.js';
6
+ import { type TagInput } from '../persistence/tag-store.js';
7
+ import type { BlogCommentStatus } from '../persistence/entities.js';
8
+ export type PostContentAuditRequest = Readonly<Pick<PostInput, 'categoryId' | 'title' | 'summary' | 'content' | 'tagIds'>>;
9
+ export declare class BlogApplication {
10
+ #private;
11
+ constructor(dataSource: DataSource, clock?: () => Date);
12
+ listCategories: (signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCategoryRow[]>;
13
+ listCategoryPage: (limit: number, cursor?: string, signal?: AbortSignal) => Promise<{
14
+ items: import("../persistence/entities.js").BlogCategoryRow[];
15
+ nextCursor: string | null;
16
+ }>;
17
+ readCategories: (ids: readonly string[], signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCategoryRow[]>;
18
+ readCategory: (id: string, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCategoryRow>;
19
+ createCategory: (input: CategoryInput, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCategoryRow>;
20
+ updateCategory: (id: string, input: CategoryInput, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCategoryRow>;
21
+ deleteCategory: (id: string, signal?: AbortSignal) => Promise<void>;
22
+ listTags: (signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogTagRow[]>;
23
+ listTagPage: (limit: number, cursor?: string, signal?: AbortSignal) => Promise<{
24
+ items: import("../persistence/entities.js").BlogTagRow[];
25
+ nextCursor: string | null;
26
+ }>;
27
+ readTag: (id: string, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogTagRow>;
28
+ createTag: (input: TagInput, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogTagRow>;
29
+ updateTag: (id: string, input: TagInput, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogTagRow>;
30
+ deleteTag: (id: string, signal?: AbortSignal) => Promise<void>;
31
+ listPosts: (input: {
32
+ limit: number;
33
+ cursor?: string | undefined;
34
+ status?: 'draft' | 'published' | 'archived' | undefined;
35
+ categoryId?: string | undefined;
36
+ }, signal?: AbortSignal) => Promise<{
37
+ items: import("../persistence/post-store.js").PostView[];
38
+ nextCursor: string | null;
39
+ }>;
40
+ listPublicPosts: (input: {
41
+ limit: number;
42
+ cursor?: string;
43
+ page?: number;
44
+ categorySlug?: string;
45
+ tagSlug?: string;
46
+ }, signal?: AbortSignal) => Promise<{
47
+ items: import("../persistence/post-store.js").PostView[];
48
+ nextCursor: string | null;
49
+ total: number;
50
+ }>;
51
+ countPublishedPostsByCategory: (signal?: AbortSignal) => Promise<ReadonlyMap<string, number>>;
52
+ listPublicPostArchive: (input: {
53
+ limit: number;
54
+ monthLimit: number;
55
+ cursor?: string;
56
+ page?: number;
57
+ year?: number;
58
+ month?: number;
59
+ startYear?: number;
60
+ startMonth?: number;
61
+ endYear?: number;
62
+ endMonth?: number;
63
+ }, signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostArchivePage>;
64
+ searchPosts: (input: {
65
+ query: string;
66
+ limit: number;
67
+ status?: 'draft' | 'published' | 'archived';
68
+ }, signal?: AbortSignal) => Promise<readonly import("../persistence/post-store.js").PostView[]>;
69
+ readPost: (id: string, signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostView>;
70
+ readPublicPost: (slug: string, signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostView | undefined>;
71
+ readPublishedPosts: (ids: readonly string[], signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostView[]>;
72
+ readPublicPostConnections: (slug: string, relatedLimit: number, signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostConnections | undefined>;
73
+ recordPostView: (postId: string, subjectHashes: readonly string[], now: Date, windowMs: number, signal?: AbortSignal) => Promise<import("../persistence/post-engagement-store.js").PostViewResult>;
74
+ readPostEngagement: (postId: string, userId?: string, signal?: AbortSignal) => Promise<import("../persistence/post-engagement-store.js").PostEngagementResult>;
75
+ setPostLiked: (postId: string, userId: string, liked: boolean, signal?: AbortSignal) => Promise<{
76
+ liked: boolean;
77
+ likeCount: number;
78
+ }>;
79
+ auditPostContent(input: PostContentAuditRequest, signal?: AbortSignal): Promise<Readonly<{
80
+ publishable: boolean;
81
+ findings: readonly import("./post-content-audit.js").ContentAuditFinding[];
82
+ }>>;
83
+ createPost: (input: PostInput, signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostView>;
84
+ updatePost: (id: string, input: PostInput, signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostView>;
85
+ publishPost: (id: string, signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostView>;
86
+ archivePost: (id: string, signal?: AbortSignal) => Promise<import("../persistence/post-store.js").PostView>;
87
+ deletePost: (id: string, signal?: AbortSignal) => Promise<void>;
88
+ listComments: (input: {
89
+ limit: number;
90
+ cursor?: string | undefined;
91
+ status?: BlogCommentStatus | undefined;
92
+ postId?: string | undefined;
93
+ order?: 'desc' | 'asc';
94
+ }, signal?: AbortSignal) => Promise<{
95
+ items: import("../persistence/entities.js").BlogCommentRow[];
96
+ nextCursor: string | null;
97
+ }>;
98
+ listRecentApprovedComments: (limit: number, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCommentRow[]>;
99
+ listPublicCommentPage: (postId: string, limit: number, cursor?: string, signal?: AbortSignal) => Promise<{
100
+ items: import("../persistence/entities.js").BlogCommentRow[];
101
+ nextCursor: string | null;
102
+ }>;
103
+ listVisibleCommentPage: (postId: string, limit: number, cursor?: string, viewerUserId?: string, order?: 'desc' | 'asc', signal?: AbortSignal) => Promise<{
104
+ items: import("../persistence/entities.js").BlogCommentRow[];
105
+ nextCursor: string | null;
106
+ }>;
107
+ readComment: (id: string, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCommentRow>;
108
+ updateCommentStatus: (id: string, status: BlogCommentStatus, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCommentRow>;
109
+ replyComment: (id: string, content: string | null, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogCommentRow>;
110
+ deleteComment: (id: string, signal?: AbortSignal) => Promise<void>;
111
+ listFriendLinkPage: (limit: number, cursor?: string, signal?: AbortSignal) => Promise<{
112
+ items: import("../persistence/entities.js").BlogFriendLinkRow[];
113
+ nextCursor: string | null;
114
+ }>;
115
+ listPublicFriendLinks: (signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogFriendLinkRow[]>;
116
+ readFriendLink: (id: string, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogFriendLinkRow>;
117
+ createFriendLink: (input: FriendLinkInput, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogFriendLinkRow>;
118
+ updateFriendLink: (id: string, input: FriendLinkInput, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogFriendLinkRow>;
119
+ setFriendLinkEnabled: (id: string, enabled: boolean, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogFriendLinkRow>;
120
+ deleteFriendLink: (id: string, signal?: AbortSignal) => Promise<void>;
121
+ listPages: (input: {
122
+ limit: number;
123
+ cursor?: string | undefined;
124
+ status?: 'draft' | 'published' | 'archived' | undefined;
125
+ position?: 'navigation' | 'sidebar' | null | undefined;
126
+ }, signal?: AbortSignal) => Promise<{
127
+ items: import("../persistence/entities.js").BlogPageRow[];
128
+ nextCursor: string | null;
129
+ }>;
130
+ listPublicPages: (position?: 'navigation' | 'sidebar' | null, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogPageRow[]>;
131
+ readPage: (id: string, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogPageRow>;
132
+ readPublicPage: (slug: string, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogPageRow | undefined>;
133
+ createPage: (input: PageInput, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogPageRow>;
134
+ updatePage: (id: string, input: PageInput, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogPageRow>;
135
+ publishPage: (id: string, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogPageRow>;
136
+ archivePage: (id: string, signal?: AbortSignal) => Promise<import("../persistence/entities.js").BlogPageRow>;
137
+ deletePage: (id: string, signal?: AbortSignal) => Promise<void>;
138
+ createComment(input: {
139
+ postId: string;
140
+ userId: string;
141
+ content: string;
142
+ ipAddress?: string | null;
143
+ userAgent?: string | null;
144
+ ipLocation?: string | null;
145
+ clientLabel?: string | null;
146
+ }, signal?: AbortSignal): Promise<import("../persistence/entities.js").BlogCommentRow>;
147
+ }
148
+ export type { PostInput, PostView } from '../persistence/post-store.js';
149
+ export type { CategoryInput } from '../persistence/category-store.js';
150
+ export type { TagInput } from '../persistence/tag-store.js';
151
+ export type { FriendLinkInput } from '../persistence/friend-link-store.js';
152
+ export type { PageInput } from '../persistence/page-store.js';
153
+ //# sourceMappingURL=blog-application.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blog-application.d.ts","sourceRoot":"","sources":["../../src/blog/blog-application.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ import { CategoryStore } from '../persistence/category-store.js';
2
+ import { CommentStore } from '../persistence/comment-store.js';
3
+ import { FriendLinkStore } from '../persistence/friend-link-store.js';
4
+ import { PostStore } from '../persistence/post-store.js';
5
+ import { PostEngagementStore } from '../persistence/post-engagement-store.js';
6
+ import { PageStore } from '../persistence/page-store.js';
7
+ import { TagStore } from '../persistence/tag-store.js';
8
+ import { auditPostContent as inspectPostContent } from './post-content-audit.js';
9
+ import { BlogConflictError, BlogNotFoundError } from './errors.js';
10
+ export class BlogApplication {
11
+ #categories;
12
+ #tags;
13
+ #posts;
14
+ #engagement;
15
+ #comments;
16
+ #friendLinks;
17
+ #pages;
18
+ constructor(dataSource, clock = () => new Date()) {
19
+ this.#categories = new CategoryStore(dataSource);
20
+ this.#tags = new TagStore(dataSource);
21
+ this.#posts = new PostStore(dataSource, clock);
22
+ this.#engagement = new PostEngagementStore(dataSource);
23
+ this.#comments = new CommentStore(dataSource, clock);
24
+ this.#friendLinks = new FriendLinkStore(dataSource);
25
+ this.#pages = new PageStore(dataSource, clock);
26
+ }
27
+ listCategories = (signal) => this.#categories.list(500, signal);
28
+ listCategoryPage = (limit, cursor, signal) => this.#categories.listPage(limit, cursor, signal);
29
+ readCategories = (ids, signal) => this.#categories.readMany(ids, signal);
30
+ readCategory = (id, signal) => this.#categories.read(id, signal);
31
+ createCategory = (input, signal) => this.#categories.create(input, signal);
32
+ updateCategory = (id, input, signal) => this.#categories.update(id, input, signal);
33
+ deleteCategory = (id, signal) => this.#categories.delete(id, signal);
34
+ listTags = (signal) => this.#tags.list(1_000, signal);
35
+ listTagPage = (limit, cursor, signal) => this.#tags.listPage(limit, cursor, signal);
36
+ readTag = (id, signal) => this.#tags.read(id, signal);
37
+ createTag = (input, signal) => this.#tags.create(input, signal);
38
+ updateTag = (id, input, signal) => this.#tags.update(id, input, signal);
39
+ deleteTag = (id, signal) => this.#tags.delete(id, signal);
40
+ listPosts = (input, signal) => this.#posts.list(input, signal);
41
+ listPublicPosts = (input, signal) => this.#posts.listPublished(input, signal);
42
+ countPublishedPostsByCategory = (signal) => this.#posts.countPublishedByCategory(signal);
43
+ listPublicPostArchive = (input, signal) => this.#posts.listPublishedArchive(input, signal);
44
+ searchPosts = (input, signal) => this.#posts.search(input, signal);
45
+ readPost = (id, signal) => this.#posts.read(id, signal);
46
+ readPublicPost = (slug, signal) => this.#posts.readPublishedBySlug(slug, signal);
47
+ readPublishedPosts = (ids, signal) => this.#posts.readPublishedByIds(ids, signal);
48
+ readPublicPostConnections = (slug, relatedLimit, signal) => this.#posts.readPublishedConnections(slug, relatedLimit, signal);
49
+ recordPostView = (postId, subjectHashes, now, windowMs, signal) => this.#engagement.recordView(postId, subjectHashes, now, windowMs, signal);
50
+ readPostEngagement = (postId, userId, signal) => this.#engagement.read(postId, userId, signal);
51
+ setPostLiked = (postId, userId, liked, signal) => this.#engagement.setLiked(postId, userId, liked, signal);
52
+ async auditPostContent(input, signal) {
53
+ signal?.throwIfAborted();
54
+ if (input.tagIds.length > 20)
55
+ throw new BlogConflictError('Post cannot contain more than 20 tags');
56
+ if (new Set(input.tagIds).size !== input.tagIds.length)
57
+ throw new BlogConflictError('Post tags must be unique');
58
+ const [category, tags] = await Promise.all([
59
+ this.#categories.read(input.categoryId, signal),
60
+ this.#tags.readMany(input.tagIds, signal),
61
+ ]);
62
+ signal?.throwIfAborted();
63
+ if (tags.length !== input.tagIds.length)
64
+ throw new BlogNotFoundError('Tag not found');
65
+ const tagsById = new Map(tags.map((tag) => [tag.id, tag]));
66
+ const taxonomy = {
67
+ category: { name: category.name },
68
+ tags: input.tagIds.map((id) => {
69
+ const tag = tagsById.get(id);
70
+ if (!tag)
71
+ throw new BlogNotFoundError('Tag not found');
72
+ return { name: tag.name };
73
+ }),
74
+ };
75
+ return inspectPostContent({
76
+ title: input.title,
77
+ summary: input.summary,
78
+ content: input.content,
79
+ taxonomy,
80
+ });
81
+ }
82
+ createPost = (input, signal) => this.#posts.create(input, signal);
83
+ updatePost = (id, input, signal) => this.#posts.update(id, input, signal);
84
+ publishPost = (id, signal) => this.#posts.publish(id, signal);
85
+ archivePost = (id, signal) => this.#posts.archive(id, signal);
86
+ deletePost = (id, signal) => this.#posts.delete(id, signal);
87
+ listComments = (input, signal) => this.#comments.list(input, signal);
88
+ listRecentApprovedComments = (limit, signal) => this.#comments.listRecentApprovedForPublishedPosts(limit, signal);
89
+ listPublicCommentPage = (postId, limit, cursor, signal) => this.#comments.listApprovedPage(postId, limit, cursor, signal);
90
+ listVisibleCommentPage = (postId, limit, cursor, viewerUserId, order = 'desc', signal) => this.#comments.listVisiblePage(postId, limit, cursor, viewerUserId, order, signal);
91
+ readComment = (id, signal) => this.#comments.read(id, signal);
92
+ updateCommentStatus = (id, status, signal) => this.#comments.setStatus(id, status, signal);
93
+ replyComment = (id, content, signal) => this.#comments.reply(id, content, signal);
94
+ deleteComment = (id, signal) => this.#comments.delete(id, signal);
95
+ listFriendLinkPage = (limit, cursor, signal) => this.#friendLinks.listPage(limit, cursor, signal);
96
+ listPublicFriendLinks = (signal) => this.#friendLinks.listEnabled(signal);
97
+ readFriendLink = (id, signal) => this.#friendLinks.read(id, signal);
98
+ createFriendLink = (input, signal) => this.#friendLinks.create(input, signal);
99
+ updateFriendLink = (id, input, signal) => this.#friendLinks.update(id, input, signal);
100
+ setFriendLinkEnabled = (id, enabled, signal) => this.#friendLinks.setEnabled(id, enabled, signal);
101
+ deleteFriendLink = (id, signal) => this.#friendLinks.delete(id, signal);
102
+ listPages = (input, signal) => this.#pages.list(input, signal);
103
+ listPublicPages = (position, signal) => this.#pages.listPublished(position, signal);
104
+ readPage = (id, signal) => this.#pages.read(id, signal);
105
+ readPublicPage = (slug, signal) => this.#pages.readPublishedBySlug(slug, signal);
106
+ createPage = (input, signal) => this.#pages.create(input, signal);
107
+ updatePage = (id, input, signal) => this.#pages.update(id, input, signal);
108
+ publishPage = (id, signal) => this.#pages.publish(id, signal);
109
+ archivePage = (id, signal) => this.#pages.archive(id, signal);
110
+ deletePage = (id, signal) => this.#pages.delete(id, signal);
111
+ async createComment(input, signal) {
112
+ return this.#comments.createForPublishedPost(input, signal);
113
+ }
114
+ }
115
+ //# sourceMappingURL=blog-application.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blog-application.js","sourceRoot":"","sources":["../../src/blog/blog-application.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { BrowserApiClient } from '@zlooks.cn/browser-api';
2
+ export interface CommentClientMetadata {
3
+ readonly ipAddress: string | null;
4
+ readonly userAgent: string | null;
5
+ readonly ipLocation: string | null;
6
+ readonly clientLabel: string | null;
7
+ }
8
+ export interface CommentClientMetadataResolver {
9
+ resolve(client: BrowserApiClient | undefined): Promise<CommentClientMetadata>;
10
+ }
11
+ export declare class OfflineCommentClientMetadataResolver implements CommentClientMetadataResolver {
12
+ #private;
13
+ constructor();
14
+ resolve(client: BrowserApiClient | undefined): Promise<CommentClientMetadata>;
15
+ private resolveLocation;
16
+ }
17
+ export declare function summarizeUserAgent(userAgent: string | null | undefined): string | null;
18
+ export declare function formatRegion(region: string): string | null;
19
+ //# sourceMappingURL=comment-client-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment-client-metadata.d.ts","sourceRoot":"","sources":["../../src/blog/comment-client-metadata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAO/D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC/E;AAID,qBAAa,oCAAqC,YAAW,6BAA6B;;IAGxF,cAEC;IAEY,OAAO,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC,qBAAqB,CAAC,CASzF;YAEa,eAAe;CAS9B;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAkBtF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM1D"}
@@ -0,0 +1,78 @@
1
+ import { isIP } from 'node:net';
2
+ import { defaultDbFile, loadContentFromFile, newWithBuffer, } from 'ip2region-ts';
3
+ export class OfflineCommentClientMetadataResolver {
4
+ #searcher;
5
+ constructor() {
6
+ this.#searcher = newWithBuffer(loadContentFromFile(defaultDbFile));
7
+ }
8
+ async resolve(client) {
9
+ if (!client)
10
+ return emptyMetadata();
11
+ const ipAddress = normalizeIpAddress(client.ipAddress);
12
+ return {
13
+ ipAddress,
14
+ userAgent: client.userAgent ?? null,
15
+ ipLocation: await this.resolveLocation(ipAddress),
16
+ clientLabel: summarizeUserAgent(client.userAgent),
17
+ };
18
+ }
19
+ async resolveLocation(ipAddress) {
20
+ if (isPrivateOrLocalAddress(ipAddress))
21
+ return '本地网络';
22
+ try {
23
+ const result = await this.#searcher.search(ipAddress);
24
+ return result.region ? formatRegion(result.region) : null;
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ }
31
+ export function summarizeUserAgent(userAgent) {
32
+ if (!userAgent)
33
+ return null;
34
+ const browser = matchLabel(userAgent, [
35
+ [/Edg(?:A|iOS)?\//, 'Edge'],
36
+ [/OPR\//, 'Opera'],
37
+ [/(?:Chrome|CriOS)\//, 'Chrome'],
38
+ [/(?:Firefox|FxiOS)\//, 'Firefox'],
39
+ [/Version\/[^ ]+.*Safari\//, 'Safari'],
40
+ ]);
41
+ const platform = matchLabel(userAgent, [
42
+ [/iPhone|iPod/, 'iPhone'],
43
+ [/iPad/, 'iPad'],
44
+ [/Android/, 'Android'],
45
+ [/Windows NT/, 'Windows'],
46
+ [/Macintosh|Mac OS X/, 'macOS'],
47
+ [/Linux/, 'Linux'],
48
+ ]);
49
+ return [browser, platform].filter(Boolean).join(' · ') || null;
50
+ }
51
+ export function formatRegion(region) {
52
+ const values = region.split('|').map((value) => value.trim()).filter((value) => value && value !== '0');
53
+ if (values.length === 0)
54
+ return null;
55
+ const [country, ...rest] = values;
56
+ const visible = country === '中国' ? rest : values;
57
+ return visible.slice(0, 4).join(' ') || country || null;
58
+ }
59
+ function matchLabel(value, candidates) {
60
+ return candidates.find(([pattern]) => pattern.test(value))?.[1];
61
+ }
62
+ function normalizeIpAddress(value) {
63
+ return value.startsWith('::ffff:') && isIP(value.slice(7)) === 4 ? value.slice(7) : value;
64
+ }
65
+ function isPrivateOrLocalAddress(value) {
66
+ if (value === '::1' || value === '127.0.0.1')
67
+ return true;
68
+ if (value.startsWith('10.') || value.startsWith('192.168.'))
69
+ return true;
70
+ const match = /^172\.(\d{1,3})\./.exec(value);
71
+ if (match?.[1] && Number(match[1]) >= 16 && Number(match[1]) <= 31)
72
+ return true;
73
+ return /^(?:fc|fd|fe8|fe9|fea|feb)/i.test(value);
74
+ }
75
+ function emptyMetadata() {
76
+ return { ipAddress: null, userAgent: null, ipLocation: null, clientLabel: null };
77
+ }
78
+ //# sourceMappingURL=comment-client-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment-client-metadata.js","sourceRoot":"","sources":["../../src/blog/comment-client-metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { PostContentAuditReport } from './post-content-audit.js';
2
+ export declare class BlogNotFoundError extends Error {
3
+ }
4
+ export declare class BlogConflictError extends Error {
5
+ }
6
+ export declare class BlogCursorError extends Error {
7
+ }
8
+ export declare class PostContentBlockedError extends BlogConflictError {
9
+ readonly report: PostContentAuditReport;
10
+ constructor(report: PostContentAuditReport);
11
+ }
12
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/blog/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAC/C,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAC/C,qBAAa,eAAgB,SAAQ,KAAK;CAAG;AAE7C,qBAAa,uBAAwB,SAAQ,iBAAiB;IAC5D,SAAgB,MAAM,EAAE,sBAAsB,CAAC;IAE/C,YAAmB,MAAM,EAAE,sBAAsB,EAUhD;CACF"}
@@ -0,0 +1,21 @@
1
+ export class BlogNotFoundError extends Error {
2
+ }
3
+ export class BlogConflictError extends Error {
4
+ }
5
+ export class BlogCursorError extends Error {
6
+ }
7
+ export class PostContentBlockedError extends BlogConflictError {
8
+ report;
9
+ constructor(report) {
10
+ const rules = [...new Set(report.findings
11
+ .filter((finding) => finding.severity === 'block')
12
+ .map((finding) => finding.ruleId))];
13
+ super(`Post content audit failed: ${rules.join(', ')}`);
14
+ this.name = 'PostContentBlockedError';
15
+ this.report = Object.freeze({
16
+ publishable: report.publishable,
17
+ findings: Object.freeze([...report.findings]),
18
+ });
19
+ }
20
+ }
21
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/blog/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,iBAAkB,SAAQ,KAAK;CAAG;AAC/C,MAAM,OAAO,iBAAkB,SAAQ,KAAK;CAAG;AAC/C,MAAM,OAAO,eAAgB,SAAQ,KAAK;CAAG;AAE7C,MAAM,OAAO,uBAAwB,SAAQ,iBAAiB;IAC5C,MAAM,CAAyB;IAE/C,YAAmB,MAA8B;QAC/C,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ;iBACtC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;iBACjD,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtC,KAAK,CAAC,8BAA8B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC1B,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;SAC9C,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,11 @@
1
+ import type { ExecutionContext } from '@hile/context';
2
+ import type { Application } from '@hile/micro';
3
+ import { type UserCurrentUserResponse, type UserPublicProfilesResponse } from '@zlooks.cn/user-shared';
4
+ import type { BlogUserDirectory } from './public-blog-service.js';
5
+ export declare class MicroUserDirectory implements BlogUserDirectory {
6
+ private readonly application;
7
+ constructor(application: Application);
8
+ authenticate(context: ExecutionContext, signal?: AbortSignal): Promise<UserCurrentUserResponse>;
9
+ readPublicProfiles(userIds: readonly string[], context: ExecutionContext, signal?: AbortSignal): Promise<UserPublicProfilesResponse>;
10
+ }
11
+ //# sourceMappingURL=micro-user-directory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"micro-user-directory.d.ts","sourceRoot":"","sources":["../../src/blog/micro-user-directory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAEL,KAAK,uBAAuB,EAAE,KAAK,0BAA0B,EAC9D,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,qBAAa,kBAAmB,YAAW,iBAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAA/C,YAAoC,WAAW,EAAE,WAAW,EAAI;IACzD,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAIrG;IACM,kBAAkB,CACvB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,gBAAgB,EACzB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,0BAA0B,CAAC,CAIrC;CACF"}
@@ -0,0 +1,18 @@
1
+ import { readCurrentUser, readUserPublicProfiles, } from '@zlooks.cn/user-shared';
2
+ export class MicroUserDirectory {
3
+ application;
4
+ constructor(application) {
5
+ this.application = application;
6
+ }
7
+ authenticate(context, signal) {
8
+ return readCurrentUser(this.application, {
9
+ context, timeout: 5_000, retries: 0, ...(signal ? { signal } : {}),
10
+ });
11
+ }
12
+ readPublicProfiles(userIds, context, signal) {
13
+ return readUserPublicProfiles(this.application, { userIds: [...userIds] }, {
14
+ context, timeout: 5_000, retries: 0, ...(signal ? { signal } : {}),
15
+ });
16
+ }
17
+ }
18
+ //# sourceMappingURL=micro-user-directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"micro-user-directory.js","sourceRoot":"","sources":["../../src/blog/micro-user-directory.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EAAE,sBAAsB,GAExC,MAAM,wBAAwB,CAAC;AAGhC,MAAM,OAAO,kBAAkB;IACO,WAAW;IAA/C,YAAoC,WAAwB;2BAAxB,WAAW;IAAgB,CAAC;IACzD,YAAY,CAAC,OAAyB,EAAE,MAAoB;QACjE,OAAO,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE;YACvC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACnE,CAAC,CAAC;IACL,CAAC;IACM,kBAAkB,CACvB,OAA0B,EAC1B,OAAyB,EACzB,MAAoB;QAEpB,OAAO,sBAAsB,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,EAAE;YACzE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACnE,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,34 @@
1
+ export type ContentAuditSeverity = 'block' | 'warning' | 'info';
2
+ export type ContentAuditField = 'title' | 'summary' | 'content' | 'category' | 'tags';
3
+ export type ContentAuditFinding = Readonly<{
4
+ ruleId: string;
5
+ severity: ContentAuditSeverity;
6
+ source: 'project' | 'search-engine' | 'heuristic';
7
+ field: ContentAuditField;
8
+ message: string;
9
+ suggestion: string;
10
+ location?: Readonly<{
11
+ line: number;
12
+ column: number;
13
+ }>;
14
+ }>;
15
+ export type PostContentAuditReport = Readonly<{
16
+ publishable: boolean;
17
+ findings: readonly ContentAuditFinding[];
18
+ }>;
19
+ export type PostContentAuditInput = Readonly<{
20
+ title: string;
21
+ summary: string | null;
22
+ content: string;
23
+ taxonomy?: Readonly<{
24
+ category: Readonly<{
25
+ name: string;
26
+ }>;
27
+ tags: readonly Readonly<{
28
+ name: string;
29
+ }>[];
30
+ }>;
31
+ }>;
32
+ export declare const POST_CONTENT_AUDIT_FINDING_LIMIT = 200;
33
+ export declare function auditPostContent(input: PostContentAuditInput): PostContentAuditReport;
34
+ //# sourceMappingURL=post-content-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-content-audit.d.ts","sourceRoot":"","sources":["../../src/blog/post-content-audit.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAChE,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAEtF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,MAAM,EAAE,SAAS,GAAG,eAAe,GAAG,WAAW,CAAC;IAClD,KAAK,EAAE,iBAAiB,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC1C,CAAC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;QAClB,QAAQ,EAAE,QAAQ,CAAC;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACrC,IAAI,EAAE,SAAS,QAAQ,CAAC;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAC;CACJ,CAAC,CAAC;AAWH,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAEpD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAcrF"}