sa2kit 1.6.3 → 1.6.6

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 (119) hide show
  1. package/dist/audioDetection/index.js.map +1 -1
  2. package/dist/audioDetection/index.mjs.map +1 -1
  3. package/dist/auth/index.d.mts +26 -1
  4. package/dist/auth/index.d.ts +26 -1
  5. package/dist/auth/index.js +51 -23
  6. package/dist/auth/index.js.map +1 -1
  7. package/dist/auth/index.mjs +34 -3
  8. package/dist/auth/index.mjs.map +1 -1
  9. package/dist/auth/middleware/index.js +3 -3
  10. package/dist/auth/middleware/index.mjs +2 -2
  11. package/dist/auth/routes/index.js +14 -14
  12. package/dist/auth/routes/index.mjs +2 -2
  13. package/dist/auth/services/index.d.mts +1 -0
  14. package/dist/auth/services/index.d.ts +1 -0
  15. package/dist/auth/services/index.js +7 -7
  16. package/dist/auth/services/index.mjs +1 -1
  17. package/dist/calendar/index.d.mts +1197 -0
  18. package/dist/calendar/index.d.ts +1197 -0
  19. package/dist/calendar/index.js +5376 -0
  20. package/dist/calendar/index.js.map +1 -0
  21. package/dist/calendar/index.mjs +5311 -0
  22. package/dist/calendar/index.mjs.map +1 -0
  23. package/dist/calendar/routes/index.d.mts +118 -0
  24. package/dist/calendar/routes/index.d.ts +118 -0
  25. package/dist/calendar/routes/index.js +335 -0
  26. package/dist/calendar/routes/index.js.map +1 -0
  27. package/dist/calendar/routes/index.mjs +327 -0
  28. package/dist/calendar/routes/index.mjs.map +1 -0
  29. package/dist/calendar/server.d.mts +1184 -0
  30. package/dist/calendar/server.d.ts +1184 -0
  31. package/dist/calendar/server.js +219 -0
  32. package/dist/calendar/server.js.map +1 -0
  33. package/dist/calendar/server.mjs +165 -0
  34. package/dist/calendar/server.mjs.map +1 -0
  35. package/dist/{chunk-EBP7AE6F.js → chunk-2ODO4HEI.js} +48 -20
  36. package/dist/chunk-2ODO4HEI.js.map +1 -0
  37. package/dist/{chunk-RCNNVNLT.mjs → chunk-3BGPZN4X.mjs} +8 -3
  38. package/dist/chunk-3BGPZN4X.mjs.map +1 -0
  39. package/dist/{chunk-FV3FNHQY.js → chunk-6W5BMXJG.js} +4 -4
  40. package/dist/{chunk-FV3FNHQY.js.map → chunk-6W5BMXJG.js.map} +1 -1
  41. package/dist/chunk-6WXOA4BE.mjs +302 -0
  42. package/dist/chunk-6WXOA4BE.mjs.map +1 -0
  43. package/dist/{chunk-NMF4ANIC.js → chunk-7Z5LLJ3A.js} +8 -2
  44. package/dist/chunk-7Z5LLJ3A.js.map +1 -0
  45. package/dist/chunk-AXP7KROR.js +314 -0
  46. package/dist/chunk-AXP7KROR.js.map +1 -0
  47. package/dist/{chunk-42IJ7HEI.js → chunk-CD77U7LZ.js} +5 -5
  48. package/dist/{chunk-42IJ7HEI.js.map → chunk-CD77U7LZ.js.map} +1 -1
  49. package/dist/{chunk-6BL3AZGD.js → chunk-DUHZ7VZP.js} +2 -2
  50. package/dist/chunk-DUHZ7VZP.js.map +1 -0
  51. package/dist/{chunk-6VHWOPRR.mjs → chunk-ESRCX5TQ.mjs} +3 -3
  52. package/dist/{chunk-6VHWOPRR.mjs.map → chunk-ESRCX5TQ.mjs.map} +1 -1
  53. package/dist/{chunk-QKXKXAAV.js → chunk-G4AMEDO5.js} +2 -2
  54. package/dist/{chunk-QKXKXAAV.js.map → chunk-G4AMEDO5.js.map} +1 -1
  55. package/dist/chunk-GAC4J5GX.js +228 -0
  56. package/dist/chunk-GAC4J5GX.js.map +1 -0
  57. package/dist/chunk-IEA55H3G.js +106 -0
  58. package/dist/chunk-IEA55H3G.js.map +1 -0
  59. package/dist/{chunk-U2L6V7KD.mjs → chunk-OCR5DS4C.mjs} +2 -2
  60. package/dist/chunk-OCR5DS4C.mjs.map +1 -0
  61. package/dist/{chunk-IBLB7ARJ.mjs → chunk-QAT2RWAO.mjs} +3 -3
  62. package/dist/{chunk-IBLB7ARJ.mjs.map → chunk-QAT2RWAO.mjs.map} +1 -1
  63. package/dist/chunk-R2F4BXUU.mjs +100 -0
  64. package/dist/chunk-R2F4BXUU.mjs.map +1 -0
  65. package/dist/chunk-T6TE7GTY.mjs +218 -0
  66. package/dist/chunk-T6TE7GTY.mjs.map +1 -0
  67. package/dist/{chunk-MBG4DBGP.mjs → chunk-ZCLAF3XN.mjs} +47 -19
  68. package/dist/chunk-ZCLAF3XN.mjs.map +1 -0
  69. package/dist/{chunk-6LEA37ZM.mjs → chunk-ZYXF3L6T.mjs} +2 -2
  70. package/dist/{chunk-6LEA37ZM.mjs.map → chunk-ZYXF3L6T.mjs.map} +1 -1
  71. package/dist/imageCrop/index.js.map +1 -1
  72. package/dist/imageCrop/index.mjs.map +1 -1
  73. package/dist/{index-DtLpANUB.d.mts → index-DSel44Ke.d.mts} +24 -1
  74. package/dist/{index-DtLpANUB.d.ts → index-DSel44Ke.d.ts} +24 -1
  75. package/dist/index.d.mts +426 -3
  76. package/dist/index.d.ts +426 -3
  77. package/dist/index.js +2116 -65
  78. package/dist/index.js.map +1 -1
  79. package/dist/index.mjs +1949 -33
  80. package/dist/index.mjs.map +1 -1
  81. package/dist/mmd/index.d.mts +78 -1
  82. package/dist/mmd/index.d.ts +78 -1
  83. package/dist/mmd/index.js +397 -50
  84. package/dist/mmd/index.js.map +1 -1
  85. package/dist/mmd/index.mjs +399 -53
  86. package/dist/mmd/index.mjs.map +1 -1
  87. package/dist/music/index.d.mts +54 -5
  88. package/dist/music/index.d.ts +54 -5
  89. package/dist/music/index.js +35 -435
  90. package/dist/music/index.js.map +1 -1
  91. package/dist/music/index.mjs +2 -424
  92. package/dist/music/index.mjs.map +1 -1
  93. package/dist/music/server/index.d.mts +1 -1
  94. package/dist/music/server/index.d.ts +1 -1
  95. package/dist/music/server/index.js +14 -6
  96. package/dist/music/server/index.mjs +1 -1
  97. package/dist/testYourself/admin/index.js +3 -3
  98. package/dist/testYourself/admin/index.mjs +1 -1
  99. package/dist/testYourself/index.js +7 -7
  100. package/dist/testYourself/index.js.map +1 -1
  101. package/dist/testYourself/index.mjs +2 -2
  102. package/dist/testYourself/index.mjs.map +1 -1
  103. package/dist/universalFile/index.d.mts +125 -7
  104. package/dist/universalFile/index.d.ts +125 -7
  105. package/dist/universalFile/index.js +1253 -30
  106. package/dist/universalFile/index.js.map +1 -1
  107. package/dist/universalFile/index.mjs +1244 -23
  108. package/dist/universalFile/index.mjs.map +1 -1
  109. package/dist/utils/index.d.mts +5 -1
  110. package/dist/utils/index.d.ts +5 -1
  111. package/dist/utils/index.js +13 -9
  112. package/dist/utils/index.mjs +1 -1
  113. package/package.json +18 -3
  114. package/dist/chunk-6BL3AZGD.js.map +0 -1
  115. package/dist/chunk-EBP7AE6F.js.map +0 -1
  116. package/dist/chunk-MBG4DBGP.mjs.map +0 -1
  117. package/dist/chunk-NMF4ANIC.js.map +0 -1
  118. package/dist/chunk-RCNNVNLT.mjs.map +0 -1
  119. package/dist/chunk-U2L6V7KD.mjs.map +0 -1
