@hieuxyz/rpc 1.1.11 → 1.2.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.
- package/README.md +1 -1
- package/dist/hieuxyz/Client.d.ts +17 -3
- package/dist/hieuxyz/Client.js +142 -3
- package/dist/hieuxyz/gateway/DiscordWebSocket.d.ts +6 -2
- package/dist/hieuxyz/gateway/DiscordWebSocket.js +9 -2
- package/dist/hieuxyz/gateway/entities/types.d.ts +82 -0
- package/dist/hieuxyz/gateway/entities/types.js +19 -1
- package/dist/hieuxyz/rpc/HieuxyzRPC.d.ts +11 -2
- package/dist/hieuxyz/rpc/HieuxyzRPC.js +41 -5
- package/dist/hieuxyz/rpc/ImageService.d.ts +11 -0
- package/dist/hieuxyz/rpc/ImageService.js +17 -0
- package/dist/hieuxyz/rpc/RpcImage.d.ts +13 -0
- package/dist/hieuxyz/rpc/RpcImage.js +22 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @hieuxyz/rpc
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@hieuxyz/rpc)
|
|
4
|
-
[](https://github.com/
|
|
4
|
+
[](https://github.com/hieuxyz00/hieuxyz_rpc/blob/master/LICENSE)
|
|
5
5
|
[](https://www.npmjs.com/package/@hieuxyz/rpc)
|
|
6
6
|
|
|
7
7
|
An easy-to-use and powerful Discord Rich Presence (RPC) library built for the Node.js environment using TypeScript. This library is designed to simplify the creation and management of custom RPC states for Discord user accounts.
|
package/dist/hieuxyz/Client.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HieuxyzRPC } from './rpc/HieuxyzRPC';
|
|
2
2
|
import { ClientProperties } from './gateway/entities/identify';
|
|
3
|
+
import { DiscordUser } from './gateway/entities/types';
|
|
3
4
|
/**
|
|
4
5
|
* Option to initialize Client.
|
|
5
6
|
*/
|
|
@@ -42,6 +43,11 @@ export declare class Client {
|
|
|
42
43
|
* Use this to set your Rich Presence state details.
|
|
43
44
|
*/
|
|
44
45
|
readonly rpc: HieuxyzRPC;
|
|
46
|
+
/**
|
|
47
|
+
* Information about the logged-in user.
|
|
48
|
+
* Populated after run() resolves.
|
|
49
|
+
*/
|
|
50
|
+
user: DiscordUser | null;
|
|
45
51
|
private readonly websocket;
|
|
46
52
|
private readonly imageService;
|
|
47
53
|
private readonly token;
|
|
@@ -51,15 +57,23 @@ export declare class Client {
|
|
|
51
57
|
* @throws {Error} If no token is provided in the options.
|
|
52
58
|
*/
|
|
53
59
|
constructor(options: ClientOptions);
|
|
60
|
+
/**
|
|
61
|
+
* Displays information about the library.
|
|
62
|
+
*/
|
|
63
|
+
private printAbout;
|
|
54
64
|
/**
|
|
55
65
|
* Connect to Discord Gateway and prepare the client for RPC updates.
|
|
56
66
|
* This method must be called before sending any Rich Presence updates.
|
|
57
|
-
* @returns {Promise<
|
|
67
|
+
* @returns {Promise<DiscordUser>} A promise will be resolved when the client is ready.
|
|
58
68
|
*/
|
|
59
|
-
run(): Promise<
|
|
69
|
+
run(): Promise<DiscordUser>;
|
|
70
|
+
private formatters;
|
|
71
|
+
private formatFlags;
|
|
72
|
+
private printDynamicTree;
|
|
73
|
+
private logUserProfile;
|
|
60
74
|
/**
|
|
61
75
|
* Close the connection to Discord Gateway.
|
|
62
|
-
* @param {boolean} [force=false] - If true, the client
|
|
76
|
+
* @param {boolean} [force=false] - If true, the client closes permanently and will not reconnect.
|
|
63
77
|
* even if `alwaysReconnect` is enabled. Defaults to false.
|
|
64
78
|
*/
|
|
65
79
|
close(force?: boolean): void;
|
package/dist/hieuxyz/Client.js
CHANGED
|
@@ -5,6 +5,7 @@ const DiscordWebSocket_1 = require("./gateway/DiscordWebSocket");
|
|
|
5
5
|
const HieuxyzRPC_1 = require("./rpc/HieuxyzRPC");
|
|
6
6
|
const ImageService_1 = require("./rpc/ImageService");
|
|
7
7
|
const logger_1 = require("./utils/logger");
|
|
8
|
+
const types_1 = require("./gateway/entities/types");
|
|
8
9
|
/**
|
|
9
10
|
* The main Client class for interacting with Discord Rich Presence.
|
|
10
11
|
* This is the starting point for creating and managing your RPC state.
|
|
@@ -23,6 +24,11 @@ class Client {
|
|
|
23
24
|
* Use this to set your Rich Presence state details.
|
|
24
25
|
*/
|
|
25
26
|
rpc;
|
|
27
|
+
/**
|
|
28
|
+
* Information about the logged-in user.
|
|
29
|
+
* Populated after run() resolves.
|
|
30
|
+
*/
|
|
31
|
+
user = null;
|
|
26
32
|
websocket;
|
|
27
33
|
imageService;
|
|
28
34
|
token;
|
|
@@ -43,21 +49,154 @@ class Client {
|
|
|
43
49
|
connectionTimeout: options.connectionTimeout,
|
|
44
50
|
});
|
|
45
51
|
this.rpc = new HieuxyzRPC_1.HieuxyzRPC(this.websocket, this.imageService);
|
|
52
|
+
this.printAbout();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Displays information about the library.
|
|
56
|
+
*/
|
|
57
|
+
printAbout() {
|
|
58
|
+
const version = '1.2.0';
|
|
59
|
+
console.log(`
|
|
60
|
+
_ _
|
|
61
|
+
| |__ (_) ___ _ ___ ___ _ ______
|
|
62
|
+
| '_ \\| |/ _ \\ | | \\ \\/ / | | |_ /
|
|
63
|
+
| | | | | __/ |_| |> <| |_| |/ /
|
|
64
|
+
|_| |_|_|\\___|\\__,_/_/\\_\\\\__, /___|
|
|
65
|
+
|___/
|
|
66
|
+
@hieuxyz/rpc v${version}
|
|
67
|
+
A powerful Discord Rich Presence library.
|
|
68
|
+
Developed by: hieuxyz
|
|
69
|
+
`);
|
|
46
70
|
}
|
|
47
71
|
/**
|
|
48
72
|
* Connect to Discord Gateway and prepare the client for RPC updates.
|
|
49
73
|
* This method must be called before sending any Rich Presence updates.
|
|
50
|
-
* @returns {Promise<
|
|
74
|
+
* @returns {Promise<DiscordUser>} A promise will be resolved when the client is ready.
|
|
51
75
|
*/
|
|
52
76
|
async run() {
|
|
53
77
|
this.websocket.connect();
|
|
54
78
|
logger_1.logger.info('Waiting for Discord session to be ready...');
|
|
55
|
-
await this.websocket.readyPromise;
|
|
79
|
+
const user = await this.websocket.readyPromise;
|
|
80
|
+
this.user = user;
|
|
81
|
+
this.logUserProfile(user);
|
|
56
82
|
logger_1.logger.info('Client is ready to send Rich Presence updates.');
|
|
83
|
+
return user;
|
|
84
|
+
}
|
|
85
|
+
formatters = {
|
|
86
|
+
email: (val) => (val ? `\x1b[90m<Hidden>\x1b[0m` : 'null'),
|
|
87
|
+
phone: (val) => (val ? `\x1b[90m<Hidden>\x1b[0m` : 'null'),
|
|
88
|
+
avatar: (val, parent) => {
|
|
89
|
+
if (!val)
|
|
90
|
+
return 'null';
|
|
91
|
+
const ext = val.startsWith('a_') ? 'gif' : 'png';
|
|
92
|
+
const userId = parent?.id;
|
|
93
|
+
const url = userId ? `https://cdn.discordapp.com/avatars/${userId}/${val}.${ext}` : '';
|
|
94
|
+
return `"${val}" ${url ? `(\x1b[34m${url}\x1b[0m)` : ''}`;
|
|
95
|
+
},
|
|
96
|
+
banner: (val, parent) => {
|
|
97
|
+
if (!val)
|
|
98
|
+
return 'null';
|
|
99
|
+
const ext = val.startsWith('a_') ? 'gif' : 'png';
|
|
100
|
+
const userId = parent?.id;
|
|
101
|
+
const url = userId ? `https://cdn.discordapp.com/banners/${userId}/${val}.${ext}` : '';
|
|
102
|
+
return `"${val}" ${url ? `(\x1b[34m${url}\x1b[0m)` : ''}`;
|
|
103
|
+
},
|
|
104
|
+
asset: (val) => {
|
|
105
|
+
const url = `https://cdn.discordapp.com/avatar-decoration-presets/${val}.png`;
|
|
106
|
+
return `"${val}" (\x1b[34m${url}\x1b[0m)`;
|
|
107
|
+
},
|
|
108
|
+
accent_color: (val) => `${val} (\x1b[33m#${val.toString(16).padStart(6, '0').toUpperCase()}\x1b[0m)`,
|
|
109
|
+
banner_color: (val) => `\x1b[33m${val}\x1b[0m`,
|
|
110
|
+
expires_at: (val) => (val ? `${val} (${new Date(val).toLocaleString()})` : 'Never'),
|
|
111
|
+
premium_type: (val) => {
|
|
112
|
+
const map = { 0: 'None', 1: 'Classic', 2: 'Nitro', 3: 'Basic' };
|
|
113
|
+
return `${val} (\x1b[32m${map[val] || 'Unknown'}\x1b[0m)`;
|
|
114
|
+
},
|
|
115
|
+
flags: (val) => this.formatFlags(val),
|
|
116
|
+
public_flags: (val) => this.formatFlags(val),
|
|
117
|
+
purchased_flags: (val) => `\x1b[33m${val}\x1b[0m`,
|
|
118
|
+
};
|
|
119
|
+
formatFlags(flags) {
|
|
120
|
+
const flagNames = [];
|
|
121
|
+
if (flags & types_1.UserFlags.STAFF)
|
|
122
|
+
flagNames.push('Staff');
|
|
123
|
+
if (flags & types_1.UserFlags.PARTNER)
|
|
124
|
+
flagNames.push('Partner');
|
|
125
|
+
if (flags & types_1.UserFlags.HYPESQUAD)
|
|
126
|
+
flagNames.push('HypeSquad');
|
|
127
|
+
if (flags & types_1.UserFlags.BUG_HUNTER_LEVEL_1)
|
|
128
|
+
flagNames.push('BugHunter I');
|
|
129
|
+
if (flags & types_1.UserFlags.HYPESQUAD_ONLINE_HOUSE_1)
|
|
130
|
+
flagNames.push('Bravery');
|
|
131
|
+
if (flags & types_1.UserFlags.HYPESQUAD_ONLINE_HOUSE_2)
|
|
132
|
+
flagNames.push('Brilliance');
|
|
133
|
+
if (flags & types_1.UserFlags.HYPESQUAD_ONLINE_HOUSE_3)
|
|
134
|
+
flagNames.push('Balance');
|
|
135
|
+
if (flags & types_1.UserFlags.PREMIUM_EARLY_SUPPORTER)
|
|
136
|
+
flagNames.push('EarlySupporter');
|
|
137
|
+
if (flags & types_1.UserFlags.BUG_HUNTER_LEVEL_2)
|
|
138
|
+
flagNames.push('BugHunter II');
|
|
139
|
+
if (flags & types_1.UserFlags.VERIFIED_DEVELOPER)
|
|
140
|
+
flagNames.push('VerifiedDev');
|
|
141
|
+
if (flags & types_1.UserFlags.CERTIFIED_MODERATOR)
|
|
142
|
+
flagNames.push('CertifiedMod');
|
|
143
|
+
if (flags & types_1.UserFlags.ACTIVE_DEVELOPER)
|
|
144
|
+
flagNames.push('ActiveDev');
|
|
145
|
+
return `${flags} \x1b[36m[${flagNames.length > 0 ? flagNames.join(', ') : 'None'}]\x1b[0m`;
|
|
146
|
+
}
|
|
147
|
+
printDynamicTree(obj, prefix = '') {
|
|
148
|
+
const entries = Object.entries(obj);
|
|
149
|
+
entries.forEach(([key, value], index) => {
|
|
150
|
+
const isLastItem = index === entries.length - 1;
|
|
151
|
+
const connector = isLastItem ? '└── ' : '├── ';
|
|
152
|
+
const childPrefix = prefix + (isLastItem ? ' ' : '│ ');
|
|
153
|
+
let displayValue = '';
|
|
154
|
+
let isObject = false;
|
|
155
|
+
if (value === null) {
|
|
156
|
+
displayValue = '\x1b[90mnull\x1b[0m';
|
|
157
|
+
}
|
|
158
|
+
else if (typeof value === 'object' && !Array.isArray(value)) {
|
|
159
|
+
isObject = true;
|
|
160
|
+
console.log(`${prefix}${connector}\x1b[1m${key}\x1b[0m`);
|
|
161
|
+
this.printDynamicTree(value, childPrefix);
|
|
162
|
+
}
|
|
163
|
+
else if (Array.isArray(value)) {
|
|
164
|
+
if (value.length > 0 && typeof value[0] !== 'object') {
|
|
165
|
+
displayValue = `[ ${value.join(', ')} ]`;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
displayValue = `[Array(${value.length})]`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
if (this.formatters[key]) {
|
|
173
|
+
displayValue = this.formatters[key](value, obj);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
if (typeof value === 'string')
|
|
177
|
+
displayValue = `"\x1b[32m${value}\x1b[0m"`;
|
|
178
|
+
else if (typeof value === 'boolean')
|
|
179
|
+
displayValue = value ? '\x1b[32mtrue\x1b[0m' : '\x1b[31mfalse\x1b[0m';
|
|
180
|
+
else if (typeof value === 'number')
|
|
181
|
+
displayValue = `\x1b[33m${value}\x1b[0m`;
|
|
182
|
+
else
|
|
183
|
+
displayValue = String(value);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (!isObject) {
|
|
187
|
+
console.log(`${prefix}${connector}${key}: ${displayValue}`);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
logUserProfile(user) {
|
|
192
|
+
logger_1.logger.info('-> User Data:');
|
|
193
|
+
this.printDynamicTree(user);
|
|
194
|
+
/*logger.info('-> Raw JSON:');
|
|
195
|
+
console.log(JSON.stringify(user));*/
|
|
57
196
|
}
|
|
58
197
|
/**
|
|
59
198
|
* Close the connection to Discord Gateway.
|
|
60
|
-
* @param {boolean} [force=false] - If true, the client
|
|
199
|
+
* @param {boolean} [force=false] - If true, the client closes permanently and will not reconnect.
|
|
61
200
|
* even if `alwaysReconnect` is enabled. Defaults to false.
|
|
62
201
|
*/
|
|
63
202
|
close(force = false) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ClientProperties } from './entities/identify';
|
|
2
|
-
import { PresenceUpdatePayload } from './entities/types';
|
|
2
|
+
import { PresenceUpdatePayload, DiscordUser } from './entities/types';
|
|
3
3
|
interface DiscordWebSocketOptions {
|
|
4
4
|
alwaysReconnect: boolean;
|
|
5
5
|
properties?: ClientProperties;
|
|
@@ -22,11 +22,15 @@ export declare class DiscordWebSocket {
|
|
|
22
22
|
private permanentClose;
|
|
23
23
|
private connectTimeout;
|
|
24
24
|
private resolveReady;
|
|
25
|
+
/**
|
|
26
|
+
* Current logged in user info.
|
|
27
|
+
*/
|
|
28
|
+
user: DiscordUser | null;
|
|
25
29
|
/**
|
|
26
30
|
* A promise will be resolved when the Gateway connection is ready.
|
|
27
31
|
* and received the READY event.
|
|
28
32
|
*/
|
|
29
|
-
readyPromise: Promise<
|
|
33
|
+
readyPromise: Promise<DiscordUser>;
|
|
30
34
|
/**
|
|
31
35
|
* Create a DiscordWebSocket instance.
|
|
32
36
|
* @param {string} token - Discord user token for authentication.
|
|
@@ -59,6 +59,10 @@ class DiscordWebSocket {
|
|
|
59
59
|
permanentClose = false;
|
|
60
60
|
connectTimeout = null;
|
|
61
61
|
resolveReady = () => { };
|
|
62
|
+
/**
|
|
63
|
+
* Current logged in user info.
|
|
64
|
+
*/
|
|
65
|
+
user = null;
|
|
62
66
|
/**
|
|
63
67
|
* A promise will be resolved when the Gateway connection is ready.
|
|
64
68
|
* and received the READY event.
|
|
@@ -183,12 +187,15 @@ class DiscordWebSocket {
|
|
|
183
187
|
if (payload.t === 'READY') {
|
|
184
188
|
this.sessionId = payload.d.session_id;
|
|
185
189
|
this.resumeGatewayUrl = payload.d.resume_gateway_url + '/?v=10&encoding=json';
|
|
190
|
+
this.user = payload.d.user;
|
|
186
191
|
logger_1.logger.info(`Session READY. Session ID: ${this.sessionId}. Resume URL set.`);
|
|
187
|
-
this.resolveReady();
|
|
192
|
+
this.resolveReady(this.user);
|
|
188
193
|
}
|
|
189
194
|
else if (payload.t === 'RESUMED') {
|
|
190
195
|
logger_1.logger.info('The session has been successfully resumed.');
|
|
191
|
-
this.
|
|
196
|
+
if (this.user) {
|
|
197
|
+
this.resolveReady(this.user);
|
|
198
|
+
}
|
|
192
199
|
}
|
|
193
200
|
break;
|
|
194
201
|
case OpCode_1.OpCode.HEARTBEAT_ACK:
|
|
@@ -27,6 +27,88 @@ export interface IdentifyPayload {
|
|
|
27
27
|
properties: IdentifyProperties;
|
|
28
28
|
compress: boolean;
|
|
29
29
|
}
|
|
30
|
+
export declare enum UserFlags {
|
|
31
|
+
STAFF = 1,
|
|
32
|
+
PARTNER = 2,
|
|
33
|
+
HYPESQUAD = 4,
|
|
34
|
+
BUG_HUNTER_LEVEL_1 = 8,
|
|
35
|
+
HYPESQUAD_ONLINE_HOUSE_1 = 64,// Bravery
|
|
36
|
+
HYPESQUAD_ONLINE_HOUSE_2 = 128,// Brilliance
|
|
37
|
+
HYPESQUAD_ONLINE_HOUSE_3 = 256,// Balance
|
|
38
|
+
PREMIUM_EARLY_SUPPORTER = 512,
|
|
39
|
+
TEAM_PSEUDO_USER = 1024,
|
|
40
|
+
BUG_HUNTER_LEVEL_2 = 16384,
|
|
41
|
+
VERIFIED_BOT = 65536,
|
|
42
|
+
VERIFIED_DEVELOPER = 131072,
|
|
43
|
+
CERTIFIED_MODERATOR = 262144,
|
|
44
|
+
BOT_HTTP_INTERACTIONS = 524288,
|
|
45
|
+
ACTIVE_DEVELOPER = 4194304
|
|
46
|
+
}
|
|
47
|
+
export interface DiscordUser {
|
|
48
|
+
id: string;
|
|
49
|
+
username: string;
|
|
50
|
+
discriminator: string;
|
|
51
|
+
global_name?: string | null;
|
|
52
|
+
avatar?: string | null;
|
|
53
|
+
bot?: boolean;
|
|
54
|
+
system?: boolean;
|
|
55
|
+
mfa_enabled?: boolean;
|
|
56
|
+
banner?: string | null;
|
|
57
|
+
accent_color?: number | null;
|
|
58
|
+
locale?: string;
|
|
59
|
+
verified?: boolean;
|
|
60
|
+
email?: string | null;
|
|
61
|
+
flags?: number;
|
|
62
|
+
premium_type?: number;
|
|
63
|
+
public_flags?: number;
|
|
64
|
+
bio?: string;
|
|
65
|
+
phone?: string | null;
|
|
66
|
+
nsfw_allowed?: boolean;
|
|
67
|
+
pronouns?: string;
|
|
68
|
+
mobile?: boolean;
|
|
69
|
+
desktop?: boolean;
|
|
70
|
+
clan?: {
|
|
71
|
+
tag: string;
|
|
72
|
+
identity_guild_id: string;
|
|
73
|
+
badge: string;
|
|
74
|
+
identity_enabled?: boolean;
|
|
75
|
+
} | null;
|
|
76
|
+
primary_guild?: {
|
|
77
|
+
tag: string;
|
|
78
|
+
identity_guild_id: string;
|
|
79
|
+
badge: string;
|
|
80
|
+
identity_enabled?: boolean;
|
|
81
|
+
} | null;
|
|
82
|
+
purchased_flags?: number;
|
|
83
|
+
premium_usage_flags?: number;
|
|
84
|
+
premium?: boolean;
|
|
85
|
+
premium_state?: {
|
|
86
|
+
premium_subscription_type?: number;
|
|
87
|
+
premium_subscription_group_role?: number;
|
|
88
|
+
premium_source?: number;
|
|
89
|
+
} | null;
|
|
90
|
+
avatar_decoration_data?: {
|
|
91
|
+
asset: string;
|
|
92
|
+
sku_id: string;
|
|
93
|
+
expires_at: number | null;
|
|
94
|
+
} | null;
|
|
95
|
+
collectibles?: {
|
|
96
|
+
nameplate?: {
|
|
97
|
+
asset: string;
|
|
98
|
+
label: string;
|
|
99
|
+
sku_id: string;
|
|
100
|
+
palette?: string;
|
|
101
|
+
expires_at?: number | null;
|
|
102
|
+
};
|
|
103
|
+
} | null;
|
|
104
|
+
display_name_styles?: {
|
|
105
|
+
font_id?: number;
|
|
106
|
+
effect_id?: number;
|
|
107
|
+
colors?: number[];
|
|
108
|
+
} | null;
|
|
109
|
+
banner_color?: string | null;
|
|
110
|
+
age_verification_status?: number;
|
|
111
|
+
}
|
|
30
112
|
export interface Activity {
|
|
31
113
|
name: string;
|
|
32
114
|
type: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ActivityType = void 0;
|
|
3
|
+
exports.UserFlags = exports.ActivityType = void 0;
|
|
4
4
|
var ActivityType;
|
|
5
5
|
(function (ActivityType) {
|
|
6
6
|
ActivityType[ActivityType["Playing"] = 0] = "Playing";
|
|
@@ -10,3 +10,21 @@ var ActivityType;
|
|
|
10
10
|
ActivityType[ActivityType["Custom"] = 4] = "Custom";
|
|
11
11
|
ActivityType[ActivityType["Competing"] = 5] = "Competing";
|
|
12
12
|
})(ActivityType || (exports.ActivityType = ActivityType = {}));
|
|
13
|
+
var UserFlags;
|
|
14
|
+
(function (UserFlags) {
|
|
15
|
+
UserFlags[UserFlags["STAFF"] = 1] = "STAFF";
|
|
16
|
+
UserFlags[UserFlags["PARTNER"] = 2] = "PARTNER";
|
|
17
|
+
UserFlags[UserFlags["HYPESQUAD"] = 4] = "HYPESQUAD";
|
|
18
|
+
UserFlags[UserFlags["BUG_HUNTER_LEVEL_1"] = 8] = "BUG_HUNTER_LEVEL_1";
|
|
19
|
+
UserFlags[UserFlags["HYPESQUAD_ONLINE_HOUSE_1"] = 64] = "HYPESQUAD_ONLINE_HOUSE_1";
|
|
20
|
+
UserFlags[UserFlags["HYPESQUAD_ONLINE_HOUSE_2"] = 128] = "HYPESQUAD_ONLINE_HOUSE_2";
|
|
21
|
+
UserFlags[UserFlags["HYPESQUAD_ONLINE_HOUSE_3"] = 256] = "HYPESQUAD_ONLINE_HOUSE_3";
|
|
22
|
+
UserFlags[UserFlags["PREMIUM_EARLY_SUPPORTER"] = 512] = "PREMIUM_EARLY_SUPPORTER";
|
|
23
|
+
UserFlags[UserFlags["TEAM_PSEUDO_USER"] = 1024] = "TEAM_PSEUDO_USER";
|
|
24
|
+
UserFlags[UserFlags["BUG_HUNTER_LEVEL_2"] = 16384] = "BUG_HUNTER_LEVEL_2";
|
|
25
|
+
UserFlags[UserFlags["VERIFIED_BOT"] = 65536] = "VERIFIED_BOT";
|
|
26
|
+
UserFlags[UserFlags["VERIFIED_DEVELOPER"] = 131072] = "VERIFIED_DEVELOPER";
|
|
27
|
+
UserFlags[UserFlags["CERTIFIED_MODERATOR"] = 262144] = "CERTIFIED_MODERATOR";
|
|
28
|
+
UserFlags[UserFlags["BOT_HTTP_INTERACTIONS"] = 524288] = "BOT_HTTP_INTERACTIONS";
|
|
29
|
+
UserFlags[UserFlags["ACTIVE_DEVELOPER"] = 4194304] = "ACTIVE_DEVELOPER";
|
|
30
|
+
})(UserFlags || (exports.UserFlags = UserFlags = {}));
|
|
@@ -42,6 +42,11 @@ export declare class HieuxyzRPC {
|
|
|
42
42
|
*/
|
|
43
43
|
private resolvedAssetsCache;
|
|
44
44
|
private renewalInterval;
|
|
45
|
+
/**
|
|
46
|
+
* Cache for Application Assets (Bot Assets).
|
|
47
|
+
* Map<ApplicationID, Map<AssetName, AssetID>>
|
|
48
|
+
*/
|
|
49
|
+
private applicationAssetsCache;
|
|
45
50
|
constructor(websocket: DiscordWebSocket, imageService: ImageService);
|
|
46
51
|
/**
|
|
47
52
|
* Returns the URL of the large image asset, if available.
|
|
@@ -99,14 +104,14 @@ export declare class HieuxyzRPC {
|
|
|
99
104
|
setParty(currentSize: number, maxSize: number): this;
|
|
100
105
|
/**
|
|
101
106
|
* Set large image and its caption text.
|
|
102
|
-
* @param {string | RpcImage} source - Image source (URL, asset key, or RpcImage object).
|
|
107
|
+
* @param {string | RpcImage} source - Image source (URL, asset key, Asset Name or RpcImage object).
|
|
103
108
|
* @param {string} [text] - Text displayed when hovering over image.
|
|
104
109
|
* @returns {this}
|
|
105
110
|
*/
|
|
106
111
|
setLargeImage(source: string | RpcImage, text?: string): this;
|
|
107
112
|
/**
|
|
108
113
|
* Set the small image and its caption text.
|
|
109
|
-
* @param {string | RpcImage} source - Image source (URL, asset key, or RpcImage object).
|
|
114
|
+
* @param {string | RpcImage} source - Image source (URL, asset key, Asset Name or RpcImage object).
|
|
110
115
|
* @param {string} [text] - Text displayed when hovering over image.
|
|
111
116
|
* @returns {this}
|
|
112
117
|
*/
|
|
@@ -176,6 +181,10 @@ export declare class HieuxyzRPC {
|
|
|
176
181
|
* Stops the background process that checks for asset renewal.
|
|
177
182
|
*/
|
|
178
183
|
stopBackgroundRenewal(): void;
|
|
184
|
+
/**
|
|
185
|
+
* Ensure assets are fetched for the current application ID.
|
|
186
|
+
*/
|
|
187
|
+
private ensureAppAssetsLoaded;
|
|
179
188
|
private resolveImage;
|
|
180
189
|
private buildActivity;
|
|
181
190
|
/**
|
|
@@ -35,6 +35,11 @@ class HieuxyzRPC {
|
|
|
35
35
|
*/
|
|
36
36
|
resolvedAssetsCache = new Map();
|
|
37
37
|
renewalInterval = null;
|
|
38
|
+
/**
|
|
39
|
+
* Cache for Application Assets (Bot Assets).
|
|
40
|
+
* Map<ApplicationID, Map<AssetName, AssetID>>
|
|
41
|
+
*/
|
|
42
|
+
applicationAssetsCache = new Map();
|
|
38
43
|
constructor(websocket, imageService) {
|
|
39
44
|
this.websocket = websocket;
|
|
40
45
|
this.imageService = imageService;
|
|
@@ -77,7 +82,6 @@ class HieuxyzRPC {
|
|
|
77
82
|
if (assetKey.startsWith('twitch:')) {
|
|
78
83
|
return `https://static-cdn.jtvnw.net/previews-ttv/live_user_${assetKey.substring(7)}.png`;
|
|
79
84
|
}
|
|
80
|
-
// For assets uploaded to a Discord application
|
|
81
85
|
if (this.applicationId && !assetKey.startsWith('http')) {
|
|
82
86
|
return `https://cdn.discordapp.com/app-assets/${this.applicationId}/${assetKey}.png`;
|
|
83
87
|
}
|
|
@@ -106,6 +110,9 @@ class HieuxyzRPC {
|
|
|
106
110
|
if (source.startsWith('attachments/') || source.startsWith('external/')) {
|
|
107
111
|
return new RpcImage_1.DiscordImage(source);
|
|
108
112
|
}
|
|
113
|
+
if (/^[a-zA-Z0-9_]+$/.test(source) && !/^\d{17,20}$/.test(source)) {
|
|
114
|
+
return new RpcImage_1.ApplicationImage(source);
|
|
115
|
+
}
|
|
109
116
|
return new RpcImage_1.RawImage(source);
|
|
110
117
|
}
|
|
111
118
|
cleanupNulls(obj) {
|
|
@@ -185,7 +192,7 @@ class HieuxyzRPC {
|
|
|
185
192
|
}
|
|
186
193
|
/**
|
|
187
194
|
* Set large image and its caption text.
|
|
188
|
-
* @param {string | RpcImage} source - Image source (URL, asset key, or RpcImage object).
|
|
195
|
+
* @param {string | RpcImage} source - Image source (URL, asset key, Asset Name or RpcImage object).
|
|
189
196
|
* @param {string} [text] - Text displayed when hovering over image.
|
|
190
197
|
* @returns {this}
|
|
191
198
|
*/
|
|
@@ -197,7 +204,7 @@ class HieuxyzRPC {
|
|
|
197
204
|
}
|
|
198
205
|
/**
|
|
199
206
|
* Set the small image and its caption text.
|
|
200
|
-
* @param {string | RpcImage} source - Image source (URL, asset key, or RpcImage object).
|
|
207
|
+
* @param {string | RpcImage} source - Image source (URL, asset key, Asset Name or RpcImage object).
|
|
201
208
|
* @param {string} [text] - Text displayed when hovering over image.
|
|
202
209
|
* @returns {this}
|
|
203
210
|
*/
|
|
@@ -252,8 +259,8 @@ class HieuxyzRPC {
|
|
|
252
259
|
* @returns {this}
|
|
253
260
|
*/
|
|
254
261
|
setApplicationId(id) {
|
|
255
|
-
if (!/^\d{
|
|
256
|
-
throw new Error('The app ID must be
|
|
262
|
+
if (!/^\d{17,20}$/.test(id)) {
|
|
263
|
+
throw new Error('The app ID must be a valid number string (17-20 digits).');
|
|
257
264
|
}
|
|
258
265
|
this.applicationId = id;
|
|
259
266
|
return this;
|
|
@@ -375,16 +382,45 @@ class HieuxyzRPC {
|
|
|
375
382
|
logger_1.logger.info('Stopped background asset renewal process.');
|
|
376
383
|
}
|
|
377
384
|
}
|
|
385
|
+
/**
|
|
386
|
+
* Ensure assets are fetched for the current application ID.
|
|
387
|
+
*/
|
|
388
|
+
async ensureAppAssetsLoaded() {
|
|
389
|
+
if (!this.applicationAssetsCache.has(this.applicationId)) {
|
|
390
|
+
logger_1.logger.info(`Fetching assets for Application ID: ${this.applicationId}...`);
|
|
391
|
+
const assets = await this.imageService.fetchApplicationAssets(this.applicationId);
|
|
392
|
+
const assetMap = new Map();
|
|
393
|
+
assets.forEach((asset) => {
|
|
394
|
+
assetMap.set(asset.name, asset.id);
|
|
395
|
+
});
|
|
396
|
+
this.applicationAssetsCache.set(this.applicationId, assetMap);
|
|
397
|
+
logger_1.logger.info(`Loaded ${assets.length} assets for Application ID: ${this.applicationId}.`);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
378
400
|
async resolveImage(image) {
|
|
379
401
|
if (!image)
|
|
380
402
|
return undefined;
|
|
381
403
|
const cacheKey = image.getCacheKey();
|
|
404
|
+
if (cacheKey.startsWith('app_asset:')) {
|
|
405
|
+
await this.ensureAppAssetsLoaded();
|
|
406
|
+
const assetName = cacheKey.substring('app_asset:'.length);
|
|
407
|
+
const appAssets = this.applicationAssetsCache.get(this.applicationId);
|
|
408
|
+
const assetId = appAssets?.get(assetName);
|
|
409
|
+
if (!assetId) {
|
|
410
|
+
logger_1.logger.warn(`Asset with name "${assetName}" not found for Application ID ${this.applicationId}.`);
|
|
411
|
+
return undefined;
|
|
412
|
+
}
|
|
413
|
+
return assetId;
|
|
414
|
+
}
|
|
382
415
|
const cachedAsset = this.resolvedAssetsCache.get(cacheKey);
|
|
383
416
|
if (cachedAsset) {
|
|
384
417
|
return await this.renewAssetIfNeeded(cacheKey, cachedAsset);
|
|
385
418
|
}
|
|
386
419
|
const resolvedAsset = await image.resolve(this.imageService);
|
|
387
420
|
if (resolvedAsset) {
|
|
421
|
+
if (resolvedAsset.startsWith('app_asset:')) {
|
|
422
|
+
return this.resolveImage(image);
|
|
423
|
+
}
|
|
388
424
|
this.resolvedAssetsCache.set(cacheKey, resolvedAsset);
|
|
389
425
|
}
|
|
390
426
|
return resolvedAsset;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export interface DiscordAsset {
|
|
2
|
+
id: string;
|
|
3
|
+
type: number;
|
|
4
|
+
name: string;
|
|
5
|
+
}
|
|
1
6
|
/**
|
|
2
7
|
* A service to handle external image proxying and local image uploading.
|
|
3
8
|
* Interact with a backend API service to manage image assets.
|
|
@@ -28,4 +33,10 @@ export declare class ImageService {
|
|
|
28
33
|
* @returns {Promise<string | undefined>} The new asset key or undefined if it failed.
|
|
29
34
|
*/
|
|
30
35
|
renewImage(assetId: string): Promise<string | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* Fetch all assets for a specific Discord Application.
|
|
38
|
+
* @param applicationId - The ID of the application.
|
|
39
|
+
* @returns {Promise<DiscordAsset[]>} List of assets (id, name, type).
|
|
40
|
+
*/
|
|
41
|
+
fetchApplicationAssets(applicationId: string): Promise<DiscordAsset[]>;
|
|
31
42
|
}
|
|
@@ -121,5 +121,22 @@ class ImageService {
|
|
|
121
121
|
}
|
|
122
122
|
return undefined;
|
|
123
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Fetch all assets for a specific Discord Application.
|
|
126
|
+
* @param applicationId - The ID of the application.
|
|
127
|
+
* @returns {Promise<DiscordAsset[]>} List of assets (id, name, type).
|
|
128
|
+
*/
|
|
129
|
+
async fetchApplicationAssets(applicationId) {
|
|
130
|
+
try {
|
|
131
|
+
const url = `https://discord.com/api/v9/oauth2/applications/${applicationId}/assets`;
|
|
132
|
+
const response = await axios_1.default.get(url);
|
|
133
|
+
return response.data;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const err = error;
|
|
137
|
+
logger_1.logger.error(`Failed to fetch assets for application ${applicationId}: ${err.message}. Ensure the App ID is correct.`);
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
124
141
|
}
|
|
125
142
|
exports.ImageService = ImageService;
|
|
@@ -54,3 +54,16 @@ export declare class RawImage extends RpcImage {
|
|
|
54
54
|
resolve(__imageService: ImageService): Promise<string | undefined>;
|
|
55
55
|
getCacheKey(): string;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Represents an asset uploaded to the Discord Application (Bot Assets).
|
|
59
|
+
* It will resolve the asset ID by matching the asset name.
|
|
60
|
+
*/
|
|
61
|
+
export declare class ApplicationImage extends RpcImage {
|
|
62
|
+
assetName: string;
|
|
63
|
+
/**
|
|
64
|
+
* @param assetName The name of the asset as defined in the Discord Developer Portal.
|
|
65
|
+
*/
|
|
66
|
+
constructor(assetName: string);
|
|
67
|
+
resolve(__imageService: ImageService): Promise<string | undefined>;
|
|
68
|
+
getCacheKey(): string;
|
|
69
|
+
}
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.RawImage = exports.LocalImage = exports.ExternalImage = exports.DiscordImage = exports.RpcImage = void 0;
|
|
36
|
+
exports.ApplicationImage = exports.RawImage = exports.LocalImage = exports.ExternalImage = exports.DiscordImage = exports.RpcImage = void 0;
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
38
|
/**
|
|
39
39
|
* Base abstract class for all RPC image types.
|
|
@@ -113,3 +113,24 @@ class RawImage extends RpcImage {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
exports.RawImage = RawImage;
|
|
116
|
+
/**
|
|
117
|
+
* Represents an asset uploaded to the Discord Application (Bot Assets).
|
|
118
|
+
* It will resolve the asset ID by matching the asset name.
|
|
119
|
+
*/
|
|
120
|
+
class ApplicationImage extends RpcImage {
|
|
121
|
+
assetName;
|
|
122
|
+
/**
|
|
123
|
+
* @param assetName The name of the asset as defined in the Discord Developer Portal.
|
|
124
|
+
*/
|
|
125
|
+
constructor(assetName) {
|
|
126
|
+
super();
|
|
127
|
+
this.assetName = assetName;
|
|
128
|
+
}
|
|
129
|
+
async resolve(__imageService) {
|
|
130
|
+
return `app_asset:${this.assetName}`;
|
|
131
|
+
}
|
|
132
|
+
getCacheKey() {
|
|
133
|
+
return `app_asset:${this.assetName}`;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.ApplicationImage = ApplicationImage;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ export { Client, ClientOptions } from './hieuxyz/Client';
|
|
|
2
2
|
export { DiscordWebSocket } from './hieuxyz/gateway/DiscordWebSocket';
|
|
3
3
|
export { HieuxyzRPC } from './hieuxyz/rpc/HieuxyzRPC';
|
|
4
4
|
export { ImageService } from './hieuxyz/rpc/ImageService';
|
|
5
|
-
export { RpcImage, DiscordImage, ExternalImage, LocalImage, RawImage } from './hieuxyz/rpc/RpcImage';
|
|
5
|
+
export { RpcImage, DiscordImage, ExternalImage, LocalImage, RawImage, ApplicationImage } from './hieuxyz/rpc/RpcImage';
|
|
6
6
|
export { logger } from './hieuxyz/utils/logger';
|
|
7
7
|
export * from './hieuxyz/gateway/entities/types';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.logger = exports.RawImage = exports.LocalImage = exports.ExternalImage = exports.DiscordImage = exports.RpcImage = exports.ImageService = exports.HieuxyzRPC = exports.DiscordWebSocket = exports.Client = void 0;
|
|
17
|
+
exports.logger = exports.ApplicationImage = exports.RawImage = exports.LocalImage = exports.ExternalImage = exports.DiscordImage = exports.RpcImage = exports.ImageService = exports.HieuxyzRPC = exports.DiscordWebSocket = exports.Client = void 0;
|
|
18
18
|
var Client_1 = require("./hieuxyz/Client");
|
|
19
19
|
Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return Client_1.Client; } });
|
|
20
20
|
var DiscordWebSocket_1 = require("./hieuxyz/gateway/DiscordWebSocket");
|
|
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "DiscordImage", { enumerable: true, get: function
|
|
|
29
29
|
Object.defineProperty(exports, "ExternalImage", { enumerable: true, get: function () { return RpcImage_1.ExternalImage; } });
|
|
30
30
|
Object.defineProperty(exports, "LocalImage", { enumerable: true, get: function () { return RpcImage_1.LocalImage; } });
|
|
31
31
|
Object.defineProperty(exports, "RawImage", { enumerable: true, get: function () { return RpcImage_1.RawImage; } });
|
|
32
|
+
Object.defineProperty(exports, "ApplicationImage", { enumerable: true, get: function () { return RpcImage_1.ApplicationImage; } });
|
|
32
33
|
var logger_1 = require("./hieuxyz/utils/logger");
|
|
33
34
|
Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });
|
|
34
35
|
__exportStar(require("./hieuxyz/gateway/entities/types"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hieuxyz/rpc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A Discord Rich Presence library for Node.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -32,18 +32,18 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://github.com/hieuxyz00/hieuxyz_rpc#readme",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"axios": "^1.
|
|
35
|
+
"axios": "^1.13.2",
|
|
36
36
|
"ws": "^8.18.3"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^
|
|
39
|
+
"@types/node": "^25.0.3",
|
|
40
40
|
"@types/ws": "^8.18.1",
|
|
41
|
-
"eslint": "^9.
|
|
41
|
+
"eslint": "^9.39.2",
|
|
42
42
|
"eslint-config-prettier": "^10.1.8",
|
|
43
43
|
"eslint-plugin-prettier": "^5.5.4",
|
|
44
|
-
"prettier": "^3.
|
|
44
|
+
"prettier": "^3.7.4",
|
|
45
45
|
"ts-node": "^10.9.2",
|
|
46
46
|
"typescript": "^5.9.3",
|
|
47
|
-
"typescript-eslint": "^8.
|
|
47
|
+
"typescript-eslint": "^8.51.0"
|
|
48
48
|
}
|
|
49
49
|
}
|