highrise.bot 1.1.0 → 1.1.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "highrise.bot",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Unofficial JavaScript SDK for the Highrise platform. Feature-complete WebSocket client with TypeScript support, built for production environments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"highrise.bot",
|
|
@@ -1,200 +1,88 @@
|
|
|
1
1
|
class AwaitClass {
|
|
2
2
|
constructor(ws) {
|
|
3
|
-
if (!ws)
|
|
4
|
-
throw new Error('ws instance is required');
|
|
5
|
-
}
|
|
3
|
+
if (!ws) throw new Error('ws instance is required');
|
|
6
4
|
this.ws = ws;
|
|
7
|
-
this._pendingAwaiters =
|
|
5
|
+
this._pendingAwaiters = {
|
|
6
|
+
chat: new Map(),
|
|
7
|
+
whisper: new Map(),
|
|
8
|
+
direct: new Map(),
|
|
9
|
+
tip: new Map(),
|
|
10
|
+
movement: new Map()
|
|
11
|
+
};
|
|
8
12
|
}
|
|
9
13
|
|
|
10
14
|
chat(filter = () => true, timeout = 30000, maxToCollect = 1, uniqueUsers = false) {
|
|
11
|
-
if (!this._validateParameters('chat', filter, timeout, maxToCollect)) {
|
|
12
|
-
return Promise.resolve([]);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
15
|
return this._createAwaiter('chat', filter, timeout, maxToCollect, uniqueUsers);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
whisper(filter = () => true, timeout = 30000, maxToCollect = 1, uniqueUsers = false) {
|
|
19
|
-
if (!this._validateParameters('whisper', filter, timeout, maxToCollect)) {
|
|
20
|
-
return Promise.resolve([]);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
19
|
return this._createAwaiter('whisper', filter, timeout, maxToCollect, uniqueUsers);
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
direct(filter = () => true, timeout = 30000, maxToCollect = 1, uniqueUsers = false) {
|
|
27
|
-
if (!this._validateParameters('direct', filter, timeout, maxToCollect)) {
|
|
28
|
-
return Promise.resolve([]);
|
|
29
|
-
}
|
|
30
23
|
return this._createAwaiter('direct', filter, timeout, maxToCollect, uniqueUsers);
|
|
31
24
|
}
|
|
32
25
|
|
|
33
26
|
tip(filter = () => true, timeout = 30000, maxToCollect = 1, uniqueUsers = false) {
|
|
34
|
-
if (!this._validateParameters('tip', filter, timeout, maxToCollect)) {
|
|
35
|
-
return Promise.resolve([]);
|
|
36
|
-
}
|
|
37
27
|
return this._createAwaiter('tip', filter, timeout, maxToCollect, uniqueUsers);
|
|
38
28
|
}
|
|
39
29
|
|
|
40
30
|
movement(filter = () => true, timeout = 30000, maxToCollect = 1, uniqueUsers = false) {
|
|
41
|
-
if (!this._validateParameters('movement', filter, timeout, maxToCollect)) {
|
|
42
|
-
return Promise.resolve([]);
|
|
43
|
-
}
|
|
44
31
|
return this._createAwaiter('movement', filter, timeout, maxToCollect, uniqueUsers);
|
|
45
32
|
}
|
|
46
33
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (typeof timeout !== 'number') {
|
|
54
|
-
throw new TypeError(`Timeout must be a number`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (timeout < 0) {
|
|
58
|
-
throw new RangeError(`Timeout cannot be negative`);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (typeof maxToCollect !== 'number') {
|
|
62
|
-
throw new TypeError(`maxToCollect must be a number`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!Number.isInteger(maxToCollect)) {
|
|
66
|
-
throw new TypeError(`maxToCollect must be an integer`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (maxToCollect < 1) {
|
|
70
|
-
throw new RangeError(`maxToCollect must be at least 1`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (maxToCollect > 1000) {
|
|
74
|
-
throw new RangeError(`maxToCollect cannot exceed 1000`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!this.ws.isConnected || !this.ws.isConnected()) {
|
|
78
|
-
throw new Error(`WebSocket is not connected to Highrise`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return true;
|
|
82
|
-
|
|
83
|
-
} catch (error) {
|
|
84
|
-
if (error instanceof TypeError) {
|
|
85
|
-
this.ws._logger.error(`await.${method}`, `TypeError: ${error.message}`, { timeout, maxToCollect }, error);
|
|
86
|
-
} else if (error instanceof RangeError) {
|
|
87
|
-
this.ws._logger.error(`await.${method}`, `RangeError: ${error.message}`, { timeout, maxToCollect }, error);
|
|
88
|
-
} else {
|
|
89
|
-
this.ws._logger.error(`await.${method}`, error.message, { timeout, maxToCollect }, error);
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
34
|
+
_createAwaiter(eventType, filter, timeout, maxToCollect, uniqueUsers) {
|
|
35
|
+
if (typeof filter !== 'function' || typeof timeout !== 'number' || timeout < 0 ||
|
|
36
|
+
!Number.isInteger(maxToCollect) || maxToCollect < 1 || maxToCollect > 1000) {
|
|
37
|
+
return Promise.resolve([]);
|
|
92
38
|
}
|
|
93
|
-
}
|
|
94
39
|
|
|
95
|
-
|
|
96
|
-
return new Promise((resolve, reject) => {
|
|
40
|
+
return new Promise((resolve) => {
|
|
97
41
|
const awaiterId = Symbol('awaiter');
|
|
98
42
|
const collected = [];
|
|
99
|
-
const seenUsers = new Set();
|
|
100
|
-
let timeoutId;
|
|
43
|
+
const seenUsers = uniqueUsers ? new Set() : null;
|
|
101
44
|
|
|
102
45
|
const cleanup = () => {
|
|
103
46
|
clearTimeout(timeoutId);
|
|
104
|
-
this._pendingAwaiters.delete(awaiterId);
|
|
47
|
+
this._pendingAwaiters[eventType].delete(awaiterId);
|
|
105
48
|
};
|
|
106
49
|
|
|
107
50
|
const awaiter = {
|
|
108
|
-
eventType,
|
|
109
51
|
filter,
|
|
110
52
|
maxToCollect,
|
|
111
53
|
collected,
|
|
112
|
-
uniqueUsers,
|
|
113
54
|
seenUsers,
|
|
114
55
|
resolve: (results) => {
|
|
115
56
|
cleanup();
|
|
116
57
|
resolve(results);
|
|
117
|
-
},
|
|
118
|
-
reject: (error) => {
|
|
119
|
-
cleanup();
|
|
120
|
-
reject(error);
|
|
121
58
|
}
|
|
122
59
|
};
|
|
123
60
|
|
|
124
|
-
this._pendingAwaiters.set(awaiterId, awaiter);
|
|
61
|
+
this._pendingAwaiters[eventType].set(awaiterId, awaiter);
|
|
125
62
|
|
|
126
|
-
|
|
127
|
-
timeoutId = setTimeout(() => {
|
|
128
|
-
awaiter.resolve(collected);
|
|
129
|
-
}, timeout);
|
|
130
|
-
}
|
|
63
|
+
const timeoutId = timeout > 0 ? setTimeout(() => awaiter.resolve(collected), timeout) : null;
|
|
131
64
|
});
|
|
132
65
|
}
|
|
133
66
|
|
|
134
67
|
_processEvent(eventType, ...eventArgs) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
this._validateEventArguments(eventType, eventArgs);
|
|
68
|
+
const awaiters = this._pendingAwaiters[eventType];
|
|
69
|
+
if (!awaiters) return;
|
|
139
70
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (awaiter.filter(...eventArgs)) {
|
|
148
|
-
awaiter.collected.push(eventArgs);
|
|
71
|
+
for (const awaiter of awaiters.values()) {
|
|
72
|
+
try {
|
|
73
|
+
if (awaiter.seenUsers && eventArgs[0]?.id) {
|
|
74
|
+
if (awaiter.seenUsers.has(eventArgs[0].id)) continue;
|
|
75
|
+
awaiter.seenUsers.add(eventArgs[0].id);
|
|
76
|
+
}
|
|
149
77
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
78
|
+
if (awaiter.filter(...eventArgs)) {
|
|
79
|
+
awaiter.collected.push(eventArgs);
|
|
80
|
+
if (awaiter.collected.length >= awaiter.maxToCollect) {
|
|
81
|
+
awaiter.resolve(awaiter.collected);
|
|
153
82
|
}
|
|
154
|
-
} catch (error) {
|
|
155
|
-
this.ws._logger.error(`await.${eventType}`, `Filter error: ${error.message}`)
|
|
156
83
|
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
_validateEventArguments(eventType, eventArgs) {
|
|
162
|
-
const validators = {
|
|
163
|
-
chat: (args) => {
|
|
164
|
-
if (args.length !== 2) throw new TypeError('Chat event requires 2 arguments (user, message)');
|
|
165
|
-
if (!args[0] || typeof args[0].id !== 'string') throw new TypeError('Invalid user object in chat event');
|
|
166
|
-
if (typeof args[1] !== 'string') throw new TypeError('Invalid message in chat event');
|
|
167
|
-
},
|
|
168
|
-
whisper: (args) => {
|
|
169
|
-
if (args.length !== 2) throw new TypeError('Whisper event requires 2 arguments (user, message)');
|
|
170
|
-
if (!args[0] || typeof args[0].id !== 'string') throw new TypeError('Invalid user object in whisper event');
|
|
171
|
-
if (typeof args[1] !== 'string') throw new TypeError('Invalid message in whisper event');
|
|
172
|
-
},
|
|
173
|
-
direct: (args) => {
|
|
174
|
-
if (args.length !== 3) throw new TypeError('Direct event requires 3 arguments (user, message, conversation)');
|
|
175
|
-
if (!args[0] || typeof args[0].id !== 'string') throw new TypeError('Invalid user object in direct event');
|
|
176
|
-
if (typeof args[1] !== 'string') throw new TypeError('Invalid message in direct event');
|
|
177
|
-
if (!args[2] || typeof args[2].id !== 'string') throw new TypeError('Invalid conversation object in direct event');
|
|
178
|
-
},
|
|
179
|
-
tip: (args) => {
|
|
180
|
-
if (args.length !== 3) throw new TypeError('Tip event requires 3 arguments (sender, receiver, currency)');
|
|
181
|
-
if (!args[0] || typeof args[0].id !== 'string') throw new TypeError('Invalid sender in tip event');
|
|
182
|
-
if (!args[1] || typeof args[1].id !== 'string') throw new TypeError('Invalid receiver in tip event');
|
|
183
|
-
if (!args[2] || typeof args[2].amount !== 'number') throw new TypeError('Invalid currency in tip event');
|
|
184
|
-
},
|
|
185
|
-
movement: (args) => {
|
|
186
|
-
if (args.length !== 3) throw new TypeError('Movement event requires 3 arguments (user, position, anchor)');
|
|
187
|
-
if (!args[0] || typeof args[0].id !== 'string') throw new TypeError('Invalid user object in movement event');
|
|
188
|
-
if (!args[1] || typeof args[1].x !== 'number') throw new TypeError('Invalid position in movement event');
|
|
189
|
-
if (args[2] !== null && (!args[2] || typeof args[2].entity_id !== 'string')) throw new TypeError('Invalid anchor in movement event');
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
if (validators[eventType]) {
|
|
194
|
-
try {
|
|
195
|
-
validators[eventType](eventArgs);
|
|
196
84
|
} catch (error) {
|
|
197
|
-
|
|
85
|
+
// Filter error - continue to next awaiter
|
|
198
86
|
}
|
|
199
87
|
}
|
|
200
88
|
}
|
|
@@ -288,11 +288,6 @@ class CommandHandler {
|
|
|
288
288
|
return false
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
if (typeof context.user.username !== 'string' || context.user.username.trim() === '') {
|
|
292
|
-
this.handlerError(`context.user.username must be a non-empty string.`)
|
|
293
|
-
return false
|
|
294
|
-
}
|
|
295
|
-
|
|
296
291
|
return true
|
|
297
292
|
}
|
|
298
293
|
|
|
@@ -37,7 +37,7 @@ class RolesManager {
|
|
|
37
37
|
this._startWebApiSync();
|
|
38
38
|
this._startAutoSave();
|
|
39
39
|
this.initialized = true;
|
|
40
|
-
this.logger.success('RolesManager', '
|
|
40
|
+
this.logger.success('RolesManager', 'Ready! Auto-syncing every 5 minutes.');
|
|
41
41
|
} catch (error) {
|
|
42
42
|
this.logger.error('RolesManager', 'Setup failed', error);
|
|
43
43
|
this._createCustomRoles();
|
package/typings/index.d.ts
CHANGED
|
@@ -828,9 +828,11 @@ interface CooldownManagerStats {
|
|
|
828
828
|
* Context passed to command handlers containing user and additional data
|
|
829
829
|
*/
|
|
830
830
|
interface CommandContext {
|
|
831
|
-
user: User;
|
|
831
|
+
user: User;
|
|
832
832
|
args?: string[];
|
|
833
833
|
message?: string;
|
|
834
|
+
conversation?: Conversation
|
|
835
|
+
/** Additional properties */
|
|
834
836
|
[key: string]: any;
|
|
835
837
|
}
|
|
836
838
|
|
|
@@ -3361,7 +3363,7 @@ declare class AwaitClass {
|
|
|
3361
3363
|
* );
|
|
3362
3364
|
* ```
|
|
3363
3365
|
*/
|
|
3364
|
-
movement(filter?: MovementFilter, timeout?: number, maxToCollect?: number, uniqueUsers?: boolean): Promise<[User, Position, AnchorPosition | null][] | []>;
|
|
3366
|
+
movement(filter?: MovementFilter, timeout?: number, maxToCollect?: number, uniqueUsers?: boolean): Promise<[User, Position | null, AnchorPosition | null][] | []>;
|
|
3365
3367
|
}
|
|
3366
3368
|
|
|
3367
3369
|
declare class WebApi {
|