@sansenjian/qq-music-api 2.1.1 → 2.2.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.
Files changed (173) hide show
  1. package/.babelrc +4 -0
  2. package/.eslintrc.json +20 -19
  3. package/AGENTS.md +153 -0
  4. package/README.md +162 -136
  5. package/{app.js → app.ts} +24 -31
  6. package/config/user-info.ts +71 -0
  7. package/index.ts +1 -0
  8. package/{jest.config.js → jest.config.ts} +19 -7
  9. package/middlewares/koa-cors.ts +81 -0
  10. package/module/apis/UCommon/UCommon.ts +13 -0
  11. package/module/apis/album/getAlbumInfo.ts +22 -0
  12. package/module/apis/comments/getComments.ts +23 -0
  13. package/module/apis/digitalAlbum/getDigitalAlbumLists.ts +23 -0
  14. package/module/apis/downloadQQMusic.ts +51 -0
  15. package/module/apis/music/getLyric.ts +34 -0
  16. package/module/apis/mv/getMvByTag.ts +24 -0
  17. package/module/apis/radio/getRadioLists.ts +27 -0
  18. package/module/apis/rank/getTopLists.ts +37 -0
  19. package/module/apis/search/getHotKey.ts +24 -0
  20. package/module/apis/search/getSearchByKey.ts +31 -0
  21. package/module/apis/search/getSmartbox.ts +43 -0
  22. package/module/apis/singers/getSimilarSinger.ts +25 -0
  23. package/module/apis/singers/getSingerDesc.ts +25 -0
  24. package/module/apis/singers/getSingerMv.ts +24 -0
  25. package/module/apis/singers/getSingerStarNum.ts +24 -0
  26. package/module/apis/songLists/songListCategories.ts +22 -0
  27. package/module/apis/songLists/songListDetail.ts +27 -0
  28. package/module/apis/songLists/songLists.ts +35 -0
  29. package/module/apis/u_common.ts +29 -0
  30. package/module/apis/user/checkQQLoginQr.ts +230 -0
  31. package/module/apis/user/getQQLoginQr.ts +28 -0
  32. package/module/apis/user/getUserAvatar.ts +32 -0
  33. package/module/apis/user/getUserLikedSongs.ts +145 -0
  34. package/module/apis/user/getUserPlaylists.ts +163 -0
  35. package/module/apis/y_common.ts +44 -0
  36. package/module/config.ts +24 -0
  37. package/module/index.ts +95 -0
  38. package/package.json +25 -6
  39. package/pnpm-workspace.yaml +2 -0
  40. package/public/index.html +411 -29
  41. package/routers/context/batchGetSongInfo.ts +60 -0
  42. package/routers/context/batchGetSongLists.ts +46 -0
  43. package/routers/context/checkQQLoginQr.ts +19 -0
  44. package/routers/context/{cookies.js → cookies.ts} +14 -12
  45. package/routers/context/getAlbumInfo.ts +31 -0
  46. package/routers/context/getComments.ts +51 -0
  47. package/routers/context/getDigitalAlbumLists.ts +18 -0
  48. package/routers/context/getDownloadQQMusic.ts +17 -0
  49. package/routers/context/getHotkey.ts +25 -0
  50. package/routers/context/getImageUrl.ts +29 -0
  51. package/routers/context/getLyric.ts +32 -0
  52. package/routers/context/getMusicPlay.ts +102 -0
  53. package/routers/context/getMv.ts +61 -0
  54. package/routers/context/getMvByTag.ts +18 -0
  55. package/routers/context/getMvPlay.ts +114 -0
  56. package/routers/context/getNewDisks.ts +58 -0
  57. package/routers/context/getQQLoginQr.ts +16 -0
  58. package/routers/context/getRadioLists.ts +18 -0
  59. package/routers/context/getRanks.ts +67 -0
  60. package/routers/context/getRecommend.ts +92 -0
  61. package/routers/context/getSearchByKey.ts +34 -0
  62. package/routers/context/getSimilarSinger.ts +29 -0
  63. package/routers/context/getSingerAlbum.ts +58 -0
  64. package/routers/context/getSingerDesc.ts +30 -0
  65. package/routers/context/getSingerHotsong.ts +58 -0
  66. package/routers/context/getSingerList.ts +56 -0
  67. package/routers/context/getSingerMv.ts +41 -0
  68. package/routers/context/getSingerStarNum.ts +29 -0
  69. package/routers/context/getSmartbox.ts +27 -0
  70. package/routers/context/getSongInfo.ts +51 -0
  71. package/routers/context/{getSongListCategories.js → getSongListCategories.ts} +5 -4
  72. package/routers/context/getSongListDetail.ts +22 -0
  73. package/routers/context/getSongLists.ts +30 -0
  74. package/routers/context/getTicketInfo.ts +51 -0
  75. package/routers/context/getTopLists.ts +18 -0
  76. package/routers/context/getUserAvatar.ts +53 -0
  77. package/routers/context/getUserLikedSongs.ts +28 -0
  78. package/routers/context/getUserPlaylists.ts +29 -0
  79. package/routers/context/index.ts +87 -0
  80. package/routers/{router.js → router.ts} +7 -55
  81. package/routers/types.ts +18 -0
  82. package/routers/util.ts +231 -0
  83. package/tests/integration/api/api.test.ts +852 -0
  84. package/tests/integration/middleware/{cors.test.js → cors.test.ts} +7 -3
  85. package/tests/setup/jest.setup.ts +15 -0
  86. package/tests/setup/testUtils.ts +35 -0
  87. package/tests/unit/util/request.test.ts +177 -0
  88. package/tsconfig.json +20 -0
  89. package/tsconfig.test.json +8 -0
  90. package/types/api.ts +105 -0
  91. package/types/global.d.ts +26 -0
  92. package/types/index.d.ts +97 -0
  93. package/util/apiResponse.ts +97 -0
  94. package/util/colors.ts +31 -0
  95. package/util/cookie.ts +40 -0
  96. package/util/{loginUtils.js → loginUtils.ts} +3 -5
  97. package/util/lyricParse.ts +86 -0
  98. package/util/request.ts +141 -0
  99. package/.github/FUNDING.yml +0 -12
  100. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  101. package/.github/ISSUE_TEMPLATE/custom.md +0 -24
  102. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  103. package/config/user-info.js +0 -42
  104. package/index.js +0 -1
  105. package/middlewares/koa-cors.js +0 -97
  106. package/module/apis/UCommon/UCommon.js +0 -6
  107. package/module/apis/album/getAlbumInfo.js +0 -33
  108. package/module/apis/comments/getComments.js +0 -35
  109. package/module/apis/digitalAlbum/getDigitalAlbumLists.js +0 -34
  110. package/module/apis/downloadQQMusic.js +0 -41
  111. package/module/apis/music/getLyric.js +0 -41
  112. package/module/apis/mv/getMvByTag.js +0 -35
  113. package/module/apis/radio/getRadioLists.js +0 -38
  114. package/module/apis/rank/getTopLists.js +0 -44
  115. package/module/apis/search/getHotKey.js +0 -35
  116. package/module/apis/search/getSearchByKey.js +0 -45
  117. package/module/apis/search/getSmartbox.js +0 -34
  118. package/module/apis/singers/getSimilarSinger.js +0 -36
  119. package/module/apis/singers/getSingerDesc.js +0 -37
  120. package/module/apis/singers/getSingerMv.js +0 -35
  121. package/module/apis/singers/getSingerStarNum.js +0 -35
  122. package/module/apis/songLists/songListCategories.js +0 -33
  123. package/module/apis/songLists/songListDetail.js +0 -38
  124. package/module/apis/songLists/songLists.js +0 -41
  125. package/module/apis/u_common.js +0 -17
  126. package/module/apis/user/checkQQLoginQr.js +0 -125
  127. package/module/apis/user/getQQLoginQr.js +0 -17
  128. package/module/apis/y_common.js +0 -27
  129. package/module/config.js +0 -31
  130. package/module/index.js +0 -82
  131. package/routers/context/batchGetSongInfo.js +0 -59
  132. package/routers/context/batchGetSongLists.js +0 -50
  133. package/routers/context/checkQQLoginQr.js +0 -17
  134. package/routers/context/getAlbumInfo.js +0 -27
  135. package/routers/context/getComments.js +0 -51
  136. package/routers/context/getDigitalAlbumLists.js +0 -14
  137. package/routers/context/getDownloadQQMusic.js +0 -14
  138. package/routers/context/getHotkey.js +0 -14
  139. package/routers/context/getImageUrl.js +0 -34
  140. package/routers/context/getLyric.js +0 -26
  141. package/routers/context/getMusicPlay.js +0 -116
  142. package/routers/context/getMv.js +0 -56
  143. package/routers/context/getMvByTag.js +0 -15
  144. package/routers/context/getMvPlay.js +0 -128
  145. package/routers/context/getNewDisks.js +0 -50
  146. package/routers/context/getQQLoginQr.js +0 -12
  147. package/routers/context/getRadioLists.js +0 -14
  148. package/routers/context/getRanks.js +0 -103
  149. package/routers/context/getRecommend.js +0 -86
  150. package/routers/context/getSearchByKey.js +0 -33
  151. package/routers/context/getSimilarSinger.js +0 -25
  152. package/routers/context/getSingerAlbum.js +0 -52
  153. package/routers/context/getSingerDesc.js +0 -25
  154. package/routers/context/getSingerHotsong.js +0 -52
  155. package/routers/context/getSingerList.js +0 -51
  156. package/routers/context/getSingerMv.js +0 -32
  157. package/routers/context/getSingerStarNum.js +0 -24
  158. package/routers/context/getSmartbox.js +0 -24
  159. package/routers/context/getSongInfo.js +0 -49
  160. package/routers/context/getSongListDetail.js +0 -25
  161. package/routers/context/getSongLists.js +0 -32
  162. package/routers/context/getTicketInfo.js +0 -45
  163. package/routers/context/getTopLists.js +0 -15
  164. package/routers/context/index.js +0 -74
  165. package/tests/integration/api/api.test.js +0 -116
  166. package/tests/setup/jest.setup.js +0 -46
  167. package/tests/setup/testUtils.js +0 -106
  168. package/tests/unit/util/lyricParse.test.js +0 -97
  169. package/tests/unit/util/request.test.js +0 -66
  170. package/util/colors.js +0 -16
  171. package/util/cookie.js +0 -22
  172. package/util/lyricParse.js +0 -67
  173. package/util/request.js +0 -57
