seyfert 2.0.0 → 2.1.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/lib/api/Routes/interactions.d.ts +8 -2
- package/lib/api/Routes/skus.d.ts +11 -0
- package/lib/api/Routes/skus.js +2 -0
- package/lib/api/api.d.ts +1 -1
- package/lib/api/api.js +14 -12
- package/lib/api/shared.d.ts +1 -1
- package/lib/api/utils/constants.d.ts +1 -1
- package/lib/api/utils/constants.js +1 -1
- package/lib/builders/Attachment.d.ts +1 -1
- package/lib/builders/Attachment.js +12 -12
- package/lib/cache/index.d.ts +4 -1
- package/lib/cache/index.js +11 -3
- package/lib/client/base.d.ts +3 -3
- package/lib/client/base.js +8 -3
- package/lib/client/client.d.ts +4 -0
- package/lib/client/client.js +30 -14
- package/lib/client/httpclient.js +2 -2
- package/lib/client/workerclient.d.ts +3 -2
- package/lib/client/workerclient.js +23 -11
- package/lib/commands/applications/entryPoint.d.ts +46 -0
- package/lib/commands/applications/entryPoint.js +56 -0
- package/lib/commands/applications/entrycontext.d.ts +40 -0
- package/lib/commands/applications/entrycontext.js +85 -0
- package/lib/commands/applications/options.d.ts +3 -2
- package/lib/commands/decorators.d.ts +11 -17
- package/lib/commands/decorators.js +3 -0
- package/lib/commands/handle.d.ts +6 -5
- package/lib/commands/handle.js +42 -0
- package/lib/commands/handler.d.ts +6 -4
- package/lib/commands/handler.js +6 -1
- package/lib/commands/index.d.ts +2 -0
- package/lib/commands/index.js +2 -0
- package/lib/commands/optionresolver.js +1 -1
- package/lib/common/bot/watcher.d.ts +1 -1
- package/lib/common/it/utils.d.ts +10 -3
- package/lib/common/it/utils.js +10 -0
- package/lib/common/shorters/interaction.d.ts +1 -1
- package/lib/common/types/util.d.ts +1 -1
- package/lib/common/types/write.d.ts +2 -2
- package/lib/deps/mixer.js +6 -1
- package/lib/events/handler.js +3 -3
- package/lib/events/hooks/custom.d.ts +1 -0
- package/lib/events/hooks/custom.js +5 -1
- package/lib/events/hooks/subscriptions.d.ts +35 -0
- package/lib/events/hooks/subscriptions.js +16 -0
- package/lib/structures/Interaction.d.ts +24 -4
- package/lib/structures/Interaction.js +54 -5
- package/lib/structures/Message.d.ts +0 -3
- package/lib/structures/Message.js +0 -3
- package/lib/structures/channels.js +2 -2
- package/lib/structures/extra/BaseGuild.d.ts +11 -1
- package/lib/structures/extra/BaseGuild.js +27 -0
- package/lib/types/gateway.d.ts +19 -2
- package/lib/types/payloads/_interactions/_applicationCommands/chatInput.d.ts +6 -1
- package/lib/types/payloads/_interactions/applicationCommands.d.ts +41 -6
- package/lib/types/payloads/_interactions/applicationCommands.js +28 -1
- package/lib/types/payloads/_interactions/responses.d.ts +74 -2
- package/lib/types/payloads/_interactions/responses.js +4 -0
- package/lib/types/payloads/channel.d.ts +44 -4
- package/lib/types/payloads/channel.js +5 -1
- package/lib/types/payloads/monetization.d.ts +29 -1
- package/lib/types/payloads/monetization.js +10 -1
- package/lib/types/rest/channel.d.ts +4 -17
- package/lib/types/rest/interactions.d.ts +30 -8
- package/lib/types/rest/monetization.d.ts +22 -1
- package/lib/types/rest/webhook.d.ts +2 -2
- package/lib/types/utils/index.d.ts +16 -5
- package/lib/types/utils/index.js +15 -4
- package/lib/websocket/SharedTypes.d.ts +9 -3
- package/lib/websocket/constants/index.d.ts +3 -2
- package/lib/websocket/constants/index.js +11 -1
- package/lib/websocket/discord/shard.d.ts +3 -2
- package/lib/websocket/discord/shard.js +25 -11
- package/lib/websocket/discord/sharder.js +59 -1
- package/lib/websocket/discord/shared.d.ts +21 -1
- package/lib/websocket/discord/socket/custom.d.ts +1 -1
- package/lib/websocket/discord/socket/custom.js +51 -34
- package/lib/websocket/discord/worker.d.ts +2 -1
- package/lib/websocket/discord/workermanager.d.ts +2 -1
- package/lib/websocket/discord/workermanager.js +30 -13
- package/package.json +8 -3
|
@@ -31,6 +31,64 @@ class ShardManager extends Map {
|
|
|
31
31
|
if (worker_threads.parentPort)
|
|
32
32
|
parentPort = worker_threads.parentPort;
|
|
33
33
|
}
|
|
34
|
+
if (this.options.resharding.interval <= 0)
|
|
35
|
+
return;
|
|
36
|
+
setInterval(async () => {
|
|
37
|
+
this.debugger?.debug('Checking if reshard is needed');
|
|
38
|
+
const info = await this.options.resharding.getInfo();
|
|
39
|
+
if (info.shards <= this.totalShards)
|
|
40
|
+
return this.debugger?.debug('Resharding not needed');
|
|
41
|
+
//https://github.com/discordeno/discordeno/blob/6a5f446c0651b9fad9f1550ff1857fe7a026426b/packages/gateway/src/manager.ts#L106C8-L106C94
|
|
42
|
+
const percentage = (info.shards / ((this.totalShards * 2500) / 1000)) * 100;
|
|
43
|
+
if (percentage < this.options.resharding.percentage)
|
|
44
|
+
return this.debugger?.debug(`Percentage is not enough to reshard ${percentage}/${this.options.resharding.percentage}`);
|
|
45
|
+
this.debugger?.info('Starting resharding process');
|
|
46
|
+
this.connectQueue.concurrency = info.session_start_limit.max_concurrency;
|
|
47
|
+
this.options.totalShards = info.shards;
|
|
48
|
+
this.options.info.session_start_limit.max_concurrency = info.session_start_limit.max_concurrency;
|
|
49
|
+
let shardsConnected = 0;
|
|
50
|
+
let handlePayload = async (sharder, _, packet) => {
|
|
51
|
+
if ((packet.t === 'GUILD_CREATE' || packet.t === 'GUILD_DELETE') &&
|
|
52
|
+
this.options.resharding.onGuild(packet.d.id)) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (packet.t !== 'READY')
|
|
56
|
+
return;
|
|
57
|
+
this.options.resharding.reloadGuilds(packet.d.guilds.map(x => x.id));
|
|
58
|
+
if (++shardsConnected < info.shards)
|
|
59
|
+
return; //waiting for last shard to connect
|
|
60
|
+
// dont listen more events when all shards are ready
|
|
61
|
+
handlePayload = async () => { };
|
|
62
|
+
await this.disconnectAll();
|
|
63
|
+
this.clear();
|
|
64
|
+
for (const [id, shard] of sharder) {
|
|
65
|
+
shard.options.handlePayload = (shardId, packet) => {
|
|
66
|
+
return this.options.handlePayload(shardId, packet);
|
|
67
|
+
};
|
|
68
|
+
this.set(id, shard);
|
|
69
|
+
}
|
|
70
|
+
sharder.clear();
|
|
71
|
+
};
|
|
72
|
+
const resharder = new ShardManager({
|
|
73
|
+
...this.options,
|
|
74
|
+
resharding: {
|
|
75
|
+
// getInfo mock, we don't need it
|
|
76
|
+
getInfo: () => ({}),
|
|
77
|
+
interval: 0,
|
|
78
|
+
percentage: 0,
|
|
79
|
+
reloadGuilds() { },
|
|
80
|
+
onGuild() {
|
|
81
|
+
return true;
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
handlePayload: (shardId, packet) => {
|
|
85
|
+
return handlePayload(resharder, shardId, packet);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
// share ratelimit
|
|
89
|
+
resharder.connectQueue = this.connectQueue;
|
|
90
|
+
await resharder.spawnShards();
|
|
91
|
+
}, this.options.resharding.interval);
|
|
34
92
|
}
|
|
35
93
|
get totalShards() {
|
|
36
94
|
return this.options.totalShards ?? this.options.info.shards;
|
|
@@ -53,7 +111,7 @@ class ShardManager extends Map {
|
|
|
53
111
|
return acc / this.size;
|
|
54
112
|
}
|
|
55
113
|
calculateShardId(guildId) {
|
|
56
|
-
return
|
|
114
|
+
return (0, common_1.calculateShardId)(guildId, this.totalShards);
|
|
57
115
|
}
|
|
58
116
|
spawn(shardId) {
|
|
59
117
|
this.debugger?.info(`Spawn shard ${shardId}`);
|
|
@@ -29,6 +29,26 @@ export interface ShardManagerOptions extends ShardDetails {
|
|
|
29
29
|
*/
|
|
30
30
|
presence?: (shardId: number, workerId: number) => GatewayPresenceUpdateData;
|
|
31
31
|
compress?: boolean;
|
|
32
|
+
resharding?: {
|
|
33
|
+
/**
|
|
34
|
+
* @returns the gateway connection info
|
|
35
|
+
*/
|
|
36
|
+
getInfo(): Promise<APIGatewayBotInfo>;
|
|
37
|
+
interval: number;
|
|
38
|
+
percentage: number;
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param ids
|
|
42
|
+
* @returns
|
|
43
|
+
*/
|
|
44
|
+
reloadGuilds: (ids: string[]) => unknown;
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
* @param id
|
|
48
|
+
* @returns true if deleted
|
|
49
|
+
*/
|
|
50
|
+
onGuild: (id: string) => boolean;
|
|
51
|
+
};
|
|
32
52
|
}
|
|
33
53
|
export interface CustomManagerAdapter {
|
|
34
54
|
postMessage(workerId: number, body: unknown): Awaitable<unknown>;
|
|
@@ -39,7 +59,7 @@ export interface WorkerManagerOptions extends Omit<ShardManagerOptions, 'handleP
|
|
|
39
59
|
adapter?: CustomManagerAdapter;
|
|
40
60
|
workers?: number;
|
|
41
61
|
/**
|
|
42
|
-
* @default
|
|
62
|
+
* @default 16
|
|
43
63
|
*/
|
|
44
64
|
shardsPerWorker?: number;
|
|
45
65
|
workerProxy?: boolean;
|
|
@@ -19,7 +19,7 @@ export declare class SeyfertWebSocket {
|
|
|
19
19
|
private connect;
|
|
20
20
|
handleReadable(): void;
|
|
21
21
|
handleEvent(body: Buffer, opcode: number): void;
|
|
22
|
-
handleClose(): void
|
|
22
|
+
handleClose(): Promise<void>;
|
|
23
23
|
send(data: string): void;
|
|
24
24
|
private _write;
|
|
25
25
|
onping(_data: string): void;
|
|
@@ -18,38 +18,51 @@ class SeyfertWebSocket {
|
|
|
18
18
|
this.path = `${urlParts.pathname}${urlParts.search || ''}`;
|
|
19
19
|
this.connect();
|
|
20
20
|
}
|
|
21
|
-
connect() {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
21
|
+
connect(retries = 0) {
|
|
22
|
+
return new Promise((resolve, rej) => {
|
|
23
|
+
const key = (0, node_crypto_1.randomBytes)(16).toString('base64');
|
|
24
|
+
const req = (0, node_https_1.request)({
|
|
25
|
+
//discord gateway hostname
|
|
26
|
+
hostname: this.hostname,
|
|
27
|
+
path: this.path,
|
|
28
|
+
headers: {
|
|
29
|
+
Connection: 'Upgrade',
|
|
30
|
+
Upgrade: 'websocket',
|
|
31
|
+
'Sec-WebSocket-Key': key,
|
|
32
|
+
'Sec-WebSocket-Version': '13',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
req.on('upgrade', (res, socket) => {
|
|
36
|
+
const hash = (0, node_crypto_1.createHash)('sha1').update(`${key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`).digest('base64');
|
|
37
|
+
const accept = res.headers['sec-websocket-accept'];
|
|
38
|
+
if (accept !== hash) {
|
|
39
|
+
socket.end(() => {
|
|
40
|
+
rej(new Error('Invalid sec-websocket-accept header'));
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.socket = socket;
|
|
45
|
+
socket.on('readable', this.handleReadable.bind(this));
|
|
46
|
+
socket.on('close', this.handleClose.bind(this));
|
|
47
|
+
socket.on('error', err => this.onerror(err));
|
|
48
|
+
resolve();
|
|
49
|
+
this.onopen();
|
|
50
|
+
});
|
|
51
|
+
req.on('close', () => {
|
|
52
|
+
req.removeAllListeners();
|
|
53
|
+
});
|
|
54
|
+
req.on('error', e => {
|
|
55
|
+
if (retries < 5) {
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
resolve(this.connect(retries + 1));
|
|
58
|
+
}, 500);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
rej(e);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
req.end();
|
|
51
65
|
});
|
|
52
|
-
req.end();
|
|
53
66
|
}
|
|
54
67
|
handleReadable() {
|
|
55
68
|
// Keep reading until no data, this is useful when two payloads merges.
|
|
@@ -66,9 +79,11 @@ class SeyfertWebSocket {
|
|
|
66
79
|
// Equivalent to readUint32BE
|
|
67
80
|
length = this.readBytes(2, slice - 2);
|
|
68
81
|
}
|
|
82
|
+
const payloadLength = slice + length;
|
|
69
83
|
// Read the frame, ignore data next to it, leave it to next `while` cycle
|
|
70
|
-
const frame = this.socket.read(
|
|
71
|
-
|
|
84
|
+
const frame = this.socket.read(payloadLength);
|
|
85
|
+
// unfinished object when socket closes while reading the data
|
|
86
|
+
if (!frame || frame.length !== payloadLength)
|
|
72
87
|
return;
|
|
73
88
|
// Get fin (0 | 1)
|
|
74
89
|
const fin = frame[0] >> 7;
|
|
@@ -131,7 +146,7 @@ class SeyfertWebSocket {
|
|
|
131
146
|
break;
|
|
132
147
|
}
|
|
133
148
|
}
|
|
134
|
-
handleClose() {
|
|
149
|
+
async handleClose() {
|
|
135
150
|
this.socket?.removeAllListeners();
|
|
136
151
|
this.socket?.destroy();
|
|
137
152
|
this.socket = undefined;
|
|
@@ -146,6 +161,8 @@ class SeyfertWebSocket {
|
|
|
146
161
|
this._write(Buffer.from(data), 1);
|
|
147
162
|
}
|
|
148
163
|
_write(buffer, opcode) {
|
|
164
|
+
if (!this.socket?.writable)
|
|
165
|
+
return;
|
|
149
166
|
const length = buffer.length;
|
|
150
167
|
let frame;
|
|
151
168
|
// Kinda same logic as above, but client-side
|
|
@@ -35,6 +35,7 @@ export type WorkerSendInfo = CreateWorkerMessage<'WORKER_INFO', WorkerInfo & {
|
|
|
35
35
|
nonce: string;
|
|
36
36
|
}>;
|
|
37
37
|
export type WorkerReady = CreateWorkerMessage<'WORKER_READY'>;
|
|
38
|
+
export type WorkerShardsConnected = CreateWorkerMessage<'WORKER_SHARDS_CONNECTED'>;
|
|
38
39
|
export type WorkerStart = CreateWorkerMessage<'WORKER_START'>;
|
|
39
40
|
export type WorkerSendApiRequest = CreateWorkerMessage<'WORKER_API_REQUEST', {
|
|
40
41
|
method: HttpMethods;
|
|
@@ -51,5 +52,5 @@ export type WorkerSendEval = CreateWorkerMessage<'EVAL', {
|
|
|
51
52
|
nonce: string;
|
|
52
53
|
toWorkerId: number;
|
|
53
54
|
}>;
|
|
54
|
-
export type WorkerMessage = WorkerRequestConnect | WorkerReceivePayload | WorkerSendResultPayload | WorkerSendCacheRequest | WorkerSendShardInfo | WorkerSendInfo | WorkerReady | WorkerSendApiRequest | WorkerSendEvalResponse | WorkerSendEval | WorkerStart;
|
|
55
|
+
export type WorkerMessage = WorkerRequestConnect | WorkerReceivePayload | WorkerSendResultPayload | WorkerSendCacheRequest | WorkerSendShardInfo | WorkerSendInfo | WorkerReady | WorkerShardsConnected | WorkerSendApiRequest | WorkerSendEvalResponse | WorkerSendEval | WorkerStart;
|
|
55
56
|
export {};
|
|
@@ -14,6 +14,7 @@ export declare class WorkerManager extends Map<number, (ClusterWorker | import('
|
|
|
14
14
|
options: MakePartial<Required<WorkerManagerOptions>, 'adapter'>;
|
|
15
15
|
debugger?: Logger;
|
|
16
16
|
connectQueue: ConnectQueue;
|
|
17
|
+
workerQueue: (() => void)[];
|
|
17
18
|
cacheAdapter: Adapter;
|
|
18
19
|
promises: Map<string, {
|
|
19
20
|
resolve: (value: any) => void;
|
|
@@ -50,7 +51,7 @@ export declare class WorkerManager extends Map<number, (ClusterWorker | import('
|
|
|
50
51
|
send(data: GatewaySendPayload, shardId: number): Promise<true>;
|
|
51
52
|
getShardInfo(shardId: number): Promise<WorkerShardInfo>;
|
|
52
53
|
getWorkerInfo(workerId: number): Promise<WorkerInfo>;
|
|
53
|
-
start(): Promise<void>;
|
|
54
|
+
start(): Promise<void | undefined>;
|
|
54
55
|
}
|
|
55
56
|
type CreateManagerMessage<T extends string, D extends object = {}> = {
|
|
56
57
|
type: T;
|
|
@@ -17,6 +17,7 @@ class WorkerManager extends Map {
|
|
|
17
17
|
options;
|
|
18
18
|
debugger;
|
|
19
19
|
connectQueue;
|
|
20
|
+
workerQueue = [];
|
|
20
21
|
cacheAdapter;
|
|
21
22
|
promises = new Map();
|
|
22
23
|
rest;
|
|
@@ -109,20 +110,22 @@ class WorkerManager extends Map {
|
|
|
109
110
|
if (!worker_threads)
|
|
110
111
|
throw new Error('Cannot prepare workers without worker_threads.');
|
|
111
112
|
for (let i = 0; i < shards.length; i++) {
|
|
112
|
-
|
|
113
|
-
if (!
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
113
|
+
const workerExists = this.has(i);
|
|
114
|
+
if (!workerExists) {
|
|
115
|
+
this.workerQueue.push(() => {
|
|
116
|
+
const worker = this.createWorker({
|
|
117
|
+
path: this.options.path,
|
|
118
|
+
debug: this.options.debug,
|
|
119
|
+
token: this.options.token,
|
|
120
|
+
shards: shards[i],
|
|
121
|
+
intents: this.options.intents,
|
|
122
|
+
workerId: i,
|
|
123
|
+
workerProxy: this.options.workerProxy,
|
|
124
|
+
totalShards: this.totalShards,
|
|
125
|
+
mode: this.options.mode,
|
|
126
|
+
});
|
|
127
|
+
this.set(i, worker);
|
|
124
128
|
});
|
|
125
|
-
this.set(i, worker);
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
}
|
|
@@ -260,6 +263,18 @@ class WorkerManager extends Map {
|
|
|
260
263
|
}
|
|
261
264
|
}
|
|
262
265
|
break;
|
|
266
|
+
case 'WORKER_SHARDS_CONNECTED':
|
|
267
|
+
{
|
|
268
|
+
const nextWorker = this.workerQueue.shift();
|
|
269
|
+
if (nextWorker) {
|
|
270
|
+
this.debugger?.info('Spawning next worker');
|
|
271
|
+
nextWorker();
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
this.debugger?.info('No more workers to spawn left');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
break;
|
|
263
278
|
case 'WORKER_API_REQUEST':
|
|
264
279
|
{
|
|
265
280
|
const response = await this.rest.request(message.method, message.url, message.requestOptions);
|
|
@@ -377,6 +392,8 @@ class WorkerManager extends Map {
|
|
|
377
392
|
}
|
|
378
393
|
const spaces = this.prepareSpaces();
|
|
379
394
|
await this.prepareWorkers(spaces);
|
|
395
|
+
// Start workers queue
|
|
396
|
+
return this.workerQueue.shift()?.();
|
|
380
397
|
}
|
|
381
398
|
}
|
|
382
399
|
exports.WorkerManager = WorkerManager;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "seyfert",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "The most advanced framework for discord bots",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"module": "./lib/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"check": "biome check --write --no-errors-on-unmatched ./src"
|
|
19
19
|
},
|
|
20
20
|
"author": "MARCROCK22",
|
|
21
|
-
"license": "
|
|
21
|
+
"license": "MIT",
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@biomejs/biome": "1.8.3",
|
|
24
24
|
"@commitlint/cli": "^19.4.0",
|
|
@@ -61,5 +61,10 @@
|
|
|
61
61
|
"name": "David",
|
|
62
62
|
"url": "https://github.com/Drylozu"
|
|
63
63
|
}
|
|
64
|
-
]
|
|
64
|
+
],
|
|
65
|
+
"lint-staged": {
|
|
66
|
+
"*.ts": [
|
|
67
|
+
"biome check --write"
|
|
68
|
+
]
|
|
69
|
+
}
|
|
65
70
|
}
|