@anyul/koishi-plugin-rss 5.2.3 → 5.2.4

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 (70) hide show
  1. package/README.md +92 -37
  2. package/lib/commands/error-handler.js +13 -1
  3. package/lib/commands/index.d.ts +3 -0
  4. package/lib/commands/index.js +7 -1
  5. package/lib/commands/runtime.d.ts +17 -0
  6. package/lib/commands/runtime.js +27 -0
  7. package/lib/commands/subscription-create.d.ts +23 -0
  8. package/lib/commands/subscription-create.js +145 -0
  9. package/lib/commands/web-monitor.d.ts +15 -0
  10. package/lib/commands/web-monitor.js +222 -0
  11. package/lib/config.js +7 -1
  12. package/lib/constants.d.ts +1 -1
  13. package/lib/constants.js +46 -83
  14. package/lib/core/ai-cache.d.ts +27 -0
  15. package/lib/core/ai-cache.js +169 -0
  16. package/lib/core/ai-client.d.ts +12 -0
  17. package/lib/core/ai-client.js +65 -0
  18. package/lib/core/ai-selector.d.ts +2 -0
  19. package/lib/core/ai-selector.js +80 -0
  20. package/lib/core/ai-summary.d.ts +10 -0
  21. package/lib/core/ai-summary.js +73 -0
  22. package/lib/core/ai-utils.d.ts +10 -0
  23. package/lib/core/ai-utils.js +104 -0
  24. package/lib/core/ai.d.ts +3 -91
  25. package/lib/core/ai.js +13 -522
  26. package/lib/core/feeder-arg.d.ts +17 -0
  27. package/lib/core/feeder-arg.js +234 -0
  28. package/lib/core/feeder-runtime.d.ts +96 -0
  29. package/lib/core/feeder-runtime.js +233 -0
  30. package/lib/core/feeder.d.ts +3 -5
  31. package/lib/core/feeder.js +61 -358
  32. package/lib/core/item-processor-runtime.d.ts +46 -0
  33. package/lib/core/item-processor-runtime.js +215 -0
  34. package/lib/core/item-processor-template.d.ts +16 -0
  35. package/lib/core/item-processor-template.js +158 -0
  36. package/lib/core/item-processor.d.ts +1 -15
  37. package/lib/core/item-processor.js +44 -319
  38. package/lib/core/notification-queue-retry.d.ts +25 -0
  39. package/lib/core/notification-queue-retry.js +78 -0
  40. package/lib/core/notification-queue-sender.d.ts +20 -0
  41. package/lib/core/notification-queue-sender.js +118 -0
  42. package/lib/core/notification-queue-store.d.ts +19 -0
  43. package/lib/core/notification-queue-store.js +137 -0
  44. package/lib/core/notification-queue-types.d.ts +49 -0
  45. package/lib/core/notification-queue-types.js +2 -0
  46. package/lib/core/notification-queue.d.ts +11 -72
  47. package/lib/core/notification-queue.js +81 -258
  48. package/lib/core/search-format.d.ts +3 -0
  49. package/lib/core/search-format.js +36 -0
  50. package/lib/core/search-providers.d.ts +13 -0
  51. package/lib/core/search-providers.js +175 -0
  52. package/lib/core/search-rotation.d.ts +4 -0
  53. package/lib/core/search-rotation.js +55 -0
  54. package/lib/core/search-service.d.ts +3 -0
  55. package/lib/core/search-service.js +100 -0
  56. package/lib/core/search-types.d.ts +39 -0
  57. package/lib/core/search-types.js +2 -0
  58. package/lib/core/search.d.ts +4 -101
  59. package/lib/core/search.js +10 -508
  60. package/lib/index.js +27 -381
  61. package/lib/tsconfig.tsbuildinfo +1 -1
  62. package/lib/types.d.ts +27 -6
  63. package/lib/utils/legacy-config.d.ts +12 -0
  64. package/lib/utils/legacy-config.js +56 -0
  65. package/lib/utils/logger.js +50 -29
  66. package/lib/utils/proxy.d.ts +3 -0
  67. package/lib/utils/proxy.js +14 -0
  68. package/lib/utils/structured-logger.d.ts +7 -3
  69. package/lib/utils/structured-logger.js +26 -19
  70. package/package.json +1 -1
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeBasicConfig = normalizeBasicConfig;
4
+ exports.normalizeSubscriptionArg = normalizeSubscriptionArg;
5
+ exports.getRuntimeBasicConfig = getRuntimeBasicConfig;
6
+ exports.getResendUpdatedContent = getResendUpdatedContent;
7
+ exports.shouldMergeVideo = shouldMergeVideo;
8
+ exports.getNextUpdateTime = getNextUpdateTime;
9
+ exports.setNextUpdateTime = setNextUpdateTime;
10
+ function normalizeBasicConfig(basic) {
11
+ const normalized = { ...(basic || {}) };
12
+ const mergeVideo = normalized.mergeVideo ?? normalized.margeVideo;
13
+ const resendUpdatedContent = normalized.resendUpdatedContent ?? normalized.resendUpdataContent;
14
+ if (mergeVideo !== undefined) {
15
+ normalized.mergeVideo = mergeVideo;
16
+ normalized.margeVideo = mergeVideo;
17
+ }
18
+ if (resendUpdatedContent !== undefined) {
19
+ normalized.resendUpdatedContent = resendUpdatedContent;
20
+ normalized.resendUpdataContent = resendUpdatedContent;
21
+ }
22
+ return normalized;
23
+ }
24
+ function normalizeSubscriptionArg(arg) {
25
+ const normalized = { ...(arg || {}) };
26
+ const nextUpdateTime = getNextUpdateTime(normalized);
27
+ if (nextUpdateTime !== undefined) {
28
+ setNextUpdateTime(normalized, nextUpdateTime);
29
+ }
30
+ return normalized;
31
+ }
32
+ function getRuntimeBasicConfig(config) {
33
+ return normalizeBasicConfig(config.basic);
34
+ }
35
+ function getResendUpdatedContent(config) {
36
+ const basic = getRuntimeBasicConfig(config);
37
+ return basic.resendUpdatedContent ?? 'disable';
38
+ }
39
+ function shouldMergeVideo(config) {
40
+ const basic = getRuntimeBasicConfig(config);
41
+ return basic.mergeVideo === true;
42
+ }
43
+ function getNextUpdateTime(arg) {
44
+ const value = arg?.nextUpdateTime ?? arg?.nextUpdataTime;
45
+ const parsed = typeof value === 'number' ? value : Number(value);
46
+ return Number.isFinite(parsed) ? parsed : undefined;
47
+ }
48
+ function setNextUpdateTime(target, nextUpdateTime) {
49
+ if (nextUpdateTime === undefined) {
50
+ delete target.nextUpdateTime;
51
+ delete target.nextUpdataTime;
52
+ return;
53
+ }
54
+ target.nextUpdateTime = nextUpdateTime;
55
+ target.nextUpdataTime = nextUpdateTime;
56
+ }
@@ -136,6 +136,52 @@ function emitLog(type, content) {
136
136
  }
