chanjs 2.8.12 → 2.8.13
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/README.md +1 -1
- package/core/Repository.js +1 -1
- package/core/errors.js +1 -1
- package/middleware/template.js +0 -28
- package/package.json +17 -18
- package/response/response.js +1 -1
- package/utils/pages.js +4 -3
package/README.md
CHANGED
package/core/Repository.js
CHANGED
|
@@ -92,7 +92,7 @@ function mapUrlFilters(query, fieldMap) {
|
|
|
92
92
|
const filter = {};
|
|
93
93
|
for (const [key, map] of Object.entries(fieldMap || {})) {
|
|
94
94
|
const raw = query?.[key];
|
|
95
|
-
if (raw
|
|
95
|
+
if (raw == null || String(raw).trim() === "") continue;
|
|
96
96
|
let piece;
|
|
97
97
|
try {
|
|
98
98
|
piece = map(String(raw).trim());
|
package/core/errors.js
CHANGED
|
@@ -50,7 +50,7 @@ export class AppError extends Error {
|
|
|
50
50
|
const json = { name: this.name, message: this.message, code: this.code, httpStatus: this.httpStatus };
|
|
51
51
|
for (const key of Object.getOwnPropertyNames(this)) {
|
|
52
52
|
const val = this[key];
|
|
53
|
-
if (val
|
|
53
|
+
if (val == null) continue;
|
|
54
54
|
if (typeof val === 'function' || typeof val === 'symbol') continue;
|
|
55
55
|
json[key] = val;
|
|
56
56
|
}
|
package/middleware/template.js
CHANGED
|
@@ -3,7 +3,6 @@ import dayjs from "dayjs";
|
|
|
3
3
|
import { createRequire } from "module";
|
|
4
4
|
import relativeTime from "dayjs/plugin/relativeTime.js";
|
|
5
5
|
import "dayjs/locale/zh-cn.js";
|
|
6
|
-
import { marked } from "marked";
|
|
7
6
|
import logger from "../utils/logger.js";
|
|
8
7
|
|
|
9
8
|
const require = createRequire(import.meta.url);
|
|
@@ -73,33 +72,6 @@ artTemplate.defaults.imports.safeStringify = (obj, keys) => {
|
|
|
73
72
|
artTemplate.defaults.imports.objKeys = (obj, separator = "\n") =>
|
|
74
73
|
typeof obj === "object" && obj ? Object.keys(obj).join(separator) : "";
|
|
75
74
|
|
|
76
|
-
/**
|
|
77
|
-
* Markdown渲染 + XSS过滤
|
|
78
|
-
* @param {string} content
|
|
79
|
-
* @param {"md"|"rich"} [editorType="rich"]
|
|
80
|
-
* @param {0|1} [allowScript=0] 1=信任内容不做XSS过滤
|
|
81
|
-
* @returns {string}
|
|
82
|
-
*/
|
|
83
|
-
artTemplate.defaults.imports.renderContent = (content, editorType = "rich", allowScript = 0) => {
|
|
84
|
-
if (typeof content !== "string") return content || "";
|
|
85
|
-
let html = content;
|
|
86
|
-
|
|
87
|
-
if (editorType === "md") {
|
|
88
|
-
try {
|
|
89
|
-
// marked v4+ 支持异步扩展,返回 string | Promise<string>
|
|
90
|
-
// 同步场景下直接取结果;若返回 Promise 则降级为空字符串
|
|
91
|
-
const result = marked.parse(content);
|
|
92
|
-
html = typeof result === "string" ? result : "";
|
|
93
|
-
} catch (e) {
|
|
94
|
-
logger.error(`[renderContent] MD解析失败: ${e.message}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// 正文 XSS 已在后台保存时统一 sanitize(sanitizeRichText),
|
|
99
|
-
// 此处不再二次转义,避免破坏第三方嵌入(B站 iframe)与自定义 class 样式。
|
|
100
|
-
return html;
|
|
101
|
-
};
|
|
102
|
-
|
|
103
75
|
/**
|
|
104
76
|
* art-template模板引擎中间件
|
|
105
77
|
* @param {express.Application} app
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "chanjs",
|
|
4
|
-
"version": "2.8.
|
|
4
|
+
"version": "2.8.13",
|
|
5
5
|
"description": "chanjs基于 Node.js + Express 5 的标准 HMVC 框架(NHMVC),纯 JavaScript(ESM)开发。",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"module": "index.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"nodejs mvc"
|
|
15
15
|
],
|
|
16
16
|
"engines": {
|
|
17
|
-
"node": ">=22.
|
|
17
|
+
"node": ">=24.22.1"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"test": "node --test"
|
|
@@ -37,29 +37,28 @@
|
|
|
37
37
|
"art-template": "^4.13.4",
|
|
38
38
|
"cookie-parser": "^1.4.7",
|
|
39
39
|
"cors": "^2.8.6",
|
|
40
|
-
"dayjs": "^1.11.
|
|
41
|
-
"dotenv": "^
|
|
42
|
-
"express": "^5.
|
|
40
|
+
"dayjs": "^1.11.23",
|
|
41
|
+
"dotenv": "^18.0.9",
|
|
42
|
+
"express": "^5.3.0",
|
|
43
43
|
"express-art-template": "^1.0.1",
|
|
44
|
-
"i18next": "^
|
|
45
|
-
"ioredis": "^
|
|
44
|
+
"i18next": "^26.5.11",
|
|
45
|
+
"ioredis": "^6.0.0",
|
|
46
46
|
"jsonwebtoken": "^9.0.3",
|
|
47
|
-
"knex": "^3.
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"pino": "^
|
|
53
|
-
"pino-
|
|
54
|
-
"pino-pretty": "^13.1.3",
|
|
47
|
+
"knex": "^3.3.0",
|
|
48
|
+
"mysql2": "^3.24.6",
|
|
49
|
+
"node-cron": "^4.6.0",
|
|
50
|
+
"pg": "^8.23.1",
|
|
51
|
+
"pino": "^10.4.0",
|
|
52
|
+
"pino-http": "^11.0.0",
|
|
53
|
+
"pino-pretty": "^13.2.0",
|
|
55
54
|
"serve-favicon": "^2.5.1",
|
|
56
|
-
"xss": "^1.0.
|
|
55
|
+
"xss": "^1.0.17"
|
|
57
56
|
},
|
|
58
57
|
"devDependencies": {
|
|
59
|
-
"zod": "^4.
|
|
58
|
+
"zod": "^4.6.7"
|
|
60
59
|
},
|
|
61
60
|
"peerDependencies": {
|
|
62
|
-
"zod": "^4.
|
|
61
|
+
"zod": "^4.6.7"
|
|
63
62
|
},
|
|
64
63
|
"peerDependenciesMeta": {
|
|
65
64
|
"zod": {
|
package/response/response.js
CHANGED
|
@@ -38,7 +38,7 @@ export function serializeError(err, exposeDetail = false) {
|
|
|
38
38
|
if (NEVER_EXPOSE.has(key)) continue;
|
|
39
39
|
if (SENSITIVE.has(key) && !exposeDetail) continue; // 生产环境不泄露堆栈/根因(SQL)
|
|
40
40
|
const val = err[key];
|
|
41
|
-
if (val
|
|
41
|
+
if (val == null) continue;
|
|
42
42
|
if (typeof val === "function" || typeof val === "symbol") continue;
|
|
43
43
|
try { extra[key] = val && typeof val === "object" && !Array.isArray(val) ? JSON.stringify(val) : val; }
|
|
44
44
|
catch { extra[key] = "[unserializable]"; }
|
package/utils/pages.js
CHANGED
|
@@ -48,7 +48,7 @@ export function pageHtml({ baseUrl, query, total, pageSize = 10, current = 1, un
|
|
|
48
48
|
|
|
49
49
|
const base = new URLSearchParams();
|
|
50
50
|
Object.entries(query || {}).forEach(([k, v]) => {
|
|
51
|
-
if (k === "current" || v
|
|
51
|
+
if (k === "current" || v == null || v === "") return;
|
|
52
52
|
base.set(k, v);
|
|
53
53
|
});
|
|
54
54
|
const link = (n) => {
|
|
@@ -116,8 +116,9 @@ export function pages(current, total, pageSize, href, query = '') {
|
|
|
116
116
|
items.push(ellipsis(), pageLink(totalPage));
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
//
|
|
120
|
-
|
|
119
|
+
// 下一页(最后一页不再给链接:current+1 恒为真值,不判断 totalPage 会渲染出越界页码,
|
|
120
|
+
// 点进去是空列表 —— 与 query 式 pageHtml() 的 current < totalPage 判断对齐)
|
|
121
|
+
items.push(navLink(current < totalPage ? current + 1 : 0, "下一页"));
|
|
121
122
|
|
|
122
123
|
return items.join("");
|
|
123
124
|
}
|