@jayfong/x-server 2.119.0 → 3.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 (290) hide show
  1. package/lib/_virtual/_rolldown/runtime.mjs +4 -0
  2. package/lib/cli/api_generator.d.mts +74 -0
  3. package/lib/cli/api_generator.mjs +310 -0
  4. package/lib/cli/build_util.d.mts +17 -0
  5. package/lib/cli/build_util.mjs +156 -0
  6. package/lib/cli/cli.d.mts +1 -0
  7. package/lib/cli/cli.mjs +355 -0
  8. package/lib/cli/css_register.d.mts +1 -0
  9. package/lib/cli/css_register.mjs +7 -0
  10. package/lib/cli/deploy_util.d.mts +23 -0
  11. package/lib/cli/deploy_util.mjs +70 -0
  12. package/lib/cli/dev_util.d.mts +7 -0
  13. package/lib/cli/dev_util.mjs +25 -0
  14. package/lib/cli/env_util.d.mts +45 -0
  15. package/lib/cli/env_util.mjs +207 -0
  16. package/lib/cli/esbuild_register.d.mts +1 -0
  17. package/lib/cli/esbuild_register.mjs +7 -0
  18. package/lib/cli/template_util.d.mts +18 -0
  19. package/lib/cli/template_util.mjs +85 -0
  20. package/lib/cli/templates/crons.ts +1 -1
  21. package/lib/cli/templates/handlers.ts +1 -1
  22. package/lib/cli/templates/hooks.ts +1 -1
  23. package/lib/cli/templates/models.ts +7 -7
  24. package/lib/cli/templates/package.json +11 -1
  25. package/lib/cli/templates/routes.ts +2 -1
  26. package/lib/core/ctx_storage.d.mts +3 -0
  27. package/lib/core/ctx_storage.mjs +4 -0
  28. package/lib/core/define_bus.d.mts +37 -0
  29. package/lib/core/define_bus.mjs +12 -0
  30. package/lib/core/{define_cron.d.ts → define_cron.d.mts} +2 -2
  31. package/lib/core/define_cron.mjs +11 -0
  32. package/lib/core/{define_handler.d.ts → define_handler.d.mts} +19 -19
  33. package/lib/core/define_handler.mjs +44 -0
  34. package/lib/core/define_hook.d.mts +2 -0
  35. package/lib/core/define_hook.mjs +6 -0
  36. package/lib/core/define_server.d.mts +3 -0
  37. package/lib/core/define_server.mjs +8 -0
  38. package/lib/core/{define_task.d.ts → define_task.d.mts} +2 -2
  39. package/lib/core/define_task.mjs +102 -0
  40. package/lib/core/get_handler_url.d.mts +2 -0
  41. package/lib/core/get_handler_url.mjs +7 -0
  42. package/lib/core/handler.d.mts +16 -0
  43. package/lib/core/handler.mjs +132 -0
  44. package/lib/core/http_error.d.mts +2 -0
  45. package/lib/core/http_error.mjs +1 -0
  46. package/lib/core/http_header.d.mts +856 -0
  47. package/lib/core/http_header.mjs +860 -0
  48. package/lib/core/http_method.d.mts +3 -0
  49. package/lib/core/http_method.mjs +10 -0
  50. package/lib/core/http_redirect.d.mts +5 -0
  51. package/lib/core/http_redirect.mjs +10 -0
  52. package/lib/core/server.d.mts +20 -0
  53. package/lib/core/server.mjs +186 -0
  54. package/lib/core/types.d.mts +256 -0
  55. package/lib/exports.d.mts +46 -0
  56. package/lib/exports.mjs +46 -0
  57. package/lib/index.d.mts +48 -0
  58. package/lib/index.mjs +45 -0
  59. package/lib/plugins/base.d.mts +4 -0
  60. package/lib/plugins/compress.d.mts +12 -0
  61. package/lib/plugins/compress.mjs +15 -0
  62. package/lib/plugins/cookie.d.mts +12 -0
  63. package/lib/plugins/cookie.mjs +15 -0
  64. package/lib/plugins/cors.d.mts +22 -0
  65. package/lib/plugins/cors.mjs +34 -0
  66. package/lib/plugins/file_parser.d.mts +15 -0
  67. package/lib/plugins/file_parser.mjs +24 -0
  68. package/lib/plugins/form_body_parser.d.mts +12 -0
  69. package/lib/plugins/form_body_parser.mjs +15 -0
  70. package/lib/plugins/ws_parser.d.mts +12 -0
  71. package/lib/plugins/ws_parser.mjs +15 -0
  72. package/lib/plugins/xml_parser.d.mts +19 -0
  73. package/lib/plugins/xml_parser.mjs +40 -0
  74. package/lib/services/ai.d.mts +31 -0
  75. package/lib/services/ai.mjs +44 -0
  76. package/lib/services/base.d.mts +4 -0
  77. package/lib/services/base.mjs +1 -0
  78. package/lib/services/cache.d.mts +165 -0
  79. package/lib/services/cache.mjs +323 -0
  80. package/lib/services/captcha.d.mts +65 -0
  81. package/lib/services/captcha.mjs +61 -0
  82. package/lib/services/{crypto.js → crypto.d.mts} +19 -78
  83. package/lib/services/crypto.mjs +141 -0
  84. package/lib/services/db_value.d.mts +60 -0
  85. package/lib/services/db_value.mjs +64 -0
  86. package/lib/services/dingtalk.d.mts +39 -0
  87. package/lib/services/dingtalk.mjs +44 -0
  88. package/lib/services/dispose.d.mts +17 -0
  89. package/lib/services/dispose.mjs +18 -0
  90. package/lib/services/emoji.d.mts +10 -0
  91. package/lib/services/emoji.mjs +2025 -0
  92. package/lib/services/file_store.d.mts +49 -0
  93. package/lib/services/file_store.mjs +58 -0
  94. package/lib/services/html.d.mts +11 -0
  95. package/lib/services/html.mjs +12 -0
  96. package/lib/services/jwt.d.mts +33 -0
  97. package/lib/services/jwt.mjs +42 -0
  98. package/lib/services/log.d.mts +37 -0
  99. package/lib/services/log.mjs +99 -0
  100. package/lib/services/mail.d.mts +22 -0
  101. package/lib/services/mail.mjs +28 -0
  102. package/lib/services/pay.d.mts +123 -0
  103. package/lib/services/pay.mjs +157 -0
  104. package/lib/services/random.d.mts +27 -0
  105. package/lib/services/random.mjs +42 -0
  106. package/lib/services/rate_limit.d.mts +37 -0
  107. package/lib/services/rate_limit.mjs +40 -0
  108. package/lib/services/redis.d.mts +11 -0
  109. package/lib/services/redis.mjs +6 -0
  110. package/lib/services/sensitive_words.d.mts +29 -0
  111. package/lib/services/sensitive_words.mjs +37 -0
  112. package/lib/services/sms.d.mts +40 -0
  113. package/lib/services/sms.mjs +30238 -0
  114. package/lib/types/dto.d.mts +30 -0
  115. package/lib/types/dto.mjs +1 -0
  116. package/lib/x.d.mts +11 -0
  117. package/lib/x.mjs +21 -0
  118. package/lib/x_init.d.mts +1 -0
  119. package/lib/x_init.mjs +10 -0
  120. package/package.json +71 -16
  121. package/lib/_cjs/cli/api_generator.js +0 -458
  122. package/lib/_cjs/cli/build_util.js +0 -243
  123. package/lib/_cjs/cli/cli.js +0 -378
  124. package/lib/_cjs/cli/css_register.js +0 -7
  125. package/lib/_cjs/cli/deploy_util.js +0 -76
  126. package/lib/_cjs/cli/dev_util.js +0 -26
  127. package/lib/_cjs/cli/env_util.js +0 -252
  128. package/lib/_cjs/cli/esbuild_register.js +0 -7
  129. package/lib/_cjs/cli/template_util.js +0 -101
  130. package/lib/_cjs/cli/templates/crons.ts +0 -2
  131. package/lib/_cjs/cli/templates/handlers.ts +0 -3
  132. package/lib/_cjs/cli/templates/hooks.ts +0 -2
  133. package/lib/_cjs/cli/templates/models.ts +0 -123
  134. package/lib/_cjs/cli/templates/package.json +0 -3
  135. package/lib/_cjs/cli/templates/routes.ts +0 -68
  136. package/lib/_cjs/core/ctx_storage.js +0 -6
  137. package/lib/_cjs/core/define_bus.js +0 -31
  138. package/lib/_cjs/core/define_cron.js +0 -13
  139. package/lib/_cjs/core/define_handler.js +0 -56
  140. package/lib/_cjs/core/define_hook.js +0 -8
  141. package/lib/_cjs/core/define_server.js +0 -10
  142. package/lib/_cjs/core/define_task.js +0 -113
  143. package/lib/_cjs/core/get_handler_url.js +0 -11
  144. package/lib/_cjs/core/handler.js +0 -216
  145. package/lib/_cjs/core/http_error.js +0 -6
  146. package/lib/_cjs/core/http_header.js +0 -142
  147. package/lib/_cjs/core/http_method.js +0 -12
  148. package/lib/_cjs/core/http_redirect.js +0 -11
  149. package/lib/_cjs/core/server.js +0 -219
  150. package/lib/_cjs/core/types.js +0 -8
  151. package/lib/_cjs/exports.js +0 -273
  152. package/lib/_cjs/index.js +0 -15
  153. package/lib/_cjs/plugins/base.js +0 -3
  154. package/lib/_cjs/plugins/compress.js +0 -18
  155. package/lib/_cjs/plugins/cookie.js +0 -18
  156. package/lib/_cjs/plugins/cors.js +0 -38
  157. package/lib/_cjs/plugins/file_parser.js +0 -28
  158. package/lib/_cjs/plugins/form_body_parser.js +0 -18
  159. package/lib/_cjs/plugins/ws_parser.js +0 -18
  160. package/lib/_cjs/plugins/xml_parser.js +0 -48
  161. package/lib/_cjs/services/ai.js +0 -48
  162. package/lib/_cjs/services/base.js +0 -3
  163. package/lib/_cjs/services/cache.js +0 -400
  164. package/lib/_cjs/services/captcha.js +0 -78
  165. package/lib/_cjs/services/crypto.js +0 -175
  166. package/lib/_cjs/services/db_value.js +0 -77
  167. package/lib/_cjs/services/dingtalk.js +0 -51
  168. package/lib/_cjs/services/dispose.js +0 -23
  169. package/lib/_cjs/services/emoji.js +0 -2034
  170. package/lib/_cjs/services/file_store.js +0 -67
  171. package/lib/_cjs/services/html.js +0 -17
  172. package/lib/_cjs/services/jwt.js +0 -65
  173. package/lib/_cjs/services/log.js +0 -108
  174. package/lib/_cjs/services/mail.js +0 -31
  175. package/lib/_cjs/services/pay.js +0 -191
  176. package/lib/_cjs/services/random.js +0 -51
  177. package/lib/_cjs/services/rate_limit.js +0 -54
  178. package/lib/_cjs/services/redis.js +0 -12
  179. package/lib/_cjs/services/sensitive_words.js +0 -61
  180. package/lib/_cjs/services/sms.js +0 -84
  181. package/lib/_cjs/types/dto.js +0 -3
  182. package/lib/_cjs/x.js +0 -35
  183. package/lib/cli/api_generator.d.ts +0 -74
  184. package/lib/cli/api_generator.js +0 -452
  185. package/lib/cli/build_util.d.ts +0 -17
  186. package/lib/cli/build_util.js +0 -236
  187. package/lib/cli/cli.d.ts +0 -2
  188. package/lib/cli/cli.js +0 -374
  189. package/lib/cli/css_register.js +0 -5
  190. package/lib/cli/deploy_util.d.ts +0 -23
  191. package/lib/cli/deploy_util.js +0 -70
  192. package/lib/cli/dev_util.d.ts +0 -8
  193. package/lib/cli/dev_util.js +0 -20
  194. package/lib/cli/env_util.d.ts +0 -45
  195. package/lib/cli/env_util.js +0 -246
  196. package/lib/cli/esbuild_register.js +0 -5
  197. package/lib/cli/template_util.d.ts +0 -18
  198. package/lib/cli/template_util.js +0 -95
  199. package/lib/core/ctx_storage.d.ts +0 -3
  200. package/lib/core/ctx_storage.js +0 -2
  201. package/lib/core/define_bus.d.ts +0 -37
  202. package/lib/core/define_bus.js +0 -27
  203. package/lib/core/define_cron.js +0 -9
  204. package/lib/core/define_handler.js +0 -48
  205. package/lib/core/define_hook.d.ts +0 -2
  206. package/lib/core/define_hook.js +0 -4
  207. package/lib/core/define_server.d.ts +0 -3
  208. package/lib/core/define_server.js +0 -6
  209. package/lib/core/define_task.js +0 -107
  210. package/lib/core/get_handler_url.d.ts +0 -2
  211. package/lib/core/get_handler_url.js +0 -7
  212. package/lib/core/handler.d.ts +0 -16
  213. package/lib/core/handler.js +0 -209
  214. package/lib/core/http_error.d.ts +0 -2
  215. package/lib/core/http_error.js +0 -2
  216. package/lib/core/http_header.d.ts +0 -856
  217. package/lib/core/http_header.js +0 -139
  218. package/lib/core/http_method.d.ts +0 -3
  219. package/lib/core/http_method.js +0 -8
  220. package/lib/core/http_redirect.d.ts +0 -5
  221. package/lib/core/http_redirect.js +0 -6
  222. package/lib/core/server.d.ts +0 -20
  223. package/lib/core/server.js +0 -213
  224. package/lib/core/types.d.ts +0 -265
  225. package/lib/core/types.js +0 -4
  226. package/lib/exports.d.ts +0 -45
  227. package/lib/exports.js +0 -47
  228. package/lib/index.d.ts +0 -2
  229. package/lib/index.js +0 -3
  230. package/lib/plugins/base.d.ts +0 -4
  231. package/lib/plugins/base.js +0 -1
  232. package/lib/plugins/compress.d.ts +0 -13
  233. package/lib/plugins/compress.js +0 -12
  234. package/lib/plugins/cookie.d.ts +0 -13
  235. package/lib/plugins/cookie.js +0 -12
  236. package/lib/plugins/cors.d.ts +0 -22
  237. package/lib/plugins/cors.js +0 -32
  238. package/lib/plugins/file_parser.d.ts +0 -16
  239. package/lib/plugins/file_parser.js +0 -22
  240. package/lib/plugins/form_body_parser.d.ts +0 -13
  241. package/lib/plugins/form_body_parser.js +0 -12
  242. package/lib/plugins/ws_parser.d.ts +0 -13
  243. package/lib/plugins/ws_parser.js +0 -12
  244. package/lib/plugins/xml_parser.d.ts +0 -19
  245. package/lib/plugins/xml_parser.js +0 -43
  246. package/lib/services/ai.d.ts +0 -31
  247. package/lib/services/ai.js +0 -43
  248. package/lib/services/base.d.ts +0 -4
  249. package/lib/services/base.js +0 -1
  250. package/lib/services/cache.d.ts +0 -173
  251. package/lib/services/cache.js +0 -394
  252. package/lib/services/captcha.d.ts +0 -65
  253. package/lib/services/captcha.js +0 -72
  254. package/lib/services/crypto.d.ts +0 -110
  255. package/lib/services/db_value.d.ts +0 -60
  256. package/lib/services/db_value.js +0 -72
  257. package/lib/services/dingtalk.d.ts +0 -39
  258. package/lib/services/dingtalk.js +0 -45
  259. package/lib/services/dispose.d.ts +0 -17
  260. package/lib/services/dispose.js +0 -17
  261. package/lib/services/emoji.d.ts +0 -10
  262. package/lib/services/emoji.js +0 -2029
  263. package/lib/services/file_store.d.ts +0 -49
  264. package/lib/services/file_store.js +0 -61
  265. package/lib/services/html.d.ts +0 -11
  266. package/lib/services/html.js +0 -12
  267. package/lib/services/jwt.d.ts +0 -34
  268. package/lib/services/jwt.js +0 -59
  269. package/lib/services/log.d.ts +0 -37
  270. package/lib/services/log.js +0 -102
  271. package/lib/services/mail.d.ts +0 -23
  272. package/lib/services/mail.js +0 -25
  273. package/lib/services/pay.d.ts +0 -123
  274. package/lib/services/pay.js +0 -185
  275. package/lib/services/random.d.ts +0 -27
  276. package/lib/services/random.js +0 -45
  277. package/lib/services/rate_limit.d.ts +0 -37
  278. package/lib/services/rate_limit.js +0 -49
  279. package/lib/services/redis.d.ts +0 -12
  280. package/lib/services/redis.js +0 -7
  281. package/lib/services/sensitive_words.d.ts +0 -29
  282. package/lib/services/sensitive_words.js +0 -56
  283. package/lib/services/sms.d.ts +0 -40
  284. package/lib/services/sms.js +0 -78
  285. package/lib/types/dto.d.ts +0 -86
  286. package/lib/types/dto.js +0 -1
  287. package/lib/x.d.ts +0 -17
  288. package/lib/x.js +0 -30
  289. /package/lib/{cli/css_register.d.ts → core/types.mjs} +0 -0
  290. /package/lib/{cli/esbuild_register.d.ts → plugins/base.mjs} +0 -0
