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,347 @@
1
+ class ItemCategory {
2
+ constructor(webapi, AxiosError) {
3
+ this.webapi = webapi;
4
+ this.logger = webapi.logger;
5
+ this.base = webapi.base;
6
+ this.AxiosErrorHandler = AxiosError
7
+ }
8
+
9
+ async get(itemId) {
10
+ const method = 'bot.webapi.item.get'
11
+
12
+ try {
13
+ if (!itemId || typeof itemId !== 'string') {
14
+ throw new TypeError('itemId must be a non-empty string');
15
+ }
16
+
17
+ const response = await this.base.get(`/items/${itemId}`);
18
+ if (response.status === 200 && response.data?.item) {
19
+ return this._formatItemDetail(response.data.item);
20
+ }
21
+ return null;
22
+ } catch (error) {
23
+ if (error instanceof TypeError) {
24
+ this.logger.error(method, `TypeError: ${error.message}`, { itemId }, error);
25
+ } else {
26
+ return this.AxiosErrorHandler.handle(error, this.logger, method, { itemId });
27
+ }
28
+ }
29
+ }
30
+
31
+ async list(params = {}) {
32
+ const method = 'bot.webapi.item.list'
33
+
34
+ const validatedParams = {
35
+ limit: Math.min(params.limit || 20, 100),
36
+ sort_order: params.sort_order || 'desc',
37
+ rarity: params.rarity,
38
+ item_name: params.item_name,
39
+ category: params.category,
40
+ starts_after: params.starts_after,
41
+ ends_before: params.ends_before
42
+ };
43
+
44
+ const AllowedSortOrder = ['asc', 'desc'];
45
+ const AllowedRarities = ['common', 'uncommon', 'rare', 'epic', 'legendary', 'none_'];
46
+ const AllowedCategories = [
47
+ 'bag', 'blush', 'body', 'dress', 'earrings', 'emote', 'eye', 'eyebrow',
48
+ 'face_hair', 'fishing_rod', 'freckle', 'glasses', 'gloves', 'hair_back',
49
+ 'hair_front', 'handbag', 'hat', 'jacket', 'lashes', 'mole', 'mouth',
50
+ 'necklace', 'nose', 'pants', 'shirt', 'shoes', 'shorts', 'skirt',
51
+ 'watch', 'fullsuit', 'sock', 'tattoo', 'rod', 'aura'
52
+ ];
53
+
54
+ try {
55
+ if (typeof params !== 'object') {
56
+ throw new TypeError('params must be an object');
57
+ }
58
+
59
+ if (validatedParams.limit <= 0 || validatedParams.limit > 100) {
60
+ throw new TypeError('limit must be between 1 and 100');
61
+ }
62
+
63
+ if (!AllowedSortOrder.includes(validatedParams.sort_order)) {
64
+ throw new TypeError(`sort_order must be one of: ${AllowedSortOrder.join(', ')}`);
65
+ }
66
+
67
+ if (validatedParams.rarity && !AllowedRarities.includes(validatedParams.rarity)) {
68
+ throw new TypeError(`rarity must be one of: ${AllowedRarities.join(', ')}`);
69
+ }
70
+
71
+ if (validatedParams.category && !AllowedCategories.includes(validatedParams.category)) {
72
+ throw new TypeError(`category must be one of: ${AllowedCategories.join(', ')}`);
73
+ }
74
+
75
+ const response = await this.base.get('/items', {
76
+ params: validatedParams
77
+ });
78
+
79
+ if (response.status === 200 && response.data?.items) {
80
+ return this._formatItemsList(response.data);
81
+ }
82
+
83
+ return null;
84
+
85
+ } catch (error) {
86
+ if (error instanceof TypeError) {
87
+ this.logger.error(method, `TypeError: ${error.message}`, { params }, error);
88
+ throw error;
89
+ } else {
90
+ return this.AxiosErrorHandler.handle(error, this.logger, method, { params });
91
+ }
92
+ }
93
+ }
94
+
95
+ async search(params = {}) {
96
+ const method = 'bot.webapi.item.search'
97
+
98
+ const validatedParams = {
99
+ limit: Math.min(params.limit || 20, 100),
100
+ skip: Math.max(params.skip || 0, 0),
101
+ query: params.query || ''
102
+ };
103
+
104
+ try {
105
+ if (typeof params !== 'object') {
106
+ throw new TypeError('params must be an object');
107
+ }
108
+
109
+ if (validatedParams.limit <= 0 || validatedParams.limit > 100) {
110
+ throw new TypeError('limit must be between 1 and 100');
111
+ }
112
+
113
+ if (typeof validatedParams.query !== 'string') {
114
+ throw new TypeError('query must be a string');
115
+ }
116
+
117
+ if (validatedParams.skip < 0) {
118
+ throw new TypeError('skip cannot be negative');
119
+ }
120
+
121
+ const response = await this.base.get('/items/search', {
122
+ params: validatedParams
123
+ });
124
+
125
+ if (response.status === 200 && response.data?.items) {
126
+ return this._formatItemsSearch(response.data);
127
+ }
128
+
129
+ return null;
130
+
131
+ } catch (error) {
132
+ if (error instanceof TypeError) {
133
+ this.logger.error(method, `TypeError: ${error.message}`, { params }, error);
134
+ throw error;
135
+ } else {
136
+ return this.AxiosErrorHandler.handle(error, this.logger, method, { params });
137
+ }
138
+ }
139
+ }
140
+
141
+ async searchByName(name, limit = 20) {
142
+ return this.search({ query: name, limit });
143
+ }
144
+
145
+ async getByCategory(category, limit = 20) {
146
+ return this.list({ category, limit });
147
+ }
148
+
149
+ async getByRarity(rarity, limit = 20) {
150
+ return this.list({ rarity, limit });
151
+ }
152
+
153
+ async getByName(name, limit = 20) {
154
+ return this.list({ item_name: name, limit });
155
+ }
156
+
157
+ async getRecent(limit = 20) {
158
+ return this.list({ limit, sort_order: 'desc' });
159
+ }
160
+
161
+ async getPurchasable(query = '', limit = 20) {
162
+ const result = await this.search({ query, limit });
163
+ if (result) {
164
+ return {
165
+ ...result,
166
+ items: result.items.filter(item => item.properties.isPurchasable)
167
+ };
168
+ }
169
+ return null;
170
+ }
171
+
172
+ async getTradable(query = '', limit = 20) {
173
+ const result = await this.search({ query, limit });
174
+ if (result) {
175
+ return {
176
+ ...result,
177
+ items: result.items.filter(item => item.properties.isTradable)
178
+ };
179
+ }
180
+ return null;
181
+ }
182
+
183
+ async getPurchasableByCategory(category, limit = 20) {
184
+ const result = await this.list({ category, limit });
185
+ if (result) {
186
+ return {
187
+ ...result,
188
+ items: result.items.filter(item => item.properties.isPurchasable)
189
+ };
190
+ }
191
+ return null;
192
+ }
193
+
194
+ async getTradableByCategory(category, limit = 20) {
195
+ const result = await this.list({ category, limit });
196
+ if (result) {
197
+ return {
198
+ ...result,
199
+ items: result.items.filter(item => item.properties.isTradable)
200
+ };
201
+ }
202
+ return null;
203
+ }
204
+
205
+ _formatItemsList(apiResponse) {
206
+ return {
207
+ items: apiResponse.items.map(item => this._formatItem(item)),
208
+ pagination: {
209
+ total: apiResponse.total,
210
+ firstId: apiResponse.first_id,
211
+ lastId: apiResponse.last_id,
212
+ hasMore: apiResponse.items.length > 0
213
+ }
214
+ };
215
+ }
216
+
217
+ _formatItemsSearch(apiResponse) {
218
+ return {
219
+ items: apiResponse.items.map(item => this._formatItem(item)),
220
+ pagination: {
221
+ total: apiResponse.total,
222
+ hasMore: apiResponse.items.length > 0,
223
+ skip: apiResponse.skip || 0
224
+ }
225
+ };
226
+ }
227
+
228
+ _formatItem(itemData) {
229
+ return {
230
+ id: itemData.item_id,
231
+ name: itemData.item_name,
232
+ category: itemData.category,
233
+ colorLinkedCategories: itemData.color_linked_categories,
234
+ colorPalettes: itemData.color_palettes,
235
+ createdAt: itemData.created_at,
236
+ description: itemData.description_key,
237
+ pricing: {
238
+ gems: itemData.gems_sale_price,
239
+ pops: itemData.pops_sale_price
240
+ },
241
+ properties: {
242
+ isPurchasable: itemData.is_purchasable || false,
243
+ isTradable: itemData.is_tradable || false
244
+ },
245
+ images: {
246
+ main: itemData.image_url,
247
+ icon: itemData.icon_url
248
+ },
249
+ links: {
250
+ linkIds: Array.isArray(itemData.link_ids) ? itemData.link_ids : [],
251
+ inspiredBy: itemData.inspired_by
252
+ },
253
+ skinParts: {
254
+ front: Array.isArray(itemData.m_front_skin_part_list)
255
+ ? itemData.m_front_skin_part_list.map(part => this._formatSkinPart(part))
256
+ : [],
257
+ back: Array.isArray(itemData.m_back_skin_part_list)
258
+ ? itemData.m_back_skin_part_list.map(part => this._formatSkinPart(part))
259
+ : []
260
+ },
261
+ metadata: {
262
+ dependentColors: itemData.m_dependent_colors,
263
+ releaseDate: itemData.release_date,
264
+ keywords: itemData.keywords
265
+ }
266
+ };
267
+ }
268
+
269
+ _formatItemDetail(itemData) {
270
+ return {
271
+ ...this._formatItem(itemData),
272
+ acquisition: {
273
+ cost: itemData.acquisition_cost,
274
+ amount: itemData.acquisition_amount,
275
+ currency: itemData.acquisition_currency
276
+ },
277
+ relatedItems: itemData.related_items ? this._formatRelatedItems(itemData.related_items) : null,
278
+ affiliations: Array.isArray(itemData.affiliations) ? itemData.affiliations.map(affil => this._formatAffiliation(affil)) : [],
279
+ storefrontListings: itemData.storefront_listings ? this._formatStorefrontListings(itemData.storefront_listings) : null
280
+ };
281
+ }
282
+
283
+ _formatSkinPart(skinPart) {
284
+ return {
285
+ bone: skinPart.bone,
286
+ slot: skinPart.slot,
287
+ imageFile: skinPart.image_file,
288
+ attachmentName: skinPart.attachment_name,
289
+ hasRemoteRenderLayer: skinPart.has_remote_render_layer || false
290
+ };
291
+ }
292
+
293
+ _formatRelatedItems(relatedItems) {
294
+ return {
295
+ items: Array.isArray(relatedItems.items) ? relatedItems.items.map(item => ({
296
+ id: item.item_id,
297
+ name: item.disp_name
298
+ })) : []
299
+ };
300
+ }
301
+
302
+ _formatAffiliation(affiliation) {
303
+ return {
304
+ id: affiliation.id,
305
+ title: affiliation.title,
306
+ type: affiliation.type,
307
+ eventType: affiliation.event_type
308
+ };
309
+ }
310
+
311
+ _formatStorefrontListings(storefront) {
312
+ return {
313
+ sellers: Array.isArray(storefront.sellers) ? storefront.sellers.map(seller => this._formatSeller(seller)) : [],
314
+ pages: storefront.pages || 0,
315
+ total: storefront.total || 0
316
+ };
317
+ }
318
+
319
+ _formatSeller(seller) {
320
+ return {
321
+ userId: seller.user_id,
322
+ username: seller.username,
323
+ outfit: Array.isArray(seller.outfit) ? seller.outfit.map(item => this._formatOutfitItem(item)) : [],
324
+ lastConnectedAt: seller.last_connected_at
325
+ };
326
+ }
327
+
328
+ _formatOutfitItem(outfitItem) {
329
+ return {
330
+ itemId: outfitItem.item_id,
331
+ name: outfitItem.name,
332
+ rarity: outfitItem.rarity,
333
+ activePalette: outfitItem.active_palette,
334
+ parts: outfitItem.parts,
335
+ colors: outfitItem.colors ? this._formatOutfitItemColors(outfitItem.colors) : null,
336
+ linkedColors: outfitItem.linked_colors
337
+ };
338
+ }
339
+
340
+ _formatOutfitItemColors(colors) {
341
+ return {
342
+ linkedColors: colors.linked_colors
343
+ };
344
+ }
345
+ }
346
+
347
+ module.exports = ItemCategory
@@ -0,0 +1,154 @@
1
+ class PostCategory {
2
+ constructor(webapi, AxiosError) {
3
+ this.webapi = webapi;
4
+ this.logger = webapi.logger;
5
+ this.base = webapi.base;
6
+ this.AxiosErrorHandler = AxiosError
7
+ }
8
+
9
+ async get(postId) {
10
+ const method = 'bot.webapi.post.get'
11
+
12
+ try {
13
+ if (!postId || typeof postId !== 'string') {
14
+ throw new TypeError('postId must be a non-empty string');
15
+ }
16
+
17
+ const response = await this.base.get(`/posts/${postId}`);
18
+ if (response.status === 200 && response.data?.post) {
19
+ return this._formatPostDetail(response.data.post);
20
+ }
21
+ return null;
22
+ } catch (error) {
23
+ if (error instanceof TypeError) {
24
+ this.logger.error(method, `TypeError: ${error.message}`, { postId }, error);
25
+ } else {
26
+ return this.AxiosErrorHandler.handle(error, this.logger, method, { postId });
27
+ }
28
+ }
29
+ }
30
+
31
+ async list(params = {}) {
32
+ const method = 'bot.webapi.post.list'
33
+
34
+ const validatedParams = {
35
+ limit: Math.min(params.limit || 20, 100),
36
+ sort_order: params.sort_order || 'desc',
37
+ author_id: params.author_id,
38
+ starts_after: params.starts_after,
39
+ ends_before: params.ends_before
40
+ };
41
+
42
+ const AllowedSortOrder = ['asc', 'desc'];
43
+
44
+ try {
45
+ if (typeof params !== 'object') {
46
+ throw new TypeError('params must be an object');
47
+ }
48
+
49
+ if (validatedParams.limit <= 0 || validatedParams.limit > 100) {
50
+ throw new TypeError('limit must be between 1 and 100');
51
+ }
52
+
53
+ if (!AllowedSortOrder.includes(validatedParams.sort_order)) {
54
+ throw new TypeError(`sort_order must be one of: ${AllowedSortOrder.join(', ')}`);
55
+ }
56
+
57
+ const response = await this.base.get('/posts', {
58
+ params: validatedParams
59
+ });
60
+
61
+ if (response.status === 200 && response.data?.posts) {
62
+ return this._formatPostsList(response.data);
63
+ }
64
+
65
+ return null;
66
+
67
+ } catch (error) {
68
+ if (error instanceof TypeError) {
69
+ this.logger.error(method, `TypeError: ${error.message}`, { params }, error);
70
+ throw error;
71
+ } else {
72
+ return this.AxiosErrorHandler.handle(error, this.logger, method, { params });
73
+ }
74
+ }
75
+ }
76
+
77
+ async getByAuthor(authorId, limit = 20) {
78
+ return this.list({ author_id: authorId, limit });
79
+ }
80
+
81
+ async getRecent(limit = 20) {
82
+ return this.list({ limit, sort_order: 'desc' });
83
+ }
84
+
85
+ _formatPostsList(apiResponse) {
86
+ return {
87
+ posts: apiResponse.posts.map(post => this._formatPostBasic(post)),
88
+ pagination: {
89
+ total: apiResponse.total,
90
+ firstId: apiResponse.first_id,
91
+ lastId: apiResponse.last_id,
92
+ hasMore: apiResponse.posts.length > 0
93
+ }
94
+ };
95
+ }
96
+
97
+ _formatPostBasic(postData) {
98
+ return {
99
+ id: postData.post_id,
100
+ authorId: postData.author_id,
101
+ createdAt: this.webapi._formatDate(postData.created_at),
102
+ type: postData.type,
103
+ visibility: postData.visibility,
104
+
105
+ stats: {
106
+ comments: postData.num_comments || 0,
107
+ likes: postData.num_likes || 0,
108
+ reposts: postData.num_reposts || 0
109
+ },
110
+
111
+ content: {
112
+ text: postData.text || '',
113
+ hasBody: !!postData.body,
114
+ caption: postData.caption
115
+ },
116
+
117
+ fileKey: postData.file_key,
118
+
119
+ featuredUserIds: Array.isArray(postData.featured_user_ids) ? postData.featured_user_ids : [],
120
+
121
+ inventory: postData.inventory ? this.webapi._formatInventory(postData.inventory) : null,
122
+
123
+ body: postData.body ? this._formatPostBody(postData.body) : null
124
+ };
125
+ }
126
+
127
+ _formatPostDetail(postData) {
128
+ return {
129
+ ...this._formatPostBasic(postData),
130
+ comments: Array.isArray(postData.comments) ? postData.comments.map(comment => this._formatComment(comment)) : []
131
+ };
132
+ }
133
+
134
+ _formatPostBody(body) {
135
+ if (!body) return null;
136
+ return {
137
+ text: body.text || '',
138
+ inventory: body.inventory ? this.webapi._formatInventory(body.inventory) : null
139
+ };
140
+ }
141
+
142
+ _formatComment(comment) {
143
+ return {
144
+ id: comment.id,
145
+ content: comment.content,
146
+ postId: comment.post_id,
147
+ authorId: comment.author_id,
148
+ authorName: comment.author_name,
149
+ likes: comment.num_likes || 0
150
+ };
151
+ }
152
+ }
153
+
154
+ module.exports = PostCategory
@@ -0,0 +1,137 @@
1
+ class RoomCategory {
2
+ constructor(webapi, AxiosError) {
3
+ this.webapi = webapi;
4
+ this.logger = webapi.logger;
5
+ this.base = webapi.base;
6
+ this.AxiosErrorHandler = AxiosError
7
+ }
8
+
9
+ async get(roomId) {
10
+ const method = 'bot.webapi.room.get'
11
+
12
+ try {
13
+ if (!roomId || typeof roomId !== 'string') {
14
+ throw new TypeError('roomId must be a non-empty string');
15
+ }
16
+
17
+ const response = await this.base.get(`/rooms/${roomId}`);
18
+ if (response.status === 200 && response.data?.room) {
19
+ return this._formatRoomDetail(response.data.room);
20
+ }
21
+
22
+ return null;
23
+ } catch (error) {
24
+ console.log(error)
25
+ if (error instanceof TypeError) {
26
+ this.logger.error(method, `TypeError: ${error.message}`, { roomId }, error);
27
+ } else {
28
+ return this.AxiosErrorHandler.handle(error, this.logger, method, { roomId });
29
+ }
30
+ }
31
+ }
32
+
33
+ async list(params = {}) {
34
+ const method = 'bot.webapi.room.list'
35
+
36
+ const validatedParams = {
37
+ limit: Math.min(params.limit || 20, 100),
38
+ sort_order: params.sort_order || 'desc',
39
+ room_name: params.room_name,
40
+ owner_id: params.owner_id,
41
+ starts_after: params.starts_after,
42
+ ends_before: params.ends_before
43
+ };
44
+
45
+ const AllowedSortOrder = ['asc', 'desc'];
46
+
47
+ try {
48
+ if (typeof params !== 'object') {
49
+ throw new TypeError('params must be an object');
50
+ }
51
+
52
+ if (validatedParams.limit <= 0 || validatedParams.limit > 100) {
53
+ throw new TypeError('limit must be between 1 and 100');
54
+ }
55
+
56
+ if (!AllowedSortOrder.includes(validatedParams.sort_order)) {
57
+ throw new TypeError(`sort_order must be one of: ${AllowedSortOrder.join(', ')}`);
58
+ }
59
+
60
+ const response = await this.base.get('/rooms', {
61
+ params: validatedParams
62
+ });
63
+
64
+ if (response.status === 200 && response.data?.rooms) {
65
+ return this._formatRoomsList(response.data);
66
+ }
67
+
68
+ return null;
69
+
70
+ } catch (error) {
71
+ if (error instanceof TypeError) {
72
+ this.logger.error(method, `TypeError: ${error.message}`, { params }, error);
73
+ throw error;
74
+ } else {
75
+ return this.AxiosErrorHandler.handle(error, this.logger, method, { params });
76
+ }
77
+ }
78
+ }
79
+
80
+ async getCurrentRoom() {
81
+ const room = await this.get(this.webapi.bot.info.room.id)
82
+ return room
83
+ }
84
+
85
+ async searchByName(name, limit = 20) {
86
+ return this.list({ room_name: name, limit });
87
+ }
88
+
89
+ async getByOwner(ownerId, limit = 20) {
90
+ return this.list({ owner_id: ownerId, limit });
91
+ }
92
+
93
+ async getRecent(limit = 20) {
94
+ return this.list({ limit, sort_order: 'desc' });
95
+ }
96
+
97
+ _formatRoomsList(apiResponse) {
98
+ return {
99
+ rooms: apiResponse.rooms.map(room => this._formatRoomBasic(room)),
100
+ pagination: {
101
+ total: apiResponse.total,
102
+ firstId: apiResponse.first_id,
103
+ lastId: apiResponse.last_id,
104
+ hasMore: apiResponse.rooms.length > 0
105
+ }
106
+ };
107
+ }
108
+
109
+ _formatRoomBasic(roomData) {
110
+ return {
111
+ id: roomData.room_id,
112
+ name: roomData.disp_name,
113
+ description: roomData.description,
114
+ category: roomData.category,
115
+ createdAt: this.webapi._formatDate(roomData.created_at),
116
+ accessPolicy: roomData.access_policy,
117
+ ownerId: roomData.owner_id,
118
+ languages: Array.isArray(roomData.locale) ? roomData.locale : [roomData.locale],
119
+ isHomeRoom: roomData.is_home_room,
120
+ designerIds: Array.isArray(roomData.designer_ids) ? roomData.designer_ids : [],
121
+ moderatorIds: Array.isArray(roomData.moderator_ids) ? roomData.moderator_ids : []
122
+ };
123
+ }
124
+
125
+ _formatRoomDetail(roomData) {
126
+ return {
127
+ ...this._formatRoomBasic(roomData),
128
+ connectedUsers: roomData.num_connected || 0,
129
+ thumbnail: roomData.thumbnail_url,
130
+ banner: roomData.banner_url,
131
+ crewId: roomData.crew_id,
132
+ bots: roomData.bots ? JSON.parse(roomData.bots) : [],
133
+ };
134
+ }
135
+ }
136
+
137
+ module.exports = RoomCategory