xray-manager 1.8.5 → 2.0.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 (324) hide show
  1. package/README.md +102 -42
  2. package/dist/cli.mjs +8587 -0
  3. package/dist/cli.mjs.map +7 -0
  4. package/package.json +13 -5
  5. package/dist/cli.d.ts +0 -11
  6. package/dist/cli.d.ts.map +0 -1
  7. package/dist/cli.js +0 -134
  8. package/dist/cli.js.map +0 -1
  9. package/dist/commands/clash.d.ts +0 -20
  10. package/dist/commands/clash.d.ts.map +0 -1
  11. package/dist/commands/clash.js +0 -156
  12. package/dist/commands/clash.js.map +0 -1
  13. package/dist/commands/config.d.ts +0 -56
  14. package/dist/commands/config.d.ts.map +0 -1
  15. package/dist/commands/config.js +0 -461
  16. package/dist/commands/config.js.map +0 -1
  17. package/dist/commands/interactive.d.ts +0 -55
  18. package/dist/commands/interactive.d.ts.map +0 -1
  19. package/dist/commands/interactive.js +0 -418
  20. package/dist/commands/interactive.js.map +0 -1
  21. package/dist/commands/logs.d.ts +0 -62
  22. package/dist/commands/logs.d.ts.map +0 -1
  23. package/dist/commands/logs.js +0 -389
  24. package/dist/commands/logs.js.map +0 -1
  25. package/dist/commands/quota.d.ts +0 -54
  26. package/dist/commands/quota.d.ts.map +0 -1
  27. package/dist/commands/quota.js +0 -661
  28. package/dist/commands/quota.js.map +0 -1
  29. package/dist/commands/review.d.ts +0 -8
  30. package/dist/commands/review.d.ts.map +0 -1
  31. package/dist/commands/review.js +0 -79
  32. package/dist/commands/review.js.map +0 -1
  33. package/dist/commands/service.d.ts +0 -43
  34. package/dist/commands/service.d.ts.map +0 -1
  35. package/dist/commands/service.js +0 -202
  36. package/dist/commands/service.js.map +0 -1
  37. package/dist/commands/user.d.ts +0 -49
  38. package/dist/commands/user.d.ts.map +0 -1
  39. package/dist/commands/user.js +0 -371
  40. package/dist/commands/user.js.map +0 -1
  41. package/dist/components/dashboard-widget.d.ts +0 -21
  42. package/dist/components/dashboard-widget.d.ts.map +0 -1
  43. package/dist/components/dashboard-widget.js +0 -234
  44. package/dist/components/dashboard-widget.js.map +0 -1
  45. package/dist/components/progress-bar.d.ts +0 -67
  46. package/dist/components/progress-bar.d.ts.map +0 -1
  47. package/dist/components/progress-bar.js +0 -138
  48. package/dist/components/progress-bar.js.map +0 -1
  49. package/dist/components/user-table.d.ts +0 -8
  50. package/dist/components/user-table.d.ts.map +0 -1
  51. package/dist/components/user-table.js +0 -91
  52. package/dist/components/user-table.js.map +0 -1
  53. package/dist/config/i18n.d.ts +0 -136
  54. package/dist/config/i18n.d.ts.map +0 -1
  55. package/dist/config/i18n.js +0 -323
  56. package/dist/config/i18n.js.map +0 -1
  57. package/dist/constants/error-codes.d.ts +0 -344
  58. package/dist/constants/error-codes.d.ts.map +0 -1
  59. package/dist/constants/error-codes.js +0 -462
  60. package/dist/constants/error-codes.js.map +0 -1
  61. package/dist/constants/exit-codes.d.ts +0 -49
  62. package/dist/constants/exit-codes.d.ts.map +0 -1
  63. package/dist/constants/exit-codes.js +0 -100
  64. package/dist/constants/exit-codes.js.map +0 -1
  65. package/dist/constants/paths.d.ts +0 -63
  66. package/dist/constants/paths.d.ts.map +0 -1
  67. package/dist/constants/paths.js +0 -78
  68. package/dist/constants/paths.js.map +0 -1
  69. package/dist/constants/quota.d.ts +0 -126
  70. package/dist/constants/quota.d.ts.map +0 -1
  71. package/dist/constants/quota.js +0 -135
  72. package/dist/constants/quota.js.map +0 -1
  73. package/dist/constants/review.d.ts +0 -14
  74. package/dist/constants/review.d.ts.map +0 -1
  75. package/dist/constants/review.js +0 -33
  76. package/dist/constants/review.js.map +0 -1
  77. package/dist/constants/supported-distros.d.ts +0 -17
  78. package/dist/constants/supported-distros.d.ts.map +0 -1
  79. package/dist/constants/supported-distros.js +0 -68
  80. package/dist/constants/supported-distros.js.map +0 -1
  81. package/dist/constants/theme.d.ts +0 -34
  82. package/dist/constants/theme.d.ts.map +0 -1
  83. package/dist/constants/theme.js +0 -52
  84. package/dist/constants/theme.js.map +0 -1
  85. package/dist/constants/timeouts.d.ts +0 -84
  86. package/dist/constants/timeouts.d.ts.map +0 -1
  87. package/dist/constants/timeouts.js +0 -111
  88. package/dist/constants/timeouts.js.map +0 -1
  89. package/dist/constants/ui-symbols.d.ts +0 -47
  90. package/dist/constants/ui-symbols.d.ts.map +0 -1
  91. package/dist/constants/ui-symbols.js +0 -48
  92. package/dist/constants/ui-symbols.js.map +0 -1
  93. package/dist/services/clash-config.d.ts +0 -16
  94. package/dist/services/clash-config.d.ts.map +0 -1
  95. package/dist/services/clash-config.js +0 -107
  96. package/dist/services/clash-config.js.map +0 -1
  97. package/dist/services/config-manager.d.ts +0 -90
  98. package/dist/services/config-manager.d.ts.map +0 -1
  99. package/dist/services/config-manager.js +0 -307
  100. package/dist/services/config-manager.js.map +0 -1
  101. package/dist/services/layout-manager.d.ts +0 -94
  102. package/dist/services/layout-manager.d.ts.map +0 -1
  103. package/dist/services/layout-manager.js +0 -192
  104. package/dist/services/layout-manager.js.map +0 -1
  105. package/dist/services/log-manager.d.ts +0 -157
  106. package/dist/services/log-manager.d.ts.map +0 -1
  107. package/dist/services/log-manager.js +0 -397
  108. package/dist/services/log-manager.js.map +0 -1
  109. package/dist/services/navigation-manager.d.ts +0 -23
  110. package/dist/services/navigation-manager.d.ts.map +0 -1
  111. package/dist/services/navigation-manager.js +0 -39
  112. package/dist/services/navigation-manager.js.map +0 -1
  113. package/dist/services/platform-detector.d.ts +0 -10
  114. package/dist/services/platform-detector.d.ts.map +0 -1
  115. package/dist/services/platform-detector.js +0 -106
  116. package/dist/services/platform-detector.js.map +0 -1
  117. package/dist/services/public-ip-manager.d.ts +0 -78
  118. package/dist/services/public-ip-manager.d.ts.map +0 -1
  119. package/dist/services/public-ip-manager.js +0 -296
  120. package/dist/services/public-ip-manager.js.map +0 -1
  121. package/dist/services/quota-enforcer.d.ts +0 -86
  122. package/dist/services/quota-enforcer.d.ts.map +0 -1
  123. package/dist/services/quota-enforcer.js +0 -151
  124. package/dist/services/quota-enforcer.js.map +0 -1
  125. package/dist/services/quota-manager.d.ts +0 -101
  126. package/dist/services/quota-manager.d.ts.map +0 -1
  127. package/dist/services/quota-manager.js +0 -257
  128. package/dist/services/quota-manager.js.map +0 -1
  129. package/dist/services/review/areas/community.d.ts +0 -9
  130. package/dist/services/review/areas/community.d.ts.map +0 -1
  131. package/dist/services/review/areas/community.js +0 -59
  132. package/dist/services/review/areas/community.js.map +0 -1
  133. package/dist/services/review/areas/contribution.d.ts +0 -9
  134. package/dist/services/review/areas/contribution.d.ts.map +0 -1
  135. package/dist/services/review/areas/contribution.js +0 -107
  136. package/dist/services/review/areas/contribution.js.map +0 -1
  137. package/dist/services/review/areas/documentation.d.ts +0 -9
  138. package/dist/services/review/areas/documentation.d.ts.map +0 -1
  139. package/dist/services/review/areas/documentation.js +0 -110
  140. package/dist/services/review/areas/documentation.js.map +0 -1
  141. package/dist/services/review/areas/license.d.ts +0 -9
  142. package/dist/services/review/areas/license.d.ts.map +0 -1
  143. package/dist/services/review/areas/license.js +0 -86
  144. package/dist/services/review/areas/license.js.map +0 -1
  145. package/dist/services/review/areas/quality.d.ts +0 -9
  146. package/dist/services/review/areas/quality.d.ts.map +0 -1
  147. package/dist/services/review/areas/quality.js +0 -84
  148. package/dist/services/review/areas/quality.js.map +0 -1
  149. package/dist/services/review/areas/security.d.ts +0 -9
  150. package/dist/services/review/areas/security.d.ts.map +0 -1
  151. package/dist/services/review/areas/security.js +0 -64
  152. package/dist/services/review/areas/security.js.map +0 -1
  153. package/dist/services/review/evidence.d.ts +0 -10
  154. package/dist/services/review/evidence.d.ts.map +0 -1
  155. package/dist/services/review/evidence.js +0 -40
  156. package/dist/services/review/evidence.js.map +0 -1
  157. package/dist/services/review/recommendations-filter.d.ts +0 -12
  158. package/dist/services/review/recommendations-filter.d.ts.map +0 -1
  159. package/dist/services/review/recommendations-filter.js +0 -20
  160. package/dist/services/review/recommendations-filter.js.map +0 -1
  161. package/dist/services/review/repo-scanner.d.ts +0 -8
  162. package/dist/services/review/repo-scanner.d.ts.map +0 -1
  163. package/dist/services/review/repo-scanner.js +0 -15
  164. package/dist/services/review/repo-scanner.js.map +0 -1
  165. package/dist/services/review/report-renderer.d.ts +0 -15
  166. package/dist/services/review/report-renderer.d.ts.map +0 -1
  167. package/dist/services/review/report-renderer.js +0 -120
  168. package/dist/services/review/report-renderer.js.map +0 -1
  169. package/dist/services/review/review-engine.d.ts +0 -15
  170. package/dist/services/review/review-engine.d.ts.map +0 -1
  171. package/dist/services/review/review-engine.js +0 -61
  172. package/dist/services/review/review-engine.js.map +0 -1
  173. package/dist/services/review/summary-builder.d.ts +0 -8
  174. package/dist/services/review/summary-builder.d.ts.map +0 -1
  175. package/dist/services/review/summary-builder.js +0 -26
  176. package/dist/services/review/summary-builder.js.map +0 -1
  177. package/dist/services/screen-manager.d.ts +0 -13
  178. package/dist/services/screen-manager.d.ts.map +0 -1
  179. package/dist/services/screen-manager.js +0 -42
  180. package/dist/services/screen-manager.js.map +0 -1
  181. package/dist/services/stats-config-manager.d.ts +0 -110
  182. package/dist/services/stats-config-manager.d.ts.map +0 -1
  183. package/dist/services/stats-config-manager.js +0 -443
  184. package/dist/services/stats-config-manager.js.map +0 -1
  185. package/dist/services/systemd-manager.d.ts +0 -197
  186. package/dist/services/systemd-manager.d.ts.map +0 -1
  187. package/dist/services/systemd-manager.js +0 -458
  188. package/dist/services/systemd-manager.js.map +0 -1
  189. package/dist/services/traffic-manager.d.ts +0 -106
  190. package/dist/services/traffic-manager.d.ts.map +0 -1
  191. package/dist/services/traffic-manager.js +0 -368
  192. package/dist/services/traffic-manager.js.map +0 -1
  193. package/dist/services/user-manager.d.ts +0 -90
  194. package/dist/services/user-manager.d.ts.map +0 -1
  195. package/dist/services/user-manager.js +0 -347
  196. package/dist/services/user-manager.js.map +0 -1
  197. package/dist/services/user-metadata-manager.d.ts +0 -85
  198. package/dist/services/user-metadata-manager.d.ts.map +0 -1
  199. package/dist/services/user-metadata-manager.js +0 -181
  200. package/dist/services/user-metadata-manager.js.map +0 -1
  201. package/dist/types/config.d.ts +0 -340
  202. package/dist/types/config.d.ts.map +0 -1
  203. package/dist/types/config.js +0 -7
  204. package/dist/types/config.js.map +0 -1
  205. package/dist/types/layout.d.ts +0 -119
  206. package/dist/types/layout.d.ts.map +0 -1
  207. package/dist/types/layout.js +0 -142
  208. package/dist/types/layout.js.map +0 -1
  209. package/dist/types/platform.d.ts +0 -72
  210. package/dist/types/platform.d.ts.map +0 -1
  211. package/dist/types/platform.js +0 -38
  212. package/dist/types/platform.js.map +0 -1
  213. package/dist/types/quota.d.ts +0 -158
  214. package/dist/types/quota.d.ts.map +0 -1
  215. package/dist/types/quota.js +0 -26
  216. package/dist/types/quota.js.map +0 -1
  217. package/dist/types/review.d.ts +0 -62
  218. package/dist/types/review.d.ts.map +0 -1
  219. package/dist/types/review.js +0 -8
  220. package/dist/types/review.js.map +0 -1
  221. package/dist/types/server-config.d.ts +0 -53
  222. package/dist/types/server-config.d.ts.map +0 -1
  223. package/dist/types/server-config.js +0 -19
  224. package/dist/types/server-config.js.map +0 -1
  225. package/dist/types/service.d.ts +0 -96
  226. package/dist/types/service.d.ts.map +0 -1
  227. package/dist/types/service.js +0 -7
  228. package/dist/types/service.js.map +0 -1
  229. package/dist/types/terminal.d.ts +0 -35
  230. package/dist/types/terminal.d.ts.map +0 -1
  231. package/dist/types/terminal.js +0 -20
  232. package/dist/types/terminal.js.map +0 -1
  233. package/dist/types/ui-components.d.ts +0 -53
  234. package/dist/types/ui-components.d.ts.map +0 -1
  235. package/dist/types/ui-components.js +0 -3
  236. package/dist/types/ui-components.js.map +0 -1
  237. package/dist/types/user-metadata.d.ts +0 -43
  238. package/dist/types/user-metadata.d.ts.map +0 -1
  239. package/dist/types/user-metadata.js +0 -17
  240. package/dist/types/user-metadata.js.map +0 -1
  241. package/dist/types/user.d.ts +0 -134
  242. package/dist/types/user.d.ts.map +0 -1
  243. package/dist/types/user.js +0 -7
  244. package/dist/types/user.js.map +0 -1
  245. package/dist/utils/clipboard.d.ts +0 -21
  246. package/dist/utils/clipboard.d.ts.map +0 -1
  247. package/dist/utils/clipboard.js +0 -45
  248. package/dist/utils/clipboard.js.map +0 -1
  249. package/dist/utils/error-formatter.d.ts +0 -60
  250. package/dist/utils/error-formatter.d.ts.map +0 -1
  251. package/dist/utils/error-formatter.js +0 -244
  252. package/dist/utils/error-formatter.js.map +0 -1
  253. package/dist/utils/errors.d.ts +0 -92
  254. package/dist/utils/errors.d.ts.map +0 -1
  255. package/dist/utils/errors.js +0 -143
  256. package/dist/utils/errors.js.map +0 -1
  257. package/dist/utils/firewall.d.ts +0 -14
  258. package/dist/utils/firewall.d.ts.map +0 -1
  259. package/dist/utils/firewall.js +0 -78
  260. package/dist/utils/firewall.js.map +0 -1
  261. package/dist/utils/format.d.ts +0 -93
  262. package/dist/utils/format.d.ts.map +0 -1
  263. package/dist/utils/format.js +0 -240
  264. package/dist/utils/format.js.map +0 -1
  265. package/dist/utils/icons.d.ts +0 -53
  266. package/dist/utils/icons.d.ts.map +0 -1
  267. package/dist/utils/icons.js +0 -143
  268. package/dist/utils/icons.js.map +0 -1
  269. package/dist/utils/layout.d.ts +0 -142
  270. package/dist/utils/layout.d.ts.map +0 -1
  271. package/dist/utils/layout.js +0 -381
  272. package/dist/utils/layout.js.map +0 -1
  273. package/dist/utils/logger.d.ts +0 -160
  274. package/dist/utils/logger.d.ts.map +0 -1
  275. package/dist/utils/logger.js +0 -351
  276. package/dist/utils/logger.js.map +0 -1
  277. package/dist/utils/network.d.ts +0 -39
  278. package/dist/utils/network.d.ts.map +0 -1
  279. package/dist/utils/network.js +0 -227
  280. package/dist/utils/network.js.map +0 -1
  281. package/dist/utils/os-detection.d.ts +0 -10
  282. package/dist/utils/os-detection.d.ts.map +0 -1
  283. package/dist/utils/os-detection.js +0 -86
  284. package/dist/utils/os-detection.js.map +0 -1
  285. package/dist/utils/preflight.d.ts +0 -57
  286. package/dist/utils/preflight.d.ts.map +0 -1
  287. package/dist/utils/preflight.js +0 -215
  288. package/dist/utils/preflight.js.map +0 -1
  289. package/dist/utils/repo-scan.d.ts +0 -54
  290. package/dist/utils/repo-scan.d.ts.map +0 -1
  291. package/dist/utils/repo-scan.js +0 -165
  292. package/dist/utils/repo-scan.js.map +0 -1
  293. package/dist/utils/report-output.d.ts +0 -13
  294. package/dist/utils/report-output.d.ts.map +0 -1
  295. package/dist/utils/report-output.js +0 -33
  296. package/dist/utils/report-output.js.map +0 -1
  297. package/dist/utils/review-id.d.ts +0 -8
  298. package/dist/utils/review-id.d.ts.map +0 -1
  299. package/dist/utils/review-id.js +0 -17
  300. package/dist/utils/review-id.js.map +0 -1
  301. package/dist/utils/splash.d.ts +0 -21
  302. package/dist/utils/splash.d.ts.map +0 -1
  303. package/dist/utils/splash.js +0 -179
  304. package/dist/utils/splash.js.map +0 -1
  305. package/dist/utils/terminal.d.ts +0 -32
  306. package/dist/utils/terminal.d.ts.map +0 -1
  307. package/dist/utils/terminal.js +0 -93
  308. package/dist/utils/terminal.js.map +0 -1
  309. package/dist/utils/traffic-formatter.d.ts +0 -45
  310. package/dist/utils/traffic-formatter.d.ts.map +0 -1
  311. package/dist/utils/traffic-formatter.js +0 -131
  312. package/dist/utils/traffic-formatter.js.map +0 -1
  313. package/dist/utils/validator.d.ts +0 -102
  314. package/dist/utils/validator.d.ts.map +0 -1
  315. package/dist/utils/validator.js +0 -238
  316. package/dist/utils/validator.js.map +0 -1
  317. package/dist/utils/vless-link.d.ts +0 -27
  318. package/dist/utils/vless-link.d.ts.map +0 -1
  319. package/dist/utils/vless-link.js +0 -69
  320. package/dist/utils/vless-link.js.map +0 -1
  321. package/dist/utils/which.d.ts +0 -13
  322. package/dist/utils/which.d.ts.map +0 -1
  323. package/dist/utils/which.js +0 -28
  324. package/dist/utils/which.js.map +0 -1
