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.0",
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 = new Map();
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
- _validateParameters(method, filter, timeout, maxToCollect) {
48
- try {
49
- if (typeof filter !== 'function') {
50
- throw new TypeError(`Filter must be a function`);
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
- _createAwaiter(eventType, filter, timeout, maxToCollect, uniqueUsers = false) {
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
- if (timeout > 0) {
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
- for (const [awaiterId, awaiter] of this._pendingAwaiters) {
136
- if (awaiter.eventType === eventType) {
137
- try {
138
- this._validateEventArguments(eventType, eventArgs);
68
+ const awaiters = this._pendingAwaiters[eventType];
69
+ if (!awaiters) return;
139
70
 
140
- if (awaiter.uniqueUsers && eventArgs[0]?.id) {
141
- if (awaiter.seenUsers.has(eventArgs[0].id)) {
142
- continue;
143
- }
144
- awaiter.seenUsers.add(eventArgs[0].id);
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
- if (awaiter.collected.length >= awaiter.maxToCollect) {
151
- awaiter.resolve(awaiter.collected);
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
- this.ws._logger.error(`await.${eventType}`, error.message)
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
 
@@ -17,6 +17,7 @@ class MessageHandler {
17
17
  setImmediate(() => {
18
18
  try {
19
19
  const message = JSON.parse(data.toString());
20
+
20
21
  if (this.validateMessageStructure(message)) {
21
22
  this._processMessage(message);
22
23
  } else {
@@ -37,7 +37,7 @@ class RolesManager {
37
37
  this._startWebApiSync();
38
38
  this._startAutoSave();
39
39
  this.initialized = true;
40
- this.logger.success('RolesManager', 'Ready! Auto-syncing every 5 minutes.');
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();
@@ -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; // Using SDK's User type
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 {