create-skweb 3.1.1 → 3.3.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/.rollup.cache/Users/stayknight/projects/skweb-mono/tools/create-skweb/dist/index.js +14 -1
- package/.rollup.cache/Users/stayknight/projects/skweb-mono/tools/create-skweb/tsconfig.tsbuildinfo +1 -1
- package/.turbo/turbo-build.log +16 -17
- package/.turbo/turbo-lint.log +11 -12
- package/.turbo/turbo-test.log +66 -1
- package/CHANGELOG.md +49 -0
- package/dist/cli.js +14 -1
- package/dist/index.js +14 -1
- package/package.json +1 -1
- package/src/index.ts +21 -1
- package/templates/cjs/.env.example +5 -9
- package/templates/cjs/ecosystem.config.js +2 -2
- package/templates/cjs/package.json +5 -5
- package/templates/cjs/src/controllers/user.js +2 -2
- package/templates/cjs/src/cron-app.js +40 -0
- package/templates/cjs/src/cron-framework.js +44 -0
- package/templates/cjs/src/swagger.js +13 -18
- package/templates/cjs/src/utils/config.js +33 -13
- package/templates/cjs/src/{app.js → web-app.js} +41 -53
- package/templates/cjs/src/web-framework.js +23 -0
- package/templates/mjs/.env.example +5 -9
- package/templates/mjs/ecosystem.config.js +2 -2
- package/templates/mjs/package.json +5 -5
- package/templates/mjs/src/controllers/user.js +2 -2
- package/templates/mjs/src/cron-app.js +45 -0
- package/templates/mjs/src/cron-framework.js +44 -0
- package/templates/mjs/src/swagger.js +13 -18
- package/templates/mjs/src/utils/config.js +29 -13
- package/templates/mjs/src/{app.js → web-app.js} +40 -56
- package/templates/mjs/src/web-framework.js +23 -0
- package/templates/ts/.env.example +5 -9
- package/templates/ts/ecosystem.config.js +2 -2
- package/templates/ts/package.json +5 -5
- package/templates/ts/src/controllers/user.ts +2 -2
- package/templates/ts/src/cron-app.ts +45 -0
- package/templates/ts/src/cron-framework.ts +44 -0
- package/templates/ts/src/swagger.ts +13 -19
- package/templates/ts/src/utils/config.ts +29 -13
- package/templates/ts/src/{app.ts → web-app.ts} +40 -63
- package/templates/ts/src/web-framework.ts +23 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/templates/cjs/src/cronWorker.js +0 -80
- package/templates/cjs/src/index.js +0 -7
- package/templates/cjs/src/services/database.js +0 -15
- package/templates/mjs/src/cronWorker.js +0 -86
- package/templates/mjs/src/index.js +0 -8
- package/templates/mjs/src/services/database.js +0 -16
- package/templates/ts/src/cronWorker.ts +0 -85
- package/templates/ts/src/index.ts +0 -8
- package/templates/ts/src/services/database.ts +0 -16
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,4 +1,69 @@
|
|
|
1
1
|
|
|
2
|
-
> create-skweb@
|
|
2
|
+
> create-skweb@3.2.0 test
|
|
3
3
|
> mocha test/**/*.mjs
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
create-skweb
|
|
8
|
+
createProject()
|
|
9
|
+
✔ should create TypeScript project from template
|
|
10
|
+
✔ should create MJS project from template
|
|
11
|
+
✔ should create CJS project from template
|
|
12
|
+
✔ should reject non-empty destination directory
|
|
13
|
+
✔ should include winston in all templates
|
|
14
|
+
✔ should include @dotenvx/dotenvx in all templates
|
|
15
|
+
✔ should include pm2 ecosystem in all templates
|
|
16
|
+
✔ should replace {{name}} placeholder in package.json
|
|
17
|
+
printBanner()
|
|
18
|
+
|
|
19
|
+
╔════════════════════════════════════════════════════════════════════╗
|
|
20
|
+
║ Create SKWeb Project ║
|
|
21
|
+
╚════════════════════════════════════════════════════════════════════╝
|
|
22
|
+
|
|
23
|
+
✔ should not throw
|
|
24
|
+
printSuccess()
|
|
25
|
+
|
|
26
|
+
╔════════════════════════════════════════════════════════════════════╗
|
|
27
|
+
║ 项目创建成功! ║
|
|
28
|
+
╚════════════════════════════════════════════════════════════════════╝
|
|
29
|
+
|
|
30
|
+
项目名称: my-app
|
|
31
|
+
项目路径: /tmp/my-app/my-app
|
|
32
|
+
|
|
33
|
+
接下来可以执行:
|
|
34
|
+
|
|
35
|
+
cd my-app
|
|
36
|
+
|
|
37
|
+
# 复制环境变量模板并按需修改
|
|
38
|
+
cp .env.example .env
|
|
39
|
+
|
|
40
|
+
# 开发模式运行
|
|
41
|
+
npm run start:dev
|
|
42
|
+
|
|
43
|
+
# 生产模式运行 (需要先构建)
|
|
44
|
+
npm run build
|
|
45
|
+
npm run start
|
|
46
|
+
|
|
47
|
+
# 查看日志
|
|
48
|
+
npm run logs
|
|
49
|
+
|
|
50
|
+
# 停止服务
|
|
51
|
+
npm run stop
|
|
52
|
+
|
|
53
|
+
# 重启服务
|
|
54
|
+
npm run restart
|
|
55
|
+
|
|
56
|
+
项目特性:
|
|
57
|
+
✅ TypeScript/MJS/CJS 支持
|
|
58
|
+
✅ @dotenvx/dotenvx 环境变量管理
|
|
59
|
+
✅ PM2 进程管理
|
|
60
|
+
✅ SKWeb Express 集成
|
|
61
|
+
✅ Keycloak/JWKS 鉴权 (可选)
|
|
62
|
+
✅ ESLint 代码检查
|
|
63
|
+
✅ Mocha 测试框架
|
|
64
|
+
|
|
65
|
+
✔ should not throw
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
10 passing (179ms)
|
|
69
|
+
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# create-skweb
|
|
2
2
|
|
|
3
|
+
## 3.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 重构模板结构:入口文件重命名为 web-app/cron-app,新增 web-framework/cron-framework 单例文件,移除冗余的 index 和 services/database
|
|
8
|
+
|
|
9
|
+
## 3.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- c5338b9: feat(templates): honor `--auth` option at generation time, not at runtime
|
|
14
|
+
|
|
15
|
+
Previously `app.js` / `app.ts` always contained both the static and jwks
|
|
16
|
+
JWT branches and decided which to use at runtime via `process.env.AUTH_PROVIDER`.
|
|
17
|
+
That meant the `--auth` CLI option was effectively a hint, not a real
|
|
18
|
+
choice: every generated project shipped both code paths and the
|
|
19
|
+
`AUTH_PROVIDER=...` line in `.env.example`, even projects that explicitly
|
|
20
|
+
chose static or jwks.
|
|
21
|
+
|
|
22
|
+
Now `createProject` reads the `auth` option and writes only the
|
|
23
|
+
matching files:
|
|
24
|
+
|
|
25
|
+
- `app.auth-static.{js,ts}` → `app.{js,ts}` (static only)
|
|
26
|
+
- `app.auth-jwks.{js,ts}` → `app.{js,ts}` (jwks only)
|
|
27
|
+
- `config.auth-static.{js,ts}` → `config.{js,ts}` (exports `checkJwtSecret`)
|
|
28
|
+
- `config.auth-jwks.{js,ts}` → `config.{js,ts}` (exports `checkOIDCConfig`)
|
|
29
|
+
- `swagger.auth-static.{js,ts}` → `swagger.{js,ts}` (HTTP bearer security)
|
|
30
|
+
- `swagger.auth-jwks.{js,ts}` → `swagger.{js,ts}` (OIDC openIdConnect)
|
|
31
|
+
- `.env.example.auth-static` → `.env.example` (JWT_SECRET only)
|
|
32
|
+
- `.env.example.auth-jwks` → `.env.example` (OIDC\_\* only)
|
|
33
|
+
|
|
34
|
+
Generated projects are now leaner: a static-only project contains no
|
|
35
|
+
JWKS code or env vars, and vice versa. The `checkJwtSecret` /
|
|
36
|
+
`checkOIDCConfig` split also keeps the JWT_SECRET default-value
|
|
37
|
+
warning from leaking into the cron worker process.
|
|
38
|
+
|
|
39
|
+
## 3.1.2
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- 03ebe56: refactor(templates): separate JWT secret validation from generic env check
|
|
44
|
+
|
|
45
|
+
`validateConfig` (in templates/cjs/mjs/ts `src/utils/config.{js,ts}`) no longer
|
|
46
|
+
warns about `JWT_SECRET` default value. The JWT-specific check is moved to a
|
|
47
|
+
new `checkJwtSecret()` helper that is now only invoked from the web bootstrap
|
|
48
|
+
(`src/app.{js,ts}`), not from `cronWorker.js` or CLI commands. This removes the
|
|
49
|
+
spurious "JWT_SECRET is using default value" warning in the cron worker
|
|
50
|
+
process, which never uses JWT.
|
|
51
|
+
|
|
3
52
|
## 3.1.1
|
|
4
53
|
|
|
5
54
|
### Patch Changes
|
package/dist/cli.js
CHANGED
|
@@ -32,12 +32,25 @@ async function createProject(options) {
|
|
|
32
32
|
await fs.mkdirs(path.join(targetDir, fileName));
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
|
+
// 跳过 auth- 后缀的文件(已合并到统一模板)
|
|
36
|
+
if (/\.auth-(static|jwks)(\.[^.]+)?$/.test(fileName)) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
// 跳过无 auth 后缀的 .env.example(改用条件模板)
|
|
40
|
+
if (fileName === '.env.example' || fileName.endsWith('/.env.example')) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const outputName = fileName;
|
|
35
44
|
let content = await fs.readFile(srcPath, 'utf-8');
|
|
45
|
+
// 处理条件块:{{#if_eq auth "static"}}...{{else}}...{{/if_eq}}
|
|
46
|
+
content = content.replace(/\{\{#if_eq auth "(static|jwks)"\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if_eq\}\}/g, (_match, value, mainContent, elseContent) => {
|
|
47
|
+
return value === auth ? mainContent : (elseContent || '');
|
|
48
|
+
});
|
|
36
49
|
content = content
|
|
37
50
|
.replace(/\{\{name\}\}/g, name)
|
|
38
51
|
.replace(/\{\{description\}\}/g, description)
|
|
39
52
|
.replace(/\{\{auth\}\}/g, auth);
|
|
40
|
-
const destPath = path.join(targetDir,
|
|
53
|
+
const destPath = path.join(targetDir, outputName);
|
|
41
54
|
await fs.writeFile(destPath, content);
|
|
42
55
|
}
|
|
43
56
|
await fs.mkdirs(path.join(targetDir, 'logs'));
|
package/dist/index.js
CHANGED
|
@@ -27,12 +27,25 @@ async function createProject(options) {
|
|
|
27
27
|
await fs.mkdirs(path.join(targetDir, fileName));
|
|
28
28
|
continue;
|
|
29
29
|
}
|
|
30
|
+
// 跳过 auth- 后缀的文件(已合并到统一模板)
|
|
31
|
+
if (/\.auth-(static|jwks)(\.[^.]+)?$/.test(fileName)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// 跳过无 auth 后缀的 .env.example(改用条件模板)
|
|
35
|
+
if (fileName === '.env.example' || fileName.endsWith('/.env.example')) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const outputName = fileName;
|
|
30
39
|
let content = await fs.readFile(srcPath, 'utf-8');
|
|
40
|
+
// 处理条件块:{{#if_eq auth "static"}}...{{else}}...{{/if_eq}}
|
|
41
|
+
content = content.replace(/\{\{#if_eq auth "(static|jwks)"\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if_eq\}\}/g, (_match, value, mainContent, elseContent) => {
|
|
42
|
+
return value === auth ? mainContent : (elseContent || '');
|
|
43
|
+
});
|
|
31
44
|
content = content
|
|
32
45
|
.replace(/\{\{name\}\}/g, name)
|
|
33
46
|
.replace(/\{\{description\}\}/g, description)
|
|
34
47
|
.replace(/\{\{auth\}\}/g, auth);
|
|
35
|
-
const destPath = path.join(targetDir,
|
|
48
|
+
const destPath = path.join(targetDir, outputName);
|
|
36
49
|
await fs.writeFile(destPath, content);
|
|
37
50
|
}
|
|
38
51
|
await fs.mkdirs(path.join(targetDir, 'logs'));
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -42,14 +42,34 @@ export async function createProject(options: CreateOptions): Promise<void> {
|
|
|
42
42
|
continue
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
// 跳过 auth- 后缀的文件(已合并到统一模板)
|
|
46
|
+
if (/\.auth-(static|jwks)(\.[^.]+)?$/.test(fileName)) {
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 跳过无 auth 后缀的 .env.example(改用条件模板)
|
|
51
|
+
if (fileName === '.env.example' || fileName.endsWith('/.env.example')) {
|
|
52
|
+
continue
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const outputName = fileName
|
|
56
|
+
|
|
45
57
|
let content = await fs.readFile(srcPath, 'utf-8')
|
|
46
58
|
|
|
59
|
+
// 处理条件块:{{#if_eq auth "static"}}...{{else}}...{{/if_eq}}
|
|
60
|
+
content = content.replace(
|
|
61
|
+
/\{\{#if_eq auth "(static|jwks)"\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if_eq\}\}/g,
|
|
62
|
+
(_match: string, value: string, mainContent: string, elseContent: string) => {
|
|
63
|
+
return value === auth ? mainContent : (elseContent || '')
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
|
|
47
67
|
content = content
|
|
48
68
|
.replace(/\{\{name\}\}/g, name)
|
|
49
69
|
.replace(/\{\{description\}\}/g, description)
|
|
50
70
|
.replace(/\{\{auth\}\}/g, auth)
|
|
51
71
|
|
|
52
|
-
const destPath = path.join(targetDir,
|
|
72
|
+
const destPath = path.join(targetDir, outputName)
|
|
53
73
|
await fs.writeFile(destPath, content)
|
|
54
74
|
}
|
|
55
75
|
|
|
@@ -38,29 +38,25 @@ REDIS_DB=0
|
|
|
38
38
|
# (Production is always disabled to avoid exposing internal API details.)
|
|
39
39
|
SWAGGER_ENABLED=true
|
|
40
40
|
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
# 'jwks': verify via JWKS endpoint (Keycloak / Auth0 / generic OIDC)
|
|
44
|
-
AUTH_PROVIDER={{auth}}
|
|
45
|
-
|
|
46
|
-
# ---------- JWT (static mode) ----------
|
|
41
|
+
{{#if_eq auth "static"}}
|
|
42
|
+
# ---------- Auth: static (HS256 shared secret) ----------
|
|
47
43
|
# [REQUIRED in production] Use a strong random string, e.g. `openssl rand -hex 32`
|
|
48
44
|
JWT_SECRET=please-change-this-in-production
|
|
49
45
|
JWT_EXPIRES_IN=7d
|
|
50
|
-
|
|
51
|
-
# ----------
|
|
46
|
+
{{else}}
|
|
47
|
+
# ---------- Auth: jwks (OIDC compatible) ----------
|
|
52
48
|
# Works with any OIDC-compliant IdP. Common issuer formats:
|
|
53
49
|
# Keycloak: https://kc.example.com/realms/myrealm
|
|
54
50
|
# Auth0: https://your-tenant.auth0.com/
|
|
55
51
|
# Okta: https://your-domain.okta.com/oauth2/default
|
|
56
52
|
# Authing: https://your-app.authing.cn/oauth2/default
|
|
57
|
-
# Keycloak Realm: https://kc.example.com/auth/realms/myrealm
|
|
58
53
|
# `audience` is the client id of this API in the IdP (recommended).
|
|
59
54
|
# JWKS URI is auto-derived as ${OIDC_ISSUER}/.well-known/jwks.json
|
|
60
55
|
# unless OIDC_JWKS_URI is set explicitly.
|
|
61
56
|
OIDC_ISSUER=
|
|
62
57
|
OIDC_AUDIENCE=
|
|
63
58
|
OIDC_JWKS_URI=
|
|
59
|
+
{{/if_eq}}
|
|
64
60
|
|
|
65
61
|
# ---------- Logging ----------
|
|
66
62
|
# error | warn | info | http | verbose | debug | silly
|
|
@@ -2,7 +2,7 @@ module.exports = {
|
|
|
2
2
|
apps: [
|
|
3
3
|
{
|
|
4
4
|
name: '{{name}}-web',
|
|
5
|
-
script: 'src/
|
|
5
|
+
script: 'src/web-app.js',
|
|
6
6
|
instances: 'max',
|
|
7
7
|
exec_mode: 'cluster',
|
|
8
8
|
env: {
|
|
@@ -16,7 +16,7 @@ module.exports = {
|
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
name: '{{name}}-cron',
|
|
19
|
-
script: 'src/
|
|
19
|
+
script: 'src/cron-app.js',
|
|
20
20
|
instances: 1,
|
|
21
21
|
exec_mode: 'fork',
|
|
22
22
|
autorestart: true,
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"restart": "pm2 restart all",
|
|
10
10
|
"delete": "pm2 delete all",
|
|
11
11
|
"logs": "pm2 logs",
|
|
12
|
-
"web:dev": "npx dotenvx run -- node --watch src/
|
|
13
|
-
"cron:dev": "npx dotenvx run -- node --watch src/
|
|
12
|
+
"web:dev": "npx dotenvx run -- node --watch src/web-app.js",
|
|
13
|
+
"cron:dev": "npx dotenvx run -- node --watch src/cron-app.js",
|
|
14
14
|
"seed": "npx dotenvx run -- node src/commands/seed.js",
|
|
15
15
|
"migrate": "npx dotenvx run -- node src/commands/migrate.js",
|
|
16
16
|
"build": "cp -r src dist",
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@dotenvx/dotenvx": "^1.75.1",
|
|
24
24
|
"http-errors": "^2.0.1",
|
|
25
|
-
"skweb-express": "^2.0.
|
|
25
|
+
"skweb-express": "^2.0.4",
|
|
26
26
|
"skweb-express-jwt": "^3.0.0",
|
|
27
27
|
"skweb-express-logger": "^2.0.0",
|
|
28
28
|
"skweb-sequelize": "^2.0.0",
|
|
29
29
|
"skweb-redis": "^2.0.0",
|
|
30
30
|
"skweb-cron": "^2.0.0",
|
|
31
|
-
"skweb-framework": "^2.1.
|
|
32
|
-
"skweb-plugin": "^2.1.
|
|
31
|
+
"skweb-framework": "^2.1.1",
|
|
32
|
+
"skweb-plugin": "^2.1.1",
|
|
33
33
|
"skweb-util": "^2.0.0",
|
|
34
34
|
"winston": "^3.19.0",
|
|
35
35
|
"sequelize": "^6.37.8",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require('dotenv/config')
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const { framework } = require('./cron-framework.js')
|
|
5
|
+
const { logger } = require('./utils/logger.js')
|
|
6
|
+
const { checkRequiredEnv } = require('./utils/config.js')
|
|
7
|
+
|
|
8
|
+
async function startCronWorker() {
|
|
9
|
+
logger.info('[cron-worker] Starting cron worker process...')
|
|
10
|
+
|
|
11
|
+
if (!checkRequiredEnv()) {
|
|
12
|
+
logger.error('[cron-worker] Configuration validation failed, exiting...')
|
|
13
|
+
process.exit(1)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
await framework.setup({
|
|
17
|
+
modelsDir: path.join(__dirname, './models'),
|
|
18
|
+
cronActionsDir: path.join(__dirname, './cronActions')
|
|
19
|
+
})
|
|
20
|
+
await framework.start()
|
|
21
|
+
logger.info('[cron-worker] Cron worker started')
|
|
22
|
+
|
|
23
|
+
process.on('uncaughtException', (err) => {
|
|
24
|
+
logger.error(`[cron-worker] uncaughtException: ${err.stack || err.message}`)
|
|
25
|
+
process.exit(1)
|
|
26
|
+
})
|
|
27
|
+
process.on('unhandledRejection', (reason) => {
|
|
28
|
+
logger.error(`[cron-worker] unhandledRejection: ${reason instanceof Error ? reason.stack : String(reason)}`)
|
|
29
|
+
process.exit(1)
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (require.main === module) {
|
|
34
|
+
startCronWorker().catch((err) => {
|
|
35
|
+
logger.error('[cron-worker] Fatal error:', err)
|
|
36
|
+
process.exit(1)
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = { startCronWorker }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
const { CronFramework } = require('skweb-framework')
|
|
3
|
+
const { logger } = require('./utils/logger.js')
|
|
4
|
+
|
|
5
|
+
const framework = new CronFramework({
|
|
6
|
+
db: {
|
|
7
|
+
host: process.env.DB_HOST || '127.0.0.1',
|
|
8
|
+
port: Number(process.env.DB_PORT) || 3306,
|
|
9
|
+
username: process.env.DB_USER || 'root',
|
|
10
|
+
password: process.env.DB_PASS || '',
|
|
11
|
+
database: process.env.DB_NAME || 'test-project',
|
|
12
|
+
dialect: process.env.DB_DIALECT || 'mysql',
|
|
13
|
+
charset: process.env.DB_CHARSET || 'utf8mb4',
|
|
14
|
+
underscored: true,
|
|
15
|
+
logging: process.env.DEBUG_DB === 'true'
|
|
16
|
+
},
|
|
17
|
+
redis: {
|
|
18
|
+
host: process.env.REDIS_HOST || '127.0.0.1',
|
|
19
|
+
port: Number(process.env.REDIS_PORT) || 6379,
|
|
20
|
+
password: process.env.REDIS_PASSWORD || undefined
|
|
21
|
+
},
|
|
22
|
+
channel: 'cron:task:cmd',
|
|
23
|
+
logger,
|
|
24
|
+
onSaveTask: async (taskData) => {
|
|
25
|
+
const SysCronTask = framework.db?.sequelize?.models.SysCronTask
|
|
26
|
+
if (SysCronTask) {
|
|
27
|
+
await SysCronTask.update(
|
|
28
|
+
{ cache: taskData.cache, data: taskData.data },
|
|
29
|
+
{ where: { id: taskData.taskId } }
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
loadTasks: async () => {
|
|
34
|
+
const SysCronTask = framework.db?.sequelize?.models.SysCronTask
|
|
35
|
+
if (!SysCronTask) return []
|
|
36
|
+
return (await SysCronTask.findAll()).map((t) => ({
|
|
37
|
+
id: String(t.id),
|
|
38
|
+
cronTime: t.cronTime,
|
|
39
|
+
method: t.method
|
|
40
|
+
}))
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
module.exports = { framework }
|
|
@@ -1,24 +1,9 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
'use strict'
|
|
2
3
|
|
|
3
4
|
const path = require('path')
|
|
4
5
|
const swaggerJSDoc = require('swagger-jsdoc')
|
|
5
6
|
|
|
6
|
-
/**
|
|
7
|
-
* 构建 OpenAPI 3.0 规范对象。
|
|
8
|
-
*
|
|
9
|
-
* 控制器中应使用 @swagger JSDoc 注释描述端点,例如:
|
|
10
|
-
*
|
|
11
|
-
* /**
|
|
12
|
-
* * @swagger
|
|
13
|
-
* * /api/users:
|
|
14
|
-
* * get:
|
|
15
|
-
* * summary: 获取用户列表
|
|
16
|
-
* * tags: [Users]
|
|
17
|
-
* * responses:
|
|
18
|
-
* * 200:
|
|
19
|
-
* * description: OK
|
|
20
|
-
* *\/
|
|
21
|
-
*/
|
|
22
7
|
function buildOpenApiSpec() {
|
|
23
8
|
return swaggerJSDoc({
|
|
24
9
|
definition: {
|
|
@@ -34,12 +19,22 @@ function buildOpenApiSpec() {
|
|
|
34
19
|
],
|
|
35
20
|
components: {
|
|
36
21
|
securitySchemes: {
|
|
22
|
+
{{#if_eq auth "static"}}
|
|
37
23
|
bearerAuth: {
|
|
38
24
|
type: 'http',
|
|
39
25
|
scheme: 'bearer',
|
|
40
|
-
bearerFormat: 'JWT'
|
|
41
|
-
description: 'Paste a JWT token here (only needed when AUTH_PROVIDER=static)'
|
|
26
|
+
bearerFormat: 'JWT'
|
|
42
27
|
}
|
|
28
|
+
{{else}}
|
|
29
|
+
oidcAuth: {
|
|
30
|
+
type: 'openIdConnect',
|
|
31
|
+
openIdConnectUrl: process.env.OIDC_JWKS_URI
|
|
32
|
+
? process.env.OIDC_JWKS_URI.replace(/\/jwks\.json$/, '/.well-known/openid-configuration')
|
|
33
|
+
: (process.env.OIDC_ISSUER
|
|
34
|
+
? `${process.env.OIDC_ISSUER.replace(/\/$/, '')}/.well-known/openid-configuration`
|
|
35
|
+
: undefined)
|
|
36
|
+
}
|
|
37
|
+
{{/if_eq}}
|
|
43
38
|
}
|
|
44
39
|
}
|
|
45
40
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
const { logger } = require('./logger.js')
|
|
2
3
|
|
|
3
4
|
function validateConfig() {
|
|
@@ -13,10 +14,6 @@ function validateConfig() {
|
|
|
13
14
|
logger.warn('[config] DB_USER not set, using default: root')
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
if (process.env.JWT_SECRET === 'please-change-this-in-production') {
|
|
17
|
-
logger.warn('[config] WARNING: JWT_SECRET is using default value, please change in production!')
|
|
18
|
-
}
|
|
19
|
-
|
|
20
17
|
if (!process.env.REDIS_HOST) {
|
|
21
18
|
logger.warn('[config] REDIS_HOST not set, using default: 127.0.0.1')
|
|
22
19
|
}
|
|
@@ -42,24 +39,47 @@ function validateConfig() {
|
|
|
42
39
|
}
|
|
43
40
|
}
|
|
44
41
|
|
|
42
|
+
{{#if_eq auth "static"}}
|
|
43
|
+
function checkJwtSecret() {
|
|
44
|
+
if (process.env.JWT_SECRET === 'please-change-this-in-production' || !process.env.JWT_SECRET) {
|
|
45
|
+
if (process.env.NODE_ENV === 'production') {
|
|
46
|
+
logger.error('[config] JWT_SECRET must be set in production!')
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
logger.warn('[config] WARNING: JWT_SECRET is using default value, please change in production!')
|
|
50
|
+
}
|
|
51
|
+
return true
|
|
52
|
+
}
|
|
53
|
+
{{else}}
|
|
54
|
+
function checkOIDCConfig() {
|
|
55
|
+
const issuer = process.env.OIDC_ISSUER
|
|
56
|
+
const jwksUri = process.env.OIDC_JWKS_URI
|
|
57
|
+
if (!issuer && !jwksUri) {
|
|
58
|
+
logger.error('[config] OIDC_ISSUER or OIDC_JWKS_URI must be set for jwks auth')
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
if (process.env.NODE_ENV === 'production' && !process.env.OIDC_AUDIENCE) {
|
|
62
|
+
logger.warn('[config] OIDC_AUDIENCE is not set; audience verification will be skipped')
|
|
63
|
+
}
|
|
64
|
+
return true
|
|
65
|
+
}
|
|
66
|
+
{{/if_eq}}
|
|
67
|
+
|
|
45
68
|
function checkRequiredEnv() {
|
|
46
69
|
const result = validateConfig()
|
|
47
|
-
|
|
70
|
+
|
|
48
71
|
if (result.errors.length > 0) {
|
|
49
72
|
logger.error('[config] Configuration validation failed:')
|
|
50
73
|
result.errors.forEach((err) => logger.error(` - ${err}`))
|
|
51
74
|
return false
|
|
52
75
|
}
|
|
53
76
|
|
|
54
|
-
if (process.env.NODE_ENV === 'production') {
|
|
55
|
-
if (!process.env.JWT_SECRET || process.env.JWT_SECRET === 'please-change-this-in-production') {
|
|
56
|
-
logger.error('[config] JWT_SECRET must be set in production!')
|
|
57
|
-
return false
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
77
|
logger.info('[config] Configuration validation passed')
|
|
62
78
|
return true
|
|
63
79
|
}
|
|
64
80
|
|
|
65
|
-
|
|
81
|
+
{{#if_eq auth "static"}}
|
|
82
|
+
module.exports = { validateConfig, checkJwtSecret, checkRequiredEnv }
|
|
83
|
+
{{else}}
|
|
84
|
+
module.exports = { validateConfig, checkOIDCConfig, checkRequiredEnv }
|
|
85
|
+
{{/if_eq}}
|