@@ -0,0 +1,228 @@
1
+ 'use strict';
2
+
3
+ var chunk2ODO4HEI_js = require('./chunk-2ODO4HEI.js');
4
+ var react = require('react');
5
+ var useSWR = require('swr');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var useSWR__default = /*#__PURE__*/_interopDefault(useSWR);
10
+
11
+ // src/music/adapters/kugou.ts
12
+ var kugouAdapter = {
13
+ parseSearchResult(data) {
14
+ const root = typeof data === "string" ? JSON.parse(data) : data;
15
+ const info = root.data?.data?.info || root.data?.info || root.info || [];
16
+ const total = root.data?.data?.total || root.data?.total || info.length;
17
+ return {
18
+ tracks: info.map((item) => {
19
+ let pic = item.pic || "";
20
+ if (item.trans_param?.union_cover) {
21
+ pic = item.trans_param.union_cover.replace("{size}", "400");
22
+ }
23
+ return {
24
+ id: item.hash || item.id,
25
+ name: item.songname || item.filename || "Unknown",
26
+ artist: item.singername || "Unknown Artist",
27
+ album: item.album_name || item.album || "",
28
+ pic,
29
+ url: item.url,
30
+ lrc: item.lrc,
31
+ source: "kugou",
32
+ isVip: item.privilege >= 8,
33
+ playable: item.status !== 0
34
+ };
35
+ }),
36
+ total
37
+ };
38
+ },
39
+ parseGetSongUrl(data) {
40
+ return data.url?.url || data.url?.backup_url?.[0] || null;
41
+ },
42
+ parseGetLyric(data) {
43
+ const root = typeof data === "string" ? JSON.parse(data) : data;
44
+ return root.lyric || root.lrc || root.data?.lyric || root.data || "";
45
+ }
46
+ };
47
+
48
+ // src/music/adapters/netease.ts
49
+ var neteaseAdapter = {
50
+ parseSearchResult(data) {
51
+ const root = typeof data === "string" ? JSON.parse(data) : data;
52
+ const songs = root.result?.songs || root.songs || (Array.isArray(root) ? root : []);
53
+ return {
54
+ tracks: songs.map((item) => ({
55
+ id: item.id,
56
+ name: item.name,
57
+ artist: Array.isArray(item.artist) ? item.artist.join(", ") : item.artist,
58
+ album: item.album?.name || item.album,
59
+ pic: item.pic || item.album?.picUrl,
60
+ url: item.url,
61
+ lrc: item.lrc,
62
+ source: "netease",
63
+ isVip: item.fee === 1 || item.fee === 4,
64
+ playable: item.noCopyrightRcmd === null
65
+ })),
66
+ total: root.result?.songCount || songs.length
67
+ };
68
+ },
69
+ parseGetSongUrl(data) {
70
+ const root = typeof data === "string" ? JSON.parse(data) : data;
71
+ const item = root.data?.[0] || root[0] || root;
72
+ return item.url || null;
73
+ },
74
+ parseGetLyric(data) {
75
+ const root = typeof data === "string" ? JSON.parse(data) : data;
76
+ return root.lyric || root.lrc || root.data?.lyric || "";
77
+ }
78
+ };
79
+
80
+ // src/music/adapters/tencent.ts
81
+ var tencentAdapter = {
82
+ parseSearchResult(data) {
83
+ const root = typeof data === "string" ? JSON.parse(data) : data;
84
+ const songData = root.data?.data?.song || root.data?.song || root.data || root;
85
+ const list = songData.list || root.songs || [];
86
+ const total = songData.totalnum || root.total || list.length;
87
+ return {
88
+ tracks: list.map((item) => {
89
+ const artist = Array.isArray(item.singer) ? item.singer.map((s) => s.name).join(", ") : item.singer?.[0]?.name || item.artist || "Unknown";
90
+ let pic = item.pic;
91
+ if (!pic && item.album?.mid) {
92
+ pic = `https://y.gtimg.cn/music/photo_new/T002R300x300M000${item.album.mid}.jpg`;
93
+ }
94
+ return {
95
+ id: item.mid || item.id || item.songid,
96
+ name: item.name || item.title || item.songname,
97
+ artist,
98
+ album: item.album?.name || item.albumname || item.album,
99
+ pic: pic || "",
100
+ url: item.url,
101
+ lrc: item.lrc,
102
+ source: "tencent",
103
+ isVip: item.pay?.pay_play === 1,
104
+ playable: item.action?.switch !== 0
105
+ };
106
+ }),
107
+ total
108
+ };
109
+ },
110
+ parseGetSongUrl(data) {
111
+ const root = data;
112
+ const urlData = root.url.url;
113
+ let finalUrl = Object.values(urlData)[0];
114
+ console.log("finalUrl2", finalUrl);
115
+ return finalUrl.startsWith("http") ? finalUrl : `http://${finalUrl}`;
116
+ },
117
+ parseGetLyric(data) {
118
+ const root = typeof data === "string" ? JSON.parse(data) : data;
119
+ return root.lyric || root.lrc || root.data?.lyric || "";
120
+ }
121
+ };
122
+
123
+ // src/music/adapters/xiami.ts
124
+ var xiamiAdapter = {
125
+ parseSearchResult(data) {
126
+ const root = typeof data === "string" ? JSON.parse(data) : data;
127
+ const result = root.data?.result || root.result || root;
128
+ const songs = result.songs || (Array.isArray(root) ? root : []);
129
+ return {
130
+ tracks: songs.map((item) => ({
131
+ id: item.id?.toString() || "",
132
+ name: item.name || "Unknown",
133
+ artist: Array.isArray(item.ar) ? item.ar.map((a) => a.name).join(", ") : item.artist || "Unknown Artist",
134
+ album: item.al?.name || item.album || "",
135
+ pic: item.al?.picUrl || item.pic || "",
136
+ url: item.url,
137
+ lrc: item.lrc,
138
+ source: "xiami",
139
+ // 这里的逻辑参考提供的数据结构
140
+ isVip: item.fee === 1 || item.fee === 8,
141
+ playable: item.copyright !== 0
142
+ })),
143
+ total: result.songCount || songs.length
144
+ };
145
+ },
146
+ parseGetSongUrl(data) {
147
+ const root = typeof data === "string" ? JSON.parse(data) : data;
148
+ const item = root.data?.[0] || root.data || root[0] || root;
149
+ return item.url || null;
150
+ },
151
+ parseGetLyric(data) {
152
+ const root = typeof data === "string" ? JSON.parse(data) : data;
153
+ return root.lyric || root.lrc || root.data?.lyric || root.data || "";
154
+ }
155
+ };
156
+
157
+ // src/music/hooks/useMusic.ts
158
+ var fetcher = (url) => fetch(url).then((res) => res.json());
159
+ var ADAPTERS = {
160
+ kugou: kugouAdapter,
161
+ netease: neteaseAdapter,
162
+ tencent: tencentAdapter,
163
+ xiami: xiamiAdapter
164
+ };
165
+ function useMusic() {
166
+ const [searchOptions, setSearchOptions] = react.useState(null);
167
+ const { data: rawData, error: searchError, isLoading: isSearching } = useSWR__default.default(
168
+ searchOptions ? `/api/music/search?keyword=${encodeURIComponent(searchOptions.keyword)}&source=${searchOptions.source || chunk2ODO4HEI_js.DEFAULT_MUSIC_SOURCE}&limit=${searchOptions.limit || 20}&offset=${searchOptions.offset || 0}${searchOptions.miku ? "&miku=true" : ""}` : null,
169
+ fetcher
170
+ );
171
+ const searchResult = react.useMemo(() => {
172
+ if (!rawData?.data || !searchOptions) return void 0;
173
+ const adapter = ADAPTERS[searchOptions.source || chunk2ODO4HEI_js.DEFAULT_MUSIC_SOURCE];
174
+ if (adapter) {
175
+ return adapter.parseSearchResult(rawData.data);
176
+ }
177
+ return void 0;
178
+ }, [rawData, searchOptions]);
179
+ const search = react.useCallback((options) => {
180
+ setSearchOptions(options);
181
+ }, []);
182
+ const getSongUrl = react.useCallback(async (id, source = chunk2ODO4HEI_js.DEFAULT_MUSIC_SOURCE) => {
183
+ try {
184
+ const res = await fetch(`/api/music/url?id=${id}&source=${source}`);
185
+ const json = await res.json();
186
+ const adapter = ADAPTERS[source];
187
+ console.log("json2", json.data, source, adapter);
188
+ if (adapter && json.data) {
189
+ console.log("getSongUrl2", json.data);
190
+ return adapter.parseGetSongUrl(json.data) || void 0;
191
+ }
192
+ return json.data?.url;
193
+ } catch (err) {
194
+ console.error("[Music] Failed to get song URL:", err);
195
+ return void 0;
196
+ }
197
+ }, []);
198
+ const getLyric = react.useCallback(async (id, source = chunk2ODO4HEI_js.DEFAULT_MUSIC_SOURCE) => {
199
+ try {
200
+ const res = await fetch(`/api/music/lyric?id=${id}&source=${source}`);
201
+ const json = await res.json();
202
+ const adapter = ADAPTERS[source];
203
+ if (adapter && json.data) {
204
+ return adapter.parseGetLyric(json.data);
205
+ }
206
+ return json.data?.lyric;
207
+ } catch (err) {
208
+ console.error("[Music] Failed to get lyric:", err);
209
+ return void 0;
210
+ }
211
+ }, []);
212
+ return {
213
+ search,
214
+ searchResult,
215
+ isSearching,
216
+ searchError,
217
+ getSongUrl,
218
+ getLyric
219
+ };
220
+ }
221
+
222
+ exports.kugouAdapter = kugouAdapter;
223
+ exports.neteaseAdapter = neteaseAdapter;
224
+ exports.tencentAdapter = tencentAdapter;
225
+ exports.useMusic = useMusic;
226
+ exports.xiamiAdapter = xiamiAdapter;
227
+ //# sourceMappingURL=chunk-GAC4J5GX.js.map
228
+ //# sourceMappingURL=chunk-GAC4J5GX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/music/adapters/kugou.ts","../src/music/adapters/netease.ts","../src/music/adapters/tencent.ts","../src/music/adapters/xiami.ts","../src/music/hooks/useMusic.ts"],"names":["useState","useSWR","DEFAULT_MUSIC_SOURCE","useMemo","useCallback"],"mappings":"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","file":"chunk-GAC4J5GX.js","sourcesContent":["import { SearchResult } from '../types';\nimport { MusicSourceAdapter } from './types';\n\nexport const kugouAdapter: MusicSourceAdapter = {\n parseSearchResult(data: any): SearchResult {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n const info = root.data?.data?.info || root.data?.info || root.info || [];\n const total = root.data?.data?.total || root.data?.total || info.length;\n return {\n tracks: info.map((item: any) => {\n // 优先从 trans_param.union_cover 提取封面,并替换 {size} 为 400\n let pic = item.pic || '';\n if (item.trans_param?.union_cover) {\n pic = item.trans_param.union_cover.replace('{size}', '400');\n }\n\n return {\n id: item.hash || item.id,\n name: item.songname || item.filename || 'Unknown',\n artist: item.singername || 'Unknown Artist',\n album: item.album_name || item.album || '',\n pic: pic,\n url: item.url,\n lrc: item.lrc,\n source: 'kugou',\n isVip: item.privilege >= 8,\n playable: item.status !== 0,\n };\n }),\n total: total,\n };\n },\n\n parseGetSongUrl(data: any): string | null {\n return data.url?.url || data.url?.backup_url?.[0] || null;\n },\n\n parseGetLyric(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n return root.lyric || root.lrc || root.data?.lyric || root.data || '';\n }\n};\n","import { SearchResult } from '../types';\nimport { MusicSourceAdapter } from './types';\n\nexport const neteaseAdapter: MusicSourceAdapter = {\n parseSearchResult(data: any): SearchResult {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n const songs = root.result?.songs || root.songs || (Array.isArray(root) ? root : []);\n \n return {\n tracks: songs.map((item: any) => ({\n id: item.id,\n name: item.name,\n artist: Array.isArray(item.artist) ? item.artist.join(', ') : item.artist,\n album: item.album?.name || item.album,\n pic: item.pic || item.album?.picUrl,\n url: item.url,\n lrc: item.lrc,\n source: 'netease',\n isVip: item.fee === 1 || item.fee === 4,\n playable: item.noCopyrightRcmd === null,\n })),\n total: root.result?.songCount || songs.length,\n };\n },\n\n parseGetSongUrl(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n const item = root.data?.[0] || root[0] || root;\n return item.url || null;\n },\n\n parseGetLyric(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n return root.lyric || root.lrc || root.data?.lyric || '';\n }\n};\n\n","import { SearchResult } from '../types';\nimport { MusicSourceAdapter } from './types';\n\nexport const tencentAdapter: MusicSourceAdapter = {\n parseSearchResult(data: any): SearchResult {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n \n // 兼容多种 QQ 音乐返回结构\n const songData = root.data?.data?.song || root.data?.song || root.data || root;\n const list = songData.list || root.songs || [];\n const total = songData.totalnum || root.total || list.length;\n \n return {\n tracks: list.map((item: any) => {\n // 解析歌手名\n const artist = Array.isArray(item.singer) \n ? item.singer.map((s: any) => s.name).join(', ') \n : (item.singer?.[0]?.name || item.artist || 'Unknown');\n\n // 处理封面图 (QQ 音乐封面通常基于 album mid)\n let pic = item.pic;\n if (!pic && item.album?.mid) {\n pic = `https://y.gtimg.cn/music/photo_new/T002R300x300M000${item.album.mid}.jpg`;\n }\n\n return {\n id: item.mid || item.id || item.songid,\n name: item.name || item.title || item.songname,\n artist: artist,\n album: item.album?.name || item.albumname || item.album,\n pic: pic || '',\n url: item.url,\n lrc: item.lrc,\n source: 'tencent',\n isVip: item.pay?.pay_play === 1,\n playable: item.action?.switch !== 0,\n };\n }),\n total: total,\n };\n },\n\n parseGetSongUrl(data: any): string | null {\n\n const root = data\n\n const urlData = root.url.url;\n let finalUrl = Object.values(urlData)[0] as string;\n console.log('finalUrl2', finalUrl);\n return finalUrl.startsWith('http') ? finalUrl : `http://${finalUrl}`;\n },\n\n parseGetLyric(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n return root.lyric || root.lrc || root.data?.lyric || '';\n }\n};\n\n","import { SearchResult } from '../types';\nimport { MusicSourceAdapter } from './types';\n\nexport const xiamiAdapter: MusicSourceAdapter = {\n parseSearchResult(data: any): SearchResult {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n // 虾米返回的结构(根据提供的数据,类似于网易云的结构)\n const result = root.data?.result || root.result || root;\n const songs = result.songs || (Array.isArray(root) ? root : []);\n \n return {\n tracks: songs.map((item: any) => ({\n id: item.id?.toString() || '',\n name: item.name || 'Unknown',\n artist: Array.isArray(item.ar) \n ? item.ar.map((a: any) => a.name).join(', ') \n : (item.artist || 'Unknown Artist'),\n album: item.al?.name || item.album || '',\n pic: item.al?.picUrl || item.pic || '',\n url: item.url,\n lrc: item.lrc,\n source: 'xiami',\n // 这里的逻辑参考提供的数据结构\n isVip: item.fee === 1 || item.fee === 8,\n playable: item.copyright !== 0,\n })),\n total: result.songCount || songs.length,\n };\n },\n\n parseGetSongUrl(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n // 兼容多种可能的包装结构\n const item = root.data?.[0] || root.data || root[0] || root;\n return item.url || null;\n },\n\n parseGetLyric(data: any): any {\n const root = typeof data === 'string' ? JSON.parse(data) : data;\n return root.lyric || root.lrc || root.data?.lyric || root.data || '';\n }\n};\n\n","import useSWR from 'swr';\nimport { useState, useCallback, useMemo } from 'react';\nimport { MusicTrack, SearchOptions, SearchResult, MusicApiResponse } from '../types';\nimport { DEFAULT_MUSIC_SOURCE } from '../constants';\nimport { \n kugouAdapter, \n neteaseAdapter, \n tencentAdapter, \n xiamiAdapter,\n MusicSourceAdapter \n} from '../adapters';\n\nconst fetcher = (url: string) => fetch(url).then(res => res.json());\n\nconst ADAPTERS: Record<string, MusicSourceAdapter> = {\n kugou: kugouAdapter,\n netease: neteaseAdapter,\n tencent: tencentAdapter,\n xiami: xiamiAdapter,\n};\n\nexport function useMusic() {\n const [searchOptions, setSearchOptions] = useState<SearchOptions | null>(null);\n\n // 搜索歌曲\n const { data: rawData, error: searchError, isLoading: isSearching } = useSWR<MusicApiResponse<any>>(\n searchOptions ? `/api/music/search?keyword=${encodeURIComponent(searchOptions.keyword)}&source=${searchOptions.source || DEFAULT_MUSIC_SOURCE}&limit=${searchOptions.limit || 20}&offset=${searchOptions.offset || 0}${searchOptions.miku ? '&miku=true' : ''}` : null,\n fetcher\n );\n\n const searchResult = useMemo(() => {\n if (!rawData?.data || !searchOptions) return undefined;\n const adapter = ADAPTERS[searchOptions.source || DEFAULT_MUSIC_SOURCE];\n if (adapter) {\n return adapter.parseSearchResult(rawData.data);\n }\n return undefined;\n }, [rawData, searchOptions]);\n\n const search = useCallback((options: SearchOptions) => {\n setSearchOptions(options);\n }, []);\n\n // 获取播放链接\n const getSongUrl = useCallback(async (id: string, source: string = DEFAULT_MUSIC_SOURCE): Promise<string | undefined> => {\n try {\n const res = await fetch(`/api/music/url?id=${id}&source=${source}`);\n const json: MusicApiResponse<any> = await res.json();\n const adapter = ADAPTERS[source];\n console.log('json2', json.data,source,adapter);\n if (adapter && json.data) {\n console.log('getSongUrl2', json.data);\n return adapter.parseGetSongUrl(json.data) || undefined;\n }\n return json.data?.url;\n } catch (err) {\n console.error('[Music] Failed to get song URL:', err);\n return undefined;\n }\n }, []);\n\n // 获取歌词\n const getLyric = useCallback(async (id: string, source: string = DEFAULT_MUSIC_SOURCE): Promise<string | undefined> => {\n try {\n const res = await fetch(`/api/music/lyric?id=${id}&source=${source}`);\n const json: MusicApiResponse<any> = await res.json();\n const adapter = ADAPTERS[source];\n if (adapter && json.data) {\n return adapter.parseGetLyric(json.data);\n }\n return json.data?.lyric;\n } catch (err) {\n console.error('[Music] Failed to get lyric:', err);\n return undefined;\n }\n }, []);\n\n return {\n search,\n searchResult,\n isSearching,\n searchError,\n getSongUrl,\n getLyric,\n };\n}\n\n"]}
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
+
7
+ var React__default = /*#__PURE__*/_interopDefault(React);
8
+
9
+ // src/components/SearchBox.tsx
10
+ var SearchBox = ({
11
+ searchQuery,
12
+ onSearchChange,
13
+ placeholder = "\u641C\u7D22\u5B9E\u9A8C\u9879\u76EE\u7684\u6807\u9898\u3001\u63CF\u8FF0\u6216\u6807\u7B7E...",
14
+ size = "large"
15
+ }) => {
16
+ const getSizeStyles = () => {
17
+ switch (size) {
18
+ case "small":
19
+ return {
20
+ container: "h-10",
21
+ input: "pl-10 pr-10 text-sm",
22
+ icon: "w-4 h-4",
23
+ iconPosition: "left-3",
24
+ clearButton: "right-2 w-6 h-6",
25
+ clearIcon: "w-3 h-3"
26
+ };
27
+ case "medium":
28
+ return {
29
+ container: "h-12",
30
+ input: "pl-12 pr-12 text-base",
31
+ icon: "w-5 h-5",
32
+ iconPosition: "left-3",
33
+ clearButton: "right-3 w-7 h-7",
34
+ clearIcon: "w-4 h-4"
35
+ };
36
+ case "large":
37
+ default:
38
+ return {
39
+ container: "h-16",
40
+ input: "pl-6 pr-16 text-lg",
41
+ icon: "w-6 h-6",
42
+ iconPosition: "left-6",
43
+ clearButton: "right-4 w-8 h-8",
44
+ clearIcon: "w-4 h-4"
45
+ };
46
+ }
47
+ };
48
+ const styles = getSizeStyles();
49
+ const isLarge = size === "large";
50
+ return /* @__PURE__ */ React__default.default.createElement("div", { className: "relative group w-full" }, /* @__PURE__ */ React__default.default.createElement(
51
+ "input",
52
+ {
53
+ type: "text",
54
+ placeholder,
55
+ value: searchQuery,
56
+ onChange: (e) => onSearchChange(e.target.value),
57
+ className: `
58
+ w-full ${styles.container} ${styles.input}
59
+ ${isLarge ? "border-2 border-gray-200 rounded-2xl shadow-lg" : "border border-gray-300 rounded-lg shadow-sm"}
60
+ bg-white
61
+ focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500
62
+ hover:border-gray-400 ${isLarge ? "hover:shadow-xl" : "hover:shadow-md"}
63
+ transition-all duration-300 ease-out
64
+ text-gray-800 placeholder-gray-500
65
+ ${isLarge ? "font-medium" : "font-normal"}
66
+ `
67
+ }
68
+ ), searchQuery && /* @__PURE__ */ React__default.default.createElement(
69
+ "button",
70
+ {
71
+ onClick: () => onSearchChange(""),
72
+ className: `
73
+ absolute top-1/2 ${styles.clearButton} transform -translate-y-1/2
74
+ z-10 group/clear
75
+ `
76
+ },
77
+ /* @__PURE__ */ React__default.default.createElement("div", { className: `
78
+ ${styles.clearButton} flex items-center justify-center
79
+ rounded-full
80
+ bg-gray-100 hover:bg-gray-200
81
+ transition-all duration-200
82
+ group-hover/clear:scale-105
83
+ ` }, /* @__PURE__ */ React__default.default.createElement(
84
+ "svg",
85
+ {
86
+ className: `${styles.clearIcon} text-gray-500 group-hover/clear:text-gray-700`,
87
+ fill: "none",
88
+ stroke: "currentColor",
89
+ viewBox: "0 0 24 24"
90
+ },
91
+ /* @__PURE__ */ React__default.default.createElement(
92
+ "path",
93
+ {
94
+ strokeLinecap: "round",
95
+ strokeLinejoin: "round",
96
+ strokeWidth: 2,
97
+ d: "M6 18L18 6M6 6l12 12"
98
+ }
99
+ )
100
+ ))
101
+ ));
102
+ };
103
+
104
+ exports.SearchBox = SearchBox;
105
+ //# sourceMappingURL=chunk-IEA55H3G.js.map
106
+ //# sourceMappingURL=chunk-IEA55H3G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/SearchBox.tsx"],"names":["React"],"mappings":"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","file":"chunk-IEA55H3G.js","sourcesContent":["import React from 'react';\n\ninterface SearchBoxProps {\n searchQuery: string;\n onSearchChange: (query: string) => void;\n placeholder?: string;\n size?: 'small' | 'medium' | 'large';\n}\n\nexport const SearchBox: React.FC<SearchBoxProps> = ({ \n searchQuery, \n onSearchChange, \n placeholder = \"搜索实验项目的标题、描述或标签...\",\n size = 'large'\n}) => {\n // 根据尺寸获取样式\n const getSizeStyles = () => {\n switch (size) {\n case 'small':\n return {\n container: 'h-10',\n input: 'pl-10 pr-10 text-sm',\n icon: 'w-4 h-4',\n iconPosition: 'left-3',\n clearButton: 'right-2 w-6 h-6',\n clearIcon: 'w-3 h-3'\n };\n case 'medium':\n return {\n container: 'h-12',\n input: 'pl-12 pr-12 text-base',\n icon: 'w-5 h-5',\n iconPosition: 'left-3',\n clearButton: 'right-3 w-7 h-7',\n clearIcon: 'w-4 h-4'\n };\n case 'large':\n default:\n return {\n container: 'h-16',\n input: 'pl-6 pr-16 text-lg',\n icon: 'w-6 h-6',\n iconPosition: 'left-6',\n clearButton: 'right-4 w-8 h-8',\n clearIcon: 'w-4 h-4'\n };\n }\n };\n\n const styles = getSizeStyles();\n const isLarge = size === 'large';\n\n return (\n <div className=\"relative group w-full\">\n {/* 搜索输入框 */}\n <input\n type=\"text\"\n placeholder={placeholder}\n value={searchQuery}\n onChange={(e) => onSearchChange(e.target.value)}\n className={`\n w-full ${styles.container} ${styles.input}\n ${isLarge ? 'border-2 border-gray-200 rounded-2xl shadow-lg' : 'border border-gray-300 rounded-lg shadow-sm'}\n bg-white \n focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 \n hover:border-gray-400 ${isLarge ? 'hover:shadow-xl' : 'hover:shadow-md'}\n transition-all duration-300 ease-out\n text-gray-800 placeholder-gray-500\n ${isLarge ? 'font-medium' : 'font-normal'}\n `}\n />\n\n {/* 清除按钮 */}\n {searchQuery && (\n <button\n onClick={() => onSearchChange('')}\n className={`\n absolute top-1/2 ${styles.clearButton} transform -translate-y-1/2\n z-10 group/clear\n `}\n >\n <div className={`\n ${styles.clearButton} flex items-center justify-center\n rounded-full \n bg-gray-100 hover:bg-gray-200 \n transition-all duration-200 \n group-hover/clear:scale-105\n `}>\n <svg \n className={`${styles.clearIcon} text-gray-500 group-hover/clear:text-gray-700`}\n fill=\"none\" \n stroke=\"currentColor\" \n viewBox=\"0 0 24 24\"\n >\n <path \n strokeLinecap=\"round\" \n strokeLinejoin=\"round\" \n strokeWidth={2} \n d=\"M6 18L18 6M6 6l12 12\" \n />\n </svg>\n </div>\n </button>\n )}\n </div>\n );\n}"]}
@@ -269,5 +269,5 @@ var DrizzleAuthService = class {
269
269
  };
