@yunzai-ng/core 0.1.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 (357) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +51 -0
  3. package/dist/adapter/accounts.d.ts +174 -0
  4. package/dist/adapter/accounts.d.ts.map +1 -0
  5. package/dist/adapter/accounts.js +653 -0
  6. package/dist/adapter/accounts.js.map +1 -0
  7. package/dist/adapter/bots.d.ts +142 -0
  8. package/dist/adapter/bots.d.ts.map +1 -0
  9. package/dist/adapter/bots.js +454 -0
  10. package/dist/adapter/bots.js.map +1 -0
  11. package/dist/adapter/host.d.ts +114 -0
  12. package/dist/adapter/host.d.ts.map +1 -0
  13. package/dist/adapter/host.js +90 -0
  14. package/dist/adapter/host.js.map +1 -0
  15. package/dist/adapter/login.d.ts +174 -0
  16. package/dist/adapter/login.d.ts.map +1 -0
  17. package/dist/adapter/login.js +345 -0
  18. package/dist/adapter/login.js.map +1 -0
  19. package/dist/adapter/registry.d.ts +102 -0
  20. package/dist/adapter/registry.d.ts.map +1 -0
  21. package/dist/adapter/registry.js +150 -0
  22. package/dist/adapter/registry.js.map +1 -0
  23. package/dist/config/core-config.d.ts +151 -0
  24. package/dist/config/core-config.d.ts.map +1 -0
  25. package/dist/config/core-config.js +338 -0
  26. package/dist/config/core-config.js.map +1 -0
  27. package/dist/config/schema.d.ts +449 -0
  28. package/dist/config/schema.d.ts.map +1 -0
  29. package/dist/config/schema.js +871 -0
  30. package/dist/config/schema.js.map +1 -0
  31. package/dist/config/store.d.ts +184 -0
  32. package/dist/config/store.d.ts.map +1 -0
  33. package/dist/config/store.js +428 -0
  34. package/dist/config/store.js.map +1 -0
  35. package/dist/config/yaml.d.ts +23 -0
  36. package/dist/config/yaml.d.ts.map +1 -0
  37. package/dist/config/yaml.js +108 -0
  38. package/dist/config/yaml.js.map +1 -0
  39. package/dist/http/client.d.ts +82 -0
  40. package/dist/http/client.d.ts.map +1 -0
  41. package/dist/http/client.js +658 -0
  42. package/dist/http/client.js.map +1 -0
  43. package/dist/index.d.ts +77 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +94 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/kernel/app.d.ts +244 -0
  48. package/dist/kernel/app.d.ts.map +1 -0
  49. package/dist/kernel/app.js +654 -0
  50. package/dist/kernel/app.js.map +1 -0
  51. package/dist/kernel/kv-sink.d.ts +34 -0
  52. package/dist/kernel/kv-sink.d.ts.map +1 -0
  53. package/dist/kernel/kv-sink.js +25 -0
  54. package/dist/kernel/kv-sink.js.map +1 -0
  55. package/dist/kernel/policy.d.ts +77 -0
  56. package/dist/kernel/policy.d.ts.map +1 -0
  57. package/dist/kernel/policy.js +99 -0
  58. package/dist/kernel/policy.js.map +1 -0
  59. package/dist/kernel/runtime.d.ts +117 -0
  60. package/dist/kernel/runtime.d.ts.map +1 -0
  61. package/dist/kernel/runtime.js +197 -0
  62. package/dist/kernel/runtime.js.map +1 -0
  63. package/dist/kernel/sql-sink.d.ts +36 -0
  64. package/dist/kernel/sql-sink.d.ts.map +1 -0
  65. package/dist/kernel/sql-sink.js +114 -0
  66. package/dist/kernel/sql-sink.js.map +1 -0
  67. package/dist/logger/format.d.ts +67 -0
  68. package/dist/logger/format.d.ts.map +1 -0
  69. package/dist/logger/format.js +218 -0
  70. package/dist/logger/format.js.map +1 -0
  71. package/dist/logger/index.d.ts +97 -0
  72. package/dist/logger/index.d.ts.map +1 -0
  73. package/dist/logger/index.js +363 -0
  74. package/dist/logger/index.js.map +1 -0
  75. package/dist/logger/rotate.d.ts +47 -0
  76. package/dist/logger/rotate.d.ts.map +1 -0
  77. package/dist/logger/rotate.js +242 -0
  78. package/dist/logger/rotate.js.map +1 -0
  79. package/dist/message/segment.d.ts +255 -0
  80. package/dist/message/segment.d.ts.map +1 -0
  81. package/dist/message/segment.js +510 -0
  82. package/dist/message/segment.js.map +1 -0
  83. package/dist/message/split.d.ts +34 -0
  84. package/dist/message/split.d.ts.map +1 -0
  85. package/dist/message/split.js +79 -0
  86. package/dist/message/split.js.map +1 -0
  87. package/dist/message/target.d.ts +29 -0
  88. package/dist/message/target.d.ts.map +1 -0
  89. package/dist/message/target.js +34 -0
  90. package/dist/message/target.js.map +1 -0
  91. package/dist/pipeline/cooldown.d.ts +84 -0
  92. package/dist/pipeline/cooldown.d.ts.map +1 -0
  93. package/dist/pipeline/cooldown.js +94 -0
  94. package/dist/pipeline/cooldown.js.map +1 -0
  95. package/dist/pipeline/dispatch.d.ts +98 -0
  96. package/dist/pipeline/dispatch.d.ts.map +1 -0
  97. package/dist/pipeline/dispatch.js +323 -0
  98. package/dist/pipeline/dispatch.js.map +1 -0
  99. package/dist/pipeline/event.d.ts +130 -0
  100. package/dist/pipeline/event.d.ts.map +1 -0
  101. package/dist/pipeline/event.js +538 -0
  102. package/dist/pipeline/event.js.map +1 -0
  103. package/dist/pipeline/middleware.d.ts +63 -0
  104. package/dist/pipeline/middleware.d.ts.map +1 -0
  105. package/dist/pipeline/middleware.js +174 -0
  106. package/dist/pipeline/middleware.js.map +1 -0
  107. package/dist/pipeline/prompt.d.ts +80 -0
  108. package/dist/pipeline/prompt.d.ts.map +1 -0
  109. package/dist/pipeline/prompt.js +155 -0
  110. package/dist/pipeline/prompt.js.map +1 -0
  111. package/dist/pipeline/router.d.ts +98 -0
  112. package/dist/pipeline/router.d.ts.map +1 -0
  113. package/dist/pipeline/router.js +489 -0
  114. package/dist/pipeline/router.js.map +1 -0
  115. package/dist/platform/detect.d.ts +24 -0
  116. package/dist/platform/detect.d.ts.map +1 -0
  117. package/dist/platform/detect.js +178 -0
  118. package/dist/platform/detect.js.map +1 -0
  119. package/dist/platform/paths.d.ts +38 -0
  120. package/dist/platform/paths.d.ts.map +1 -0
  121. package/dist/platform/paths.js +129 -0
  122. package/dist/platform/paths.js.map +1 -0
  123. package/dist/platform/system.d.ts +71 -0
  124. package/dist/platform/system.d.ts.map +1 -0
  125. package/dist/platform/system.js +242 -0
  126. package/dist/platform/system.js.map +1 -0
  127. package/dist/plugin/context.d.ts +92 -0
  128. package/dist/plugin/context.d.ts.map +1 -0
  129. package/dist/plugin/context.js +573 -0
  130. package/dist/plugin/context.js.map +1 -0
  131. package/dist/plugin/define.d.ts +92 -0
  132. package/dist/plugin/define.d.ts.map +1 -0
  133. package/dist/plugin/define.js +82 -0
  134. package/dist/plugin/define.js.map +1 -0
  135. package/dist/plugin/discover.d.ts +106 -0
  136. package/dist/plugin/discover.d.ts.map +1 -0
  137. package/dist/plugin/discover.js +254 -0
  138. package/dist/plugin/discover.js.map +1 -0
  139. package/dist/plugin/events.d.ts +109 -0
  140. package/dist/plugin/events.d.ts.map +1 -0
  141. package/dist/plugin/events.js +209 -0
  142. package/dist/plugin/events.js.map +1 -0
  143. package/dist/plugin/hooks.d.ts +266 -0
  144. package/dist/plugin/hooks.d.ts.map +1 -0
  145. package/dist/plugin/hooks.js +84 -0
  146. package/dist/plugin/hooks.js.map +1 -0
  147. package/dist/plugin/host.d.ts +160 -0
  148. package/dist/plugin/host.d.ts.map +1 -0
  149. package/dist/plugin/host.js +546 -0
  150. package/dist/plugin/host.js.map +1 -0
  151. package/dist/plugin/market.d.ts +264 -0
  152. package/dist/plugin/market.d.ts.map +1 -0
  153. package/dist/plugin/market.js +700 -0
  154. package/dist/plugin/market.js.map +1 -0
  155. package/dist/plugin/services.d.ts +116 -0
  156. package/dist/plugin/services.d.ts.map +1 -0
  157. package/dist/plugin/services.js +213 -0
  158. package/dist/plugin/services.js.map +1 -0
  159. package/dist/plugin/tar.d.ts +65 -0
  160. package/dist/plugin/tar.d.ts.map +1 -0
  161. package/dist/plugin/tar.js +277 -0
  162. package/dist/plugin/tar.js.map +1 -0
  163. package/dist/render/registry.d.ts +127 -0
  164. package/dist/render/registry.d.ts.map +1 -0
  165. package/dist/render/registry.js +306 -0
  166. package/dist/render/registry.js.map +1 -0
  167. package/dist/scheduler/index.d.ts +67 -0
  168. package/dist/scheduler/index.d.ts.map +1 -0
  169. package/dist/scheduler/index.js +279 -0
  170. package/dist/scheduler/index.js.map +1 -0
  171. package/dist/server/api.d.ts +179 -0
  172. package/dist/server/api.d.ts.map +1 -0
  173. package/dist/server/api.js +602 -0
  174. package/dist/server/api.js.map +1 -0
  175. package/dist/server/auth.d.ts +83 -0
  176. package/dist/server/auth.d.ts.map +1 -0
  177. package/dist/server/auth.js +178 -0
  178. package/dist/server/auth.js.map +1 -0
  179. package/dist/server/browse.d.ts +60 -0
  180. package/dist/server/browse.d.ts.map +1 -0
  181. package/dist/server/browse.js +187 -0
  182. package/dist/server/browse.js.map +1 -0
  183. package/dist/server/files.d.ts +27 -0
  184. package/dist/server/files.d.ts.map +1 -0
  185. package/dist/server/files.js +76 -0
  186. package/dist/server/files.js.map +1 -0
  187. package/dist/server/index.d.ts +189 -0
  188. package/dist/server/index.d.ts.map +1 -0
  189. package/dist/server/index.js +1123 -0
  190. package/dist/server/index.js.map +1 -0
  191. package/dist/server/table.d.ts +105 -0
  192. package/dist/server/table.d.ts.map +1 -0
  193. package/dist/server/table.js +289 -0
  194. package/dist/server/table.js.map +1 -0
  195. package/dist/store/index.d.ts +50 -0
  196. package/dist/store/index.d.ts.map +1 -0
  197. package/dist/store/index.js +120 -0
  198. package/dist/store/index.js.map +1 -0
  199. package/dist/store/json.d.ts +73 -0
  200. package/dist/store/json.d.ts.map +1 -0
  201. package/dist/store/json.js +174 -0
  202. package/dist/store/json.js.map +1 -0
  203. package/dist/store/kv.d.ts +126 -0
  204. package/dist/store/kv.d.ts.map +1 -0
  205. package/dist/store/kv.js +232 -0
  206. package/dist/store/kv.js.map +1 -0
  207. package/dist/store/level.d.ts +103 -0
  208. package/dist/store/level.d.ts.map +1 -0
  209. package/dist/store/level.js +119 -0
  210. package/dist/store/level.js.map +1 -0
  211. package/dist/store/memory.d.ts +61 -0
  212. package/dist/store/memory.d.ts.map +1 -0
  213. package/dist/store/memory.js +94 -0
  214. package/dist/store/memory.js.map +1 -0
  215. package/dist/store/sql.d.ts +142 -0
  216. package/dist/store/sql.d.ts.map +1 -0
  217. package/dist/store/sql.js +246 -0
  218. package/dist/store/sql.js.map +1 -0
  219. package/dist/testing/fake.d.ts +109 -0
  220. package/dist/testing/fake.d.ts.map +1 -0
  221. package/dist/testing/fake.js +196 -0
  222. package/dist/testing/fake.js.map +1 -0
  223. package/dist/testing/index.d.ts +16 -0
  224. package/dist/testing/index.d.ts.map +1 -0
  225. package/dist/testing/index.js +16 -0
  226. package/dist/testing/index.js.map +1 -0
  227. package/dist/testing/mock-adapter.d.ts +205 -0
  228. package/dist/testing/mock-adapter.d.ts.map +1 -0
  229. package/dist/testing/mock-adapter.js +309 -0
  230. package/dist/testing/mock-adapter.js.map +1 -0
  231. package/dist/util/deep.d.ts +108 -0
  232. package/dist/util/deep.d.ts.map +1 -0
  233. package/dist/util/deep.js +275 -0
  234. package/dist/util/deep.js.map +1 -0
  235. package/dist/util/defer.d.ts +107 -0
  236. package/dist/util/defer.d.ts.map +1 -0
  237. package/dist/util/defer.js +163 -0
  238. package/dist/util/defer.js.map +1 -0
  239. package/dist/util/dispose.d.ts +88 -0
  240. package/dist/util/dispose.d.ts.map +1 -0
  241. package/dist/util/dispose.js +143 -0
  242. package/dist/util/dispose.js.map +1 -0
  243. package/dist/util/duration.d.ts +28 -0
  244. package/dist/util/duration.d.ts.map +1 -0
  245. package/dist/util/duration.js +77 -0
  246. package/dist/util/duration.js.map +1 -0
  247. package/dist/util/fs.d.ts +110 -0
  248. package/dist/util/fs.d.ts.map +1 -0
  249. package/dist/util/fs.js +269 -0
  250. package/dist/util/fs.js.map +1 -0
  251. package/dist/util/id.d.ts +49 -0
  252. package/dist/util/id.d.ts.map +1 -0
  253. package/dist/util/id.js +87 -0
  254. package/dist/util/id.js.map +1 -0
  255. package/dist/util/lru.d.ts +74 -0
  256. package/dist/util/lru.d.ts.map +1 -0
  257. package/dist/util/lru.js +156 -0
  258. package/dist/util/lru.js.map +1 -0
  259. package/dist/util/queue.d.ts +64 -0
  260. package/dist/util/queue.d.ts.map +1 -0
  261. package/dist/util/queue.js +147 -0
  262. package/dist/util/queue.js.map +1 -0
  263. package/dist/util/text.d.ts +86 -0
  264. package/dist/util/text.d.ts.map +1 -0
  265. package/dist/util/text.js +182 -0
  266. package/dist/util/text.js.map +1 -0
  267. package/package.json +44 -0
  268. package/src/adapter/accounts.ts +758 -0
  269. package/src/adapter/bots.ts +582 -0
  270. package/src/adapter/host.ts +224 -0
  271. package/src/adapter/login.ts +481 -0
  272. package/src/adapter/registry.ts +202 -0
  273. package/src/config/core-config.test.ts +60 -0
  274. package/src/config/core-config.ts +401 -0
  275. package/src/config/schema.test.ts +179 -0
  276. package/src/config/schema.ts +1036 -0
  277. package/src/config/store.test.ts +245 -0
  278. package/src/config/store.ts +506 -0
  279. package/src/config/yaml.ts +119 -0
  280. package/src/http/client.test.ts +568 -0
  281. package/src/http/client.ts +777 -0
  282. package/src/index.ts +106 -0
  283. package/src/kernel/app.test.ts +267 -0
  284. package/src/kernel/app.ts +843 -0
  285. package/src/kernel/kv-sink.ts +58 -0
  286. package/src/kernel/policy.ts +120 -0
  287. package/src/kernel/runtime.test.ts +542 -0
  288. package/src/kernel/runtime.ts +307 -0
  289. package/src/kernel/sql-sink.ts +154 -0
  290. package/src/logger/format.ts +259 -0
  291. package/src/logger/index.ts +427 -0
  292. package/src/logger/rotate.ts +265 -0
  293. package/src/message/segment.test.ts +335 -0
  294. package/src/message/segment.ts +569 -0
  295. package/src/message/split.ts +97 -0
  296. package/src/message/target.ts +48 -0
  297. package/src/pipeline/cooldown.ts +136 -0
  298. package/src/pipeline/dispatch.ts +419 -0
  299. package/src/pipeline/event.ts +735 -0
  300. package/src/pipeline/middleware.test.ts +426 -0
  301. package/src/pipeline/middleware.ts +199 -0
  302. package/src/pipeline/prompt.ts +212 -0
  303. package/src/pipeline/router.test.ts +432 -0
  304. package/src/pipeline/router.ts +575 -0
  305. package/src/platform/detect.ts +178 -0
  306. package/src/platform/paths.ts +147 -0
  307. package/src/platform/system.test.ts +102 -0
  308. package/src/platform/system.ts +289 -0
  309. package/src/plugin/context.test.ts +459 -0
  310. package/src/plugin/context.ts +757 -0
  311. package/src/plugin/define.test.ts +120 -0
  312. package/src/plugin/define.ts +142 -0
  313. package/src/plugin/discover.test.ts +253 -0
  314. package/src/plugin/discover.ts +353 -0
  315. package/src/plugin/events.test.ts +162 -0
  316. package/src/plugin/events.ts +266 -0
  317. package/src/plugin/hooks.ts +373 -0
  318. package/src/plugin/host.test.ts +696 -0
  319. package/src/plugin/host.ts +738 -0
  320. package/src/plugin/market.test.ts +781 -0
  321. package/src/plugin/market.ts +870 -0
  322. package/src/plugin/services.test.ts +135 -0
  323. package/src/plugin/services.ts +261 -0
  324. package/src/plugin/tar.test.ts +158 -0
  325. package/src/plugin/tar.ts +309 -0
  326. package/src/render/registry.test.ts +127 -0
  327. package/src/render/registry.ts +439 -0
  328. package/src/scheduler/index.ts +357 -0
  329. package/src/server/api.test.ts +802 -0
  330. package/src/server/api.ts +869 -0
  331. package/src/server/auth.ts +201 -0
  332. package/src/server/browse.test.ts +193 -0
  333. package/src/server/browse.ts +240 -0
  334. package/src/server/files.ts +97 -0
  335. package/src/server/index.test.ts +566 -0
  336. package/src/server/index.ts +1386 -0
  337. package/src/server/table.ts +351 -0
  338. package/src/store/index.ts +156 -0
  339. package/src/store/json.ts +198 -0
  340. package/src/store/kv.test.ts +307 -0
  341. package/src/store/kv.ts +256 -0
  342. package/src/store/level.ts +167 -0
  343. package/src/store/memory.ts +109 -0
  344. package/src/store/sql.test.ts +204 -0
  345. package/src/store/sql.ts +324 -0
  346. package/src/testing/fake.ts +297 -0
  347. package/src/testing/index.ts +15 -0
  348. package/src/testing/mock-adapter.ts +588 -0
  349. package/src/util/deep.ts +272 -0
  350. package/src/util/defer.ts +211 -0
  351. package/src/util/dispose.ts +169 -0
  352. package/src/util/duration.ts +82 -0
  353. package/src/util/fs.ts +279 -0
  354. package/src/util/id.ts +94 -0
  355. package/src/util/lru.ts +185 -0
  356. package/src/util/queue.ts +167 -0
  357. package/src/util/text.ts +189 -0
