vantiv.io 1.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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +864 -0
  3. package/index.js +13 -0
  4. package/package.json +28 -0
  5. package/src/classes/Actions/Awaiter.js +202 -0
  6. package/src/classes/Actions/Channel.js +73 -0
  7. package/src/classes/Actions/Direct.js +263 -0
  8. package/src/classes/Actions/Inventory.js +156 -0
  9. package/src/classes/Actions/Music.js +278 -0
  10. package/src/classes/Actions/Player.js +377 -0
  11. package/src/classes/Actions/Public.js +66 -0
  12. package/src/classes/Actions/Room.js +333 -0
  13. package/src/classes/Actions/Utils.js +29 -0
  14. package/src/classes/Actions/lib/AudioStreaming.js +447 -0
  15. package/src/classes/Caches/MovementCache.js +357 -0
  16. package/src/classes/Handlers/AxiosErrorHandler.js +68 -0
  17. package/src/classes/Handlers/ErrorHandler.js +65 -0
  18. package/src/classes/Handlers/EventHandlers.js +259 -0
  19. package/src/classes/Handlers/WebSocketHandlers.js +54 -0
  20. package/src/classes/Managers/ChannelManager.js +303 -0
  21. package/src/classes/Managers/DanceFloorManagers.js +509 -0
  22. package/src/classes/Managers/Helpers/CleanupManager.js +130 -0
  23. package/src/classes/Managers/Helpers/LoggerManager.js +171 -0
  24. package/src/classes/Managers/Helpers/MetricsManager.js +83 -0
  25. package/src/classes/Managers/Networking/ConnectionManager.js +259 -0
  26. package/src/classes/Managers/Networking/CooldownManager.js +516 -0
  27. package/src/classes/Managers/Networking/EventsManager.js +64 -0
  28. package/src/classes/Managers/Networking/KeepAliveManager.js +109 -0
  29. package/src/classes/Managers/Networking/MessageHandler.js +110 -0
  30. package/src/classes/Managers/Networking/Request.js +329 -0
  31. package/src/classes/Managers/PermissionManager.js +288 -0
  32. package/src/classes/WebApi/Category/Grab.js +98 -0
  33. package/src/classes/WebApi/Category/Item.js +347 -0
  34. package/src/classes/WebApi/Category/Post.js +154 -0
  35. package/src/classes/WebApi/Category/Room.js +137 -0
  36. package/src/classes/WebApi/Category/User.js +88 -0
  37. package/src/classes/WebApi/webapi.js +52 -0
  38. package/src/constants/TypesConstants.js +89 -0
  39. package/src/constants/WebSocketConstants.js +80 -0
  40. package/src/core/Highrise.js +123 -0
  41. package/src/core/HighriseWebsocket.js +228 -0
  42. package/src/utils/ConvertSvgToPng.js +51 -0
  43. package/src/utils/ModelPool.js +160 -0
  44. package/src/utils/Models.js +128 -0
  45. package/src/utils/versionCheck.js +27 -0
  46. package/src/validators/ConfigValidator.js +205 -0
  47. package/src/validators/ConnectionValidator.js +65 -0
  48. package/typings/index.d.ts +3820 -0