137
137
  logger.info(content);
138
138
  }
139
+ function filterContextFields(context, contextFields) {
140
+ if (!contextFields?.length) {
141
+ return context;
142
+ }
143
+ const filteredContext = {};
144
+ contextFields.forEach((field) => {
145
+ if (context[field] !== undefined) {
146
+ filteredContext[field] = context[field];
147
+ }
148
+ });
149
+ return filteredContext;
150
+ }
151
+ function formatContextValue(value) {
152
+ if (value instanceof Error) {
153
+ return value.message || value.name;
154
+ }
155
+ if (typeof value === 'object' && value !== null) {
156
+ try {
157
+ return JSON.stringify(value);
158
+ }
159
+ catch {
160
+ return String(value);
161
+ }
162
+ }
163
+ return String(value);
164
+ }
165
+ function formatTextLog(message, name, context, loggingConfig) {
166
+ const parts = [];
167
+ if (loggingConfig?.includeModule !== false && name) {
168
+ parts.push(`[${name}]`);
169
+ }
170
+ parts.push(message);
171
+ const textOutput = parts.filter(Boolean).join(' ').trim();
172
+ if (!context || Object.keys(context).length === 0) {
173
+ return textOutput;
174
+ }
175
+ const filteredContext = filterContextFields(context, loggingConfig?.contextFields);
176
+ if (Object.keys(filteredContext).length === 0) {
177
+ return textOutput;
178
+ }
179
+ const contextStr = Object.entries(filteredContext)
180
+ .sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
181
+ .map(([key, value]) => `${key}=${formatContextValue(value)}`)
182
+ .join(', ');
183
+ return `${textOutput}\n↳ ${contextStr}`;
184
+ }
139
185
  /**
140
186
  * 增强的调试日志函数
141
187
  *
@@ -206,41 +252,16 @@ function debug(config, message, name = '', type = 'details', context) {
206
252
  }
207
253
  // 添加上下文信息
208
254
  if (loggingConfig.includeContext && context) {
209
- // 如果指定了 contextFields,只包含这些字段
210
- if (loggingConfig.contextFields && loggingConfig.contextFields.length > 0) {
211
- const filteredContext = {};
212
- loggingConfig.contextFields.forEach(field => {
213
- if (context[field] !== undefined) {
214
- filteredContext[field] = context[field];
215
- }
216
- });
217
- if (Object.keys(filteredContext).length > 0) {
218
- logEntry.context = filteredContext;
219
- }
220
- }
221
- else if (Object.keys(context).length > 0) {
222
- // 否则包含所有上下文
223
- logEntry.context = context;
255
+ const filteredContext = filterContextFields(context, loggingConfig.contextFields);
256
+ if (Object.keys(filteredContext).length > 0) {
257
+ logEntry.context = filteredContext;
224
258
  }
225
259
  }
226
260
  // 输出结构化日志
227
261
  emitLog(type, JSON.stringify(logEntry));
228
262
  }
229
263
  else {
230
- // 传统文本格式
231
- let textOutput = formattedMessage;
232
- // 添加模块前缀(如果有)
233
- if (name) {
234
- textOutput = `[${name}] ${textOutput}`;
235
- }
236
- // 如果有上下文且不使用结构化日志,在末尾添加简化的上下文信息
237
- if (context && Object.keys(context).length > 0) {
238
- const contextStr = Object.entries(context)
239
- .map(([key, value]) => `${key}=${typeof value === 'object' ? JSON.stringify(value) : value}`)
240
- .join(' ');
241
- textOutput += ` | ${contextStr}`;
242
- }
243
- emitLog(type, textOutput);
264
+ emitLog(type, formatTextLog(formattedMessage, name, context, loggingConfig));
244
265
  }
245
266
  }
246
267
  /**
@@ -0,0 +1,3 @@
1
+ import type { AxiosRequestConfig } from 'axios';
2
+ import type { Config } from '../types';
3
+ export declare function buildAxiosProxyConfig(config: Config): Pick<AxiosRequestConfig, 'httpsAgent' | 'proxy'>;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAxiosProxyConfig = buildAxiosProxyConfig;
4
+ const https_proxy_agent_1 = require("https-proxy-agent");
5
+ function buildAxiosProxyConfig(config) {
6
+ if (!config.net?.proxyAgent?.enabled) {
7
+ return {};
8
+ }
9
+ const proxyUrl = `${config.net.proxyAgent.protocol}://${config.net.proxyAgent.host}:${config.net.proxyAgent.port}`;
10
+ return {
11
+ httpsAgent: new https_proxy_agent_1.HttpsProxyAgent(proxyUrl),
12
+ proxy: false,
13
+ };
14
+ }
@@ -1,6 +1,9 @@
1
1
  /**
2
- * 结构化日志系统
3
- * 提供统一的日志格式,支持 JSON 输出和性能监控
2
+ * 观测辅助日志包装层。
3
+ *
4
+ * 注意:当前插件主流程日志入口是 `src/utils/logger.ts` 中的
5
+ * `debug / debugInfo / debugError / createDebugWithContext`。
6
+ * 这里保留为可选的观测与兼容包装,不应作为新业务代码的首选入口。
4
7
  */
