create-skweb 2.1.0 → 3.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.
@@ -20,27 +20,27 @@
20
20
  "clean:temp": "rm -rf .rollup.cache"
21
21
  },
22
22
  "dependencies": {
23
- "@dotenvx/dotenvx": "^1.71.0",
24
- "http-errors": "^2.0.0",
25
- "skweb-express": "^1.1.0",
26
- "skweb-express-jwt": "^2.0.0",
27
- "skweb-express-logger": "^1.1.0",
28
- "skweb-sequelize": "^1.1.0",
29
- "skweb-redis": "^1.1.0",
30
- "skweb-cron": "^1.1.0",
31
- "skweb-framework": "^1.1.0",
32
- "skweb-plugin": "^1.1.0",
33
- "skweb-util": "^1.1.0",
34
- "winston": "^3.17.0",
35
- "sequelize": "^6.37.7",
36
- "swagger-jsdoc": "^6.2.8",
23
+ "@dotenvx/dotenvx": "^1.75.1",
24
+ "http-errors": "^2.0.1",
25
+ "skweb-express": "^2.0.0",
26
+ "skweb-express-jwt": "^3.0.0",
27
+ "skweb-express-logger": "^2.0.0",
28
+ "skweb-sequelize": "^2.0.0",
29
+ "skweb-redis": "^2.0.0",
30
+ "skweb-cron": "^2.0.0",
31
+ "skweb-framework": "^2.0.0",
32
+ "skweb-plugin": "^2.0.0",
33
+ "skweb-util": "^2.0.0",
34
+ "winston": "^3.19.0",
35
+ "sequelize": "^6.37.8",
36
+ "swagger-jsdoc": "^6.3.0",
37
37
  "swagger-ui-express": "^5.0.1"
38
38
  },
39
39
  "devDependencies": {
40
- "chai": "^6.2.1",
41
- "mocha": "^11.7.5",
42
- "eslint": "^9.39.1",
43
- "@eslint/js": "^9.39.1"
40
+ "chai": "^6.2.2",
41
+ "mocha": "^11.7.6",
42
+ "eslint": "^10.5.0",
43
+ "@eslint/js": "^10.0.1"
44
44
  },
