@sansenjian/qq-music-api 2.2.1 → 2.2.9

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 (353) hide show
  1. package/CHANGELOG.md +124 -33
  2. package/README.md +2 -0
  3. package/dist/app.js +77 -0
  4. package/dist/config/service-config.js +37 -0
  5. package/dist/config/user-info.js +59 -0
  6. package/dist/index.js +3 -0
  7. package/dist/jest.config.js +52 -0
  8. package/dist/middlewares/fallback-middleware.js +29 -0
  9. package/dist/middlewares/koa-cors.js +63 -0
  10. package/dist/module/apis/UCommon/UCommon.js +10 -0
  11. package/dist/module/apis/album/getAlbumInfo.js +23 -0
  12. package/dist/module/apis/comments/getComments.js +24 -0
  13. package/dist/module/apis/digitalAlbum/getDigitalAlbumLists.js +22 -0
  14. package/dist/module/apis/downloadQQMusic.js +48 -0
  15. package/dist/module/apis/extend/getPlaylistTags.js +158 -0
  16. package/dist/module/apis/music/getLyric.js +32 -0
  17. package/dist/module/apis/music/getMusicPlay.js +187 -0
  18. package/dist/module/apis/mv/getMvByTag.js +23 -0
  19. package/dist/module/apis/radio/getRadioLists.js +26 -0
  20. package/dist/module/apis/rank/getTopLists.js +35 -0
  21. package/dist/module/apis/recommend/getDailyRecommend.js +124 -0
  22. package/dist/module/apis/recommend/getPersonalRecommend.js +114 -0
  23. package/dist/module/apis/search/getHotKey.js +25 -0
  24. package/dist/module/apis/search/getSearchByKey.js +32 -0
  25. package/dist/module/apis/search/getSmartbox.js +40 -0
  26. package/dist/module/apis/singers/getSimilarSinger.js +24 -0
  27. package/dist/module/apis/singers/getSingerDesc.js +24 -0
  28. package/dist/module/apis/singers/getSingerMv.js +23 -0
  29. package/dist/module/apis/singers/getSingerStarNum.js +23 -0
  30. package/dist/module/apis/songLists/songListCategories.js +23 -0
  31. package/dist/module/apis/songLists/songListDetail.js +28 -0
  32. package/dist/module/apis/songLists/songLists.js +35 -0
  33. package/dist/module/apis/u_common.js +62 -0
  34. package/dist/module/apis/user/checkQQLoginQr.js +189 -0
  35. package/dist/module/apis/user/getQQLoginQr.js +23 -0
  36. package/dist/module/apis/user/getUserAvatar.js +25 -0
  37. package/dist/module/apis/user/getUserLikedSongs.js +129 -0
  38. package/dist/module/apis/user/getUserPlaylists.js +138 -0
  39. package/dist/module/apis/y_common.js +69 -0
  40. package/dist/module/config.js +24 -0
  41. package/dist/module/index.js +72 -0
  42. package/dist/package.json +120 -0
  43. package/dist/routers/context/batchGetSongInfo.js +48 -0
  44. package/dist/routers/context/batchGetSongLists.js +35 -0
  45. package/dist/routers/context/checkQQLoginQr.js +16 -0
  46. package/dist/routers/context/cookies.js +36 -0
  47. package/dist/routers/context/getAlbumInfo.js +22 -0
  48. package/dist/routers/context/getComments.js +31 -0
  49. package/dist/routers/context/getDailyRecommend.js +33 -0
  50. package/dist/routers/context/getDigitalAlbumLists.js +16 -0
  51. package/dist/routers/context/getDownloadQQMusic.js +16 -0
  52. package/dist/routers/context/getHotkey.js +20 -0
  53. package/dist/routers/context/getImageUrl.js +25 -0
  54. package/dist/routers/context/getLyric.js +29 -0
  55. package/dist/routers/context/getMusicPlay.js +33 -0
  56. package/dist/routers/context/getMv.js +51 -0
  57. package/dist/routers/context/getMvByTag.js +16 -0
  58. package/dist/routers/context/getMvPlay.js +104 -0
  59. package/dist/routers/context/getNewDisks.js +52 -0
  60. package/dist/routers/context/getPersonalRecommend.js +42 -0
  61. package/dist/routers/context/getPlaylistTags.js +54 -0
  62. package/dist/routers/context/getQQLoginQr.js +14 -0
  63. package/dist/routers/context/getRadioLists.js +16 -0
  64. package/dist/routers/context/getRanks.js +53 -0
  65. package/dist/routers/context/getRecommend.js +88 -0
  66. package/dist/routers/context/getSearchByKey.js +32 -0
  67. package/dist/routers/context/getSimilarSinger.js +27 -0
  68. package/dist/routers/context/getSingerAlbum.js +48 -0
  69. package/dist/routers/context/getSingerDesc.js +28 -0
  70. package/dist/routers/context/getSingerHotsong.js +48 -0
  71. package/dist/routers/context/getSingerList.js +39 -0
  72. package/dist/routers/context/getSingerMv.js +36 -0
  73. package/dist/routers/context/getSingerStarNum.js +27 -0
  74. package/dist/routers/context/getSmartbox.js +27 -0
  75. package/dist/routers/context/getSongInfo.js +40 -0
  76. package/dist/routers/context/getSongListCategories.js +22 -0
  77. package/dist/routers/context/getSongListDetail.js +17 -0
  78. package/dist/routers/context/getSongLists.js +25 -0
  79. package/dist/routers/context/getTicketInfo.js +47 -0
  80. package/dist/routers/context/getTopLists.js +16 -0
  81. package/dist/routers/context/getUserAvatar.js +35 -0
  82. package/dist/routers/context/getUserLikedSongs.js +24 -0
  83. package/dist/routers/context/getUserPlaylists.js +27 -0
  84. package/dist/routers/context/index.js +98 -0
  85. package/dist/routers/router.js +69 -0
  86. package/dist/routers/types.js +2 -0
  87. package/dist/routers/util.js +219 -0
  88. package/dist/scripts/run-tests-with-flags.js +139 -0
  89. package/dist/types/api.js +55 -0
  90. package/dist/util/apiResponse.js +88 -0
  91. package/dist/util/colors.js +19 -0
  92. package/dist/util/cookie.js +34 -0
  93. package/dist/util/cookieResolver.js +66 -0
  94. package/dist/util/loginUtils.js +30 -0
  95. package/dist/util/lyricParse.js +72 -0
  96. package/dist/util/request.js +118 -0
  97. package/docs-dist/404.html +24 -0
  98. package/docs-dist/CHANGELOG-ARCHITECTURE.html +131 -0
  99. package/docs-dist/COOKIE_CONFIG_GUIDE.html +39 -0
  100. package/docs-dist/FALLBACK_MODE_GUIDE.html +101 -0
  101. package/docs-dist/README.html +447 -0
  102. package/docs-dist/TEST_USER_PLAYLISTS.html +42 -0
  103. package/docs-dist/USER_AVATAR_GUIDE.html +100 -0
  104. package/docs-dist/api/comments.html +48 -0
  105. package/docs-dist/api/index.html +27 -0
  106. package/docs-dist/api/music.html +51 -0
  107. package/docs-dist/api/other.html +33 -0
  108. package/docs-dist/api/playlist.html +77 -0
  109. package/docs-dist/api/rank.html +48 -0
  110. package/docs-dist/api/search.html +62 -0
  111. package/docs-dist/api/singer.html +47 -0
  112. package/docs-dist/api/user.html +64 -0
  113. package/docs-dist/assets/CHANGELOG-ARCHITECTURE.md.r40JGJZK.js +105 -0
  114. package/docs-dist/assets/CHANGELOG-ARCHITECTURE.md.r40JGJZK.lean.js +1 -0
  115. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.BVXl7WHu.js +13 -0
  116. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.BVXl7WHu.lean.js +1 -0
  117. package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.BBdcIdh_.js +75 -0
  118. package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.BBdcIdh_.lean.js +1 -0
  119. package/docs-dist/assets/README.md.D6Tw0nRd.js +421 -0
  120. package/docs-dist/assets/README.md.D6Tw0nRd.lean.js +1 -0
  121. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.DSt20Igj.js +16 -0
  122. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.DSt20Igj.lean.js +1 -0
  123. package/docs-dist/assets/USER_AVATAR_GUIDE.md.CVHPs2Dn.js +74 -0
  124. package/docs-dist/assets/USER_AVATAR_GUIDE.md.CVHPs2Dn.lean.js +1 -0
  125. package/docs-dist/assets/api_comments.md.79Q_C8Qp.js +22 -0
  126. package/docs-dist/assets/api_comments.md.79Q_C8Qp.lean.js +1 -0
  127. package/docs-dist/assets/api_index.md.CU3By8tw.js +1 -0
  128. package/docs-dist/assets/api_index.md.CU3By8tw.lean.js +1 -0
  129. package/docs-dist/assets/api_music.md.B1AzLePX.js +25 -0
  130. package/docs-dist/assets/api_music.md.B1AzLePX.lean.js +1 -0
  131. package/docs-dist/assets/api_other.md.DCg4bzA7.js +7 -0
  132. package/docs-dist/assets/api_other.md.DCg4bzA7.lean.js +1 -0
  133. package/docs-dist/assets/api_playlist.md.8ACJ3QqD.js +51 -0
  134. package/docs-dist/assets/api_playlist.md.8ACJ3QqD.lean.js +1 -0
  135. package/docs-dist/assets/api_rank.md.B8IP2ZRy.js +22 -0
  136. package/docs-dist/assets/api_rank.md.B8IP2ZRy.lean.js +1 -0
  137. package/docs-dist/assets/api_search.md.DO9J6nvp.js +36 -0
  138. package/docs-dist/assets/api_search.md.DO9J6nvp.lean.js +1 -0
  139. package/docs-dist/assets/api_singer.md.CcL32xuN.js +21 -0
  140. package/docs-dist/assets/api_singer.md.CcL32xuN.lean.js +1 -0
  141. package/docs-dist/assets/api_user.md.Cb7Ky3Sn.js +38 -0
  142. package/docs-dist/assets/api_user.md.Cb7Ky3Sn.lean.js +1 -0
  143. package/docs-dist/assets/app.CSainqD9.js +1 -0
  144. package/docs-dist/assets/chunks/@localSearchIndexroot.BKleDIv-.js +1 -0
  145. package/docs-dist/assets/chunks/VPLocalSearchBox.BUBaq7tw.js +9 -0
  146. package/docs-dist/assets/chunks/framework.aJbMEiY9.js +19 -0
  147. package/docs-dist/assets/chunks/theme.CzMhU0Ps.js +2 -0
  148. package/docs-dist/assets/guide_architecture.md.CzgqynmB.js +258 -0
  149. package/docs-dist/assets/guide_architecture.md.CzgqynmB.lean.js +1 -0
  150. package/docs-dist/assets/guide_authentication.md.a8yTA8Xe.js +4 -0
  151. package/docs-dist/assets/guide_authentication.md.a8yTA8Xe.lean.js +1 -0
  152. package/docs-dist/assets/guide_index.md.BgUUL6fI.js +1 -0
  153. package/docs-dist/assets/guide_index.md.BgUUL6fI.lean.js +1 -0
  154. package/docs-dist/assets/guide_installation.md.BCZ4jBl_.js +7 -0
  155. package/docs-dist/assets/guide_installation.md.BCZ4jBl_.lean.js +1 -0
  156. package/docs-dist/assets/guide_quickstart.md.9-4dA6wS.js +13 -0
  157. package/docs-dist/assets/guide_quickstart.md.9-4dA6wS.lean.js +1 -0
  158. package/docs-dist/assets/index.md.z0hAJioN.js +1 -0
  159. package/docs-dist/assets/index.md.z0hAJioN.lean.js +1 -0
  160. package/docs-dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  161. package/docs-dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  162. package/docs-dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  163. package/docs-dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  164. package/docs-dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  165. package/docs-dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  166. package/docs-dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  167. package/docs-dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  168. package/docs-dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  169. package/docs-dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  170. package/docs-dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  171. package/docs-dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  172. package/docs-dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  173. package/docs-dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  174. package/docs-dist/assets/reference_response-format.md.VvQTLDZr.js +12 -0
  175. package/docs-dist/assets/reference_response-format.md.VvQTLDZr.lean.js +1 -0
  176. package/docs-dist/assets/style.DM4qKDd4.css +1 -0
  177. package/docs-dist/guide/architecture.html +284 -0
  178. package/docs-dist/guide/authentication.html +30 -0
  179. package/docs-dist/guide/index.html +27 -0
  180. package/docs-dist/guide/installation.html +33 -0
  181. package/docs-dist/guide/quickstart.html +39 -0
  182. package/docs-dist/hashmap.json +1 -0
  183. package/docs-dist/index.html +27 -0
  184. package/docs-dist/logo.svg +4 -0
  185. package/docs-dist/reference/response-format.html +38 -0
  186. package/docs-dist/version.json +7 -0
  187. package/docs-dist/vp-icons.css +1 -0
  188. package/package.json +31 -17
  189. package/.babelrc +0 -7
  190. package/.dockerignore +0 -5
  191. package/.editorconfig +0 -31
  192. package/.eslintrc.json +0 -22
  193. package/.github/workflows/deploy-docs.yml +0 -54
  194. package/.github/workflows/release.yml +0 -37
  195. package/.github/workflows/test.yml +0 -70
  196. package/.husky/commit-msg +0 -1
  197. package/.husky/pre-commit +0 -1
  198. package/.prettierignore +0 -1
  199. package/.prettierrc +0 -9
  200. package/AGENTS.md +0 -153
  201. package/Dockerfile +0 -18
  202. package/QQ/351/237/263/344/271/220-v0.xmind +0 -0
  203. package/QQ/351/237/263/344/271/220-v1.xmind +0 -0
  204. package/app.ts +0 -68
  205. package/commitlint.config.js +0 -20
  206. package/config/user-info.ts +0 -71
  207. package/index.ts +0 -1
  208. package/jest.config.ts +0 -41
  209. package/middlewares/koa-cors.ts +0 -81
  210. package/module/apis/UCommon/UCommon.ts +0 -13
  211. package/module/apis/album/getAlbumInfo.ts +0 -22
  212. package/module/apis/comments/getComments.ts +0 -23
  213. package/module/apis/digitalAlbum/getDigitalAlbumLists.ts +0 -23
  214. package/module/apis/downloadQQMusic.ts +0 -51
  215. package/module/apis/music/getLyric.ts +0 -34
  216. package/module/apis/mv/getMvByTag.ts +0 -24
  217. package/module/apis/radio/getRadioLists.ts +0 -27
  218. package/module/apis/rank/getTopLists.ts +0 -37
  219. package/module/apis/search/getHotKey.ts +0 -24
  220. package/module/apis/search/getSearchByKey.ts +0 -31
  221. package/module/apis/search/getSmartbox.ts +0 -43
  222. package/module/apis/singers/getSimilarSinger.ts +0 -25
  223. package/module/apis/singers/getSingerDesc.ts +0 -25
  224. package/module/apis/singers/getSingerMv.ts +0 -24
  225. package/module/apis/singers/getSingerStarNum.ts +0 -24
  226. package/module/apis/songLists/songListCategories.ts +0 -22
  227. package/module/apis/songLists/songListDetail.ts +0 -27
  228. package/module/apis/songLists/songLists.ts +0 -35
  229. package/module/apis/u_common.ts +0 -29
  230. package/module/apis/user/checkQQLoginQr.ts +0 -230
  231. package/module/apis/user/getQQLoginQr.ts +0 -28
  232. package/module/apis/user/getUserAvatar.ts +0 -32
  233. package/module/apis/user/getUserLikedSongs.ts +0 -145
  234. package/module/apis/user/getUserPlaylists.ts +0 -163
  235. package/module/apis/y_common.ts +0 -44
  236. package/module/config.ts +0 -24
  237. package/module/index.ts +0 -95
  238. package/music.png +0 -0
  239. package/pnpm-workspace.yaml +0 -2
  240. package/public/index.html +0 -430
  241. package/routers/context/batchGetSongInfo.ts +0 -60
  242. package/routers/context/batchGetSongLists.ts +0 -46
  243. package/routers/context/checkQQLoginQr.ts +0 -19
  244. package/routers/context/cookies.ts +0 -38
  245. package/routers/context/getAlbumInfo.ts +0 -31
  246. package/routers/context/getComments.ts +0 -51
  247. package/routers/context/getDigitalAlbumLists.ts +0 -18
  248. package/routers/context/getDownloadQQMusic.ts +0 -17
  249. package/routers/context/getHotkey.ts +0 -25
  250. package/routers/context/getImageUrl.ts +0 -29
  251. package/routers/context/getLyric.ts +0 -32
  252. package/routers/context/getMusicPlay.ts +0 -102
  253. package/routers/context/getMv.ts +0 -61
  254. package/routers/context/getMvByTag.ts +0 -18
  255. package/routers/context/getMvPlay.ts +0 -114
  256. package/routers/context/getNewDisks.ts +0 -58
  257. package/routers/context/getQQLoginQr.ts +0 -16
  258. package/routers/context/getRadioLists.ts +0 -18
  259. package/routers/context/getRanks.ts +0 -67
  260. package/routers/context/getRecommend.ts +0 -92
  261. package/routers/context/getSearchByKey.ts +0 -34
  262. package/routers/context/getSimilarSinger.ts +0 -29
  263. package/routers/context/getSingerAlbum.ts +0 -58
  264. package/routers/context/getSingerDesc.ts +0 -30
  265. package/routers/context/getSingerHotsong.ts +0 -58
  266. package/routers/context/getSingerList.ts +0 -56
  267. package/routers/context/getSingerMv.ts +0 -41
  268. package/routers/context/getSingerStarNum.ts +0 -29
  269. package/routers/context/getSmartbox.ts +0 -27
  270. package/routers/context/getSongInfo.ts +0 -51
  271. package/routers/context/getSongListCategories.ts +0 -23
  272. package/routers/context/getSongListDetail.ts +0 -22
  273. package/routers/context/getSongLists.ts +0 -30
  274. package/routers/context/getTicketInfo.ts +0 -51
  275. package/routers/context/getTopLists.ts +0 -18
  276. package/routers/context/getUserAvatar.ts +0 -53
  277. package/routers/context/getUserLikedSongs.ts +0 -28
  278. package/routers/context/getUserPlaylists.ts +0 -29
  279. package/routers/context/index.ts +0 -87
  280. package/routers/router.ts +0 -88
  281. package/routers/types.ts +0 -18
  282. package/routers/util.ts +0 -231
  283. package/screenshot/album-image.png +0 -0
  284. package/screenshot/batchGetSongInfo.png +0 -0
  285. package/screenshot/batchGetSongLists.png +0 -0
  286. package/screenshot/downloadQQMusic.png +0 -0
  287. package/screenshot/get-album-image.png +0 -0
  288. package/screenshot/get-play-all-data.png +0 -0
  289. package/screenshot/get-song-album-id.png +0 -0
  290. package/screenshot/get-song-id.png +0 -0
  291. package/screenshot/get-song-image.png +0 -0
  292. package/screenshot/getAlbumInfo.png +0 -0
  293. package/screenshot/getComments-id.png +0 -0
  294. package/screenshot/getComments-param.png +0 -0
  295. package/screenshot/getComments.png +0 -0
  296. package/screenshot/getDigitalAlbumLists.png +0 -0
  297. package/screenshot/getLyric-parse.png +0 -0
  298. package/screenshot/getLyric.png +0 -0
  299. package/screenshot/getMusicPlay.png +0 -0
  300. package/screenshot/getMv.png +0 -0
  301. package/screenshot/getMvByTag.png +0 -0
  302. package/screenshot/getMvPlay.png +0 -0
  303. package/screenshot/getNewDisks.png +0 -0
  304. package/screenshot/getRadioLists.png +0 -0
  305. package/screenshot/getRanks.png +0 -0
  306. package/screenshot/getRecommend.png +0 -0
  307. package/screenshot/getSearchByKey.png +0 -0
  308. package/screenshot/getSimilarSinger.png +0 -0
  309. package/screenshot/getSingerAlbum.png +0 -0
  310. package/screenshot/getSingerDesc.png +0 -0
  311. package/screenshot/getSingerHotsong.png +0 -0
  312. package/screenshot/getSingerList.png +0 -0
  313. package/screenshot/getSingerMv-default.png +0 -0
  314. package/screenshot/getSingerMv-listen.png +0 -0
  315. package/screenshot/getSingerMv-time.png +0 -0
  316. package/screenshot/getSingerStarNum.png +0 -0
  317. package/screenshot/getSmartbox.png +0 -0
  318. package/screenshot/getSongInfo.png +0 -0
  319. package/screenshot/getSongListCategories.png +0 -0
  320. package/screenshot/getSongListDetail.png +0 -0
  321. package/screenshot/getSongLists-params.png +0 -0
  322. package/screenshot/getSongLists.png +0 -0
  323. package/screenshot/getTicketInfo.png +0 -0
  324. package/screenshot/getTopLists.png +0 -0
  325. package/screenshot/gethotkey.png +0 -0
  326. package/screenshot/just-get-play-url.png +0 -0
  327. package/screenshot/musicPlay.png +0 -0
  328. package/screenshot/new-feature-error-tips.png +0 -0
  329. package/screenshot/normalize-cookie.png +0 -0
  330. package/screenshot/qq-music-v0.png +0 -0
  331. package/screenshot/qq-music.png +0 -0
  332. package/screenshot/song-image.png +0 -0
  333. package/screenshot/song-quality-128.png +0 -0
  334. package/screenshot/song-quality-m4a.png +0 -0
  335. package/scripts/build-images.js +0 -36
  336. package/scripts/commit-push.sh +0 -103
  337. package/tests/integration/api/api.test.ts +0 -852
  338. package/tests/integration/middleware/cors.test.ts +0 -41
  339. package/tests/setup/jest.setup.ts +0 -15
  340. package/tests/setup/testUtils.ts +0 -35
  341. package/tests/unit/util/request.test.ts +0 -177
  342. package/tsconfig.json +0 -20
  343. package/tsconfig.test.json +0 -8
  344. package/types/api.ts +0 -105
  345. package/types/global.d.ts +0 -26
  346. package/types/index.d.ts +0 -97
  347. package/util/apiResponse.ts +0 -97
  348. package/util/colors.ts +0 -31
  349. package/util/cookie.ts +0 -40
  350. package/util/loginUtils.ts +0 -26
  351. package/util/lyricParse.ts +0 -86
  352. package/util/request.ts +0 -141
  353. package/vercel.json +0 -15
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const module_1 = require("../../module");
4
+ // 获取用户喜欢的歌曲列表
5
+ exports.default = async (ctx, next) => {
6
+ const { uin, offset = 0, limit = 30 } = ctx.query;
7
+ if (!uin) {
8
+ ctx.status = 400;
9
+ ctx.body = {
10
+ error: '缺少 uin 参数'
11
+ };
12
+ return;
13
+ }
14
+ const { status, body } = await (0, module_1.getUserLikedSongs)({
15
+ uin: uin,
16
+ offset: Number(offset),
17
+ limit: Number(limit)
18
+ });
19
+ Object.assign(ctx, {
20
+ status,
21
+ body
22
+ });
23
+ await next();
24
+ };
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const module_1 = require("../../module");
4
+ const cookieResolver_1 = require("../../util/cookieResolver");
5
+ exports.default = async (ctx, next) => {
6
+ const { uin, offset = 0, limit = 30 } = ctx.query;
7
+ if (!uin) {
8
+ ctx.status = 400;
9
+ ctx.body = {
10
+ error: '缺少 uin 参数'
11
+ };
12
+ return;
13
+ }
14
+ const normalizedUin = Array.isArray(uin) ? uin[0] : uin;
15
+ const { cookie } = (0, cookieResolver_1.resolveRequestCookie)(ctx);
16
+ const { status, body } = await (0, module_1.getUserPlaylists)({
17
+ uin: String(normalizedUin),
18
+ offset: Number(offset),
19
+ limit: Number(limit),
20
+ cookie
21
+ });
22
+ Object.assign(ctx, {
23
+ status,
24
+ body
25
+ });
26
+ await next();
27
+ };
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // Import refactored controllers
7
+ const getDownloadQQMusic_1 = __importDefault(require("./getDownloadQQMusic"));
8
+ const getHotkey_1 = __importDefault(require("./getHotkey"));
9
+ const getSearchByKey_1 = __importDefault(require("./getSearchByKey"));
10
+ const getSmartbox_1 = __importDefault(require("./getSmartbox"));
11
+ const getSongListCategories_1 = __importDefault(require("./getSongListCategories"));
12
+ const getSongLists_1 = __importDefault(require("./getSongLists"));
13
+ const batchGetSongLists_1 = __importDefault(require("./batchGetSongLists"));
14
+ const getSongInfo_1 = __importDefault(require("./getSongInfo"));
15
+ const batchGetSongInfo_1 = __importDefault(require("./batchGetSongInfo"));
16
+ const getSongListDetail_1 = __importDefault(require("./getSongListDetail"));
17
+ const getNewDisks_1 = __importDefault(require("./getNewDisks"));
18
+ const getMvByTag_1 = __importDefault(require("./getMvByTag"));
19
+ const getMv_1 = __importDefault(require("./getMv"));
20
+ const getSingerList_1 = __importDefault(require("./getSingerList"));
21
+ const getSimilarSinger_1 = __importDefault(require("./getSimilarSinger"));
22
+ const getSingerAlbum_1 = __importDefault(require("./getSingerAlbum"));
23
+ const getSingerHotsong_1 = __importDefault(require("./getSingerHotsong"));
24
+ const getSingerMv_1 = __importDefault(require("./getSingerMv"));
25
+ const getSingerDesc_1 = __importDefault(require("./getSingerDesc"));
26
+ const getSingerStarNum_1 = __importDefault(require("./getSingerStarNum"));
27
+ const getRadioLists_1 = __importDefault(require("./getRadioLists"));
28
+ const getDigitalAlbumLists_1 = __importDefault(require("./getDigitalAlbumLists"));
29
+ const getLyric_1 = __importDefault(require("./getLyric"));
30
+ const getMusicPlay_1 = __importDefault(require("./getMusicPlay"));
31
+ const getAlbumInfo_1 = __importDefault(require("./getAlbumInfo"));
32
+ const getComments_1 = __importDefault(require("./getComments"));
33
+ const getRecommend_1 = __importDefault(require("./getRecommend"));
34
+ const getMvPlay_1 = __importDefault(require("./getMvPlay"));
35
+ const getTopLists_1 = __importDefault(require("./getTopLists"));
36
+ const getRanks_1 = __importDefault(require("./getRanks"));
37
+ const getTicketInfo_1 = __importDefault(require("./getTicketInfo"));
38
+ const getImageUrl_1 = __importDefault(require("./getImageUrl"));
39
+ const getQQLoginQr_1 = __importDefault(require("./getQQLoginQr"));
40
+ const checkQQLoginQr_1 = __importDefault(require("./checkQQLoginQr"));
41
+ const cookies_1 = __importDefault(require("./cookies"));
42
+ const getUserPlaylists_1 = __importDefault(require("./getUserPlaylists"));
43
+ const getUserAvatar_1 = __importDefault(require("./getUserAvatar"));
44
+ const getUserLikedSongs_1 = __importDefault(require("./getUserLikedSongs"));
45
+ const getDailyRecommend_1 = require("./getDailyRecommend");
46
+ const getPersonalRecommend_1 = require("./getPersonalRecommend");
47
+ const getPlaylistTags_1 = require("./getPlaylistTags");
48
+ // Export all controllers with consistent naming
49
+ exports.default = {
50
+ getCookie: cookies_1.default.get,
51
+ setCookie: cookies_1.default.set,
52
+ getDownloadQQMusic: getDownloadQQMusic_1.default,
53
+ getHotKey: getHotkey_1.default,
54
+ getSearchByKey: getSearchByKey_1.default,
55
+ getSmartbox: getSmartbox_1.default,
56
+ getSongListCategories: getSongListCategories_1.default,
57
+ getSongLists: getSongLists_1.default,
58
+ batchGetSongLists: batchGetSongLists_1.default,
59
+ getSongInfo: getSongInfo_1.default,
60
+ batchGetSongInfo: batchGetSongInfo_1.default,
61
+ getSongListDetail: getSongListDetail_1.default,
62
+ getNewDisks: getNewDisks_1.default,
63
+ getMvByTag: getMvByTag_1.default,
64
+ getMv: getMv_1.default,
65
+ getSingerList: getSingerList_1.default,
66
+ getSimilarSinger: getSimilarSinger_1.default,
67
+ getSingerAlbum: getSingerAlbum_1.default,
68
+ getSingerHotsong: getSingerHotsong_1.default,
69
+ getSingerMv: getSingerMv_1.default,
70
+ getSingerDesc: getSingerDesc_1.default,
71
+ getSingerStarNum: getSingerStarNum_1.default,
72
+ getRadioLists: getRadioLists_1.default,
73
+ getDigitalAlbumLists: getDigitalAlbumLists_1.default,
74
+ getLyric: getLyric_1.default,
75
+ getMusicPlay: getMusicPlay_1.default,
76
+ getAlbumInfo: getAlbumInfo_1.default,
77
+ getComments: getComments_1.default,
78
+ getRecommend: getRecommend_1.default,
79
+ getMvPlay: getMvPlay_1.default,
80
+ getTopLists: getTopLists_1.default,
81
+ getRanks: getRanks_1.default,
82
+ getTicketInfo: getTicketInfo_1.default,
83
+ getImageUrl: getImageUrl_1.default,
84
+ getQQLoginQr: getQQLoginQr_1.default,
85
+ checkQQLoginQr: checkQQLoginQr_1.default,
86
+ getUserPlaylists: getUserPlaylists_1.default,
87
+ getUserAvatar: getUserAvatar_1.default,
88
+ getUserLikedSongs: getUserLikedSongs_1.default,
89
+ getDailyRecommend: getDailyRecommend_1.getDailyRecommendController,
90
+ getPrivateFM: getDailyRecommend_1.getPrivateFMController,
91
+ getNewSongs: getDailyRecommend_1.getNewSongsController,
92
+ getPersonalRecommend: getPersonalRecommend_1.getPersonalRecommendController,
93
+ getSimilarSongs: getPersonalRecommend_1.getSimilarSongsController,
94
+ getPlaylistTags: getPlaylistTags_1.getPlaylistTagsController,
95
+ getPlaylistsByTag: getPlaylistTags_1.getPlaylistsByTagController,
96
+ getHotComments: getPlaylistTags_1.getHotCommentsController,
97
+ getSingerListByArea: getPlaylistTags_1.getSingerListByAreaController
98
+ };
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const router_1 = __importDefault(require("@koa/router"));
7
+ const context_1 = __importDefault(require("./context"));
8
+ const router = new router_1.default();
9
+ router.get('/user/getCookie', context_1.default.getCookie);
10
+ router.get('/user/setCookie', context_1.default.setCookie);
11
+ router.get('/user/getUserPlaylists', context_1.default.getUserPlaylists);
12
+ router.get('/user/getUserAvatar', context_1.default.getUserAvatar);
13
+ router.get('/user/getUserLikedSongs', context_1.default.getUserLikedSongs);
14
+ router.get('/downloadQQMusic', context_1.default.getDownloadQQMusic);
15
+ router.get('/getHotkey', context_1.default.getHotKey);
16
+ router.get('/getSearchByKey/:key', context_1.default.getSearchByKey);
17
+ router.get('/getSearchByKey', context_1.default.getSearchByKey);
18
+ router.get('/getSmartbox/:key', context_1.default.getSmartbox);
19
+ router.get('/getSmartbox', context_1.default.getSmartbox);
20
+ router.get('/getSongListCategories', context_1.default.getSongListCategories);
21
+ router.get('/getSongLists/:page/:limit/:categoryId/:sortId', context_1.default.getSongLists);
22
+ router.get('/getSongLists', context_1.default.getSongLists);
23
+ router.post('/batchGetSongLists', context_1.default.batchGetSongLists);
24
+ router.get('/getSongInfo/:songmid', context_1.default.getSongInfo);
25
+ router.get('/getSongInfo', context_1.default.getSongInfo);
26
+ router.post('/batchGetSongInfo', context_1.default.batchGetSongInfo);
27
+ router.get('/getSongListDetail/:disstid', context_1.default.getSongListDetail);
28
+ router.get('/getSongListDetail', context_1.default.getSongListDetail);
29
+ router.get('/getNewDisks', context_1.default.getNewDisks);
30
+ router.get('/getMvByTag', context_1.default.getMvByTag);
31
+ router.get('/getMv', context_1.default.getMv);
32
+ router.get('/getSingerList', context_1.default.getSingerList);
33
+ router.get('/getSimilarSinger', context_1.default.getSimilarSinger);
34
+ router.get('/getSingerAlbum', context_1.default.getSingerAlbum);
35
+ router.get('/getSingerHotsong', context_1.default.getSingerHotsong);
36
+ router.get('/getSingerMv', context_1.default.getSingerMv);
37
+ router.get('/getSingerDesc', context_1.default.getSingerDesc);
38
+ router.get('/getSingerStarNum', context_1.default.getSingerStarNum);
39
+ router.get('/getRadioLists', context_1.default.getRadioLists);
40
+ router.get('/getDigitalAlbumLists', context_1.default.getDigitalAlbumLists);
41
+ router.get('/getLyric/:songmid', context_1.default.getLyric);
42
+ router.get('/getLyric', context_1.default.getLyric);
43
+ router.get('/getMusicPlay/:songmid', context_1.default.getMusicPlay);
44
+ router.get('/getMusicPlay', context_1.default.getMusicPlay);
45
+ router.get('/getAlbumInfo/:albummid', context_1.default.getAlbumInfo);
46
+ router.get('/getAlbumInfo', context_1.default.getAlbumInfo);
47
+ router.get('/getComments', context_1.default.getComments);
48
+ router.get('/getRecommend', context_1.default.getRecommend);
49
+ router.get('/getMvPlay', context_1.default.getMvPlay);
50
+ router.get('/getTopLists', context_1.default.getTopLists);
51
+ router.get('/getRanks', context_1.default.getRanks);
52
+ router.get('/getTicketInfo', context_1.default.getTicketInfo);
53
+ router.get('/getImageUrl', context_1.default.getImageUrl);
54
+ router.get('/getQQLoginQr', context_1.default.getQQLoginQr);
55
+ router.get('/user/getQQLoginQr', context_1.default.getQQLoginQr);
56
+ router.post('/checkQQLoginQr', context_1.default.checkQQLoginQr);
57
+ router.post('/user/checkQQLoginQr', context_1.default.checkQQLoginQr);
58
+ // 推荐相关
59
+ router.get('/getDailyRecommend', context_1.default.getDailyRecommend);
60
+ router.get('/getPrivateFM', context_1.default.getPrivateFM);
61
+ router.get('/getNewSongs', context_1.default.getNewSongs);
62
+ router.get('/getPersonalRecommend', context_1.default.getPersonalRecommend);
63
+ router.get('/getSimilarSongs', context_1.default.getSimilarSongs);
64
+ // 扩展功能
65
+ router.get('/getPlaylistTags', context_1.default.getPlaylistTags);
66
+ router.get('/getPlaylistsByTag', context_1.default.getPlaylistsByTag);
67
+ router.get('/getHotComments', context_1.default.getHotComments);
68
+ router.get('/getSingerListByArea', context_1.default.getSingerListByArea);
69
+ exports.default = router;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createController = createController;
4
+ exports.createPostController = createPostController;
5
+ exports.validateRequired = validateRequired;
6
+ exports.handleControllerResponse = handleControllerResponse;
7
+ exports.createCustomController = createCustomController;
8
+ exports.setApiResponse = setApiResponse;
9
+ exports.withErrorHandler = withErrorHandler;
10
+ const INTERNAL_ERROR_MESSAGE = '服务器内部错误';
11
+ const normalizeErrorMessage = (error) => {
12
+ if (error instanceof Error && error.message) {
13
+ return error.message;
14
+ }
15
+ return INTERNAL_ERROR_MESSAGE;
16
+ };
17
+ const setInternalErrorResponse = (ctx, error) => {
18
+ console.error('Controller error:', error);
19
+ ctx.status = 500;
20
+ ctx.body = {
21
+ error: INTERNAL_ERROR_MESSAGE,
22
+ };
23
+ };
24
+ const isMissingRequiredValue = (value) => {
25
+ if (value === undefined || value === null) {
26
+ return true;
27
+ }
28
+ if (typeof value === 'string') {
29
+ return value.trim() === '';
30
+ }
31
+ return false;
32
+ };
33
+ /**
34
+ * 创建 Controller 的工厂函数
35
+ * @param apiFunction API 函数
36
+ * @param options 配置选项
37
+ * @example
38
+ * export default createController(
39
+ * require('../../module').getSingerDesc,
40
+ * {
41
+ * validator: (params) => {
42
+ * if (!params.singermid) {
43
+ * return { valid: false, error: '缺少 singermid 参数' };
44
+ * }
45
+ * return { valid: true };
46
+ * },
47
+ * errorMessage: 'no singermid'
48
+ * }
49
+ * );
50
+ */
51
+ function createController(apiFunction, options) {
52
+ return async (ctx, next) => {
53
+ try {
54
+ // 从 query 和 params 中提取参数
55
+ const params = {
56
+ ...ctx.query,
57
+ ...ctx.params,
58
+ };
59
+ // 验证参数
60
+ if (options?.validator) {
61
+ const validation = options.validator(params);
62
+ if (!validation.valid) {
63
+ ctx.status = 400;
64
+ ctx.body = {
65
+ response: validation.error || options.errorMessage || 'Invalid parameters',
66
+ };
67
+ return;
68
+ }
69
+ }
70
+ // 构建 API 调用参数
71
+ const apiProps = {
72
+ method: 'get',
73
+ params,
74
+ option: {},
75
+ };
76
+ // 调用 API
77
+ const { status, body } = await apiFunction(apiProps);
78
+ // 设置响应
79
+ Object.assign(ctx, { status, body });
80
+ }
81
+ catch (error) {
82
+ if (options?.onError) {
83
+ options.onError(ctx, error);
84
+ }
85
+ else {
86
+ setInternalErrorResponse(ctx, error);
87
+ }
88
+ }
89
+ };
90
+ }
91
+ /**
92
+ * 创建需要 POST 数据的 Controller
93
+ * @param apiFunction API 函数
94
+ * @param options 配置选项
95
+ */
96
+ function createPostController(apiFunction, options) {
97
+ return async (ctx, next) => {
98
+ try {
99
+ // 从 request.body 中提取参数
100
+ const params = ctx.request.body || {};
101
+ // 验证参数
102
+ if (options?.validator) {
103
+ const validation = options.validator(params);
104
+ if (!validation.valid) {
105
+ ctx.status = 400;
106
+ ctx.body = {
107
+ response: validation.error || options.errorMessage || 'Invalid parameters',
108
+ };
109
+ return;
110
+ }
111
+ }
112
+ // 构建 API 调用参数
113
+ const apiProps = {
114
+ method: 'post',
115
+ params,
116
+ option: {},
117
+ };
118
+ // 调用 API
119
+ const { status, body } = await apiFunction(apiProps);
120
+ // 设置响应
121
+ Object.assign(ctx, { status, body });
122
+ }
123
+ catch (error) {
124
+ if (options?.onError) {
125
+ options.onError(ctx, error);
126
+ }
127
+ else {
128
+ setInternalErrorResponse(ctx, error);
129
+ }
130
+ }
131
+ };
132
+ }
133
+ /**
134
+ * 简单的参数验证器
135
+ * @param requiredFields 必需的字段列表
136
+ * @example
137
+ * validator: validateRequired(['singermid', 'songmid'])
138
+ */
139
+ function validateRequired(fields) {
140
+ return (params) => {
141
+ const missingFields = fields.filter(field => isMissingRequiredValue(params[field]));
142
+ if (missingFields.length > 0) {
143
+ return {
144
+ valid: false,
145
+ error: `缺少必需参数:${missingFields.join(', ')}`,
146
+ };
147
+ }
148
+ return { valid: true };
149
+ };
150
+ }
151
+ /**
152
+ * 处理 Controller 响应
153
+ * @param ctx Koa Context
154
+ * @param apiCall API 调用函数
155
+ */
156
+ async function handleControllerResponse(ctx, apiCall) {
157
+ try {
158
+ const { status, body } = await apiCall();
159
+ Object.assign(ctx, { status, body });
160
+ }
161
+ catch (error) {
162
+ console.error('Controller response error:', normalizeErrorMessage(error));
163
+ ctx.status = 500;
164
+ ctx.body = { error: INTERNAL_ERROR_MESSAGE };
165
+ }
166
+ }
167
+ /**
168
+ * 创建带自定义参数处理的 Controller
169
+ * @param handler 自定义处理函数
170
+ * @param apiFunction API 函数
171
+ */
172
+ function createCustomController(handler, apiFunction) {
173
+ return async (ctx, next) => {
174
+ try {
175
+ const customParams = handler(ctx);
176
+ const apiProps = {
177
+ method: 'get',
178
+ option: {},
179
+ ...customParams,
180
+ };
181
+ const { status, body } = await apiFunction(apiProps);
182
+ Object.assign(ctx, { status, body });
183
+ }
184
+ catch (error) {
185
+ console.error('Custom controller error:', normalizeErrorMessage(error));
186
+ ctx.status = 500;
187
+ ctx.body = { error: INTERNAL_ERROR_MESSAGE };
188
+ }
189
+ };
190
+ }
191
+ /**
192
+ * 统一处理 API 响应并设置到 Koa 上下文
193
+ * @param ctx - Koa 上下文
194
+ * @param apiResponse - API 响应对象
195
+ */
196
+ function setApiResponse(ctx, apiResponse) {
197
+ ctx.status = apiResponse.status || 500;
198
+ ctx.body = apiResponse.body;
199
+ }
200
+ /**
201
+ * 包装异步控制器,自动处理错误
202
+ * @param handler - 控制器处理函数
203
+ * @returns 包装后的控制器
204
+ */
205
+ function withErrorHandler(handler) {
206
+ return async (ctx, next) => {
207
+ try {
208
+ await handler(ctx);
209
+ await next();
210
+ }
211
+ catch (error) {
212
+ console.error('Controller error:', error);
213
+ ctx.status = 502;
214
+ ctx.body = {
215
+ error: error.message || '服务器内部错误',
216
+ };
217
+ }
218
+ };
219
+ }
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /**
3
+ * 运行测试并生成带 flags 的覆盖率报告
4
+ *
5
+ * 用法:
6
+ * - 运行所有测试:npm run test:flags
7
+ * - 只运行单元测试:npm run test:flags:unit
8
+ *
9
+ * 注意:此脚本通过 tsx 运行,不使用 ts-node
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ const child_process_1 = require("child_process");
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const ROOT_DIR = path.resolve(__dirname, '..');
49
+ const COVERAGE_DIR = path.join(ROOT_DIR, 'coverage');
50
+ // 确保覆盖率目录存在
51
+ if (!fs.existsSync(COVERAGE_DIR)) {
52
+ fs.mkdirSync(COVERAGE_DIR, { recursive: true });
53
+ }
54
+ /**
55
+ * 运行命令
56
+ * 注意:command 参数必须是硬编码的命令字符串,不能包含用户输入
57
+ * @param command - 要执行的命令(必须是硬编码字符串)
58
+ * @param env - 环境变量
59
+ */
60
+ function runCommand(command, env = {}) {
61
+ try {
62
+ // 使用 execSync 执行命令,命令必须是固定的字符串
63
+ // 安全说明:此函数只能用于执行硬编码的命令,不接受外部输入
64
+ // 所有调用此函数的地方都必须使用字符串字面量
65
+ (0, child_process_1.execSync)(command, {
66
+ stdio: 'inherit',
67
+ env: { ...process.env, ...env },
68
+ cwd: ROOT_DIR
69
+ });
70
+ }
71
+ catch (error) {
72
+ console.error(`命令执行失败:${command}`);
73
+ throw error;
74
+ }
75
+ }
76
+ /**
77
+ * 运行 Jest 测试(安全版本)
78
+ * 使用参数化方式执行 Jest,避免命令注入风险
79
+ * @param args - Jest 命令行参数数组
80
+ * @param env - 环境变量
81
+ */
82
+ function runJest(args, env = {}) {
83
+ const command = `npx jest ${args.join(' ')}`;
84
+ return runCommand(command, env);
85
+ }
86
+ function runUnitTests() {
87
+ console.log('\n🧪 运行单元测试...\n');
88
+ // 运行单元测试 - 使用参数化方式
89
+ runJest(['--coverage', '--testPathPattern=tests/unit'], {
90
+ JEST_JUNIT_OUTPUT_NAME: 'unit-test-results.xml',
91
+ COVERAGE_FILE: 'coverage/unit-coverage.json'
92
+ });
93
+ // 移动覆盖率文件
94
+ const coverageFile = path.join(COVERAGE_DIR, 'coverage-final.json');
95
+ if (fs.existsSync(coverageFile)) {
96
+ const unitCoverageFile = path.join(COVERAGE_DIR, 'unit-coverage-final.json');
97
+ fs.copyFileSync(coverageFile, unitCoverageFile);
98
+ console.log(`✅ 单元测试覆盖率已保存到:${unitCoverageFile}`);
99
+ }
100
+ }
101
+ function runAllTests() {
102
+ console.log('\n🧪 运行所有测试...\n');
103
+ // 运行所有测试 - 使用参数化方式
104
+ runJest(['--coverage'], {
105
+ JEST_JUNIT_OUTPUT_NAME: 'test-results.xml',
106
+ COVERAGE_FILE: 'coverage/all-coverage.json'
107
+ });
108
+ // 移动覆盖率文件
109
+ const coverageFile = path.join(COVERAGE_DIR, 'coverage-final.json');
110
+ if (fs.existsSync(coverageFile)) {
111
+ const allCoverageFile = path.join(COVERAGE_DIR, 'all-coverage-final.json');
112
+ fs.copyFileSync(coverageFile, allCoverageFile);
113
+ console.log(`✅ 所有测试覆盖率已保存到:${allCoverageFile}`);
114
+ }
115
+ }
116
+ function main() {
117
+ const args = process.argv.slice(2);
118
+ const testType = args[0] || 'all';
119
+ console.log('🚀 开始运行测试...\n');
120
+ try {
121
+ if (testType === 'unit') {
122
+ runUnitTests();
123
+ }
124
+ else if (testType === 'all') {
125
+ runAllTests();
126
+ }
127
+ else {
128
+ console.error(`❌ 未知的测试类型:${testType}`);
129
+ console.error('可用选项:unit, all');
130
+ process.exit(1);
131
+ }
132
+ console.log('\n✅ 测试完成!\n');
133
+ }
134
+ catch (error) {
135
+ console.error('\n❌ 测试失败!\n');
136
+ process.exit(1);
137
+ }
138
+ }
139
+ main();
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createSuccessResponse = createSuccessResponse;
4
+ exports.createErrorResponse = createErrorResponse;
5
+ exports.handleApi = handleApi;
6
+ /**
7
+ * 成功响应创建器
8
+ */
9
+ function createSuccessResponse(data, status = 200) {
10
+ return {
11
+ status,
12
+ body: {
13
+ response: data,
14
+ },
15
+ };
16
+ }
17
+ /**
18
+ * 错误响应创建器
19
+ */
20
+ function createErrorResponse(error, status = 500) {
21
+ return {
22
+ status,
23
+ body: {
24
+ error,
25
+ },
26
+ };
27
+ }
28
+ /**
29
+ * API Promise 处理器 - 自动处理成功和错误情况
30
+ */
31
+ async function handleApi(promise, options) {
32
+ try {
33
+ const result = await promise;
34
+ const responseData = options?.transformData
35
+ ? options.transformData(result.data || result)
36
+ : result.data || result;
37
+ return {
38
+ status: options?.customStatus || 200,
39
+ body: {
40
+ response: responseData,
41
+ },
42
+ };
43
+ }
44
+ catch (error) {
45
+ if (options?.logError !== false) {
46
+ console.log('API error:', error);
47
+ }
48
+ return {
49
+ status: options?.customStatus || 500,
50
+ body: {
51
+ error,
52
+ },
53
+ };
54
+ }
55
+ }