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.
Files changed (50) hide show
  1. package/.rollup.cache/Users/stayknight/projects/skweb-mono/tools/create-skweb/dist/index.js +14 -1
  2. package/.rollup.cache/Users/stayknight/projects/skweb-mono/tools/create-skweb/tsconfig.tsbuildinfo +1 -1
  3. package/.turbo/turbo-build.log +16 -17
  4. package/.turbo/turbo-lint.log +11 -12
  5. package/.turbo/turbo-test.log +66 -1
  6. package/CHANGELOG.md +49 -0
  7. package/dist/cli.js +14 -1
  8. package/dist/index.js +14 -1
  9. package/package.json +1 -1
  10. package/src/index.ts +21 -1
  11. package/templates/cjs/.env.example +5 -9
  12. package/templates/cjs/ecosystem.config.js +2 -2
  13. package/templates/cjs/package.json +5 -5
  14. package/templates/cjs/src/controllers/user.js +2 -2
  15. package/templates/cjs/src/cron-app.js +40 -0
  16. package/templates/cjs/src/cron-framework.js +44 -0
  17. package/templates/cjs/src/swagger.js +13 -18
  18. package/templates/cjs/src/utils/config.js +33 -13
  19. package/templates/cjs/src/{app.js → web-app.js} +41 -53
  20. package/templates/cjs/src/web-framework.js +23 -0
  21. package/templates/mjs/.env.example +5 -9
  22. package/templates/mjs/ecosystem.config.js +2 -2
  23. package/templates/mjs/package.json +5 -5
  24. package/templates/mjs/src/controllers/user.js +2 -2
  25. package/templates/mjs/src/cron-app.js +45 -0
  26. package/templates/mjs/src/cron-framework.js +44 -0
  27. package/templates/mjs/src/swagger.js +13 -18
  28. package/templates/mjs/src/utils/config.js +29 -13
  29. package/templates/mjs/src/{app.js → web-app.js} +40 -56
  30. package/templates/mjs/src/web-framework.js +23 -0
  31. package/templates/ts/.env.example +5 -9
  32. package/templates/ts/ecosystem.config.js +2 -2
  33. package/templates/ts/package.json +5 -5
  34. package/templates/ts/src/controllers/user.ts +2 -2
  35. package/templates/ts/src/cron-app.ts +45 -0
  36. package/templates/ts/src/cron-framework.ts +44 -0
  37. package/templates/ts/src/swagger.ts +13 -19
  38. package/templates/ts/src/utils/config.ts +29 -13
  39. package/templates/ts/src/{app.ts → web-app.ts} +40 -63
  40. package/templates/ts/src/web-framework.ts +23 -0
  41. package/tsconfig.tsbuildinfo +1 -1
  42. package/templates/cjs/src/cronWorker.js +0 -80
  43. package/templates/cjs/src/index.js +0 -7
  44. package/templates/cjs/src/services/database.js +0 -15
  45. package/templates/mjs/src/cronWorker.js +0 -86
  46. package/templates/mjs/src/index.js +0 -8
  47. package/templates/mjs/src/services/database.js +0 -16
  48. package/templates/ts/src/cronWorker.ts +0 -85
  49. package/templates/ts/src/index.ts +0 -8
  50. package/templates/ts/src/services/database.ts +0 -16
@@ -1,4 +1,69 @@
1
1
 
2
- > create-skweb@1.2.1 test
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, fileName);
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, fileName);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-skweb",
3
- "version": "3.1.1",
3
+ "version": "3.3.0",
4
4
  "description": "Create a new SKWeb project with TypeScript, CJS, or MJS support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
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, fileName)
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
- # ---------- Auth Provider ----------
42
- # 'static' (default): use a shared secret (HS256)
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
- # ---------- JWT (jwks mode, OIDC compatible) ----------
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/index.js',
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/cronWorker.js',
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/index.js",
13
- "cron:dev": "npx dotenvx run -- node --watch src/cronWorker.js",
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.3",
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.0",
32
- "skweb-plugin": "^2.1.0",
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",
@@ -1,7 +1,7 @@
1
1
  const createHttpError = require('http-errors')
2
- const { db } = require('../services/database.js')
2
+ const { framework } = require('../web-framework.js')
3
3
 
4
- const { SysUser } = db.sequelize.models
4
+ const { SysUser } = framework.models
5
5
 
6
6
  /**
7
7
  * @swagger
@@ -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
- module.exports = { validateConfig, checkRequiredEnv }
81
+ {{#if_eq auth "static"}}
82
+ module.exports = { validateConfig, checkJwtSecret, checkRequiredEnv }
83
+ {{else}}
84
+ module.exports = { validateConfig, checkOIDCConfig, checkRequiredEnv }
85
+ {{/if_eq}}