5
8
  import { Config } from '../types';
6
9
  /**
@@ -62,7 +65,8 @@ export declare class PerformanceTimer {
62
65
  };
63
66
  }
64
67
  /**
65
- * 结构化日志记录器类
68
+ * 结构化日志记录器类。
69
+ * 内部仍然回落到主日志入口,避免形成第二条日志主线。
66
70
  */
67
71
  export declare class StructuredLogger {
68
72
  private config;
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
2
  /**
3
- * 结构化日志系统
4
- * 提供统一的日志格式,支持 JSON 输出和性能监控
3
+ * 观测辅助日志包装层。
4
+ *
5
+ * 注意:当前插件主流程日志入口是 `src/utils/logger.ts` 中的
6
+ * `debug / debugInfo / debugError / createDebugWithContext`。
7
+ * 这里保留为可选的观测与兼容包装,不应作为新业务代码的首选入口。
5
8
  */
6
9
  Object.defineProperty(exports, "__esModule", { value: true });
7
10
  exports.StructuredLogger = exports.PerformanceTimer = exports.LogLevel = void 0;
@@ -58,7 +61,8 @@ class PerformanceTimer {
58
61
  }
59
62
  exports.PerformanceTimer = PerformanceTimer;
60
63
  /**
61
- * 结构化日志记录器类
64
+ * 结构化日志记录器类。
65
+ * 内部仍然回落到主日志入口,避免形成第二条日志主线。
62
66
  */
63
67
  class StructuredLogger {
64
68
  config;
@@ -80,38 +84,41 @@ class StructuredLogger {
80
84
  if (this.enableJsonOutput) {
81
85
  return JSON.stringify(entry);
82
86
  }
83
- // 文本格式
84
- const parts = [
87
+ const header = [
85
88
  `[${entry.timestamp}]`,
86
89
  `[${entry.level.toUpperCase()}]`,
87
90
  entry.module ? `[${entry.module}]` : '',
88
91
  entry.message
89
92
  ].filter(Boolean).join(' ');
90
- // 添加性能数据
93
+ const lines = [header];
94
+ if (entry.context && Object.keys(entry.context).length > 0) {
95
+ const contextStr = Object.entries(entry.context)
96
+ .map(([key, value]) => `${key}=${value}`)
97
+ .join(', ');
98
+ lines.push(`↳ context: ${contextStr}`);
99
+ }
100
+ if (entry.data && Object.keys(entry.data).length > 0) {
101
+ const dataStr = Object.entries(entry.data)
102
+ .map(([key, value]) => `${key}=${typeof value === 'object' ? JSON.stringify(value) : value}`)
103
+ .join(', ');
104
+ lines.push(`↳ data: ${dataStr}`);
105
+ }
91
106
  if (entry.performance) {
92
107
  const perfParts = [];
93
108
  if (entry.performance.duration) {
94
- perfParts.push(`⏱️ ${entry.performance.duration}ms`);
109
+ perfParts.push(`duration=${entry.performance.duration}ms`);
95
110
  }
96
111
  if (entry.performance.memory) {
97
- perfParts.push(`💾 ${entry.performance.memory.toFixed(2)}MB`);
112
+ perfParts.push(`memory=${entry.performance.memory.toFixed(2)}MB`);
98
113
  }
99
114
  if (perfParts.length > 0) {
100
- return parts + '\n' + perfParts.join(' | ');
115
+ lines.push(`↳ performance: ${perfParts.join(', ')}`);
101
116
  }
102
117
  }
103
- // 添加上下文数据
104
- if (entry.context && Object.keys(entry.context).length > 0) {
105
- const contextStr = Object.entries(entry.context)
106
- .map(([key, value]) => `${key}=${value}`)
107
- .join(', ');
108
- return parts + `\n📍 ${contextStr}`;
109
- }
110
- // 添加错误信息
111
118
  if (entry.error) {
112
- return parts + `\n❌ ${entry.error.name}: ${entry.error.message}`;
119
+ lines.push(`↳ error: ${entry.error.name}: ${entry.error.message}`);
113
120
  }
114
- return parts;
121
+ return lines.join('\n');
115
122
  }
116
123
  /**
117
124
  * 记录日志
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@anyul/koishi-plugin-rss",
3
3
  "description": "Koishi RSS订阅器,支持多种RSS源、图片渲染、AI摘要等高级功能",
4
- "version": "5.2.3",
4
+ "version": "5.2.4",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "author": "Anyuluo <anyul@email.com>",