create-skweb 2.0.0 → 2.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.
@@ -1,18 +1,18 @@
1
1
 
2
2
  
3
- > create-skweb@2.0.0 prebuild
3
+ > create-skweb@2.1.0 prebuild
4
4
  > tsc --outDir dist --rootDir src
5
5
 
6
6
  ⠙
7
- > create-skweb@2.0.0 build
8
- > rollup -c rollup.config.mjs && node scripts/inject-shebang.cjs && chmod +x dist/cli.cjs
7
+ > create-skweb@2.1.0 build
8
+ > rollup -c rollup.config.mjs && node scripts/inject-shebang.mjs && chmod +x dist/cli.cjs
9
9
 
10
10
  ⠙
11
11
  src/index.ts → dist/index.js, dist/index.cjs...
12
- created dist/index.js, dist/index.cjs in 398ms
12
+ created dist/index.js, dist/index.cjs in 372ms
13
13
  
14
14
  src/cli.ts → dist/cli.cjs...
15
15
  (!) Plugin replace: @rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
16
- created dist/cli.cjs in 245ms
17
- [inject-shebang] Shebang added to dist/cli.cjs
16
+ created dist/cli.cjs in 295ms
17
+ [inject-shebang] Shebang added to /Users/stayknight/projects/skweb-mono/tools/create-skweb/dist/cli.cjs
18
18
  ⠙
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # create-skweb
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4afc39b: 修复多个技术层与设计层问题:
8
+
9
+ **skweb-express**
10
+
11
+ - 修复 `setUserAuth` / `setVerifyAuth` 类型签名(增加 `key` 参数),与实现对齐
12
+ - `permission.ts` 加入互斥检查:`setUserAuth` 与 `setVerifyAuth` 不可同时调用
13
+ - `createAuthVerify` 修复 `authResult` 未写回 `req[key]` 的 bug,改用 `_.merge` 避免污染返回值
14
+ - `index.ts` 移除误挂载在 `app.useController` 上的方法
15
+ - `response.ts` 增强安全性:默认隐藏 5xx 内部错误消息,可通过 `app.set('hideISE', false)` 显式开启
16
+
17
+ **skweb-framework**
18
+
19
+ - `WebFramework` / `CronFramework` 新增 `stop()` 方法,支持 SIGINT/SIGTERM 优雅关闭(关闭 HTTP server / cron manager / DB 连接 / Redis)
20
+
21
+ **create-skweb**
22
+
23
+ - `sync-template-versions.mjs` 增强 dry-run 引导:启动时显式声明模式,新增 `--help` 与 STRICT 模式彩色输出
24
+ - `inject-shebang.cjs` 迁移为 `inject-shebang.mjs`(与 ESM 风格统一),支持目标文件参数,修复 `skweb-cli` 构建时 shebang 错位到 `create-skweb/dist/` 的 bug
25
+ - `skweb-cli/package.json` 修复 `inject-shebang` 路径错误(`../../scripts/` → `../create-skweb/scripts/`)
26
+ - 三个模板(cjs/mjs/ts)的 `.gitignore` 完全统一,补齐 `coverage/`、`.rollup.cache/`、IDE/日志/测试产物等通用项
27
+ - ts 模板补齐 `tslib` 与 `@rollup/plugin-json` 依赖,修复 `rollup.config.mjs` 缺 `json()` 插件
28
+ - ts 模板 `cronWorker.ts` 改用 `framework.dbInstance`(受保护的 `db` 改用公共 getter)
29
+
3
30
  ## 2.0.0
4
31
 
5
32
  ### Major Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-skweb",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Create a new SKWeb project with TypeScript, CJS, or MJS support",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -13,11 +13,14 @@
13
13
  "clean": "rm -rf dist",
14
14
  "clean:temp": "rm -rf .rollup.cache",
15
15
  "prebuild": "tsc --outDir dist --rootDir src",
16
- "build": "rollup -c rollup.config.mjs && node scripts/inject-shebang.cjs && chmod +x dist/cli.cjs",
17
- "build:dev": "rollup -c rollup.config.mjs --environment NODE_ENV:development && node scripts/inject-shebang.cjs && chmod +x dist/cli.cjs",
16
+ "build": "rollup -c rollup.config.mjs && node scripts/inject-shebang.mjs && chmod +x dist/cli.cjs",
17
+ "build:dev": "rollup -c rollup.config.mjs --environment NODE_ENV:development && node scripts/inject-shebang.mjs && chmod +x dist/cli.cjs",
18
18
  "lint": "eslint --fix --ext .ts src",