@@ -0,0 +1,171 @@
1
+ const chalk = require('chalk');
2
+
3
+ class Logger {
4
+ constructor(bot, options = {}) {
5
+ this.bot = bot;
6
+ this.options = {
7
+ showTimestamp: true,
8
+ showMethodName: true,
9
+ colors: true,
10
+ ...options
11
+ };
12
+
13
+ this.chalk = this.options.colors ? chalk : new chalk.Instance({ level: 0 });
14
+ }
15
+
16
+ getMessageText(levelColor, message) {
17
+ if (!this.options.colors) return message;
18
+
19
+ switch (levelColor) {
20
+ case 'green':
21
+ return this.chalk.green(message);
22
+ case 'red':
23
+ return this.chalk.red(message);
24
+ case 'yellow':
25
+ return this.chalk.yellow(message);
26
+ case 'blue':
27
+ return this.chalk.blue(message);
28
+ case 'magenta':
29
+ return this.chalk.magenta(message);
30
+ default:
31
+ return message;
32
+ }
33
+ }
34
+
35
+ _formatMessage(level, method, message = '', data = null) {
36
+ const parts = [];
37
+
38
+ let header = '┌─ ';
39
+
40
+ if (this.options.showTimestamp) {
41
+ header += this.chalk.magenta(`[${new Date().toISOString()}] `);
42
+ }
43
+
44
+ let levelColor;
45
+ switch (level) {
46
+ case 'SUCCESS':
47
+ header += this.chalk.green('[SUCCESS]');
48
+ levelColor = 'green';
49
+ break;
50
+ case 'ERROR':
51
+ header += this.chalk.red('[ERROR]');
52
+ levelColor = 'red';
53
+ break;
54
+ case 'WARN':
55
+ header += this.chalk.yellow('[WARN]');
56
+ levelColor = 'yellow';
57
+ break;
58
+ case 'INFO':
59
+ header += this.chalk.blue('[INFO]');
60
+ levelColor = 'blue';
61
+ break;
62
+ case 'DEBUG':
63
+ header += this.chalk.magenta('[DEBUG]');
64
+ levelColor = 'magenta';
65
+ break;
66
+ default:
67
+ header += `[${level}]`;
68
+ levelColor = 'default';
69
+ }
70
+
71
+ if (this.options.showMethodName && method) {
72
+ header += ' ' + this.chalk.white('─') + ' ' + this.chalk.cyan(`[${method}]`);
73
+ }
74
+
75
+ parts.push(header);
76
+
77
+
78
+ if (data) {
79
+ const dataStr = typeof data === 'object' ? JSON.stringify(data) : String(data);
80
+ parts.push('├─ ' + this.chalk.yellow('Data:') + ' ' + this.chalk.gray(dataStr));
81
+ }
82
+
83
+
84
+ const connector = data ? '└─ ' : '└─ ';
85
+ const coloredMessage = this.getMessageText(levelColor, String(message));
86
+ parts.push(connector + this.chalk.yellow('Message:') + ' ' + coloredMessage);
87
+
88
+ return parts.join('\n');
89
+ }
90
+
91
+ _formatErrorMessage(error, method, data = null) {
92
+ const parts = [];
93
+
94
+
95
+ let header = '┌─ ';
96
+
97
+ if (this.options.showTimestamp) {
98
+ header += this.chalk.magenta(`[${new Date().toISOString()}] `);
99
+ }
100
+
101
+ header += this.chalk.red('[ERROR]');
102
+
103
+ if (this.options.showMethodName && method) {
104
+ header += ' ' + this.chalk.white('─') + ' ' + this.chalk.cyan(`[${method}]`);
105
+ }
106
+
107
+ parts.push(header);
108
+
109
+
110
+ if (data) {
111
+ const dataStr = typeof data === 'object' ? JSON.stringify(data) : String(data);
112
+ parts.push('├─ ' + this.chalk.yellow('Data:') + ' ' + this.chalk.gray(dataStr));
113
+ }
114
+
115
+
116
+ const errorMsg = error.message || String(error);
117
+ const messageLines = errorMsg.split('\n');
118
+ const hasPreviousLines = parts.length > 1;
119
+
120
+ parts.push('├─ ' + this.chalk.yellow('Message:') + ' ' + this.chalk.red(messageLines[0]));
121
+
122
+ for (let i = 1; i < messageLines.length; i++) {
123
+ const prefix = hasPreviousLines ? '│ ' : ' ';
124
+ parts.push(prefix + ' ' + this.chalk.red(messageLines[i]));
125
+ }
126
+
127
+
128
+ const stack = error.stack || '';
129
+ const callerLine = stack.split('\n')
130
+ .find(line => line.includes('Highrise.<anonymous>') || line.includes(method))
131
+ ?.trim() || 'Unknown location';
132
+
133
+ const location = callerLine.match(/\((.*):(\d+):(\d+)\)/)?.[0] || callerLine;
134
+ parts.push('└─ ' + this.chalk.yellow('Caller:') + ' ' + this.chalk.gray(location));
135
+
136
+ return parts.join('\n');
137
+ }
138
+
139
+ log(level, method, message, data = null) {
140
+ const formatted = this._formatMessage(level, method, message, data);
141
+ console.log(this.options.colors ? formatted : this._stripColors(formatted));
142
+ }
143
+
144
+ success(method, message, data = null) {
145
+ this.log('SUCCESS', method, message, data);
146
+ }
147
+
148
+ error(method, message, data = null, errorInstance = null) {
149
+ const error = errorInstance instanceof Error ? errorInstance : new Error(String(message));
150
+ const formatted = this._formatErrorMessage(error, method, data);
151
+ console.log(this.options.colors ? formatted : this._stripColors(formatted));
152
+ }
153
+
154
+ warn(method, message, data = null) {
155
+ this.log('WARN', method, message, data);
156
+ }
157
+
158
+ info(method, message, data = null) {
159
+ this.log('INFO', method, message, data);
160
+ }
161
+
162
+ debug(method, message, data = null) {
163
+ this.log('DEBUG', method, message, data);
164
+ }
165
+
166
+ _stripColors(text) {
167
+ return text.replace(/\x1b\[\d+m/g, '');
168
+ }
169
+ }
170
+
171
+ module.exports = { Logger };
@@ -0,0 +1,83 @@
1
+ const WebSocketConstants = require('highrise-core/src/constants/WebSocketConstants');
2
+
3
+ class MetricsManager {
4
+ constructor() {
5
+ this.startTime = Date.now();
6
+ this.messagesReceived = 0;
7
+ this.messagesSent = 0;
8
+ this.eventsProcessed = 0;
9
+ this.errors = 0;
10
+ this.reconnects = 0;
11
+ this.cacheStats = {
12
+ lastUpdate: 0,
13
+ activeUsers: 0,
14
+ inactiveUsers: 0,
15
+ memoryUsage: 0,
16
+ changesProcessed: 0
17
+ };
18
+ }
19
+
20
+ increment(metric, value = 1) {
21
+ if (this[metric] !== undefined) {
22
+ this[metric] += value;
23
+ }
24
+ }
25
+
26
+ updateCacheStats(stats) {
27
+ this.cacheStats = {
28
+ ...this.cacheStats,
29
+ ...stats,
30
+ lastUpdate: Date.now()
31
+ };
32
+ }
33
+
34
+ getUptime() {
35
+ const uptime = Date.now() - this.startTime;
36
+
37
+ const weeks = Math.floor(uptime / (7 * 24 * 60 * 60 * 1000));
38
+ const days = Math.floor((uptime % (7 * 24 * 60 * 60 * 1000)) / (24 * 60 * 60 * 1000));
39
+ const hours = Math.floor((uptime % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
40
+ const minutes = Math.floor((uptime % (60 * 60 * 1000)) / (60 * 1000));
41
+ const seconds = Math.floor((uptime % (60 * 1000)) / 1000);
42
+
43
+ const parts = [];
44
+ if (weeks > 0) parts.push(`${weeks}w`);
45
+ if (days > 0) parts.push(`${days}d`);
46
+ if (hours > 0) parts.push(`${hours}h`);
47
+ if (minutes > 0) parts.push(`${minutes}m`);
48
+ if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
49
+
50
+ return parts.join(' ');
51
+ }
52
+
53
+ formatBytes(bytes) {
54
+ if (bytes === 0) return '0 B';
55
+ const k = 1024;
56
+ const sizes = ['B', 'KB', 'MB', 'GB'];
57
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
58
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
59
+ }
60
+
61
+ getSnapshot() {
62
+ return {
63
+ uptime: this.getUptime(),
64
+ messagesReceived: this.messagesReceived,
65
+ messagesSent: this.messagesSent,
66
+ eventsProcessed: this.eventsProcessed,
67
+ errors: this.errors,
68
+ reconnects: this.reconnects,
69
+ cacheStats: { ...this.cacheStats }
70
+ };
71
+ }
72
+
73
+ reset() {
74
+ this.startTime = Date.now();
75
+ this.messagesReceived = 0;
76
+ this.messagesSent = 0;
77
+ this.eventsProcessed = 0;
78
+ this.errors = 0;
79
+ this.reconnects = 0;
80
+ }
81
+ }
82
+
83
+ module.exports = MetricsManager;
@@ -0,0 +1,259 @@
1
+ const WebSocketConstants = require('highrise-core/src/constants/WebSocketConstants');
2
+ const EventEmitter = require('events');
3
+ const WebSocket = require('ws');
4
+
5
+ class ConnectionManager extends EventEmitter {
6
+ constructor(server, logger, options = {}) {
7
+ super();
8
+
9
+ this.server = server;
10
+ this.logger = logger;
11
+ this.ws = null;
12
+
13
+ this.autoReconnect = options.autoReconnect ?? true;
14
+ this.reconnectDelay = options.reconnectDelay ?? WebSocketConstants.DEFAULT_RECONNECT_DELAY;
15
+
16
+ this.reconnectAttempts = 0;
17
+ this.reconnectTimeout = null;
18
+ this.connected = false;
19
+ this.reconnecting = false;
20
+ this.isManualDisconnect = false;
21
+
22
+ this.connectionAuth = null;
23
+ }
24
+
25
+ connect(token, roomId, events) {
26
+ this.connectionAuth = { token, roomId, events };
27
+ this.isManualDisconnect = false;
28
+ this._establishConnection();
29
+ }
30
+
31
+ _establishConnection() {
32
+ if (!this.connectionAuth) {
33
+ throw new Error('No connection authentication available');
34
+ }
35
+
36
+ this._clearReconnectTimeout();
37
+ this.reconnecting = true;
38
+
39
+ const { token, roomId, events } = this.connectionAuth;
40
+ const eventsParam = events.join(',');
41
+ const endpoint = `${WebSocketConstants.BASE_WS_URL}?events=${eventsParam}`;
42
+
43
+ if (this.ws) {
44
+ this._cleanupWebSocket();
45
+ }
46
+
47
+ this.ws = new WebSocket(endpoint, {
48
+ headers: {
49
+ [WebSocketConstants.HEADERS.API_TOKEN]: token,
50
+ [WebSocketConstants.HEADERS.ROOM_ID]: roomId
51
+ }
52
+ });
53
+
54
+ this._setupWebSocketHandlers();
55
+ }
56
+
57
+ _cleanupWebSocket() {
58
+ if (this.ws) {
59
+ this.ws.removeAllListeners();
60
+
61
+ if (this.ws.readyState !== WebSocket.CLOSED &&
62
+ this.ws.readyState !== WebSocket.CLOSING) {
63
+ this.ws.close();
64
+ }
65
+
66
+ this.ws = null;
67
+ }
68
+ }
69
+
70
+ _setupWebSocketHandlers() {
71
+ this.ws.on('open', () => this._handleOpen());
72
+ this.ws.on('message', (data) => this.emit('message', data));
73
+ this.ws.on('close', (code, reason) => this._handleClose(code, reason));
74
+ this.ws.on('error', (error) => this._handleError(error));
75
+ }
76
+
77
+ _handleOpen() {
78
+ if (!this.connected) {
79
+ this.connected = true;
80
+ }
81
+
82
+ if (!this.reconnecting) {
83
+ this.reconnectAttempts = 0;
84
+ }
85
+
86
+ this.reconnecting = false;
87
+ this._clearReconnectTimeout();
88
+
89
+ this.emit('connected');
90
+ this.logger.success('ConnectionManager', 'WebSocket connection established');
91
+ }
92
+
93
+ _handleClose(code, reason) {
94
+ if (this.connected) {
95
+ this.connected = false;
96
+ }
97
+
98
+ const reasonStr = reason.toString();
99
+ this.emit('disconnected', { code, reason: reasonStr });
100
+ this.logger.warn('ConnectionManager', `Connection closed`, {
101
+ code,
102
+ reason: reasonStr,
103
+ reconnectAttempts: this.reconnectAttempts,
104
+ autoReconnect: this.autoReconnect,
105
+ reconnecting: this.reconnecting
106
+ });
107
+
108
+ const wasReconnecting = this.reconnecting;
109
+ this.reconnecting = false;
110
+
111
+ if (this.autoReconnect && !this.isManualDisconnect && !wasReconnecting) {
112
+ const shouldReconnect = this._shouldReconnect(code, reasonStr);
113
+
114
+ if (shouldReconnect) {
115
+ this._scheduleReconnect();
116
+ } else {
117
+ this.logger.warn('ConnectionManager', 'Not reconnecting due to close code or reason', {
118
+ code,
119
+ reason: reasonStr
120
+ });
121
+ }
122
+ }
123
+ }
124
+
125
+ _shouldReconnect(code, reason) {
126
+ if (code === 1000 && reason.includes('Manual disconnect')) {
127
+ return false;
128
+ }
129
+
130
+ if (code === 4001 || code === 4003 || code === 4004) {
131
+ this.logger.error('ConnectionManager', 'Authentication failed, not reconnecting', { code, reason });
132
+ return false;
133
+ }
134
+
135
+ if (code === 4009 || code === 4029) {
136
+ this.logger.error('ConnectionManager', 'Rate limited or banned, not reconnecting', { code, reason });
137
+ return false;
138
+ }
139
+
140
+ return true;
141
+ }
142
+
143
+ _handleError(error) {
144
+ this.emit('error', error);
145
+ this.logger.error('ConnectionManager', 'WebSocket error', {
146
+ error: error.message,
147
+ reconnectAttempts: this.reconnectAttempts,
148
+ reconnecting: this.reconnecting
149
+ });
150
+ }
151
+
152
+ _clearReconnectTimeout() {
153
+ if (this.reconnectTimeout) {
154
+ clearTimeout(this.reconnectTimeout);
155
+ this.reconnectTimeout = null;
156
+ }
157
+ }
158
+
159
+ _scheduleReconnect() {
160
+ if (this.reconnecting) {
161
+ this.logger.debug('ConnectionManager', 'Already reconnecting, skipping duplicate');
162
+ return;
163
+ }
164
+
165
+ const maxAttempts = WebSocketConstants.MAX_RECONNECT_ATTEMPTS || 10;
166
+ if (this.reconnectAttempts >= maxAttempts) {
167
+ this.logger.error('ConnectionManager', 'Max reconnection attempts reached', {
168
+ attempts: this.reconnectAttempts,
169
+ maxAttempts
170
+ });
171
+ this.emit('reconnectFailed', {
172
+ attempts: this.reconnectAttempts,
173
+ maxAttempts
174
+ });
175
+ return;
176
+ }
177
+
178
+ this._clearReconnectTimeout();
179
+
180
+ const delay = Math.min(
181
+ this.reconnectDelay * Math.pow(WebSocketConstants.RECONNECT_BACKOFF_FACTOR, this.reconnectAttempts),
182
+ WebSocketConstants.MAX_RECONNECT_DELAY
183
+ );
184
+
185
+ this.reconnectAttempts++;
186
+ this.reconnecting = true;
187
+
188
+ this.server.metrics.increment('reconnects');
189
+
190
+ this.logger.info('ConnectionManager', `Scheduling reconnect...`, {
191
+ attempt: this.reconnectAttempts,
192
+ delay: `${delay}ms (${Math.round(delay / 1000)}s)`,
193
+ maxDelay: `${WebSocketConstants.MAX_RECONNECT_DELAY}ms`
194
+ });
195
+
196
+ this.reconnectTimeout = setTimeout(() => {
197
+ if (this.connectionAuth && !this.isManualDisconnect) {
198
+ this.logger.info('ConnectionManager', `Attempting reconnection (attempt ${this.reconnectAttempts})...`);
199
+ this._establishConnection();
200
+ } else {
201
+ this.reconnecting = false;
202
+ }
203
+ }, delay);
204
+ }
205
+
206
+ disconnect(code = WebSocketConstants.ERROR_CODES.NORMAL_CLOSURE, reason = 'Manual disconnect') {
207
+ this.autoReconnect = false;
208
+ this.isManualDisconnect = true;
209
+ this.reconnecting = false;
210
+
211
+ this._clearReconnectTimeout();
212
+
213
+ if (this.ws && this.ws.readyState !== WebSocket.CLOSED && this.ws.readyState !== WebSocket.CLOSING) {
214
+ this.ws.close(code, reason);
215
+ }
216
+
217
+ this.connected = false;
218
+ this.emit('disconnected', { code, reason, manual: true });
219
+ }
220
+
221
+ send(data) {
222
+ if (!this.isConnected() || !this.ws) {
223
+ throw new Error('WebSocket is not connected');
224
+ }
225
+
226
+ const payload = typeof data === 'string' ? data : JSON.stringify(data);
227
+ this.ws.send(payload);
228
+
229
+ this.server.metrics.increment('messagesSent');
230
+
231
+ return true;
232
+ }
233
+
234
+ isConnected() {
235
+ return this.ws && this.ws.readyState === WebSocket.OPEN;
236
+ }
237
+
238
+ getWebSocket() {
239
+ return this.ws;
240
+ }
241
+
242
+ getReconnectStats() {
243
+ return {
244
+ attempts: this.reconnectAttempts,
245
+ reconnecting: this.reconnecting,
246
+ autoReconnect: this.autoReconnect,
247
+ isManualDisconnect: this.isManualDisconnect
248
+ };
249
+ }
250
+
251
+ cleanup() {
252
+ this.disconnect();
253
+ this.removeAllListeners();
254
+ this.connectionAuth = null;
255
+ this._cleanupWebSocket();
256
+ }
257
+ }
258
+
259
+ module.exports = ConnectionManager;