typespeed 2.4.10 → 2.4.11

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.
@@ -21,10 +21,10 @@ jobs:
21
21
  ports:
22
22
  - 5672
23
23
  steps:
24
- - uses: actions/setup-node@v1
24
+ - uses: actions/checkout@v4
25
+ - uses: actions/setup-node@v4
25
26
  with:
26
- node-version: 16
27
- - uses: actions/checkout@v2
27
+ node-version: 22
28
28
  - name: Setup MySQL
29
29
  run: |
30
30
  sudo /etc/init.d/mysql start
@@ -32,12 +32,12 @@ jobs:
32
32
  CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`)) \
33
33
  ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;SHOW TABLES;' -uroot -proot
34
34
  - name: 'Cache node_modules'
35
- uses: actions/cache@v2
35
+ uses: actions/cache@v4
36
36
  with:
37
37
  path: ~/.npm
38
- key: ${{ runner.os }}-node-v18-${{ hashFiles('**/package.json') }}
38
+ key: ${{ runner.os }}-node-v22-${{ hashFiles('**/package.json') }}
39
39
  restore-keys: |
40
- ${{ runner.os }}-node-v18-
40
+ ${{ runner.os }}-node-v22-
41
41
  - name: Install Dependencies
42
42
  run: npm install
43
43
  - name: Run Tests with Coverage
package/CHANGELOG.md ADDED
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ typespeed 版本演进记录。本文件 2026-09-06 从 git 历史反推建立;git 最早提交 2022-09-18(ch01)。
4
+
5
+ ## 2.4.x(当前 2.4.10)
6
+
7
+ - **2.4.10**:升级 jsonwebtoken 和 mysql2 库(2024-05-07,当前 HEAD)
8
+ - **2.4.9**:修复 SocketIO、MQ、Redis 等对象获取不准确问题(2024-04-22)
9
+ - **2.4.8**:修复 socket.io 未从 bean 工厂获取装饰类的问题;修复 select 返回值不为 null 的问题(2024-04-22)
10
+ - **2.4.7**:logx 日志模块(2024-04-21)
11
+ - **2.4.6**:修复 redis 实例错误问题(2024-03-17)
12
+ - **2.4.5**:版本发布(2023-12-14)
13
+ - **2.4.4**:版本发布(2023-12-01)
14
+ - **2.4.3**:`@redisSubscriber` 装饰器在无 redis 配置时抛异常;修复生成 dist 目录问题;getRootPath 兼容 Windows(2023-11-15)
15
+ - **2.4.2**:修复 database where 条件 AND 匹配超过 2 个时拼装出错的问题(2023-10-23)
16
+ - **2.4.1**:补充 introduction 目录的装饰器允许配置(2023-08-04)
17
+ - **2.4.0**:socket.io 完成——disconnect / handshake(connected)/ 房间示例 / 全部测试用例(2023-08-04)
18
+
19
+ ## 2.3.x(2023-06 ~ 2023-07)
20
+
21
+ - **2.3.6**:增加应用目录路径配置(2023-07-06)
22
+ - **2.3.5**:增加 redis 订阅模式(需开启两个 redis 实例);增加 zranking / zrevranking 返回排名与分数的 Map,方便开发排行榜逻辑(2023-06-29)
23
+ - **2.3.4**:CI 完善——限制只有 main 分支执行测试、调整测试 node 版本为 16、增加覆盖率 badge;改正 MQ 测试方法(2023-06-28)
24
+ - **2.3.3**:修复 jwt 拦截器问题;fixed d.ts
25
+ - **2.3.2**:start 增加 callback 参数;修改拦截器逻辑
26
+ - **2.3.1**:版本发布
27
+ - **2.3.0**:测试体系搭建——首个测试程序、cookie / session 测试、second page 测试(header / 文件上传 / jwt)、数据库读写测试(修正 resultType 问题)、测试程序增加 rabbitmq 配置
28
+
29
+ ## 2.2.x
30
+
31
+ - **2.2.1**:修改并增加测试逻辑
32
+ - **2.2.0**:express 返回 listen 对象方便停止服务;修改 core 获取应用程序 main 地址的方式,使通过其他方式启动的程序也能正常获得应用地址;更新获取应用程序路径方法(第一层引入时检查堆栈)
33
+
34
+ ## 2.1.x
35
+
36
+ - **2.1.3**:去除无关依赖
37
+ - **2.1.2**:升级 consolidate;`@reqParam` / `@reqQuery` 可省略参数直接使用参数名
38
+ - **2.1.1**:版本发布
39
+ - **2.1.0**:去除实验相关代码,更新引用地址
40
+
41
+ ## 2.0.x
42
+
43
+ - **2.0.23**:增加 9 个请求方法的注释
44
+ - **2.0.22**:完成 9 个请求参数的赋值装饰器;解决路由方法参数个数统计问题(before / after 一并处理);增加全局权限认证方法,完成全局认证类测试(JWT)
45
+ - **2.0.21**:增加 debug 日志打印
46
+ - **2.0.20**:增加 README 内容
47
+ - **2.0.19**:修正 README 内一个图标失效问题
48
+ - **2.0.18**:增加导出内容的注释
49
+ - **2.0.17 / 2.0.16**:版本发布
50
+ - **2.0.15**:添加 d.ts 文件并去除自动生成的
51
+ - **2.0.14**:将 rabbitmq 整合
52
+ - **2.0.13**:初始情况 rabbitmq 不监听;解决 async / await 问题;初步完成 mq 装饰器与发送
53
+ - **2.0.12**:增加 Rabbit MQ 的测试
54
+ - **2.0.11 / 2.0.10 / 2.0.9 / 2.0.8 / 2.0.7**:发布与 package.json 脚本调整
55
+ - **2.0.6**:修正 command 命令出错问题;补充装饰器介绍示例代码、访问器装饰器、入门材料
56
+ - **2.0.5 / 2.0.4**:版本发布
57
+ - **2.0.3**:修正 command 命令出错问题;更新脚手架的模板文件以避免 tsc 编译
58
+ - **2.0.2**:增加脚手架(typespeed 命令行)
59
+ - **2.0.1**:首个 2.0 发布(调整 npm 发布脚本、统一载入入口)
60
+
61
+ ## 早期原型期(2022-09 起,v2.0 之前)
62
+
63
+ 基于 ch01 / ch02 系列实验提交(`685ee1b` 起)的框架核心能力开发:
64
+
65
+ - **装饰器体系**:`@start` / `@app` / `@bean` / `@log` / 注入 / 参数注入(autoware / inject 调整)
66
+ - **AOP**:before / after 拦截完成
67
+ - **Web 路由**:修饰器路由、路由中间件(basicAuth / jwt / upload 先后顺序处理)、404 与 500 错误页面、async / await 支持
68
+ - **数据层**:Insert / Update / Delete / Select 完成;SQL 参数注入(`?` 编号绑定);ResultType 标记查询结果类型;ORM 化(Model 继承:findAll / findOne / create / delete / findCount / update / incr / decr);分页查询;nodeCache 缓存(新增/修改时按版本号刷新)
69
+ - **基础设施**:静态资源、favicon、compression、cookies、session(Redis 存储)、文件上传(multiparty + 路由中间件)、多模版引擎(consolidate)、配置系统(全局配置 + 覆盖)、读写库(主从)接入
70
+ - **集成**:Redis 一般使用(避免启动连不上报错)、schedule 定时器、外部载入结构调整(统一载入入口)
package/README.md CHANGED
@@ -1,32 +1,74 @@
1
1
  # TypeSpeed Framework
2
2
 
3
- [![typescript](https://badgen.net/badge/icon/TypeScript?icon=typescript&label)](https://www.npmjs.com/package/typespeed)
4
- [![npm](https://badgen.net/npm/v/typespeed?color=cyan)](https://www.npmjs.com/package/typespeed)
5
- [![downloads](https://badgen.net/npm/dt/typespeed?color=pink)](https://www.npmjs.com/package/typespeed)
6
- [![license](https://badgen.net/github/license/speedphp/typespeed)](https://github.com/SpeedPHP/typespeed/blob/main/LICENSE)
7
- [![GitHub Build Status](https://img.shields.io/github/actions/workflow/status/speedphp/typespeed/test.yml)](https://github.com/SpeedPHP/typespeed/commits/main)
8
- [![Codecov](https://img.shields.io/codecov/c/github/speedphp/typespeed)
9
- ](https://codecov.io/gh/SpeedPHP/typespeed)
3
+
4
+
5
+ ![typescript](https://badgen.net/badge/icon/TypeScript?icon=typescript\&label)
6
+
7
+
8
+
9
+ ![npm](https://badgen.net/npm/v/typespeed?color=cyan)
10
+
11
+
12
+
13
+ ![downloads](https://badgen.net/npm/dt/typespeed?color=pink)
14
+
15
+
16
+
17
+ ![license](https://badgen.net/github/license/speedphp/typespeed)
18
+
19
+
20
+
21
+ ![GitHub Build Status](https://img.shields.io/github/actions/workflow/status/speedphp/typespeed/test.yml)
22
+
23
+
24
+
25
+ ![Codecov](https://img.shields.io/codecov/c/github/speedphp/typespeed)
26
+
27
+ ### 资料体系
28
+
29
+ TypeSpeed 不只提供一个框架,还配有完整的「书 + 视频 + 双源码」学习资料:
30
+
31
+
32
+
33
+ * **书**:《TypeScript 框架开发实践(微课视频版)》(曾振中 著,清华大学出版社)——[京东购买](https://item.jd.com/14275373.html)
34
+
35
+ * **视频课程**:随书微课视频(每节配套源码快照见 ts-practice)
36
+
37
+ * **附书源码・ts-book**:[https://github.com/speedphp/ts-book](https://github.com/speedphp/ts-book)—— 按章组织(chapter01 \~ chapter06),每章含可运行示例
38
+
39
+ * **视频代码・ts-practice**:[https://github.com/speedphp/ts-practice](https://github.com/speedphp/ts-practice)—— 按书籍章节号打 tag(如 `4.10.4` = 第 4 章第 10 节第 4 步),每节视频对应一份可跑源码快照
10
40
 
11
41
  ### 特点
12
42
 
13
- - 遵循 MIT 许可的开源项目。
14
- - 提供 31 个 TypeScript 装饰器,这些装饰器构成了完整的 Web 框架功能,包括对象管理、Web 路由、数据库操作等。
15
- - 通过命令行脚手架,可以快速创建项目,零配置启动。
16
- - 基于依赖注入、AOP、中间件和启动扫描等编程理念开发实现。
17
- - 底层采用 ExpressJS 实现,提供稳定、快速的 Web 服务。
18
- - 框架提供了两种风格不同却各具优点的数据操作模式。
43
+
44
+
45
+ * 遵循 MIT 许可的开源项目。
46
+
47
+ * 提供 31 TypeScript 装饰器,这些装饰器构成了完整的 Web 框架功能,包括对象管理、Web 路由、数据库操作等。
48
+
49
+ * 通过命令行脚手架,可以快速创建项目,零配置启动。
50
+
51
+ * 基于依赖注入、AOP、中间件和启动扫描等编程理念开发实现。
52
+
53
+ * 底层采用 ExpressJS 实现,提供稳定、快速的 Web 服务。
54
+
55
+ * 框架提供了两种风格不同却各具优点的数据操作模式。
19
56
 
20
57
  ### 安装
21
58
 
22
59
  TypeSpeed 环境要求 NodeJS 16+,TypeScript 运行时。
23
60
 
24
- ```sh
61
+
62
+
63
+ ```
25
64
  npm install typespeed -g
26
65
  ```