19
19
  "check": "tsc --noEmit",
20
- "test": "mocha test/**/*.mjs"
20
+ "test": "mocha test/**/*.mjs",
21
+ "sync:versions": "node scripts/sync-template-versions.mjs",
22
+ "sync:versions:apply": "node scripts/sync-template-versions.mjs --apply",
23
+ "sync:versions:strict": "node scripts/sync-template-versions.mjs --strict"
21
24
  },
22
25
  "dependencies": {
23
26
  "commander": "^12.1.0",
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ //
3
+ // inject-shebang.mjs
4
+ //
5
+ // 给 rollup 产出的 CLI 文件加 shebang。
6
+ // rollup 在某些场景下会丢失或重复 shebang(特别是使用 @rollup/plugin-replace
7
+ // 替换 /usr/bin/env 时),这里统一收口。
8
+ //
9
+ // 用法:
10
+ // node scripts/inject-shebang.mjs # 默认 ./dist/cli.cjs
11
+ // node scripts/inject-shebang.mjs dist/cli.cjs # 相对 cwd 的目标
12
+ // node scripts/inject-shebang.mjs /abs/path/cli # 绝对路径
13
+ //
14
+ // 说明:
15
+ // - 已存在 shebang 时跳过,不重复添加
16
+ // - 文件不存在时给出明确错误信息(避免静默失败)
17
+ //
18
+
19
+ import fs from 'node:fs'
20
+ import path from 'node:path'
21
+
22
+ const SHEBANG = '#!/usr/bin/env node\n'
23
+
24
+ const arg = process.argv[2]
25
+ const target = arg ? path.resolve(arg) : path.resolve('dist/cli.cjs')
26
+
27
+ if (!fs.existsSync(target)) {
28
+ console.error(`[inject-shebang] target not found: ${target}`)
29
+ process.exit(1)
30
+ }
31
+
32
+ let content = fs.readFileSync(target, 'utf-8')
33
+ if (content.startsWith('#!')) {
34
+ console.log(`[inject-shebang] Shebang already present in ${target}`)
35
+ process.exit(0)
36
+ }
37
+
38
+ fs.writeFileSync(target, SHEBANG + content, 'utf-8')
39
+ console.log(`[inject-shebang] Shebang added to ${target}`)
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ //
3
+ // sync-template-versions.mjs
4
+ //
5
+ // 把本工程 packages 下的 skweb-* 包版本号
6
+ // 同步到 tools/create-skweb/templates 下的 package.json。
7
+ //
8
+ // 用法:
9
+ // node scripts/sync-template-versions.mjs # 默认 dry-run,仅打印
10
+ // node scripts/sync-template-versions.mjs --apply # 写回文件
11
+ // node scripts/sync-template-versions.mjs --strict # 严格模式:发现不一致退出码 1
12
+ // node scripts/sync-template-versions.mjs --help # 查看帮助
13
+ //
14
+ // 同步规则:
15
+ // - workspace 的 X.Y.Z 映射到模板的 ^X.Y.0
16
+ // - 仅修改 skweb-* 开头的依赖(其他依赖不动)
17
+ // - 仅处理 templates 目录下 .json 文件
18
+ //
19
+ // 退出码:
20
+ // 0 全部一致,或已 --apply 写回
21
+ // 1 --strict 模式下发现不一致且未 --apply
22
+ // 2 执行过程异常
23
+ //
24
+ // 建议在以下时机执行:
25
+ // - 每次 changeset version 之后
26
+ // - 提交前
27
+ // - CI 发布前
28
+ //
29
+
30
+ import fs from 'node:fs'
31
+ import path from 'node:path'
32
+ import { fileURLToPath } from 'node:url'
33
+
34
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
35
+ const ROOT = path.join(__dirname, '..', '..', '..') // -> skweb-mono/
36
+ const PACKAGES_DIR = path.join(ROOT, 'packages')
37
+ const TEMPLATES_DIR = path.join(__dirname, '..', 'templates')
38
+
39
+ // ANSI 颜色(仅在 TTY 启用,避免污染 CI 日志)
40
+ const useColor = process.stdout.isTTY && !process.env.NO_COLOR
41
+ const color = (code) => (useColor ? `\x1b[${code}m` : '')
42
+ const cBold = color('1')
43
+ const cYellow = color('33')
44
+ const cRed = color('31')
45
+ const cGreen = color('32')
46
+ const cCyan = color('36')
47
+ const cReset = color('0')
48
+
49
+ function showHelp() {
50
+ console.log(`${cBold}sync-template-versions${cReset}
51
+ 把 packages/ 下的 skweb-* 版本号同步到 templates/ 下的 package.json。
52
+
53
+ ${cBold}用法${cReset}
54
+ ${cCyan}node scripts/sync-template-versions.mjs${cReset} ${cYellow}# 默认 dry-run${cReset}
55
+ ${cCyan}node scripts/sync-template-versions.mjs --apply${cReset} # 写回文件
56
+ ${cCyan}node scripts/sync-template-versions.mjs --strict${cReset} # 严格模式(CI 推荐)
57
+ ${cCyan}node scripts/sync-template-versions.mjs --help${cReset} # 查看帮助
58
+
59
+ ${cBold}同步规则${cReset}
60
+ - workspace 的 X.Y.Z 映射到模板的 ^X.Y.0
61
+ - 仅修改 skweb-* 开头的依赖
62
+ - 仅处理 templates 目录下 *.json
63
+
64
+ ${cBold}退出码${cReset}
65
+ 0 全部一致,或已 --apply 写回
66
+ 1 --strict 模式下发现不一致且未 --apply
67
+ 2 执行过程异常
68
+
69
+ ${cBold}同步规则说明${cReset}
70
+ 使用 ${cCyan}--apply${cReset} 真正写入文件;不带 --apply 永远只打印,不会改动模板。`)
71
+ }
72
+
73
+ const APPLY = process.argv.includes('--apply')
74
+ const STRICT = process.argv.includes('--strict')
75
+ const HELP = process.argv.includes('--help') || process.argv.includes('-h')
76
+
77
+ if (HELP) {
78
+ showHelp()
79
+ process.exit(0)
80
+ }
81
+
82
+ // 扫描 packages/ 下所有 package.json,返回 { 包名: 版本 } 映射。
83
+ function loadWorkspaceVersions() {
84
+ const result = {}
85
+ if (!fs.existsSync(PACKAGES_DIR)) {
86
+ throw new Error(`packages dir not found: ${PACKAGES_DIR}`)
87
+ }
88
+ for (const dir of fs.readdirSync(PACKAGES_DIR)) {
89
+ const pkgJsonPath = path.join(PACKAGES_DIR, dir, 'package.json')
90
+ if (!fs.existsSync(pkgJsonPath)) continue
91
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'))
92
+ if (pkg.name && pkg.version) {
93
+ result[pkg.name] = pkg.version
94
+ }
95
+ }
96
+ return result
97
+ }
98
+
99
+ // 把 X.Y.Z 转换为 ^X.Y.0 范围,允许 minor/patch 升级。
100
+ function toRange(version) {
101
+ const parts = version.split('.')
102
+ if (parts.length < 2) {
103
+ throw new Error(`unexpected version format: ${version}`)
104
+ }
105
+ return `^${parts[0]}.${parts[1]}.0`
106
+ }
107
+
108
+ // 同步单个模板文件,返回变更列表。
109
+ function syncTemplate(templatePath, workspaceVersions) {
110
+ const raw = fs.readFileSync(templatePath, 'utf-8')
111
+ const pkg = JSON.parse(raw)
112
+ const deps = pkg.dependencies || {}
113
+ const changes = []
114
+
115
+ for (const depName of Object.keys(deps)) {
116
+ if (!depName.startsWith('skweb-')) continue
117
+ if (!workspaceVersions[depName]) continue
118
+ const newRange = toRange(workspaceVersions[depName])
119
+ const oldRange = deps[depName]
120
+ if (oldRange !== newRange) {
121
+ changes.push({ dep: depName, old: oldRange, new: newRange })
122
+ deps[depName] = newRange
123
+ }
124
+ }
125
+
126
+ if (changes.length > 0 && APPLY) {
127
+ const updated = JSON.stringify(pkg, null, 2) + '\n'
128
+ fs.writeFileSync(templatePath, updated, 'utf-8')
129
+ }
130
+
131
+ return changes
132
+ }
133
+
134
+ function main() {
135
+ // 在最顶部打印运行模式,避免用户漏看后续信息
136
+ if (APPLY) {
137
+ console.log(`${cGreen}[sync] mode: APPLY (will write to files)${cReset}`)
138
+ } else {
139
+ console.log(`${cYellow}[sync] mode: DRY-RUN (no files will be modified; pass --apply to write)${cReset}`)
140
+ }
141
+ if (STRICT) {
142
+ console.log(`${cYellow}[sync] mode: STRICT (will exit 1 on pending changes)${cReset}`)
143
+ }
144
+ console.log('')
145
+
146
+ const workspaceVersions = loadWorkspaceVersions()
147
+ console.log(`[sync] workspace versions: ${Object.keys(workspaceVersions).length} packages`)
148
+ for (const [name, ver] of Object.entries(workspaceVersions)) {
149
+ console.log(` ${name}: ${ver} -> ${toRange(ver)}`)
150
+ }
151
+ console.log('')
152
+
153
+ if (!fs.existsSync(TEMPLATES_DIR)) {
154
+ throw new Error(`templates dir not found: ${TEMPLATES_DIR}`)
155
+ }
156
+
157
+ let totalChanges = 0
158
+ const templateDirs = fs.readdirSync(TEMPLATES_DIR).filter(d => {
159
+ const full = path.join(TEMPLATES_DIR, d)
160
+ return fs.statSync(full).isDirectory()
161
+ })
162
+
163
+ for (const tpl of templateDirs) {
164
+ const pkgJson = path.join(TEMPLATES_DIR, tpl, 'package.json')
165
+ if (!fs.existsSync(pkgJson)) continue
166
+ const changes = syncTemplate(pkgJson, workspaceVersions)
167
+ if (changes.length === 0) {
168
+ console.log(`[sync] ${tpl}/package.json: in sync`)
169
+ } else {
170
+ totalChanges += changes.length
171
+ const tag = APPLY ? `${cGreen}[APPLIED]${cReset}` : `${cYellow}[dry-run]${cReset}`
172
+ console.log(`[sync] ${tpl}/package.json: ${changes.length} update(s) ${tag}`)
173
+ for (const c of changes) {
174
+ console.log(` ${c.dep}: ${c.old} -> ${c.new}`)
175
+ }
176
+ }
177
+ }
178
+
179
+ console.log('')
180
+ if (totalChanges === 0) {
181
+ console.log(`${cGreen}[sync] All templates are in sync with workspace versions.${cReset}`)
182
+ } else if (APPLY) {
183
+ console.log(`${cGreen}[sync] Applied ${totalChanges} update(s).${cReset}`)
184
+ } else {
185
+ console.log(
186
+ `${cYellow}[sync] ${totalChanges} update(s) pending.${cReset} ` +
187
+ `${cBold}Re-run with ${cCyan}--apply${cReset}${cBold} to write.${cReset}`
188
+ )
189
+ if (STRICT) {
190
+ console.log(`${cRed}[sync] STRICT mode: exiting with code 1.${cReset}`)
191
+ process.exit(1)
192
+ }
193
+ }
194
+ }
195
+
196
+ try {
197
+ main()
198
+ } catch (err) {
199
+ console.error('[sync] FAILED:', err.message)
200
+ process.exit(2)
201
+ }
@@ -22,15 +22,15 @@
22
22
  "dependencies": {
23
23
  "@dotenvx/dotenvx": "^1.71.0",
24
24
  "http-errors": "^2.0.0",
25
- "skweb-express": "^1.0.0",
26
- "skweb-express-jwt": "^1.2.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",
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
34
  "winston": "^3.17.0",
35
35
  "sequelize": "^6.37.7",
36
36
  "swagger-jsdoc": "^6.2.8",
@@ -22,15 +22,15 @@
22
22
  "dependencies": {
23
23
  "@dotenvx/dotenvx": "^1.71.0",
24
24
  "http-errors": "^2.0.0",
25
- "skweb-express": "^1.0.0",
26
- "skweb-express-jwt": "^1.2.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",
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
34
  "winston": "^3.17.0",
35
35
  "sequelize": "^6.37.7",
36
36
  "swagger-jsdoc": "^6.2.8",
@@ -24,15 +24,15 @@
24
24
  "dependencies": {
25
25
  "@dotenvx/dotenvx": "^1.71.0",
26
26
  "http-errors": "^2.0.0",
27
- "skweb-express": "^1.0.0",
28
- "skweb-express-jwt": "^1.2.0",
29
- "skweb-express-logger": "^1.0.0",
30
- "skweb-sequelize": "^1.0.0",
31
- "skweb-redis": "^1.0.0",
32
- "skweb-cron": "^1.0.0",
33
- "skweb-framework": "^1.0.0",
34
- "skweb-plugin": "^1.0.0",
35
- "skweb-util": "^1.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
36
  "winston": "^3.17.0",
37
37
  "sequelize": "^6.37.7",
38
38
  "swagger-jsdoc": "^6.2.8",
@@ -48,10 +48,13 @@
48
48
  "mocha": "^11.7.5",
49
49
  "tsx": "^4.22.4",
50
50
  "typescript": "^5.9.3",
51
+ "tslib": "^2.8.1",
51
52
  "rollup": "^2.79.2",
52
53
  "@rollup/plugin-typescript": "^12.3.0",
54
+ "@rollup/plugin-json": "^6.1.0",
53
55
  "@rollup/plugin-node-resolve": "^16.0.3",
54
56
  "@rollup/plugin-commonjs": "^29.0.0",
57
+ "@rollup/plugin-terser": "^0.4.4",
55
58
  "eslint": "^9.39.1",
56
59
  "typescript-eslint": "^8.49.0"
57
60
  },
@@ -2,6 +2,7 @@ import resolve from '@rollup/plugin-node-resolve'
2
2
  import commonjs from '@rollup/plugin-commonjs'
3
3
  import typescript from '@rollup/plugin-typescript'
4
4
  import terser from '@rollup/plugin-terser'
5
+ import json from '@rollup/plugin-json'
5
6
 
6
7
  const isProduction = process.env.NODE_ENV === 'production'
7
8
 
@@ -15,6 +16,7 @@ export default {
15
16
  plugins: [
16
17
  resolve(),
17
18
  commonjs(),
19
+ json(),
18
20
  typescript({ tsconfig: './tsconfig.json' }),
19
21
  isProduction && terser()
20
22
  ],
@@ -37,7 +37,7 @@ async function startCronWorker(): Promise<void> {
37
37
  channel: 'cron:task:cmd',
38
38
  logger,
39
39
  onSaveTask: async (taskData: { taskId: string; cache: unknown; data: unknown }) => {
40
- const SysCronTask = framework.db?.sequelize?.models.SysCronTask as any
40
+ const SysCronTask = framework.dbInstance?.sequelize?.models.SysCronTask as any
41
41
  if (SysCronTask) {
42
42
  await SysCronTask.update(
43
43
  { cache: taskData.cache, data: taskData.data },
@@ -46,7 +46,7 @@ async function startCronWorker(): Promise<void> {
46
46
  }
47
47
  },
48
48
  loadTasks: async () => {
49
- const SysCronTask = framework.db?.sequelize?.models.SysCronTask as any
49
+ const SysCronTask = framework.dbInstance?.sequelize?.models.SysCronTask as any
50
50
  if (!SysCronTask) return []
51
51
  return (await SysCronTask.findAll()).map((t: any) => ({
52
52
  id: String(t.id),
@@ -1,14 +0,0 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
-
4
- const target = path.join(__dirname, '..', 'dist', 'cli.cjs')
5
- const shebang = '#!/usr/bin/env node\n'
6
-
7
- let content = fs.readFileSync(target, 'utf-8')
8
- if (!content.startsWith('#!')) {
9
- content = shebang + content
10
- fs.writeFileSync(target, content)
11
- console.log('[inject-shebang] Shebang added to dist/cli.cjs')
12
- } else {
13
- console.log('[inject-shebang] Shebang already present')
14
- }