@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,871 @@
1
+ var _a;
2
+ import { deepClone, isPlainObject } from "../util/deep.js";
3
+ import { parseDuration } from "../util/duration.js";
4
+ /** 校验失败抛出的错误 */
5
+ export class SchemaError extends Error {
6
+ /** 错误名 */
7
+ name = "SchemaError";
8
+ /** 全部问题 */
9
+ issues;
10
+ /**
11
+ * @param issues 校验问题列表
12
+ */
13
+ constructor(issues) {
14
+ const lines = issues
15
+ .filter(i => i.severity === "error")
16
+ .map(i => ` · ${i.path === "" ? "(根)" : i.path}:${i.message}`);
17
+ super(`配置校验失败:\n${lines.join("\n")}`);
18
+ this.issues = issues;
19
+ }
20
+ }
21
+ /** 校验失败的哨兵值 */
22
+ const INVALID = Symbol("invalid");
23
+ /**
24
+ * 配置 schema 节点
25
+ *
26
+ * 不可变:全部 fluent 方法均返回新实例,因此可安全地抽取公共片段以供复用。
27
+ */
28
+ export class Schema {
29
+ /** 内部定义 */
30
+ #def;
31
+ /**
32
+ * @param def 内部定义;请通过 `s.*` 工厂函数创建,不要直接 new
33
+ */
34
+ constructor(def) {
35
+ this.#def = def;
36
+ }
37
+ /* ───────────────────────────── 元信息 ───────────────────────────── */
38
+ /**
39
+ * 设置表单标签
40
+ * @param text 标签文案
41
+ * @returns 新 schema
42
+ */
43
+ title(text) {
44
+ return this.#patch({ meta: { title: text } });
45
+ }
46
+ /**
47
+ * 设置说明文案
48
+ * @param text 说明
49
+ * @returns 新 schema
50
+ */
51
+ desc(text) {
52
+ return this.#patch({ meta: { description: text } });
53
+ }
54
+ /**
55
+ * 设置分组(WebUI 折叠区块)
56
+ * @param name 分组名
57
+ * @returns 新 schema
58
+ */
59
+ group(name) {
60
+ return this.#patch({ meta: { group: name } });
61
+ }
62
+ /**
63
+ * 设置排序权重,小的在前
64
+ * @param weight 权重
65
+ * @returns 新 schema
66
+ */
67
+ order(weight) {
68
+ return this.#patch({ meta: { order: weight } });
69
+ }
70
+ /**
71
+ * 指定控件类型
72
+ * @param widget 控件
73
+ * @returns 新 schema
74
+ */
75
+ widget(widget) {
76
+ return this.#patch({ meta: { widget } });
77
+ }
78
+ /**
79
+ * 标记为敏感字段
80
+ *
81
+ * WebUI 读取时脱敏、日志中不打印。CK、token、密码必须标。
82
+ * @returns 新 schema
83
+ */
84
+ secret() {
85
+ return this.#patch({ meta: { secret: true, widget: this.#def.meta.widget ?? "password" } });
86
+ }
87
+ /**
88
+ * 标记为只读
89
+ * @returns 新 schema
90
+ */
91
+ readonly() {
92
+ return this.#patch({ meta: { readonly: true } });
93
+ }
94
+ /**
95
+ * 设置输入框占位符
96
+ * @param text 占位文案
97
+ * @returns 新 schema
98
+ */
99
+ placeholder(text) {
100
+ return this.#patch({ meta: { placeholder: text } });
101
+ }
102
+ /**
103
+ * 设置条件显隐
104
+ * @param cond 同级字段取值条件,如 `{ mode: "ws-reverse" }`;值写成数组表示"取其中之一"
105
+ * @returns 新 schema
106
+ */
107
+ showWhen(cond) {
108
+ return this.#patch({ meta: { showWhen: cond } });
109
+ }
110
+ /* ───────────────────────────── 可选与默认 ───────────────────────────── */
111
+ /**
112
+ * 标记为可缺省
113
+ * @returns 新 schema,输出类型带上 undefined
114
+ */
115
+ optional() {
116
+ return this.#patch({ optional: true });
117
+ }
118
+ /**
119
+ * 设置默认值
120
+ *
121
+ * 有默认值的字段在输出类型里仍是必填 —— 因为解析后一定有值。
122
+ * @param value 默认值
123
+ * @returns 新 schema
124
+ */
125
+ default(value) {
126
+ return this.#patch({ hasDefault: true, defaultValue: value });
127
+ }
128
+ /**
129
+ * 追加自定义校验
130
+ * @param message 不通过时的中文提示
131
+ * @param test 返回 true 表示通过
132
+ * @returns 新 schema
133
+ */
134
+ check(message, test) {
135
+ const checks = [...(this.#def.checks ?? []), { message, test: test }];
136
+ return this.#patch({ checks });
137
+ }
138
+ /* ───────────────────────────── 约束 ───────────────────────────── */
139
+ /**
140
+ * 下界:数值最小值 / 字符串最短长度 / 数组最少元素
141
+ * @param value 下界
142
+ * @returns 新 schema
143
+ */
144
+ min(value) {
145
+ return this.#patch({ min: value });
146
+ }
147
+ /**
148
+ * 上界:数值最大值 / 字符串最长长度 / 数组最多元素
149
+ * @param value 上界
150
+ * @returns 新 schema
151
+ */
152
+ max(value) {
153
+ return this.#patch({ max: value });
154
+ }
155
+ /**
156
+ * 字符串正则约束
157
+ * @param regex 正则
158
+ * @param message 自定义提示
159
+ * @returns 新 schema
160
+ */
161
+ pattern(regex, message) {
162
+ const next = this.#patch({ pattern: regex });
163
+ return message ? next.check(message, v => typeof v !== "string" || regex.test(v)) : next;
164
+ }
165
+ /**
166
+ * 要求整数
167
+ * @returns 新 schema
168
+ */
169
+ int() {
170
+ return this.#patch({ int: true, step: this.#def.step ?? 1 });
171
+ }
172
+ /**
173
+ * 数值步长(表单提示用)
174
+ * @param value 步长
175
+ * @returns 新 schema
176
+ */
177
+ step(value) {
178
+ return this.#patch({ step: value });
179
+ }
180
+ /**
181
+ * 对象:拒绝未识别的键
182
+ *
183
+ * 缺省行为是"保留并 warn",适配器这类结构明确的配置可以开严格模式。
184
+ * @returns 新 schema
185
+ */
186
+ strict() {
187
+ return this.#patch({ strict: true });
188
+ }
189
+ /**
190
+ * 数组:允许单值自动包成数组
191
+ *
192
+ * 让 `masterQQ: 123` 与 `masterQQ: [123]` 都能用 —— 旧配置最常见的困惑点。
193
+ * @returns 新 schema
194
+ */
195
+ single() {
196
+ return this.#patch({ wrapSingle: true });
197
+ }
198
+ /* ───────────────────────────── 解析 ───────────────────────────── */
199
+ /**
200
+ * 解析并校验
201
+ * @param input 待校验值
202
+ * @returns 结果对象;失败时带全部问题,不抛错
203
+ */
204
+ safeParse(input) {
205
+ const issues = [];
206
+ const value = this.#validate(input, "", issues);
207
+ const failed = value === INVALID || issues.some(i => i.severity === "error");
208
+ return failed ? { ok: false, issues } : { ok: true, value: value, issues };
209
+ }
210
+ /**
211
+ * 解析并校验,失败抛错
212
+ * @param input 待校验值
213
+ * @returns 校验后的值(已填默认、已强制转换)
214
+ * @throws SchemaError 校验失败
215
+ */
216
+ parse(input) {
217
+ const result = this.safeParse(input);
218
+ if (!result.ok)
219
+ throw new SchemaError(result.issues);
220
+ return result.value;
221
+ }
222
+ /**
223
+ * 只取默认值,不需要输入
224
+ *
225
+ * 用于生成初始配置文件。
226
+ * @returns 全部默认值构成的对象
227
+ * @throws SchemaError 当 schema 里有无默认值的必填项
228
+ */
229
+ defaults() {
230
+ return this.parse(undefined);
231
+ }
232
+ /**
233
+ * 降级为 WebUI 表单描述
234
+ * @returns 表单描述结构体
235
+ */
236
+ describe() {
237
+ const def = this.#def;
238
+ const out = { type: this.#descriptorType() };
239
+ if (def.meta.title !== undefined)
240
+ out.title = def.meta.title;
241
+ if (def.meta.description !== undefined)
242
+ out.description = def.meta.description;
243
+ if (def.hasDefault)
244
+ out.default = deepClone(def.defaultValue);
245
+ if (!def.optional && !def.hasDefault)
246
+ out.required = true;
247
+ if (def.meta.secret)
248
+ out.secret = true;
249
+ if (def.meta.readonly)
250
+ out.readonly = true;
251
+ if (def.meta.widget !== undefined)
252
+ out.widget = def.meta.widget;
253
+ if (def.meta.group !== undefined)
254
+ out.group = def.meta.group;
255
+ if (def.meta.order !== undefined)
256
+ out.order = def.meta.order;
257
+ if (def.meta.placeholder !== undefined)
258
+ out.placeholder = def.meta.placeholder;
259
+ if (def.meta.showWhen !== undefined)
260
+ out.showWhen = def.meta.showWhen;
261
+ if (def.min !== undefined)
262
+ out.min = def.min;
263
+ if (def.max !== undefined)
264
+ out.max = def.max;
265
+ if (def.step !== undefined)
266
+ out.step = def.step;
267
+ if (def.pattern !== undefined)
268
+ out.pattern = def.pattern.source;
269
+ if (def.kind === "object" && def.shape) {
270
+ const properties = {};
271
+ for (const [key, child] of Object.entries(def.shape))
272
+ properties[key] = child.describe();
273
+ out.properties = properties;
274
+ }
275
+ if (def.kind === "array" && def.element)
276
+ out.items = def.element.describe();
277
+ if (def.kind === "record" && def.valueSchema)
278
+ out.values = def.valueSchema.describe();
279
+ if (def.kind === "enum" && def.enumItems)
280
+ out.enum = def.enumItems.map(item => ({ ...item }));
281
+ if (def.kind === "literal")
282
+ out.enum = [{ value: def.literalValue }];
283
+ return out;
284
+ }
285
+ /**
286
+ * 对象 schema:取子字段 schema
287
+ * @param key 字段名
288
+ * @returns 子 schema;不是对象或字段不存在时 undefined
289
+ */
290
+ /**
291
+ *
292
+ */
293
+ field(key) {
294
+ return this.#def.shape?.[key];
295
+ }
296
+ /**
297
+ * 收集全部标了 `secret()` 的字段路径
298
+ *
299
+ * 日志脱敏与 WebUI 读取脱敏都用它,保证"标一次、处处生效"。
300
+ * @returns 点分路径列表
301
+ */
302
+ secretPaths() {
303
+ const out = [];
304
+ this.#collectSecrets("", out);
305
+ return out;
306
+ }
307
+ /* ───────────────────────────── 内部 ───────────────────────────── */
308
+ /**
309
+ * 克隆并打补丁
310
+ * @param patch 要覆盖的定义片段
311
+ * @returns 新 schema
312
+ */
313
+ #patch(patch) {
314
+ return new _a({
315
+ ...this.#def,
316
+ ...patch,
317
+ meta: { ...this.#def.meta, ...(patch.meta ?? {}) }
318
+ });
319
+ }
320
+ /**
321
+ * 映射到表单描述的类型名
322
+ * @returns 描述类型
323
+ */
324
+ #descriptorType() {
325
+ switch (this.#def.kind) {
326
+ case "literal":
327
+ return "enum";
328
+ case "string":
329
+ case "number":
330
+ case "boolean":
331
+ case "enum":
332
+ case "array":
333
+ case "object":
334
+ case "record":
335
+ return this.#def.kind;
336
+ default:
337
+ return "unknown";
338
+ }
339
+ }
340
+ /**
341
+ * 递归收集敏感字段路径
342
+ * @param prefix 当前路径前缀
343
+ * @param out 收集容器
344
+ */
345
+ #collectSecrets(prefix, out) {
346
+ if (this.#def.meta.secret)
347
+ out.push(prefix);
348
+ if (this.#def.shape) {
349
+ for (const [key, child] of Object.entries(this.#def.shape)) {
350
+ child.#collectSecrets(prefix === "" ? key : `${prefix}.${key}`, out);
351
+ }
352
+ }
353
+ if (this.#def.element)
354
+ this.#def.element.#collectSecrets(prefix === "" ? "*" : `${prefix}.*`, out);
355
+ if (this.#def.valueSchema)
356
+ this.#def.valueSchema.#collectSecrets(prefix === "" ? "*" : `${prefix}.*`, out);
357
+ }
358
+ /**
359
+ * 记录一条问题
360
+ * @param issues 收集容器
361
+ * @param path 路径
362
+ * @param message 说明
363
+ * @param severity 严重程度
364
+ */
365
+ #fail(issues, path, message, severity = "error") {
366
+ issues.push({ path, message, severity });
367
+ }
368
+ /**
369
+ * 核心校验
370
+ * @param input 输入值
371
+ * @param path 当前路径
372
+ * @param issues 问题收集容器
373
+ * @returns 校验后的值,或 INVALID
374
+ */
375
+ #validate(input, path, issues) {
376
+ const def = this.#def;
377
+ // 缺失值处理:默认值 → 可选 → 对象自动物化 → 报缺失
378
+ if (input === undefined || input === null) {
379
+ if (def.hasDefault)
380
+ return this.#materializeDefault(path, issues);
381
+ if (def.optional)
382
+ return undefined;
383
+ if (def.kind === "object")
384
+ return this.#validateObject({}, path, issues);
385
+ if (def.kind === "unknown")
386
+ return undefined;
387
+ this.#fail(issues, path, "缺少必填项");
388
+ return INVALID;
389
+ }
390
+ let value;
391
+ switch (def.kind) {
392
+ case "string":
393
+ value = this.#validateString(input, path, issues);
394
+ break;
395
+ case "number":
396
+ value = this.#validateNumber(input, path, issues);
397
+ break;
398
+ case "boolean":
399
+ value = this.#validateBoolean(input, path, issues);
400
+ break;
401
+ case "enum":
402
+ value = this.#validateEnum(input, path, issues);
403
+ break;
404
+ case "literal":
405
+ value = input === def.literalValue ? input : this.#reject(issues, path, `必须为 ${String(def.literalValue)}`);
406
+ break;
407
+ case "array":
408
+ value = this.#validateArray(input, path, issues);
409
+ break;
410
+ case "object":
411
+ value = this.#validateObject(input, path, issues);
412
+ break;
413
+ case "record":
414
+ value = this.#validateRecord(input, path, issues);
415
+ break;
416
+ default:
417
+ value = input;
418
+ }
419
+ if (value === INVALID)
420
+ return INVALID;
421
+ for (const rule of def.checks ?? []) {
422
+ if (!rule.test(value)) {
423
+ this.#fail(issues, path, rule.message);
424
+ return INVALID;
425
+ }
426
+ }
427
+ return value;
428
+ }
429
+ /**
430
+ * 记录错误并返回 INVALID
431
+ * @param issues 问题收集容器
432
+ * @param path 路径
433
+ * @param message 说明
434
+ * @returns INVALID
435
+ */
436
+ #reject(issues, path, message) {
437
+ this.#fail(issues, path, message);
438
+ return INVALID;
439
+ }
440
+ /**
441
+ * 把声明的默认值也过一遍校验
442
+ *
443
+ * 默认值必须走同一条校验/转换链,否则 `defaults()` 与 `parse(用户文件)`
444
+ * 会给出**形态不同的同一份配置**(例如 duration 的默认 `0` 与文件里读回的
445
+ * `"0"`),下游按路径比对时就会在每次启动时误报"配置变了"。
446
+ *
447
+ * 默认值不合法属于插件作者的 bug,不是用户的错:这里只记 warn 并退回原始
448
+ * 默认值,让机器人照常启动,而不是让用户面对一个自己无法修复的启动失败。
449
+ * @param path 当前路径
450
+ * @param issues 问题收集容器
451
+ * @returns 规范化后的默认值
452
+ */
453
+ #materializeDefault(path, issues) {
454
+ const raw = deepClone(this.#def.defaultValue);
455
+ if (raw === undefined || raw === null)
456
+ return raw;
457
+ const probe = [];
458
+ const value = this.#validate(raw, path, probe);
459
+ if (value === INVALID || probe.some(i => i.severity === "error")) {
460
+ const detail = probe.map(i => i.message).join(";");
461
+ issues.push({
462
+ path,
463
+ message: `schema 声明的默认值不符合自身规则(${detail}),请联系插件作者`,
464
+ severity: "warn"
465
+ });
466
+ return raw;
467
+ }
468
+ issues.push(...probe);
469
+ return value;
470
+ }
471
+ /**
472
+ * 校验字符串
473
+ * @param input 输入
474
+ * @param path 路径
475
+ * @param issues 问题容器
476
+ * @returns 字符串或 INVALID
477
+ */
478
+ #validateString(input, path, issues) {
479
+ const def = this.#def;
480
+ // 数字/布尔宽容转字符串:YAML 里 `token: 12345` 会被解析成数字
481
+ let text;
482
+ if (typeof input === "string")
483
+ text = input;
484
+ else if (typeof input === "number" && def.allowNumber)
485
+ return input;
486
+ else if (typeof input === "number" || typeof input === "boolean")
487
+ text = String(input);
488
+ else
489
+ return this.#reject(issues, path, "应为字符串");
490
+ if (def.trim !== false)
491
+ text = text.trim();
492
+ if (def.min !== undefined && [...text].length < def.min) {
493
+ return this.#reject(issues, path, `长度不能少于 ${def.min}`);
494
+ }
495
+ if (def.max !== undefined && [...text].length > def.max) {
496
+ return this.#reject(issues, path, `长度不能超过 ${def.max}`);
497
+ }
498
+ if (def.pattern && !def.pattern.test(text)) {
499
+ return this.#reject(issues, path, `格式不正确(需匹配 ${def.pattern.source})`);
500
+ }
501
+ return text;
502
+ }
503
+ /**
504
+ * 校验数值
505
+ * @param input 输入
506
+ * @param path 路径
507
+ * @param issues 问题容器
508
+ * @returns 数值或 INVALID
509
+ */
510
+ #validateNumber(input, path, issues) {
511
+ const def = this.#def;
512
+ let num;
513
+ if (typeof input === "number")
514
+ num = input;
515
+ else if (typeof input === "string" && input.trim() !== "" && Number.isFinite(Number(input))) {
516
+ num = Number(input);
517
+ }
518
+ else
519
+ return this.#reject(issues, path, "应为数字");
520
+ if (!Number.isFinite(num))
521
+ return this.#reject(issues, path, "应为有限数字");
522
+ if (def.int && !Number.isInteger(num))
523
+ return this.#reject(issues, path, "应为整数");
524
+ if (def.min !== undefined && num < def.min)
525
+ return this.#reject(issues, path, `不能小于 ${def.min}`);
526
+ if (def.max !== undefined && num > def.max)
527
+ return this.#reject(issues, path, `不能大于 ${def.max}`);
528
+ return num;
529
+ }
530
+ /**
531
+ * 校验布尔
532
+ * @param input 输入
533
+ * @param path 路径
534
+ * @param issues 问题容器
535
+ * @returns 布尔或 INVALID
536
+ */
537
+ #validateBoolean(input, path, issues) {
538
+ if (typeof input === "boolean")
539
+ return input;
540
+ if (typeof input === "string") {
541
+ const text = input.trim().toLowerCase();
542
+ if (["true", "1", "yes", "on", "是"].includes(text))
543
+ return true;
544
+ if (["false", "0", "no", "off", "否"].includes(text))
545
+ return false;
546
+ }
547
+ if (input === 1)
548
+ return true;
549
+ if (input === 0)
550
+ return false;
551
+ return this.#reject(issues, path, "应为布尔值");
552
+ }
553
+ /**
554
+ * 校验枚举
555
+ * @param input 输入
556
+ * @param path 路径
557
+ * @param issues 问题容器
558
+ * @returns 枚举值或 INVALID
559
+ */
560
+ #validateEnum(input, path, issues) {
561
+ const items = this.#def.enumItems ?? [];
562
+ for (const item of items) {
563
+ if (item.value === input)
564
+ return input;
565
+ // WebUI 的 select 只会回传字符串,数字枚举需要按文本比一次
566
+ if (String(item.value) === String(input))
567
+ return item.value;
568
+ }
569
+ const allowed = items.map(i => String(i.value)).join(" / ");
570
+ return this.#reject(issues, path, `只能是 ${allowed}`);
571
+ }
572
+ /**
573
+ * 校验数组
574
+ * @param input 输入
575
+ * @param path 路径
576
+ * @param issues 问题容器
577
+ * @returns 数组或 INVALID
578
+ */
579
+ #validateArray(input, path, issues) {
580
+ const def = this.#def;
581
+ let list;
582
+ if (Array.isArray(input))
583
+ list = input;
584
+ else if (def.wrapSingle)
585
+ list = [input];
586
+ else
587
+ return this.#reject(issues, path, "应为数组");
588
+ if (def.min !== undefined && list.length < def.min) {
589
+ return this.#reject(issues, path, `至少需要 ${def.min} 项`);
590
+ }
591
+ if (def.max !== undefined && list.length > def.max) {
592
+ return this.#reject(issues, path, `最多 ${def.max} 项`);
593
+ }
594
+ const element = def.element;
595
+ if (!element)
596
+ return deepClone(list);
597
+ const out = [];
598
+ let bad = false;
599
+ for (let i = 0; i < list.length; i++) {
600
+ const item = element.#validate(list[i], `${path}[${i}]`, issues);
601
+ if (item === INVALID)
602
+ bad = true;
603
+ else
604
+ out.push(item);
605
+ }
606
+ return bad ? INVALID : out;
607
+ }
608
+ /**
609
+ * 校验对象
610
+ * @param input 输入
611
+ * @param path 路径
612
+ * @param issues 问题容器
613
+ * @returns 对象或 INVALID
614
+ */
615
+ #validateObject(input, path, issues) {
616
+ const def = this.#def;
617
+ if (!isPlainObject(input))
618
+ return this.#reject(issues, path, "应为对象");
619
+ const shape = def.shape ?? {};
620
+ const out = {};
621
+ let bad = false;
622
+ for (const [key, child] of Object.entries(shape)) {
623
+ const childPath = path === "" ? key : `${path}.${key}`;
624
+ const value = child.#validate(input[key], childPath, issues);
625
+ if (value === INVALID)
626
+ bad = true;
627
+ else if (value !== undefined)
628
+ out[key] = value;
629
+ }
630
+ for (const key of Object.keys(input)) {
631
+ if (Object.prototype.hasOwnProperty.call(shape, key))
632
+ continue;
633
+ const childPath = path === "" ? key : `${path}.${key}`;
634
+ if (def.strict) {
635
+ this.#fail(issues, childPath, "无法识别的配置项");
636
+ bad = true;
637
+ }
638
+ else {
639
+ // 保留但提示:可能是拼写错误,也可能来自暂时卸载的插件
640
+ this.#fail(issues, childPath, "无法识别的配置项,已原样保留", "warn");
641
+ out[key] = deepClone(input[key]);
642
+ }
643
+ }
644
+ return bad ? INVALID : out;
645
+ }
646
+ /**
647
+ * 校验字典
648
+ * @param input 输入
649
+ * @param path 路径
650
+ * @param issues 问题容器
651
+ * @returns 字典或 INVALID
652
+ */
653
+ #validateRecord(input, path, issues) {
654
+ if (!isPlainObject(input))
655
+ return this.#reject(issues, path, "应为键值对象");
656
+ const valueSchema = this.#def.valueSchema;
657
+ if (!valueSchema)
658
+ return deepClone(input);
659
+ const out = {};
660
+ let bad = false;
661
+ for (const [key, raw] of Object.entries(input)) {
662
+ const childPath = path === "" ? key : `${path}.${key}`;
663
+ const value = valueSchema.#validate(raw, childPath, issues);
664
+ if (value === INVALID)
665
+ bad = true;
666
+ else
667
+ out[key] = value;
668
+ }
669
+ return bad ? INVALID : out;
670
+ }
671
+ }
672
+ _a = Schema;
673
+ /**
674
+ * 创建基础节点
675
+ * @param def 定义片段
676
+ * @returns schema
677
+ */
678
+ function make(def) {
679
+ return new Schema({ ...def, meta: def.meta ?? {} });
680
+ }
681
+ /**
682
+ * 字符串
683
+ * @returns 字符串 schema
684
+ */
685
+ function string() {
686
+ return make({ kind: "string" });
687
+ }
688
+ /**
689
+ * 数字
690
+ * @returns 数字 schema
691
+ */
692
+ function number() {
693
+ return make({ kind: "number" });
694
+ }
695
+ /**
696
+ * 布尔
697
+ * @returns 布尔 schema
698
+ */
699
+ function boolean() {
700
+ return make({ kind: "boolean" });
701
+ }
702
+ /**
703
+ * 字面量
704
+ * @param value 唯一允许的值
705
+ * @returns 字面量 schema
706
+ */
707
+ function literal(value) {
708
+ return make({ kind: "literal", literalValue: value });
709
+ }
710
+ /**
711
+ * 枚举
712
+ * @param values 候选值
713
+ * @param labels 值到展示文案的映射
714
+ * @returns 枚举 schema
715
+ */
716
+ function enumOf(values, labels) {
717
+ const items = values.map(value => {
718
+ const label = labels?.[String(value)];
719
+ return label === undefined ? { value } : { value, label };
720
+ });
721
+ return make({ kind: "enum", enumItems: items, meta: { widget: "select" } });
722
+ }
723
+ /**
724
+ * 带说明的枚举(WebUI 下拉框里显示 label 与 description)
725
+ * @param items 候选项
726
+ * @returns 枚举 schema
727
+ */
728
+ function select(items) {
729
+ return make({
730
+ kind: "enum",
731
+ enumItems: items.map(item => ({ ...item })),
732
+ meta: { widget: "select" }
733
+ });
734
+ }
735
+ /**
736
+ * 数组
737
+ * @param element 元素 schema
738
+ * @returns 数组 schema
739
+ */
740
+ function array(element) {
741
+ return make({ kind: "array", element });
742
+ }
743
+ /**
744
+ * 对象
745
+ * @param shape 字段表
746
+ * @returns 对象 schema
747
+ */
748
+ function object(shape) {
749
+ return make({ kind: "object", shape });
750
+ }
751
+ /**
752
+ * 字典(键任意、值同构)
753
+ * @param valueSchema 值 schema
754
+ * @returns 字典 schema
755
+ */
756
+ function record(valueSchema) {
757
+ return make({ kind: "record", valueSchema, meta: { widget: "keyValue" } });
758
+ }
759
+ /**
760
+ * 任意值(不校验)
761
+ *
762
+ * 兼容出口:插件存在确实无法描述的结构时使用,但 WebUI 仅能提供 JSON 编辑框。
763
+ * @returns 任意值 schema
764
+ */
765
+ function unknownValue() {
766
+ return make({ kind: "unknown", meta: { widget: "code" } });
767
+ }
768
+ /**
769
+ * 时长(`"30s"` / `"7d"` / 毫秒数)
770
+ *
771
+ * 数值写法与字符串写法都原样保留,不互相转换 —— 见 `SchemaDef.allowNumber`。
772
+ * @returns 时长 schema
773
+ */
774
+ function duration() {
775
+ return make({ kind: "string", meta: { widget: "duration" }, allowNumber: true }).check("时长格式应为毫秒数或形如 30s / 5m / 1h / 7d", value => typeof value === "number" || parseDuration(value, Number.NaN) === parseDuration(value, 0));
776
+ }
777
+ /**
778
+ * cron 表达式
779
+ * @returns cron schema
780
+ */
781
+ function cron() {
782
+ return make({ kind: "string", meta: { widget: "cron" } }).check("cron 表达式应为 5 或 6 段", value => {
783
+ const parts = value.trim().split(/\s+/);
784
+ return parts.length === 5 || parts.length === 6;
785
+ });
786
+ }
787
+ /**
788
+ * 端口号
789
+ * @returns 端口 schema
790
+ */
791
+ function port() {
792
+ return make({ kind: "number", meta: { widget: "number" }, int: true, min: 1, max: 65535 });
793
+ }
794
+ /**
795
+ * 密码 / 令牌(自动脱敏)
796
+ * @returns 敏感字符串 schema
797
+ */
798
+ function password() {
799
+ return string().secret();
800
+ }
801
+ /**
802
+ * 多行文本
803
+ * @returns 文本域 schema
804
+ */
805
+ function text() {
806
+ return string().widget("textarea");
807
+ }
808
+ /**
809
+ * 字符串标签数组(WebUI 用 tag 输入框)
810
+ * @returns 标签数组 schema
811
+ */
812
+ function tags() {
813
+ return array(string()).widget("tags").single();
814
+ }
815
+ /**
816
+ * id 列表(QQ 号 / 群号,允许写单个值)
817
+ * @returns id 数组 schema
818
+ */
819
+ function ids() {
820
+ return array(string().pattern(/^\d{1,20}$/, "应为纯数字 id"))
821
+ .widget("tags")
822
+ .single();
823
+ }
824
+ /**
825
+ * 目录路径
826
+ * @returns 目录 schema
827
+ */
828
+ function dir() {
829
+ return string().widget("dir");
830
+ }
831
+ /**
832
+ * 文件路径
833
+ * @returns 文件 schema
834
+ */
835
+ function file() {
836
+ return string().widget("file");
837
+ }
838
+ /**
839
+ * schema 构造器集合
840
+ *
841
+ * 用法:
842
+ * ```ts
843
+ * const conf = s.object({
844
+ * port: s.port().default(3000).title("监听端口"),
845
+ * mode: s.enum(["ws", "ws-reverse"]).default("ws-reverse").title("连接方式")
846
+ * })
847
+ * type Conf = Infer<typeof conf>
848
+ * ```
849
+ */
850
+ export const s = {
851
+ string,
852
+ number,
853
+ boolean,
854
+ literal,
855
+ enum: enumOf,
856
+ select,
857
+ array,
858
+ object,
859
+ record,
860
+ unknown: unknownValue,
861
+ duration,
862
+ cron,
863
+ port,
864
+ password,
865
+ text,
866
+ tags,
867
+ ids,
868
+ dir,
869
+ file
870
+ };
871
+ //# sourceMappingURL=schema.js.map