@twikoojs/edgeone-makers 2.0.12 → 2.0.14
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/cloud-functions/index.js +47 -38
- package/package.json +5 -5
|
@@ -43,7 +43,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
43
43
|
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
44
44
|
//#endregion
|
|
45
45
|
//#region ../shared/dist/index.mjs
|
|
46
|
-
/*! @twikoojs/shared v2.0.
|
|
46
|
+
/*! @twikoojs/shared v2.0.14 */
|
|
47
47
|
/**
|
|
48
48
|
* Twikoo 统一版本号常量(构建期占位符)。
|
|
49
49
|
*
|
|
@@ -56,7 +56,7 @@ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
|
56
56
|
* 占位符字面量由 `@twikoojs/tsdown-config` 的 `VERSION_PLACEHOLDER` 常量定义,
|
|
57
57
|
* 客户端与服务端统一读取本常量,避免版本号在多包之间手工同步。
|
|
58
58
|
*/
|
|
59
|
-
const VERSION = "2.0.
|
|
59
|
+
const VERSION = "2.0.14";
|
|
60
60
|
/**
|
|
61
61
|
* 后端事件名常量(Scope E:24 个客户端事件 + 1 个服务端内部事件)。
|
|
62
62
|
*
|
|
@@ -24334,19 +24334,33 @@ async function getXml2js() {
|
|
|
24334
24334
|
return pickDefault(await loadLib("xml2js"));
|
|
24335
24335
|
}
|
|
24336
24336
|
/**
|
|
24337
|
-
* 获取 html-to-text
|
|
24337
|
+
* 获取 html-to-text 编译产物;通知忽略图片,长度检查按替代文本或固定占位计数。
|
|
24338
|
+
* @param options 是否使用评论长度计数规则
|
|
24338
24339
|
* @returns 编译后的转换函数
|
|
24339
24340
|
*/
|
|
24340
|
-
async function getHtmlToText() {
|
|
24341
|
+
async function getHtmlToText(options = {}) {
|
|
24341
24342
|
return pickDefault(await loadLib("html-to-text")).compile({
|
|
24342
24343
|
wordwrap: false,
|
|
24343
|
-
|
|
24344
|
-
|
|
24345
|
-
|
|
24346
|
-
|
|
24347
|
-
|
|
24348
|
-
|
|
24349
|
-
|
|
24344
|
+
formatters: {
|
|
24345
|
+
/** 图片按替代文本计数;无替代文本的图片和分隔线各占 10 个字符。 */
|
|
24346
|
+
wordCount(elem, _walk, builder) {
|
|
24347
|
+
const text = elem.name === "img" ? elem.attribs.alt?.trim() : "";
|
|
24348
|
+
builder.addInline(text || "-".repeat(10), { noWordTransform: true });
|
|
24349
|
+
} },
|
|
24350
|
+
selectors: [
|
|
24351
|
+
{
|
|
24352
|
+
selector: "a",
|
|
24353
|
+
options: { ignoreHref: true }
|
|
24354
|
+
},
|
|
24355
|
+
{
|
|
24356
|
+
selector: "img",
|
|
24357
|
+
format: options.forWordCount ? "wordCount" : "skip"
|
|
24358
|
+
},
|
|
24359
|
+
...options.forWordCount ? [{
|
|
24360
|
+
selector: "hr",
|
|
24361
|
+
format: "wordCount"
|
|
24362
|
+
}] : []
|
|
24363
|
+
]
|
|
24350
24364
|
});
|
|
24351
24365
|
}
|
|
24352
24366
|
/**
|
|
@@ -24755,22 +24769,25 @@ async function parseCommentForAdmin(comments, caps) {
|
|
|
24755
24769
|
* 语义对齐)。
|
|
24756
24770
|
*
|
|
24757
24771
|
* 链路(COMMENT_SUBMIT):
|
|
24758
|
-
* 1. preCheckSpam 预检(长度 / 屏蔽词 / 人工审核标记 /
|
|
24772
|
+
* 1. preCheckSpam 预检(长度 / 屏蔽词 / 人工审核标记 / 违禁词)——按需加载纯文本转换器;
|
|
24759
24773
|
* 2. checkCaptcha 验证码(Turnstile / Geetest / Cap 内嵌或外部);
|
|
24760
24774
|
* 3. limitFilter 频率限制(单 IP 与全站 10 分钟窗口);
|
|
24761
24775
|
* 4. postCheckSpam 后检(腾讯云 TMS / Akismet / Jev / LLM,postSubmit 异步阶段)。
|
|
24762
24776
|
*/
|
|
24763
24777
|
/**
|
|
24764
|
-
*
|
|
24778
|
+
* 预垃圾评论检测;长度限制按 HTML 转换后的文本计算。
|
|
24765
24779
|
* @param comment 待检评论字段
|
|
24766
24780
|
* @param config 全量配置
|
|
24767
24781
|
* @param logger 请求日志
|
|
24768
24782
|
* @returns 是否标记为垃圾(MANUAL_REVIEW / 违禁词)
|
|
24769
24783
|
*/
|
|
24770
|
-
function preCheckSpam(comment, config, logger) {
|
|
24784
|
+
async function preCheckSpam(comment, config, logger) {
|
|
24771
24785
|
let limitLength = parseInt(String(config.LIMIT_LENGTH ?? ""));
|
|
24772
24786
|
if (Number.isNaN(limitLength)) limitLength = 500;
|
|
24773
|
-
if (limitLength
|
|
24787
|
+
if (limitLength) {
|
|
24788
|
+
if (comment.comment.length > limitLength * 10) throw new Error("评论内容过长");
|
|
24789
|
+
if ((await getHtmlToText({ forWordCount: true }))(comment.comment).length > limitLength) throw new Error("评论内容过长");
|
|
24790
|
+
}
|
|
24774
24791
|
if (config.BLOCKED_WORDS) {
|
|
24775
24792
|
const commentLowerCase = comment.comment.toLowerCase();
|
|
24776
24793
|
const nickLowerCase = comment.nick.toLowerCase();
|
|
@@ -25659,33 +25676,26 @@ function commentMatchesKeyword(comment, keyword, options = {}) {
|
|
|
25659
25676
|
}
|
|
25660
25677
|
/**
|
|
25661
25678
|
* 可见性语义展开(1.x getCommentQuery 的 $or 服务层等价形态):
|
|
25662
|
-
* 管理员(未开 HIDE_SPAM)全可见;否则「非垃圾
|
|
25679
|
+
* 管理员(未开 HIDE_SPAM)全可见;否则「非垃圾 + 本人垃圾」双查合并,两组互斥。
|
|
25663
25680
|
* @param db 数据库
|
|
25664
25681
|
* @param condition 基础条件
|
|
25665
25682
|
* @param uid 当前用户
|
|
25666
25683
|
* @param isAdminUser 是否管理员
|
|
25667
25684
|
* @param config 全量配置
|
|
25668
|
-
* @param options
|
|
25669
|
-
* @returns
|
|
25685
|
+
* @param options 查询选项(排序和读取上限同时应用于两个分支)
|
|
25686
|
+
* @returns 合并后的评论
|
|
25670
25687
|
*/
|
|
25671
25688
|
async function queryVisibleComments(db, condition, uid, isAdminUser, config, options) {
|
|
25672
25689
|
if (isAdminUser && config.HIDE_SPAM !== "true") return db.getComments(condition, options);
|
|
25673
|
-
const [notSpam,
|
|
25690
|
+
const [notSpam, mySpam] = await Promise.all([db.getComments({
|
|
25674
25691
|
...condition,
|
|
25675
25692
|
isSpam: { [NOT]: true }
|
|
25676
25693
|
}, options), db.getComments({
|
|
25677
25694
|
...condition,
|
|
25678
|
-
uid
|
|
25679
|
-
|
|
25680
|
-
|
|
25681
|
-
const merged = [];
|
|
25682
|
-
for (const doc of [...notSpam, ...mine]) {
|
|
25683
|
-
const id = String(doc._id);
|
|
25684
|
-
if (!seen.has(id)) {
|
|
25685
|
-
seen.add(id);
|
|
25686
|
-
merged.push(doc);
|
|
25687
|
-
}
|
|
25688
|
-
}
|
|
25695
|
+
uid,
|
|
25696
|
+
isSpam: true
|
|
25697
|
+
}, options)]);
|
|
25698
|
+
const merged = [...notSpam, ...mySpam];
|
|
25689
25699
|
if (options?.sort) {
|
|
25690
25700
|
const entries = Object.entries(options.sort);
|
|
25691
25701
|
merged.sort((a, b) => {
|
|
@@ -25786,7 +25796,7 @@ const commentGet = async (ctx) => {
|
|
|
25786
25796
|
};
|
|
25787
25797
|
};
|
|
25788
25798
|
/**
|
|
25789
|
-
*
|
|
25799
|
+
* 可见性计数:非垃圾 + 本人垃圾,两组互斥,避免读取完整文档去重。
|
|
25790
25800
|
* @param ctx 请求上下文
|
|
25791
25801
|
* @param condition 基础条件
|
|
25792
25802
|
* @returns 可见条数
|
|
@@ -25794,16 +25804,15 @@ const commentGet = async (ctx) => {
|
|
|
25794
25804
|
async function queryVisibleCount(ctx, condition) {
|
|
25795
25805
|
const db = ctx.adapters.database;
|
|
25796
25806
|
if (isAdmin(ctx.config, ctx.accessToken) && ctx.config.HIDE_SPAM !== "true") return db.countComments(condition);
|
|
25797
|
-
const [
|
|
25807
|
+
const [notSpam, mySpam] = await Promise.all([db.countComments({
|
|
25798
25808
|
...condition,
|
|
25799
25809
|
isSpam: { [NOT]: true }
|
|
25800
|
-
}), db.
|
|
25810
|
+
}), db.countComments({
|
|
25801
25811
|
...condition,
|
|
25802
|
-
uid: ctx.accessToken
|
|
25812
|
+
uid: ctx.accessToken,
|
|
25813
|
+
isSpam: true
|
|
25803
25814
|
})]);
|
|
25804
|
-
|
|
25805
|
-
for (const doc of [...a, ...b]) seen.add(String(doc._id));
|
|
25806
|
-
return seen.size;
|
|
25815
|
+
return notSpam + mySpam;
|
|
25807
25816
|
}
|
|
25808
25817
|
/**
|
|
25809
25818
|
* COMMENT_GET_FOR_ADMIN 事件处理器(1.x commentGetForAdmin + getCommentSearchCondition
|
|
@@ -26548,7 +26557,7 @@ async function parseCommentDoc(ctx) {
|
|
|
26548
26557
|
}),
|
|
26549
26558
|
pid: comment.pid ? toStr(comment.pid) : toStr(comment.rid),
|
|
26550
26559
|
rid: comment.rid,
|
|
26551
|
-
isSpam: isAdminUser ? false : preCheckSpam({
|
|
26560
|
+
isSpam: isAdminUser ? false : await preCheckSpam({
|
|
26552
26561
|
comment: toStr(comment.comment),
|
|
26553
26562
|
nick: toStr(comment.nick),
|
|
26554
26563
|
link: comment.link,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twikoojs/edgeone-makers",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.14",
|
|
4
4
|
"description": "Twikoo comment system backend for Tencent EdgeOne Makers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,19 +21,19 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@cap.js/server": "^4.0.5",
|
|
23
23
|
"@edgeone/pages-blob": "latest",
|
|
24
|
-
"@twikoojs/common": "2.0.
|
|
25
|
-
"@twikoojs/shared": "2.0.
|
|
24
|
+
"@twikoojs/common": "2.0.14",
|
|
25
|
+
"@twikoojs/shared": "2.0.14",
|
|
26
26
|
"bowser": "^2.14.1",
|
|
27
27
|
"form-data": "^4.0.6",
|
|
28
28
|
"html-to-text": "^10.0.1",
|
|
29
29
|
"marked": "^18.0.13",
|
|
30
30
|
"pako": "^3.0.2",
|
|
31
|
-
"pushoo": "^2.0.
|
|
31
|
+
"pushoo": "^2.0.14",
|
|
32
32
|
"xml2js": "^0.6.2"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@imaegoo/node-ip2region": "^2.1.1",
|
|
36
|
-
"@types/node": "^26.6.
|
|
36
|
+
"@types/node": "^26.6.4"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "node scripts/build-ip2region-data.mjs && tsdown && node scripts/build-zip.mjs",
|