270
270
 
271
271
  export { DrizzleAuthService, generateToken, getTokenFromRequest, hashPassword, verifyJwtToken, verifyPassword };
272
- //# sourceMappingURL=chunk-U2L6V7KD.mjs.map
273
- //# sourceMappingURL=chunk-U2L6V7KD.mjs.map
272
+ //# sourceMappingURL=chunk-OCR5DS4C.mjs.map
273
+ //# sourceMappingURL=chunk-OCR5DS4C.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/services/password-utils.ts","../src/auth/services/token-utils.ts","../src/auth/services/drizzle-auth-service.ts"],"names":[],"mappings":"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","file":"chunk-OCR5DS4C.mjs","sourcesContent":["/**\n * Auth Services - Password Utilities\n * 密码哈希相关工具函数\n */\n\nimport bcrypt from 'bcryptjs';\n\n/**\n * 哈希密码\n */\nexport async function hashPassword(password: string, saltRounds: number = 12): Promise<string> {\n return bcrypt.hash(password, saltRounds);\n}\n\n/**\n * 验证密码\n */\nexport async function verifyPassword(password: string, hashedPassword: string): Promise<boolean> {\n return bcrypt.compare(password, hashedPassword);\n}\n\n","/**\n * Auth Services - Token Utilities\n * Token 相关工具函数\n */\n\nimport jwt from 'jsonwebtoken';\nimport type { UserRole } from '../schema/enums';\n\n/**\n * JWT Payload\n */\nexport interface JwtPayload {\n userId: string;\n email: string;\n username?: string;\n role: UserRole;\n iat?: number;\n exp?: number;\n}\n\n/**\n * 生成 JWT Token\n */\nexport function generateToken(\n payload: Omit<JwtPayload, 'iat' | 'exp'>,\n secret: string,\n expiresIn: string | number = '7d'\n): string {\n return jwt.sign(payload, secret, { expiresIn } as jwt.SignOptions);\n}\n\n/**\n * 验证 JWT Token\n */\nexport function verifyJwtToken(token: string, secret: string): JwtPayload {\n return jwt.verify(token, secret) as JwtPayload;\n}\n\n/**\n * 从请求中获取 Token\n * 优先从 Cookie 读取(Web),兼容 Authorization Header(Mobile/API)\n */\nexport function getTokenFromRequest(request: Request): string | null {\n // 🔐 优先从 httpOnly Cookie 读取(Web 管理后台,更安全)\n const cookieHeader = request.headers.get('Cookie');\n if (cookieHeader) {\n // 匹配 auth_token\n const match = cookieHeader.match(/auth_token=([^;]+)/);\n if (match && match[1]) {\n return match[1];\n }\n }\n\n // 🔄 兼容从 Authorization Header 读取(移动端、小程序、API 调用)\n const authHeader = request.headers.get('Authorization');\n if (authHeader && authHeader.startsWith('Bearer ')) {\n const token = authHeader.substring(7);\n return token || null;\n }\n\n return null;\n}\n\n","/**\n * Auth Services - Drizzle Auth Service\n * 基于 Drizzle ORM 的认证服务\n */\n\nimport { eq, and, gt } from 'drizzle-orm';\nimport { randomBytes } from 'crypto';\nimport { user, session } from '../schema';\nimport { hashPassword, verifyPassword } from './password-utils';\nimport { generateToken, verifyJwtToken } from './token-utils';\nimport type {\n AuthServiceConfig,\n AuthResult,\n VerifyResult,\n UserInfo,\n SessionInfo,\n} from './types';\nimport type { UserRole } from '../schema/enums';\n\n/**\n * Drizzle 认证服务类\n *\n * @example\n * ```typescript\n * import { DrizzleAuthService } from '@qhr123/sa2kit/auth/services';\n * import { db } from './db';\n *\n * const authService = new DrizzleAuthService({\n * db,\n * jwtSecret: process.env.JWT_SECRET!,\n * jwtExpiresIn: '7d',\n * });\n *\n * // 用户注册\n * const result = await authService.signUp('user@example.com', 'password123', 'username');\n *\n * // 用户登录\n * const loginResult = await authService.signIn('user@example.com', 'password123');\n * ```\n */\nexport class DrizzleAuthService {\n private config: Required<AuthServiceConfig>;\n\n constructor(config: AuthServiceConfig) {\n // 设置默认值\n this.config = {\n db: config.db,\n jwtSecret: config.jwtSecret,\n jwtExpiresIn: config.jwtExpiresIn || '7d',\n saltRounds: config.saltRounds || 12,\n checkSecretStrength: config.checkSecretStrength !== false,\n };\n\n // 验证配置\n this.validateConfig();\n }\n\n /**\n * 验证配置\n */\n private validateConfig(): void {\n if (!this.config.jwtSecret) {\n throw new Error(\n 'JWT_SECRET is required. Please provide jwtSecret in config. ' +\n \"You can generate a secure secret with: node -e \\\"console.log(require('crypto').randomBytes(64).toString('hex'))\\\"\"\n );\n }\n\n // 生产环境检查密钥强度\n if (\n this.config.checkSecretStrength &&\n process.env.NODE_ENV === 'production' &&\n this.config.jwtSecret.length < 32\n ) {\n throw new Error(\n `JWT_SECRET is too short (${this.config.jwtSecret.length} chars, minimum 32 required in production)`\n );\n }\n }\n\n /**\n * 用户注册\n */\n async signUp(\n email: string,\n password: string,\n username?: string,\n role: UserRole = 'USER'\n ): Promise<AuthResult> {\n try {\n // 检查用户是否已存在\n const existingUser = await this.config.db\n .select()\n .from(user)\n .where(eq(user.email, email))\n .limit(1);\n\n if (existingUser.length > 0) {\n throw new Error('用户已存在');\n }\n\n // 哈希密码\n const hashedPassword = await hashPassword(password, this.config.saltRounds);\n\n // 创建用户\n const [newUser] = await this.config.db\n .insert(user)\n .values({\n id: randomBytes(16).toString('hex'),\n email,\n password: hashedPassword,\n username: username || email.split('@')[0],\n role,\n emailVerified: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n })\n .returning();\n\n // 生成 JWT token\n const token = generateToken(\n {\n userId: newUser.id,\n email: newUser.email,\n role: newUser.role as UserRole,\n },\n this.config.jwtSecret,\n this.config.jwtExpiresIn\n );\n\n // 创建会话\n await this.createSession(newUser.id, token);\n\n return {\n user: {\n id: newUser.id,\n email: newUser.email,\n username: newUser.username,\n role: newUser.role as UserRole,\n },\n token,\n };\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * 用户登录\n */\n async signIn(email: string, password: string): Promise<AuthResult> {\n try {\n // 查找用户\n const [foundUser] = await this.config.db\n .select()\n .from(user)\n .where(eq(user.email, email))\n .limit(1);\n\n if (!foundUser) {\n throw new Error('邮箱或密码错误');\n }\n\n // 验证密码\n if (!foundUser.password) {\n throw new Error('用户密码未设置');\n }\n\n const isPasswordValid = await verifyPassword(password, foundUser.password);\n if (!isPasswordValid) {\n throw new Error('邮箱或密码错误');\n }\n\n // 生成 JWT token\n const token = generateToken(\n {\n userId: foundUser.id,\n email: foundUser.email,\n role: foundUser.role as UserRole,\n },\n this.config.jwtSecret,\n this.config.jwtExpiresIn\n );\n\n // 创建会话\n await this.createSession(foundUser.id, token);\n\n return {\n user: {\n id: foundUser.id,\n email: foundUser.email,\n username: foundUser.username,\n role: foundUser.role as UserRole,\n },\n token,\n };\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * 验证 Token\n */\n async verifyToken(token: string): Promise<VerifyResult> {\n try {\n // 验证 JWT\n const decoded = verifyJwtToken(token, this.config.jwtSecret);\n\n // 检查会话是否存在且未过期\n const [foundSession] = await this.config.db\n .select()\n .from(session)\n .where(\n and(eq(session.token, token), gt(session.expiresAt, new Date().toISOString()))\n )\n .limit(1);\n\n if (!foundSession) {\n throw new Error('会话无效或已过期');\n }\n\n // 获取用户信息\n const [foundUser] = await this.config.db\n .select()\n .from(user)\n .where(eq(user.id, decoded.userId))\n .limit(1);\n\n if (!foundUser) {\n throw new Error('用户不存在');\n }\n\n return {\n user: {\n id: foundUser.id,\n email: foundUser.email,\n username: foundUser.username,\n role: foundUser.role as UserRole,\n },\n session: foundSession as SessionInfo,\n };\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * 创建会话\n */\n async createSession(\n userId: string,\n token: string,\n ipAddress?: string,\n userAgent?: string\n ): Promise<void> {\n const expiresAt = new Date();\n expiresAt.setDate(expiresAt.getDate() + 7); // 7天后过期\n\n await this.config.db.insert(session).values({\n id: randomBytes(16).toString('hex'),\n userId,\n token,\n expiresAt: expiresAt.toISOString(),\n ipAddress,\n userAgent,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n }\n\n /**\n * 删除会话(登出)\n */\n async signOut(token: string): Promise<{ success: boolean }> {\n try {\n await this.config.db.delete(session).where(eq(session.token, token));\n return { success: true };\n } catch (error) {\n throw error;\n }\n }\n\n /**\n * 获取会话\n */\n async getSession(token: string): Promise<VerifyResult | null> {\n try {\n return await this.verifyToken(token);\n } catch (error) {\n return null;\n }\n }\n\n /**\n * 检查管理员权限\n */\n async requireAdmin(token: string): Promise<VerifyResult> {\n const result = await this.verifyToken(token);\n if (!['ADMIN', 'SUPER_ADMIN'].includes(result.user.role)) {\n throw new Error('需要管理员权限');\n }\n return result;\n }\n\n /**\n * 检查超级管理员权限\n */\n async requireSuperAdmin(token: string): Promise<VerifyResult> {\n const result = await this.verifyToken(token);\n if (result.user.role !== 'SUPER_ADMIN') {\n throw new Error('需要超级管理员权限');\n }\n return result;\n }\n\n /**\n * 通过用户 ID 获取用户信息\n */\n async getUserById(userId: string): Promise<UserInfo | null> {\n try {\n const [foundUser] = await this.config.db\n .select()\n .from(user)\n .where(eq(user.id, userId))\n .limit(1);\n\n if (!foundUser) {\n return null;\n }\n\n return {\n id: foundUser.id,\n email: foundUser.email,\n username: foundUser.username,\n role: foundUser.role as UserRole,\n };\n } catch (error) {\n return null;\n }\n }\n\n /**\n * 通过邮箱获取用户信息\n */\n async getUserByEmail(email: string): Promise<UserInfo | null> {\n try {\n const [foundUser] = await this.config.db\n .select()\n .from(user)\n .where(eq(user.email, email))\n .limit(1);\n\n if (!foundUser) {\n return null;\n }\n\n return {\n id: foundUser.id,\n email: foundUser.email,\n username: foundUser.username,\n role: foundUser.role as UserRole,\n };\n } catch (error) {\n return null;\n }\n }\n}\n\n"]}
@@ -1,4 +1,4 @@
1
- import { getTokenFromRequest } from './chunk-U2L6V7KD.mjs';
1
+ import { getTokenFromRequest } from './chunk-OCR5DS4C.mjs';
2
2
 
3
3
  // src/auth/routes/login.ts
4
4
  function addCorsHeaders(response, config, request) {
@@ -556,5 +556,5 @@ function createAnalyticsAdapter(analyticsService, options) {
556
556
  }
557
557
 
558
558
  export { createAnalyticsAdapter, createDefaultBaseConfig, createDefaultLoginConfig, createDefaultRegisterConfig, createLoginHandler, createLoginOptionsHandler, createLogoutHandler, createLogoutOptionsHandler, createMeHandler, createMeOptionsHandler, createRegisterHandler, createRegisterOptionsHandler };
559
- //# sourceMappingURL=chunk-IBLB7ARJ.mjs.map
560
- //# sourceMappingURL=chunk-IBLB7ARJ.mjs.map
559
+ //# sourceMappingURL=chunk-QAT2RWAO.mjs.map
560
+ //# sourceMappingURL=chunk-QAT2RWAO.mjs.map