@@ -0,0 +1,163 @@
1
+ import request from '../../../util/request';
2
+ import { customResponse, errorResponse } from '../../../util/apiResponse';
3
+ import type { ApiResponse } from '../../../types/api';
4
+
5
+ interface UserPlaylistItem {
6
+ [key: string]: unknown;
7
+ }
8
+
9
+ const DEBUG_ENABLED = process.env.DEBUG === 'true';
10
+
11
+ const debugLog = (message: string, payload?: unknown) => {
12
+ if (DEBUG_ENABLED) {
13
+ console.log(`[getUserPlaylists] ${message}`, payload ?? '');
14
+ }
15
+ };
16
+
17
+ const getNamedCandidateEntries = (payload: Record<string, any>) => [
18
+ ['data.mydiss.list', payload?.data?.mydiss?.list],
19
+ ['data.mymusic', payload?.data?.mymusic],
20
+ ['data.createdDissList', payload?.data?.createdDissList],
21
+ ['data.createdList', payload?.data?.createdList],
22
+ ['data.creator', payload?.data?.creator],
23
+ ['data.creator.playlist', payload?.data?.creator?.playlist],
24
+ ['data.creator.playlists', payload?.data?.creator?.playlists],
25
+ ['data.playlist', payload?.data?.playlist],
26
+ ['data.playlists', payload?.data?.playlists],
27
+ ['mydiss.list', payload?.mydiss?.list],
28
+ ['mymusic', payload?.mymusic],
29
+ ['createdDissList', payload?.createdDissList],
30
+ ['createdList', payload?.createdList],
31
+ ['creator', payload?.creator],
32
+ ['creator.playlist', payload?.creator?.playlist],
33
+ ['creator.playlists', payload?.creator?.playlists],
34
+ ['playlist', payload?.playlist],
35
+ ['playlists', payload?.playlists]
36
+ ] as const;
37
+
38
+ const extractPlaylists = (payload: Record<string, any>): UserPlaylistItem[] => {
39
+ debugLog('payload top-level keys', Object.keys(payload || {}));
40
+ debugLog('payload.data keys', payload?.data && typeof payload.data === 'object' ? Object.keys(payload.data) : []);
41
+
42
+ const matchedEntry = getNamedCandidateEntries(payload).find(([, candidate]) => Array.isArray(candidate));
43
+
44
+ if (matchedEntry) {
45
+ const [candidatePath, playlists] = matchedEntry;
46
+ debugLog('matched playlist candidate', {
47
+ candidatePath,
48
+ length: (playlists as unknown[]).length
49
+ });
50
+ return playlists as UserPlaylistItem[];
51
+ }
52
+
53
+ debugLog(
54
+ 'playlist candidates summary',
55
+ getNamedCandidateEntries(payload).map(([candidatePath, candidate]) => ({
56
+ candidatePath,
57
+ type: Array.isArray(candidate) ? 'array' : typeof candidate,
58
+ keys: candidate && typeof candidate === 'object' && !Array.isArray(candidate) ? Object.keys(candidate) : undefined
59
+ }))
60
+ );
61
+
62
+ throw new Error('用户歌单响应中未找到歌单列表字段');
63
+ };
64
+
65
+ const getErrorMessage = (payload: Record<string, any>): string => {
66
+ const candidates = [payload.message, payload.msg, payload.errmsg, payload.error];
67
+ const matched = candidates.find(candidate => typeof candidate === 'string' && candidate.trim() !== '');
68
+ return (matched as string | undefined) || '获取用户歌单失败';
69
+ };
70
+
71
+ // 获取用户创建的歌单
72
+ // 注意:此接口需要有效的 QQ 音乐 Cookie 才能正常工作
73
+ export const getUserPlaylists = async (params: {
74
+ uin: string;
75
+ offset?: number;
76
+ limit?: number;
77
+ }): Promise<ApiResponse> => {
78
+ const { uin, offset = 0, limit = 30 } = params;
79
+
80
+ // 使用 c6.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg 接口
81
+ // 这是通过 Chrome DevTools 抓包发现的实际使用的接口
82
+ const url = 'https://c6.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg';
83
+ const pageOffset = offset % limit;
84
+
85
+ try {
86
+ debugLog('request meta', {
87
+ url,
88
+ uin,
89
+ offset,
90
+ limit,
91
+ pageOffset,
92
+ hasGlobalCookie: Boolean(global.userInfo?.cookie),
93
+ cookieLength: global.userInfo?.cookie?.length || 0
94
+ });
95
+
96
+ const response = await request<Record<string, any>>({
97
+ url,
98
+ method: 'GET',
99
+ isUUrl: 'u',
100
+ options: {
101
+ params: {
102
+ _: Date.now(),
103
+ cv: 4747474,
104
+ ct: 24,
105
+ format: 'json',
106
+ inCharset: 'utf-8',
107
+ outCharset: 'utf-8',
108
+ notice: 0,
109
+ platform: 'yqq.json',
110
+ needNewCode: 0,
111
+ uin: Number.parseInt(uin, 10),
112
+ g_tk_new_20200303: 0,
113
+ g_tk: 0,
114
+ cid: 205360838,
115
+ userid: Number.parseInt(uin, 10),
116
+ reqfrom: 1,
117
+ reqtype: 0,
118
+ hostUin: 0,
119
+ loginUin: Number.parseInt(uin, 10)
120
+ },
121
+ headers: {
122
+ Referer: `https://y.qq.com/portal/profile.html?uin=${uin}`,
123
+ Cookie: global.userInfo?.cookie || ''
124
+ }
125
+ }
126
+ });
127
+
128
+ const payload = response.data;
129
+
130
+ debugLog('upstream payload summary', {
131
+ topLevelKeys: payload && typeof payload === 'object' ? Object.keys(payload) : null,
132
+ code: payload?.code,
133
+ hasData: Boolean(payload?.data),
134
+ dataKeys: payload?.data && typeof payload.data === 'object' ? Object.keys(payload.data) : []
135
+ });
136
+
137
+ if (!payload || typeof payload !== 'object') {
138
+ debugLog('invalid payload received', payload);
139
+ return errorResponse('用户歌单响应格式无效', 502);
140
+ }
141
+
142
+ if (typeof payload.code === 'number' && payload.code !== 0) {
143
+ debugLog('upstream business error payload', payload);
144
+ return errorResponse(getErrorMessage(payload), 502);
145
+ }
146
+
147
+ const upstreamPlaylists = extractPlaylists(payload);
148
+ const playlists = pageOffset > 0 ? upstreamPlaylists.slice(pageOffset, pageOffset + limit) : upstreamPlaylists;
149
+
150
+ debugLog('final response contract', {
151
+ wrapper: 'customResponse',
152
+ expectedBodyShape: { response: { code: 0, data: { playlists: '...' } } },
153
+ upstreamLength: upstreamPlaylists.length,
154
+ normalizedLength: playlists.length
155
+ });
156
+
157
+ return customResponse({ response: { code: 0, data: { playlists } } }, 200);
158
+ } catch (error) {
159
+ console.error('获取用户歌单失败:', error);
160
+ return errorResponse((error as Error).message || '获取用户歌单失败', 502);
161
+ }
162
+ };
163
+
@@ -0,0 +1,44 @@
1
+ import { AxiosRequestConfig, Method } from 'axios';
2
+ import request from '../../util/request';
3
+ import * as config from '../config';
4
+
5
+ interface YCommonOptions {
6
+ url: string;
7
+ method?: Method | string;
8
+ options?: AxiosRequestConfig;
9
+ hasCommonParams?: boolean;
10
+ }
11
+
12
+ export default ({ url, method = 'get', options = {}, hasCommonParams = true }: YCommonOptions) => {
13
+ const opts: AxiosRequestConfig = { ...options };
14
+
15
+ // Merge commonParams into params
16
+ // commonParams acts as defaults, specific params override them
17
+ if (hasCommonParams) {
18
+ opts.params = { ...config.commonParams, ...(opts.params || {}) };
19
+ } else {
20
+ opts.params = { ...(opts.params || {}) };
21
+ }
22
+
23
+ opts.headers = {
24
+ referer: 'https://c.y.qq.com/',
25
+ host: 'c.y.qq.com',
26
+ ...(opts.headers || {})
27
+ };
28
+
29
+ if (process.env.DEBUG === 'true') {
30
+ const logOpts = { ...opts, headers: { ...opts.headers } };
31
+ const SENSITIVE_HEADER_KEYS = ['cookie', 'authorization', 'proxy-authorization'];
32
+
33
+ if (logOpts.headers) {
34
+ Object.keys(logOpts.headers).forEach(key => {
35
+ if (SENSITIVE_HEADER_KEYS.includes(key.toLowerCase())) {
36
+ (logOpts.headers as any)[key] = '[masked]';
37
+ }
38
+ });
39
+ }
40
+
41
+ console.log(url, { opts: logOpts });
42
+ }
43
+ return request(url, method as Method, opts);
44
+ };
@@ -0,0 +1,24 @@
1
+ export const commonParams = {
2
+ g_tk: 1124214810,
3
+ loginUin: (global.userInfo as any)?.uin || '0',
4
+ hostUin: 0,
5
+ inCharset: 'utf8',
6
+ outCharset: 'utf-8',
7
+ // format: 'json',
8
+ notice: 0,
9
+ platform: 'yqq.json',
10
+ needNewCode: 0
11
+ };
12
+
13
+ export const _guid = (Math.round(2147483647 * Math.random()) * new Date().getUTCMilliseconds()) % 1e10;
14
+
15
+ export const options = {
16
+ param: 'jsonpCallback',
17
+ prefix: 'tan'
18
+ // prefix: 'jp',
19
+ };
20
+
21
+ export const optionsPrefix = {
22
+ param: 'jsonpCallback',
23
+ prefix: 'playlistinfoCallback'
24
+ };
@@ -0,0 +1,95 @@
1
+ import downloadQQMusic from './apis/downloadQQMusic';
2
+ // search
3
+ import getHotKey from './apis/search/getHotKey';
4
+ import getSearchByKey from './apis/search/getSearchByKey';
5
+ import getSmartbox from './apis/search/getSmartbox';
6
+
7
+ // song list
8
+ import songLists from './apis/songLists/songLists';
9
+ import songListCategories from './apis/songLists/songListCategories';
10
+ import songListDetail from './apis/songLists/songListDetail';
11
+
12
+ // MV
13
+ import getMvByTag from './apis/mv/getMvByTag';
14
+
15
+ // singer
16
+ import getSimilarSinger from './apis/singers/getSimilarSinger';
17
+ import getSingerMv from './apis/singers/getSingerMv';
18
+ import getSingerDesc from './apis/singers/getSingerDesc';
19
+ import getSingerStarNum from './apis/singers/getSingerStarNum';
20
+
21
+ // radio
22
+ import getRadioLists from './apis/radio/getRadioLists';
23
+
24
+ // DigitalAlbum
25
+ import getDigitalAlbumLists from './apis/digitalAlbum/getDigitalAlbumLists';
26
+
27
+ // music
28
+ import getLyric from './apis/music/getLyric';
29
+
30
+ // album
31
+ import getAlbumInfo from './apis/album/getAlbumInfo';
32
+
33
+ // comments
34
+ import getComments from './apis/comments/getComments';
35
+
36
+ // UCommon
37
+ import UCommon from './apis/UCommon/UCommon';
38
+
39
+ // getTopLists
40
+ import getTopLists from './apis/rank/getTopLists';
41
+
42
+ // getQQLoginQr
43
+ import getQQLoginQr from './apis/user/getQQLoginQr';
44
+
45
+ // checkQQLoginQr
46
+ import checkQQLoginQr from './apis/user/checkQQLoginQr';
47
+
48
+ // getUserPlaylists
49
+ import { getUserPlaylists } from './apis/user/getUserPlaylists';
50
+
51
+ // getUserAvatar
52
+ import { getUserAvatar } from './apis/user/getUserAvatar';
53
+
54
+ // getUserLikedSongs
55
+ import { getUserLikedSongs } from './apis/user/getUserLikedSongs';
56
+
57
+ export {
58
+ downloadQQMusic,
59
+ // search
60
+ getHotKey,
61
+ getSearchByKey,
62
+ getSmartbox,
63
+ // song lists
64
+ songLists,
65
+ songListCategories,
66
+ songListDetail,
67
+ // MV
68
+ getMvByTag,
69
+ // singer
70
+ getSimilarSinger,
71
+ getSingerMv,
72
+ getSingerDesc,
73
+ getSingerStarNum,
74
+ // radio
75
+ getRadioLists,
76
+ // DigitalAlbum
77
+ getDigitalAlbumLists,
78
+ // music
79
+ getLyric,
80
+ // album
81
+ getAlbumInfo,
82
+ // comments
83
+ getComments,
84
+ // UCommon
85
+ UCommon,
86
+ // getTopLists
87
+ getTopLists,
88
+ // login
89
+ getQQLoginQr,
90
+ checkQQLoginQr,
91
+ // user
92
+ getUserPlaylists,
93
+ getUserAvatar,
94
+ getUserLikedSongs
95
+ };
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@sansenjian/qq-music-api",
3
- "version": "2.1.1",
3
+ "version": "2.2.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
7
  "description": "QQ Music API - QQ音乐API koa2实现",
