create-aomex 0.0.1

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-2024 geekact
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,169 @@
1
+ // src/input-package-manager.ts
2
+ import inquirer from "inquirer";
3
+ var packageManagers = ["pnpm", "npm", "yarn"];
4
+ var inputPackageManager = async (argv2) => {
5
+ for (const expected of packageManagers) {
6
+ if (argv2[expected]) return expected;
7
+ }
8
+ const { manager } = await inquirer.prompt({
9
+ name: "manager",
10
+ message: "\u9009\u62E9\u5305\u7BA1\u7406\u5DE5\u5177",
11
+ type: "list",
12
+ choices: packageManagers,
13
+ default: "pnpm",
14
+ askAnswered: true
15
+ });
16
+ return manager;
17
+ };
18
+
19
+ // src/input-project-name.ts
20
+ import inquirer2 from "inquirer";
21
+ import kebabCase from "lodash.kebabcase";
22
+ import { existsSync } from "node:fs";
23
+ import path from "node:path";
24
+ var inputProjectName = async (argv2) => {
25
+ if (typeof argv2["name"] === "string") return argv2["name"];
26
+ const result = await inquirer2.prompt({
27
+ name: "projectName",
28
+ type: "input",
29
+ message: "\u9879\u76EE\u540D\u79F0",
30
+ suffix: ":"
31
+ });
32
+ const projectName2 = kebabCase(result.projectName);
33
+ const absolutePath = path.posix.resolve(projectName2);
34
+ if (existsSync(absolutePath) && argv2["force"] !== true) {
35
+ const { goon } = await inquirer2.prompt({
36
+ name: "goon",
37
+ type: "confirm",
38
+ message: `\u76EE\u5F55 "${absolutePath}" \u5DF2\u7ECF\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6\uFF1F`,
39
+ suffix: ":"
40
+ });
41
+ if (!goon) {
42
+ process.exit(0);
43
+ }
44
+ }
45
+ return projectName2;
46
+ };
47
+
48
+ // src/index.ts
49
+ import path3 from "node:path/posix";
50
+ import yargsParser from "yargs-parser";
51
+ import { existsSync as existsSync2 } from "node:fs";
52
+ import { cp, mkdir, rm } from "node:fs/promises";
53
+ import { Listr } from "listr2";
54
+ import { promisify, styleText } from "node:util";
55
+ import childProcess from "node:child_process";
56
+
57
+ // src/replace-variables.ts
58
+ import { readFile, writeFile } from "node:fs/promises";
59
+ import path2 from "node:path";
60
+ var replaceVariables = async (filename, variables) => {
61
+ const packageJSONFile = path2.resolve(filename);
62
+ let packageContent = await readFile(packageJSONFile, "utf8");
63
+ Object.entries(variables).forEach(([key, value]) => {
64
+ packageContent = packageContent.replaceAll(`{{${key}}}`, value);
65
+ });
66
+ await writeFile(packageJSONFile, packageContent);
67
+ };
68
+
69
+ // src/index.ts
70
+ var argv = yargsParser(process.argv.slice(2));
71
+ var projectName = await inputProjectName(argv);
72
+ var packageManager = await inputPackageManager(argv);
73
+ var templateDir = path3.join(import.meta.dirname, "..", "templates");
74
+ var targetDir = path3.resolve(projectName);
75
+ var exec = promisify(childProcess.exec);
76
+ var sleep = () => new Promise((resolve) => setTimeout(resolve, 500));
77
+ var spinner = new Listr([]);
78
+ spinner.add({
79
+ title: "\u521B\u5EFA\u76EE\u5F55",
80
+ task: async () => {
81
+ if (existsSync2(targetDir)) {
82
+ await rm(targetDir, { recursive: true, force: true });
83
+ }
84
+ await mkdir(targetDir, { recursive: true });
85
+ process.chdir(path3.resolve(projectName));
86
+ }
87
+ });
88
+ spinner.add({
89
+ title: "git\u521D\u59CB\u5316",
90
+ task: async () => {
91
+ await exec("git init");
92
+ await sleep();
93
+ }
94
+ });
95
+ spinner.add({
96
+ title: "\u590D\u5236\u6A21\u677F\u6587\u4EF6",
97
+ task: async () => {
98
+ await cp(templateDir, targetDir, { recursive: true });
99
+ await replaceVariables("package.json", { projectName, packageManager });
100
+ await replaceVariables("README.md", { projectName, packageManager });
101
+ await sleep();
102
+ }
103
+ });
104
+ spinner.add({
105
+ title: "\u589E\u52A0volta\u914D\u7F6E",
106
+ skip: async () => {
107
+ return !/\d\.\d/.test((await exec("volta -v")).stdout);
108
+ },
109
+ task: async () => {
110
+ await exec("volta pin node");
111
+ if (packageManager !== "npm") {
112
+ await exec(`volta pin ${packageManager}`);
113
+ }
114
+ }
115
+ });
116
+ spinner.add({
117
+ title: "\u5B89\u88C5\u63D2\u4EF6",
118
+ task: async (_, task) => {
119
+ const packages = [
120
+ { pkg: "@aomex/core" },
121
+ { pkg: "@aomex/web" },
122
+ { pkg: "@aomex/console" },
123
+ { pkg: "@aomex/router" },
124
+ { pkg: "@aomex/cors" },
125
+ { pkg: "@aomex/etag" },
126
+ { pkg: "@aomex/compress" },
127
+ { pkg: "@aomex/http-logger" },
128
+ { pkg: "@aomex/commander" },
129
+ { pkg: "@aomex/openapi" },
130
+ { pkg: "@prisma/client" },
131
+ { pkg: "prisma", dev: true },
132
+ { pkg: "typescript", dev: true },
133
+ { pkg: "@types/node", dev: true },
134
+ { pkg: "tsx", dev: true },
135
+ { pkg: "husky", dev: true },
136
+ { pkg: "tsc-alias", dev: true },
137
+ { pkg: "prettier", dev: true },
138
+ { pkg: "@commitlint/cli", dev: true },
139
+ { pkg: "@commitlint/config-conventional", dev: true },
140
+ { pkg: "eslint", dev: true },
141
+ { pkg: "@typescript-eslint/eslint-plugin", dev: true },
142
+ { pkg: "@typescript-eslint/parser", dev: true },
143
+ { pkg: "eslint-plugin-check-file", dev: true }
144
+ ];
145
+ const action = packageManager === "npm" ? "install" : "add";
146
+ const devSuffix = packageManager === "npm" ? "--save-dev" : "-D";
147
+ for (let i = 0; i < packages.length; ++i) {
148
+ const { pkg, dev } = packages[i];
149
+ task.title = "\u5B89\u88C5\u63D2\u4EF6 " + styleText("gray", pkg);
150
+ await exec(`${packageManager} ${action} ${pkg} ${dev ? devSuffix : ""}`, {
151
+ cwd: process.cwd(),
152
+ env: process.env
153
+ });
154
+ }
155
+ task.title = "\u5B89\u88C5\u63D2\u4EF6";
156
+ }
157
+ });
158
+ spinner.add({
159
+ title: "\u751F\u6210prisma/client\u6587\u4EF6",
160
+ task: async () => {
161
+ await exec("npx prisma generate");
162
+ await sleep();
163
+ }
164
+ });
165
+ await spinner.run();
166
+ console.log(
167
+ "\n\u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF1A" + styleText(["blue", "underline"], process.cwd()) + "\n"
168
+ );
169
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/input-package-manager.ts","../src/input-project-name.ts","../src/index.ts","../src/replace-variables.ts"],"sourcesContent":["import inquirer from 'inquirer';\n\nconst packageManagers = <const>['pnpm', 'npm', 'yarn'];\n\nexport type PackageManager = (typeof packageManagers)[number];\n\nexport const inputPackageManager = async (\n argv: Record<string, any>,\n): Promise<PackageManager> => {\n for (const expected of packageManagers) {\n if (argv[expected]) return expected;\n }\n\n const { manager } = await inquirer.prompt<{\n manager: PackageManager;\n }>({\n name: 'manager',\n message: '选择包管理工具',\n type: 'list',\n choices: packageManagers,\n default: 'pnpm',\n askAnswered: true,\n });\n\n return manager;\n};\n","import inquirer from 'inquirer';\nimport kebabCase from 'lodash.kebabcase';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\n\nexport const inputProjectName = async (\n argv: Record<string, any>,\n): Promise<string> => {\n if (typeof argv['name'] === 'string') return argv['name'];\n\n const result = await inquirer.prompt<{ projectName: string }>({\n name: 'projectName',\n type: 'input',\n message: '项目名称',\n suffix: ':',\n });\n\n const projectName = kebabCase(result.projectName);\n\n const absolutePath = path.posix.resolve(projectName);\n if (existsSync(absolutePath) && argv['force'] !== true) {\n const { goon } = await inquirer.prompt<{ goon: boolean }>({\n name: 'goon',\n type: 'confirm',\n message: `目录 \"${absolutePath}\" 已经存在,是否覆盖?`,\n suffix: ':',\n });\n\n if (!goon) {\n process.exit(0);\n }\n }\n\n return projectName;\n};\n","import { inputPackageManager } from './input-package-manager';\nimport { inputProjectName } from './input-project-name';\nimport path from 'node:path/posix';\nimport yargsParser from 'yargs-parser';\nimport { existsSync } from 'node:fs';\nimport { cp, mkdir, rm } from 'node:fs/promises';\nimport { Listr } from 'listr2';\nimport { promisify, styleText } from 'node:util';\nimport childProcess from 'node:child_process';\nimport { replaceVariables } from './replace-variables';\n\nconst argv = yargsParser(process.argv.slice(2));\nconst projectName = await inputProjectName(argv);\nconst packageManager = await inputPackageManager(argv);\nconst templateDir = path.join(import.meta.dirname, '..', 'templates');\nconst targetDir = path.resolve(projectName);\n\nconst exec = promisify(childProcess.exec);\nconst sleep = () => new Promise((resolve) => setTimeout(resolve, 500));\n\nconst spinner = new Listr([]);\n\nspinner.add({\n title: '创建目录',\n task: async () => {\n if (existsSync(targetDir)) {\n await rm(targetDir, { recursive: true, force: true });\n }\n await mkdir(targetDir, { recursive: true });\n process.chdir(path.resolve(projectName));\n },\n});\n\nspinner.add({\n title: 'git初始化',\n task: async () => {\n await exec('git init');\n await sleep();\n },\n});\n\nspinner.add({\n title: '复制模板文件',\n task: async () => {\n await cp(templateDir, targetDir, { recursive: true });\n await replaceVariables('package.json', { projectName, packageManager });\n await replaceVariables('README.md', { projectName, packageManager });\n await sleep();\n },\n});\n\nspinner.add({\n title: '增加volta配置',\n skip: async () => {\n return !/\\d\\.\\d/.test((await exec('volta -v')).stdout);\n },\n task: async () => {\n await exec('volta pin node');\n if (packageManager !== 'npm') {\n await exec(`volta pin ${packageManager}`);\n }\n },\n});\n\nspinner.add({\n title: '安装插件',\n task: async (_, task) => {\n const packages: { pkg: string; dev?: boolean }[] = [\n { pkg: '@aomex/core' },\n { pkg: '@aomex/web' },\n { pkg: '@aomex/console' },\n { pkg: '@aomex/router' },\n { pkg: '@aomex/cors' },\n { pkg: '@aomex/etag' },\n { pkg: '@aomex/compress' },\n { pkg: '@aomex/http-logger' },\n { pkg: '@aomex/commander' },\n { pkg: '@aomex/openapi' },\n { pkg: '@prisma/client' },\n { pkg: 'prisma', dev: true },\n { pkg: 'typescript', dev: true },\n { pkg: '@types/node', dev: true },\n { pkg: 'tsx', dev: true },\n { pkg: 'husky', dev: true },\n { pkg: 'tsc-alias', dev: true },\n { pkg: 'prettier', dev: true },\n { pkg: '@commitlint/cli', dev: true },\n { pkg: '@commitlint/config-conventional', dev: true },\n { pkg: 'eslint', dev: true },\n { pkg: '@typescript-eslint/eslint-plugin', dev: true },\n { pkg: '@typescript-eslint/parser', dev: true },\n { pkg: 'eslint-plugin-check-file', dev: true },\n ];\n const action = packageManager === 'npm' ? 'install' : 'add';\n const devSuffix = packageManager === 'npm' ? '--save-dev' : '-D';\n\n for (let i = 0; i < packages.length; ++i) {\n const { pkg, dev } = packages[i]!;\n task.title = '安装插件 ' + styleText('gray', pkg);\n await exec(`${packageManager} ${action} ${pkg} ${dev ? devSuffix : ''}`, {\n cwd: process.cwd(),\n env: process.env,\n });\n }\n task.title = '安装插件';\n },\n});\n\nspinner.add({\n title: '生成prisma/client文件',\n task: async () => {\n await exec('npx prisma generate');\n await sleep();\n },\n});\n\nawait spinner.run();\n\nconsole.log(\n '\\n项目创建成功:' + styleText(['blue', 'underline'], process.cwd()) + '\\n',\n);\n","import { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\n\nexport const replaceVariables = async (\n filename: string,\n variables: Record<string, string>,\n) => {\n const packageJSONFile = path.resolve(filename);\n let packageContent = await readFile(packageJSONFile, 'utf8');\n Object.entries(variables).forEach(([key, value]) => {\n packageContent = packageContent.replaceAll(`{{${key}}}`, value);\n });\n await writeFile(packageJSONFile, packageContent);\n};\n"],"mappings":"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","names":["argv","inquirer","argv","projectName","path","existsSync","path","path","existsSync"]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "create-aomex",
3
+ "version": "0.0.1",
4
+ "repository": "git@github.com:aomex/create-aomex.git",
5
+ "author": "geekact <fanwenhua1990@gmail.com>",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "scripts": {
9
+ "cli": "tsx src/index.ts",
10
+ "release": "release-it --ci",
11
+ "build": "tsup",
12
+ "prepublishOnly": "pnpm build"
13
+ },
14
+ "volta": {
15
+ "node": "20.15.0",
16
+ "pnpm": "9.4.0"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "templates",
27
+ "LICENSE",
28
+ "package.json",
29
+ "README.md"
30
+ ],
31
+ "bin": "dist/index.js",
32
+ "packageManager": "pnpm@9.4.0",
33
+ "dependencies": {
34
+ "inquirer": "^9.2.23",
35
+ "listr2": "^8.2.3",
36
+ "lodash.kebabcase": "^4.1.1",
37
+ "yargs-parser": "^21.1.1"
38
+ },
39
+ "devDependencies": {
40
+ "@aomex/commander": "^1.0.4",
41
+ "@aomex/compress": "^1.0.4",
42
+ "@aomex/console": "^1.0.4",
43
+ "@aomex/core": "^1.0.4",
44
+ "@aomex/cors": "^1.0.4",
45
+ "@aomex/etag": "^1.0.4",
46
+ "@aomex/helmet": "^1.0.4",
47
+ "@aomex/http-logger": "^1.0.4",
48
+ "@aomex/openapi": "^1.0.4",
49
+ "@aomex/router": "^1.0.4",
50
+ "@aomex/web": "^1.0.4",
51
+ "@prisma/client": "^5.16.0",
52
+ "@types/inquirer": "^9.0.7",
53
+ "@types/lodash.kebabcase": "^4.1.9",
54
+ "@types/node": "^20.14.8",
55
+ "@types/yargs-parser": "^21.0.3",
56
+ "prisma": "^5.16.0",
57
+ "release-it": "^17.4.0",
58
+ "tsup": "^8.1.0",
59
+ "tsx": "^4.15.7",
60
+ "typescript": "^5.5.2"
61
+ }
62
+ }
@@ -0,0 +1,2 @@
1
+ extends:
2
+ - '@commitlint/config-conventional'
package/templates/.env ADDED
@@ -0,0 +1 @@
1
+ DATABASE_URL="mysql://USERNAME:PASSWORD@HOST:PORT/DB_NAME"
@@ -0,0 +1,37 @@
1
+ parser: '@typescript-eslint/parser'
2
+ plugins:
3
+ - '@typescript-eslint'
4
+ - 'check-file'
5
+ root: true
6
+ parserOptions:
7
+ project: true
8
+ rules:
9
+ '@typescript-eslint/no-explicit-any': 'error'
10
+ '@typescript-eslint/no-unsafe-argument': 'error'
11
+ '@typescript-eslint/no-unsafe-assignment': 'error'
12
+ '@typescript-eslint/no-unsafe-call': 'error'
13
+ '@typescript-eslint/no-unsafe-member-access': 'error'
14
+ '@typescript-eslint/no-unsafe-return': 'error'
15
+
16
+ '@typescript-eslint/await-thenable': 'error'
17
+ # Number String Object
18
+ '@typescript-eslint/ban-types': 'error'
19
+ '@typescript-eslint/ban-ts-comments': 'error'
20
+ '@typescript-eslint/no-duplicate-type-constituents': 'error'
21
+ '@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error'
22
+ # foo?.bar!
23
+ '@typescript-eslint/no-non-null-asserted-optional-chain': 'error'
24
+ '@typescript-eslint/no-unnecessary-condition': 'error'
25
+ '@typescript-eslint/no-unnecessary-type-assertion': 'error'
26
+ '@typescript-eslint/no-unnecessary-type-constraint': 'error'
27
+
28
+ '@typescript-eslint/non-nullable-type-assertion-style': 'error'
29
+ '@typescript-eslint/prefer-as-const': 'error'
30
+ '@typescript-eslint/prefer-destructuring': 'error',
31
+ '@typescript-eslint/prefer-optional-chain': 'error'
32
+ '@typescript-eslint/prefer-reduce-type-parameter': 'error'
33
+ '@typescript-eslint/switch-exhaustiveness-check': 'error'
34
+ '@typescript-eslint/consistent-type-definitions': ['error', 'interface']
35
+
36
+ 'check-file/filename-naming-convention': ['error', { '**/*': '[a-z0-9-.]+' }]
37
+ 'check-file/folder-naming-convention': ['error', { '**/': '[a-z0-9-]+' }]
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env sh
2
+
3
+ npx --no-install commitlint --edit $1
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+
3
+ npx --no-install prettier --cache --check .
4
+ npx --no-install tsc
@@ -0,0 +1,5 @@
1
+ dist/
2
+ pnpm-lock.yaml
3
+ coverage/
4
+ openapi.json
5
+ build/
@@ -0,0 +1,16 @@
1
+ semi: true
2
+ singleQuote: true
3
+ # Change when properties in objects are quoted.
4
+ # If at least one property in an object requires quotes, quote all properties.
5
+ quoteProps: consistent
6
+ tabWidth: 2
7
+ printWidth: 100
8
+ endOfLine: lf
9
+ trailingComma: all
10
+ bracketSpacing: true
11
+ # Include parentheses around a sole arrow function parameter.
12
+ arrowParens: always
13
+ proseWrap: preserve
14
+ jsxSingleQuote: false
15
+ # Put > on the last line instead of at a new line.
16
+ bracketSameLine: false
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["esbenp.prettier-vscode", "Prisma.prisma"]
3
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "editor.formatOnSave": true,
3
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
4
+ "[prisma]": {
5
+ "editor.defaultFormatter": "Prisma.prisma"
6
+ },
7
+ "editor.tabSize": 2,
8
+ "editor.inlayHints.fontSize": 9,
9
+ "typescript.inlayHints.parameterNames.enabled": "all",
10
+ "typescript.inlayHints.enumMemberValues.enabled": true,
11
+ "typescript.inlayHints.functionLikeReturnTypes.enabled": true,
12
+ "typescript.tsdk": "node_modules/typescript/lib",
13
+ "typescript.preferences.quoteStyle": "single",
14
+ "typescript.suggest.autoImports": true,
15
+ "cSpell.ignoreWords": ["aomex", "mdchain", "openapi", "commitlint"]
16
+ }
@@ -0,0 +1,15 @@
1
+ # {{projectName}}
2
+
3
+ 使用 aomex 服务端框架,文档 [https://aomex.js.org](aomex.js.org)
4
+
5
+ ## 启动服务
6
+
7
+ ```bash
8
+ {{packageManager}} start
9
+ ```
10
+
11
+ ## 编译成 js 文件
12
+
13
+ ```bash
14
+ {{packageManager}} build
15
+ ```
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "license": "UNLICENSED",
5
+ "type": "module",
6
+ "scripts": {
7
+ "start": "node --import tsx/esm --watch src/web.ts",
8
+ "build": "tsc && tsc-alias --resolve-full-paths",
9
+ "prepare": "husky",
10
+ "preinstall": "npx only-allow {{packageManager}}"
11
+ }
12
+ }
@@ -0,0 +1,26 @@
1
+ datasource db {
2
+ provider = "mysql"
3
+ url = env("DATABASE_URL")
4
+ relationMode = "prisma"
5
+ }
6
+
7
+ generator client {
8
+ provider = "prisma-client-js"
9
+ }
10
+
11
+ model User {
12
+ id Int @id @default(autoincrement())
13
+ name String
14
+ age Int
15
+ created_at DateTime @default(now()) @db.DateTime(0)
16
+ updated_at DateTime @default(now()) @updatedAt @db.DateTime(0)
17
+ }
18
+
19
+ model Post {
20
+ id Int @id @default(autoincrement())
21
+ user_id Int
22
+ title String
23
+ content String @db.Text()
24
+ created_at DateTime @default(now()) @db.DateTime(0)
25
+ updated_at DateTime @default(now()) @updatedAt @db.DateTime(0)
26
+ }
@@ -0,0 +1,10 @@
1
+ import { ConsoleApp } from '@aomex/console';
2
+ import { appChain } from './middleware/console.chain';
3
+
4
+ const app = new ConsoleApp({
5
+ locale: 'zh_CN',
6
+ mount: appChain,
7
+ });
8
+
9
+ await app.run();
10
+ process.exit(0);
@@ -0,0 +1,12 @@
1
+ import { Commander } from '@aomex/commander';
2
+ import { commanderChain } from '../middleware/console.chain';
3
+
4
+ export const commander = new Commander({
5
+ mount: commanderChain,
6
+ });
7
+
8
+ commander.create('hello', {
9
+ async action(_ctx) {
10
+ console.log('Hello World');
11
+ },
12
+ });
@@ -0,0 +1,9 @@
1
+ import { mdchain } from '@aomex/core';
2
+ import { openapiGenerator } from './openapi.md';
3
+ import { commanders } from '@aomex/commander';
4
+
5
+ export const appChain = mdchain.console
6
+ .mount(openapiGenerator)
7
+ .mount(commanders('./src/commanders'));
8
+
9
+ export const commanderChain = appChain.mount(null);
@@ -0,0 +1,13 @@
1
+ import { openapi } from '@aomex/openapi';
2
+
3
+ export const openapiGenerator = openapi({
4
+ routers: ['./src/routers'],
5
+ docs: {
6
+ servers: [
7
+ {
8
+ url: 'http://localhost:3000',
9
+ description: 'Local',
10
+ },
11
+ ],
12
+ },
13
+ });
@@ -0,0 +1,17 @@
1
+ import { mdchain } from '@aomex/core';
2
+ import { cors } from '@aomex/cors';
3
+ import { compress } from '@aomex/compress';
4
+ import { routers } from '@aomex/router';
5
+ import { httpLogger } from '@aomex/http-logger';
6
+ import { helmet } from '@aomex/helmet';
7
+ import { etag } from '@aomex/etag';
8
+
9
+ export const appChain = mdchain.web
10
+ .mount(cors())
11
+ .mount(compress())
12
+ .mount(httpLogger())
13
+ .mount(etag())
14
+ .mount(helmet())
15
+ .mount(routers('./src/routers'));
16
+
17
+ export const routerChain = appChain;
@@ -0,0 +1,18 @@
1
+ import { Router } from '@aomex/router';
2
+ import { routerChain } from '../middleware/web.chain';
3
+
4
+ export const router = new Router({
5
+ mount: routerChain,
6
+ });
7
+
8
+ router.get('/', {
9
+ async action(ctx) {
10
+ ctx.send('hello world');
11
+ },
12
+ });
13
+
14
+ router.post('/', {
15
+ async action(ctx) {
16
+ ctx.send(201, { id: 1 });
17
+ },
18
+ });
@@ -0,0 +1,5 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+
3
+ export const db = new PrismaClient({
4
+ log: ['info'],
5
+ });
@@ -0,0 +1,11 @@
1
+ import { combineServices } from '@aomex/core';
2
+ import { UserService } from './user.service';
3
+
4
+ export const services = combineServices({
5
+ user: UserService,
6
+ });
7
+
8
+ declare module '@aomex/core' {
9
+ type T = typeof services;
10
+ export interface CombinedServices extends T {}
11
+ }
@@ -0,0 +1,12 @@
1
+ import { Service } from '@aomex/core';
2
+ import { db } from './db';
3
+
4
+ export class UserService extends Service {
5
+ findAll() {
6
+ return db.user.findAll();
7
+ }
8
+
9
+ findById(userId: number) {
10
+ return db.user.findUnique({ where: { id: userId } });
11
+ }
12
+ }
@@ -0,0 +1,11 @@
1
+ import { WebApp } from '@aomex/web';
2
+ import { appChain } from './middleware/web.chain';
3
+
4
+ export const app = new WebApp({
5
+ locale: 'zh_CN',
6
+ mount: appChain,
7
+ });
8
+
9
+ app.listen(process.env['PORT'] || 3000, () => {
10
+ console.log('服务已启动');
11
+ });
@@ -0,0 +1,35 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2022",
4
+ "module": "es2022",
5
+ "lib": ["es2022"],
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "moduleResolution": "node",
11
+ "allowUnusedLabels": false,
12
+ "allowUnreachableCode": false,
13
+ "exactOptionalPropertyTypes": false,
14
+ "noFallthroughCasesInSwitch": true,
15
+ "noImplicitOverride": true,
16
+ "noImplicitReturns": true,
17
+ "noPropertyAccessFromIndexSignature": true,
18
+ "noUncheckedIndexedAccess": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "verbatimModuleSyntax": true,
22
+ "allowJs": false,
23
+ "checkJs": false,
24
+ "declaration": false,
25
+ "removeComments": false,
26
+ "rootDir": "./",
27
+ "noEmit": true,
28
+ "importHelpers": false,
29
+ "downlevelIteration": true,
30
+ "noImplicitAny": true,
31
+ "noImplicitThis": true,
32
+ "allowSyntheticDefaultImports": true,
33
+ "resolveJsonModule": true
34
+ }
35
+ }