yukimu 1.3.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.
- package/dist/BitrateOptimizer.d.ts +52 -0
- package/dist/BitrateOptimizer.d.ts.map +1 -0
- package/dist/BitrateOptimizer.js +115 -0
- package/dist/BitrateOptimizer.js.map +1 -0
- package/dist/ConnectionPool.d.ts +52 -3
- package/dist/ConnectionPool.d.ts.map +1 -1
- package/dist/ConnectionPool.js +124 -32
- package/dist/ConnectionPool.js.map +1 -1
- package/dist/Constants.d.ts +27 -2
- package/dist/Constants.d.ts.map +1 -1
- package/dist/Constants.js +133 -11
- package/dist/Constants.js.map +1 -1
- package/dist/Logger.d.ts +22 -0
- package/dist/Logger.d.ts.map +1 -0
- package/dist/Logger.js +74 -0
- package/dist/Logger.js.map +1 -0
- package/dist/Node.d.ts +17 -4
- package/dist/Node.d.ts.map +1 -1
- package/dist/Node.js +226 -88
- package/dist/Node.js.map +1 -1
- package/dist/Player.d.ts +74 -7
- package/dist/Player.d.ts.map +1 -1
- package/dist/Player.js +317 -92
- package/dist/Player.js.map +1 -1
- package/dist/Plugin.d.ts +19 -1
- package/dist/Plugin.d.ts.map +1 -1
- package/dist/Plugin.js +8 -0
- package/dist/Plugin.js.map +1 -1
- package/dist/Queue.d.ts +69 -2
- package/dist/Queue.d.ts.map +1 -1
- package/dist/Queue.js +138 -17
- package/dist/Queue.js.map +1 -1
- package/dist/Resolver.d.ts +33 -2
- package/dist/Resolver.d.ts.map +1 -1
- package/dist/Resolver.js +225 -33
- package/dist/Resolver.js.map +1 -1
- package/dist/Rest.d.ts +27 -4
- package/dist/Rest.d.ts.map +1 -1
- package/dist/Rest.js +157 -25
- package/dist/Rest.js.map +1 -1
- package/dist/TrackCache.d.ts +30 -5
- package/dist/TrackCache.d.ts.map +1 -1
- package/dist/TrackCache.js +119 -15
- package/dist/TrackCache.js.map +1 -1
- package/dist/WsQueue.d.ts +31 -1
- package/dist/WsQueue.d.ts.map +1 -1
- package/dist/WsQueue.js +70 -12
- package/dist/WsQueue.js.map +1 -1
- package/dist/Yukimu.d.ts +38 -5
- package/dist/Yukimu.d.ts.map +1 -1
- package/dist/Yukimu.js +150 -57
- package/dist/Yukimu.js.map +1 -1
- package/dist/connector/Connector.d.ts +26 -0
- package/dist/connector/Connector.d.ts.map +1 -1
- package/dist/connector/Connector.js +28 -0
- package/dist/connector/Connector.js.map +1 -1
- package/dist/connector/DiscordJS.d.ts +20 -1
- package/dist/connector/DiscordJS.d.ts.map +1 -1
- package/dist/connector/DiscordJS.js +44 -2
- package/dist/connector/DiscordJS.js.map +1 -1
- package/dist/connector/Eris.d.ts +12 -1
- package/dist/connector/Eris.d.ts.map +1 -1
- package/dist/connector/Eris.js +40 -6
- package/dist/connector/Eris.js.map +1 -1
- package/dist/connector/Oceanic.d.ts +12 -1
- package/dist/connector/Oceanic.d.ts.map +1 -1
- package/dist/connector/Oceanic.js +39 -4
- package/dist/connector/Oceanic.js.map +1 -1
- package/dist/errors/YukimuError.d.ts +40 -4
- package/dist/errors/YukimuError.d.ts.map +1 -1
- package/dist/errors/YukimuError.js +79 -8
- package/dist/errors/YukimuError.js.map +1 -1
- package/dist/index.d.ts +13 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -16
- package/dist/index.js.map +1 -1
- package/dist/plugins/AutoResume.d.ts +18 -1
- package/dist/plugins/AutoResume.d.ts.map +1 -1
- package/dist/plugins/AutoResume.js +109 -21
- package/dist/plugins/AutoResume.js.map +1 -1
- package/dist/plugins/AutoplayPlugin.d.ts +35 -0
- package/dist/plugins/AutoplayPlugin.d.ts.map +1 -0
- package/dist/plugins/AutoplayPlugin.js +111 -0
- package/dist/plugins/AutoplayPlugin.js.map +1 -0
- package/dist/plugins/InactivityPlugin.d.ts +30 -0
- package/dist/plugins/InactivityPlugin.d.ts.map +1 -0
- package/dist/plugins/InactivityPlugin.js +86 -0
- package/dist/plugins/InactivityPlugin.js.map +1 -0
- package/dist/plugins/PlayerMoved.d.ts +23 -1
- package/dist/plugins/PlayerMoved.d.ts.map +1 -1
- package/dist/plugins/PlayerMoved.js +57 -12
- package/dist/plugins/PlayerMoved.js.map +1 -1
- package/dist/types.d.ts +198 -71
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +49 -5
- package/.cache/replit/env/latest +0 -88
- package/.cache/replit/env/latest.json +0 -1
- package/.cache/replit/modules/nodejs-20.res +0 -1
- package/.cache/replit/modules/python-3.11.res +0 -1
- package/.cache/replit/modules/replit.res +0 -1
- package/.cache/replit/modules.stamp +0 -0
- package/.cache/replit/nix/dotreplitenv.json +0 -1
- package/.cache/replit/toolchain.json +0 -1
- package/.local/state/workflow-logs/7zVU0iVo-fBL1ccMCmELy/configure_your_app.packager.installForAll.0 +0 -9
- package/.local/state/workflow-logs/7zVU0iVo-fBL1ccMCmELy/configure_your_app.shell.exec.1 +0 -1
- package/.local/state/workflow-logs/KRgHXizaECjWI5nWtS7Dj/configure_your_app.packager.installForAll.0 +0 -1
- package/.local/state/workflow-logs/KRgHXizaECjWI5nWtS7Dj/configure_your_app.shell.exec.1 +0 -1
- package/.local/state/workflow-logs/U0AinJQVHonnwGjj0RXLn/configure_your_app.packager.installForAll.0 +0 -2
- package/.local/state/workflow-logs/jVavLOnv1MqxUvxhMmqER/configure_your_app.packager.installForAll.0 +0 -1
- package/.local/state/workflow-logs/jVavLOnv1MqxUvxhMmqER/configure_your_app.shell.exec.1 +0 -1
- package/.replit +0 -7
- package/.upm/store.json +0 -1
- package/src/ConnectionPool.ts +0 -114
- package/src/Constants.ts +0 -45
- package/src/Node.ts +0 -302
- package/src/Player.ts +0 -332
- package/src/Plugin.ts +0 -7
- package/src/Queue.ts +0 -66
- package/src/Resolver.ts +0 -90
- package/src/Rest.ts +0 -127
- package/src/TrackCache.ts +0 -46
- package/src/WsQueue.ts +0 -58
- package/src/Yukimu.ts +0 -213
- package/src/connector/Connector.ts +0 -13
- package/src/connector/DiscordJS.ts +0 -26
- package/src/connector/Eris.ts +0 -24
- package/src/connector/Oceanic.ts +0 -22
- package/src/errors/YukimuError.ts +0 -31
- package/src/index.ts +0 -24
- package/src/plugins/AutoResume.ts +0 -37
- package/src/plugins/PlayerMoved.ts +0 -26
- package/src/types.ts +0 -145
- package/tsconfig.json +0 -22
package/dist/Rest.js
CHANGED
|
@@ -1,43 +1,101 @@
|
|
|
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
|
|
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 {
|
|
7
|
-
|
|
20
|
+
node;
|
|
21
|
+
rateLimit = null;
|
|
22
|
+
consecutiveFailures = 0;
|
|
23
|
+
circuitOpenUntil = 0;
|
|
24
|
+
static MAX_CONSECUTIVE_FAILURES = 5;
|
|
25
|
+
static CIRCUIT_OPEN_DURATION = 30_000;
|
|
26
|
+
constructor(node) {
|
|
27
|
+
this.node = node;
|
|
28
|
+
}
|
|
8
29
|
get baseUrl() {
|
|
9
30
|
const protocol = this.node.options.secure ? "https" : "http";
|
|
10
31
|
return `${protocol}://${this.node.options.host}:${this.node.options.port}`;
|
|
11
32
|
}
|
|
12
|
-
get prefix() {
|
|
33
|
+
get prefix() {
|
|
34
|
+
return this.node.version === 4 ? "/v4" : "";
|
|
35
|
+
}
|
|
13
36
|
get headers() {
|
|
14
37
|
return {
|
|
15
38
|
Authorization: this.node.options.password,
|
|
16
39
|
"User-Id": this.node.manager.options.clientId,
|
|
17
|
-
"Client-Name":
|
|
40
|
+
"Client-Name": Constants_1.CLIENT_NAME,
|
|
18
41
|
"Content-Type": "application/json",
|
|
19
42
|
...(this.node.version === 3 ? { "Num-Shards": "1" } : {}),
|
|
20
43
|
};
|
|
21
44
|
}
|
|
22
|
-
|
|
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
|
+
}
|
|
23
57
|
const url = `${this.baseUrl}${this.prefix}${path}`;
|
|
24
58
|
const controller = new AbortController();
|
|
25
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
59
|
+
const timeout = setTimeout(() => controller.abort(), Constants_1.DEFAULTS.REST_TIMEOUT);
|
|
26
60
|
try {
|
|
27
|
-
const res = await
|
|
61
|
+
const res = await fetch(url, {
|
|
28
62
|
method,
|
|
29
63
|
headers: this.headers,
|
|
30
|
-
body: body ? JSON.stringify(body) : undefined,
|
|
64
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
31
65
|
signal: controller.signal,
|
|
32
66
|
});
|
|
33
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
|
+
}
|
|
34
88
|
if (!res.ok) {
|
|
35
89
|
const text = await res.text().catch(() => "Unknown error");
|
|
36
90
|
throw new YukimuError_1.RestError(`REST ${res.status} on ${method} ${path}: ${text}`, res.status, path);
|
|
37
91
|
}
|
|
92
|
+
// Reset circuit breaker on success
|
|
93
|
+
this.consecutiveFailures = 0;
|
|
38
94
|
if (res.status === 204)
|
|
39
95
|
return undefined;
|
|
40
96
|
const text = await res.text();
|
|
97
|
+
if (!text)
|
|
98
|
+
return null;
|
|
41
99
|
let parsed;
|
|
42
100
|
try {
|
|
43
101
|
parsed = JSON.parse(text);
|
|
@@ -46,23 +104,40 @@ class Rest {
|
|
|
46
104
|
return null;
|
|
47
105
|
}
|
|
48
106
|
// Normalize Lavalink v4.2+ response — uses "data" instead of "tracks"
|
|
49
|
-
if (parsed &&
|
|
50
|
-
|
|
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
|
+
}
|
|
51
116
|
}
|
|
52
117
|
return parsed;
|
|
53
118
|
}
|
|
54
119
|
catch (err) {
|
|
55
120
|
clearTimeout(timeout);
|
|
56
|
-
|
|
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") {
|
|
57
130
|
throw new YukimuError_1.RestError(`REST timeout on ${method} ${path}`, 408, path);
|
|
131
|
+
}
|
|
58
132
|
throw err;
|
|
59
133
|
}
|
|
60
134
|
}
|
|
135
|
+
// ─── API Methods ────────────────────────────────────────────────────────
|
|
61
136
|
async loadTracks(identifier) {
|
|
62
137
|
const raw = await this.request("GET", `/loadtracks?identifier=${encodeURIComponent(identifier)}`);
|
|
63
138
|
if (!raw)
|
|
64
139
|
return { loadType: "empty", tracks: [] };
|
|
65
|
-
return this.node.version === 3 ? this.normalizeV3(raw) : raw;
|
|
140
|
+
return this.node.version === 3 ? this.normalizeV3(raw) : this.normalizeV4(raw);
|
|
66
141
|
}
|
|
67
142
|
async decodeTrack(encoded) {
|
|
68
143
|
return this.request("GET", `/decodetrack?encodedTrack=${encodeURIComponent(encoded)}`);
|
|
@@ -89,26 +164,83 @@ class Rest {
|
|
|
89
164
|
await this.request("DELETE", path).catch(() => { });
|
|
90
165
|
}
|
|
91
166
|
async updateSession(body) {
|
|
92
|
-
if (this.node.version !== 4)
|
|
167
|
+
if (this.node.version !== 4 || !this.node.sessionId)
|
|
93
168
|
return;
|
|
94
169
|
return this.request("PATCH", `/sessions/${this.node.sessionId}`, body);
|
|
95
170
|
}
|
|
171
|
+
// ─── Normalization ──────────────────────────────────────────────────────
|
|
172
|
+
normalizeV4(raw) {
|
|
173
|
+
const result = raw;
|
|
174
|
+
if (!result.tracks)
|
|
175
|
+
result.tracks = [];
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
96
178
|
normalizeV3(raw) {
|
|
97
|
-
const loadType = (raw
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
+
});
|
|
103
190
|
switch (loadType) {
|
|
104
|
-
case "track_loaded":
|
|
105
|
-
|
|
106
|
-
case "
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
+
};
|
|
110
222
|
}
|
|
111
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
|
+
}
|
|
112
244
|
}
|
|
113
245
|
exports.Rest = Rest;
|
|
114
246
|
//# sourceMappingURL=Rest.js.map
|
package/dist/Rest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Rest.js","sourceRoot":"","sources":["../src/Rest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Rest.js","sourceRoot":"","sources":["../src/Rest.ts"],"names":[],"mappings":"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"}
|
package/dist/TrackCache.d.ts
CHANGED
|
@@ -1,15 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
/** Yukimu v2.0.0 — LRU Track Cache with Stats */
|
|
2
|
+
import type { Track, SearchResult } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* A TTL-based LRU cache for tracks and search results.
|
|
5
|
+
*
|
|
6
|
+
* Improvements from v1:
|
|
7
|
+
* - LRU eviction when cache exceeds maxSize
|
|
8
|
+
* - Lazy sweep (only sweeps if cache is non-empty)
|
|
9
|
+
* - Cache hit/miss stats for monitoring
|
|
10
|
+
* - Search result caching (not just individual tracks)
|
|
11
|
+
* - Configurable TTL and max size
|
|
12
|
+
*/
|
|
2
13
|
export declare class TrackCache {
|
|
3
|
-
private
|
|
14
|
+
private tracks;
|
|
15
|
+
private searches;
|
|
4
16
|
private readonly ttl;
|
|
17
|
+
private readonly maxSize;
|
|
5
18
|
private sweepInterval;
|
|
6
|
-
|
|
19
|
+
private _hits;
|
|
20
|
+
private _misses;
|
|
21
|
+
constructor(ttlMs?: number, maxSize?: number);
|
|
7
22
|
set(encoded: string, track: Track): void;
|
|
8
23
|
get(encoded: string): Track | null;
|
|
9
24
|
has(encoded: string): boolean;
|
|
10
|
-
|
|
11
|
-
|
|
25
|
+
deleteTrack(encoded: string): void;
|
|
26
|
+
setSearch(identifier: string, result: SearchResult): void;
|
|
27
|
+
getSearch(identifier: string): SearchResult | null;
|
|
28
|
+
private startSweep;
|
|
12
29
|
private sweep;
|
|
30
|
+
get stats(): {
|
|
31
|
+
tracks: number;
|
|
32
|
+
searches: number;
|
|
33
|
+
hits: number;
|
|
34
|
+
misses: number;
|
|
35
|
+
hitRate: number;
|
|
36
|
+
};
|
|
37
|
+
clear(): void;
|
|
13
38
|
destroy(): void;
|
|
14
39
|
get size(): number;
|
|
15
40
|
}
|
package/dist/TrackCache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrackCache.d.ts","sourceRoot":"","sources":["../src/TrackCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"TrackCache.d.ts","sourceRoot":"","sources":["../src/TrackCache.ts"],"names":[],"mappings":"AAAA,iDAAiD;AAEjD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAQnD;;;;;;;;;GASG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,QAAQ,CAAoD;IACpE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,aAAa,CAA+C;IACpE,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,OAAO,CAAK;gBAER,KAAK,GAAE,MAA2B,EAAE,OAAO,GAAE,MAAgC;IAQlF,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAWxC,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAkBlC,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI7B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAMlC,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI;IAazD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAezD,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,KAAK;IAYb,IAAW,KAAK;;;;;;MAUf;IAIM,KAAK,IAAI,IAAI;IAKb,OAAO,IAAI,IAAI;IAUtB,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
|
package/dist/TrackCache.js
CHANGED
|
@@ -1,40 +1,144 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/** Yukimu v2.0.0 — LRU Track Cache with Stats */
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.TrackCache = void 0;
|
|
5
|
+
const Constants_1 = require("./Constants");
|
|
6
|
+
/**
|
|
7
|
+
* A TTL-based LRU cache for tracks and search results.
|
|
8
|
+
*
|
|
9
|
+
* Improvements from v1:
|
|
10
|
+
* - LRU eviction when cache exceeds maxSize
|
|
11
|
+
* - Lazy sweep (only sweeps if cache is non-empty)
|
|
12
|
+
* - Cache hit/miss stats for monitoring
|
|
13
|
+
* - Search result caching (not just individual tracks)
|
|
14
|
+
* - Configurable TTL and max size
|
|
15
|
+
*/
|
|
4
16
|
class TrackCache {
|
|
5
|
-
|
|
6
|
-
|
|
17
|
+
tracks = new Map();
|
|
18
|
+
searches = new Map();
|
|
19
|
+
ttl;
|
|
20
|
+
maxSize;
|
|
21
|
+
sweepInterval = null;
|
|
22
|
+
_hits = 0;
|
|
23
|
+
_misses = 0;
|
|
24
|
+
constructor(ttlMs = Constants_1.DEFAULTS.CACHE_TTL, maxSize = Constants_1.DEFAULTS.MAX_CACHE_SIZE) {
|
|
7
25
|
this.ttl = ttlMs;
|
|
8
|
-
this.
|
|
26
|
+
this.maxSize = maxSize;
|
|
27
|
+
this.startSweep();
|
|
9
28
|
}
|
|
29
|
+
// ─── Track Cache ────────────────────────────────────────────────────────
|
|
10
30
|
set(encoded, track) {
|
|
11
|
-
|
|
31
|
+
// LRU eviction: delete oldest entries if at capacity
|
|
32
|
+
if (this.tracks.size >= this.maxSize && !this.tracks.has(encoded)) {
|
|
33
|
+
const firstKey = this.tracks.keys().next().value;
|
|
34
|
+
if (firstKey !== undefined) {
|
|
35
|
+
this.tracks.delete(firstKey);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
this.tracks.set(encoded, { value: track, expiresAt: Date.now() + this.ttl });
|
|
12
39
|
}
|
|
13
40
|
get(encoded) {
|
|
14
|
-
const entry = this.
|
|
41
|
+
const entry = this.tracks.get(encoded);
|
|
42
|
+
if (!entry) {
|
|
43
|
+
this._misses++;
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (Date.now() > entry.expiresAt) {
|
|
47
|
+
this.tracks.delete(encoded);
|
|
48
|
+
this._misses++;
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
this._hits++;
|
|
52
|
+
// Move to end for LRU (delete + re-set)
|
|
53
|
+
this.tracks.delete(encoded);
|
|
54
|
+
this.tracks.set(encoded, entry);
|
|
55
|
+
return entry.value;
|
|
56
|
+
}
|
|
57
|
+
has(encoded) {
|
|
58
|
+
return this.get(encoded) !== null;
|
|
59
|
+
}
|
|
60
|
+
deleteTrack(encoded) {
|
|
61
|
+
this.tracks.delete(encoded);
|
|
62
|
+
}
|
|
63
|
+
// ─── Search Result Cache ────────────────────────────────────────────────
|
|
64
|
+
setSearch(identifier, result) {
|
|
65
|
+
// Only cache successful results
|
|
66
|
+
if (result.loadType === "error")
|
|
67
|
+
return;
|
|
68
|
+
if (this.searches.size >= this.maxSize && !this.searches.has(identifier)) {
|
|
69
|
+
const firstKey = this.searches.keys().next().value;
|
|
70
|
+
if (firstKey !== undefined) {
|
|
71
|
+
this.searches.delete(firstKey);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
this.searches.set(identifier, { value: result, expiresAt: Date.now() + this.ttl });
|
|
75
|
+
}
|
|
76
|
+
getSearch(identifier) {
|
|
77
|
+
const entry = this.searches.get(identifier);
|
|
15
78
|
if (!entry)
|
|
16
79
|
return null;
|
|
17
80
|
if (Date.now() > entry.expiresAt) {
|
|
18
|
-
this.
|
|
81
|
+
this.searches.delete(identifier);
|
|
19
82
|
return null;
|
|
20
83
|
}
|
|
21
|
-
|
|
84
|
+
// LRU
|
|
85
|
+
this.searches.delete(identifier);
|
|
86
|
+
this.searches.set(identifier, entry);
|
|
87
|
+
return entry.value;
|
|
88
|
+
}
|
|
89
|
+
// ─── Sweep ──────────────────────────────────────────────────────────────
|
|
90
|
+
startSweep() {
|
|
91
|
+
this.sweepInterval = setInterval(() => {
|
|
92
|
+
// Only sweep if there are entries (lazy sweep)
|
|
93
|
+
if (this.tracks.size > 0 || this.searches.size > 0) {
|
|
94
|
+
this.sweep();
|
|
95
|
+
}
|
|
96
|
+
}, Constants_1.DEFAULTS.CACHE_SWEEP_INTERVAL);
|
|
97
|
+
// Prevent the interval from keeping the process alive
|
|
98
|
+
if (this.sweepInterval.unref) {
|
|
99
|
+
this.sweepInterval.unref();
|
|
100
|
+
}
|
|
22
101
|
}
|
|
23
|
-
has(encoded) { return this.get(encoded) !== null; }
|
|
24
|
-
delete(encoded) { this.cache.delete(encoded); }
|
|
25
|
-
clear() { this.cache.clear(); }
|
|
26
102
|
sweep() {
|
|
27
103
|
const now = Date.now();
|
|
28
|
-
for (const [key, entry] of this.
|
|
104
|
+
for (const [key, entry] of this.tracks) {
|
|
105
|
+
if (now > entry.expiresAt)
|
|
106
|
+
this.tracks.delete(key);
|
|
107
|
+
}
|
|
108
|
+
for (const [key, entry] of this.searches) {
|
|
29
109
|
if (now > entry.expiresAt)
|
|
30
|
-
this.
|
|
110
|
+
this.searches.delete(key);
|
|
31
111
|
}
|
|
32
112
|
}
|
|
113
|
+
// ─── Stats ──────────────────────────────────────────────────────────────
|
|
114
|
+
get stats() {
|
|
115
|
+
return {
|
|
116
|
+
tracks: this.tracks.size,
|
|
117
|
+
searches: this.searches.size,
|
|
118
|
+
hits: this._hits,
|
|
119
|
+
misses: this._misses,
|
|
120
|
+
hitRate: this._hits + this._misses > 0
|
|
121
|
+
? Math.round((this._hits / (this._hits + this._misses)) * 100)
|
|
122
|
+
: 0,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// ─── Lifecycle ──────────────────────────────────────────────────────────
|
|
126
|
+
clear() {
|
|
127
|
+
this.tracks.clear();
|
|
128
|
+
this.searches.clear();
|
|
129
|
+
}
|
|
33
130
|
destroy() {
|
|
34
|
-
|
|
35
|
-
|
|
131
|
+
if (this.sweepInterval) {
|
|
132
|
+
clearInterval(this.sweepInterval);
|
|
133
|
+
this.sweepInterval = null;
|
|
134
|
+
}
|
|
135
|
+
this.clear();
|
|
136
|
+
this._hits = 0;
|
|
137
|
+
this._misses = 0;
|
|
138
|
+
}
|
|
139
|
+
get size() {
|
|
140
|
+
return this.tracks.size;
|
|
36
141
|
}
|
|
37
|
-
get size() { return this.cache.size; }
|
|
38
142
|
}
|
|
39
143
|
exports.TrackCache = TrackCache;
|
|
40
144
|
//# sourceMappingURL=TrackCache.js.map
|
package/dist/TrackCache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrackCache.js","sourceRoot":"","sources":["../src/TrackCache.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"TrackCache.js","sourceRoot":"","sources":["../src/TrackCache.ts"],"names":[],"mappings":"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"}
|
package/dist/WsQueue.d.ts
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
|
+
/** Yukimu v2.0.0 — WebSocket Message Queue with Timeouts & Priority */
|
|
1
2
|
import WebSocket from "ws";
|
|
3
|
+
/**
|
|
4
|
+
* Manages a WebSocket message queue that buffers messages when the socket
|
|
5
|
+
* is not open and flushes them once it becomes available.
|
|
6
|
+
*
|
|
7
|
+
* Fixes from v1:
|
|
8
|
+
* - Messages are rejected after a configurable timeout (prevents hanging promises)
|
|
9
|
+
* - Max queue size prevents unbounded memory growth
|
|
10
|
+
* - Priority messages (voice updates) are sent first
|
|
11
|
+
* - No duplicate "open" listener — flush is called externally
|
|
12
|
+
*/
|
|
2
13
|
export declare class WsQueue {
|
|
3
14
|
private queue;
|
|
4
15
|
private ws;
|
|
16
|
+
private readonly sendTimeout;
|
|
17
|
+
private readonly maxQueueSize;
|
|
18
|
+
constructor(sendTimeout?: 30000, maxQueueSize?: 100);
|
|
19
|
+
/**
|
|
20
|
+
* Set the underlying WebSocket.
|
|
21
|
+
* Unlike v1, does NOT add an "open" listener to avoid race conditions.
|
|
22
|
+
* The caller (Node) is responsible for calling flush() at the right time.
|
|
23
|
+
*/
|
|
5
24
|
setSocket(ws: WebSocket | null): void;
|
|
6
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Send data through the WebSocket, or queue it if not ready.
|
|
27
|
+
* @param data - The payload to send (will be JSON-serialized)
|
|
28
|
+
* @param priority - If true, message is prepended to the queue (used for voice updates)
|
|
29
|
+
*/
|
|
30
|
+
send(data: Record<string, unknown>, priority?: boolean): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Flush all queued messages. Called by Node after WebSocket is confirmed open.
|
|
33
|
+
*/
|
|
7
34
|
flush(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Clear the queue and reject all pending messages.
|
|
37
|
+
*/
|
|
8
38
|
clear(): void;
|
|
9
39
|
get size(): number;
|
|
10
40
|
}
|
package/dist/WsQueue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WsQueue.d.ts","sourceRoot":"","sources":["../src/WsQueue.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"WsQueue.d.ts","sourceRoot":"","sources":["../src/WsQueue.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,OAAO,SAAS,MAAM,IAAI,CAAC;AAW3B;;;;;;;;;GASG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,WAAW,QAA2B,EAAE,YAAY,MAAwB;IAKxF;;;;OAIG;IACI,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI;IAI5C;;;;OAIG;IACI,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC3E;;OAEG;IACI,KAAK,IAAI,IAAI;IAsBpB;;OAEG;IACI,KAAK,IAAI,IAAI;IAQpB,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
|