@hieuxyz/rpc 1.0.6
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/LICENSE +15 -0
- package/README.md +176 -0
- package/dist/hieuxyz/Client.d.ts +46 -0
- package/dist/hieuxyz/Client.js +59 -0
- package/dist/hieuxyz/gateway/DiscordWebSocket.d.ts +47 -0
- package/dist/hieuxyz/gateway/DiscordWebSocket.js +169 -0
- package/dist/hieuxyz/gateway/entities/OpCode.d.ts +13 -0
- package/dist/hieuxyz/gateway/entities/OpCode.js +17 -0
- package/dist/hieuxyz/gateway/entities/identify.d.ts +2 -0
- package/dist/hieuxyz/gateway/entities/identify.js +15 -0
- package/dist/hieuxyz/gateway/entities/types.d.ts +59 -0
- package/dist/hieuxyz/gateway/entities/types.js +12 -0
- package/dist/hieuxyz/rpc/HieuxyzRPC.d.ts +115 -0
- package/dist/hieuxyz/rpc/HieuxyzRPC.js +239 -0
- package/dist/hieuxyz/rpc/ImageService.d.ts +25 -0
- package/dist/hieuxyz/rpc/ImageService.js +106 -0
- package/dist/hieuxyz/rpc/RpcImage.d.ts +47 -0
- package/dist/hieuxyz/rpc/RpcImage.js +103 -0
- package/dist/hieuxyz/utils/logger.d.ts +5 -0
- package/dist/hieuxyz/utils/logger.js +8 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +34 -0
- package/package.json +33 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { DiscordWebSocket } from "../gateway/DiscordWebSocket";
|
|
2
|
+
import { SettableActivityType } from "../gateway/entities/types";
|
|
3
|
+
import { ImageService } from "./ImageService";
|
|
4
|
+
import { RpcImage } from "./RpcImage";
|
|
5
|
+
interface RpcButton {
|
|
6
|
+
label: string;
|
|
7
|
+
url: string;
|
|
8
|
+
}
|
|
9
|
+
export type DiscordPlatform = 'desktop' | 'android' | 'ios' | 'samsung' | 'xbox' | 'ps4' | 'ps5' | 'embedded';
|
|
10
|
+
/**
|
|
11
|
+
* Class built for creating and managing Discord Rich Presence states.
|
|
12
|
+
*/
|
|
13
|
+
export declare class HieuxyzRPC {
|
|
14
|
+
private websocket;
|
|
15
|
+
private imageService;
|
|
16
|
+
private activity;
|
|
17
|
+
private assets;
|
|
18
|
+
private status;
|
|
19
|
+
private applicationId;
|
|
20
|
+
private platform;
|
|
21
|
+
private resolvedAssetsCache;
|
|
22
|
+
constructor(websocket: DiscordWebSocket, imageService: ImageService);
|
|
23
|
+
private _toRpcImage;
|
|
24
|
+
private sanitize;
|
|
25
|
+
/**
|
|
26
|
+
* Name the operation (first line of RPC).
|
|
27
|
+
* @param name - Name to display.
|
|
28
|
+
* @returns {this}
|
|
29
|
+
*/
|
|
30
|
+
setName(name: string): this;
|
|
31
|
+
/**
|
|
32
|
+
* Set details for the operation (second line of RPC).
|
|
33
|
+
* @param details - Details to display.
|
|
34
|
+
* @returns {this}
|
|
35
|
+
*/
|
|
36
|
+
setDetails(details: string): this;
|
|
37
|
+
/**
|
|
38
|
+
* Set the state for the operation (third line of the RPC).
|
|
39
|
+
* @param state - State to display.
|
|
40
|
+
* @returns {this}
|
|
41
|
+
*/
|
|
42
|
+
setState(state: string): this;
|
|
43
|
+
/**
|
|
44
|
+
* Set the activity type.
|
|
45
|
+
* @param type - The type of activity (e.g. 0, 'playing', or ActivityType.Playing).
|
|
46
|
+
* @returns {this}
|
|
47
|
+
*/
|
|
48
|
+
setType(type: SettableActivityType): this;
|
|
49
|
+
/**
|
|
50
|
+
* Set a start and/or end timestamp for the activity.
|
|
51
|
+
* @param start - Unix timestamp (milliseconds) for start time.
|
|
52
|
+
* @param end - Unix timestamp (milliseconds) for the end time.
|
|
53
|
+
* @returns {this}
|
|
54
|
+
*/
|
|
55
|
+
setTimestamps(start?: number, end?: number): this;
|
|
56
|
+
/**
|
|
57
|
+
* Set party information for the activity.
|
|
58
|
+
* @param currentSize - Current number of players.
|
|
59
|
+
* @param maxSize - Maximum number of players.
|
|
60
|
+
* @returns {this}
|
|
61
|
+
*/
|
|
62
|
+
setParty(currentSize: number, maxSize: number): this;
|
|
63
|
+
/**
|
|
64
|
+
* Set large image and its caption text.
|
|
65
|
+
* @param source - Image source (URL, asset key, or RpcImage object).
|
|
66
|
+
* @param text - Text displayed when hovering over image.
|
|
67
|
+
* @returns {this}
|
|
68
|
+
*/
|
|
69
|
+
setLargeImage(source: string | RpcImage, text?: string): this;
|
|
70
|
+
/**
|
|
71
|
+
* Set the small image and its caption text.
|
|
72
|
+
* @param source - Image source (URL, asset key, or RpcImage object).
|
|
73
|
+
* @param text - Text displayed when hovering over image.
|
|
74
|
+
* @returns {this}
|
|
75
|
+
*/
|
|
76
|
+
setSmallImage(source: string | RpcImage, text?: string): this;
|
|
77
|
+
/**
|
|
78
|
+
* Set clickable buttons for RPC (up to 2).
|
|
79
|
+
* @param buttons - An array of button objects.
|
|
80
|
+
* @returns {this}
|
|
81
|
+
*/
|
|
82
|
+
setButtons(buttons: RpcButton[]): this;
|
|
83
|
+
/**
|
|
84
|
+
* Set custom application ID for RPC.
|
|
85
|
+
* @param id - Discord app ID (must be an 18 or 19 digit number string).
|
|
86
|
+
* @throws {Error} If ID is invalid.
|
|
87
|
+
* @returns {this}
|
|
88
|
+
*/
|
|
89
|
+
setApplicationId(id: string): this;
|
|
90
|
+
/**
|
|
91
|
+
* Set the user's status (e.g. online, idle, dnd).
|
|
92
|
+
* @param status - Desired state.
|
|
93
|
+
* @returns {this}
|
|
94
|
+
*/
|
|
95
|
+
setStatus(status: 'online' | 'dnd' | 'idle' | 'invisible' | 'offline'): this;
|
|
96
|
+
/**
|
|
97
|
+
* Set the platform on which the activity is running.
|
|
98
|
+
* @param platform - Platform (e.g. 'desktop', 'xbox').
|
|
99
|
+
* @returns {this}
|
|
100
|
+
*/
|
|
101
|
+
setPlatform(platform: DiscordPlatform): this;
|
|
102
|
+
private buildActivity;
|
|
103
|
+
/**
|
|
104
|
+
* Build the final Rich Presence payload and send it to Discord.
|
|
105
|
+
* @returns {Promise<void>}
|
|
106
|
+
*/
|
|
107
|
+
build(): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Sends an update to an existing RPC.
|
|
110
|
+
* This is essentially an alias for `build()`.
|
|
111
|
+
* @returns {Promise<void>}
|
|
112
|
+
*/
|
|
113
|
+
updateRPC(): Promise<void>;
|
|
114
|
+
}
|
|
115
|
+
export {};
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HieuxyzRPC = void 0;
|
|
4
|
+
const types_1 = require("../gateway/entities/types");
|
|
5
|
+
const RpcImage_1 = require("./RpcImage");
|
|
6
|
+
/**
|
|
7
|
+
* Class built for creating and managing Discord Rich Presence states.
|
|
8
|
+
*/
|
|
9
|
+
class HieuxyzRPC {
|
|
10
|
+
websocket;
|
|
11
|
+
imageService;
|
|
12
|
+
activity = {};
|
|
13
|
+
assets = {};
|
|
14
|
+
status = 'online';
|
|
15
|
+
applicationId = '1416676323459469363'; // Default ID, can be changed
|
|
16
|
+
platform = 'desktop';
|
|
17
|
+
resolvedAssetsCache = {};
|
|
18
|
+
constructor(websocket, imageService) {
|
|
19
|
+
this.websocket = websocket;
|
|
20
|
+
this.imageService = imageService;
|
|
21
|
+
}
|
|
22
|
+
_toRpcImage(source) {
|
|
23
|
+
if (typeof source !== 'string') {
|
|
24
|
+
return source;
|
|
25
|
+
}
|
|
26
|
+
if (source.startsWith('https://') || source.startsWith('http://')) {
|
|
27
|
+
try {
|
|
28
|
+
const url = new URL(source);
|
|
29
|
+
if (url.hostname === 'cdn.discordapp.com' || url.hostname === 'media.discordapp.net') {
|
|
30
|
+
const discordAssetPath = url.pathname.substring(1);
|
|
31
|
+
return new RpcImage_1.DiscordImage(discordAssetPath);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return new RpcImage_1.ExternalImage(source);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
console.warn(`Could not parse "${source}" into a valid URL. Treating as RawImage.`);
|
|
39
|
+
return new RpcImage_1.RawImage(source);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (source.startsWith('attachments/') || source.startsWith('external/')) {
|
|
43
|
+
return new RpcImage_1.DiscordImage(source);
|
|
44
|
+
}
|
|
45
|
+
return new RpcImage_1.RawImage(source);
|
|
46
|
+
}
|
|
47
|
+
sanitize(str, length = 128) {
|
|
48
|
+
return str.length > length ? str.substring(0, length) : str;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Name the operation (first line of RPC).
|
|
52
|
+
* @param name - Name to display.
|
|
53
|
+
* @returns {this}
|
|
54
|
+
*/
|
|
55
|
+
setName(name) {
|
|
56
|
+
this.activity.name = this.sanitize(name);
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Set details for the operation (second line of RPC).
|
|
61
|
+
* @param details - Details to display.
|
|
62
|
+
* @returns {this}
|
|
63
|
+
*/
|
|
64
|
+
setDetails(details) {
|
|
65
|
+
this.activity.details = this.sanitize(details);
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Set the state for the operation (third line of the RPC).
|
|
70
|
+
* @param state - State to display.
|
|
71
|
+
* @returns {this}
|
|
72
|
+
*/
|
|
73
|
+
setState(state) {
|
|
74
|
+
this.activity.state = this.sanitize(state);
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Set the activity type.
|
|
79
|
+
* @param type - The type of activity (e.g. 0, 'playing', or ActivityType.Playing).
|
|
80
|
+
* @returns {this}
|
|
81
|
+
*/
|
|
82
|
+
setType(type) {
|
|
83
|
+
if (typeof type === 'string') {
|
|
84
|
+
const typeMap = {
|
|
85
|
+
playing: types_1.ActivityType.Playing,
|
|
86
|
+
streaming: types_1.ActivityType.Streaming,
|
|
87
|
+
listening: types_1.ActivityType.Listening,
|
|
88
|
+
watching: types_1.ActivityType.Watching,
|
|
89
|
+
custom: types_1.ActivityType.Custom,
|
|
90
|
+
competing: types_1.ActivityType.Competing,
|
|
91
|
+
};
|
|
92
|
+
this.activity.type = typeMap[type.toLowerCase()] ?? types_1.ActivityType.Playing;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.activity.type = type;
|
|
96
|
+
}
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Set a start and/or end timestamp for the activity.
|
|
101
|
+
* @param start - Unix timestamp (milliseconds) for start time.
|
|
102
|
+
* @param end - Unix timestamp (milliseconds) for the end time.
|
|
103
|
+
* @returns {this}
|
|
104
|
+
*/
|
|
105
|
+
setTimestamps(start, end) {
|
|
106
|
+
this.activity.timestamps = { start, end };
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Set party information for the activity.
|
|
111
|
+
* @param currentSize - Current number of players.
|
|
112
|
+
* @param maxSize - Maximum number of players.
|
|
113
|
+
* @returns {this}
|
|
114
|
+
*/
|
|
115
|
+
setParty(currentSize, maxSize) {
|
|
116
|
+
this.activity.party = { id: 'hieuxyz', size: [currentSize, maxSize] };
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Set large image and its caption text.
|
|
121
|
+
* @param source - Image source (URL, asset key, or RpcImage object).
|
|
122
|
+
* @param text - Text displayed when hovering over image.
|
|
123
|
+
* @returns {this}
|
|
124
|
+
*/
|
|
125
|
+
setLargeImage(source, text) {
|
|
126
|
+
this.assets.large_image = this._toRpcImage(source);
|
|
127
|
+
if (text)
|
|
128
|
+
this.assets.large_text = this.sanitize(text);
|
|
129
|
+
delete this.resolvedAssetsCache.large_image;
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Set the small image and its caption text.
|
|
134
|
+
* @param source - Image source (URL, asset key, or RpcImage object).
|
|
135
|
+
* @param text - Text displayed when hovering over image.
|
|
136
|
+
* @returns {this}
|
|
137
|
+
*/
|
|
138
|
+
setSmallImage(source, text) {
|
|
139
|
+
this.assets.small_image = this._toRpcImage(source);
|
|
140
|
+
if (text)
|
|
141
|
+
this.assets.small_text = this.sanitize(text);
|
|
142
|
+
delete this.resolvedAssetsCache.small_image;
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Set clickable buttons for RPC (up to 2).
|
|
147
|
+
* @param buttons - An array of button objects.
|
|
148
|
+
* @returns {this}
|
|
149
|
+
*/
|
|
150
|
+
setButtons(buttons) {
|
|
151
|
+
const validButtons = buttons.slice(0, 2);
|
|
152
|
+
this.activity.buttons = validButtons.map(b => this.sanitize(b.label, 32));
|
|
153
|
+
this.activity.metadata = { button_urls: validButtons.map(b => b.url) };
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Set custom application ID for RPC.
|
|
158
|
+
* @param id - Discord app ID (must be an 18 or 19 digit number string).
|
|
159
|
+
* @throws {Error} If ID is invalid.
|
|
160
|
+
* @returns {this}
|
|
161
|
+
*/
|
|
162
|
+
setApplicationId(id) {
|
|
163
|
+
if (!/^\d{18,19}$/.test(id)) {
|
|
164
|
+
throw new Error("The app ID must be an 18 or 19 digit number.");
|
|
165
|
+
}
|
|
166
|
+
this.applicationId = id;
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Set the user's status (e.g. online, idle, dnd).
|
|
171
|
+
* @param status - Desired state.
|
|
172
|
+
* @returns {this}
|
|
173
|
+
*/
|
|
174
|
+
setStatus(status) {
|
|
175
|
+
this.status = status;
|
|
176
|
+
return this;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Set the platform on which the activity is running.
|
|
180
|
+
* @param platform - Platform (e.g. 'desktop', 'xbox').
|
|
181
|
+
* @returns {this}
|
|
182
|
+
*/
|
|
183
|
+
setPlatform(platform) {
|
|
184
|
+
this.platform = platform;
|
|
185
|
+
return this;
|
|
186
|
+
}
|
|
187
|
+
async buildActivity() {
|
|
188
|
+
if (this.assets.large_image && !this.resolvedAssetsCache.large_image) {
|
|
189
|
+
this.resolvedAssetsCache.large_image = await this.assets.large_image.resolve(this.imageService);
|
|
190
|
+
}
|
|
191
|
+
if (this.assets.small_image && !this.resolvedAssetsCache.small_image) {
|
|
192
|
+
this.resolvedAssetsCache.small_image = await this.assets.small_image.resolve(this.imageService);
|
|
193
|
+
}
|
|
194
|
+
const finalAssets = {
|
|
195
|
+
large_text: this.assets.large_text,
|
|
196
|
+
small_text: this.assets.small_text,
|
|
197
|
+
};
|
|
198
|
+
if (this.resolvedAssetsCache.large_image) {
|
|
199
|
+
finalAssets.large_image = this.resolvedAssetsCache.large_image;
|
|
200
|
+
}
|
|
201
|
+
if (this.resolvedAssetsCache.small_image) {
|
|
202
|
+
finalAssets.small_image = this.resolvedAssetsCache.small_image;
|
|
203
|
+
}
|
|
204
|
+
const finalActivity = { ...this.activity };
|
|
205
|
+
finalActivity.assets = finalAssets;
|
|
206
|
+
finalActivity.application_id = this.applicationId;
|
|
207
|
+
finalActivity.platform = this.platform;
|
|
208
|
+
if (!finalActivity.name) {
|
|
209
|
+
finalActivity.name = "Custom Status";
|
|
210
|
+
}
|
|
211
|
+
if (typeof finalActivity.type === 'undefined') {
|
|
212
|
+
finalActivity.type = types_1.ActivityType.Playing;
|
|
213
|
+
}
|
|
214
|
+
return finalActivity;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Build the final Rich Presence payload and send it to Discord.
|
|
218
|
+
* @returns {Promise<void>}
|
|
219
|
+
*/
|
|
220
|
+
async build() {
|
|
221
|
+
const activity = await this.buildActivity();
|
|
222
|
+
const presencePayload = {
|
|
223
|
+
since: 0,
|
|
224
|
+
activities: [activity],
|
|
225
|
+
status: this.status,
|
|
226
|
+
afk: false,
|
|
227
|
+
};
|
|
228
|
+
this.websocket.sendActivity(presencePayload);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Sends an update to an existing RPC.
|
|
232
|
+
* This is essentially an alias for `build()`.
|
|
233
|
+
* @returns {Promise<void>}
|
|
234
|
+
*/
|
|
235
|
+
async updateRPC() {
|
|
236
|
+
await this.build();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
exports.HieuxyzRPC = HieuxyzRPC;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A service to handle external image proxying and local image uploading.
|
|
3
|
+
* Interact with a backend API service to manage image assets.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ImageService {
|
|
6
|
+
private apiClient;
|
|
7
|
+
/**
|
|
8
|
+
* Create an ImageService instance.
|
|
9
|
+
* @param apiBaseUrl - The base URL of the image upload/proxy API.
|
|
10
|
+
*/
|
|
11
|
+
constructor(apiBaseUrl?: string);
|
|
12
|
+
/**
|
|
13
|
+
* Get an asset key proxy for an external image URL.
|
|
14
|
+
* @param url - URL of external image.
|
|
15
|
+
* @returns {Promise<string | undefined>} Asset key resolved or undefined if failed.
|
|
16
|
+
*/
|
|
17
|
+
getExternalUrl(url: string): Promise<string | undefined>;
|
|
18
|
+
/**
|
|
19
|
+
* Upload an image from the local file system to the image service.
|
|
20
|
+
* @param filePath - Path to the image file.
|
|
21
|
+
* @param fileName - File name to use when uploading.
|
|
22
|
+
* @returns {Promise<string | undefined>} Asset key resolved or undefined if failed.
|
|
23
|
+
*/
|
|
24
|
+
uploadImage(filePath: string, fileName: string): Promise<string | undefined>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ImageService = void 0;
|
|
40
|
+
const axios_1 = __importDefault(require("axios"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
43
|
+
const logger_1 = require("../utils/logger");
|
|
44
|
+
/**
|
|
45
|
+
* A service to handle external image proxying and local image uploading.
|
|
46
|
+
* Interact with a backend API service to manage image assets.
|
|
47
|
+
*/
|
|
48
|
+
class ImageService {
|
|
49
|
+
apiClient;
|
|
50
|
+
/**
|
|
51
|
+
* Create an ImageService instance.
|
|
52
|
+
* @param apiBaseUrl - The base URL of the image upload/proxy API.
|
|
53
|
+
*/
|
|
54
|
+
constructor(apiBaseUrl = 'https://rpc.hieuxyz.fun') {
|
|
55
|
+
this.apiClient = axios_1.default.create({
|
|
56
|
+
baseURL: apiBaseUrl,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get an asset key proxy for an external image URL.
|
|
61
|
+
* @param url - URL of external image.
|
|
62
|
+
* @returns {Promise<string | undefined>} Asset key resolved or undefined if failed.
|
|
63
|
+
*/
|
|
64
|
+
async getExternalUrl(url) {
|
|
65
|
+
try {
|
|
66
|
+
const response = await this.apiClient.get('/image', { params: { url } });
|
|
67
|
+
if (response.data && response.data.id) {
|
|
68
|
+
return response.data.id;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
logger_1.logger.error(`Unable to get external proxy URL for ${url}: ${error}`);
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Upload an image from the local file system to the image service.
|
|
78
|
+
* @param filePath - Path to the image file.
|
|
79
|
+
* @param fileName - File name to use when uploading.
|
|
80
|
+
* @returns {Promise<string | undefined>} Asset key resolved or undefined if failed.
|
|
81
|
+
*/
|
|
82
|
+
async uploadImage(filePath, fileName) {
|
|
83
|
+
try {
|
|
84
|
+
if (!fs.existsSync(filePath)) {
|
|
85
|
+
logger_1.logger.error(`File not found at path: ${filePath}`);
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const form = new form_data_1.default();
|
|
89
|
+
form.append('file', fs.createReadStream(filePath));
|
|
90
|
+
form.append('file_name', fileName);
|
|
91
|
+
const response = await this.apiClient.post('/upload', form, {
|
|
92
|
+
headers: {
|
|
93
|
+
...form.getHeaders()
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
if (response.data && response.data.id) {
|
|
97
|
+
return response.data.id;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
logger_1.logger.error(`Unable to upload image ${fileName}: ${error}`);
|
|
102
|
+
}
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.ImageService = ImageService;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ImageService } from './ImageService';
|
|
2
|
+
/**
|
|
3
|
+
* Base abstract class for all RPC image types.
|
|
4
|
+
*/
|
|
5
|
+
export declare abstract class RpcImage {
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the image into an asset key that Discord can understand.
|
|
8
|
+
* @param imageService - An instance of ImageService to handle uploads or proxies.
|
|
9
|
+
* @returns {Promise<string | undefined>} Asset key has been resolved.
|
|
10
|
+
*/
|
|
11
|
+
abstract resolve(imageService: ImageService): Promise<string | undefined>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Represents an image that already exists on Discord's servers (e.g., via proxy or previous upload).
|
|
15
|
+
*/
|
|
16
|
+
export declare class DiscordImage extends RpcImage {
|
|
17
|
+
private imageKey;
|
|
18
|
+
constructor(imageKey: string);
|
|
19
|
+
resolve(): Promise<string | undefined>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Represents an image from an external URL.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ExternalImage extends RpcImage {
|
|
25
|
+
private url;
|
|
26
|
+
constructor(url: string);
|
|
27
|
+
resolve(imageService: ImageService): Promise<string | undefined>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Represents an image from the local file system.
|
|
31
|
+
* Images will be uploaded via ImageService.
|
|
32
|
+
*/
|
|
33
|
+
export declare class LocalImage extends RpcImage {
|
|
34
|
+
private filePath;
|
|
35
|
+
private fileName;
|
|
36
|
+
constructor(filePath: string, fileName?: string);
|
|
37
|
+
resolve(imageService: ImageService): Promise<string | undefined>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Represents a resolved raw asset key.
|
|
41
|
+
* No further processing required.
|
|
42
|
+
*/
|
|
43
|
+
export declare class RawImage extends RpcImage {
|
|
44
|
+
private assetKey;
|
|
45
|
+
constructor(assetKey: string);
|
|
46
|
+
resolve(imageService: ImageService): Promise<string | undefined>;
|
|
47
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.RawImage = exports.LocalImage = exports.ExternalImage = exports.DiscordImage = exports.RpcImage = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
/**
|
|
39
|
+
* Base abstract class for all RPC image types.
|
|
40
|
+
*/
|
|
41
|
+
class RpcImage {
|
|
42
|
+
}
|
|
43
|
+
exports.RpcImage = RpcImage;
|
|
44
|
+
/**
|
|
45
|
+
* Represents an image that already exists on Discord's servers (e.g., via proxy or previous upload).
|
|
46
|
+
*/
|
|
47
|
+
class DiscordImage extends RpcImage {
|
|
48
|
+
imageKey;
|
|
49
|
+
constructor(imageKey) {
|
|
50
|
+
super();
|
|
51
|
+
this.imageKey = imageKey;
|
|
52
|
+
}
|
|
53
|
+
async resolve() {
|
|
54
|
+
return this.imageKey.startsWith('mp:') ? this.imageKey : `mp:${this.imageKey}`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.DiscordImage = DiscordImage;
|
|
58
|
+
/**
|
|
59
|
+
* Represents an image from an external URL.
|
|
60
|
+
*/
|
|
61
|
+
class ExternalImage extends RpcImage {
|
|
62
|
+
url;
|
|
63
|
+
constructor(url) {
|
|
64
|
+
super();
|
|
65
|
+
this.url = url;
|
|
66
|
+
}
|
|
67
|
+
async resolve(imageService) {
|
|
68
|
+
return imageService.getExternalUrl(this.url);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.ExternalImage = ExternalImage;
|
|
72
|
+
/**
|
|
73
|
+
* Represents an image from the local file system.
|
|
74
|
+
* Images will be uploaded via ImageService.
|
|
75
|
+
*/
|
|
76
|
+
class LocalImage extends RpcImage {
|
|
77
|
+
filePath;
|
|
78
|
+
fileName;
|
|
79
|
+
constructor(filePath, fileName) {
|
|
80
|
+
super();
|
|
81
|
+
this.filePath = filePath;
|
|
82
|
+
this.fileName = fileName || path.basename(filePath);
|
|
83
|
+
}
|
|
84
|
+
async resolve(imageService) {
|
|
85
|
+
return imageService.uploadImage(this.filePath, this.fileName);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.LocalImage = LocalImage;
|
|
89
|
+
/**
|
|
90
|
+
* Represents a resolved raw asset key.
|
|
91
|
+
* No further processing required.
|
|
92
|
+
*/
|
|
93
|
+
class RawImage extends RpcImage {
|
|
94
|
+
assetKey;
|
|
95
|
+
constructor(assetKey) {
|
|
96
|
+
super();
|
|
97
|
+
this.assetKey = assetKey;
|
|
98
|
+
}
|
|
99
|
+
async resolve(imageService) {
|
|
100
|
+
return this.assetKey;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.RawImage = RawImage;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logger = void 0;
|
|
4
|
+
exports.logger = {
|
|
5
|
+
info: (message) => console.log(`[INFO] ${new Date().toISOString()} - ${message}`),
|
|
6
|
+
warn: (message) => console.warn(`[WARN] ${new Date().toISOString()} - ${message}`),
|
|
7
|
+
error: (message) => console.error(`[ERROR] ${new Date().toISOString()} - ${message}`),
|
|
8
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Client, ClientOptions } from './hieuxyz/Client';
|
|
2
|
+
export { DiscordWebSocket } from './hieuxyz/gateway/DiscordWebSocket';
|
|
3
|
+
export { HieuxyzRPC } from './hieuxyz/rpc/HieuxyzRPC';
|
|
4
|
+
export { ImageService } from './hieuxyz/rpc/ImageService';
|
|
5
|
+
export { RpcImage, DiscordImage, ExternalImage, LocalImage, RawImage } from './hieuxyz/rpc/RpcImage';
|
|
6
|
+
export { logger } from './hieuxyz/utils/logger';
|
|
7
|
+
export * from './hieuxyz/gateway/entities/types';
|