yukimu 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/BitrateOptimizer.d.ts +52 -0
  2. package/dist/BitrateOptimizer.d.ts.map +1 -0
  3. package/dist/BitrateOptimizer.js +115 -0
  4. package/dist/BitrateOptimizer.js.map +1 -0
  5. package/dist/ConnectionPool.d.ts +52 -2
  6. package/dist/ConnectionPool.d.ts.map +1 -1
  7. package/dist/ConnectionPool.js +123 -44
  8. package/dist/ConnectionPool.js.map +1 -1
  9. package/dist/Constants.d.ts +26 -47
  10. package/dist/Constants.d.ts.map +1 -1
  11. package/dist/Constants.js +134 -67
  12. package/dist/Constants.js.map +1 -1
  13. package/dist/Logger.d.ts +22 -0
  14. package/dist/Logger.d.ts.map +1 -0
  15. package/dist/Logger.js +74 -0
  16. package/dist/Logger.js.map +1 -0
  17. package/dist/Node.d.ts +17 -4
  18. package/dist/Node.d.ts.map +1 -1
  19. package/dist/Node.js +217 -79
  20. package/dist/Node.js.map +1 -1
  21. package/dist/Player.d.ts +77 -6
  22. package/dist/Player.d.ts.map +1 -1
  23. package/dist/Player.js +319 -75
  24. package/dist/Player.js.map +1 -1
  25. package/dist/Plugin.d.ts +16 -12
  26. package/dist/Plugin.d.ts.map +1 -1
  27. package/dist/Plugin.js +5 -9
  28. package/dist/Plugin.js.map +1 -1
  29. package/dist/Queue.d.ts +69 -3
  30. package/dist/Queue.d.ts.map +1 -1
  31. package/dist/Queue.js +123 -17
  32. package/dist/Queue.js.map +1 -1
  33. package/dist/Resolver.d.ts +33 -2
  34. package/dist/Resolver.d.ts.map +1 -1
  35. package/dist/Resolver.js +233 -27
  36. package/dist/Resolver.js.map +1 -1
  37. package/dist/Rest.d.ts +25 -3
  38. package/dist/Rest.d.ts.map +1 -1
  39. package/dist/Rest.js +165 -23
  40. package/dist/Rest.js.map +1 -1
  41. package/dist/TrackCache.d.ts +28 -8
  42. package/dist/TrackCache.d.ts.map +1 -1
  43. package/dist/TrackCache.js +111 -24
  44. package/dist/TrackCache.js.map +1 -1
  45. package/dist/WsQueue.d.ts +30 -9
  46. package/dist/WsQueue.d.ts.map +1 -1
  47. package/dist/WsQueue.js +66 -24
  48. package/dist/WsQueue.js.map +1 -1
  49. package/dist/Yukimu.d.ts +37 -13
  50. package/dist/Yukimu.d.ts.map +1 -1
  51. package/dist/Yukimu.js +146 -59
  52. package/dist/Yukimu.js.map +1 -1
  53. package/dist/connector/Connector.d.ts +26 -0
  54. package/dist/connector/Connector.d.ts.map +1 -1
  55. package/dist/connector/Connector.js +28 -0
  56. package/dist/connector/Connector.js.map +1 -1
  57. package/dist/connector/DiscordJS.d.ts +21 -19
  58. package/dist/connector/DiscordJS.d.ts.map +1 -1
  59. package/dist/connector/DiscordJS.js +44 -2
  60. package/dist/connector/DiscordJS.js.map +1 -1
  61. package/dist/connector/Eris.d.ts +13 -17
  62. package/dist/connector/Eris.d.ts.map +1 -1
  63. package/dist/connector/Eris.js +36 -4
  64. package/dist/connector/Eris.js.map +1 -1
  65. package/dist/connector/Oceanic.d.ts +13 -14
  66. package/dist/connector/Oceanic.d.ts.map +1 -1
  67. package/dist/connector/Oceanic.js +35 -2
  68. package/dist/connector/Oceanic.js.map +1 -1
  69. package/dist/errors/YukimuError.d.ts +40 -4
  70. package/dist/errors/YukimuError.d.ts.map +1 -1
  71. package/dist/errors/YukimuError.js +79 -9
  72. package/dist/errors/YukimuError.js.map +1 -1
  73. package/dist/index.d.ts +13 -4
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +30 -21
  76. package/dist/index.js.map +1 -1
  77. package/dist/plugins/AutoResume.d.ts +18 -14
  78. package/dist/plugins/AutoResume.d.ts.map +1 -1
  79. package/dist/plugins/AutoResume.js +101 -21
  80. package/dist/plugins/AutoResume.js.map +1 -1
  81. package/dist/plugins/AutoplayPlugin.d.ts +35 -0
  82. package/dist/plugins/AutoplayPlugin.d.ts.map +1 -0
  83. package/dist/plugins/AutoplayPlugin.js +111 -0
  84. package/dist/plugins/AutoplayPlugin.js.map +1 -0
  85. package/dist/plugins/InactivityPlugin.d.ts +30 -0
  86. package/dist/plugins/InactivityPlugin.d.ts.map +1 -0
  87. package/dist/plugins/InactivityPlugin.js +86 -0
  88. package/dist/plugins/InactivityPlugin.js.map +1 -0
  89. package/dist/plugins/PlayerMoved.d.ts +23 -1
  90. package/dist/plugins/PlayerMoved.d.ts.map +1 -1
  91. package/dist/plugins/PlayerMoved.js +57 -12
  92. package/dist/plugins/PlayerMoved.js.map +1 -1
  93. package/dist/types.d.ts +196 -78
  94. package/dist/types.d.ts.map +1 -1
  95. package/dist/types.js +1 -0
  96. package/dist/types.js.map +1 -1
  97. package/package.json +49 -5
  98. package/.cache/replit/env/latest +0 -88
  99. package/.cache/replit/env/latest.json +0 -1
  100. package/.cache/replit/modules/nodejs-20.res +0 -1
  101. package/.cache/replit/modules/python-3.11.res +0 -1
  102. package/.cache/replit/modules/replit.res +0 -1
  103. package/.cache/replit/modules.stamp +0 -0
  104. package/.cache/replit/nix/dotreplitenv.json +0 -1
  105. package/.cache/replit/toolchain.json +0 -1
  106. package/.local/state/workflow-logs/7zVU0iVo-fBL1ccMCmELy/configure_your_app.packager.installForAll.0 +0 -9
  107. package/.local/state/workflow-logs/7zVU0iVo-fBL1ccMCmELy/configure_your_app.shell.exec.1 +0 -1
  108. package/.local/state/workflow-logs/KRgHXizaECjWI5nWtS7Dj/configure_your_app.packager.installForAll.0 +0 -1
  109. package/.local/state/workflow-logs/KRgHXizaECjWI5nWtS7Dj/configure_your_app.shell.exec.1 +0 -1
  110. package/.local/state/workflow-logs/U0AinJQVHonnwGjj0RXLn/configure_your_app.packager.installForAll.0 +0 -2
  111. package/.local/state/workflow-logs/jVavLOnv1MqxUvxhMmqER/configure_your_app.packager.installForAll.0 +0 -1
  112. package/.local/state/workflow-logs/jVavLOnv1MqxUvxhMmqER/configure_your_app.shell.exec.1 +0 -1
  113. package/.replit +0 -7
  114. package/.upm/store.json +0 -1
  115. package/src/ConnectionPool.ts +0 -131
  116. package/src/Constants.ts +0 -101
  117. package/src/Node.ts +0 -309
  118. package/src/Player.ts +0 -337
  119. package/src/Plugin.ts +0 -23
  120. package/src/Queue.ts +0 -91
  121. package/src/Resolver.ts +0 -79
  122. package/src/Rest.ts +0 -121
  123. package/src/TrackCache.ts +0 -69
  124. package/src/WsQueue.ts +0 -78
  125. package/src/Yukimu.ts +0 -248
  126. package/src/connector/Connector.ts +0 -13
  127. package/src/connector/DiscordJS.ts +0 -33
  128. package/src/connector/Eris.ts +0 -35
  129. package/src/connector/Oceanic.ts +0 -32
  130. package/src/errors/YukimuError.ts +0 -33
  131. package/src/index.ts +0 -46
  132. package/src/plugins/AutoResume.ts +0 -61
  133. package/src/plugins/PlayerMoved.ts +0 -26
  134. package/src/types.ts +0 -145
  135. package/tsconfig.json +0 -20