66
+
27
67
  ### 使用
28
68
 
29
- ```sh
69
+
70
+
71
+ ```
30
72
  typespeed new blog
31
73
 
32
74
  cd ./blog
package/dist/typespeed.js CHANGED
@@ -86,10 +86,14 @@ function value(configPath) {
86
86
  }
87
87
  exports.value = value;
88
88
  function getRootPath(lines) {
89
- const macths = ["at Function.Module._load", "at Module.require", "at require", "at Object.<anonymous>"];
89
+ // 兼容新旧 Node 栈帧(Node<22: "Function.Module._load" / Node22+: "Function._load")、
90
+ // mocha(ts-node) 下 "Context.<anonymous>" 与中间可能插入的 "wrapModuleLoad" 帧:
91
+ // 按顺序出现匹配(不要求严格相邻),提高在各种加载器下的容错。
92
+ const macths = [/at Function(\.Module)?\._load/, "at Module.require", /at require\b/, /at (Object|Context)\.<anonymous>/];
90
93
  let matchIndex = 0;
91
94
  for (let line of lines) {
92
- if (line.includes(macths[matchIndex])) {
95
+ const matcher = macths[matchIndex];
96
+ if (matcher instanceof RegExp ? matcher.test(line) : line.includes(matcher)) {
93
97
  if (matchIndex === macths.length - 1) {
94
98
  let arr = line.split("(")[1].split(":");
95
99
  arr.pop();
@@ -98,9 +102,6 @@ function getRootPath(lines) {
98
102
  }
99
103
  matchIndex++;
100
104
  }
101
- else {
102
- matchIndex = 0;
103
- }
104
105
  }
105
106
  return undefined;
106
107
  }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "typespeed",
3
- "version": "2.4.10",
3
+ "version": "2.4.11",
4
4
  "description": "A new Framework for TypeScript.",
5
5
  "author": "speedphp",
6
6
  "license": "MIT License",
7
7
  "scripts": {
8
- "test": "mocha --require ts-node/register test/**/*.ts --exit",
8
+ "test": "NODE_OPTIONS=--no-experimental-strip-types mocha --require ts-node/register test/**/*.ts --exit",
9
9
  "test-with-coverage": "nyc --reporter=lcov npm test",
10
10
  "start": "ts-node --transpile-only app/src/main.ts",
11
11
  "build": "tsc -p .",
package/src/typespeed.ts CHANGED
@@ -70,19 +70,21 @@ function value(configPath: string): any {
70
70
  }
71
71
 
72
72
  function getRootPath(lines: string[]) {
73
- const macths = ["at Function.Module._load", "at Module.require", "at require", "at Object.<anonymous>"];
73
+ // 兼容新旧 Node 栈帧(Node<22: "Function.Module._load" / Node22+: "Function._load")、
74
+ // mocha(ts-node) 下 "Context.<anonymous>" 与中间可能插入的 "wrapModuleLoad" 帧:
75
+ // 按顺序出现匹配(不要求严格相邻),提高在各种加载器下的容错。
76
+ const macths = [/at Function(\.Module)?\._load/, "at Module.require", /at require\b/, /at (Object|Context)\.<anonymous>/];
74
77
  let matchIndex = 0;
75
78
  for (let line of lines) {
76
- if (line.includes(macths[matchIndex])) {
77
- if(matchIndex === macths.length - 1) {
79
+ const matcher = macths[matchIndex];
80
+ if (matcher instanceof RegExp ? matcher.test(line) : line.includes(matcher)) {
81
+ if (matchIndex === macths.length - 1) {
78
82
  let arr = line.split("(")[1].split(":")
79
83
  arr.pop()
80
84
  arr.pop()
81
85
  return arr.join(':')
82
86
  }
83
87
  matchIndex++;
84
- }else{
85
- matchIndex = 0;
86
88
  }
87
89
  }
88
90
  return undefined;
@@ -0,0 +1,31 @@
1
+ services:
2
+ mysql:
3
+ image: mysql:8.0
4
+ container_name: typespeed-test-mysql
5
+ environment:
6
+ MYSQL_ROOT_PASSWORD: root
7
+ MYSQL_DATABASE: test
8
+ ports:
9
+ - "3306:3306"
10
+ volumes:
11
+ - ./mysql-init:/docker-entrypoint-initdb.d
12
+ healthcheck:
13
+ test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-proot"]
14
+ interval: 3s
15
+ timeout: 3s
16
+ retries: 20
17
+
18
+ redis:
19
+ image: redis:7
20
+ container_name: typespeed-test-redis
21
+ ports:
22
+ - "6379:6379"
23
+
24
+ rabbitmq:
25
+ image: rabbitmq:3.8
26
+ container_name: typespeed-test-rabbitmq
27
+ environment:
28
+ RABBITMQ_DEFAULT_USER: guest
29
+ RABBITMQ_DEFAULT_PASS: guest
30
+ ports:
31
+ - "5672:5672"
@@ -0,0 +1,8 @@
1
+ -- 与 CI 的 Setup MySQL 步骤一致:建 test 库 + user 表
2
+ CREATE DATABASE IF NOT EXISTS test DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
3
+ USE test;
4
+ CREATE TABLE IF NOT EXISTS `user` (
5
+ `id` int(11) NOT NULL AUTO_INCREMENT,
6
+ `name` varchar(100) DEFAULT NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
@@ -0,0 +1,69 @@
1
+ # 本地 Docker 测试方案
2
+
3
+ typespeed 测试依赖三个外部服务(MySQL / Redis / RabbitMQ),本机没有常驻服务时用 Docker 起一套与 CI 一致的环境来跑测试。
4
+
5
+ ## 一、前置条件
6
+
7
+ - 本机已安装 **OrbStack**(或 Docker Desktop),Docker CLI 可用:`docker --version`
8
+ - 若 OrbStack 未运行,先启动它(菜单栏点开即可,或 `open -a OrbStack`)
9
+ - 端口占用:默认映射 `3306 / 6379 / 5672`,起容器前确认空闲(`nc -z localhost 3306` 等)
10
+
11
+ ## 二、一键启动测试依赖
12
+
13
+ ```bash
14
+ cd /Users/zzz/book/typespeed
15
+ docker compose -f test-env/docker-compose.test.yml up -d
16
+ ```
17
+
18
+ 启动三个容器:
19
+
20
+ | 服务 | 容器名 | 端口 | 账号 |
21
+ |------|--------|------|------|
22
+ | MySQL 8.0 | typespeed-test-mysql | 127.0.0.1:3306 | root / root,库 `test` |
23
+ | Redis 7 | typespeed-test-redis | 127.0.0.1:6379 | 无 |
24
+ | RabbitMQ 3.8 | typespeed-test-rabbitmq | 127.0.0.1:5672 | guest / guest |
25
+
26
+ MySQL 首次启动会自动执行 `test-env/mysql-init/init.sql`(建 `test` 库 + `user` 表,与 CI 的 Setup MySQL 步骤一致)。
27
+
28
+ 检查就绪状态:
29
+
30
+ ```bash
31
+ docker compose -f test-env/docker-compose.test.yml ps # 三容器 Up 且 mysql 为 healthy
32
+ docker exec typespeed-test-mysql mysql -uroot -proot -e "USE test; SHOW TABLES;"
33
+ docker exec typespeed-test-redis redis-cli ping # PONG
34
+ docker exec typespeed-test-rabbitmq rabbitmq-diagnostics -q ping # Ping succeeded
35
+ ```
36
+
37
+ ## 三、跑测试
38
+
39
+ ```bash
40
+ npm test
41
+ ```
42
+
43
+ 预期:`51 passing`。
44
+
45
+ > 说明:`package.json` 的 test 脚本已加 `NODE_OPTIONS=--no-experimental-strip-types`,这是 Node 22 下 mocha 加载 CJS 风格 .ts 测试的必需项(否则报 `require is not defined`)。
46
+
47
+ ## 四、收尾
48
+
49
+ ```bash
50
+ docker compose -f test-env/docker-compose.test.yml down # 停容器(保留数据卷需加 -v)
51
+ ```
52
+
53
+ ## 五、本次排障记录(2026-09-06)
54
+
55
+ 本地 `npm test` 曾长期 0 passing / 47 failing,所有请求返回 404 错误页(`src/default/pages/404.html`,即 MIT License 模板页)。曾误判为"缺本地服务"(环境差异),用 Docker 起齐服务后依然全挂,最终定位为**框架根因**:
56
+
57
+ 1. `src/typespeed.ts` 的 `getRootPath()` 靠匹配调用栈推断应用根目录(`mainPath`),原匹配写死旧版 Node 栈帧格式 `at Function.Module._load` 和 `at Object.<anonymous>`:
58
+ - Node 22 的帧是 `at Function._load`(少了 `Module.`);
59
+ - mocha 下 hooks 的帧是 `at Context.<anonymous>`(不是 `Object.`),且 `Function._load` 与 `Module.require` 之间会插入 `wrapModuleLoad` 帧。
60
+ - 匹配全部落空 → `mainPath` 回退成 mocha 的 bin 目录 → config 不加载、app/src 下组件不加载、路由不注册 → 一切请求 404。
61
+ 2. 修复:`getRootPath` 改为**按顺序出现匹配**(不要求帧严格相邻),帧格式用正则兼容新旧 Node 与 mocha。改动见 `src/typespeed.ts`(未提交)。
62
+ 3. 修复后本地 `npm test` 全绿 **51 passing (3s)**。
63
+ 4. 连带影响:CI 若从 node 16 升到 node 22(见 0.4 改动),旧的栈匹配同样会失效——本修复对 CI 也是必需的。
64
+
65
+ ## 六、附:docker-compose.test.yml 内容要点
66
+
67
+ - 服务定义与 CI(`.github/workflows/test.yml`)的 services 保持一致:mysql root/root + `test` 库、redis、rabbitmq guest/guest。
68
+ - MySQL 加了 healthcheck,避免测试启动时库还没就绪。
69
+ - 初始化 SQL 挂在 `test-env/mysql-init/init.sql`,与 CI 建表语句一致。