@@ -0,0 +1,363 @@
1
+ /**
2
+ * 模块职责:日志枢纽(pino 实例、控制台/文件双路输出、运行时改级别、尾部缓冲)
3
+ * 依赖方向:依赖 logger/format、logger/rotate、util
4
+ * 生命周期:应用级单例,`close()` 时刷盘
5
+ * 注意事项:三个不显然的设计决定 ——
6
+ *
7
+ * 1) **pino 实例常驻 trace,级别过滤放在包装层做**。pino 的 child
8
+ * logger 在创建时固化 level,改父级不会传播给已有子级;而 WebUI
9
+ * 上"把日志级别调成 debug"必须立刻对所有插件生效。所以过滤前移到
10
+ * `#emit`,顺带连 `joinArgs` 的字符串拼接都省掉了,比 pino 自带
11
+ * 的级别检查更省。
12
+ *
13
+ * 2) **参数按 console.log 语义拼接**(见 format.ts 的 `joinArgs`)。
14
+ * pino 原生仅识别第一个参数,`logger.info("查询", uid)` 将丢弃 uid。
15
+ *
16
+ * 3) **不采用 pino.multistream**。控制台与文件的级别过滤在自有的
17
+ * dispatcher 中完成,同时将日志写入 WebUI 的环形缓冲,一次解析三处使用。
18
+ */
19
+ import pino from "pino";
20
+ import { LEVEL_VALUES, formatRecord, joinArgs, parseRecord, supportsColor } from "./format.js";
21
+ import { RotatingFileWriter } from "./rotate.js";
22
+ /** 默认尾部缓冲条数 */
23
+ const DEFAULT_TAIL = 500;
24
+ /**
25
+ * 级别名转数字,`silent` 视为最高
26
+ * @param level 级别名
27
+ * @returns 数字级别
28
+ */
29
+ function levelValue(level) {
30
+ return level === "silent" ? Number.POSITIVE_INFINITY : LEVEL_VALUES[level];
31
+ }
32
+ /**
33
+ * 日志枢纽
34
+ *
35
+ * 内核只创建一个;插件通过 `ctx.logger`(即 `hub.root.child({ scope })`)取用。
36
+ */
37
+ export class LoggerHub {
38
+ /** pino 实例(级别恒为 trace,过滤在包装层做) */
39
+ #pino;
40
+ /** 文件写入器 */
41
+ #writer;
42
+ /** 环形缓冲 */
43
+ #ring;
44
+ /** 环形缓冲写指针 */
45
+ #ringPos = 0;
46
+ /** 环形缓冲是否已绕回(用于判断有效长度) */
47
+ #ringFull = false;
48
+ /** 实时订阅者 */
49
+ #subscribers = new Set();
50
+ /** 防止订阅者内部再打日志导致无限递归 */
51
+ #notifying = false;
52
+ /** 全局级别 */
53
+ #level;
54
+ /** 控制台级别数字 */
55
+ #consoleValue;
56
+ /** 文件级别数字 */
57
+ #fileValue;
58
+ /** 生效阈值:两路里更低的那个,低于它的日志直接不生成 */
59
+ #threshold;
60
+ /** 是否输出控制台 */
61
+ #console;
62
+ /** 是否着色 */
63
+ #color;
64
+ /** 作用域列宽 */
65
+ #scopeWidth;
66
+ /** 根日志器 */
67
+ root;
68
+ /**
69
+ * @param config 日志配置
70
+ */
71
+ constructor(config = {}) {
72
+ this.#level = config.level ?? "info";
73
+ this.#console = config.console !== false;
74
+ this.#color = config.color ?? supportsColor();
75
+ this.#scopeWidth = config.scopeWidth ?? 14;
76
+ this.#ring = new Array(Math.max(50, config.tailSize ?? DEFAULT_TAIL));
77
+ this.#consoleValue = this.#console ? levelValue(config.consoleLevel ?? this.#level) : Number.POSITIVE_INFINITY;
78
+ this.#fileValue = config.dir ? levelValue(config.fileLevel ?? this.#level) : Number.POSITIVE_INFINITY;
79
+ this.#threshold = Math.min(this.#consoleValue, this.#fileValue);
80
+ this.#writer = config.dir
81
+ ? new RotatingFileWriter({
82
+ dir: config.dir,
83
+ basename: config.basename,
84
+ maxSize: config.maxSize,
85
+ keepDays: config.keepDays,
86
+ maxFiles: config.maxFiles
87
+ })
88
+ : undefined;
89
+ this.#pino = pino({
90
+ level: "trace",
91
+ // 去掉 pid/hostname:单机机器人用不上,白占日志体积
92
+ base: undefined,
93
+ serializers: { err: pino.stdSerializers.err }
94
+ }, { write: (line) => this.#dispatch(line) });
95
+ this.root = new HubLogger(this, this.#pino);
96
+ }
97
+ /** 当前全局级别 */
98
+ get level() {
99
+ return this.#level;
100
+ }
101
+ /** 当前日志文件路径;未启用文件输出时 undefined */
102
+ get file() {
103
+ return this.#writer?.file;
104
+ }
105
+ /**
106
+ * 判断某级别当前是否会被输出
107
+ *
108
+ * 由 `HubLogger` 在每次打日志前调用;命中 false 时连消息都不拼。
109
+ * @param level 目标级别
110
+ * @returns 是否启用
111
+ */
112
+ enabled(level) {
113
+ return levelValue(level) >= this.#threshold;
114
+ }
115
+ /**
116
+ * 运行时修改级别
117
+ *
118
+ * 立刻对所有已创建的子日志器生效 —— 这正是把过滤放在包装层的原因。
119
+ * @param level 新级别
120
+ * @param target 只改某一路:`"console"` / `"file"`;缺省两路都改
121
+ */
122
+ setLevel(level, target) {
123
+ const value = levelValue(level);
124
+ if (target === "console") {
125
+ if (this.#console)
126
+ this.#consoleValue = value;
127
+ }
128
+ else if (target === "file") {
129
+ if (this.#writer)
130
+ this.#fileValue = value;
131
+ }
132
+ else {
133
+ this.#level = level;
134
+ if (this.#console)
135
+ this.#consoleValue = value;
136
+ if (this.#writer)
137
+ this.#fileValue = value;
138
+ }
139
+ this.#threshold = Math.min(this.#consoleValue, this.#fileValue);
140
+ }
141
+ /**
142
+ * 取尾部日志
143
+ * @param query 查询条件
144
+ * @returns 按时间正序的日志记录
145
+ */
146
+ tail(query = {}) {
147
+ const size = this.#ring.length;
148
+ const count = this.#ringFull ? size : this.#ringPos;
149
+ const minLevel = query.level ? levelValue(query.level) : 0;
150
+ const keyword = query.keyword?.toLowerCase();
151
+ const out = [];
152
+ for (let i = 0; i < count; i++) {
153
+ // 从最旧的一条开始按环形顺序读
154
+ const index = this.#ringFull ? (this.#ringPos + i) % size : i;
155
+ const rec = this.#ring[index];
156
+ if (!rec)
157
+ continue;
158
+ if (levelValue(rec.level) < minLevel)
159
+ continue;
160
+ if (query.scope && rec.scope !== query.scope)
161
+ continue;
162
+ if (keyword && !rec.msg.toLowerCase().includes(keyword))
163
+ continue;
164
+ out.push(rec);
165
+ }
166
+ const limit = query.limit ?? out.length;
167
+ return limit >= out.length ? out : out.slice(out.length - limit);
168
+ }
169
+ /**
170
+ * 订阅实时日志(WebUI 的 SSE / WebSocket 推送用)
171
+ * @param fn 回调;**不要在里面打日志**,会被静默丢弃以防递归
172
+ * @returns 取消订阅
173
+ */
174
+ subscribe(fn) {
175
+ this.#subscribers.add(fn);
176
+ return () => void this.#subscribers.delete(fn);
177
+ }
178
+ /** 同步刷盘 */
179
+ flush() {
180
+ this.#writer?.flushSync();
181
+ }
182
+ /** 刷盘并关闭文件 */
183
+ close() {
184
+ this.#subscribers.clear();
185
+ this.#writer?.close();
186
+ }
187
+ /**
188
+ * 分发一行 pino 输出
189
+ *
190
+ * 一次解析,三处使用:控制台、文件、环形缓冲/订阅者。
191
+ * @param line pino 生成的 JSON 行
192
+ */
193
+ #dispatch(line) {
194
+ const rec = parseRecord(line);
195
+ if (!rec) {
196
+ // 无法解析时原样输出至控制台,优于直接丢弃
197
+ if (this.#console)
198
+ process.stdout.write(line);
199
+ return;
200
+ }
201
+ const value = levelValue(rec.level);
202
+ if (value >= this.#consoleValue) {
203
+ const text = formatRecord(rec, { color: this.#color, scopeWidth: this.#scopeWidth });
204
+ // warn 及以上走 stderr,便于 `yzng start 2> error.log` 单独收集
205
+ if (value >= LEVEL_VALUES.warn)
206
+ process.stderr.write(text);
207
+ else
208
+ process.stdout.write(text);
209
+ }
210
+ if (this.#writer && value >= this.#fileValue) {
211
+ this.#writer.write(line);
212
+ // fatal 立即落盘:这行之后进程很可能就没了
213
+ if (value >= LEVEL_VALUES.fatal)
214
+ this.#writer.flushSync();
215
+ }
216
+ this.#ring[this.#ringPos] = rec;
217
+ this.#ringPos = (this.#ringPos + 1) % this.#ring.length;
218
+ if (this.#ringPos === 0)
219
+ this.#ringFull = true;
220
+ this.#notify(rec);
221
+ }
222
+ /**
223
+ * 通知订阅者
224
+ * @param rec 日志记录
225
+ */
226
+ #notify(rec) {
227
+ if (this.#subscribers.size === 0 || this.#notifying)
228
+ return;
229
+ this.#notifying = true;
230
+ try {
231
+ for (const fn of this.#subscribers) {
232
+ try {
233
+ fn(rec);
234
+ }
235
+ catch {
236
+ // 订阅者出错不能影响日志本身
237
+ }
238
+ }
239
+ }
240
+ finally {
241
+ this.#notifying = false;
242
+ }
243
+ }
244
+ }
245
+ /**
246
+ * 面向插件的日志器实现
247
+ *
248
+ * 只是 pino 的薄包装:加上级别前置过滤、console.log 风格参数拼接、`mark`。
249
+ */
250
+ class HubLogger {
251
+ /** 所属枢纽 */
252
+ #hub;
253
+ /** 底层 pino 实例(已绑定 scope 等字段) */
254
+ #pino;
255
+ /**
256
+ * @param hub 日志枢纽
257
+ * @param instance pino 实例
258
+ */
259
+ constructor(hub, instance) {
260
+ this.#hub = hub;
261
+ this.#pino = instance;
262
+ }
263
+ /** 当前生效级别 */
264
+ get level() {
265
+ return this.#hub.level;
266
+ }
267
+ /**
268
+ * 最细粒度的追踪日志
269
+ * @param msg 消息
270
+ * @param args 附加参数
271
+ */
272
+ trace(msg, ...args) {
273
+ this.#emit("trace", msg, args);
274
+ }
275
+ /**
276
+ * 调试信息
277
+ * @param msg 消息
278
+ * @param args 附加参数
279
+ */
280
+ debug(msg, ...args) {
281
+ this.#emit("debug", msg, args);
282
+ }
283
+ /**
284
+ * 常规信息
285
+ * @param msg 消息
286
+ * @param args 附加参数
287
+ */
288
+ info(msg, ...args) {
289
+ this.#emit("info", msg, args);
290
+ }
291
+ /**
292
+ * 需要留意但不影响运行
293
+ * @param msg 消息
294
+ * @param args 附加参数
295
+ */
296
+ warn(msg, ...args) {
297
+ this.#emit("warn", msg, args);
298
+ }
299
+ /**
300
+ * 出错但可继续
301
+ * @param msg 消息
302
+ * @param args 附加参数
303
+ */
304
+ error(msg, ...args) {
305
+ this.#emit("error", msg, args);
306
+ }
307
+ /**
308
+ * 致命错误
309
+ * @param msg 消息
310
+ * @param args 附加参数
311
+ */
312
+ fatal(msg, ...args) {
313
+ this.#emit("fatal", msg, args);
314
+ }
315
+ /**
316
+ * 重要信息,等价于 `info`
317
+ * @param msg 消息
318
+ * @param args 附加参数
319
+ */
320
+ mark(msg, ...args) {
321
+ this.#emit("info", msg, args);
322
+ }
323
+ /**
324
+ * 派生子日志器
325
+ * @param bindings 固定字段
326
+ * @returns 新日志器
327
+ */
328
+ child(bindings) {
329
+ return new HubLogger(this.#hub, this.#pino.child(bindings));
330
+ }
331
+ /**
332
+ * 判断级别是否启用
333
+ * @param level 目标级别
334
+ * @returns 是否启用
335
+ */
336
+ isLevelEnabled(level) {
337
+ return this.#hub.enabled(level);
338
+ }
339
+ /**
340
+ * 实际写日志
341
+ * @param level 级别
342
+ * @param msg 首个参数
343
+ * @param args 其余参数
344
+ */
345
+ #emit(level, msg, args) {
346
+ if (!this.#hub.enabled(level))
347
+ return;
348
+ const joined = joinArgs(args.length === 0 ? [msg] : [msg, ...args]);
349
+ if (joined.err)
350
+ this.#pino[level]({ err: joined.err }, joined.msg);
351
+ else
352
+ this.#pino[level](joined.msg);
353
+ }
354
+ }
355
+ /**
356
+ * 创建日志枢纽
357
+ * @param config 日志配置
358
+ * @returns 日志枢纽
359
+ */
360
+ export function createLoggerHub(config = {}) {
361
+ return new LoggerHub(config);
362
+ }
363
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /** 滚动写入参数 */
2
+ export interface RotateOptions {
3
+ /** 日志目录 */
4
+ dir: string;
5
+ /** 文件名前缀,缺省 `"app"` */
6
+ basename?: string;
7
+ /** 单文件字节上限,缺省 8MB */
8
+ maxSize?: number;
9
+ /** 保留天数,缺省 14 */
10
+ keepDays?: number;
11
+ /** 文件数上限,缺省 100(防止同一天大量写入日志将磁盘写满) */
12
+ maxFiles?: number;
13
+ /** 批量刷盘间隔毫秒,缺省 200 */
14
+ flushInterval?: number;
15
+ /** 缓冲字节数上限,超过立即刷盘,缺省 32KB */
16
+ bufferLimit?: number;
17
+ }
18
+ /**
19
+ * 滚动日志写入器
20
+ *
21
+ * 触发滚动的两个条件:跨自然日、当前文件超过 `maxSize`。
22
+ * 同一天内超限则追加序号:`app-2026-08-21.1.log`。
23
+ */
24
+ export declare class RotatingFileWriter {
25
+ #private;
26
+ /**
27
+ * @param opts 滚动参数
28
+ */
29
+ constructor(opts: RotateOptions);
30
+ /** 当前正在写入的文件路径 */
31
+ get file(): string;
32
+ /**
33
+ * 写入一行(调用方需自带换行符,pino 已带)
34
+ * @param line 日志行
35
+ */
36
+ write(line: string): void;
37
+ /**
38
+ * 同步刷盘
39
+ *
40
+ * 进程退出、`uncaughtException`、`fatal` 级日志之后都应调用,
41
+ * 否则最关键的几行日志会随进程一起消失。
42
+ */
43
+ flushSync(): void;
44
+ /** 刷盘并关闭文件 */
45
+ close(): void;
46
+ }
47
+ //# sourceMappingURL=rotate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotate.d.ts","sourceRoot":"","sources":["../../src/logger/rotate.ts"],"names":[],"mappings":"AAiBA,aAAa;AACb,MAAM,WAAW,aAAa;IAC5B,WAAW;IACX,GAAG,EAAE,MAAM,CAAA;IACX,uBAAuB;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iBAAiB;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,sBAAsB;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAiBD;;;;;GAKG;AACH,qBAAa,kBAAkB;;IAiC7B;;OAEG;gBACS,IAAI,EAAE,aAAa;IAU/B,kBAAkB;IAClB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmBzB;;;;;OAKG;IACH,SAAS,IAAI,IAAI;IAsBjB,cAAc;IACd,KAAK,IAAI,IAAI;CAyGd"}
@@ -0,0 +1,242 @@
1
+ /**
2
+ * 模块职责:日志文件的滚动写入与保留策略
3
+ * 依赖方向:仅依赖 node:fs / node:path
4
+ * 生命周期:由 LoggerHub 创建与关闭;`close()` 前必须 `flushSync()`
5
+ * 注意事项:刻意**不用** `pino-roll` / `pino/file` 这类 worker 线程 transport。
6
+ * worker transport 在两个场景下存在缺陷:
7
+ * 1) 单文件打包(Windows 安装包)里 worker 入口路径解析不到;
8
+ * 2) 进程被强杀时 worker 尚未落盘的日志直接丢失 —— 而崩溃前最后
9
+ * 几行日志恰恰是排障最需要的。
10
+ *
11
+ * 因此此处自行维护一个 fd 与内存缓冲:常态下批量异步刷盘,退出与致命
12
+ * 错误时 `flushSync()` 同步落盘。写入用 `writeSync` 循环,处理
13
+ * 部分写入(管道/网络盘上会发生)。
14
+ */
15
+ import { closeSync, existsSync, mkdirSync, openSync, readdirSync, statSync, unlinkSync, writeSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ /** 默认单文件上限:8MB */
18
+ const DEFAULT_MAX_SIZE = 8 * 1024 * 1024;
19
+ /**
20
+ * 取本地日期字符串
21
+ * @param date 时间
22
+ * @returns 形如 `"2026-08-21"`
23
+ */
24
+ function localDay(date) {
25
+ const y = date.getFullYear();
26
+ const m = String(date.getMonth() + 1).padStart(2, "0");
27
+ const d = String(date.getDate()).padStart(2, "0");
28
+ return `${y}-${m}-${d}`;
29
+ }
30
+ /**
31
+ * 滚动日志写入器
32
+ *
33
+ * 触发滚动的两个条件:跨自然日、当前文件超过 `maxSize`。
34
+ * 同一天内超限则追加序号:`app-2026-08-21.1.log`。
35
+ */
36
+ export class RotatingFileWriter {
37
+ /** 日志目录 */
38
+ #dir;
39
+ /** 文件名前缀 */
40
+ #basename;
41
+ /** 单文件上限 */
42
+ #maxSize;
43
+ /** 保留天数 */
44
+ #keepDays;
45
+ /** 文件数上限 */
46
+ #maxFiles;
47
+ /** 刷盘间隔 */
48
+ #flushInterval;
49
+ /** 缓冲上限 */
50
+ #bufferLimit;
51
+ /** 当前文件描述符 */
52
+ #fd = -1;
53
+ /** 当前文件路径 */
54
+ #file = "";
55
+ /** 当前文件已写字节数 */
56
+ #size = 0;
57
+ /** 当前文件对应的日期 */
58
+ #day = "";
59
+ /** 待刷盘缓冲 */
60
+ #buffer = [];
61
+ /** 缓冲字节数(按 UTF-8 估算) */
62
+ #bufferBytes = 0;
63
+ /** 刷盘定时器 */
64
+ #timer;
65
+ /** 是否已关闭 */
66
+ #closed = false;
67
+ /**
68
+ * @param opts 滚动参数
69
+ */
70
+ constructor(opts) {
71
+ this.#dir = opts.dir;
72
+ this.#basename = opts.basename ?? "app";
73
+ this.#maxSize = Math.max(64 * 1024, opts.maxSize ?? DEFAULT_MAX_SIZE);
74
+ this.#keepDays = Math.max(1, opts.keepDays ?? 14);
75
+ this.#maxFiles = Math.max(2, opts.maxFiles ?? 100);
76
+ this.#flushInterval = Math.max(50, opts.flushInterval ?? 200);
77
+ this.#bufferLimit = Math.max(4096, opts.bufferLimit ?? 32 * 1024);
78
+ }
79
+ /** 当前正在写入的文件路径 */
80
+ get file() {
81
+ return this.#file;
82
+ }
83
+ /**
84
+ * 写入一行(调用方需自带换行符,pino 已带)
85
+ * @param line 日志行
86
+ */
87
+ write(line) {
88
+ if (this.#closed)
89
+ return;
90
+ this.#buffer.push(line);
91
+ this.#bufferBytes += Buffer.byteLength(line);
92
+ if (this.#bufferBytes >= this.#bufferLimit) {
93
+ this.flushSync();
94
+ return;
95
+ }
96
+ if (!this.#timer) {
97
+ this.#timer = setTimeout(() => {
98
+ this.#timer = undefined;
99
+ this.flushSync();
100
+ }, this.#flushInterval);
101
+ // unref:日志缓冲不该拖着进程不让退出
102
+ if (typeof this.#timer.unref === "function")
103
+ this.#timer.unref();
104
+ }
105
+ }
106
+ /**
107
+ * 同步刷盘
108
+ *
109
+ * 进程退出、`uncaughtException`、`fatal` 级日志之后都应调用,
110
+ * 否则最关键的几行日志会随进程一起消失。
111
+ */
112
+ flushSync() {
113
+ if (this.#buffer.length === 0)
114
+ return;
115
+ const payload = this.#buffer.join("");
116
+ this.#buffer = [];
117
+ this.#bufferBytes = 0;
118
+ try {
119
+ this.#ensureTarget(Buffer.byteLength(payload));
120
+ if (this.#fd < 0)
121
+ return;
122
+ const data = Buffer.from(payload, "utf8");
123
+ let offset = 0;
124
+ // writeSync 可能只写了一部分,必须循环
125
+ while (offset < data.length) {
126
+ offset += writeSync(this.#fd, data, offset, data.length - offset);
127
+ }
128
+ this.#size += data.length;
129
+ }
130
+ catch {
131
+ // 日志系统本身不能抛错,否则会把"记录错误"变成"制造错误"。
132
+ // 磁盘满或权限问题只能静默丢弃,控制台流仍然可用。
133
+ }
134
+ }
135
+ /** 刷盘并关闭文件 */
136
+ close() {
137
+ if (this.#closed)
138
+ return;
139
+ this.flushSync();
140
+ this.#closed = true;
141
+ if (this.#timer) {
142
+ clearTimeout(this.#timer);
143
+ this.#timer = undefined;
144
+ }
145
+ if (this.#fd >= 0) {
146
+ try {
147
+ closeSync(this.#fd);
148
+ }
149
+ catch {
150
+ // 关闭失败无从处理
151
+ }
152
+ this.#fd = -1;
153
+ }
154
+ }
155
+ /**
156
+ * 确保当前文件可写且容量足够
157
+ * @param incoming 即将写入的字节数
158
+ */
159
+ #ensureTarget(incoming) {
160
+ const day = localDay(new Date());
161
+ const needRotate = this.#fd < 0 || day !== this.#day || this.#size + incoming > this.#maxSize;
162
+ if (!needRotate)
163
+ return;
164
+ if (this.#fd >= 0) {
165
+ try {
166
+ closeSync(this.#fd);
167
+ }
168
+ catch {
169
+ // 忽略
170
+ }
171
+ this.#fd = -1;
172
+ }
173
+ mkdirSync(this.#dir, { recursive: true });
174
+ this.#day = day;
175
+ // 找当天第一个未超限的序号
176
+ let index = 0;
177
+ let file = join(this.#dir, `${this.#basename}-${day}.log`);
178
+ let size = this.#sizeOf(file);
179
+ while (size + incoming > this.#maxSize && index < 1000) {
180
+ index++;
181
+ file = join(this.#dir, `${this.#basename}-${day}.${index}.log`);
182
+ size = this.#sizeOf(file);
183
+ }
184
+ this.#file = file;
185
+ this.#size = size;
186
+ this.#fd = openSync(file, "a");
187
+ this.#cleanup();
188
+ }
189
+ /**
190
+ * 取文件大小
191
+ * @param file 文件路径
192
+ * @returns 字节数;不存在时 0
193
+ */
194
+ #sizeOf(file) {
195
+ try {
196
+ return existsSync(file) ? statSync(file).size : 0;
197
+ }
198
+ catch {
199
+ return 0;
200
+ }
201
+ }
202
+ /**
203
+ * 按保留策略删除旧日志
204
+ *
205
+ * 只在滚动时调用(低频),因此用同步 API 无妨。
206
+ */
207
+ #cleanup() {
208
+ try {
209
+ const pattern = new RegExp(`^${this.#basename}-(\\d{4}-\\d{2}-\\d{2})(?:\\.(\\d+))?\\.log$`);
210
+ const files = [];
211
+ for (const name of readdirSync(this.#dir)) {
212
+ const m = pattern.exec(name);
213
+ if (m)
214
+ files.push({ name, day: m[1], index: Number(m[2] ?? 0) });
215
+ }
216
+ // 按日期倒序、同日按序号倒序 → 数组头部是最新的
217
+ files.sort((a, b) => (a.day === b.day ? b.index - a.index : a.day < b.day ? 1 : -1));
218
+ const cutoff = new Date();
219
+ cutoff.setDate(cutoff.getDate() - this.#keepDays);
220
+ const cutoffDay = localDay(cutoff);
221
+ for (let i = 0; i < files.length; i++) {
222
+ const entry = files[i];
223
+ const tooOld = entry.day < cutoffDay;
224
+ const tooMany = i >= this.#maxFiles;
225
+ if (!tooOld && !tooMany)
226
+ continue;
227
+ if (join(this.#dir, entry.name) === this.#file)
228
+ continue;
229
+ try {
230
+ unlinkSync(join(this.#dir, entry.name));
231
+ }
232
+ catch {
233
+ // 文件被占用(Windows 常见)时留到下次滚动再试
234
+ }
235
+ }
236
+ }
237
+ catch {
238
+ // 清理失败不影响写入
239
+ }
240
+ }
241
+ }
242
+ //# sourceMappingURL=rotate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotate.js","sourceRoot":"","sources":["../../src/logger/rotate.ts"],"names":[],"mappings":"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"}