multichat-ts 0.0.83 → 0.0.85

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.
@@ -9,6 +9,11 @@ export type Message = {
9
9
  id: string;
10
10
  raw_text: string;
11
11
  timestamp_sent: number;
12
+ resubscription?: {
13
+ id: string;
14
+ months: number;
15
+ subscribed_since_timestamp: string;
16
+ };
12
17
  user: {
13
18
  badges: Badge[];
14
19
  color: string;
@@ -20,7 +20,7 @@ export declare class KickPusher {
20
20
  getStoredExternalEmotes(): EmoteURLsByName;
21
21
  connect(channel?: {
22
22
  channelName?: string;
23
- }): Promise<void>;
23
+ }, get_channel?: (channelName: string) => Promise<GetChannelResponse | undefined>): Promise<void>;
24
24
  disconnect(): void;
25
25
  on<EventName extends EventNames>(event_name: EventName, callback_fn: EventCallbackFunctions[EventName]): void;
26
26
  private onSubscriptionSuccess;
@@ -163,8 +163,16 @@ export interface ChatMessageEvent {
163
163
  id: string;
164
164
  chatroom_id: number;
165
165
  content: string;
166
- type: string;
166
+ type: 'message' | 'celebration';
167
167
  created_at: string;
168
+ metadata?: {
169
+ celebration: {
170
+ created_at: string;
171
+ id: string;
172
+ total_months: number;
173
+ type: 'subscription_renewed';
174
+ };
175
+ };
168
176
  sender: {
169
177
  id: number;
170
178
  username: string;
@@ -37,15 +37,22 @@ export class KickPusher {
37
37
  getStoredExternalEmotes() {
38
38
  return this.assets.external_emotes;
39
39
  }
40
- async connect(channel) {
40
+ async connect(channel, get_channel = async (channelName) => {
41
+ const res = await fetch(`https://kick.com/api/v2/channels/${channelName}`, {
42
+ headers: {
43
+ accept: 'aplication/json',
44
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
45
+ },
46
+ });
47
+ const json = await res.json();
48
+ return json;
49
+ }) {
41
50
  if (channel?.channelName)
42
51
  this.channel_name = channel.channelName;
43
52
  if (!this.channel_name)
44
53
  return console.error('channel_name not specified');
45
54
  console.log(`connecting to ${this.channel_name}...`);
46
- const channel_response = await fetch(`https://kick.com/api/v2/channels/${this.channel_name}`)
47
- .then((res) => res.json())
48
- .then((json) => json);
55
+ const channel_response = await get_channel(this.channel_name);
49
56
  if (!channel_response)
50
57
  return console.error('Failed to connect to Kick.com chat');
51
58
  channel_response.subscriber_badges.forEach((subscriber_badge) => {
@@ -85,7 +92,6 @@ export class KickPusher {
85
92
  this.public_listeners.raw_message?.(data);
86
93
  const text = data.content;
87
94
  const emote_matches = [...data.content.matchAll(/\[emote:\d+:[a-zA-Z0-9]*\]/g)];
88
- console.log(emote_matches);
89
95
  const body = [];
90
96
  emote_matches.forEach((match) => {
91
97
  const emote_string = match[0];
@@ -135,7 +141,7 @@ export class KickPusher {
135
141
  });
136
142
  }
137
143
  body.sort((a, b) => a.start_inclusive - b.start_inclusive);
138
- this.public_listeners.message?.({
144
+ const message = {
139
145
  id: data.id,
140
146
  user: {
141
147
  id: `${data.sender.id}`,
@@ -172,6 +178,14 @@ export class KickPusher {
172
178
  },
173
179
  raw_text: data.content,
174
180
  timestamp_sent: Date.parse(data.created_at),
175
- });
181
+ };
182
+ if (data.type === 'celebration' && data.metadata?.celebration) {
183
+ message.resubscription = {
184
+ id: data.metadata.celebration.id,
185
+ months: data.metadata.celebration.total_months,
186
+ subscribed_since_timestamp: data.metadata.celebration.created_at,
187
+ };
188
+ }
189
+ this.public_listeners.message?.(message);
176
190
  }
177
191
  }
@@ -9,6 +9,11 @@ export type Message = {
9
9
  id: string;
10
10
  raw_text: string;
11
11
  timestamp_sent: number;
12
+ resubscription?: {
13
+ id: string;
14
+ months: number;
15
+ subscribed_since_timestamp: string;
16
+ };
12
17
  user: {
13
18
  badges: Badge[];
14
19
  color: string;
@@ -20,7 +20,7 @@ export declare class KickPusher {
20
20
  getStoredExternalEmotes(): EmoteURLsByName;
21
21
  connect(channel?: {
22
22
  channelName?: string;
23
- }): Promise<void>;
23
+ }, get_channel?: (channelName: string) => Promise<GetChannelResponse | undefined>): Promise<void>;
24
24
  disconnect(): void;
25
25
  on<EventName extends EventNames>(event_name: EventName, callback_fn: EventCallbackFunctions[EventName]): void;
26
26
  private onSubscriptionSuccess;
@@ -163,8 +163,16 @@ export interface ChatMessageEvent {
163
163
  id: string;
164
164
  chatroom_id: number;
165
165
  content: string;
166
- type: string;
166
+ type: 'message' | 'celebration';
167
167
  created_at: string;
168
+ metadata?: {
169
+ celebration: {
170
+ created_at: string;
171
+ id: string;
172
+ total_months: number;
173
+ type: 'subscription_renewed';
174
+ };
175
+ };
168
176
  sender: {
169
177
  id: number;
170
178
  username: string;
@@ -37,15 +37,22 @@ export class KickPusher {
37
37
  getStoredExternalEmotes() {
38
38
  return this.assets.external_emotes;
39
39
  }
40
- async connect(channel) {
40
+ async connect(channel, get_channel = async (channelName) => {
41
+ const res = await fetch(`https://kick.com/api/v2/channels/${channelName}`, {
42
+ headers: {
43
+ accept: 'aplication/json',
44
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
45
+ },
46
+ });
47
+ const json = await res.json();
48
+ return json;
49
+ }) {
41
50
  if (channel?.channelName)
42
51
  this.channel_name = channel.channelName;
43
52
  if (!this.channel_name)
44
53
  return console.error('channel_name not specified');
45
54
  console.log(`connecting to ${this.channel_name}...`);
46
- const channel_response = await fetch(`https://kick.com/api/v2/channels/${this.channel_name}`)
47
- .then((res) => res.json())
48
- .then((json) => json);
55
+ const channel_response = await get_channel(this.channel_name);
49
56
  if (!channel_response)
50
57
  return console.error('Failed to connect to Kick.com chat');
51
58
  channel_response.subscriber_badges.forEach((subscriber_badge) => {
@@ -85,7 +92,6 @@ export class KickPusher {
85
92
  this.public_listeners.raw_message?.(data);
86
93
  const text = data.content;
87
94
  const emote_matches = [...data.content.matchAll(/\[emote:\d+:[a-zA-Z0-9]*\]/g)];
88
- console.log(emote_matches);
89
95
  const body = [];
90
96
  emote_matches.forEach((match) => {
91
97
  const emote_string = match[0];
@@ -135,7 +141,7 @@ export class KickPusher {
135
141
  });
136
142
  }
137
143
  body.sort((a, b) => a.start_inclusive - b.start_inclusive);
138
- this.public_listeners.message?.({
144
+ const message = {
139
145
  id: data.id,
140
146
  user: {
141
147
  id: `${data.sender.id}`,
@@ -172,6 +178,14 @@ export class KickPusher {
172
178
  },
173
179
  raw_text: data.content,
174
180
  timestamp_sent: Date.parse(data.created_at),
175
- });
181
+ };
182
+ if (data.type === 'celebration' && data.metadata?.celebration) {
183
+ message.resubscription = {
184
+ id: data.metadata.celebration.id,
185
+ months: data.metadata.celebration.total_months,
186
+ subscribed_since_timestamp: data.metadata.celebration.created_at,
187
+ };
188
+ }
189
+ this.public_listeners.message?.(message);
176
190
  }
177
191
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multichat-ts",
3
- "version": "0.0.83",
3
+ "version": "0.0.85",
4
4
  "type": "module",
5
5
  "description": "Receive type-safe realtime events for chat-related messages on multiple platforms (Twitch, Kick)",
6
6
  "repository": {
@@ -10,6 +10,11 @@ export type Message = {
10
10
  id: string;
11
11
  raw_text: string;
12
12
  timestamp_sent: number;
13
+ resubscription?: {
14
+ id: string;
15
+ months: number;
16
+ subscribed_since_timestamp: string;
17
+ };
13
18
  user: {
14
19
  badges: Badge[];
15
20
  color: string;
@@ -65,15 +65,28 @@ export class KickPusher {
65
65
  return this.assets.external_emotes;
66
66
  }
67
67
 
68
- public async connect(channel?: { channelName?: string }) {
68
+ public async connect(
69
+ channel?: { channelName?: string },
70
+ get_channel: (channelName: string) => Promise<GetChannelResponse | undefined> = async (
71
+ channelName,
72
+ ) => {
73
+ const res = await fetch(`https://kick.com/api/v2/channels/${channelName}`, {
74
+ headers: {
75
+ accept: 'aplication/json',
76
+ 'user-agent':
77
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
78
+ },
79
+ });
80
+ const json = await res.json();
81
+ return json as GetChannelResponse | undefined;
82
+ },
83
+ ) {
69
84
  if (channel?.channelName) this.channel_name = channel.channelName;
70
85
  if (!this.channel_name) return console.error('channel_name not specified');
71
86
 
72
87
  console.log(`connecting to ${this.channel_name}...`);
73
88
 
74
- const channel_response = await fetch(`https://kick.com/api/v2/channels/${this.channel_name}`)
75
- .then((res) => res.json())
76
- .then((json) => json as GetChannelResponse | undefined);
89
+ const channel_response = await get_channel(this.channel_name);
77
90
 
78
91
  if (!channel_response) return console.error('Failed to connect to Kick.com chat');
79
92
 
@@ -89,7 +102,6 @@ export class KickPusher {
89
102
  this.socket = new Pusher(this.kick_pusher_key, {
90
103
  cluster: 'us2',
91
104
  });
92
-
93
105
  /*
94
106
  | 'App\\Events\\ChatMessageEvent'
95
107
  | 'App\\Events\\ChatroomClearEvent'
@@ -115,6 +127,14 @@ export class KickPusher {
115
127
  .bind('App\\Events\\GiftedSubscriptionsEvent', (data: ChatGiftedEvent) =>
116
128
  this.onChatGifted(data),
117
129
  );
130
+
131
+ /*
132
+ {"event":"App\\Events\\ChatMessageSentEvent","data":"{\"message\":{\"id\":\"e676ab50-d59c-43ae-b7cd-2b60c5b89c08\",\"message\":null,\"type\":\"info\",\"replied_to\":null,\"is_info\":null,\"link_preview\":null,\"chatroom_id\":5755510,\"role\":\"user\",\"created_at\":1736022879,\"action\":\"gift\",\"optional_message\":null,\"months_subscribed\":null,\"subscriptions_count\":5,\"giftedUsers\":[{\"username\":\"lovesxb1\",\"monthsSubscribed\":1},{\"username\":\"O7no\",\"monthsSubscribed\":1},{\"username\":\"viiRayan\",\"monthsSubscribed\":1},{\"username\":\"Shabib_3005\",\"monthsSubscribed\":1},{\"username\":\"Khadielja\",\"monthsSubscribed\":1}]},\"user\":{\"id\":34844645,\"username\":\"Jana_ai\",\"role\":\"user\",\"isSuperAdmin\":null,\"profile_thumb\":\"https:\\/\\/kick-files-prod.s3.us-west-2.amazonaws.com\\/images\\/user\\/34844645\\/profile_image\\/conversion\\/90b8d01a-acda-4cdb-896b-8ce6d40b6767-thumb.webp?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAS3MDRZGPDOOAYROR%2F20250104%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250104T203439Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Signature=ac0e479335c68c7be15861e9f78866410d64fa1627fc87433365f110901243c0\",\"verified\":false,\"follower_badges\":[],\"is_subscribed\":null,\"is_founder\":false,\"months_subscribed\":null,\"quantity_gifted\":0}}","channel":"chatrooms.5755510"}
133
+ */
134
+
135
+ /*
136
+ {"event":"App\\Events\\LuckyUsersWhoGotGiftSubscriptionsEvent","data":"{\"channel\":{\"id\":5789932,\"user_id\":5882384,\"slug\":\"sulaiman\",\"is_banned\":false,\"playback_url\":\"https:\\/\\/fa723fc1b171.us-west-2.playback.live-video.net\\/api\\/video\\/v1\\/us-west-2.196233775518.channel.L29JBfLzKok0.m3u8\",\"name_updated_at\":null,\"vod_enabled\":true,\"subscription_enabled\":true,\"is_affiliate\":false,\"can_host\":true,\"chatroom\":{\"id\":5755510,\"chatable_type\":\"App\\\\Models\\\\Channel\",\"channel_id\":5789932,\"created_at\":\"2023-06-08T08:24:23.000000Z\",\"updated_at\":\"2024-12-11T07:20:32.000000Z\",\"chat_mode_old\":\"public\",\"chat_mode\":\"public\",\"slow_mode\":false,\"chatable_id\":5789932,\"followers_mode\":true,\"subscribers_mode\":false,\"emotes_mode\":false,\"message_interval\":6,\"following_min_duration\":0}},\"usernames\":[\"lovesxb1\",\"O7no\",\"viiRayan\",\"Shabib_3005\",\"Khadielja\"],\"gifter_username\":\"Jana_ai\"}","channel":"channel.5789932"}
137
+ */
118
138
  }
119
139
 
120
140
  public disconnect() {
@@ -145,7 +165,6 @@ export class KickPusher {
145
165
  this.public_listeners.raw_message?.(data);
146
166
  const text = data.content;
147
167
  const emote_matches = [...data.content.matchAll(/\[emote:\d+:[a-zA-Z0-9]*\]/g)];
148
- console.log(emote_matches);
149
168
 
150
169
  const body: BodyComponent[] = [];
151
170
 
@@ -203,8 +222,7 @@ export class KickPusher {
203
222
  }
204
223
 
205
224
  body.sort((a, b) => a.start_inclusive - b.start_inclusive);
206
-
207
- this.public_listeners.message?.({
225
+ const message: Message = {
208
226
  id: data.id,
209
227
  user: {
210
228
  id: `${data.sender.id}`,
@@ -241,7 +259,16 @@ export class KickPusher {
241
259
  },
242
260
  raw_text: data.content,
243
261
  timestamp_sent: Date.parse(data.created_at),
244
- });
262
+ };
263
+
264
+ if (data.type === 'celebration' && data.metadata?.celebration) {
265
+ message.resubscription = {
266
+ id: data.metadata.celebration.id,
267
+ months: data.metadata.celebration.total_months,
268
+ subscribed_since_timestamp: data.metadata.celebration.created_at,
269
+ };
270
+ }
271
+ this.public_listeners.message?.(message);
245
272
  }
246
273
  }
247
274
 
@@ -381,8 +408,16 @@ export interface ChatMessageEvent {
381
408
  id: string;
382
409
  chatroom_id: number;
383
410
  content: string;
384
- type: string;
411
+ type: 'message' | 'celebration';
385
412
  created_at: string;
413
+ metadata?: {
414
+ celebration: {
415
+ created_at: string;
416
+ id: string;
417
+ total_months: number;
418
+ type: 'subscription_renewed';
419
+ };
420
+ };
386
421
  sender: {
387
422
  id: number;
388
423
  username: string;
@@ -1,168 +1,173 @@
1
- export * from './kick.js';
2
- export * from './twitch.js';
3
-
4
- export type Message = {
5
- body: BodyComponent[];
6
- channel: {
7
- room_id: string;
8
- name: string;
9
- };
10
- id: string;
11
- raw_text: string;
12
- timestamp_sent: number;
13
- user: {
14
- badges: Badge[];
15
- color: string;
16
- id: string;
17
- username: string;
18
- display_name: string;
19
- roles: {
20
- [role in 'vip' | 'moderator' | 'turbo' | 'admin' | 'global_moderator' | 'staff']?: boolean;
21
- };
22
- };
23
- };
24
-
25
- export type ClearMessages = {
26
- channel: {
27
- room_id: string;
28
- name: string;
29
- };
30
- user?: {
31
- id: string;
32
- username: string;
33
- };
34
- timeout_duration_seconds?: number | undefined;
35
- timestamp_sent: number;
36
- };
37
-
38
- export type DeleteMessage = {
39
- channel: {
40
- room_id?: string;
41
- name: string;
42
- };
43
- user?: {
44
- username: string;
45
- };
46
- id: string;
47
- raw_text: string;
48
- timestamp_sent: number;
49
- };
50
-
51
- type EventData = {
52
- subscription: {
53
- months: number;
54
- streak?: number;
55
- subscription_plan: {
56
- type: 'prime' | 1000 | 2000 | 3000;
57
- name: string;
58
- };
59
- gift_upgrade?: {
60
- gift_total: number;
61
- promo_name: string;
62
- sender: {
63
- username: string;
64
- display_name: string;
65
- };
66
- };
67
- };
68
- gift: {
69
- months: number;
70
- recipient: {
71
- id: string;
72
- username: string;
73
- display_name: string;
74
- };
75
- subscription_plan: {
76
- type: 'prime' | 1000 | 2000 | 3000;
77
- name: string;
78
- };
79
- };
80
- raid: {
81
- sender: {
82
- username: string;
83
- display_name: string;
84
- viewer_count: number;
85
- };
86
- };
87
- };
88
-
89
- export type Event = {
90
- [E in keyof EventData]: {
91
- type: E;
92
- body: BodyComponent[];
93
- channel: {
94
- room_id: string;
95
- name: string;
96
- };
97
- id: string;
98
- raw_text: string;
99
- system_message: string;
100
- timestamp_sent: number;
101
- user: {
102
- badges: Badge[];
103
- color: string;
104
- id: string;
105
- username: string;
106
- display_name: string;
107
- roles: {
108
- [role in
109
- | 'moderator'
110
- | 'subscriber'
111
- | 'turbo'
112
- | 'admin'
113
- | 'global_moderator'
114
- | 'staff']?: boolean;
115
- };
116
- };
117
- data: EventData[E];
118
- };
119
- }[keyof EventData];
120
-
121
- export type BodyComponentEmote = {
122
- end_exclusive: number;
123
- start_inclusive: number;
124
- type: 'emote';
125
- url: string;
126
- };
127
-
128
- export type BodyComponent =
129
- | {
130
- end_exclusive: number;
131
- label: string;
132
- start_inclusive: number;
133
- type: 'link';
134
- url: string;
135
- }
136
- | {
137
- end_exclusive: number;
138
- start_inclusive: number;
139
- text: string;
140
- type: 'text';
141
- }
142
- | BodyComponentEmote;
143
-
144
- type Badge = {
145
- info?: string | undefined;
146
- set_id: string;
147
- url: string;
148
- };
149
-
150
- export type BadgeURLsByNameOrCount = {
151
- [badge_name: string]:
152
- | string
153
- | {
154
- [badge_count: number]: string;
155
- };
156
- };
157
-
158
- export type BadgeURLsBySetIDOrSetIDAndVersion = {
159
- [set_id: string]:
160
- | {
161
- [version: string]: string;
162
- }
163
- | string;
164
- };
165
-
166
- export type EmoteURLsByName = {
167
- [emote_name: string]: string;
168
- };
1
+ export * from './kick.js';
2
+ export * from './twitch.js';
3
+
4
+ export type Message = {
5
+ body: BodyComponent[];
6
+ channel: {
7
+ room_id: string;
8
+ name: string;
9
+ };
10
+ id: string;
11
+ raw_text: string;
12
+ timestamp_sent: number;
13
+ resubscription?: {
14
+ id: string;
15
+ months: number;
16
+ subscribed_since_timestamp: string;
17
+ };
18
+ user: {
19
+ badges: Badge[];
20
+ color: string;
21
+ id: string;
22
+ username: string;
23
+ display_name: string;
24
+ roles: {
25
+ [role in 'vip' | 'moderator' | 'turbo' | 'admin' | 'global_moderator' | 'staff']?: boolean;
26
+ };
27
+ };
28
+ };
29
+
30
+ export type ClearMessages = {
31
+ channel: {
32
+ room_id: string;
33
+ name: string;
34
+ };
35
+ user?: {
36
+ id: string;
37
+ username: string;
38
+ };
39
+ timeout_duration_seconds?: number | undefined;
40
+ timestamp_sent: number;
41
+ };
42
+
43
+ export type DeleteMessage = {
44
+ channel: {
45
+ room_id?: string;
46
+ name: string;
47
+ };
48
+ user?: {
49
+ username: string;
50
+ };
51
+ id: string;
52
+ raw_text: string;
53
+ timestamp_sent: number;
54
+ };
55
+
56
+ type EventData = {
57
+ subscription: {
58
+ months: number;
59
+ streak?: number;
60
+ subscription_plan: {
61
+ type: 'prime' | 1000 | 2000 | 3000;
62
+ name: string;
63
+ };
64
+ gift_upgrade?: {
65
+ gift_total: number;
66
+ promo_name: string;
67
+ sender: {
68
+ username: string;
69
+ display_name: string;
70
+ };
71
+ };
72
+ };
73
+ gift: {
74
+ months: number;
75
+ recipient: {
76
+ id: string;
77
+ username: string;
78
+ display_name: string;
79
+ };
80
+ subscription_plan: {
81
+ type: 'prime' | 1000 | 2000 | 3000;
82
+ name: string;
83
+ };
84
+ };
85
+ raid: {
86
+ sender: {
87
+ username: string;
88
+ display_name: string;
89
+ viewer_count: number;
90
+ };
91
+ };
92
+ };
93
+
94
+ export type Event = {
95
+ [E in keyof EventData]: {
96
+ type: E;
97
+ body: BodyComponent[];
98
+ channel: {
99
+ room_id: string;
100
+ name: string;
101
+ };
102
+ id: string;
103
+ raw_text: string;
104
+ system_message: string;
105
+ timestamp_sent: number;
106
+ user: {
107
+ badges: Badge[];
108
+ color: string;
109
+ id: string;
110
+ username: string;
111
+ display_name: string;
112
+ roles: {
113
+ [role in
114
+ | 'moderator'
115
+ | 'subscriber'
116
+ | 'turbo'
117
+ | 'admin'
118
+ | 'global_moderator'
119
+ | 'staff']?: boolean;
120
+ };
121
+ };
122
+ data: EventData[E];
123
+ };
124
+ }[keyof EventData];
125
+
126
+ export type BodyComponentEmote = {
127
+ end_exclusive: number;
128
+ start_inclusive: number;
129
+ type: 'emote';
130
+ url: string;
131
+ };
132
+
133
+ export type BodyComponent =
134
+ | {
135
+ end_exclusive: number;
136
+ label: string;
137
+ start_inclusive: number;
138
+ type: 'link';
139
+ url: string;
140
+ }
141
+ | {
142
+ end_exclusive: number;
143
+ start_inclusive: number;
144
+ text: string;
145
+ type: 'text';
146
+ }
147
+ | BodyComponentEmote;
148
+
149
+ type Badge = {
150
+ info?: string | undefined;
151
+ set_id: string;
152
+ url: string;
153
+ };
154
+
155
+ export type BadgeURLsByNameOrCount = {
156
+ [badge_name: string]:
157
+ | string
158
+ | {
159
+ [badge_count: number]: string;
160
+ };
161
+ };
162
+
163
+ export type BadgeURLsBySetIDOrSetIDAndVersion = {
164
+ [set_id: string]:
165
+ | {
166
+ [version: string]: string;
167
+ }
168
+ | string;
169
+ };
170
+
171
+ export type EmoteURLsByName = {
172
+ [emote_name: string]: string;
173
+ };