@hieuxyz/rpc 1.0.8 → 1.0.91

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/README.md CHANGED
@@ -73,25 +73,26 @@ async function start() {
73
73
  .setSmallImage(new LocalImage(path.join(__dirname, 'vscode.png')), "VS Code");
74
74
 
75
75
  await client.rpc.build();
76
+ logger.info("Initial RPC has been set!");
76
77
 
77
- setTimeout(async () => {
78
- logger.info("Updating RPC details dynamically...");
78
+ setTimeout(() => {
79
+ logger.info("Clearing RPC and resetting builder...");
80
+ client.rpc.clear();
79
81
 
80
- // Change the necessary information
81
82
  client.rpc
82
- .setDetails("Reviewing pull requests")
83
- .setState("PR #01: Feature enhancement")
84
- .setParty(2, 5);
85
-
86
- await client.rpc.updateRPC();
83
+ .setName("On a break")
84
+ .setDetails("Thinking about the next feature")
85
+ .setLargeImage("mp:external/dZwPAoMNVxT5qYqecH3Mfgxv1RQEdtGBU8nAspOcAo4/https/c.tenor.com/fvuYGhI1vgUAAAAC/tenor.gif", "Coffee Time");
87
86
 
88
- logger.info("RPC has been dynamically updated!");
87
+ client.rpc.build();
88
+ logger.info("A new RPC has been set after clearing.");
89
89
 
90
- }, 15000);
90
+ }, 20000);
91
91
 
92
92
  process.on('SIGINT', () => {
93
93
  logger.info("SIGINT received. Closing connection...");
94
- client.close();
94
+ client.rpc.clear();
95
+ client.close(true);
95
96
  process.exit(0);
96
97
  });
97
98
  }
@@ -149,17 +150,34 @@ This is the main starting point.
149
150
 
150
151
  Main builder class for RPC.
151
152
 
152
- - `.setName(string)`: Activity name (first line).
153
- - `.setDetails(string)`: Activity details (second line).
154
- - `.setState(string)`: Activity status (third line).
155
- - `.setTimestamps(start?, end?)`: Set start/end time.
156
- - `.setParty(current, max)`: Set group information.
157
- - `.setLargeImage(RpcImage, text?)`: Set large image and caption.
158
- - `.setSmallImage(RpcImage, text?)`: Set thumbnail and caption.
159
- - `.setButtons(buttons[])`: Set buttons (up to 2).
160
- - `.setPlatform(platform)`: Lay the platform (`'desktop'`, `'xbox'`, `'ps5'`).
161
- - `.build()`: First RPC send.
162
- - `.updateRPC()`: Send updates to an existing RPC.(it just call build() lol)
153
+ #### Setter Methods
154
+ - `.setName(string)`: Sets the activity name (first line).
155
+ - `.setDetails(string)`: Sets the activity details (second line).
156
+ - `.setState(string)`: Sets the activity state (third line).
157
+ - `.setTimestamps(start?, end?)`: Sets the start and/or end times.
158
+ - `.setParty(current, max)`: Sets the party information.
159
+ - `.setLargeImage(RpcImage, text?)`: Sets the large image and its tooltip text.
160
+ - `.setSmallImage(RpcImage, text?)`: Sets the small image and its tooltip text.
161
+ - `.setButtons(buttons[])`: Sets up to two clickable buttons.
162
+ - `.setPlatform(platform)`: Sets the platform (`'desktop'`, `'xbox'`, etc.).
163
+ - `.setInstance(boolean)`: Marks the activity as a specific, joinable instance.
164
+ - `.setApplicationId(string)`: Sets a custom Application ID.
165
+ - `.setStatus('online' | ...)`: Sets the user's presence status.
166
+
167
+ #### Clearer Methods
168
+ - `.clearDetails()`: Removes the activity details.
169
+ - `.clearState()`: Removes the activity state.
170
+ - `.clearTimestamps()`: Removes the timestamps.
171
+ - `.clearParty()`: Removes the party information.
172
+ - `.clearLargeImage()`: Removes the large image and its text.
173
+ - `.clearSmallImage()`: Removes the small image and its text.
174
+ - `.clearButtons()`: Removes all buttons.
175
+ - `.clearInstance()`: Removes the instance flag.
176
+
177
+ #### Core Methods
178
+ - `.build()`: Builds and sends the presence payload to Discord.
179
+ - `.updateRPC()`: Builds and sends an updated presence payload. (Alias for `build()`).
180
+ - `.clear()`: Clears the entire Rich Presence from the user's profile and resets the builder to its default state.
163
181
 