8
- "main": "index.js",
8
+ "main": "dist/index.js",
9
9
  "scripts": {
10
- "dev": "nodemon app.js & npm run docs:dev",
11
- "start": "node app.js",
10
+ "dev": "tsx app.ts",
11
+ "build": "tsc",
12
+ "start": "node dist/app.js",
12
13
  "test": "jest",
13
14
  "test:watch": "jest --watch",
14
15
  "test:coverage": "jest --coverage",
@@ -52,17 +53,30 @@
52
53
  "@koa/router": "^15.3.1",
53
54
  "axios": "^1.13.6",
54
55
  "date-fns": "^4.1.0",
55
- "koa": "^2.15.0",
56
+ "is-generator-function": "1.0.10",
57
+ "koa": "^2.16.1",
56
58
  "koa-bodyparser": "^4.4.1",
57
- "koa-static": "^5.0.0"
59
+ "koa-static": "^5.0.0",
60
+ "reflect-metadata": "^0.2.2"
61
+ },
62
+ "pnpm": {
63
+ "overrides": {
64
+ "is-generator-function": "^1.0.10"
65
+ }
58
66
  },
59
67
  "devDependencies": {
60
68
  "@babel/core": "^7.23.0",
61
69
  "@babel/plugin-transform-async-to-generator": "^7.23.0",
70
+ "@babel/preset-env": "^7.29.0",
71
+ "@babel/preset-typescript": "^7.28.5",
62
72
  "@babel/register": "^7.23.0",
63
73
  "@commitlint/cli": "^18.0.0",
64
74
  "@commitlint/config-conventional": "^18.0.0",
65
75
  "@types/jest": "^30.0.0",
76
+ "@types/koa": "^3.0.1",
77
+ "@types/koa__router": "^12.0.5",
78
+ "@types/koa-bodyparser": "^4.3.13",
79
+ "@types/node": "^25.3.3",
66
80
  "@types/supertest": "^7.2.0",
67
81
  "chalk": "^4.1.0",
68
82
  "conventional-changelog-cli": "^4.0.0",
@@ -76,8 +90,13 @@
76
90
  "lint-staged": "^15.0.0",
77
91
  "nodemon": "^3.1.14",
78
92
  "prettier": "^3.8.1",
93
+ "rimraf": "^6.1.3",
79
94
  "sinon": "^21.0.1",
80
95
  "supertest": "^7.2.2",
96
+ "ts-jest": "^29.4.6",
97
+ "ts-node": "^10.9.2",
98
+ "tsx": "^4.21.0",
99
+ "typescript": "5.7.3",
81
100
  "vitepress": "^1.6.4",
82
101
  "vue": "^3.5.29"
83
102
  },
@@ -0,0 +1,2 @@
1
+ onlyBuiltDependencies:
2
+ - esbuild