@@ -0,0 +1,4 @@
1
+ import { createRequire } from "node:module";
2
+ // \0rolldown/runtime.js
3
+ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
4
+ export { __require };
@@ -0,0 +1,74 @@
1
+ import { XHandler } from "../core/types.mjs";
2
+ import createDebug from "debug";
3
+ import { ts } from "ts-morph";
4
+ import { JSONSchema4 } from "json-schema";
5
+ import { OpenAPIV3_1 } from "openapi-types";
6
+ import { LiteralUnion } from "vtils/types";
7
+ /** 注释 */
8
+ type Comment = {
9
+ existing: boolean;
10
+ description: string;
11
+ tags: Map<LiteralUnion<'private', string>, string>;
12
+ };
13
+ /** 接口传输数据 */
14
+ type ApiDto = {
15
+ name: string;
16
+ desc: string;
17
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'file';
18
+ enum: any[];
19
+ required: boolean;
20
+ children: ApiDto[];
21
+ };
22
+ /** 接口数据 */
23
+ type ApiData = {
24
+ category: string;
25
+ name: string;
26
+ desc: string;
27
+ path: string[];
28
+ handlerMethod: XHandler.Method;
29
+ method: string;
30
+ requestData: ApiDto;
31
+ responseData: ApiDto;
32
+ requestDataJsonSchema: JSONSchema4;
33
+ responseDataJsonSchema: JSONSchema4;
34
+ };
35
+ export type ApiGeneratorOptions = {
36
+ cwd?: string;
37
+ include?: string[];
38
+ exclude?: string[];
39
+ name?: string;
40
+ };
41
+ export declare class ApiGenerator {
42
+ private options;
43
+ private cwd;
44
+ constructor(options?: ApiGeneratorOptions);
45
+ debug: createDebug.Debugger;
46
+ categoryUrlRe: RegExp;
47
+ checker: ts.TypeChecker;
48
+ start(): Promise<void>;
49
+ getComment(symbol?: ts.Symbol): Comment;
50
+ getApiDto({ type, keySymbol }: {
51
+ type: ts.Type;
52
+ keySymbol?: ts.Symbol;
53
+ }): ApiDto;
54
+ apiDataToJsonSchema(apiData: ApiDto, jsonSchema?: JSONSchema4): JSONSchema4;
55
+ apiDataToYApiData(handles: ApiData[]): {
56
+ name: string;
57
+ desc: string;
58
+ list: any;
59
+ }[];
60
+ apiDataToOpenAPI31Data(handles: ApiData[]): Omit<Omit<import("openapi-types").OpenAPIV3.Document<{}>, "paths" | "components">, "paths" | "components" | "info" | "servers" | "webhooks" | "jsonSchemaDialect"> & {
61
+ info: OpenAPIV3_1.InfoObject;
62
+ jsonSchemaDialect?: string;
63
+ servers?: OpenAPIV3_1.ServerObject[];
64
+ } & Pick<{
65
+ paths: OpenAPIV3_1.PathsObject<{}, {}>;
66
+ webhooks: Record<string, OpenAPIV3_1.PathItemObject | OpenAPIV3_1.ReferenceObject>;
67
+ components: OpenAPIV3_1.ComponentsObject;
68
+ }, "paths"> & Omit<Partial<{
69
+ paths: OpenAPIV3_1.PathsObject<{}, {}>;
70
+ webhooks: Record<string, OpenAPIV3_1.PathItemObject | OpenAPIV3_1.ReferenceObject>;
71
+ components: OpenAPIV3_1.ComponentsObject;
72
+ }>, "paths">;
73
+ }
74
+ export {};
@@ -0,0 +1,310 @@
1
+ import { HandlerMethodToHttpMethod } from "../core/http_method.mjs";
2
+ import { castArray, ii, pascalCase } from "vtils";
3
+ import path from "node:path";
4
+ import fs from "fs-extra";
5
+ import createDebug from "debug";
6
+ import mo, { ts } from "ts-morph";
7
+ // src/cli/api_generator.ts
8
+ var ApiGenerator = class {
9
+ options;
10
+ cwd;
11
+ constructor(options = {}) {
12
+ this.options = options;
13
+ this.cwd = this.options.cwd || process.cwd();
14
+ }
15
+ debug = createDebug("api");
16
+ categoryUrlRe = /^.+\/src\/handlers\/(?:index\.ts|(.*)\/index\.ts|(.*)\.ts)$/;
17
+ checker;
18
+ async start() {
19
+ this.debug("启动项目...");
20
+ const tsConfigPath = path.join(this.cwd, "tsconfig.json");
21
+ const handlersPath = path.join(this.cwd, "node_modules/.x/handlers.ts");
22
+ const entryFile = path.join(this.cwd, "src/generated/handlers.ts");
23
+ const moProject = new mo.Project({ tsConfigFilePath: tsConfigPath });
24
+ moProject.createSourceFile(entryFile, await fs.readFile(handlersPath, "utf-8"));
25
+ const program = moProject.getProgram().compilerObject;
26
+ const checker = program.getTypeChecker();
27
+ this.checker = checker;
28
+ const entrySourceFile = program.getSourceFile(entryFile);
29
+ const moduleSymbol = checker.getSymbolAtLocation(entrySourceFile);
30
+ const categorySymbols = checker.getExportsOfModule(moduleSymbol);
31
+ const apiData = [];
32
+ for (const categorySymbol of categorySymbols) {
33
+ const handlerSymbols = checker.getTypeOfSymbol(categorySymbol).getProperties();
34
+ const categorySourceFilePath = handlerSymbols[0].getDeclarations()[0].getSourceFile().fileName;
35
+ if (/@dev[/.]/.test(categorySourceFilePath)) continue;
36
+ if (this.options.include?.length) {
37
+ if (this.options.include.every((item) => !categorySourceFilePath.includes(item))) continue;
38
+ }
39
+ if (this.options.exclude?.length) {
40
+ if (this.options.exclude.some((item) => categorySourceFilePath.includes(item))) continue;
41
+ }
42
+ const categoryUrlMatch = categorySourceFilePath.match(this.categoryUrlRe);
43
+ let categoryUrl = categoryUrlMatch[1] ?? categoryUrlMatch[2] ?? "";
44
+ categoryUrl = categoryUrl === "" ? "/" : `/${categoryUrl}/`;
45
+ for (const handlerSymbol of handlerSymbols) {
46
+ let handlerPath = [handlerSymbol.getName()];
47
+ const handlerNode = handlerSymbol.getDeclarations()[0];
48
+ if (ts.isVariableDeclaration(handlerNode) && handlerNode.initializer && ts.isCallExpression(handlerNode.initializer) && ts.isObjectLiteralExpression(handlerNode.initializer.arguments[0])) {
49
+ const requestPathNode = handlerNode.initializer.arguments[0].properties.find((item) => item.name?.getText() === "requestPath");
50
+ if (requestPathNode && ts.isPropertyAssignment(requestPathNode)) {
51
+ const customHandlerPath = ts.isStringLiteral(requestPathNode.initializer) ? requestPathNode.initializer.text : ts.isArrayLiteralExpression(requestPathNode.initializer) ? requestPathNode.initializer.elements.filter((item) => ts.isStringLiteral(item)).map((item) => item.text) : "";
52
+ if (customHandlerPath.length) handlerPath = castArray(customHandlerPath);
53
+ }
54
+ }
55
+ const handlerUrl = handlerPath.map((path) => `${categoryUrl}${path}`);
56
+ const handlerComment = this.getComment(handlerSymbol);
57
+ if (handlerComment.tags.has("private")) {
58
+ this.debug("跳过生成接口: %s", `${handlerUrl}`);
59
+ continue;
60
+ }
61
+ this.debug("生成接口: %s ...", handlerUrl);
62
+ const handlerType = checker.getTypeAtLocation(handlerNode);
63
+ const [requestType, responseType, methodType] = checker.getTypeArguments(handlerType);
64
+ const handlerCategory = pascalCase(categoryUrl) || "Index";
65
+ const handlerDescription = handlerComment.description || handlerUrl.join(", ");
66
+ const handlerMethod = methodType.value;
67
+ const httpMethod = HandlerMethodToHttpMethod[handlerMethod];
68
+ const requestData = this.getApiDto({ type: requestType });
69
+ const responseData = this.getApiDto({ type: responseType });
70
+ const requestDataJsonSchema = this.apiDataToJsonSchema(requestData);
71
+ const responseDataJsonSchema = this.apiDataToJsonSchema(responseData);
72
+ const handlerDescriptionDividerIndex = handlerDescription.indexOf("\n\n");
73
+ const apiName = handlerDescriptionDividerIndex === -1 ? handlerDescription : handlerDescription.substring(0, handlerDescriptionDividerIndex);
74
+ const apiDesc = handlerDescriptionDividerIndex === -1 ? "" : handlerDescription.substring(handlerDescriptionDividerIndex + 2);
75
+ apiData.push({
76
+ category: handlerCategory,
77
+ name: apiName,
78
+ desc: apiDesc,
79
+ path: handlerUrl,
80
+ handlerMethod,
81
+ method: httpMethod,
82
+ requestData,
83
+ responseData,
84
+ requestDataJsonSchema,
85
+ responseDataJsonSchema
86
+ });
87
+ }
88
+ }
89
+ this.debug("写入文件...");
90
+ const prefix = this.options.name ? `${this.options.name}_` : "";
91
+ await Promise.all([
92
+ fs.outputJSON(path.join(this.cwd, `temp/${prefix}api.json`), apiData, { spaces: 2 }),
93
+ fs.outputJSON(path.join(this.cwd, `temp/${prefix}yapi.json`), this.apiDataToYApiData(apiData), { spaces: 2 }),
94
+ fs.outputJSON(path.join(this.cwd, `temp/${prefix}openapi31.json`), this.apiDataToOpenAPI31Data(apiData), { spaces: 2 })
95
+ ]);
96
+ }
97
+ getComment(symbol) {
98
+ if (!symbol) return {
99
+ existing: false,
100
+ description: "",
101
+ tags: /* @__PURE__ */ new Map()
102
+ };
103
+ const description = ts.displayPartsToString(symbol.getDocumentationComment(this.checker)).trim();
104
+ const tags = symbol.getJsDocTags().map((item) => {
105
+ return {
106
+ label: item.name,
107
+ value: ts.displayPartsToString(item.text).trim()
108
+ };
109
+ });
110
+ return {
111
+ existing: !!description,
112
+ description,
113
+ tags: tags.reduce((res, item) => {
114
+ res.set(item.label, item.value);
115
+ return res;
116
+ }, /* @__PURE__ */ new Map())
117
+ };
118
+ }
119
+ getApiDto({ type, keySymbol = type.symbol || type.aliasSymbol }) {
120
+ const hasTypeFlag = (flag, _type = type) => (_type.flags & flag) === flag;
121
+ let valueSymbol = type.symbol || type.aliasSymbol;
122
+ const keySymbolName = keySymbol?.getName() || "";
123
+ let valueSymbolName = valueSymbol?.getName() || "";
124
+ const comment = this.getComment(keySymbol);
125
+ let isRequired = keySymbol ? !(keySymbol.getFlags() & ts.SymbolFlags.Optional) : false;
126
+ const apiName = keySymbolName || "__type";
127
+ if (valueSymbolName === "Decimal") return {
128
+ name: apiName,
129
+ desc: comment.description,
130
+ required: isRequired,
131
+ type: "number",
132
+ enum: [],
133
+ children: []
134
+ };
135
+ if (valueSymbolName === "SocketStream") return {
136
+ name: "ws",
137
+ desc: comment.description,
138
+ required: isRequired,
139
+ type: "object",
140
+ enum: [],
141
+ children: []
142
+ };
143
+ if (valueSymbolName === "MultipartFile") return {
144
+ name: "file",
145
+ desc: comment.description,
146
+ required: isRequired,
147
+ type: "file",
148
+ enum: [],
149
+ children: []
150
+ };
151
+ if (valueSymbolName === "Buffer") return {
152
+ name: "buffer",
153
+ desc: comment.description,
154
+ required: isRequired,
155
+ type: "object",
156
+ enum: [],
157
+ children: []
158
+ };
159
+ const rawUnionTypes = type.isUnion() && type.types || [];
160
+ const unionTypes = rawUnionTypes.filter((item) => !hasTypeFlag(ts.TypeFlags.Null, item) && !hasTypeFlag(ts.TypeFlags.Undefined, item));
161
+ const isUnion = !!unionTypes.length;
162
+ if (isUnion) {
163
+ if (unionTypes.length !== rawUnionTypes.length) isRequired = false;
164
+ type = unionTypes[0];
165
+ valueSymbol = type.symbol || type.aliasSymbol;
166
+ valueSymbolName = this.checker.getBaseTypeOfLiteralType(type).getSymbol()?.getName() || "";
167
+ }
168
+ const isIntersection = type.isIntersection();
169
+ const intersectionTypes = isIntersection && type.types || [];
170
+ const isDate = valueSymbolName === "Date";
171
+ const isRegExp = valueSymbolName === "RegExp";
172
+ const isBigIntLiteral = hasTypeFlag(ts.TypeFlags.BigIntLiteral);
173
+ const isBigInt = hasTypeFlag(ts.TypeFlags.BigInt) || isBigIntLiteral;
174
+ const isArray = valueSymbolName === "Array" || valueSymbolName === "ReadonlyArray";
175
+ const isStringLiteral = hasTypeFlag(ts.TypeFlags.StringLiteral);
176
+ const isString = hasTypeFlag(ts.TypeFlags.String) || isStringLiteral || isBigInt || isDate || isRegExp;
177
+ const isNumberLiteral = hasTypeFlag(ts.TypeFlags.NumberLiteral);
178
+ const isNumber = hasTypeFlag(ts.TypeFlags.Number) || isNumberLiteral;
179
+ const isBoolean = hasTypeFlag(ts.TypeFlags.Boolean) || hasTypeFlag(ts.TypeFlags.BooleanLiteral);
180
+ const isLiteral = isStringLiteral || isNumberLiteral || isBigIntLiteral;
181
+ const isObject = !isArray && !isString && !isNumber && !isBoolean && hasTypeFlag(ts.TypeFlags.Object) || isIntersection;
182
+ return {
183
+ name: apiName,
184
+ desc: keySymbol && this.getComment(keySymbol).description || "",
185
+ enum: (isUnion ? unionTypes.map((item) => item.value) : isLiteral ? [type.value] : []).filter((v) => v != null),
186
+ type: isArray ? "array" : isString ? "string" : isNumber ? "number" : isBoolean ? "boolean" : "object",
187
+ required: isRequired,
188
+ children: isArray ? [this.getApiDto({ type: this.checker.getTypeArguments(type)[0] })] : isObject ? ii(() => {
189
+ return this.checker.getAllPossiblePropertiesOfTypes(intersectionTypes.length ? intersectionTypes : [type]).map((childSymbol) => {
190
+ const childType = this.checker.getTypeOfSymbol(childSymbol);
191
+ return this.getApiDto({
192
+ type: childType,
193
+ keySymbol: childSymbol
194
+ });
195
+ });
196
+ }) : []
197
+ };
198
+ }
199
+ apiDataToJsonSchema(apiData, jsonSchema = {}) {
200
+ jsonSchema.description = apiData.desc;
201
+ if (apiData.type === "object") {
202
+ jsonSchema.type = "object";
203
+ jsonSchema.properties = apiData.children.reduce((res, item) => {
204
+ res[item.name] = this.apiDataToJsonSchema(item);
205
+ return res;
206
+ }, {});
207
+ jsonSchema.required = apiData.children.filter((item) => item.required).map((item) => item.name);
208
+ } else if (apiData.type === "array") {
209
+ jsonSchema.type = "array";
210
+ jsonSchema.items = apiData.children.map((item) => this.apiDataToJsonSchema(item))[0];
211
+ } else {
212
+ jsonSchema.type = apiData.type;
213
+ if (apiData.enum.length) jsonSchema.enum = apiData.enum;
214
+ }
215
+ return jsonSchema;
216
+ }
217
+ apiDataToYApiData(handles) {
218
+ const data = {};
219
+ for (const handle of handles) for (const path of handle.path) {
220
+ data[handle.category] = data[handle.category] || [];
221
+ data[handle.category].push(handle.handlerMethod === "GET" ? {
222
+ method: handle.method.toUpperCase(),
223
+ title: handle.name,
224
+ markdown: handle.desc,
225
+ path,
226
+ res_body_type: "json",
227
+ req_body_is_json_schema: false,
228
+ res_body_is_json_schema: true,
229
+ req_params: [],
230
+ req_query: handle.requestData.children.map((item) => ({
231
+ required: item.required ? 1 : 0,
232
+ name: item.name,
233
+ desc: item.desc,
234
+ type: "string"
235
+ })),
236
+ req_headers: [],
237
+ req_body_form: [],
238
+ res_body: JSON.stringify(handle.responseDataJsonSchema)
239
+ } : handle.handlerMethod === "FILE" ? {
240
+ method: handle.method.toUpperCase(),
241
+ title: handle.name,
242
+ markdown: handle.desc,
243
+ path,
244
+ req_body_type: "form",
245
+ res_body_type: "json",
246
+ req_body_is_json_schema: false,
247
+ res_body_is_json_schema: true,
248
+ req_params: [],
249
+ req_query: [],
250
+ req_headers: [],
251
+ req_body_form: handle.requestData.children.map((item) => ({
252
+ required: item.required ? 1 : 0,
253
+ name: item.name,
254
+ desc: item.desc,
255
+ type: item.type === "file" ? "file" : "text"
256
+ })),
257
+ res_body: JSON.stringify(handle.responseDataJsonSchema)
258
+ } : {
259
+ method: handle.method.toUpperCase(),
260
+ title: handle.name,
261
+ markdown: handle.desc,
262
+ path,
263
+ req_body_type: "json",
264
+ res_body_type: "json",
265
+ req_body_is_json_schema: true,
266
+ res_body_is_json_schema: true,
267
+ req_params: [],
268
+ req_query: [],
269
+ req_headers: [],
270
+ req_body_form: [],
271
+ req_body_other: JSON.stringify(handle.requestDataJsonSchema),
272
+ res_body: JSON.stringify(handle.responseDataJsonSchema)
273
+ });
274
+ }
275
+ return Object.keys(data).map((cat) => ({
276
+ name: cat,
277
+ desc: cat,
278
+ list: data[cat]
279
+ }));
280
+ }
281
+ apiDataToOpenAPI31Data(handles) {
282
+ const data = {
283
+ openapi: "3.1.0",
284
+ info: {
285
+ title: `${process.env.APP_NAME}`,
286
+ version: "1.0.0"
287
+ },
288
+ paths: {},
289
+ servers: [{
290
+ url: `${process.env.APP_URL}`.replace(/\/+$/, ""),
291
+ description: "生产"
292
+ }, {
293
+ url: `http://127.0.0.1:${process.env.APP_PORT}`,
294
+ description: "本地"
295
+ }]
296
+ };
297
+ for (const handle of handles) for (const path of handle.path) data.paths[path] = { [handle.method.toLowerCase()]: {
298
+ tags: [handle.category],
299
+ summary: handle.name,
300
+ description: handle.desc,
301
+ requestBody: { content: { "application/json": { schema: handle.requestDataJsonSchema } } },
302
+ responses: { "200": {
303
+ description: "success",
304
+ content: { "application/json": { schema: handle.responseDataJsonSchema } }
305
+ } }
306
+ } };
307
+ return data;
308
+ }
309
+ };
310
+ export { ApiGenerator };
@@ -0,0 +1,17 @@
1
+ export interface BuildOptions {
2
+ appId: string;
3
+ cwd: string;
4
+ external?: string[];
5
+ inlineEnvs?: Record<string, any>;
6
+ minify?: boolean;
7
+ noInstall?: boolean;
8
+ channel?: string;
9
+ excludeFiles?: string[];
10
+ noEmptyDistDir?: boolean;
11
+ pm2MaxMemoryRestart?: string;
12
+ pm2CronRestart?: string;
13
+ pm2NodeArgs?: string | string[];
14
+ }
15
+ export declare class BuildUtil {
16
+ static build(options: BuildOptions): Promise<void>;
17
+ }
@@ -0,0 +1,156 @@
1
+ import { __require } from "../_virtual/_rolldown/runtime.mjs";
2
+ import { dedent, uniq } from "vtils";
3
+ import path from "node:path";
4
+ import fs from "fs-extra";
5
+ import compressing from "compressing";
6
+ import * as esbuild from "esbuild";
7
+ import exec from "execa";
8
+ // src/cli/build_util.ts
9
+ var BuildUtil = class {
10
+ static async build(options) {
11
+ const mainFile = path.join(options.cwd, "src/main.ts");
12
+ const pkgFile = path.join(options.cwd, "package.json");
13
+ const pkgContent = await fs.readJson(pkgFile);
14
+ const distDir = path.join(options.cwd, options.channel ? `dist/${options.channel}` : "dist");
15
+ const tempDir = path.join(options.cwd, options.channel ? `temp/${options.channel}` : "temp");
16
+ const distMainFile = path.join(distDir, "main.js");
17
+ const distPkgFile = path.join(distDir, "package.json");
18
+ const distNvmrcFile = path.join(distDir, ".nvmrc");
19
+ const distPm2File = path.join(distDir, "pm2.config.js");
20
+ const distNoInstallFile = path.join(distDir, "no_install.lock");
21
+ const distBundleFile = path.join(tempDir, `app.${pkgContent.version}.tgz`);
22
+ await fs.ensureDir(distDir);
23
+ await fs.ensureDir(tempDir);
24
+ const external = uniq([...options.external || [], "bull"]);
25
+ const externalWithVersions = (await Promise.all(external.map(async (item) => {
26
+ try {
27
+ const itemPkgFile = path.join(process.cwd(), `node_modules/${item}/package.json`);
28
+ return {
29
+ name: item,
30
+ version: (await fs.readJson(itemPkgFile)).version
31
+ };
32
+ } catch {
33
+ return {
34
+ name: item,
35
+ version: ""
36
+ };
37
+ }
38
+ }))).filter((item) => !!item.version);
39
+ try {
40
+ const hexoidPackageJsonFile = __require.resolve("hexoid/package.json");
41
+ const pkg = await fs.readJson(hexoidPackageJsonFile);
42
+ delete pkg.module;
43
+ await fs.writeJson(hexoidPackageJsonFile, pkg);
44
+ } catch {}
45
+ if (!options.noEmptyDistDir) await fs.emptyDir(distDir);
46
+ const { default: macrosPlugin } = await import("unplugin-macros/esbuild");
47
+ await esbuild.build({
48
+ entryPoints: [mainFile],
49
+ bundle: true,
50
+ outfile: distMainFile,
51
+ platform: "node",
52
+ mainFields: ["module", "main"],
53
+ target: `node${process.version.slice(1)}`,
54
+ external,
55
+ minify: options.minify ?? true,
56
+ format: "cjs",
57
+ sourcemap: false,
58
+ treeShaking: true,
59
+ banner: { js: [...Object.keys(options.inlineEnvs || {}).map((key) => `process.env[${JSON.stringify(key)}]=${JSON.stringify(options.inlineEnvs[key])};`), `process.env["X_SERVER_ENVS"]=${JSON.stringify(JSON.stringify(options.inlineEnvs || {}))};`].join("\n") },
60
+ plugins: [{
61
+ name: "extract-assets",
62
+ async setup(build) {
63
+ build.onLoad({ filter: /\/svg-captcha\/lib\/option-manager\.js$/ }, async (args) => {
64
+ let js = await fs.readFile(args.path, "utf-8");
65
+ js = js.replace("../fonts/Comismsh.ttf", "./assets/svg-captcha/fonts/Comismsh.ttf");
66
+ await fs.copy(path.dirname(__require.resolve("svg-captcha/fonts/LICENSE.md")), path.join(distDir, "assets/svg-captcha/fonts"));
67
+ return {
68
+ contents: js,
69
+ loader: "js"
70
+ };
71
+ });
72
+ build.onLoad({ filter: /\/vm2\/lib\/vm\.js$/ }, async (args) => {
73
+ let js = await fs.readFile(args.path, "utf-8");
74
+ const jsDir = path.dirname(args.path);
75
+ const assetsDir = path.join(distDir, "assets/vm2");
76
+ await fs.ensureDir(assetsDir);
77
+ js = js.replace(/__dirname/g, "\"./assets/vm2\"");
78
+ await Promise.all([fs.copyFile(path.join(jsDir, "bridge.js"), path.join(assetsDir, "bridge.js")), fs.copyFile(path.join(jsDir, "setup-sandbox.js"), path.join(assetsDir, "setup-sandbox.js"))]);
79
+ return {
80
+ contents: js,
81
+ loader: "js"
82
+ };
83
+ });
84
+ build.onLoad({ filter: /@dev[/.]/ }, async () => {
85
+ return {
86
+ contents: "module.exports = {}",
87
+ loader: "js"
88
+ };
89
+ });
90
+ if (options.excludeFiles?.length) {
91
+ const excludeRegExps = options.excludeFiles.map((item) => new RegExp(item));
92
+ build.onLoad({ filter: /\.ts$/ }, async (args) => {
93
+ if (excludeRegExps.some((re) => re.test(args.path))) return {
94
+ contents: "module.exports = {}",
95
+ loader: "js"
96
+ };
97
+ });
98
+ }
99
+ }
100
+ }, macrosPlugin()],
101
+ loader: { ".css": "empty" }
102
+ });
103
+ const prismaSchemaFile = path.join(options.cwd, "src/db/schema.prisma");
104
+ if (await fs.pathExists(prismaSchemaFile)) {
105
+ const distPrismaSchemaFile = path.join(distDir, path.basename(prismaSchemaFile));
106
+ await fs.copyFile(prismaSchemaFile, distPrismaSchemaFile);
107
+ const multipleSchemaDir = path.join(options.cwd, "src/db/schema");
108
+ if (await fs.pathExists(multipleSchemaDir)) {
109
+ const distMultipleSchemaDir = path.join(distDir, path.basename(multipleSchemaDir));
110
+ await fs.copy(multipleSchemaDir, distMultipleSchemaDir);
111
+ }
112
+ }
113
+ const deps = externalWithVersions.reduce((res, item) => {
114
+ res[item.name] = item.version;
115
+ return res;
116
+ }, {});
117
+ const distPkgContent = {
118
+ name: options.appId,
119
+ version: pkgContent.version,
120
+ dependencies: deps
121
+ };
122
+ await fs.writeJSON(distPkgFile, distPkgContent);
123
+ const nvmrcFile = path.join(options.cwd, ".nvmrc");
124
+ const hasNvmrc = await fs.pathExists(nvmrcFile);
125
+ if (hasNvmrc) await fs.writeFile(distNvmrcFile, await fs.readFile(nvmrcFile));
126
+ await fs.writeFile(distPm2File, dedent`
127
+ module.exports = {
128
+ apps: [
129
+ {
130
+ name: ${JSON.stringify(distPkgContent.name)},
131
+ script: './main.js',
132
+ interpreter: 'node',
133
+ interpreter_args: ${JSON.stringify(options.pm2NodeArgs || [])},
134
+ ${hasNvmrc ? `
135
+ env: {
136
+ PATH: \`\${require('child_process').execSync('fnm exec which node').toString().trim().replace(/\\/node$/, '')}:\${process.env.PATH}\`,
137
+ },
138
+ ` : ""}
139
+ ${options.pm2MaxMemoryRestart ? `max_memory_restart: '${options.pm2MaxMemoryRestart}',` : ""}
140
+ ${options.pm2CronRestart ? `cron_restart: '${options.pm2CronRestart}',` : ""}
141
+ },
142
+ ],
143
+ }
144
+ `);
145
+ if (externalWithVersions.length) {
146
+ if (options.noInstall) await fs.writeFile(distNoInstallFile, "");
147
+ else await exec("tyn", {
148
+ cwd: distDir,
149
+ stdio: "inherit",
150
+ env: { yarn_disable_self_update_check: "true" }
151
+ });
152
+ }
153
+ await compressing.tgz.compressDir(distDir, distBundleFile);
154
+ }
155
+ };
156
+ export { BuildUtil };
@@ -0,0 +1 @@
1
+ export {}