164
182
  ### Types of images
165
183
 
@@ -33,7 +33,7 @@ class Client {
33
33
  */
34
34
  constructor(options) {
35
35
  if (!options.token) {
36
- throw new Error("Tokens are required to connect to Discord.");
36
+ throw new Error('Tokens are required to connect to Discord.');
37
37
  }
38
38
  this.token = options.token;
39
39
  this.imageService = new ImageService_1.ImageService(options.apiBaseUrl);
@@ -49,9 +49,9 @@ class Client {
49
49
  */
50
50
  async run() {
51
51
  this.websocket.connect();
52
- logger_1.logger.info("Waiting for Discord session to be ready...");
52
+ logger_1.logger.info('Waiting for Discord session to be ready...');
53
53
  await this.websocket.readyPromise;
54
- logger_1.logger.info("Client is ready to send Rich Presence updates.");
54
+ logger_1.logger.info('Client is ready to send Rich Presence updates.');
55
55
  }
56
56
  /**
57
57
  * Close the connection to Discord Gateway.
@@ -37,17 +37,18 @@ class DiscordWebSocket {
37
37
  */
38
38
  constructor(token, options) {
39
39
  if (!this.isTokenValid(token)) {
40
- throw new Error("Invalid token provided.");
40
+ throw new Error('Invalid token provided.');
41
41
  }
42
42
  this.token = token;
43
43
  this.options = options;
44
- this.readyPromise = new Promise(resolve => (this.resolveReady = resolve));
44
+ this.readyPromise = new Promise((resolve) => (this.resolveReady = resolve));
45
45
  }
46
46
  resetReadyPromise() {
47
- this.readyPromise = new Promise(resolve => (this.resolveReady = resolve));
47
+ this.readyPromise = new Promise((resolve) => (this.resolveReady = resolve));
48
48
  }
49
49
  isTokenValid(token) {
50
- return /^[a-zA-Z0-9_-]{24}\.[a-zA-Z0-9_-]{6}\.[a-zA-Z0-9_-]{38}$/.test(token) || /^mfa\.[a-zA-Z0-9_-]{84}$/.test(token);
50
+ return (/^[a-zA-Z0-9_-]{24}\.[a-zA-Z0-9_-]{6}\.[a-zA-Z0-9_-]{38}$/.test(token) ||
51
+ /^mfa\.[a-zA-Z0-9_-]{84}$/.test(token));
51
52
  }
52
53
  /**
53
54
  * Initiate connection to Discord Gateway.
@@ -55,13 +56,13 @@ class DiscordWebSocket {
55
56
  */
56
57
  connect() {
57
58
  if (this.isReconnecting) {
58
- logger_1.logger.info("Connection attempt aborted: reconnection already in progress.");
59
+ logger_1.logger.info('Connection attempt aborted: reconnection already in progress.');
59
60
  return;
60
61
  }
61
62
  this.permanentClose = false;
62
63
  this.isReconnecting = true;
63
64
  this.resetReadyPromise();
64
- const url = this.resumeGatewayUrl || "wss://gateway.discord.gg/?v=10&encoding=json";
65
+ const url = this.resumeGatewayUrl || 'wss://gateway.discord.gg/?v=10&encoding=json';
65
66
  logger_1.logger.info(`Attempting to connect to ${url}...`);
66
67
  this.ws = new ws_1.default(url);
67
68
  this.ws.on('open', () => {
@@ -73,7 +74,7 @@ class DiscordWebSocket {
73
74
  logger_1.logger.warn(`Connection closed: ${code} - ${reason.toString('utf-8')}`);
74
75
  this.cleanupHeartbeat();
75
76
  if (this.permanentClose) {
76
- logger_1.logger.info("Connection permanently closed by client. Not reconnecting.");
77
+ logger_1.logger.info('Connection permanently closed by client. Not reconnecting.');
77
78
  return;
78
79
  }
79
80
  if (this.isReconnecting)
@@ -90,7 +91,7 @@ class DiscordWebSocket {
90
91
  }, 500);
91
92
  }
92
93
  else {
93
- logger_1.logger.info("Not attempting to reconnect based on close code and client options.");
94
+ logger_1.logger.info('Not attempting to reconnect based on close code and client options.');
94
95
  }
95
96
  });
96
97
  this.ws.on('error', (err) => {
@@ -117,30 +118,30 @@ class DiscordWebSocket {
117
118
  case OpCode_1.OpCode.DISPATCH:
118
119
  if (payload.t === 'READY') {
119
120
  this.sessionId = payload.d.session_id;
120
- this.resumeGatewayUrl = payload.d.resume_gateway_url + "/?v=10&encoding=json";
121
+ this.resumeGatewayUrl = payload.d.resume_gateway_url + '/?v=10&encoding=json';
121
122
  logger_1.logger.info(`Session READY. Session ID: ${this.sessionId}. Resume URL set.`);
122
123
  this.resolveReady();
123
124
  }
124
125
  else if (payload.t === 'RESUMED') {
125
- logger_1.logger.info("The session has been successfully resumed.");
126
+ logger_1.logger.info('The session has been successfully resumed.');
126
127
  this.resolveReady();
127
128
  }
128
129
  break;
129
130
  case OpCode_1.OpCode.HEARTBEAT_ACK:
130
- logger_1.logger.info("Heartbeat acknowledged.");
131
+ logger_1.logger.info('Heartbeat acknowledged.');
131
132
  break;
132
133
  case OpCode_1.OpCode.INVALID_SESSION:
133
134
  logger_1.logger.warn(`Received INVALID_SESSION. Resumable: ${payload.d}`);
134
135
  if (payload.d) {
135
- this.ws?.close(4000, "Invalid session, attempting to resume.");
136
+ this.ws?.close(4000, 'Invalid session, attempting to resume.');
136
137
  }
137
138
  else {
138
- this.ws?.close(4004, "Invalid session, starting a new session.");
139
+ this.ws?.close(4004, 'Invalid session, starting a new session.');
139
140
  }
140
141
  break;
141
142
  case OpCode_1.OpCode.RECONNECT:
142
- logger_1.logger.info("Gateway requested RECONNECT. Closing to reconnect and resume.");
143
- this.ws?.close(4000, "Gateway requested reconnect.");
143
+ logger_1.logger.info('Gateway requested RECONNECT. Closing to reconnect and resume.');
144
+ this.ws?.close(4000, 'Gateway requested reconnect.');
144
145
  break;
145
146
  default:
146
147
  break;
@@ -154,7 +155,7 @@ class DiscordWebSocket {
154
155
  }
155
156
  this.heartbeatInterval = setInterval(() => {
156
157
  if (this.ws?.readyState !== ws_1.default.OPEN) {
157
- logger_1.logger.warn("Heartbeat skipped: WebSocket is not open.");
158
+ logger_1.logger.warn('Heartbeat skipped: WebSocket is not open.');
158
159
  this.cleanupHeartbeat();
159
160
  return;
160
161
  }
@@ -171,21 +172,21 @@ class DiscordWebSocket {
171
172
  identify() {
172
173
  const identifyPayload = (0, identify_1.getIdentifyPayload)(this.token);
173
174
  this.sendJson({ op: OpCode_1.OpCode.IDENTIFY, d: identifyPayload });
174
- logger_1.logger.info("Identify payload sent.");
175
+ logger_1.logger.info('Identify payload sent.');
175
176
  }
176
177
  resume() {
177
178
  if (!this.sessionId || this.sequence === null) {
178
- logger_1.logger.error("Attempted to resume without session ID or sequence. Falling back to identify.");
179
+ logger_1.logger.error('Attempted to resume without session ID or sequence. Falling back to identify.');
179
180
  this.identify();
180
181
  return;
181
182
  }
182
183
  const resumePayload = {
183
184
  token: this.token,
184
185
  session_id: this.sessionId,
185
- seq: this.sequence
186
+ seq: this.sequence,
186
187
  };
187
188
  this.sendJson({ op: OpCode_1.OpCode.RESUME, d: resumePayload });
188
- logger_1.logger.info("Resume payload sent.");
189
+ logger_1.logger.info('Resume payload sent.');
189
190
  }
190
191
  /**
191
192
  * Send presence update payload to Gateway.
@@ -193,14 +194,14 @@ class DiscordWebSocket {
193
194
  */
194
195
  sendActivity(presence) {
195
196
  this.sendJson({ op: OpCode_1.OpCode.PRESENCE_UPDATE, d: presence });
196
- logger_1.logger.info("Presence update sent.");
197
+ logger_1.logger.info('Presence update sent.');
197
198
  }
198
199
  sendJson(data) {
199
200
  if (this.ws?.readyState === ws_1.default.OPEN) {
200
201
  this.ws.send(JSON.stringify(data));
201
202
  }
202
203
  else {
203
- logger_1.logger.warn("Attempted to send data while WebSocket was not open.");
204
+ logger_1.logger.warn('Attempted to send data while WebSocket was not open.');
204
205
  }
205
206
  }
206
207
  /**
@@ -209,15 +210,15 @@ class DiscordWebSocket {
209
210
  */
210
211
  close(force = false) {
211
212
  if (force) {
212
- logger_1.logger.info("Forcing permanent closure. Reconnects will be disabled.");
213
+ logger_1.logger.info('Forcing permanent closure. Reconnects will be disabled.');
213
214
  this.permanentClose = true;
214
215
  }
215
216
  else {
216
- logger_1.logger.info("Closing connection manually...");
217
+ logger_1.logger.info('Closing connection manually...');
217
218
  }
218
219
  this.isReconnecting = false;
219
220
  if (this.ws) {
220
- this.ws.close(1000, "Client initiated closure");
221
+ this.ws.close(1000, 'Client initiated closure');
221
222
  }
222
223
  }
223
224
  cleanupHeartbeat() {
@@ -1,2 +1,2 @@
1
- import { IdentifyPayload } from "./types";
1
+ import { IdentifyPayload } from './types';
2
2
  export declare function getIdentifyPayload(token: string): IdentifyPayload;
@@ -6,9 +6,9 @@ function getIdentifyPayload(token) {
6
6
  token: token,
7
7
  capabilities: 65,
8
8
  properties: {
9
- os: "Windows",
10
- browser: "Discord Client",
11
- device: "hieuxyz©rpc",
9
+ os: 'Windows',
10
+ browser: 'Discord Client',
11
+ device: 'hieuxyz©rpc',
12
12
  },
13
13
  compress: false,
14
14
  };
@@ -1,4 +1,4 @@
1
- import { OpCode } from "./OpCode";
1
+ import { OpCode } from './OpCode';
2
2
  export declare enum ActivityType {
3
3
  Playing = 0,
4
4
  Streaming = 1,
@@ -32,6 +32,7 @@ export interface Activity {
32
32
  details?: string;
33
33
  state?: string;
34
34
  platform?: string;
35
+ instance?: boolean;
35
36
  party?: {
36
37
  id?: string;
37
38
  size?: [number, number];
@@ -1,7 +1,7 @@
1
- import { DiscordWebSocket } from "../gateway/DiscordWebSocket";
2
- import { SettableActivityType } from "../gateway/entities/types";
3
- import { ImageService } from "./ImageService";
4
- import { RpcImage } from "./RpcImage";
1
+ import { DiscordWebSocket } from '../gateway/DiscordWebSocket';
2
+ import { SettableActivityType } from '../gateway/entities/types';
3
+ import { ImageService } from './ImageService';
4
+ import { RpcImage } from './RpcImage';
5
5
  interface RpcButton {
6
6
  label: string;
7
7
  url: string;
@@ -27,6 +27,7 @@ export declare class HieuxyzRPC {
27
27
  private renewalInterval;
28
28
  constructor(websocket: DiscordWebSocket, imageService: ImageService);
29
29
  private _toRpcImage;
30
+ private cleanupNulls;
30
31
  private sanitize;
31
32
  /**
32
33
  * Name the operation (first line of RPC).
@@ -105,6 +106,20 @@ export declare class HieuxyzRPC {
105
106
  * @returns {this}
106
107
  */
107
108
  setPlatform(platform: DiscordPlatform): this;
109
+ /**
110
+ * Marks the activity as a joinable instance for the game.
111
+ * @param instance - Whether this activity is a specific instance.
112
+ * @returns {this}
113
+ */
114
+ setInstance(instance: boolean): this;
115
+ clearDetails(): this;
116
+ clearState(): this;
117
+ clearTimestamps(): this;
118
+ clearParty(): this;
119
+ clearButtons(): this;
120
+ clearInstance(): this;
121
+ clearLargeImage(): this;
122
+ clearSmallImage(): this;
108
123
  private getExpiryTime;
109
124
  private renewAssetIfNeeded;
110
125
  private startBackgroundRenewal;
@@ -125,5 +140,12 @@ export declare class HieuxyzRPC {
125
140
  * @returns {Promise<void>}
126
141
  */
127
142
  updateRPC(): Promise<void>;
143
+ /**
144
+ * Clears the current Rich Presence from Discord and resets the builder state.
145
+ * This sends an empty activity payload to Discord and then resets all configured
146
+ * options (name, details, images, etc.) to their default values, allowing you
147
+ * to build a new presence from scratch.
148
+ */
149
+ clear(): void;
128
150
  }
129
151
  export {};
@@ -42,7 +42,7 @@ class HieuxyzRPC {
42
42
  return new RpcImage_1.ExternalImage(source);
43
43
  }
44
44
  }
45
- catch (e) {
45
+ catch {
46
46
  logger_1.logger.warn(`Could not parse "${source}" into a valid URL. Treating as RawImage.`);
47
47
  return new RpcImage_1.RawImage(source);
48
48
  }
@@ -52,6 +52,9 @@ class HieuxyzRPC {
52
52
  }
53
53
  return new RpcImage_1.RawImage(source);
54
54
  }
55
+ cleanupNulls(obj) {
56
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== null && v !== undefined));
57
+ }
55
58
  sanitize(str, length = 128) {
56
59
  return str.length > length ? str.substring(0, length) : str;
57
60
  }
@@ -155,8 +158,8 @@ class HieuxyzRPC {
155
158
  */
156
159
  setButtons(buttons) {
157
160
  const validButtons = buttons.slice(0, 2);
158
- this.activity.buttons = validButtons.map(b => this.sanitize(b.label, 32));
159
- this.activity.metadata = { button_urls: validButtons.map(b => b.url) };
161
+ this.activity.buttons = validButtons.map((b) => this.sanitize(b.label, 32));
162
+ this.activity.metadata = { button_urls: validButtons.map((b) => b.url) };
160
163
  return this;
161
164
  }
162
165
  /**
@@ -167,7 +170,7 @@ class HieuxyzRPC {
167
170
  */
168
171
  setApplicationId(id) {
169
172
  if (!/^\d{18,19}$/.test(id)) {
170
- throw new Error("The app ID must be an 18 or 19 digit number.");
173
+ throw new Error('The app ID must be an 18 or 19 digit number.');
171
174
  }
172
175
  this.applicationId = id;
173
176
  return this;
@@ -190,6 +193,50 @@ class HieuxyzRPC {
190
193
  this.platform = platform;
191
194
  return this;
192
195
  }
196
+ /**
197
+ * Marks the activity as a joinable instance for the game.
198
+ * @param instance - Whether this activity is a specific instance.
199
+ * @returns {this}
200
+ */
201
+ setInstance(instance) {
202
+ this.activity.instance = instance;
203
+ return this;
204
+ }
205
+ clearDetails() {
206
+ this.activity.details = undefined;
207
+ return this;
208
+ }
209
+ clearState() {
210
+ this.activity.state = undefined;
211
+ return this;
212
+ }
213
+ clearTimestamps() {
214
+ this.activity.timestamps = undefined;
215
+ return this;
216
+ }
217
+ clearParty() {
218
+ this.activity.party = undefined;
219
+ return this;
220
+ }
221
+ clearButtons() {
222
+ this.activity.buttons = undefined;
223
+ this.activity.metadata = undefined;
224
+ return this;
225
+ }
226
+ clearInstance() {
227
+ this.activity.instance = undefined;
228
+ return this;
229
+ }
230
+ clearLargeImage() {
231
+ this.assets.large_image = undefined;
232
+ this.assets.large_text = undefined;
233
+ return this;
234
+ }
235
+ clearSmallImage() {
236
+ this.assets.small_image = undefined;
237
+ this.assets.small_text = undefined;
238
+ return this;
239
+ }
193
240
  getExpiryTime(assetKey) {
194
241
  if (!assetKey.startsWith('mp:attachments'))
195
242
  return null;
@@ -201,14 +248,14 @@ class HieuxyzRPC {
201
248
  return parseInt(expiresTimestamp, 16) * 1000;
202
249
  }
203
250
  }
204
- catch (e) {
251
+ catch {
205
252
  logger_1.logger.error(`Could not parse asset URL for expiry check: ${assetKey}`);
206
253
  }
207
254
  return null;
208
255
  }
209
256
  async renewAssetIfNeeded(cacheKey, assetKey) {
210
257
  const expiryTimeMs = this.getExpiryTime(assetKey);
211
- if (expiryTimeMs && expiryTimeMs < (Date.now() + 3600000)) {
258
+ if (expiryTimeMs && expiryTimeMs < Date.now() + 3600000) {
212
259
  logger_1.logger.info(`Asset ${cacheKey} is expiring soon. Renewing...`);
213
260
  const assetId = assetKey.split('mp:attachments/')[1];
214
261
  const newAsset = await this.imageService.renewImage(assetId);
@@ -225,7 +272,7 @@ class HieuxyzRPC {
225
272
  clearInterval(this.renewalInterval);
226
273
  }
227
274
  this.renewalInterval = setInterval(async () => {
228
- logger_1.logger.info("Running background asset renewal check...");
275
+ logger_1.logger.info('Running background asset renewal check...');
229
276
  for (const [cacheKey, assetKey] of this.resolvedAssetsCache.entries()) {
230
277
  await this.renewAssetIfNeeded(cacheKey, assetKey);
231
278
  }
@@ -238,14 +285,14 @@ class HieuxyzRPC {
238
285
  if (this.renewalInterval) {
239
286
  clearInterval(this.renewalInterval);
240
287
  this.renewalInterval = null;
241
- logger_1.logger.info("Stopped background asset renewal process.");
288
+ logger_1.logger.info('Stopped background asset renewal process.');
242
289
  }
243
290
  }
244
291
  async resolveImage(image) {
245
292
  if (!image)
246
293
  return undefined;
247
294
  const cacheKey = image.getCacheKey();
248
- let cachedAsset = this.resolvedAssetsCache.get(cacheKey);
295
+ const cachedAsset = this.resolvedAssetsCache.get(cacheKey);
249
296
  if (cachedAsset) {
250
297
  return await this.renewAssetIfNeeded(cacheKey, cachedAsset);
251
298
  }
@@ -267,16 +314,16 @@ class HieuxyzRPC {
267
314
  if (small_image)
268
315
  finalAssets.small_image = small_image;
269
316
  const finalActivity = { ...this.activity };
270
- finalActivity.assets = (large_image || small_image) ? finalAssets : undefined;
317
+ finalActivity.assets = large_image || small_image ? finalAssets : undefined;
271
318
  finalActivity.application_id = this.applicationId;
272
319
  finalActivity.platform = this.platform;
273
320
  if (!finalActivity.name) {
274
- finalActivity.name = "hieuxyzRPC";
321
+ finalActivity.name = 'hieuxyzRPC';
275
322
  }
276
323
  if (typeof finalActivity.type === 'undefined') {
277
324
  finalActivity.type = types_1.ActivityType.Playing;
278
325
  }
279
- return finalActivity;
326
+ return this.cleanupNulls(finalActivity);
280
327
  }
281
328
  /**
282
329
  * Build the final Rich Presence payload and send it to Discord.
@@ -300,5 +347,26 @@ class HieuxyzRPC {
300
347
  async updateRPC() {
301
348
  await this.build();
302
349
  }
350
+ /**
351
+ * Clears the current Rich Presence from Discord and resets the builder state.
352
+ * This sends an empty activity payload to Discord and then resets all configured
353
+ * options (name, details, images, etc.) to their default values, allowing you
354
+ * to build a new presence from scratch.
355
+ */
356
+ clear() {
357
+ const clearPayload = {
358
+ since: 0,
359
+ activities: [],
360
+ status: this.status,
361
+ afk: true,
362
+ };
363
+ this.websocket.sendActivity(clearPayload);
364
+ logger_1.logger.info('Rich Presence cleared from Discord.');
365
+ this.activity = {};
366
+ this.assets = {};
367
+ this.applicationId = '1416676323459469363'; // Reset to default
368
+ this.platform = 'desktop'; // Reset to default
369
+ logger_1.logger.info('RPC builder has been reset to its initial state.');
370
+ }
303
371
  }
304
372
  exports.HieuxyzRPC = HieuxyzRPC;
@@ -90,8 +90,8 @@ class ImageService {
90
90
  form.append('file_name', fileName);
91
91
  const response = await this.apiClient.post('/upload', form, {
92
92
  headers: {
93
- ...form.getHeaders()
94
- }
93
+ ...form.getHeaders(),
94
+ },
95
95
  });
96
96
  if (response.data && response.data.id) {
97
97
  return response.data.id;
@@ -51,6 +51,6 @@ export declare class LocalImage extends RpcImage {
51
51
  export declare class RawImage extends RpcImage {
52
52
  private assetKey;
53
53
  constructor(assetKey: string);
54
- resolve(imageService: ImageService): Promise<string | undefined>;
54
+ resolve(__imageService: ImageService): Promise<string | undefined>;
55
55
  getCacheKey(): string;
56
56
  }
@@ -105,7 +105,7 @@ class RawImage extends RpcImage {
105
105
  super();
106
106
  this.assetKey = assetKey;
107
107
  }
108
- async resolve(imageService) {
108
+ async resolve(__imageService) {
109
109
  return this.assetKey;
110
110
  }
111
111
  getCacheKey() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hieuxyz/rpc",
3
- "version": "1.0.8",
3
+ "version": "1.0.91",
4
4
  "description": "A Discord Rich Presence library for Node.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,7 +11,10 @@
11
11
  ],
12
12
  "scripts": {
13
13
  "build": "tsc",
14
- "dev": "node -r ts-node/register --env-file=.env examples/main.ts"
14
+ "dev": "node -r ts-node/register --env-file=.env examples/main.ts",
15
+ "lint": "eslint \"src/**/*.ts\" --report-unused-disable-directives --max-warnings 0",
16
+ "lint:fix": "eslint \"src/**/*.ts\" --fix",
17
+ "format": "prettier --write \"src/**/*.ts\" \"examples/**/*.ts\""
15
18
  },
16
19
  "keywords": [
17
20
  "discord",
@@ -25,9 +28,14 @@
25
28
  "ws": "^8.18.3"
26
29
  },
27
30
  "devDependencies": {
28
- "@types/node": "^24.5.2",
31
+ "@types/node": "^24.6.0",
29
32
  "@types/ws": "^8.18.1",
33
+ "eslint": "^9.36.0",
34
+ "eslint-config-prettier": "^10.1.8",
35
+ "eslint-plugin-prettier": "^5.5.4",
36
+ "prettier": "^3.6.2",
30
37
  "ts-node": "^10.9.2",
31
- "typescript": "^5.9.2"
38
+ "typescript": "^5.9.2",
39
+ "typescript-eslint": "^8.45.0"
32
40
  }
33
41
  }