@@ -1,661 +0,0 @@
1
- "use strict";
2
- /**
3
- * Quota Command Handler
4
- *
5
- * Handles quota-related commands (set, show, reset, list)
6
- *
7
- * @module commands/quota
8
- */
9
- var __importDefault = (this && this.__importDefault) || function (mod) {
10
- return (mod && mod.__esModule) ? mod : { "default": mod };
11
- };
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.promptQuotaInput = promptQuotaInput;
14
- exports.setQuota = setQuota;
15
- exports.showQuota = showQuota;
16
- exports.resetQuota = resetQuota;
17
- exports.listQuotas = listQuotas;
18
- exports.reenableUser = reenableUser;
19
- exports.configureStatsApi = configureStatsApi;
20
- exports.executeQuotaCheck = executeQuotaCheck;
21
- const quota_manager_1 = require("../services/quota-manager");
22
- const traffic_manager_1 = require("../services/traffic-manager");
23
- const user_manager_1 = require("../services/user-manager");
24
- const stats_config_manager_1 = require("../services/stats-config-manager");
25
- const quota_enforcer_1 = require("../services/quota-enforcer");
26
- const traffic_formatter_1 = require("../utils/traffic-formatter");
27
- const quota_1 = require("../constants/quota");
28
- const logger_1 = __importDefault(require("../utils/logger"));
29
- const chalk_1 = __importDefault(require("chalk"));
30
- const ora_1 = __importDefault(require("ora"));
31
- const prompts_1 = require("@inquirer/prompts");
32
- const ui_symbols_1 = require("../constants/ui-symbols");
33
- const layout_1 = require("../utils/layout");
34
- const layout_manager_1 = __importDefault(require("../services/layout-manager"));
35
- const i18n_1 = require("../config/i18n");
36
- /**
37
- * Get alert level color function
38
- */
39
- function getAlertColor(level) {
40
- switch (level) {
41
- case 'exceeded':
42
- return chalk_1.default.red;
43
- case 'warning':
44
- return chalk_1.default.yellow;
45
- default:
46
- return chalk_1.default.green;
47
- }
48
- }
49
- /**
50
- * Prompt user to setup Stats API if not available
51
- * @returns true if Stats API is now available, false otherwise
52
- */
53
- async function promptStatsApiSetup(options = {}) {
54
- const statsManager = new stats_config_manager_1.StatsConfigManager(options.configPath, options.serviceName);
55
- const detection = await statsManager.detectStatsConfig();
56
- if (detection.available) {
57
- if (detection.detectedPort) {
58
- try {
59
- const quotaManager = new quota_manager_1.QuotaManager();
60
- await quotaManager.setApiPort(detection.detectedPort);
61
- }
62
- catch (error) {
63
- logger_1.default.warn(`保存 API 端口失败: ${error.message}`);
64
- }
65
- }
66
- return true;
67
- }
68
- // Show detection result
69
- logger_1.default.newline();
70
- console.log(chalk_1.default.yellow(` ⚠️ ${detection.message}`));
71
- logger_1.default.newline();
72
- if (detection.missingComponents.length === 0) {
73
- // Config exists but API not responding
74
- console.log(chalk_1.default.gray(' Stats API 已配置但无法连接,请检查 Xray 服务状态'));
75
- return false;
76
- }
77
- // Prompt for auto-configuration
78
- const shouldConfigure = await (0, prompts_1.confirm)({
79
- message: '是否自动配置 Stats API?配置后可查看流量统计',
80
- default: true,
81
- });
82
- if (!shouldConfigure) {
83
- return false;
84
- }
85
- // Execute configuration
86
- const spinner = (0, ora_1.default)('正在配置 Stats API...').start();
87
- spinner.text = '正在备份配置...';
88
- const result = await statsManager.enableStatsApi();
89
- if (result.success) {
90
- spinner.succeed(chalk_1.default.green(result.message));
91
- logger_1.default.newline();
92
- console.log(chalk_1.default.cyan(' API 端口: ') + chalk_1.default.white(result.apiPort));
93
- if (result.backupPath) {
94
- console.log(chalk_1.default.cyan(' 备份文件: ') + chalk_1.default.gray(result.backupPath));
95
- }
96
- logger_1.default.newline();
97
- try {
98
- const quotaManager = new quota_manager_1.QuotaManager();
99
- await quotaManager.setApiPort(result.apiPort);
100
- }
101
- catch (error) {
102
- logger_1.default.warn(`保存 API 端口失败: ${error.message}`);
103
- }
104
- return true;
105
- }
106
- else {
107
- spinner.fail(chalk_1.default.red(result.message));
108
- if (result.error) {
109
- console.log(chalk_1.default.red(` 错误: ${result.error}`));
110
- }
111
- if (result.rolledBack) {
112
- console.log(chalk_1.default.yellow(' 已自动恢复原配置'));
113
- }
114
- if (result.backupPath) {
115
- console.log(chalk_1.default.gray(` 备份文件: ${result.backupPath}`));
116
- }
117
- logger_1.default.newline();
118
- return false;
119
- }
120
- }
121
- /**
122
- * Parse quota input with validation
123
- * Supports formats: "10GB", "500MB", "1TB", preset selection
124
- */
125
- async function promptQuotaInput() {
126
- // First, offer preset options
127
- const presetChoices = quota_1.PRESET_QUOTAS.map((p) => ({
128
- name: p.label,
129
- value: p.bytes,
130
- }));
131
- presetChoices.push({
132
- name: '自定义输入',
133
- value: -2, // Special value for custom input
134
- });
135
- const selected = await (0, prompts_1.select)({
136
- message: '选择流量配额:',
137
- choices: presetChoices,
138
- });
139
- if (selected === -2) {
140
- // Custom input
141
- const customInput = await (0, prompts_1.input)({
142
- message: '请输入配额 (例如: 10GB, 500MB, 1TB):',
143
- validate: (value) => {
144
- const bytes = (0, traffic_formatter_1.parseTraffic)(value);
145
- if (bytes === -1 &&
146
- value.toLowerCase() !== '无限制' &&
147
- value.toLowerCase() !== 'unlimited') {
148
- return '无效的配额格式,请使用如 10GB, 500MB, 1TB 的格式';
149
- }
150
- return true;
151
- },
152
- });
153
- return (0, traffic_formatter_1.parseTraffic)(customInput);
154
- }
155
- return selected;
156
- }
157
- /**
158
- * Set quota for a user
159
- */
160
- async function setQuota(options = {}) {
161
- try {
162
- const userManager = new user_manager_1.UserManager(options.configPath, options.serviceName);
163
- const quotaManager = new quota_manager_1.QuotaManager();
164
- // List users first
165
- const users = await userManager.listUsers();
166
- if (users.length === 0) {
167
- logger_1.default.warn('暂无用户,请先添加用户');
168
- return;
169
- }
170
- // Select user
171
- const userChoices = users.map((u) => ({
172
- name: `${u.email} (${u.id.substring(0, 8)}...)`,
173
- value: u.email,
174
- }));
175
- const selectedEmail = await (0, prompts_1.select)({
176
- message: '选择要设置配额的用户:',
177
- choices: userChoices,
178
- });
179
- // Get current quota
180
- const currentQuota = await quotaManager.getQuota(selectedEmail);
181
- const currentDisplay = currentQuota.quotaBytes < 0 ? '无限制' : (0, traffic_formatter_1.formatTraffic)(currentQuota.quotaBytes).display;
182
- logger_1.default.newline();
183
- console.log(chalk_1.default.gray(`当前配额: ${currentDisplay}`));
184
- logger_1.default.newline();
185
- // Prompt for new quota
186
- const quotaBytes = await promptQuotaInput();
187
- const spinner = (0, ora_1.default)('正在设置配额...').start();
188
- await quotaManager.setQuota({
189
- email: selectedEmail,
190
- quotaBytes,
191
- quotaType: quotaBytes < 0 ? 'unlimited' : 'limited',
192
- });
193
- spinner.succeed(chalk_1.default.green('配额设置成功!'));
194
- const newDisplay = quotaBytes < 0 ? '无限制' : (0, traffic_formatter_1.formatTraffic)(quotaBytes).display;
195
- logger_1.default.newline();
196
- console.log(chalk_1.default.cyan(' 用户: ') + chalk_1.default.white(selectedEmail));
197
- console.log(chalk_1.default.cyan(' 新配额: ') + chalk_1.default.white(newDisplay));
198
- logger_1.default.newline();
199
- }
200
- catch (error) {
201
- logger_1.default.error(error.message);
202
- process.exit(1);
203
- }
204
- }
205
- /**
206
- * Show quota details for a user
207
- */
208
- async function showQuota(options = {}) {
209
- try {
210
- const userManager = new user_manager_1.UserManager(options.configPath, options.serviceName);
211
- const quotaManager = new quota_manager_1.QuotaManager();
212
- const trafficManager = new traffic_manager_1.TrafficManager();
213
- // List users first
214
- const users = await userManager.listUsers();
215
- if (users.length === 0) {
216
- logger_1.default.warn('暂无用户');
217
- return;
218
- }
219
- // Select user
220
- const userChoices = users.map((u) => ({
221
- name: `${u.email} (${u.id.substring(0, 8)}...)`,
222
- value: u.email,
223
- }));
224
- const selectedEmail = await (0, prompts_1.select)({
225
- message: '选择要查看的用户:',
226
- choices: userChoices,
227
- });
228
- const spinner = (0, ora_1.default)('正在获取配额信息...').start();
229
- // Get quota and usage
230
- const quota = await quotaManager.getQuota(selectedEmail);
231
- let usage = await trafficManager.getUsage(selectedEmail);
232
- spinner.stop();
233
- const terminalSize = layout_manager_1.default.detectTerminalSize();
234
- const headerTitle = `${ui_symbols_1.menuIcons.STATS} 用户配额详情`;
235
- const headerText = (0, layout_1.renderHeader)(headerTitle, terminalSize.width, 'left');
236
- logger_1.default.newline();
237
- logger_1.default.separator();
238
- console.log(chalk_1.default.bold.cyan(headerText));
239
- logger_1.default.separator();
240
- logger_1.default.newline();
241
- // User info
242
- console.log(chalk_1.default.cyan(' 用户: ') + chalk_1.default.white(selectedEmail));
243
- console.log(chalk_1.default.cyan(' 状态: ') +
244
- (quota.status === 'active' ? chalk_1.default.green('活跃') : chalk_1.default.red('已禁用')));
245
- logger_1.default.newline();
246
- // Quota info
247
- const quotaDisplay = quota.quotaBytes < 0 ? '无限制' : (0, traffic_formatter_1.formatTraffic)(quota.quotaBytes).display;
248
- console.log(chalk_1.default.cyan(' 配额: ') + chalk_1.default.white(quotaDisplay));
249
- // Usage info
250
- if (usage) {
251
- const usedDisplay = (0, traffic_formatter_1.formatTraffic)(usage.total).display;
252
- const percent = (0, traffic_formatter_1.calculateUsagePercent)(usage.total, quota.quotaBytes);
253
- const alertLevel = (0, traffic_formatter_1.getAlertLevel)(percent);
254
- const colorFn = getAlertColor(alertLevel);
255
- console.log(chalk_1.default.cyan(' 已用: ') + colorFn(usedDisplay));
256
- console.log(chalk_1.default.cyan(' 使用率: ') + colorFn(`${percent}%`));
257
- if (quota.quotaBytes > 0) {
258
- const remaining = Math.max(0, quota.quotaBytes - usage.total);
259
- console.log(chalk_1.default.cyan(' 剩余: ') + chalk_1.default.white((0, traffic_formatter_1.formatTraffic)(remaining).display));
260
- }
261
- logger_1.default.newline();
262
- console.log(chalk_1.default.gray(` 上行: ${(0, traffic_formatter_1.formatTraffic)(usage.uplink).display}`));
263
- console.log(chalk_1.default.gray(` 下行: ${(0, traffic_formatter_1.formatTraffic)(usage.downlink).display}`));
264
- }
265
- else {
266
- // Stats API not available - prompt for setup
267
- const configured = await promptStatsApiSetup(options);
268
- if (configured) {
269
- // Retry getting usage after configuration
270
- usage = await trafficManager.getUsage(selectedEmail);
271
- if (usage) {
272
- const usedDisplay = (0, traffic_formatter_1.formatTraffic)(usage.total).display;
273
- const percent = (0, traffic_formatter_1.calculateUsagePercent)(usage.total, quota.quotaBytes);
274
- const alertLevel = (0, traffic_formatter_1.getAlertLevel)(percent);
275
- const colorFn = getAlertColor(alertLevel);
276
- console.log(chalk_1.default.cyan(' 已用: ') + colorFn(usedDisplay));
277
- console.log(chalk_1.default.cyan(' 使用率: ') + colorFn(`${percent}%`));
278
- if (quota.quotaBytes > 0) {
279
- const remaining = Math.max(0, quota.quotaBytes - usage.total);
280
- console.log(chalk_1.default.cyan(' 剩余: ') + chalk_1.default.white((0, traffic_formatter_1.formatTraffic)(remaining).display));
281
- }
282
- logger_1.default.newline();
283
- console.log(chalk_1.default.gray(` 上行: ${(0, traffic_formatter_1.formatTraffic)(usage.uplink).display}`));
284
- console.log(chalk_1.default.gray(` 下行: ${(0, traffic_formatter_1.formatTraffic)(usage.downlink).display}`));
285
- }
286
- }
287
- }
288
- logger_1.default.newline();
289
- console.log(chalk_1.default.gray(` 上次重置: ${quota.lastReset}`));
290
- logger_1.default.newline();
291
- if (options.json) {
292
- console.log(JSON.stringify({ quota, usage }, null, 2));
293
- }
294
- }
295
- catch (error) {
296
- logger_1.default.error(error.message);
297
- process.exit(1);
298
- }
299
- }
300
- /**
301
- * Reset usage for a user
302
- */
303
- async function resetQuota(options = {}) {
304
- try {
305
- const userManager = new user_manager_1.UserManager(options.configPath, options.serviceName);
306
- const quotaManager = new quota_manager_1.QuotaManager();
307
- // List users first
308
- const users = await userManager.listUsers();
309
- if (users.length === 0) {
310
- logger_1.default.warn('暂无用户');
311
- return;
312
- }
313
- // Select user
314
- const userChoices = users.map((u) => ({
315
- name: `${u.email} (${u.id.substring(0, 8)}...)`,
316
- value: u.email,
317
- }));
318
- const selectedEmail = await (0, prompts_1.select)({
319
- message: '选择要重置流量的用户:',
320
- choices: userChoices,
321
- });
322
- // Confirm
323
- const confirmed = await (0, prompts_1.confirm)({
324
- message: `确定要重置 ${selectedEmail} 的已用流量吗?`,
325
- default: false,
326
- });
327
- if (!confirmed) {
328
- logger_1.default.info('操作已取消');
329
- return;
330
- }
331
- const spinner = (0, ora_1.default)('正在重置流量...').start();
332
- await quotaManager.resetUsage(selectedEmail);
333
- spinner.succeed(chalk_1.default.green('流量重置成功!'));
334
- logger_1.default.newline();
335
- }
336
- catch (error) {
337
- logger_1.default.error(error.message);
338
- process.exit(1);
339
- }
340
- }
341
- /**
342
- * List all users with quota info
343
- */
344
- async function listQuotas(options = {}) {
345
- try {
346
- const userManager = new user_manager_1.UserManager(options.configPath, options.serviceName);
347
- const quotaManager = new quota_manager_1.QuotaManager();
348
- const trafficManager = new traffic_manager_1.TrafficManager();
349
- let statsAvailable = await trafficManager.isUsageAvailable();
350
- const shouldPromptStats = !options.json && !process.env.VITEST && process.env.NODE_ENV !== 'test';
351
- if (!statsAvailable && shouldPromptStats) {
352
- const configured = await promptStatsApiSetup(options);
353
- if (configured) {
354
- statsAvailable = await trafficManager.isUsageAvailable();
355
- }
356
- }
357
- const spinner = (0, ora_1.default)('正在获取配额信息...').start();
358
- const users = await userManager.listUsers();
359
- const quotas = await quotaManager.getAllQuotas();
360
- const usages = statsAvailable ? await trafficManager.getAllUsage() : [];
361
- spinner.stop();
362
- const terminalSize = layout_manager_1.default.detectTerminalSize();
363
- const headerTitle = `${ui_symbols_1.menuIcons.STATS} 用户配额列表 (共 ${users.length} 个用户)`;
364
- const headerText = (0, layout_1.renderHeader)(headerTitle, terminalSize.width, 'left');
365
- logger_1.default.newline();
366
- logger_1.default.separator();
367
- console.log(chalk_1.default.bold.cyan(headerText));
368
- logger_1.default.separator();
369
- logger_1.default.newline();
370
- if (users.length === 0) {
371
- console.log(chalk_1.default.gray(' 暂无用户'));
372
- logger_1.default.newline();
373
- return;
374
- }
375
- if (!statsAvailable) {
376
- console.log(chalk_1.default.yellow(' 流量统计未启用,无法显示实际使用量。'));
377
- console.log(chalk_1.default.gray(' 提示: 配额管理 → 配置 Stats API'));
378
- logger_1.default.newline();
379
- }
380
- // Build user list with quota info
381
- const usersWithQuota = [];
382
- for (const user of users) {
383
- const quota = quotas[user.email] || {
384
- quotaBytes: -1,
385
- quotaType: 'unlimited',
386
- usedBytes: 0,
387
- lastReset: '',
388
- status: 'active',
389
- };
390
- const usage = statsAvailable ? usages.find((u) => u.email === user.email) : undefined;
391
- const usedBytes = statsAvailable ? usage?.total || 0 : 0;
392
- const percent = statsAvailable ? (0, traffic_formatter_1.calculateUsagePercent)(usedBytes, quota.quotaBytes) : 0;
393
- const alertLevel = statsAvailable ? (0, traffic_formatter_1.getAlertLevel)(percent) : 'normal';
394
- usersWithQuota.push({
395
- ...user,
396
- quota,
397
- usage,
398
- usagePercent: percent,
399
- alertLevel,
400
- quotaDisplay: quota.quotaBytes < 0 ? '无限制' : (0, traffic_formatter_1.formatTraffic)(quota.quotaBytes).display,
401
- usageDisplay: statsAvailable
402
- ? (0, traffic_formatter_1.formatUsageSummary)(usedBytes, quota.quotaBytes)
403
- : '统计未启用',
404
- });
405
- }
406
- // Display table
407
- for (const user of usersWithQuota) {
408
- const colorFn = statsAvailable ? getAlertColor(user.alertLevel) : chalk_1.default.gray;
409
- const statusIcon = statsAvailable
410
- ? user.alertLevel === 'exceeded'
411
- ? '🔴'
412
- : user.alertLevel === 'warning'
413
- ? '🟡'
414
- : '🟢'
415
- : '⚪';
416
- console.log(` ${statusIcon} ${chalk_1.default.white(user.email)}`);
417
- console.log(` 配额: ${chalk_1.default.cyan(user.quotaDisplay)}`);
418
- console.log(` 使用: ${colorFn(user.usageDisplay)}`);
419
- logger_1.default.newline();
420
- }
421
- if (options.json) {
422
- console.log(JSON.stringify(usersWithQuota, null, 2));
423
- }
424
- }
425
- catch (error) {
426
- logger_1.default.error(error.message);
427
- process.exit(1);
428
- }
429
- }
430
- /**
431
- * Re-enable a disabled user
432
- */
433
- async function reenableUser(_options = {}) {
434
- try {
435
- const quotaManager = new quota_manager_1.QuotaManager();
436
- // Get all quotas and filter disabled users
437
- const quotas = await quotaManager.getAllQuotas();
438
- const disabledUsers = Object.entries(quotas)
439
- .filter(([, q]) => q.status === 'disabled' || q.status === 'exceeded')
440
- .map(([email]) => email);
441
- if (disabledUsers.length === 0) {
442
- logger_1.default.info('没有被禁用的用户');
443
- return;
444
- }
445
- // Select user
446
- const userChoices = disabledUsers.map((email) => ({
447
- name: email,
448
- value: email,
449
- }));
450
- const selectedEmail = await (0, prompts_1.select)({
451
- message: '选择要重新启用的用户:',
452
- choices: userChoices,
453
- });
454
- // Confirm
455
- const confirmed = await (0, prompts_1.confirm)({
456
- message: `确定要重新启用 ${selectedEmail} 吗?`,
457
- default: true,
458
- });
459
- if (!confirmed) {
460
- logger_1.default.info('操作已取消');
461
- return;
462
- }
463
- const spinner = (0, ora_1.default)('正在重新启用用户...').start();
464
- await quotaManager.setStatus(selectedEmail, 'active');
465
- spinner.succeed(chalk_1.default.green('用户已重新启用!'));
466
- logger_1.default.newline();
467
- }
468
- catch (error) {
469
- logger_1.default.error(error.message);
470
- process.exit(1);
471
- }
472
- }
473
- /**
474
- * Configure Stats API manually
475
- */
476
- async function configureStatsApi(options = {}) {
477
- try {
478
- const statsManager = new stats_config_manager_1.StatsConfigManager(options.configPath, options.serviceName);
479
- const detection = await statsManager.detectStatsConfig();
480
- const terminalSize = layout_manager_1.default.detectTerminalSize();
481
- const headerTitle = `${ui_symbols_1.menuIcons.CONFIG} Stats API 配置`;
482
- const headerText = (0, layout_1.renderHeader)(headerTitle, terminalSize.width, 'left');
483
- logger_1.default.newline();
484
- logger_1.default.separator();
485
- console.log(chalk_1.default.bold.cyan(headerText));
486
- logger_1.default.separator();
487
- logger_1.default.newline();
488
- // Show current status
489
- console.log(chalk_1.default.cyan(' 当前状态: ') +
490
- (detection.available ? chalk_1.default.green('已配置且可用') : chalk_1.default.yellow('未配置或不可用')));
491
- if (detection.available && detection.detectedPort) {
492
- console.log(chalk_1.default.cyan(' API 端口: ') + chalk_1.default.white(detection.detectedPort));
493
- console.log(chalk_1.default.cyan(' 服务状态: ') +
494
- (detection.serviceRunning ? chalk_1.default.green('运行中') : chalk_1.default.red('已停止')));
495
- logger_1.default.newline();
496
- try {
497
- const quotaManager = new quota_manager_1.QuotaManager();
498
- await quotaManager.setApiPort(detection.detectedPort);
499
- }
500
- catch (error) {
501
- logger_1.default.warn(`保存 API 端口失败: ${error.message}`);
502
- }
503
- logger_1.default.info('Stats API 已配置,无需重新配置');
504
- return;
505
- }
506
- // Show missing components
507
- if (detection.missingComponents.length > 0) {
508
- const componentNames = {
509
- stats: 'stats 配置块',
510
- policy: 'policy 配置',
511
- api: 'API 配置',
512
- 'api-inbound': 'API 入站配置',
513
- 'api-outbound': 'API 出站配置',
514
- 'api-routing': 'API 路由规则',
515
- };
516
- const missingNames = detection.missingComponents
517
- .map((c) => componentNames[c] || c)
518
- .join('、');
519
- console.log(chalk_1.default.cyan(' 缺失组件: ') + chalk_1.default.yellow(missingNames));
520
- }
521
- logger_1.default.newline();
522
- // Show benefits
523
- console.log(chalk_1.default.gray(' 配置 Stats API 后,您可以:'));
524
- console.log(chalk_1.default.gray(' • 查看用户实时流量使用情况'));
525
- console.log(chalk_1.default.gray(' • 设置流量配额并自动限制'));
526
- console.log(chalk_1.default.gray(' • 查看流量统计报表'));
527
- logger_1.default.newline();
528
- // Confirm configuration
529
- const shouldConfigure = await (0, prompts_1.confirm)({
530
- message: '是否立即配置 Stats API?',
531
- default: true,
532
- });
533
- if (!shouldConfigure) {
534
- logger_1.default.info('操作已取消');
535
- return;
536
- }
537
- // Execute configuration
538
- const spinner = (0, ora_1.default)('正在配置 Stats API...').start();
539
- spinner.text = '正在备份配置...';
540
- const result = await statsManager.enableStatsApi();
541
- if (result.success) {
542
- spinner.succeed(chalk_1.default.green(result.message));
543
- logger_1.default.newline();
544
- console.log(chalk_1.default.cyan(' API 端口: ') + chalk_1.default.white(result.apiPort));
545
- if (result.backupPath) {
546
- console.log(chalk_1.default.cyan(' 备份文件: ') + chalk_1.default.gray(result.backupPath));
547
- }
548
- logger_1.default.newline();
549
- try {
550
- const quotaManager = new quota_manager_1.QuotaManager();
551
- await quotaManager.setApiPort(result.apiPort);
552
- }
553
- catch (error) {
554
- logger_1.default.warn(`保存 API 端口失败: ${error.message}`);
555
- }
556
- }
557
- else {
558
- spinner.fail(chalk_1.default.red(result.message));
559
- if (result.error) {
560
- console.log(chalk_1.default.red(` 错误: ${result.error}`));
561
- }
562
- if (result.rolledBack) {
563
- console.log(chalk_1.default.yellow(' 已自动恢复原配置'));
564
- }
565
- if (result.backupPath) {
566
- console.log(chalk_1.default.gray(` 备份文件: ${result.backupPath}`));
567
- }
568
- logger_1.default.newline();
569
- }
570
- }
571
- catch (error) {
572
- logger_1.default.error(error.message);
573
- process.exit(1);
574
- }
575
- }
576
- /**
577
- * Execute quota check and enforce limits
578
- *
579
- * @param options - Command options
580
- */
581
- async function executeQuotaCheck(options = {}) {
582
- const translations = (0, i18n_1.t)();
583
- try {
584
- const terminalSize = layout_manager_1.default.detectTerminalSize();
585
- const headerTitle = `${ui_symbols_1.menuIcons.QUOTA} ${translations.quota.executeCheck}`;
586
- const headerText = (0, layout_1.renderHeader)(headerTitle, terminalSize.width, 'left');
587
- logger_1.default.newline();
588
- logger_1.default.separator();
589
- console.log(chalk_1.default.bold.cyan(headerText));
590
- logger_1.default.separator();
591
- logger_1.default.newline();
592
- // Check if Stats API is available
593
- const statsAvailable = await promptStatsApiSetup(options);
594
- if (!statsAvailable) {
595
- logger_1.default.warn('Stats API 不可用,无法执行配额检查');
596
- return;
597
- }
598
- // Execute quota enforcement
599
- const spinner = (0, ora_1.default)('正在检查用户配额...').start();
600
- const enforcer = new quota_enforcer_1.QuotaEnforcer(options.configPath, options.serviceName);
601
- const summary = await enforcer.enforceQuotas(true); // Auto-disable exceeded users
602
- spinner.succeed(chalk_1.default.green(translations.quota.checkComplete));
603
- logger_1.default.newline();
604
- // Display summary
605
- console.log(chalk_1.default.cyan(' 检查结果:'));
606
- logger_1.default.newline();
607
- // Normal users
608
- console.log(chalk_1.default.green(` ✓ ${translations.quota.normalUsers}: ${summary.normalCount}`));
609
- // Warning users
610
- if (summary.warningCount > 0) {
611
- console.log(chalk_1.default.yellow(` ⚠ ${translations.quota.warningUsers}: ${summary.warningCount}`));
612
- }
613
- // Exceeded users
614
- if (summary.exceededCount > 0) {
615
- console.log(chalk_1.default.red(` ✗ ${translations.quota.exceededUsers}: ${summary.exceededCount} (${translations.quota.disabledUsers})`));
616
- }
617
- // Newly disabled
618
- if (summary.newlyDisabledCount > 0) {
619
- console.log(chalk_1.default.red(` ! 新禁用: ${summary.newlyDisabledCount}`));
620
- }
621
- logger_1.default.newline();
622
- // Show details if there are exceeded users
623
- if (summary.exceededCount > 0 && summary.results) {
624
- console.log(chalk_1.default.cyan(' 超限用户详情:'));
625
- for (const detail of summary.results) {
626
- if (detail.alertLevel === 'exceeded') {
627
- const usedFormatted = (0, traffic_formatter_1.formatTraffic)(detail.usedBytes);
628
- const quotaFormatted = (0, traffic_formatter_1.formatTraffic)(detail.quotaBytes);
629
- console.log(chalk_1.default.red(` • ${detail.email}: ${usedFormatted} / ${quotaFormatted}`));
630
- }
631
- }
632
- logger_1.default.newline();
633
- }
634
- // Update user metadata status
635
- const userManager = new user_manager_1.UserManager(options.configPath, options.serviceName);
636
- const metadataManager = userManager.getMetadataManager();
637
- if (summary.results) {
638
- for (const detail of summary.results) {
639
- if (detail.alertLevel === 'exceeded') {
640
- try {
641
- // Find user by email to get UUID
642
- const users = await userManager.listUsers();
643
- const user = users.find((u) => u.email === detail.email);
644
- if (user) {
645
- await metadataManager.updateStatus(user.id, 'exceeded');
646
- }
647
- }
648
- catch {
649
- // Ignore metadata update errors
650
- }
651
- }
652
- }
653
- }
654
- logger_1.default.info('配额检查完成');
655
- }
656
- catch (error) {
657
- logger_1.default.error(error.message);
658
- process.exit(1);
659
- }
660
- }
661
- //# sourceMappingURL=quota.js.map