create-skweb 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +17 -0
- package/.turbo/turbo-check.log +4 -0
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +65 -0
- package/CHANGELOG.md +7 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +199 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +115 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
- package/rollup.config.mjs +71 -0
- package/src/cli.ts +118 -0
- package/src/index.ts +122 -0
- package/templates/cjs/ecosystem.config.js +32 -0
- package/templates/cjs/eslint.config.js +25 -0
- package/templates/cjs/package.json +46 -0
- package/templates/cjs/src/app.js +91 -0
- package/templates/cjs/src/commands/migrate.js +35 -0
- package/templates/cjs/src/commands/seed.js +58 -0
- package/templates/cjs/src/controllers/hello.js +33 -0
- package/templates/cjs/src/controllers/user.js +101 -0
- package/templates/cjs/src/cronActions/cleanup.js +12 -0
- package/templates/cjs/src/cronWorker.js +85 -0
- package/templates/cjs/src/index.js +7 -0
- package/templates/cjs/src/models/SysUser.js +38 -0
- package/templates/cjs/src/seeds/SysUser.json +1 -0
- package/templates/cjs/src/services/database.js +15 -0
- package/templates/cjs/src/utils/config.js +65 -0
- package/templates/cjs/src/utils/logger.js +53 -0
- package/templates/cjs/test/index.js +13 -0
- package/templates/mjs/ecosystem.config.js +32 -0
- package/templates/mjs/eslint.config.js +25 -0
- package/templates/mjs/package.json +46 -0
- package/templates/mjs/src/app.js +97 -0
- package/templates/mjs/src/commands/migrate.js +38 -0
- package/templates/mjs/src/commands/seed.js +63 -0
- package/templates/mjs/src/controllers/hello.js +33 -0
- package/templates/mjs/src/controllers/user.js +101 -0
- package/templates/mjs/src/cronActions/cleanup.js +9 -0
- package/templates/mjs/src/cronWorker.js +91 -0
- package/templates/mjs/src/index.js +8 -0
- package/templates/mjs/src/models/SysUser.js +40 -0
- package/templates/mjs/src/seeds/SysUser.json +1 -0
- package/templates/mjs/src/services/database.js +16 -0
- package/templates/mjs/src/utils/config.js +63 -0
- package/templates/mjs/src/utils/logger.js +52 -0
- package/templates/mjs/test/index.mjs +13 -0
- package/templates/ts/ecosystem.config.js +36 -0
- package/templates/ts/eslint.config.js +17 -0
- package/templates/ts/package.json +57 -0
- package/templates/ts/rollup.config.mjs +39 -0
- package/templates/ts/src/app.ts +96 -0
- package/templates/ts/src/commands/migrate.ts +38 -0
- package/templates/ts/src/commands/seed.ts +63 -0
- package/templates/ts/src/controllers/hello.ts +33 -0
- package/templates/ts/src/controllers/user.ts +101 -0
- package/templates/ts/src/cronActions/cleanup.ts +10 -0
- package/templates/ts/src/cronWorker.ts +90 -0
- package/templates/ts/src/index.ts +8 -0
- package/templates/ts/src/models/SysUser.ts +49 -0
- package/templates/ts/src/seeds/SysUser.json +1 -0
- package/templates/ts/src/services/database.ts +16 -0
- package/templates/ts/src/utils/config.ts +68 -0
- package/templates/ts/src/utils/logger.ts +63 -0
- package/templates/ts/test/index.mjs +13 -0
- package/templates/ts/tsconfig.json +20 -0
- package/test/index.mjs +137 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import commonjs from '@rollup/plugin-commonjs'
|
|
2
|
+
import resolve from '@rollup/plugin-node-resolve'
|
|
3
|
+
import typescript from '@rollup/plugin-typescript'
|
|
4
|
+
import terser from '@rollup/plugin-terser'
|
|
5
|
+
import replace from '@rollup/plugin-replace'
|
|
6
|
+
|
|
7
|
+
const isProduction = process.env.NODE_ENV === 'production'
|
|
8
|
+
|
|
9
|
+
export default [
|
|
10
|
+
{
|
|
11
|
+
input: 'src/index.ts',
|
|
12
|
+
output: [
|
|
13
|
+
{
|
|
14
|
+
file: 'dist/index.js',
|
|
15
|
+
format: 'es',
|
|
16
|
+
sourcemap: true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
file: 'dist/index.cjs',
|
|
20
|
+
format: 'cjs',
|
|
21
|
+
sourcemap: true,
|
|
22
|
+
exports: 'named'
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
plugins: [
|
|
26
|
+
resolve(),
|
|
27
|
+
commonjs(),
|
|
28
|
+
typescript({ tsconfig: './tsconfig.json' }),
|
|
29
|
+
isProduction && terser()
|
|
30
|
+
],
|
|
31
|
+
external: [
|
|
32
|
+
'commander',
|
|
33
|
+
'inquirer',
|
|
34
|
+
'ora',
|
|
35
|
+
'fs-extra',
|
|
36
|
+
'fs',
|
|
37
|
+
'path',
|
|
38
|
+
'child_process',
|
|
39
|
+
'os'
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
input: 'src/cli.ts',
|
|
44
|
+
output: {
|
|
45
|
+
file: 'dist/cli.js',
|
|
46
|
+
format: 'es',
|
|
47
|
+
sourcemap: true,
|
|
48
|
+
banner: '#!/usr/bin/env node'
|
|
49
|
+
},
|
|
50
|
+
plugins: [
|
|
51
|
+
replace({
|
|
52
|
+
'#!/usr/bin/env node': '',
|
|
53
|
+
delimiters: ['', '']
|
|
54
|
+
}),
|
|
55
|
+
resolve(),
|
|
56
|
+
commonjs(),
|
|
57
|
+
typescript({ tsconfig: './tsconfig.json', declaration: false, declarationMap: false }),
|
|
58
|
+
isProduction && terser()
|
|
59
|
+
],
|
|
60
|
+
external: [
|
|
61
|
+
'commander',
|
|
62
|
+
'inquirer',
|
|
63
|
+
'ora',
|
|
64
|
+
'fs-extra',
|
|
65
|
+
'fs',
|
|
66
|
+
'path',
|
|
67
|
+
'child_process',
|
|
68
|
+
'os'
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
]
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import inquirer from 'inquirer'
|
|
5
|
+
import ora from 'ora'
|
|
6
|
+
import {
|
|
7
|
+
createProject,
|
|
8
|
+
installDependencies,
|
|
9
|
+
initGit,
|
|
10
|
+
printBanner,
|
|
11
|
+
printSuccess
|
|
12
|
+
} from './index'
|
|
13
|
+
|
|
14
|
+
async function main() {
|
|
15
|
+
const program = new Command()
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.name('create-skweb')
|
|
19
|
+
.description('Create a new SKWeb project with TypeScript, CJS, or MJS support')
|
|
20
|
+
.argument('[name]', 'Project name')
|
|
21
|
+
.option('--template <type>', 'Template type: ts, mjs, cjs', 'ts')
|
|
22
|
+
.option('--dest <path>', 'Destination directory', '.')
|
|
23
|
+
.option('--skip-install', 'Skip dependency installation')
|
|
24
|
+
.option('--skip-git', 'Skip git initialization')
|
|
25
|
+
.action(async (name, options) => {
|
|
26
|
+
printBanner()
|
|
27
|
+
|
|
28
|
+
if (!name) {
|
|
29
|
+
const answers = await inquirer.prompt([
|
|
30
|
+
{
|
|
31
|
+
type: 'input',
|
|
32
|
+
name: 'name',
|
|
33
|
+
message: 'Enter project name:',
|
|
34
|
+
default: 'my-skweb-app',
|
|
35
|
+
validate: (input: string) => {
|
|
36
|
+
if (!input || input.trim() === '') {
|
|
37
|
+
return 'Please enter a project name'
|
|
38
|
+
}
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: 'list',
|
|
44
|
+
name: 'template',
|
|
45
|
+
message: 'Select project template:',
|
|
46
|
+
choices: [
|
|
47
|
+
{ name: 'TypeScript', value: 'ts' },
|
|
48
|
+
{ name: 'ES Modules (MJS)', value: 'mjs' },
|
|
49
|
+
{ name: 'CommonJS (CJS)', value: 'cjs' }
|
|
50
|
+
],
|
|
51
|
+
default: 'ts'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: 'input',
|
|
55
|
+
name: 'dest',
|
|
56
|
+
message: 'Enter destination directory:',
|
|
57
|
+
default: '.'
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: 'confirm',
|
|
61
|
+
name: 'install',
|
|
62
|
+
message: 'Install dependencies?',
|
|
63
|
+
default: true
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
type: 'confirm',
|
|
67
|
+
name: 'git',
|
|
68
|
+
message: 'Initialize git repository?',
|
|
69
|
+
default: true
|
|
70
|
+
}
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
name = answers.name
|
|
74
|
+
options.template = answers.template
|
|
75
|
+
options.dest = answers.dest
|
|
76
|
+
options.skipInstall = !answers.install
|
|
77
|
+
options.skipGit = !answers.git
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const spinner = ora('Creating project...').start()
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await createProject({
|
|
84
|
+
name,
|
|
85
|
+
template: options.template as 'ts' | 'mjs' | 'cjs',
|
|
86
|
+
dest: options.dest
|
|
87
|
+
})
|
|
88
|
+
spinner.succeed('Project files created')
|
|
89
|
+
|
|
90
|
+
if (!options.skipInstall) {
|
|
91
|
+
spinner.text = 'Installing dependencies...'
|
|
92
|
+
spinner.start()
|
|
93
|
+
await installDependencies(options.dest)
|
|
94
|
+
spinner.succeed('Dependencies installed')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!options.skipGit) {
|
|
98
|
+
spinner.text = 'Initializing git repository...'
|
|
99
|
+
spinner.start()
|
|
100
|
+
await initGit(options.dest)
|
|
101
|
+
spinner.succeed('Git repository initialized')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
spinner.stop()
|
|
105
|
+
|
|
106
|
+
printSuccess(name, options.dest)
|
|
107
|
+
|
|
108
|
+
} catch (error) {
|
|
109
|
+
spinner.fail('Failed to create project')
|
|
110
|
+
console.error(error)
|
|
111
|
+
process.exit(1)
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
await program.parseAsync()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
main().catch(console.error)
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fs from 'fs-extra'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { fileURLToPath } from 'url'
|
|
4
|
+
import { execSync } from 'child_process'
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
|
|
8
|
+
export interface CreateOptions {
|
|
9
|
+
name: string
|
|
10
|
+
description?: string
|
|
11
|
+
template: 'ts' | 'mjs' | 'cjs'
|
|
12
|
+
dest: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function createProject(options: CreateOptions): Promise<void> {
|
|
16
|
+
const { name, description = 'A SKWeb project', template, dest } = options
|
|
17
|
+
|
|
18
|
+
const templateDir = path.join(__dirname, '..', 'templates', template)
|
|
19
|
+
const targetDir = path.resolve(dest)
|
|
20
|
+
|
|
21
|
+
if (await fs.pathExists(targetDir)) {
|
|
22
|
+
if ((await fs.readdir(targetDir)).length > 0) {
|
|
23
|
+
throw new Error(`目标目录 ${targetDir} 不为空`)
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
await fs.mkdirs(targetDir)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const files = await fs.readdir(templateDir, { recursive: true })
|
|
30
|
+
|
|
31
|
+
for (const file of files) {
|
|
32
|
+
const fileName = String(file)
|
|
33
|
+
const srcPath = path.join(templateDir, fileName)
|
|
34
|
+
const stats = await fs.stat(srcPath)
|
|
35
|
+
|
|
36
|
+
if (stats.isDirectory()) {
|
|
37
|
+
await fs.mkdirs(path.join(targetDir, fileName))
|
|
38
|
+
continue
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let content = await fs.readFile(srcPath, 'utf-8')
|
|
42
|
+
|
|
43
|
+
content = content
|
|
44
|
+
.replace(/\{\{name\}\}/g, name)
|
|
45
|
+
.replace(/\{\{description\}\}/g, description)
|
|
46
|
+
|
|
47
|
+
const destPath = path.join(targetDir, fileName)
|
|
48
|
+
await fs.writeFile(destPath, content)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
await fs.mkdirs(path.join(targetDir, 'logs'))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function installDependencies(dest: string): Promise<void> {
|
|
55
|
+
const targetDir = path.resolve(dest)
|
|
56
|
+
|
|
57
|
+
execSync('npm install', {
|
|
58
|
+
cwd: targetDir,
|
|
59
|
+
stdio: 'inherit'
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
execSync('npm install pm2 -g', {
|
|
63
|
+
cwd: targetDir,
|
|
64
|
+
stdio: 'inherit'
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function initGit(dest: string): Promise<void> {
|
|
69
|
+
const targetDir = path.resolve(dest)
|
|
70
|
+
|
|
71
|
+
execSync('git init', {
|
|
72
|
+
cwd: targetDir,
|
|
73
|
+
stdio: 'inherit'
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function printBanner(): void {
|
|
78
|
+
console.log(`
|
|
79
|
+
╔════════════════════════════════════════════════════════════════════╗
|
|
80
|
+
║ Create SKWeb Project ║
|
|
81
|
+
╚════════════════════════════════════════════════════════════════════╝
|
|
82
|
+
`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function printSuccess(name: string, dest: string): void {
|
|
86
|
+
console.log(`
|
|
87
|
+
╔════════════════════════════════════════════════════════════════════╗
|
|
88
|
+
║ 项目创建成功! ║
|
|
89
|
+
╚════════════════════════════════════════════════════════════════════╝
|
|
90
|
+
|
|
91
|
+
项目名称: ${name}
|
|
92
|
+
项目路径: ${path.resolve(dest)}
|
|
93
|
+
|
|
94
|
+
接下来可以执行:
|
|
95
|
+
|
|
96
|
+
cd ${path.basename(path.resolve(dest))}
|
|
97
|
+
|
|
98
|
+
# 开发模式运行
|
|
99
|
+
npm run start:dev
|
|
100
|
+
|
|
101
|
+
# 生产模式运行 (需要先构建)
|
|
102
|
+
npm run build
|
|
103
|
+
npm run start
|
|
104
|
+
|
|
105
|
+
# 查看日志
|
|
106
|
+
npm run logs
|
|
107
|
+
|
|
108
|
+
# 停止服务
|
|
109
|
+
npm run stop
|
|
110
|
+
|
|
111
|
+
# 重启服务
|
|
112
|
+
npm run restart
|
|
113
|
+
|
|
114
|
+
项目特性:
|
|
115
|
+
✅ TypeScript/MJS/CJS 支持
|
|
116
|
+
✅ @dotenvx/dotenvx 环境变量管理
|
|
117
|
+
✅ PM2 进程管理
|
|
118
|
+
✅ SKWeb Express 集成
|
|
119
|
+
✅ ESLint 代码检查
|
|
120
|
+
✅ Mocha 测试框架
|
|
121
|
+
`)
|
|
122
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
apps: [
|
|
3
|
+
{
|
|
4
|
+
name: '{{name}}-web',
|
|
5
|
+
script: 'src/index.js',
|
|
6
|
+
instances: 'max',
|
|
7
|
+
exec_mode: 'cluster',
|
|
8
|
+
env: {
|
|
9
|
+
NODE_ENV: 'production',
|
|
10
|
+
PORT: 3000
|
|
11
|
+
},
|
|
12
|
+
max_memory_restart: '512M',
|
|
13
|
+
error_file: 'logs/web-err.log',
|
|
14
|
+
out_file: 'logs/web-out.log',
|
|
15
|
+
log_date_format: 'YYYY-MM-DD HH:mm:ss Z'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: '{{name}}-cron',
|
|
19
|
+
script: 'src/cronWorker.js',
|
|
20
|
+
instances: 1,
|
|
21
|
+
exec_mode: 'fork',
|
|
22
|
+
autorestart: true,
|
|
23
|
+
env: {
|
|
24
|
+
NODE_ENV: 'production'
|
|
25
|
+
},
|
|
26
|
+
max_memory_restart: '512M',
|
|
27
|
+
error_file: 'logs/cron-err.log',
|
|
28
|
+
out_file: 'logs/cron-out.log',
|
|
29
|
+
log_date_format: 'YYYY-MM-DD HH:mm:ss Z'
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const js = require('@eslint/js')
|
|
2
|
+
|
|
3
|
+
module.exports = [
|
|
4
|
+
{ ignores: ['dist', 'node_modules', 'logs', 'test'] },
|
|
5
|
+
js.configs.recommended,
|
|
6
|
+
{
|
|
7
|
+
languageOptions: {
|
|
8
|
+
ecmaVersion: 2022,
|
|
9
|
+
sourceType: 'commonjs',
|
|
10
|
+
globals: {
|
|
11
|
+
process: 'readonly',
|
|
12
|
+
console: 'readonly',
|
|
13
|
+
Buffer: 'readonly',
|
|
14
|
+
__dirname: 'readonly',
|
|
15
|
+
__filename: 'readonly',
|
|
16
|
+
require: 'readonly',
|
|
17
|
+
module: 'readonly',
|
|
18
|
+
exports: 'writable'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
rules: {
|
|
22
|
+
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "{{description}}",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "pm2 start ecosystem.config.js",
|
|
8
|
+
"stop": "pm2 stop all",
|
|
9
|
+
"restart": "pm2 restart all",
|
|
10
|
+
"delete": "pm2 delete all",
|
|
11
|
+
"logs": "pm2 logs",
|
|
12
|
+
"web:dev": "npx dotenvx run -- node --watch src/index.js",
|
|
13
|
+
"cron:dev": "npx dotenvx run -- node --watch src/cronWorker.js",
|
|
14
|
+
"seed": "npx dotenvx run -- node src/commands/seed.js",
|
|
15
|
+
"migrate": "npx dotenvx run -- node src/commands/migrate.js",
|
|
16
|
+
"build": "cp -r src dist",
|
|
17
|
+
"lint": "eslint --fix --ext .js src",
|
|
18
|
+
"test": "npx dotenvx run -- mocha test/**/*.js",
|
|
19
|
+
"clean": "rm -rf dist",
|
|
20
|
+
"clean:temp": "rm -rf .rollup.cache"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@dotenvx/dotenvx": "^1.71.0",
|
|
24
|
+
"http-errors": "^2.0.0",
|
|
25
|
+
"skweb-express": "^1.0.0",
|
|
26
|
+
"skweb-express-jwt": "^1.0.0",
|
|
27
|
+
"skweb-express-logger": "^1.0.0",
|
|
28
|
+
"skweb-sequelize": "^1.0.0",
|
|
29
|
+
"skweb-redis": "^1.0.0",
|
|
30
|
+
"skweb-cron": "^1.0.0",
|
|
31
|
+
"skweb-framework": "^1.0.0",
|
|
32
|
+
"skweb-plugin": "^1.0.0",
|
|
33
|
+
"skweb-util": "^1.0.0",
|
|
34
|
+
"winston": "^3.17.0",
|
|
35
|
+
"sequelize": "^6.37.7"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"chai": "^6.2.1",
|
|
39
|
+
"mocha": "^11.7.5",
|
|
40
|
+
"eslint": "^9.39.1",
|
|
41
|
+
"@eslint/js": "^9.39.1"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20.18.1"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require('dotenv/config')
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const express = require('skweb-express')
|
|
5
|
+
const expressLogger = require('skweb-express-logger').default || require('skweb-express-logger')
|
|
6
|
+
const { WebFramework } = require('skweb-framework')
|
|
7
|
+
const { logger } = require('./utils/logger.js')
|
|
8
|
+
const { checkRequiredEnv } = require('./utils/config.js')
|
|
9
|
+
|
|
10
|
+
async function bootstrap() {
|
|
11
|
+
logger.info('[app] Initializing web process...')
|
|
12
|
+
|
|
13
|
+
if (!checkRequiredEnv()) {
|
|
14
|
+
logger.error('[app] Configuration validation failed, exiting...')
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const framework = new WebFramework({
|
|
19
|
+
db: {
|
|
20
|
+
host: process.env.DB_HOST || '127.0.0.1',
|
|
21
|
+
port: Number(process.env.DB_PORT) || 3306,
|
|
22
|
+
username: process.env.DB_USER || 'root',
|
|
23
|
+
password: process.env.DB_PASS || '',
|
|
24
|
+
database: process.env.DB_NAME || 'test-project',
|
|
25
|
+
dialect: process.env.DB_DIALECT || 'mysql',
|
|
26
|
+
charset: process.env.DB_CHARSET || 'utf8mb4',
|
|
27
|
+
underscored: true,
|
|
28
|
+
logging: process.env.DEBUG_DB === 'true' ? (msg) => logger.debug(msg) : false
|
|
29
|
+
},
|
|
30
|
+
redis: {
|
|
31
|
+
host: process.env.REDIS_HOST || '127.0.0.1',
|
|
32
|
+
port: Number(process.env.REDIS_PORT) || 6379,
|
|
33
|
+
password: process.env.REDIS_PASSWORD || undefined
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
await framework.runPluginBeforeSetup()
|
|
38
|
+
await framework.setupModels(path.join(__dirname, './models'))
|
|
39
|
+
await framework.loadPluginModels()
|
|
40
|
+
await framework.runPluginAfterSetup()
|
|
41
|
+
|
|
42
|
+
const app = framework.createApp()
|
|
43
|
+
|
|
44
|
+
app.disable('x-powered-by')
|
|
45
|
+
app.disable('etag')
|
|
46
|
+
|
|
47
|
+
app.set('trust proxy', true)
|
|
48
|
+
|
|
49
|
+
app.set('wrap response', true)
|
|
50
|
+
app.setOkCode(0)
|
|
51
|
+
app.setOkMessage('success')
|
|
52
|
+
|
|
53
|
+
app.setJWT('default', {
|
|
54
|
+
secret: process.env.JWT_SECRET || 'please-change-this-in-production',
|
|
55
|
+
algorithms: ['HS256'],
|
|
56
|
+
sign: { expiresIn: process.env.JWT_EXPIRES_IN || '7d' },
|
|
57
|
+
requestProperty: 'resolvedToken'
|
|
58
|
+
})
|
|
59
|
+
app.setJwtHintHeader('JwtHint')
|
|
60
|
+
|
|
61
|
+
app.use(expressLogger())
|
|
62
|
+
app.use(express.static(path.join(__dirname, '..', 'public')))
|
|
63
|
+
|
|
64
|
+
await framework.loadControllers(path.join(__dirname, './controllers'))
|
|
65
|
+
await framework.loadPluginControllers()
|
|
66
|
+
|
|
67
|
+
framework.start(Number(process.env.PORT) || 3000)
|
|
68
|
+
|
|
69
|
+
logger.info('[app] Initialization complete (web process)')
|
|
70
|
+
|
|
71
|
+
process.on('SIGINT', async () => {
|
|
72
|
+
logger.info('[app] Received SIGINT, shutting down gracefully...')
|
|
73
|
+
await framework.stop()
|
|
74
|
+
process.exit(0)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
process.on('SIGTERM', async () => {
|
|
78
|
+
logger.info('[app] Received SIGTERM, shutting down gracefully...')
|
|
79
|
+
await framework.stop()
|
|
80
|
+
process.exit(0)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (require.main === module) {
|
|
85
|
+
bootstrap().catch((err) => {
|
|
86
|
+
logger.error('[app] Fatal error:', err)
|
|
87
|
+
process.exit(1)
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = { bootstrap }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require('dotenv/config')
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const { Database } = require('skweb-sequelize')
|
|
5
|
+
const { logger } = require('../utils/logger.js')
|
|
6
|
+
|
|
7
|
+
async function runMigrate() {
|
|
8
|
+
logger.info('[migrate] Running database migrations...')
|
|
9
|
+
|
|
10
|
+
const db = new Database({
|
|
11
|
+
host: process.env.DB_HOST || '127.0.0.1',
|
|
12
|
+
port: Number(process.env.DB_PORT) || 3306,
|
|
13
|
+
username: process.env.DB_USER || 'root',
|
|
14
|
+
password: process.env.DB_PASS || '',
|
|
15
|
+
database: process.env.DB_NAME || 'test-project',
|
|
16
|
+
dialect: process.env.DB_DIALECT || 'mysql',
|
|
17
|
+
charset: process.env.DB_CHARSET || 'utf8mb4',
|
|
18
|
+
underscored: true,
|
|
19
|
+
logging: process.env.DEBUG_DB === 'true' ? (msg) => logger.debug(msg) : false
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
await db.loadModelsDir(path.join(__dirname, '..', 'models'))
|
|
23
|
+
db.associateAllModels()
|
|
24
|
+
await db.sequelize.sync({ alter: true })
|
|
25
|
+
logger.info('[migrate] Database schema synced')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (require.main === module) {
|
|
29
|
+
runMigrate().catch((err) => {
|
|
30
|
+
logger.error('[migrate] Fatal error:', err)
|
|
31
|
+
process.exit(1)
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = { runMigrate }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require('dotenv/config')
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const { Database } = require('skweb-sequelize')
|
|
6
|
+
const { logger } = require('../utils/logger.js')
|
|
7
|
+
|
|
8
|
+
async function runSeed() {
|
|
9
|
+
logger.info('[seed] Initializing database with seed data...')
|
|
10
|
+
|
|
11
|
+
const db = new Database({
|
|
12
|
+
host: process.env.DB_HOST || '127.0.0.1',
|
|
13
|
+
port: Number(process.env.DB_PORT) || 3306,
|
|
14
|
+
username: process.env.DB_USER || 'root',
|
|
15
|
+
password: process.env.DB_PASS || '',
|
|
16
|
+
database: process.env.DB_NAME || 'test-project',
|
|
17
|
+
dialect: process.env.DB_DIALECT || 'mysql',
|
|
18
|
+
charset: process.env.DB_CHARSET || 'utf8mb4',
|
|
19
|
+
underscored: true,
|
|
20
|
+
logging: process.env.DEBUG_DB === 'true' ? (msg) => logger.debug(msg) : false
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
await db.loadModelsDir(path.join(__dirname, '..', 'models'))
|
|
24
|
+
db.associateAllModels()
|
|
25
|
+
|
|
26
|
+
const seedsDir = path.join(__dirname, '..', 'seeds')
|
|
27
|
+
if (!fs.existsSync(seedsDir)) {
|
|
28
|
+
logger.warn('[seed] No seeds directory found')
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const files = fs.readdirSync(seedsDir)
|
|
33
|
+
for (const file of files) {
|
|
34
|
+
if (!file.endsWith('.json')) continue
|
|
35
|
+
const modelName = path.basename(file, '.json')
|
|
36
|
+
const Model = db.sequelize.models[modelName]
|
|
37
|
+
if (!Model) {
|
|
38
|
+
logger.warn(`[seed] Model ${modelName} not found`)
|
|
39
|
+
continue
|
|
40
|
+
}
|
|
41
|
+
const data = JSON.parse(fs.readFileSync(path.join(seedsDir, file), 'utf-8'))
|
|
42
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
43
|
+
await Model.bulkCreate(data, { ignoreDuplicates: true })
|
|
44
|
+
logger.info(`[seed] Seeded ${modelName} with ${data.length} records`)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
logger.info('[seed] Database initialization complete')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (require.main === module) {
|
|
52
|
+
runSeed().catch((err) => {
|
|
53
|
+
logger.error('[seed] Fatal error:', err)
|
|
54
|
+
process.exit(1)
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { runSeed }
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module.exports = [
|
|
2
|
+
{
|
|
3
|
+
method: 'get',
|
|
4
|
+
path: '/',
|
|
5
|
+
async handler() {
|
|
6
|
+
return {
|
|
7
|
+
message: 'Welcome to SKWeb!',
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
timestamp: new Date().toISOString()
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
method: 'get',
|
|
15
|
+
path: '/health',
|
|
16
|
+
async handler() {
|
|
17
|
+
return {
|
|
18
|
+
status: 'ok',
|
|
19
|
+
timestamp: new Date().toISOString()
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
method: 'post',
|
|
25
|
+
path: '/echo',
|
|
26
|
+
async handler(req) {
|
|
27
|
+
return {
|
|
28
|
+
message: 'Echo received',
|
|
29
|
+
data: req.body
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
]
|