45
45
  "engines": {
46
46
  "node": ">=20.18.1"
@@ -3,7 +3,7 @@ import 'dotenv/config'
3
3
  import path from 'path'
4
4
  import { fileURLToPath } from 'url'
5
5
  import express from 'skweb-express'
6
- import expressLogger from 'skweb-express-logger'
6
+ import expressLogger, { errorHandler as expressErrorHandler } from 'skweb-express-logger'
7
7
  import swaggerUi from 'swagger-ui-express'
8
8
  import logger from './utils/logger.js'
9
9
  import { checkRequiredEnv } from './utils/config.js'
@@ -135,16 +135,14 @@ async function bootstrap() {
135
135
 
136
136
  logger.info('[app] Initialization complete (web process)')
137
137
 
138
- process.on('SIGINT', async () => {
139
- logger.info('[app] Received SIGINT, shutting down gracefully...')
140
- await framework.stop()
141
- process.exit(0)
138
+ // 未捕获异常:打印堆栈后直接退出。OS / 进程管理器负责回收资源。
139
+ process.on('uncaughtException', (err) => {
140
+ logger.error(`[app] uncaughtException: ${err.stack || err.message}`)
141
+ process.exit(1)
142
142
  })
143
-
144
- process.on('SIGTERM', async () => {
145
- logger.info('[app] Received SIGTERM, shutting down gracefully...')
146
- await framework.stop()
147
- process.exit(0)
143
+ process.on('unhandledRejection', (reason) => {
144
+ logger.error(`[app] unhandledRejection: ${reason instanceof Error ? reason.stack : String(reason)}`)
145
+ process.exit(1)
148
146
  })
149
147
  }
150
148
 
@@ -67,16 +67,14 @@ async function startCronWorker() {
67
67
  framework.start()
68
68
  logger.info('[cron-worker] Cron worker started')
69
69
 
70
- process.on('SIGINT', async () => {
71
- logger.info('[cron-worker] Received SIGINT, shutting down...')
72
- await framework.stop()
73
- process.exit(0)
70
+ // 未捕获异常:打印堆栈后直接退出。OS / 进程管理器负责回收资源。
71
+ process.on('uncaughtException', (err) => {
72
+ logger.error(`[cron-worker] uncaughtException: ${err.stack || err.message}`)
73
+ process.exit(1)
74
74
  })
75
-
76
- process.on('SIGTERM', async () => {
77
- logger.info('[cron-worker] Received SIGTERM, shutting down...')
78
- await framework.stop()
79
- process.exit(0)
75
+ process.on('unhandledRejection', (reason) => {
76
+ logger.error(`[cron-worker] unhandledRejection: ${reason instanceof Error ? reason.stack : String(reason)}`)
77
+ process.exit(1)
80
78
  })
81
79
  }
82
80
 
@@ -22,41 +22,41 @@
22
22
  "clean:temp": "rm -rf .rollup.cache"
23
23
  },
24
24
  "dependencies": {
25
- "@dotenvx/dotenvx": "^1.71.0",
26
- "http-errors": "^2.0.0",
27
- "skweb-express": "^1.1.0",
28
- "skweb-express-jwt": "^2.0.0",
29
- "skweb-express-logger": "^1.1.0",
30
- "skweb-sequelize": "^1.1.0",
31
- "skweb-redis": "^1.1.0",
32
- "skweb-cron": "^1.1.0",
33
- "skweb-framework": "^1.1.0",
34
- "skweb-plugin": "^1.1.0",
35
- "skweb-util": "^1.1.0",
36
- "winston": "^3.17.0",
37
- "sequelize": "^6.37.7",
38
- "swagger-jsdoc": "^6.2.8",
25
+ "@dotenvx/dotenvx": "^1.75.1",
26
+ "http-errors": "^2.0.1",
27
+ "skweb-express": "^2.0.0",
28
+ "skweb-express-jwt": "^3.0.0",
29
+ "skweb-express-logger": "^2.0.0",
30
+ "skweb-sequelize": "^2.0.0",
31
+ "skweb-redis": "^2.0.0",
32
+ "skweb-cron": "^2.0.0",
33
+ "skweb-framework": "^2.0.0",
34
+ "skweb-plugin": "^2.0.0",
35
+ "skweb-util": "^2.0.0",
36
+ "winston": "^3.19.0",
37
+ "sequelize": "^6.37.8",
38
+ "swagger-jsdoc": "^6.3.0",
39
39
  "swagger-ui-express": "^5.0.1"
40
40
  },
41
41
  "devDependencies": {
42
- "@types/node": "^25.0.1",
42
+ "@types/node": "^26.0.0",
43
43
  "@types/mocha": "^10.0.10",
44
- "@types/http-errors": "^2.0.4",
44
+ "@types/http-errors": "^2.0.5",
45
45
  "@types/swagger-jsdoc": "^6.0.4",
46
46
  "@types/swagger-ui-express": "^4.1.8",
47
- "chai": "^6.2.1",
48
- "mocha": "^11.7.5",
47
+ "chai": "^6.2.2",
48
+ "mocha": "^11.7.6",
49
49
  "tsx": "^4.22.4",
50
- "typescript": "^5.9.3",
50
+ "typescript": "^6.0.3",
51
51
  "tslib": "^2.8.1",
52
- "rollup": "^2.79.2",
52
+ "rollup": "^4.62.2",
53
53
  "@rollup/plugin-typescript": "^12.3.0",
54
54
  "@rollup/plugin-json": "^6.1.0",
55
55
  "@rollup/plugin-node-resolve": "^16.0.3",
56
- "@rollup/plugin-commonjs": "^29.0.0",
57
- "@rollup/plugin-terser": "^0.4.4",
58
- "eslint": "^9.39.1",
59
- "typescript-eslint": "^8.49.0"
56
+ "@rollup/plugin-commonjs": "^29.0.3",
57
+ "@rollup/plugin-terser": "^1.0.0",
58
+ "eslint": "^10.5.0",
59
+ "typescript-eslint": "^8.62.0"
60
60
  },
61
61
  "engines": {
62
62
  "node": ">=20.18.1"
@@ -35,6 +35,8 @@ export default {
35
35
  'express',
36
36
  'sequelize',
37
37
  'ioredis',
38
+ 'swagger-ui-express',
39
+ 'swagger-jsdoc',
38
40
  'path',
39
41
  'fs'
40
42
  ]
@@ -3,7 +3,7 @@ import 'dotenv/config'
3
3
  import path from 'path'
4
4
  import { fileURLToPath } from 'url'
5
5
  import express from 'skweb-express'
6
- import expressLogger from 'skweb-express-logger'
6
+ import expressLogger, { errorHandler as expressErrorHandler } from 'skweb-express-logger'
7
7
  import { WebFramework } from 'skweb-framework'
8
8
  import type { JWTOptions } from 'skweb-express-jwt'
9
9
  import swaggerUi from 'swagger-ui-express'
@@ -142,16 +142,15 @@ async function bootstrap(): Promise<void> {
142
142
 
143
143
  logger.info('[app] Initialization complete (web process)')
144
144
 
145
- process.on('SIGINT', async () => {
146
- logger.info('[app] Received SIGINT, shutting down gracefully...')
147
- await framework.stop()
148
- process.exit(0)
145
+ // 未捕获异常:打印堆栈后直接退出。OS / 进程管理器(pm2 / docker / k8s)
146
+ // 负责回收 socket / fd,框架不在此路径上做资源清理——简单可靠。
147
+ process.on('uncaughtException', (err) => {
148
+ logger.error(`[app] uncaughtException: ${err.stack || err.message}`)
149
+ process.exit(1)
149
150
  })
150
-
151
- process.on('SIGTERM', async () => {
152
- logger.info('[app] Received SIGTERM, shutting down gracefully...')
153
- await framework.stop()
154
- process.exit(0)
151
+ process.on('unhandledRejection', (reason) => {
152
+ logger.error(`[app] unhandledRejection: ${reason instanceof Error ? reason.stack : String(reason)}`)
153
+ process.exit(1)
155
154
  })
156
155
  }
157
156
 
@@ -66,16 +66,14 @@ async function startCronWorker(): Promise<void> {
66
66
  framework.start()
67
67
  logger.info('[cron-worker] Cron worker started')
68
68
 
69
- process.on('SIGINT', async () => {
70
- logger.info('[cron-worker] Received SIGINT, shutting down...')
71
- await framework.stop()
72
- process.exit(0)
69
+ // 未捕获异常:打印堆栈后直接退出。OS / 进程管理器负责回收资源。
70
+ process.on('uncaughtException', (err) => {
71
+ logger.error(`[cron-worker] uncaughtException: ${err.stack || err.message}`)
72
+ process.exit(1)
73
73
  })
74
-
75
- process.on('SIGTERM', async () => {
76
- logger.info('[cron-worker] Received SIGTERM, shutting down...')
77
- await framework.stop()
78
- process.exit(0)
74
+ process.on('unhandledRejection', (reason) => {
75
+ logger.error(`[cron-worker] unhandledRejection: ${reason instanceof Error ? reason.stack : String(reason)}`)
76
+ process.exit(1)
79
77
  })
80
78
  }
81
79
 
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ES2020",
3
+ "target": "ES2022",
4
4
  "module": "ESNext",
5
- "lib": ["ES2020"],
6
- "moduleResolution": "Node",
5
+ "lib": ["ES2022"],
6
+ "moduleResolution": "Bundler",
7
7
  "strict": true,
8
8
  "esModuleInterop": true,
9
9
  "skipLibCheck": true,
@@ -12,8 +12,7 @@
12
12
  "declaration": true,
13
13
  "sourceMap": true,
14
14
  "rootDir": "src",
15
- "outDir": "dist",
16
- "baseUrl": "."
15
+ "outDir": "dist"
17
16
  },
18
17
  "include": ["src/**/*.ts"],
19
18
  "exclude": ["node_modules", "dist", "test"]
package/test/index.mjs CHANGED
@@ -8,6 +8,12 @@ import { createProject, printBanner, printSuccess } from '../dist/index.js'
8
8
  const __filename = fileURLToPath(import.meta.url)
9
9
  const __dirname = path.dirname(__filename)
10
10
 
11
+ // helper: createProject 把项目放在 <dest>/<name> 下,
12
+ // 测试断言用的所有路径都要走 <dest>/<name>。
13
+ function projectPath(tmpDir, name = 'my-app') {
14
+ return path.join(tmpDir, name)
15
+ }
16
+
11
17
  describe('create-skweb', () => {
12
18
  describe('createProject()', () => {
13
19
  let tmpDir
@@ -21,42 +27,47 @@ describe('create-skweb', () => {
21
27
  })
22
28
 
23
29
  it('should create TypeScript project from template', async () => {
30
+ const root = projectPath(tmpDir)
24
31
  await createProject({
25
32
  name: 'my-app',
26
33
  template: 'ts',
27
34
  dest: tmpDir
28
35
  })
29
36
 
30
- expect(fs.existsSync(path.join(tmpDir, 'package.json'))).to.be.true
31
- expect(fs.existsSync(path.join(tmpDir, 'src', 'app.ts'))).to.be.true
32
- expect(fs.existsSync(path.join(tmpDir, 'src', 'utils', 'logger.ts'))).to.be.true
37
+ expect(fs.existsSync(path.join(root, 'package.json'))).to.be.true
38
+ expect(fs.existsSync(path.join(root, 'src', 'app.ts'))).to.be.true
39
+ expect(fs.existsSync(path.join(root, 'src', 'utils', 'logger.ts'))).to.be.true
33
40
  })
34
41
 
35
42
  it('should create MJS project from template', async () => {
43
+ const root = projectPath(tmpDir)
36
44
  await createProject({
37
45
  name: 'my-app',
38
46
  template: 'mjs',
39
47
  dest: tmpDir
40
48
  })
41
49
 
42
- expect(fs.existsSync(path.join(tmpDir, 'package.json'))).to.be.true
43
- expect(fs.existsSync(path.join(tmpDir, 'src', 'app.js'))).to.be.true
50
+ expect(fs.existsSync(path.join(root, 'package.json'))).to.be.true
51
+ expect(fs.existsSync(path.join(root, 'src', 'app.js'))).to.be.true
44
52
  })
45
53
 
46
54
  it('should create CJS project from template', async () => {
55
+ const root = projectPath(tmpDir)
47
56
  await createProject({
48
57
  name: 'my-app',
49
58
  template: 'cjs',
50
59
  dest: tmpDir
51
60
  })
52
61
 
53
- expect(fs.existsSync(path.join(tmpDir, 'package.json'))).to.be.true
54
- expect(fs.existsSync(path.join(tmpDir, 'src', 'app.js'))).to.be.true
62
+ expect(fs.existsSync(path.join(root, 'package.json'))).to.be.true
63
+ expect(fs.existsSync(path.join(root, 'src', 'app.js'))).to.be.true
55
64
  })
56
65
 
57
66
  it('should reject non-empty destination directory', async () => {
58
- // tmpDir 中创建一个文件
59
- fs.writeFileSync(path.join(tmpDir, 'existing.txt'), 'x')
67
+ // 在目标项目目录 (tmpDir/my-app) 里创建一个文件,createProject 应拒绝
68
+ const target = projectPath(tmpDir)
69
+ fs.mkdirsSync(target)
70
+ fs.writeFileSync(path.join(target, 'existing.txt'), 'x')
60
71
 
61
72
  try {
62
73
  await createProject({
@@ -79,7 +90,7 @@ describe('create-skweb', () => {
79
90
  template,
80
91
  dest: tmpDir
81
92
  })
82
- const pkg = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'))
93
+ const pkg = JSON.parse(fs.readFileSync(path.join(projectPath(tmpDir), 'package.json'), 'utf-8'))
83
94
  expect(pkg.dependencies.winston, `${template} should have winston dep`).to.exist
84
95
  }
85
96
  })
@@ -93,7 +104,7 @@ describe('create-skweb', () => {
93
104
  template,
94
105
  dest: tmpDir
95
106
  })
96
- const pkg = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'))
107
+ const pkg = JSON.parse(fs.readFileSync(path.join(projectPath(tmpDir), 'package.json'), 'utf-8'))
97
108
  expect(pkg.dependencies['@dotenvx/dotenvx'], `${template} should have dotenvx`).to.exist
98
109
  }
99
110
  })
@@ -107,7 +118,7 @@ describe('create-skweb', () => {
107
118
  template,
108
119
  dest: tmpDir
109
120
  })
110
- expect(fs.existsSync(path.join(tmpDir, 'ecosystem.config.js')), `${template} should have pm2 ecosystem`).to.be.true
121
+ expect(fs.existsSync(path.join(projectPath(tmpDir), 'ecosystem.config.js')), `${template} should have pm2 ecosystem`).to.be.true
111
122
  }
112
123
  })
113
124
 
@@ -117,7 +128,7 @@ describe('create-skweb', () => {
117
128
  template: 'ts',
118
129
  dest: tmpDir
119
130
  })
120
- const pkg = JSON.parse(fs.readFileSync(path.join(tmpDir, 'package.json'), 'utf-8'))
131
+ const pkg = JSON.parse(fs.readFileSync(path.join(projectPath(tmpDir, 'my-custom-app'), 'package.json'), 'utf-8'))
121
132
  expect(pkg.name).to.equal('my-custom-app')
122
133
  expect(pkg.name).to.not.match(/\{\{name\}\}/)
123
134
  })
package/tsconfig.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "ES2020",
3
+ "target": "ES2022",
4
4
  "module": "ESNext",
5
- "lib": ["ES2020"],
6
- "moduleResolution": "Node",
5
+ "lib": ["ES2022"],
6
+ "moduleResolution": "Bundler",
7
7
  "strict": true,
8
8
  "esModuleInterop": true,
9
9
  "skipLibCheck": true,
@@ -14,7 +14,6 @@
14
14
  "sourceMap": true,
15
15
  "rootDir": "src",
16
16
  "outDir": "dist",
17
- "baseUrl": ".",
18
17
  "types": ["node"]
19
18
  },
20
19
  "include": ["src/**/*.ts"],
package/dist/cli.cjs DELETED
@@ -1,261 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict';
4
-
5
- var commander = require('commander');
6
- var inquirer = require('inquirer');
7
- var ora = require('ora');
8
- var fs = require('fs-extra');
9
- var path = require('path');
10
- var url = require('url');
11
- var child_process = require('child_process');
12
-
13
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
-
15
- var inquirer__default = /*#__PURE__*/_interopDefaultLegacy(inquirer);
16
- var ora__default = /*#__PURE__*/_interopDefaultLegacy(ora);
17
- var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
18
- var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
19
-
20
- const __dirname$1 = path__default["default"].dirname(url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.src || new URL('cli.cjs', document.baseURI).href))));
21
- async function createProject(options) {
22
- const { name, description = 'A SKWeb project', template, dest } = options;
23
- const auth = options.auth ?? 'static';
24
- const templateDir = path__default["default"].join(__dirname$1, '..', 'templates', template);
25
- const baseDir = path__default["default"].resolve(dest);
26
- const targetDir = path__default["default"].join(baseDir, name);
27
- if (await fs__default["default"].pathExists(targetDir)) {
28
- if ((await fs__default["default"].readdir(targetDir)).length > 0) {
29
- throw new Error(`目标目录 ${targetDir} 不为空`);
30
- }
31
- }
32
- else {
33
- await fs__default["default"].mkdirs(targetDir);
34
- }
35
- const files = await fs__default["default"].readdir(templateDir, { recursive: true });
36
- for (const file of files) {
37
- const fileName = String(file);
38
- const srcPath = path__default["default"].join(templateDir, fileName);
39
- const stats = await fs__default["default"].stat(srcPath);
40
- if (stats.isDirectory()) {
41
- await fs__default["default"].mkdirs(path__default["default"].join(targetDir, fileName));
42
- continue;
43
- }
44
- let content = await fs__default["default"].readFile(srcPath, 'utf-8');
45
- content = content
46
- .replace(/\{\{name\}\}/g, name)
47
- .replace(/\{\{description\}\}/g, description)
48
- .replace(/\{\{auth\}\}/g, auth);
49
- const destPath = path__default["default"].join(targetDir, fileName);
50
- await fs__default["default"].writeFile(destPath, content);
51
- }
52
- await fs__default["default"].mkdirs(path__default["default"].join(targetDir, 'logs'));
53
- }
54
- async function installDependencies(dest, name) {
55
- const targetDir = name ? path__default["default"].join(path__default["default"].resolve(dest), name) : path__default["default"].resolve(dest);
56
- child_process.execSync('npm install', {
57
- cwd: targetDir,
58
- stdio: 'inherit'
59
- });
60
- child_process.execSync('npm install pm2 -g', {
61
- cwd: targetDir,
62
- stdio: 'inherit'
63
- });
64
- }
65
- async function initGit(dest, name) {
66
- const targetDir = name ? path__default["default"].join(path__default["default"].resolve(dest), name) : path__default["default"].resolve(dest);
67
- child_process.execSync('git init', {
68
- cwd: targetDir,
69
- stdio: 'inherit'
70
- });
71
- }
72
- function printBanner() {
73
- console.log(`
74
- ╔════════════════════════════════════════════════════════════════════╗
75
- ║ Create SKWeb Project ║
76
- ╚════════════════════════════════════════════════════════════════════╝
77
- `);
78
- }
79
- function printSuccess(name, dest) {
80
- const projectPath = path__default["default"].join(path__default["default"].resolve(dest), name);
81
- console.log(`
82
- ╔════════════════════════════════════════════════════════════════════╗
83
- ║ 项目创建成功! ║
84
- ╚════════════════════════════════════════════════════════════════════╝
85
-
86
- 项目名称: ${name}
87
- 项目路径: ${projectPath}
88
-
89
- 接下来可以执行:
90
-
91
- cd ${name}
92
-
93
- # 复制环境变量模板并按需修改
94
- cp .env.example .env
95
-
96
- # 开发模式运行
97
- npm run start:dev
98
-
99
- # 生产模式运行 (需要先构建)
100
- npm run build
101
- npm run start
102
-
103
- # 查看日志
104
- npm run logs
105
-
106
- # 停止服务
107
- npm run stop
108
-
109
- # 重启服务
110
- npm run restart
111
-
112
- 项目特性:
113
- ✅ TypeScript/MJS/CJS 支持
114
- ✅ @dotenvx/dotenvx 环境变量管理
115
- ✅ PM2 进程管理
116
- ✅ SKWeb Express 集成
117
- ✅ Keycloak/JWKS 鉴权 (可选)
118
- ✅ ESLint 代码检查
119
- ✅ Mocha 测试框架
120
- `);
121
- }
122
-
123
- async function main() {
124
- const program = new commander.Command();
125
- program
126
- .name('create-skweb')
127
- .description('Create a new SKWeb project with TypeScript, CJS, or MJS support')
128
- .argument('[name]', 'Project name')
129
- .option('--template <type>', 'Template type: ts, mjs, cjs', 'ts')
130
- .option('--dest <path>', 'Destination directory', '.')
131
- .option('--auth <type>', 'Auth provider: static (HS256) or jwks (Keycloak/Auth0)', 'static')
132
- .option('--skip-install', 'Skip dependency installation')
133
- .option('--skip-git', 'Skip git initialization')
134
- .action(async (name, options) => {
135
- printBanner();
136
- // 只要没有传 --no-interactive 且任何一个关键参数缺失,就走交互式 prompt
137
- const providedTemplate = process.argv.includes('--template');
138
- const providedDest = process.argv.includes('--dest');
139
- const providedAuth = process.argv.includes('--auth');
140
- const providedSkipInstall = process.argv.includes('--skip-install');
141
- const providedSkipGit = process.argv.includes('--skip-git');
142
- // 如果有任何一个关键参数未通过命令行提供,就走交互式 prompt
143
- const needsPrompt = !name
144
- || !providedTemplate
145
- || !providedDest
146
- || !providedAuth
147
- || !providedSkipInstall
148
- || !providedSkipGit;
149
- if (needsPrompt) {
150
- const questions = [];
151
- if (!name) {
152
- questions.push({
153
- type: 'input',
154
- name: 'name',
155
- message: 'Enter project name:',
156
- default: 'my-skweb-app',
157
- validate: (input) => {
158
- if (!input || input.trim() === '') {
159
- return 'Please enter a project name';
160
- }
161
- return true;
162
- }
163
- });
164
- }
165
- if (!providedTemplate) {
166
- questions.push({
167
- type: 'list',
168
- name: 'template',
169
- message: 'Select project template:',
170
- choices: [
171
- { name: 'TypeScript', value: 'ts' },
172
- { name: 'ES Modules (MJS)', value: 'mjs' },
173
- { name: 'CommonJS (CJS)', value: 'cjs' }
174
- ],
175
- default: 'ts'
176
- });
177
- }
178
- if (!providedAuth) {
179
- questions.push({
180
- type: 'list',
181
- name: 'auth',
182
- message: 'Select auth provider:',
183
- choices: [
184
- { name: 'Static (HS256 shared secret)', value: 'static' },
185
- { name: 'JWKS (Keycloak / Auth0 / OIDC)', value: 'jwks' }
186
- ],
187
- default: 'static'
188
- });
189
- }
190
- if (!providedDest) {
191
- questions.push({
192
- type: 'input',
193
- name: 'dest',
194
- message: 'Enter destination directory:',
195
- default: '.'
196
- });
197
- }
198
- if (!providedSkipInstall) {
199
- questions.push({
200
- type: 'confirm',
201
- name: 'install',
202
- message: 'Install dependencies?',
203
- default: true
204
- });
205
- }
206
- if (!providedSkipGit) {
207
- questions.push({
208
- type: 'confirm',
209
- name: 'git',
210
- message: 'Initialize git repository?',
211
- default: true
212
- });
213
- }
214
- const answers = await inquirer__default["default"].prompt(questions);
215
- if (answers.name)
216
- name = answers.name;
217
- if (answers.template)
218
- options.template = answers.template;
219
- if (answers.auth)
220
- options.auth = answers.auth;
221
- if (answers.dest)
222
- options.dest = answers.dest;
223
- if (typeof answers.install === 'boolean')
224
- options.skipInstall = !answers.install;
225
- if (typeof answers.git === 'boolean')
226
- options.skipGit = !answers.git;
227
- }
228
- const spinner = ora__default["default"]('Creating project...').start();
229
- try {
230
- await createProject({
231
- name,
232
- template: options.template,
233
- dest: options.dest,
234
- auth: (options.auth || 'static')
235
- });
236
- spinner.succeed('Project files created');
237
- if (!options.skipInstall) {
238
- spinner.text = 'Installing dependencies...';
239
- spinner.start();
240
- await installDependencies(options.dest, name);
241
- spinner.succeed('Dependencies installed');
242
- }
243
- if (!options.skipGit) {
244
- spinner.text = 'Initializing git repository...';
245
- spinner.start();
246
- await initGit(options.dest, name);
247
- spinner.succeed('Git repository initialized');
248
- }
249
- spinner.stop();
250
- printSuccess(name, options.dest);
251
- }
252
- catch (error) {
253
- spinner.fail('Failed to create project');
254
- console.error(error);
255
- process.exit(1);
256
- }
257
- });
258
- await program.parseAsync();
259
- }
260
- main().catch(console.error);
261
- //# sourceMappingURL=cli.cjs.map