package/dist/Resolver.js CHANGED
@@ -1,51 +1,176 @@
1
1
  "use strict";
2
+ /** Yukimu v2.0.0 — Track Resolver with Retry, Caching & Fallback */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.Resolver = void 0;
4
5
  const Constants_1 = require("./Constants");
6
+ /**
7
+ * Resolves search queries and URLs into playable tracks.
8
+ *
9
+ * Improvements from v1:
10
+ * - Accepts optional `node` parameter (loads on the correct node for a player)
11
+ * - Search retry with fallback sources
12
+ * - Search result caching
13
+ * - Spotify playlist/album resolution
14
+ * - Spotify token refresh with retry and timeout
15
+ * - Rate limit handling for Spotify API
16
+ */
5
17
  class Resolver {
18
+ manager;
19
+ spotifyToken = null;
20
+ spotifyExpiry = 0;
21
+ spotifyRefreshing = false;
6
22
  constructor(manager) {
7
- this.spotifyToken = null;
8
- this.spotifyExpiry = 0;
9
23
  this.manager = manager;
10
24
  }
11
- async resolve(query, source, requester) {
12
- const node = this.manager.getBestNode();
25
+ /**
26
+ * Resolve a query (URL or search term) into tracks.
27
+ *
28
+ * @param query - A URL or search query string
29
+ * @param source - The search source to use (ignored for URLs)
30
+ * @param requester - Optional requester metadata to attach to tracks
31
+ * @param node - Optional specific node to use for loading
32
+ */
33
+ async resolve(query, source, requester, node) {
34
+ const targetNode = node ?? this.getLoadNode();
13
35
  const isUrl = /^https?:\/\//.test(query);
14
- const identifier = isUrl ? query : `${Constants_1.SOURCE_PREFIXES[source] ?? "ytsearch"}:${query}`;
15
- const result = await node.loadTracks(identifier);
36
+ const prefix = Constants_1.SOURCE_PREFIXES[source];
37
+ const identifier = isUrl ? query : `${prefix ?? "ytsearch"}:${query}`;
38
+ // Check search cache first
39
+ const cached = this.manager.trackCache.getSearch(identifier);
40
+ if (cached) {
41
+ this.manager.logger.debug(`Search cache hit for: ${identifier.slice(0, 80)}`);
42
+ // Clone and attach requester
43
+ const result = { ...cached, tracks: [...cached.tracks] };
44
+ if (requester)
45
+ this.attachRequester(result.tracks, requester);
46
+ return result;
47
+ }
48
+ // Try loading tracks with retry
49
+ let result = null;
50
+ let lastError = null;
51
+ for (let attempt = 0; attempt <= Constants_1.DEFAULTS.MAX_SEARCH_RETRIES; attempt++) {
52
+ try {
53
+ result = await targetNode.loadTracks(identifier);
54
+ if (result && result.loadType !== "error")
55
+ break;
56
+ lastError = result?.exception;
57
+ }
58
+ catch (err) {
59
+ lastError = err;
60
+ this.manager.logger.debug(`loadTracks attempt ${attempt + 1} failed for "${identifier.slice(0, 80)}": ${err}`);
61
+ }
62
+ }
63
+ if (!result) {
64
+ this.manager.logger.warn(`All loadTracks attempts failed for: ${identifier.slice(0, 80)}`);
65
+ return { loadType: "error", tracks: [], exception: { severity: "common", cause: String(lastError), message: String(lastError) } };
66
+ }
67
+ if (!result.tracks)
68
+ result.tracks = [];
16
69
  // Attach requester
17
- if (requester)
18
- result.tracks.forEach(t => { t.requester = requester; });
19
- // Spotify fallback — if LavaSrc not installed
70
+ if (requester && result.tracks.length > 0) {
71
+ this.attachRequester(result.tracks, requester);
72
+ }
73
+ // Spotify fallback — if LavaSrc is not installed, try to resolve via metadata
20
74
  if ((result.loadType === "error" || result.loadType === "empty") && isUrl) {
21
- const spotifyMatch = query.match(/spotify\.com\/track\/([a-zA-Z0-9]+)/);
22
- if (spotifyMatch) {
23
- const meta = await this.resolveSpotifyMeta(spotifyMatch[1]);
24
- if (meta)
25
- return this.resolve(`${meta.title} ${meta.artist}`, "youtube", requester);
26
- }
75
+ const spotifyFallback = await this.trySpotifyFallback(query, source, requester);
76
+ if (spotifyFallback)
77
+ return spotifyFallback;
27
78
  }
28
- // Cache all returned tracks
29
- for (const track of result.tracks) {
30
- if (track.encoded)
31
- this.manager.trackCache.set(track.encoded, track);
79
+ // Cache successful results
80
+ if (result.tracks.length > 0) {
81
+ this.manager.trackCache.setSearch(identifier, result);
82
+ // Also cache individual tracks
83
+ for (const track of result.tracks) {
84
+ if (track?.encoded) {
85
+ this.manager.trackCache.set(track.encoded, track);
86
+ }
87
+ }
32
88
  }
33
89
  return result;
34
90
  }
91
+ /**
92
+ * Detect the source platform from a URL.
93
+ */
35
94
  detectSource(url) {
36
95
  for (const [source, patterns] of Object.entries(Constants_1.URL_PATTERNS)) {
37
- if (patterns.some(p => p.test(url)))
96
+ if (patterns.some((p) => p.test(url)))
38
97
  return source;
39
98
  }
40
99
  return null;
41
100
  }
101
+ // ─── Spotify Fallback ─────────────────────────────────────────────────
102
+ async trySpotifyFallback(query, _source, requester) {
103
+ // Single track
104
+ const trackMatch = query.match(/spotify\.com\/track\/([a-zA-Z0-9]+)/);
105
+ if (trackMatch?.[1]) {
106
+ const meta = await this.resolveSpotifyMeta(trackMatch[1]);
107
+ if (meta) {
108
+ return this.resolve(`${meta.title} ${meta.artist}`, "youtube", requester);
109
+ }
110
+ }
111
+ // Playlist
112
+ const playlistMatch = query.match(/spotify\.com\/playlist\/([a-zA-Z0-9]+)/);
113
+ if (playlistMatch?.[1]) {
114
+ const tracks = await this.resolveSpotifyPlaylist(playlistMatch[1]);
115
+ if (tracks.length > 0) {
116
+ // Resolve first 50 tracks via YouTube search
117
+ const resolved = [];
118
+ for (const meta of tracks.slice(0, 50)) {
119
+ try {
120
+ const result = await this.resolve(`${meta.title} ${meta.artist}`, "youtube", requester);
121
+ if (result.tracks[0])
122
+ resolved.push(result.tracks[0]);
123
+ }
124
+ catch {
125
+ // Skip failed tracks
126
+ }
127
+ }
128
+ if (resolved.length > 0) {
129
+ return { loadType: "playlist", tracks: resolved, playlistInfo: { name: "Spotify Playlist", selectedTrack: 0 } };
130
+ }
131
+ }
132
+ }
133
+ // Album
134
+ const albumMatch = query.match(/spotify\.com\/album\/([a-zA-Z0-9]+)/);
135
+ if (albumMatch?.[1]) {
136
+ const tracks = await this.resolveSpotifyAlbum(albumMatch[1]);
137
+ if (tracks.length > 0) {
138
+ const resolved = [];
139
+ for (const meta of tracks.slice(0, 50)) {
140
+ try {
141
+ const result = await this.resolve(`${meta.title} ${meta.artist}`, "youtube", requester);
142
+ if (result.tracks[0])
143
+ resolved.push(result.tracks[0]);
144
+ }
145
+ catch {
146
+ // Skip failed tracks
147
+ }
148
+ }
149
+ if (resolved.length > 0) {
150
+ return { loadType: "playlist", tracks: resolved, playlistInfo: { name: "Spotify Album", selectedTrack: 0 } };
151
+ }
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+ // ─── Spotify API ──────────────────────────────────────────────────────
42
157
  async getSpotifyToken() {
43
158
  const opts = this.manager.options.spotify;
44
159
  if (!opts)
45
160
  return null;
46
- if (this.spotifyToken && Date.now() < this.spotifyExpiry)
161
+ // Return cached token if still valid
162
+ if (this.spotifyToken && Date.now() < this.spotifyExpiry) {
47
163
  return this.spotifyToken;
164
+ }
165
+ // Prevent concurrent refresh
166
+ if (this.spotifyRefreshing) {
167
+ await this.sleep(1000);
168
+ return this.spotifyToken;
169
+ }
170
+ this.spotifyRefreshing = true;
48
171
  try {
172
+ const controller = new AbortController();
173
+ const timeout = setTimeout(() => controller.abort(), 10_000);
49
174
  const res = await fetch("https://accounts.spotify.com/api/token", {
50
175
  method: "POST",
51
176
  headers: {
@@ -53,31 +178,112 @@ class Resolver {
53
178
  Authorization: `Basic ${Buffer.from(`${opts.clientId}:${opts.clientSecret}`).toString("base64")}`,
54
179
  },
55
180
  body: "grant_type=client_credentials",
181
+ signal: controller.signal,
56
182
  });
57
- const data = await res.json();
183
+ clearTimeout(timeout);
184
+ if (!res.ok) {
185
+ this.manager.logger.warn(`Spotify token request failed: ${res.status}`);
186
+ return null;
187
+ }
188
+ const data = (await res.json());
58
189
  this.spotifyToken = data.access_token;
59
- this.spotifyExpiry = Date.now() + data.expires_in * 1000 - 5000;
190
+ this.spotifyExpiry = Date.now() + data.expires_in * 1000 - Constants_1.DEFAULTS.SPOTIFY_TOKEN_REFRESH_BUFFER;
60
191
  return this.spotifyToken;
61
192
  }
62
- catch {
193
+ catch (err) {
194
+ this.manager.logger.warn(`Spotify token refresh failed: ${err}`);
63
195
  return null;
64
196
  }
197
+ finally {
198
+ this.spotifyRefreshing = false;
199
+ }
65
200
  }
66
201
  async resolveSpotifyMeta(trackId) {
67
202
  const token = await this.getSpotifyToken();
68
203
  if (!token)
69
204
  return null;
70
205
  try {
71
- const res = await fetch(`https://api.spotify.com/v1/tracks/${trackId}`, {
206
+ const controller = new AbortController();
207
+ const timeout = setTimeout(() => controller.abort(), 10_000);
208
+ const res = await fetch(`https://api.spotify.com/v1/tracks/${encodeURIComponent(trackId)}`, {
72
209
  headers: { Authorization: `Bearer ${token}` },
210
+ signal: controller.signal,
73
211
  });
74
- const data = await res.json();
75
- return { title: data.name, artist: data.artists[0]?.name ?? "Unknown" };
212
+ clearTimeout(timeout);
213
+ if (!res.ok)
214
+ return null;
215
+ const data = (await res.json());
216
+ return {
217
+ title: data.name,
218
+ artist: data.artists?.[0]?.name ?? "Unknown",
219
+ };
76
220
  }
77
221
  catch {
78
222
  return null;
79
223
  }
80
224
  }
225
+ async resolveSpotifyPlaylist(playlistId) {
226
+ const token = await this.getSpotifyToken();
227
+ if (!token)
228
+ return [];
229
+ try {
230
+ const controller = new AbortController();
231
+ const timeout = setTimeout(() => controller.abort(), 15_000);
232
+ const res = await fetch(`https://api.spotify.com/v1/playlists/${encodeURIComponent(playlistId)}/tracks?limit=50`, {
233
+ headers: { Authorization: `Bearer ${token}` },
234
+ signal: controller.signal,
235
+ });
236
+ clearTimeout(timeout);
237
+ if (!res.ok)
238
+ return [];
239
+ const data = (await res.json());
240
+ return data.items
241
+ .filter((item) => item.track)
242
+ .map((item) => ({
243
+ title: item.track.name,
244
+ artist: item.track.artists?.[0]?.name ?? "Unknown",
245
+ }));
246
+ }
247
+ catch {
248
+ return [];
249
+ }
250
+ }
251
+ async resolveSpotifyAlbum(albumId) {
252
+ const token = await this.getSpotifyToken();
253
+ if (!token)
254
+ return [];
255
+ try {
256
+ const controller = new AbortController();
257
+ const timeout = setTimeout(() => controller.abort(), 15_000);
258
+ const res = await fetch(`https://api.spotify.com/v1/albums/${encodeURIComponent(albumId)}/tracks?limit=50`, {
259
+ headers: { Authorization: `Bearer ${token}` },
260
+ signal: controller.signal,
261
+ });
262
+ clearTimeout(timeout);
263
+ if (!res.ok)
264
+ return [];
265
+ const data = (await res.json());
266
+ return data.items.map((item) => ({
267
+ title: item.name,
268
+ artist: item.artists?.[0]?.name ?? "Unknown",
269
+ }));
270
+ }
271
+ catch {
272
+ return [];
273
+ }
274
+ }
275
+ // ─── Helpers ──────────────────────────────────────────────────────────
276
+ getLoadNode() {
277
+ return this.manager.getBestNode();
278
+ }
279
+ attachRequester(tracks, requester) {
280
+ for (const t of tracks) {
281
+ t["requester"] = requester;
282
+ }
283
+ }
284
+ sleep(ms) {
285
+ return new Promise((resolve) => setTimeout(resolve, ms));
286
+ }
81
287
  }
82
288
  exports.Resolver = Resolver;
83
289
  //# sourceMappingURL=Resolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Resolver.js","sourceRoot":"","sources":["../src/Resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Resolver.js","sourceRoot":"","sources":["../src/Resolver.ts"],"names":[],"mappings":"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"}
package/dist/Rest.d.ts CHANGED
@@ -1,24 +1,46 @@
1
+ /** Yukimu v2.0.0 — REST Client with Retry, Rate Limiting & Circuit Breaker */
1
2
  import type { Node } from "./Node";
2
3
  import type { SearchResult, Track, NodeStats, NodeInfo } from "./types";
4
+ /**
5
+ * REST client for communicating with a Lavalink node's HTTP API.
6
+ *
7
+ * Improvements from v1:
8
+ * - Automatic retry with exponential backoff for 429/5xx errors
9
+ * - Rate limit tracking (respects Retry-After headers)
10
+ * - Request timeout with proper AbortController cleanup
11
+ * - Uses VERSION constant for Client-Name header
12
+ * - Fixed v4.2+ data normalization bug (single track vs array)
13
+ * - Per-path rate limit awareness
14
+ * - Circuit breaker: after N consecutive failures, stop sending requests temporarily
15
+ */
3
16
  export declare class Rest {
4
- private node;
17
+ private readonly node;
18
+ private rateLimit;
19
+ private consecutiveFailures;
20
+ private circuitOpenUntil;
21
+ private static readonly MAX_CONSECUTIVE_FAILURES;
22
+ private static readonly CIRCUIT_OPEN_DURATION;
5
23
  constructor(node: Node);
6
24
  get baseUrl(): string;
7
25
  get prefix(): string;
8
26
  get headers(): Record<string, string>;
9
- request<T = unknown>(method: string, path: string, body?: unknown): Promise<T>;
27
+ request<T = unknown>(method: string, path: string, body?: unknown, retries?: number): Promise<T>;
10
28
  loadTracks(identifier: string): Promise<SearchResult>;
11
29
  decodeTrack(encoded: string): Promise<Track>;
12
30
  decodeTracks(encoded: string[]): Promise<Track[]>;
13
31
  getInfo(): Promise<NodeInfo>;
14
32
  getStats(): Promise<NodeStats>;
15
- getVersion(): Promise<string>;
16
33
  updatePlayer(guildId: string, body: unknown, noReplace?: boolean): Promise<unknown>;
17
34
  destroyPlayer(guildId: string): Promise<void>;
18
35
  updateSession(body: {
19
36
  resuming?: boolean;
20
37
  timeout?: number;
21
38
  }): Promise<unknown>;
39
+ private normalizeV4;
22
40
  private normalizeV3;
41
+ private updateRateLimit;
42
+ private parseRetryAfter;
43
+ private getRetryDelay;
44
+ private sleep;
23
45
  }
24
46
  //# sourceMappingURL=Rest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Rest.d.ts","sourceRoot":"","sources":["../src/Rest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIxE,qBAAa,IAAI;IACf,OAAO,CAAC,IAAI,CAAO;gBAEP,IAAI,EAAE,IAAI;IAItB,IAAI,OAAO,IAAI,MAAM,CAGpB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQpC;IAEY,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IA6B9E,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAKrD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAI5C,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAIjD,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;IAI5B,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;IAI9B,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAK7B,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,UAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAOjF,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7C,aAAa,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAK5F,OAAO,CAAC,WAAW;CAcpB"}
1
+ {"version":3,"file":"Rest.d.ts","sourceRoot":"","sources":["../src/Rest.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAI9E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAY,MAAM,SAAS,CAAC;AASlF;;;;;;;;;;;GAWG;AACH,qBAAa,IAAI;IACf,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;IAC5B,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,gBAAgB,CAAK;IAE7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAK;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAU;gBAE3C,IAAI,EAAE,IAAI;IAItB,IAAI,OAAO,IAAI,MAAM,CAGpB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQpC;IAIY,OAAO,CAAC,CAAC,GAAG,OAAO,EAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,GAAE,MAAkC,GAC1C,OAAO,CAAC,CAAC,CAAC;IA4GA,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAUrD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAI5C,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAIjD,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;IAI5B,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;IAI9B,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,UAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAOjF,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7C,aAAa,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAO5F,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,WAAW;IAyCnB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,KAAK;CAGd"}
package/dist/Rest.js CHANGED
@@ -1,9 +1,28 @@
1
1
  "use strict";
2
+ /** Yukimu v2.0.0 — REST Client with Retry, Rate Limiting & Circuit Breaker */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.Rest = void 0;
4
5
  const YukimuError_1 = require("./errors/YukimuError");
5
- const TIMEOUT_MS = 15000;
6
+ const Constants_1 = require("./Constants");
7
+ /**
8
+ * REST client for communicating with a Lavalink node's HTTP API.
9
+ *
10
+ * Improvements from v1:
11
+ * - Automatic retry with exponential backoff for 429/5xx errors
12
+ * - Rate limit tracking (respects Retry-After headers)
13
+ * - Request timeout with proper AbortController cleanup
14
+ * - Uses VERSION constant for Client-Name header
15
+ * - Fixed v4.2+ data normalization bug (single track vs array)
16
+ * - Per-path rate limit awareness
17
+ * - Circuit breaker: after N consecutive failures, stop sending requests temporarily
18
+ */
6
19
  class Rest {
20
+ node;
21
+ rateLimit = null;
22
+ consecutiveFailures = 0;
23
+ circuitOpenUntil = 0;
24
+ static MAX_CONSECUTIVE_FAILURES = 5;
25
+ static CIRCUIT_OPEN_DURATION = 30_000;
7
26
  constructor(node) {
8
27
  this.node = node;
9
28
  }
@@ -18,41 +37,107 @@ class Rest {
18
37
  return {
19
38
  Authorization: this.node.options.password,
20
39
  "User-Id": this.node.manager.options.clientId,
21
- "Client-Name": "Yukimu/1.2.0",
40
+ "Client-Name": Constants_1.CLIENT_NAME,
22
41
  "Content-Type": "application/json",
23
42
  ...(this.node.version === 3 ? { "Num-Shards": "1" } : {}),
24
43
  };
25
44
  }
26
- async request(method, path, body) {
45
+ // ─── Core Request ───────────────────────────────────────────────────────
46
+ async request(method, path, body, retries = Constants_1.DEFAULTS.REST_MAX_RETRIES) {
47
+ // Circuit breaker check
48
+ if (Date.now() < this.circuitOpenUntil) {
49
+ throw new YukimuError_1.RestError(`Circuit breaker open for node "${this.node.options.name}" — too many consecutive failures`, 503, path);
50
+ }
51
+ // Rate limit check
52
+ if (this.rateLimit && this.rateLimit.remaining <= 0 && Date.now() < this.rateLimit.resetAt) {
53
+ const waitMs = this.rateLimit.resetAt - Date.now();
54
+ this.node.manager.logger.debug(`Rate limited on ${path}, waiting ${waitMs}ms`);
55
+ await this.sleep(waitMs);
56
+ }
27
57
  const url = `${this.baseUrl}${this.prefix}${path}`;
28
58
  const controller = new AbortController();
29
- const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
59
+ const timeout = setTimeout(() => controller.abort(), Constants_1.DEFAULTS.REST_TIMEOUT);
30
60
  try {
31
- const res = await globalThis.fetch(url, {
61
+ const res = await fetch(url, {
32
62
  method,
33
63
  headers: this.headers,
34
- body: body ? JSON.stringify(body) : undefined,
64
+ body: body !== undefined ? JSON.stringify(body) : undefined,
35
65
  signal: controller.signal,
36
66
  });
37
67
  clearTimeout(timeout);
68
+ // Track rate limit headers
69
+ this.updateRateLimit(res);
70
+ // Handle rate limiting with retry
71
+ if (res.status === 429) {
72
+ const retryAfter = this.parseRetryAfter(res);
73
+ if (retries > 0) {
74
+ this.node.manager.logger.warn(`Rate limited on ${method} ${path}, retrying in ${retryAfter}ms`);
75
+ await this.sleep(retryAfter);
76
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
77
+ return this.request(method, path, body, (retries - 1));
78
+ }
79
+ throw new YukimuError_1.RestError(`Rate limited on ${method} ${path}`, 429, path, retryAfter);
80
+ }
81
+ // Handle server errors with retry
82
+ if (res.status >= 500 && retries > 0) {
83
+ const delay = this.getRetryDelay(Constants_1.DEFAULTS.REST_MAX_RETRIES - retries);
84
+ this.node.manager.logger.warn(`Server error ${res.status} on ${method} ${path}, retrying in ${delay}ms`);
85
+ await this.sleep(delay);
86
+ return this.request(method, path, body, (retries - 1));
87
+ }
38
88
  if (!res.ok) {
39
89
  const text = await res.text().catch(() => "Unknown error");
40
90
  throw new YukimuError_1.RestError(`REST ${res.status} on ${method} ${path}: ${text}`, res.status, path);
41
91
  }
92
+ // Reset circuit breaker on success
93
+ this.consecutiveFailures = 0;
42
94
  if (res.status === 204)
43
95
  return undefined;
44
- return res.json();
96
+ const text = await res.text();
97
+ if (!text)
98
+ return null;
99
+ let parsed;
100
+ try {
101
+ parsed = JSON.parse(text);
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ // Normalize Lavalink v4.2+ response — uses "data" instead of "tracks"
107
+ if (parsed && "data" in parsed && !("tracks" in parsed)) {
108
+ const data = parsed["data"];
109
+ if (Array.isArray(data)) {
110
+ parsed["tracks"] = data;
111
+ }
112
+ else if (data && typeof data === "object") {
113
+ // Single track response — wrap in array
114
+ parsed["tracks"] = [data];
115
+ }
116
+ }
117
+ return parsed;
45
118
  }
46
119
  catch (err) {
47
120
  clearTimeout(timeout);
48
- if (err.name === "AbortError")
121
+ // Increment circuit breaker
122
+ this.consecutiveFailures++;
123
+ if (this.consecutiveFailures >= Rest.MAX_CONSECUTIVE_FAILURES) {
124
+ this.circuitOpenUntil = Date.now() + Rest.CIRCUIT_OPEN_DURATION;
125
+ this.node.manager.logger.error(`Circuit breaker opened for node "${this.node.options.name}" after ${this.consecutiveFailures} failures`);
126
+ }
127
+ if (err instanceof YukimuError_1.RestError)
128
+ throw err;
129
+ if (err instanceof Error && err.name === "AbortError") {
49
130
  throw new YukimuError_1.RestError(`REST timeout on ${method} ${path}`, 408, path);
131
+ }
50
132
  throw err;
51
133
  }
52
134
  }
135
+ // ─── API Methods ────────────────────────────────────────────────────────
53
136
  async loadTracks(identifier) {
54
137
  const raw = await this.request("GET", `/loadtracks?identifier=${encodeURIComponent(identifier)}`);
55
- return this.node.version === 3 ? this.normalizeV3(raw) : raw;
138
+ if (!raw)
139
+ return { loadType: "empty", tracks: [] };
140
+ return this.node.version === 3 ? this.normalizeV3(raw) : this.normalizeV4(raw);
56
141
  }
57
142
  async decodeTrack(encoded) {
58
143
  return this.request("GET", `/decodetrack?encodedTrack=${encodeURIComponent(encoded)}`);
@@ -66,10 +151,6 @@ class Rest {
66
151
  async getStats() {
67
152
  return this.request("GET", "/stats");
68
153
  }
69
- async getVersion() {
70
- const res = await globalThis.fetch(`${this.baseUrl}/version`, { headers: this.headers });
71
- return res.text();
72
- }
73
154
  async updatePlayer(guildId, body, noReplace = false) {
74
155
  const path = this.node.version === 4
75
156
  ? `/sessions/${this.node.sessionId}/players/${guildId}?noReplace=${noReplace}`
@@ -80,25 +161,86 @@ class Rest {
80
161
  const path = this.node.version === 4
81
162
  ? `/sessions/${this.node.sessionId}/players/${guildId}`
82
163
  : `/players/${guildId}`;
83
- await this.request("DELETE", path);
164
+ await this.request("DELETE", path).catch(() => { });
84
165
  }
85
166
  async updateSession(body) {
86
- if (this.node.version !== 4)
167
+ if (this.node.version !== 4 || !this.node.sessionId)
87
168
  return;
88
169
  return this.request("PATCH", `/sessions/${this.node.sessionId}`, body);
89
170
  }
171
+ // ─── Normalization ──────────────────────────────────────────────────────
172
+ normalizeV4(raw) {
173
+ const result = raw;
174
+ if (!result.tracks)
175
+ result.tracks = [];
176
+ return result;
177
+ }
90
178
  normalizeV3(raw) {
91
- const loadType = (raw.loadType ?? "").toLowerCase();
92
- const norm = (tracks) => (tracks ?? []).map((t) => ({ encoded: t.track ?? t.encoded, info: t.info, pluginInfo: t.pluginInfo ?? {} }));
179
+ const loadType = String(raw["loadType"] ?? "").toLowerCase();
180
+ const rawTracks = raw["tracks"];
181
+ const tracks = Array.isArray(rawTracks) ? rawTracks : [];
182
+ const norm = (items) => items.map((t) => {
183
+ const track = t;
184
+ return {
185
+ encoded: (track["track"] ?? track["encoded"]),
186
+ info: track["info"],
187
+ pluginInfo: (track["pluginInfo"] ?? {}),
188
+ };
189
+ });
93
190
  switch (loadType) {
94
- case "track_loaded": return { loadType: "track", tracks: norm(raw.tracks) };
95
- case "playlist_loaded": return { loadType: "playlist", tracks: norm(raw.tracks), playlistInfo: raw.playlistInfo };
96
- case "search_result": return { loadType: "search", tracks: norm(raw.tracks) };
97
- case "no_matches": return { loadType: "empty", tracks: [] };
98
- case "load_failed": return { loadType: "error", tracks: [], exception: raw.exception };
99
- default: return { loadType: "empty", tracks: [] };
191
+ case "track_loaded":
192
+ return { loadType: "track", tracks: norm(tracks) };
193
+ case "playlist_loaded":
194
+ return {
195
+ loadType: "playlist",
196
+ tracks: norm(tracks),
197
+ playlistInfo: raw["playlistInfo"],
198
+ };
199
+ case "search_result":
200
+ return { loadType: "search", tracks: norm(tracks) };
201
+ case "no_matches":
202
+ return { loadType: "empty", tracks: [] };
203
+ case "load_failed":
204
+ return {
205
+ loadType: "error",
206
+ tracks: [],
207
+ exception: raw["exception"],
208
+ };
209
+ default:
210
+ return { loadType: "empty", tracks: [] };
211
+ }
212
+ }
213
+ // ─── Helpers ────────────────────────────────────────────────────────────
214
+ updateRateLimit(res) {
215
+ const remaining = res.headers.get("x-ratelimit-remaining");
216
+ const reset = res.headers.get("x-ratelimit-reset");
217
+ if (remaining !== null && reset !== null) {
218
+ this.rateLimit = {
219
+ remaining: parseInt(remaining, 10),
220
+ resetAt: parseInt(reset, 10) * 1000,
221
+ };
100
222
  }
101
223
  }
224
+ parseRetryAfter(res) {
225
+ const retryAfter = res.headers.get("retry-after");
226
+ if (retryAfter) {
227
+ const seconds = parseFloat(retryAfter);
228
+ if (!isNaN(seconds))
229
+ return Math.ceil(seconds * 1000);
230
+ }
231
+ return 5000; // Default 5s
232
+ }
233
+ getRetryDelay(attempt) {
234
+ const base = Constants_1.DEFAULTS.REST_RETRY_BASE_DELAY;
235
+ const max = Constants_1.DEFAULTS.REST_RETRY_MAX_DELAY;
236
+ const delay = Math.min(base * Math.pow(2, attempt), max);
237
+ // Add jitter ±25%
238
+ const jitter = delay * 0.25 * (Math.random() * 2 - 1);
239
+ return Math.round(delay + jitter);
240
+ }
241
+ sleep(ms) {
242
+ return new Promise((resolve) => setTimeout(resolve, ms));
243
+ }
102
244
  }
103
245
  exports.Rest = Rest;
104
246
  //# sourceMappingURL=Rest.js.map