@wolfstar/plugin-sharder 0.0.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/LICENSE +202 -0
- package/README.md +344 -0
- package/dist/esm/index.d.ts +2052 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +3491 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,2052 @@
|
|
|
1
|
+
import { Err, Ok, Result, Result as Result$1 } from "@sapphire/result";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
import { WorkerOptions } from "node:worker_threads";
|
|
4
|
+
import { ZlibOptions } from "node:zlib";
|
|
5
|
+
import { Worker as Worker$1 } from "node:cluster";
|
|
6
|
+
import { ChildProcess } from "node:child_process";
|
|
7
|
+
import { ConnectionOptions, TlsOptions } from "node:tls";
|
|
8
|
+
//#region src/ShardPing.d.ts
|
|
9
|
+
/**
|
|
10
|
+
* The options of the manager's pings.
|
|
11
|
+
*/
|
|
12
|
+
export interface ShardPingOptions {
|
|
13
|
+
/**
|
|
14
|
+
* How often the manager pings each ready shard, in milliseconds; `-1` or `Infinity` disables the pings.
|
|
15
|
+
*
|
|
16
|
+
* @default 45_000
|
|
17
|
+
*/
|
|
18
|
+
interval?: number;
|
|
19
|
+
/**
|
|
20
|
+
* How long a ready shard may go without answering a ping, in milliseconds, before it is deemed unresponsive:
|
|
21
|
+
* emitted as `shardUnresponsive`, or restarted when nothing listens to it.
|
|
22
|
+
*
|
|
23
|
+
* @default 60_000
|
|
24
|
+
*/
|
|
25
|
+
timeout?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Whether the next ping is sent `interval` after the last answer, rather than after the last ping.
|
|
28
|
+
*
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
delaySinceReceived?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Pings a shard, measures its latency, and notices when it stops answering.
|
|
35
|
+
*/
|
|
36
|
+
export declare class ShardPing {
|
|
37
|
+
#private;
|
|
38
|
+
/**
|
|
39
|
+
* When the last ping was sent, `-1` before the first one.
|
|
40
|
+
*/
|
|
41
|
+
lastSentTimestamp: number;
|
|
42
|
+
/**
|
|
43
|
+
* When the last answer came, `-1` before the first one.
|
|
44
|
+
*/
|
|
45
|
+
lastReceivedTimestamp: number;
|
|
46
|
+
/**
|
|
47
|
+
* The round trip of the last ping, in milliseconds; `-1` before the first answer.
|
|
48
|
+
*/
|
|
49
|
+
latency: number;
|
|
50
|
+
readonly interval: number;
|
|
51
|
+
readonly timeout: number;
|
|
52
|
+
readonly delaySinceReceived: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
constructor(options: ShardPingOptions, send: (sentAt: number) => Promise<void>, onTimeout: () => void);
|
|
57
|
+
/**
|
|
58
|
+
* Whether the pings are running.
|
|
59
|
+
*/
|
|
60
|
+
get running(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Whether the last ping was answered.
|
|
63
|
+
*/
|
|
64
|
+
get hasReceivedResponse(): boolean;
|
|
65
|
+
get lastSentAt(): Date | null;
|
|
66
|
+
get lastReceivedAt(): Date | null;
|
|
67
|
+
/**
|
|
68
|
+
* When the next ping is due, or `null` when the pings are not running.
|
|
69
|
+
*/
|
|
70
|
+
get nextPingTimestamp(): number | null;
|
|
71
|
+
/**
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
start(): void;
|
|
75
|
+
/**
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
stop(): void;
|
|
79
|
+
/**
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
receive(sentAt: number): void;
|
|
83
|
+
/**
|
|
84
|
+
* Whether the manager pings at all.
|
|
85
|
+
*/
|
|
86
|
+
get enabled(): boolean;
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/messages/MessageHandler.d.ts
|
|
90
|
+
/**
|
|
91
|
+
* The data a channel carries between the manager and a shard, once serialized and transformed.
|
|
92
|
+
*/
|
|
93
|
+
export type ChannelData = string | Uint8Array;
|
|
94
|
+
/**
|
|
95
|
+
* Turns the packets exchanged by the manager and its shards into data a channel carries, and back.
|
|
96
|
+
*
|
|
97
|
+
* @remarks
|
|
98
|
+
* The manager tells its shards the name of its handler, and {@link ShardClient} builds the same one from the registry
|
|
99
|
+
* (see {@link registerMessageHandler}): a custom handler must be registered in the shards too.
|
|
100
|
+
*/
|
|
101
|
+
export interface MessageHandler {
|
|
102
|
+
/**
|
|
103
|
+
* The name of the handler in the registry.
|
|
104
|
+
*/
|
|
105
|
+
readonly name: string;
|
|
106
|
+
serialize(packet: unknown): unknown;
|
|
107
|
+
deserialize(data: unknown): unknown;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Serializes packets as JSON: every body must be JSON-serializable. The default.
|
|
111
|
+
*/
|
|
112
|
+
export declare class JsonMessageHandler implements MessageHandler {
|
|
113
|
+
readonly name = "json";
|
|
114
|
+
serialize(packet: unknown): string;
|
|
115
|
+
deserialize(data: unknown): unknown;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Serializes packets with `node:v8`, which keeps `Map`s, `Set`s, `Date`s, `BigInt`s, typed arrays, and circular
|
|
119
|
+
* references.
|
|
120
|
+
*/
|
|
121
|
+
export declare class V8MessageHandler implements MessageHandler {
|
|
122
|
+
readonly name = "v8";
|
|
123
|
+
serialize(packet: unknown): Uint8Array;
|
|
124
|
+
deserialize(data: unknown): unknown;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Passes packets as they are, for channels that clone values themselves: worker threads, and processes with the
|
|
128
|
+
* `advanced` IPC serialization. It cannot be combined with transformers, nor cross the network.
|
|
129
|
+
*/
|
|
130
|
+
export declare class RawMessageHandler implements MessageHandler {
|
|
131
|
+
readonly name = "raw";
|
|
132
|
+
serialize(packet: unknown): unknown;
|
|
133
|
+
deserialize(data: unknown): unknown;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Registers a message handler under its name, so managers and shards can refer to it by name.
|
|
137
|
+
*
|
|
138
|
+
* @param name The name of the handler, the same as its `name`.
|
|
139
|
+
* @param factory Builds the handler.
|
|
140
|
+
*/
|
|
141
|
+
export declare function registerMessageHandler(name: string, factory: () => MessageHandler): void;
|
|
142
|
+
/**
|
|
143
|
+
* Resolves a message handler, or the name of a registered one.
|
|
144
|
+
*
|
|
145
|
+
* @param handler The handler, or its name.
|
|
146
|
+
*/
|
|
147
|
+
export declare function resolveMessageHandler(handler: MessageHandler | string): MessageHandler;
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/messages/MessageTransformer.d.ts
|
|
150
|
+
/**
|
|
151
|
+
* The channel a transformer reads or writes on.
|
|
152
|
+
*/
|
|
153
|
+
export interface TransformerContext {
|
|
154
|
+
/**
|
|
155
|
+
* The ID of the channel: the shard the data comes from or goes to.
|
|
156
|
+
*/
|
|
157
|
+
channelId: number;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Transforms serialized data on its way to the channel, and back: compression, encryption, signing, ...
|
|
161
|
+
*
|
|
162
|
+
* @remarks
|
|
163
|
+
* Transformers compose: they write in the order they are given, and read in the reverse order. `[gzip, aes]` gzips
|
|
164
|
+
* then encrypts when writing, and decrypts then gunzips when reading. A transformer throwing while reading rejects the
|
|
165
|
+
* data, which is reported as an invalid message.
|
|
166
|
+
*
|
|
167
|
+
* Like {@link MessageHandler}s, the manager tells its shards the names of its transformers: custom ones must be
|
|
168
|
+
* registered in the shards too, see {@link registerMessageTransformer}.
|
|
169
|
+
*/
|
|
170
|
+
export interface MessageTransformer {
|
|
171
|
+
/**
|
|
172
|
+
* The name of the transformer in the registry.
|
|
173
|
+
*/
|
|
174
|
+
readonly name: string;
|
|
175
|
+
write(data: ChannelData, context: TransformerContext): ChannelData | Promise<ChannelData>;
|
|
176
|
+
read(data: ChannelData, context: TransformerContext): ChannelData | Promise<ChannelData>;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Compresses messages with gzip.
|
|
180
|
+
*/
|
|
181
|
+
export declare class GzipTransformer implements MessageTransformer {
|
|
182
|
+
readonly name = "gzip";
|
|
183
|
+
private readonly options;
|
|
184
|
+
/**
|
|
185
|
+
* @param options The compression options, e.g. its `level`.
|
|
186
|
+
*/
|
|
187
|
+
constructor(options?: ZlibOptions);
|
|
188
|
+
write(data: ChannelData): Promise<Uint8Array>;
|
|
189
|
+
read(data: ChannelData): Promise<Uint8Array>;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Compresses messages with Brotli, smaller than gzip at a higher CPU cost.
|
|
193
|
+
*/
|
|
194
|
+
export declare class BrotliTransformer implements MessageTransformer {
|
|
195
|
+
readonly name = "brotli";
|
|
196
|
+
write(data: ChannelData): Promise<Uint8Array>;
|
|
197
|
+
read(data: ChannelData): Promise<Uint8Array>;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Registers a message transformer under its name, so managers and shards can refer to it by name.
|
|
201
|
+
*
|
|
202
|
+
* @param name The name of the transformer, the same as its `name`.
|
|
203
|
+
* @param factory Builds the transformer, e.g. with a key read from the environment.
|
|
204
|
+
*/
|
|
205
|
+
export declare function registerMessageTransformer(name: string, factory: () => MessageTransformer): void;
|
|
206
|
+
/**
|
|
207
|
+
* Resolves a message transformer, or the name of a registered one.
|
|
208
|
+
*
|
|
209
|
+
* @param transformer The transformer, or its name.
|
|
210
|
+
*/
|
|
211
|
+
export declare function resolveMessageTransformer(transformer: MessageTransformer | string): MessageTransformer;
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/messages/protocol.d.ts
|
|
214
|
+
/**
|
|
215
|
+
* The lifecycle status of a shard, as it signals it to its manager.
|
|
216
|
+
*/
|
|
217
|
+
export declare const ShardStatus: {
|
|
218
|
+
/**
|
|
219
|
+
* Not spawned yet, or stopped.
|
|
220
|
+
*/
|
|
221
|
+
readonly Idle: "Idle";
|
|
222
|
+
/**
|
|
223
|
+
* Spawned, and not ready to answer yet.
|
|
224
|
+
*/
|
|
225
|
+
readonly Starting: "Starting";
|
|
226
|
+
/**
|
|
227
|
+
* Fully operative.
|
|
228
|
+
*/
|
|
229
|
+
readonly Ready: "Ready";
|
|
230
|
+
/**
|
|
231
|
+
* Running, but disconnected from what it serves, e.g. the gateway.
|
|
232
|
+
*/
|
|
233
|
+
readonly Disconnected: "Disconnected";
|
|
234
|
+
/**
|
|
235
|
+
* Running, and reconnecting to what it serves.
|
|
236
|
+
*/
|
|
237
|
+
readonly Reconnecting: "Reconnecting";
|
|
238
|
+
/**
|
|
239
|
+
* Shutting down, not to be restarted.
|
|
240
|
+
*/
|
|
241
|
+
readonly Exiting: "Exiting";
|
|
242
|
+
/**
|
|
243
|
+
* Shutting down, to be restarted.
|
|
244
|
+
*/
|
|
245
|
+
readonly Restarting: "Restarting";
|
|
246
|
+
};
|
|
247
|
+
export type ShardStatus = (typeof ShardStatus)[keyof typeof ShardStatus];
|
|
248
|
+
/**
|
|
249
|
+
* Where a message or a request goes: a shard's ID, or `"all"` for every shard. Left out, it goes to the manager.
|
|
250
|
+
*/
|
|
251
|
+
type ShardTarget = number | "all";
|
|
252
|
+
/**
|
|
253
|
+
* The operation of a packet.
|
|
254
|
+
*
|
|
255
|
+
* @internal
|
|
256
|
+
*/
|
|
257
|
+
declare const Op: {
|
|
258
|
+
readonly Signal: 0;
|
|
259
|
+
readonly Ping: 1;
|
|
260
|
+
readonly Pong: 2;
|
|
261
|
+
readonly Message: 3;
|
|
262
|
+
readonly Request: 4;
|
|
263
|
+
readonly Reply: 5;
|
|
264
|
+
readonly Abort: 6;
|
|
265
|
+
readonly Close: 7;
|
|
266
|
+
};
|
|
267
|
+
/**
|
|
268
|
+
* @internal
|
|
269
|
+
*/
|
|
270
|
+
type Op = (typeof Op)[keyof typeof Op];
|
|
271
|
+
/**
|
|
272
|
+
* The requests the sharder itself sends, rather than the application.
|
|
273
|
+
*
|
|
274
|
+
* - `identify` (shard → manager): waits for the turn of a gateway shard to identify. Body: the gateway shard ID.
|
|
275
|
+
* - `gatewayInformation` (shard → manager): the manager's cached `GET /gateway/bot`.
|
|
276
|
+
* - `control` (shard → manager): starts, closes, or restarts shards or gateway shards. Body: {@link ControlRequest}.
|
|
277
|
+
* - `startShard` / `closeShard` (manager → shard): starts or closes a gateway shard. Body: the gateway shard ID.
|
|
278
|
+
*
|
|
279
|
+
* @internal
|
|
280
|
+
*/
|
|
281
|
+
type SystemCall = "identify" | "gatewayInformation" | "control" | "startShard" | "closeShard";
|
|
282
|
+
/**
|
|
283
|
+
* What a shard asks its manager to start, close, or restart.
|
|
284
|
+
*/
|
|
285
|
+
interface ControlRequest {
|
|
286
|
+
action: "start" | "close" | "restart";
|
|
287
|
+
/**
|
|
288
|
+
* A shard (`{ channel }`, or `"all"`), or a gateway shard (`{ shard }`).
|
|
289
|
+
*/
|
|
290
|
+
target: {
|
|
291
|
+
channel: ShardTarget;
|
|
292
|
+
} | {
|
|
293
|
+
shard: number;
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* The error of a failed request, as sent over the channel.
|
|
298
|
+
*
|
|
299
|
+
* @internal
|
|
300
|
+
*/
|
|
301
|
+
interface SerializedError {
|
|
302
|
+
name: string;
|
|
303
|
+
message: string;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* The packets exchanged between the manager and its shards, before serialization.
|
|
307
|
+
*
|
|
308
|
+
* @internal
|
|
309
|
+
*/
|
|
310
|
+
type Packet = {
|
|
311
|
+
op: typeof Op.Signal;
|
|
312
|
+
status: ShardStatus;
|
|
313
|
+
} | {
|
|
314
|
+
op: typeof Op.Ping;
|
|
315
|
+
sentAt: number;
|
|
316
|
+
} | {
|
|
317
|
+
op: typeof Op.Pong;
|
|
318
|
+
sentAt: number;
|
|
319
|
+
} | {
|
|
320
|
+
op: typeof Op.Message;
|
|
321
|
+
body: unknown;
|
|
322
|
+
to?: ShardTarget;
|
|
323
|
+
from?: number | null;
|
|
324
|
+
} | {
|
|
325
|
+
op: typeof Op.Request;
|
|
326
|
+
nonce: number;
|
|
327
|
+
body: unknown;
|
|
328
|
+
to?: ShardTarget;
|
|
329
|
+
from?: number | null;
|
|
330
|
+
timeout?: number;
|
|
331
|
+
/**
|
|
332
|
+
* For broadcasts: reply with every outcome rather than rejecting on the first failure.
|
|
333
|
+
*/
|
|
334
|
+
partial?: boolean;
|
|
335
|
+
system?: SystemCall;
|
|
336
|
+
} | {
|
|
337
|
+
op: typeof Op.Reply;
|
|
338
|
+
nonce: number;
|
|
339
|
+
body?: unknown;
|
|
340
|
+
error?: SerializedError;
|
|
341
|
+
} | {
|
|
342
|
+
op: typeof Op.Abort;
|
|
343
|
+
nonce: number;
|
|
344
|
+
} | {
|
|
345
|
+
op: typeof Op.Close;
|
|
346
|
+
};
|
|
347
|
+
/**
|
|
348
|
+
* Serializes packets with a {@link MessageHandler}, then runs them through the {@link MessageTransformer}s, and the
|
|
349
|
+
* other way around.
|
|
350
|
+
*
|
|
351
|
+
* @internal
|
|
352
|
+
*/
|
|
353
|
+
declare class PacketCodec {
|
|
354
|
+
readonly handler: MessageHandler;
|
|
355
|
+
readonly transformers: readonly MessageTransformer[];
|
|
356
|
+
constructor(handler: MessageHandler, transformers: readonly MessageTransformer[]);
|
|
357
|
+
encode(packet: Packet, context: TransformerContext): Promise<unknown>;
|
|
358
|
+
decode(data: unknown, context: TransformerContext): Promise<Packet>;
|
|
359
|
+
}
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/strategies/ChannelStrategy.d.ts
|
|
362
|
+
/**
|
|
363
|
+
* What a shard is told about itself when spawned, read back by {@link ShardClient}.
|
|
364
|
+
*/
|
|
365
|
+
export interface ShardContext {
|
|
366
|
+
/**
|
|
367
|
+
* The ID of the shard: the index of its channel in the manager.
|
|
368
|
+
*/
|
|
369
|
+
id: number;
|
|
370
|
+
/**
|
|
371
|
+
* The IDs of the gateway shards the shard connects.
|
|
372
|
+
*/
|
|
373
|
+
shards: readonly number[];
|
|
374
|
+
/**
|
|
375
|
+
* The total number of gateway shards, across every shard (and every manager).
|
|
376
|
+
*/
|
|
377
|
+
shardCount: number;
|
|
378
|
+
/**
|
|
379
|
+
* How long the ready shard may go without a ping from its manager, in milliseconds, before
|
|
380
|
+
* `managerUnresponsive`; `null` when the manager does not ping.
|
|
381
|
+
*/
|
|
382
|
+
pingTimeout: number | null;
|
|
383
|
+
/**
|
|
384
|
+
* How long the shard waits for the replies of its requests by default, in milliseconds.
|
|
385
|
+
*/
|
|
386
|
+
requestTimeout: number;
|
|
387
|
+
/**
|
|
388
|
+
* The name of the manager's message handler.
|
|
389
|
+
*/
|
|
390
|
+
messageHandler: string;
|
|
391
|
+
/**
|
|
392
|
+
* The names of the manager's message transformers, in order.
|
|
393
|
+
*/
|
|
394
|
+
transformers: readonly string[];
|
|
395
|
+
/**
|
|
396
|
+
* How the shard talks to its parent: the process IPC channel, or its worker thread port. Set by the strategy.
|
|
397
|
+
*/
|
|
398
|
+
transport?: "process" | "worker";
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* The callbacks a {@link ChannelStrategy} reports a spawned shard's activity through.
|
|
402
|
+
*/
|
|
403
|
+
export interface ShardTransportEvents {
|
|
404
|
+
message(data: unknown): void;
|
|
405
|
+
/**
|
|
406
|
+
* The shard stopped. Called once per spawn.
|
|
407
|
+
*/
|
|
408
|
+
exit(code: number | null): void;
|
|
409
|
+
/**
|
|
410
|
+
* The shard failed, e.g. a worker that could not start.
|
|
411
|
+
*/
|
|
412
|
+
error(error: unknown): void;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* What a strategy spawns a shard with, on top of its context.
|
|
416
|
+
*/
|
|
417
|
+
export interface SpawnOptions {
|
|
418
|
+
/**
|
|
419
|
+
* Environment variables for the shard, e.g. `DISCORD_TOKEN`.
|
|
420
|
+
*/
|
|
421
|
+
env: Record<string, string>;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* The manager's end of the channel to one spawned shard.
|
|
425
|
+
*/
|
|
426
|
+
export interface ShardTransport {
|
|
427
|
+
send(data: unknown): Promise<void>;
|
|
428
|
+
/**
|
|
429
|
+
* Stops the shard, resolving once it stopped.
|
|
430
|
+
*/
|
|
431
|
+
kill(): Promise<void>;
|
|
432
|
+
/**
|
|
433
|
+
* The ID of the shard's process, for observability.
|
|
434
|
+
*/
|
|
435
|
+
readonly pid?: number | null;
|
|
436
|
+
/**
|
|
437
|
+
* The ID of the shard's worker thread.
|
|
438
|
+
*/
|
|
439
|
+
readonly threadId?: number | null;
|
|
440
|
+
/**
|
|
441
|
+
* The host running the shard, for strategies spawning shards elsewhere.
|
|
442
|
+
*/
|
|
443
|
+
readonly host?: string | null;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Spawns shards: as child processes, cluster workers, worker threads, on other machines, or anything else. The
|
|
447
|
+
* sharder RFC's channel strategy.
|
|
448
|
+
*/
|
|
449
|
+
export interface ChannelStrategy {
|
|
450
|
+
/**
|
|
451
|
+
* The name of the strategy in the registry, see {@link registerStrategy}.
|
|
452
|
+
*/
|
|
453
|
+
readonly name: string;
|
|
454
|
+
/**
|
|
455
|
+
* Prepares the strategy before the first spawn, e.g. starts listening for proxies.
|
|
456
|
+
*/
|
|
457
|
+
init?(): Promise<void>;
|
|
458
|
+
/**
|
|
459
|
+
* Releases what the strategy holds, once every shard is closed.
|
|
460
|
+
*/
|
|
461
|
+
destroy?(): Promise<void>;
|
|
462
|
+
spawn(context: ShardContext, events: ShardTransportEvents, options: SpawnOptions): ShardTransport;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* The environment variable carrying the {@link ShardContext} of a shard.
|
|
466
|
+
*/
|
|
467
|
+
export declare const ShardContextVariable = "WOLFSTAR_SHARDER";
|
|
468
|
+
/**
|
|
469
|
+
* Serializes a shard's context for its environment or worker data.
|
|
470
|
+
*
|
|
471
|
+
* @internal
|
|
472
|
+
*/
|
|
473
|
+
export declare function encodeContext(context: ShardContext): string;
|
|
474
|
+
//#endregion
|
|
475
|
+
//#region src/util/errors.d.ts
|
|
476
|
+
/**
|
|
477
|
+
* What a sharder operation fails with: the `E` of the `try*` methods' `Result<T, E>`.
|
|
478
|
+
*/
|
|
479
|
+
export type ShardError = ShardRequestError | ShardRequestTimeoutError | ShardUnavailableError | ShardSpawnError | Error;
|
|
480
|
+
/**
|
|
481
|
+
* The handler of a request threw, or there was none: the error is the remote one, rebuilt.
|
|
482
|
+
*/
|
|
483
|
+
export declare class ShardRequestError extends Error {
|
|
484
|
+
/**
|
|
485
|
+
* The name of the remote error, e.g. `TypeError`.
|
|
486
|
+
*/
|
|
487
|
+
readonly remoteName: string;
|
|
488
|
+
constructor(remoteName: string, message: string);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* A request got no reply in time. The other side was told to abort it.
|
|
492
|
+
*/
|
|
493
|
+
export declare class ShardRequestTimeoutError extends Error {
|
|
494
|
+
readonly timeout: number;
|
|
495
|
+
constructor(timeout: number);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* A shard stopped, is not ready in time, or does not exist.
|
|
499
|
+
*/
|
|
500
|
+
export declare class ShardUnavailableError extends Error {
|
|
501
|
+
readonly channelId: number;
|
|
502
|
+
constructor(channelId: number, reason: string);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* A shard failed before it was ready: its process exited, or its worker could not start. The sharder RFC's `error`
|
|
506
|
+
* signal.
|
|
507
|
+
*/
|
|
508
|
+
export declare class ShardSpawnError extends Error {
|
|
509
|
+
readonly channelId: number;
|
|
510
|
+
/**
|
|
511
|
+
* The exit code, when the shard exited.
|
|
512
|
+
*/
|
|
513
|
+
readonly code: number | null;
|
|
514
|
+
constructor(channelId: number, code: number | null, cause?: unknown);
|
|
515
|
+
}
|
|
516
|
+
//#endregion
|
|
517
|
+
//#region src/util/gateway.d.ts
|
|
518
|
+
/**
|
|
519
|
+
* The `GET /gateway/bot` payload, the same shape as discord-api-types' `APIGatewayBotInfo`, which `@discordjs/ws`'s
|
|
520
|
+
* `WebSocketManager#fetchGatewayInformation` returns.
|
|
521
|
+
*/
|
|
522
|
+
interface GatewayInformation {
|
|
523
|
+
url: string;
|
|
524
|
+
shards: number;
|
|
525
|
+
session_start_limit: {
|
|
526
|
+
total: number;
|
|
527
|
+
remaining: number;
|
|
528
|
+
/**
|
|
529
|
+
* In milliseconds.
|
|
530
|
+
*/
|
|
531
|
+
reset_after: number;
|
|
532
|
+
max_concurrency: number;
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* The options of {@link fetchRecommendedShardCount}.
|
|
537
|
+
*/
|
|
538
|
+
interface RecommendedShardCountOptions {
|
|
539
|
+
/**
|
|
540
|
+
* How many guilds a gateway shard should hold. Discord's recommendation is based on 1000.
|
|
541
|
+
*
|
|
542
|
+
* @default 1000
|
|
543
|
+
*/
|
|
544
|
+
guildsPerShard?: number;
|
|
545
|
+
/**
|
|
546
|
+
* Rounds the count up to a multiple of it, e.g. 16 for large bot sharding.
|
|
547
|
+
*
|
|
548
|
+
* @default 1
|
|
549
|
+
*/
|
|
550
|
+
multipleOf?: number;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Fetches `GET /gateway/bot`.
|
|
554
|
+
*
|
|
555
|
+
* @param token The bot token.
|
|
556
|
+
*/
|
|
557
|
+
export declare function fetchGatewayInformation(token: string): Promise<GatewayInformation>;
|
|
558
|
+
/**
|
|
559
|
+
* Turns Discord's recommended shard count into the one to spawn.
|
|
560
|
+
*
|
|
561
|
+
* @param recommended The `shards` of `GET /gateway/bot`.
|
|
562
|
+
* @param options How many guilds per gateway shard, and what to round the count up to.
|
|
563
|
+
*/
|
|
564
|
+
export declare function resolveRecommendedShardCount(recommended: number, options?: RecommendedShardCountOptions): number;
|
|
565
|
+
/**
|
|
566
|
+
* Fetches how many gateway shards Discord recommends for the bot, like discord.js's `fetchRecommendedShardCount`.
|
|
567
|
+
*
|
|
568
|
+
* @param token The bot token.
|
|
569
|
+
* @param options How many guilds per gateway shard, and what to round the count up to.
|
|
570
|
+
*/
|
|
571
|
+
export declare function fetchRecommendedShardCount(token: string, options?: RecommendedShardCountOptions): Promise<number>;
|
|
572
|
+
/**
|
|
573
|
+
* Gets the gateway shard receiving the events of a guild.
|
|
574
|
+
*
|
|
575
|
+
* @param guildId The ID of the guild.
|
|
576
|
+
* @param shardCount The total number of gateway shards.
|
|
577
|
+
*/
|
|
578
|
+
export declare function shardIdForGuild(guildId: string, shardCount: number): number;
|
|
579
|
+
//#endregion
|
|
580
|
+
//#region src/util/requests.d.ts
|
|
581
|
+
/**
|
|
582
|
+
* The options of a request.
|
|
583
|
+
*/
|
|
584
|
+
interface RequestOptions {
|
|
585
|
+
/**
|
|
586
|
+
* How long to wait for the reply, in milliseconds. Defaults to the manager's `requestTimeout`.
|
|
587
|
+
*/
|
|
588
|
+
timeout?: number;
|
|
589
|
+
/**
|
|
590
|
+
* Aborts the request: dropped from the queue if it waits for a shard to be ready, and aborted on the other side
|
|
591
|
+
* otherwise, whose handler gets an aborted `signal`.
|
|
592
|
+
*/
|
|
593
|
+
signal?: AbortSignal;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* The options of a broadcast request.
|
|
597
|
+
*/
|
|
598
|
+
interface BroadcastRequestOptions extends RequestOptions {
|
|
599
|
+
/**
|
|
600
|
+
* Whether to resolve with the outcome of every shard, like `Promise.allSettled`, rather than rejecting on the first
|
|
601
|
+
* failure: the replies that came before a timeout or an abort are kept.
|
|
602
|
+
*/
|
|
603
|
+
partial?: boolean;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Answers the requests of the other side. Its return value (or the value it resolves to) is the reply, and a throw is
|
|
607
|
+
* rejected on the other side as a {@link ShardRequestError}. It may also return a `Result`: `Ok` is the reply, `Err`
|
|
608
|
+
* the error.
|
|
609
|
+
*/
|
|
610
|
+
type RequestHandler<Context> = (body: any, context: Context & {
|
|
611
|
+
signal: AbortSignal;
|
|
612
|
+
}) => unknown;
|
|
613
|
+
//#endregion
|
|
614
|
+
//#region src/util/Supervisor.d.ts
|
|
615
|
+
/**
|
|
616
|
+
* What else restarts when a shard crashes, after Erlang/OTP's supervisor strategies.
|
|
617
|
+
*
|
|
618
|
+
* - `one-for-one`: only the crashed shard.
|
|
619
|
+
* - `one-for-all`: every shard.
|
|
620
|
+
* - `rest-for-one`: the crashed shard, and every shard after it.
|
|
621
|
+
*/
|
|
622
|
+
type SupervisorStrategy = "one-for-one" | "one-for-all" | "rest-for-one";
|
|
623
|
+
/**
|
|
624
|
+
* How a manager restarts crashing shards, after Erlang/OTP's supervisors: a shard crashing more than `intensity`
|
|
625
|
+
* times within `period` is given up on.
|
|
626
|
+
*/
|
|
627
|
+
interface SupervisorOptions {
|
|
628
|
+
/**
|
|
629
|
+
* How many crashes are tolerated, `-1` or `Infinity` for no limit.
|
|
630
|
+
*
|
|
631
|
+
* @default -1
|
|
632
|
+
*/
|
|
633
|
+
intensity?: number;
|
|
634
|
+
/**
|
|
635
|
+
* The window the crashes are counted in, in milliseconds. `0` counts the crashes in a row instead, until the shard
|
|
636
|
+
* is ready again.
|
|
637
|
+
*
|
|
638
|
+
* @default 0
|
|
639
|
+
*/
|
|
640
|
+
period?: number;
|
|
641
|
+
/**
|
|
642
|
+
* @default "one-for-one"
|
|
643
|
+
*/
|
|
644
|
+
strategy?: SupervisorStrategy;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Counts the crashes of each shard against the supervisor's intensity.
|
|
648
|
+
*
|
|
649
|
+
* @internal
|
|
650
|
+
*/
|
|
651
|
+
declare class Supervisor {
|
|
652
|
+
#private;
|
|
653
|
+
readonly intensity: number;
|
|
654
|
+
readonly period: number;
|
|
655
|
+
readonly strategy: SupervisorStrategy;
|
|
656
|
+
constructor(options?: SupervisorOptions);
|
|
657
|
+
/**
|
|
658
|
+
* Counts a crash. Returns how many crashes count, and whether the shard may be restarted.
|
|
659
|
+
*
|
|
660
|
+
* @param channelId The ID of the crashed shard.
|
|
661
|
+
*/
|
|
662
|
+
crash(channelId: number): {
|
|
663
|
+
crashes: number;
|
|
664
|
+
restart: boolean;
|
|
665
|
+
};
|
|
666
|
+
/**
|
|
667
|
+
* Forgets the crashes of a shard that is ready again, when they are counted in a row.
|
|
668
|
+
*
|
|
669
|
+
* @param channelId The ID of the shard.
|
|
670
|
+
*/
|
|
671
|
+
ready(channelId: number): void;
|
|
672
|
+
}
|
|
673
|
+
//#endregion
|
|
674
|
+
//#region src/ShardManager.d.ts
|
|
675
|
+
/**
|
|
676
|
+
* How the gateway shards are laid out across shards.
|
|
677
|
+
*/
|
|
678
|
+
export interface ShardLayoutOptions {
|
|
679
|
+
/**
|
|
680
|
+
* The layout: a number spawns one shard per gateway shard, an array spawns one shard per entry connecting that
|
|
681
|
+
* many gateway shards, and `"auto"` splits the gateway shards across `clusters` shards.
|
|
682
|
+
*
|
|
683
|
+
* @default "auto"
|
|
684
|
+
* @example
|
|
685
|
+
* ```ts
|
|
686
|
+
* // 9 shards, connecting one gateway shard each.
|
|
687
|
+
* new ShardManager({ shards: 9 });
|
|
688
|
+
* // 3 shards, connecting 3 gateway shards each: 0-2, 3-5 and 6-8.
|
|
689
|
+
* new ShardManager({ shards: [3, 3, 3] });
|
|
690
|
+
* // Discord's recommended count, split across 4 shards.
|
|
691
|
+
* new ShardManager({ shards: "auto", clusters: 4 });
|
|
692
|
+
* ```
|
|
693
|
+
*/
|
|
694
|
+
shards?: number | readonly number[] | "auto";
|
|
695
|
+
/**
|
|
696
|
+
* The total number of gateway shards, across every manager: `"auto"` is Discord's recommendation. Defaults to the
|
|
697
|
+
* number of gateway shards of this manager.
|
|
698
|
+
*/
|
|
699
|
+
totalShards?: number | "auto";
|
|
700
|
+
/**
|
|
701
|
+
* The gateway shards this manager spawns, when several managers split them. Defaults to all of them.
|
|
702
|
+
*/
|
|
703
|
+
shardList?: readonly number[];
|
|
704
|
+
/**
|
|
705
|
+
* How many shards to split the gateway shards across, with `shards: "auto"`.
|
|
706
|
+
*
|
|
707
|
+
* @default os.availableParallelism()
|
|
708
|
+
*/
|
|
709
|
+
clusters?: number;
|
|
710
|
+
/**
|
|
711
|
+
* How Discord's recommended count is turned into the total, with `"auto"`.
|
|
712
|
+
*/
|
|
713
|
+
recommended?: RecommendedShardCountOptions;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* The options of a {@link ShardManager}.
|
|
717
|
+
*/
|
|
718
|
+
export interface ShardManagerOptions extends ShardLayoutOptions {
|
|
719
|
+
/**
|
|
720
|
+
* How to spawn the shards: a {@link ChannelStrategy}, or the name of a registered one (`"fork"`, `"cluster"`,
|
|
721
|
+
* `"worker"`, `"network"`), built with `strategyOptions`.
|
|
722
|
+
*
|
|
723
|
+
* @default "fork"
|
|
724
|
+
*/
|
|
725
|
+
strategy?: ChannelStrategy | string;
|
|
726
|
+
/**
|
|
727
|
+
* The options of a strategy given by name.
|
|
728
|
+
*/
|
|
729
|
+
strategyOptions?: unknown;
|
|
730
|
+
/**
|
|
731
|
+
* The bot token: used for `"auto"` layouts and `GET /gateway/bot`, and passed to the shards as `DISCORD_TOKEN`.
|
|
732
|
+
*
|
|
733
|
+
* @default process.env.DISCORD_TOKEN
|
|
734
|
+
*/
|
|
735
|
+
token?: string;
|
|
736
|
+
/**
|
|
737
|
+
* How `GET /gateway/bot` is fetched and cached. The shards get it from the manager, so it is fetched once for all.
|
|
738
|
+
*/
|
|
739
|
+
gatewayInformation?: {
|
|
740
|
+
/**
|
|
741
|
+
* Fetches it, instead of requesting Discord with the token.
|
|
742
|
+
*/
|
|
743
|
+
fetch?: () => Promise<GatewayInformation>;
|
|
744
|
+
/**
|
|
745
|
+
* How long to reuse it, in milliseconds; the session start limit is kept up to date meanwhile.
|
|
746
|
+
*
|
|
747
|
+
* @default 86_400_000
|
|
748
|
+
*/
|
|
749
|
+
ttl?: number;
|
|
750
|
+
};
|
|
751
|
+
/**
|
|
752
|
+
* How the identifies of the gateway shards are paced, across every shard. See {@link ShardClient.identifyThrottler}.
|
|
753
|
+
*/
|
|
754
|
+
identify?: {
|
|
755
|
+
/**
|
|
756
|
+
* How many gateway shards may identify at once: `"auto"` is the `max_concurrency` of `GET /gateway/bot`, or `1`
|
|
757
|
+
* without a token.
|
|
758
|
+
*
|
|
759
|
+
* @default "auto"
|
|
760
|
+
*/
|
|
761
|
+
concurrency?: number | "auto";
|
|
762
|
+
/**
|
|
763
|
+
* How long a concurrency bucket waits between identifies, in milliseconds.
|
|
764
|
+
*
|
|
765
|
+
* @default 5_000
|
|
766
|
+
*/
|
|
767
|
+
delay?: number;
|
|
768
|
+
};
|
|
769
|
+
/**
|
|
770
|
+
* How crashing shards are restarted.
|
|
771
|
+
*/
|
|
772
|
+
supervisor?: SupervisorOptions;
|
|
773
|
+
spawn?: {
|
|
774
|
+
/**
|
|
775
|
+
* How long to wait after a shard is ready before spawning the next one, in milliseconds. With
|
|
776
|
+
* {@link ShardClient.identifyThrottler} pacing the identifies, it can be `0`.
|
|
777
|
+
*
|
|
778
|
+
* @default 5_000
|
|
779
|
+
*/
|
|
780
|
+
delay?: number;
|
|
781
|
+
/**
|
|
782
|
+
* How long a shard has to signal that it is ready, in milliseconds. Past it, it is killed and spawned again at
|
|
783
|
+
* the end of the queue.
|
|
784
|
+
*
|
|
785
|
+
* @default 30_000
|
|
786
|
+
*/
|
|
787
|
+
timeout?: number;
|
|
788
|
+
/**
|
|
789
|
+
* How long a shard is expected to take to be ready, in milliseconds. Defaults to the average of the shards
|
|
790
|
+
* spawned so far. A shard slower than the estimate (plus the margin) is emitted as `shardSlowStart`, and a request
|
|
791
|
+
* for a starting shard that is not expected to be ready before its timeout is rejected right away.
|
|
792
|
+
*/
|
|
793
|
+
readyHint?: number;
|
|
794
|
+
/**
|
|
795
|
+
* The margin of error of the estimate, as a fraction of it.
|
|
796
|
+
*
|
|
797
|
+
* @default 0.1
|
|
798
|
+
*/
|
|
799
|
+
readyHintMargin?: number;
|
|
800
|
+
};
|
|
801
|
+
ping?: ShardPingOptions;
|
|
802
|
+
/**
|
|
803
|
+
* How long requests wait for their reply by default, in milliseconds.
|
|
804
|
+
*
|
|
805
|
+
* @default ping.timeout
|
|
806
|
+
*/
|
|
807
|
+
requestTimeout?: number;
|
|
808
|
+
/**
|
|
809
|
+
* How messages are serialized: a handler, or the name of a registered one. The shards build the same one.
|
|
810
|
+
*
|
|
811
|
+
* @default "json"
|
|
812
|
+
*/
|
|
813
|
+
messageHandler?: MessageHandler | string;
|
|
814
|
+
/**
|
|
815
|
+
* How serialized messages are transformed (compressed, encrypted, ...), in order: transformers, or names of
|
|
816
|
+
* registered ones. The shards build the same ones.
|
|
817
|
+
*
|
|
818
|
+
* @default []
|
|
819
|
+
*/
|
|
820
|
+
transformers?: readonly (MessageTransformer | string)[];
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* The events of a {@link ShardManager}.
|
|
824
|
+
*/
|
|
825
|
+
export interface ShardManagerEvents {
|
|
826
|
+
/**
|
|
827
|
+
* A shard was spawned.
|
|
828
|
+
*/
|
|
829
|
+
shardCreate: [channel: ShardChannel];
|
|
830
|
+
/**
|
|
831
|
+
* A shard signalled a new status, or stopped (`Idle`).
|
|
832
|
+
*/
|
|
833
|
+
shardStatus: [channel: ShardChannel, status: ShardStatus];
|
|
834
|
+
shardReady: [channel: ShardChannel];
|
|
835
|
+
shardDisconnect: [channel: ShardChannel];
|
|
836
|
+
shardReconnecting: [channel: ShardChannel];
|
|
837
|
+
/**
|
|
838
|
+
* A shard answered a ping; `latency` is the round trip, in milliseconds.
|
|
839
|
+
*/
|
|
840
|
+
shardPing: [channel: ShardChannel, latency: number];
|
|
841
|
+
/**
|
|
842
|
+
* A ready shard did not answer the pings in time. Without listeners, it is restarted.
|
|
843
|
+
*/
|
|
844
|
+
shardUnresponsive: [channel: ShardChannel];
|
|
845
|
+
/**
|
|
846
|
+
* A shard takes longer than the estimate (plus its margin) to be ready.
|
|
847
|
+
*/
|
|
848
|
+
shardSlowStart: [channel: ShardChannel, elapsed: number, estimate: number];
|
|
849
|
+
/**
|
|
850
|
+
* A shard is about to be spawned again: it asked for it, crashed, or was restarted.
|
|
851
|
+
*/
|
|
852
|
+
shardRestart: [channel: ShardChannel];
|
|
853
|
+
/**
|
|
854
|
+
* A shard's process or thread stopped.
|
|
855
|
+
*/
|
|
856
|
+
shardExit: [channel: ShardChannel, code: number | null];
|
|
857
|
+
/**
|
|
858
|
+
* A shard was closed by its manager.
|
|
859
|
+
*/
|
|
860
|
+
shardDestroy: [channel: ShardChannel];
|
|
861
|
+
/**
|
|
862
|
+
* A shard failed: it exited before it was ready (a {@link ShardSpawnError}), or its strategy reported an error.
|
|
863
|
+
* Without listeners, it goes to `error`.
|
|
864
|
+
*/
|
|
865
|
+
shardError: [channel: ShardChannel, error: unknown];
|
|
866
|
+
/**
|
|
867
|
+
* A shard crashed more often than the supervisor tolerates, and is not restarted anymore. Without listeners, it
|
|
868
|
+
* goes to `error`.
|
|
869
|
+
*/
|
|
870
|
+
shardGiveUp: [channel: ShardChannel, crashes: number];
|
|
871
|
+
/**
|
|
872
|
+
* A shard sent data that could not be read. Without listeners, it is logged with `console.error`.
|
|
873
|
+
*/
|
|
874
|
+
shardInvalidMessage: [channel: ShardChannel, error: unknown];
|
|
875
|
+
/**
|
|
876
|
+
* A shard sent a message to the manager.
|
|
877
|
+
*/
|
|
878
|
+
message: [body: any, channel: ShardChannel];
|
|
879
|
+
/**
|
|
880
|
+
* Without listeners, errors are logged with `console.error`.
|
|
881
|
+
*/
|
|
882
|
+
error: [error: unknown];
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Spawns shards, keeps them alive, and carries messages between them.
|
|
886
|
+
*
|
|
887
|
+
* @remarks
|
|
888
|
+
* Follows discord.js's sharder RFC (discordjs/discord.js#8084): a "shard" is a process, cluster worker, worker
|
|
889
|
+
* thread, or remote process, which may connect several gateway shards, and the manager talks to each through a
|
|
890
|
+
* {@link ShardChannel}. The manager is agnostic of the bot: a shard runs any script using {@link ShardClient}.
|
|
891
|
+
*
|
|
892
|
+
* @example
|
|
893
|
+
* ```ts
|
|
894
|
+
* const manager = new ShardManager({ strategy: new ForkStrategy({ path: "./bot.js" }), clusters: 4 });
|
|
895
|
+
* manager.setRequestHandler((body, { channel }) => ...);
|
|
896
|
+
* await manager.spawn();
|
|
897
|
+
* const guilds = await manager.broadcastRequest({ type: "guildCount" });
|
|
898
|
+
* ```
|
|
899
|
+
*/
|
|
900
|
+
export declare class ShardManager extends EventEmitter<ShardManagerEvents> {
|
|
901
|
+
#private;
|
|
902
|
+
readonly strategy: ChannelStrategy;
|
|
903
|
+
/**
|
|
904
|
+
* The channels to the shards, by ID. Empty until {@link ShardManager.spawn} for `"auto"` layouts.
|
|
905
|
+
*/
|
|
906
|
+
channels: readonly ShardChannel[];
|
|
907
|
+
/**
|
|
908
|
+
* The total number of gateway shards, `0` until resolved for `"auto"` layouts.
|
|
909
|
+
*/
|
|
910
|
+
shardCount: number;
|
|
911
|
+
readonly spawnDelay: number;
|
|
912
|
+
readonly spawnTimeout: number;
|
|
913
|
+
readonly readyHint: number | null;
|
|
914
|
+
readonly readyHintMargin: number;
|
|
915
|
+
readonly requestTimeout: number;
|
|
916
|
+
readonly pingOptions: Required<ShardPingOptions>;
|
|
917
|
+
/**
|
|
918
|
+
* @internal
|
|
919
|
+
*/
|
|
920
|
+
readonly codec: PacketCodec;
|
|
921
|
+
/**
|
|
922
|
+
* @internal
|
|
923
|
+
*/
|
|
924
|
+
readonly supervisor: Supervisor;
|
|
925
|
+
/**
|
|
926
|
+
* @internal
|
|
927
|
+
*/
|
|
928
|
+
readonly spawnEnv: Record<string, string>;
|
|
929
|
+
/**
|
|
930
|
+
* @internal
|
|
931
|
+
*/
|
|
932
|
+
requestHandler: RequestHandler<{
|
|
933
|
+
channel: ShardChannel;
|
|
934
|
+
}> | null;
|
|
935
|
+
constructor(options?: ShardManagerOptions);
|
|
936
|
+
/**
|
|
937
|
+
* How long a shard is expected to take to be ready: `spawn.readyHint`, or the average of the shards so far.
|
|
938
|
+
*/
|
|
939
|
+
get readyEstimate(): number | null;
|
|
940
|
+
/**
|
|
941
|
+
* Spawns every shard, one after the other, each waiting for the previous one to be ready plus the spawn delay. A
|
|
942
|
+
* shard not ready in time is killed and tried again at the end of the queue, as long as the supervisor allows.
|
|
943
|
+
*/
|
|
944
|
+
spawn(): Promise<void>;
|
|
945
|
+
/**
|
|
946
|
+
* Fetches `GET /gateway/bot`, cached for every shard, with its session start limit kept up to date.
|
|
947
|
+
*
|
|
948
|
+
* @param force Whether to skip the cache.
|
|
949
|
+
*/
|
|
950
|
+
fetchGatewayInformation(force?: boolean): Promise<GatewayInformation>;
|
|
951
|
+
/**
|
|
952
|
+
* Gets the channel to the shard connecting a gateway shard.
|
|
953
|
+
*
|
|
954
|
+
* @param shardId The ID of the gateway shard.
|
|
955
|
+
*/
|
|
956
|
+
channelFor(shardId: number): ShardChannel | undefined;
|
|
957
|
+
/**
|
|
958
|
+
* Gets the channel to the shard receiving the events of a guild.
|
|
959
|
+
*
|
|
960
|
+
* @param guildId The ID of the guild.
|
|
961
|
+
*/
|
|
962
|
+
channelForGuild(guildId: string): ShardChannel | undefined;
|
|
963
|
+
/**
|
|
964
|
+
* Sets the handler answering the requests the shards send to the manager.
|
|
965
|
+
*
|
|
966
|
+
* @param handler The handler; its return value is the reply.
|
|
967
|
+
*/
|
|
968
|
+
setRequestHandler(handler: RequestHandler<{
|
|
969
|
+
channel: ShardChannel;
|
|
970
|
+
}> | null): this;
|
|
971
|
+
/**
|
|
972
|
+
* Sends a message to a shard, emitted as `message` by its {@link ShardClient}.
|
|
973
|
+
*
|
|
974
|
+
* @param channelId The ID of the shard.
|
|
975
|
+
* @param body The message.
|
|
976
|
+
* @param options How long to wait for the shard to be ready, and an abort signal.
|
|
977
|
+
*/
|
|
978
|
+
send(channelId: number, body: unknown, options?: RequestOptions): Promise<void>;
|
|
979
|
+
/**
|
|
980
|
+
* Sends a request to a shard, answered by its {@link ShardClient}'s request handler.
|
|
981
|
+
*
|
|
982
|
+
* @param channelId The ID of the shard.
|
|
983
|
+
* @param body The request.
|
|
984
|
+
* @param options The timeout and abort signal of the request.
|
|
985
|
+
*/
|
|
986
|
+
request<Reply = unknown>(channelId: number, body: unknown, options?: RequestOptions): Promise<Reply>;
|
|
987
|
+
/**
|
|
988
|
+
* Sends a message to every shard.
|
|
989
|
+
*
|
|
990
|
+
* @param body The message.
|
|
991
|
+
* @param options How long to wait for the shards to be ready, and an abort signal.
|
|
992
|
+
*/
|
|
993
|
+
broadcast(body: unknown, options?: RequestOptions): Promise<void>;
|
|
994
|
+
/**
|
|
995
|
+
* Sends a request to every shard, like discord.js's `broadcastEval` without the `eval`.
|
|
996
|
+
*
|
|
997
|
+
* @param body The request.
|
|
998
|
+
* @param options The timeout and abort signal of every request, and whether to keep partial results.
|
|
999
|
+
* @returns The replies by shard ID, or with `partial`, the outcome of every request.
|
|
1000
|
+
*/
|
|
1001
|
+
broadcastRequest<Reply = unknown>(body: unknown, options: BroadcastRequestOptions & {
|
|
1002
|
+
partial: true;
|
|
1003
|
+
}): Promise<PromiseSettledResult<Reply>[]>;
|
|
1004
|
+
broadcastRequest<Reply = unknown>(body: unknown, options?: BroadcastRequestOptions): Promise<Reply[]>;
|
|
1005
|
+
/**
|
|
1006
|
+
* {@link ShardManager.send}, resolving with a `Result` rather than rejecting.
|
|
1007
|
+
*/
|
|
1008
|
+
trySend(channelId: number, body: unknown, options?: RequestOptions): Promise<Result$1<void, ShardError>>;
|
|
1009
|
+
/**
|
|
1010
|
+
* {@link ShardManager.request}, resolving with a `Result` rather than rejecting.
|
|
1011
|
+
*/
|
|
1012
|
+
tryRequest<Reply = unknown>(channelId: number, body: unknown, options?: RequestOptions): Promise<Result$1<Reply, ShardError>>;
|
|
1013
|
+
/**
|
|
1014
|
+
* {@link ShardManager.broadcastRequest}, resolving with one `Result` per shard, by shard ID.
|
|
1015
|
+
*/
|
|
1016
|
+
tryBroadcastRequest<Reply = unknown>(body: unknown, options?: RequestOptions): Promise<Result$1<Reply, ShardError>[]>;
|
|
1017
|
+
/**
|
|
1018
|
+
* Restarts a shard: closes it then spawns it again, or with `rolling`, spawns the new one first and closes the old
|
|
1019
|
+
* one once the new one is ready.
|
|
1020
|
+
*
|
|
1021
|
+
* @param channelId The ID of the shard.
|
|
1022
|
+
* @param options Whether to restart it rolling, and the timeout.
|
|
1023
|
+
*/
|
|
1024
|
+
restart(channelId: number, options?: ShardRestartOptions): Promise<void>;
|
|
1025
|
+
/**
|
|
1026
|
+
* Restarts every shard, one after the other, with the spawn delay between them.
|
|
1027
|
+
*
|
|
1028
|
+
* @param options Whether to restart them rolling, and the timeout.
|
|
1029
|
+
*/
|
|
1030
|
+
restartAll(options?: ShardRestartOptions): Promise<void>;
|
|
1031
|
+
/**
|
|
1032
|
+
* Reshards with close to no downtime: spawns the shards of a new layout while the current ones keep running, then
|
|
1033
|
+
* closes the current ones once every new one is ready.
|
|
1034
|
+
*
|
|
1035
|
+
* @param layout The new layout. Left out, Discord's recommendation split across `clusters`.
|
|
1036
|
+
*/
|
|
1037
|
+
reshard(layout?: ShardLayoutOptions): Promise<void>;
|
|
1038
|
+
/**
|
|
1039
|
+
* Asks the shard connecting a gateway shard to start it, through its {@link ShardClient.setShardHandler}.
|
|
1040
|
+
*
|
|
1041
|
+
* @param shardId The ID of the gateway shard.
|
|
1042
|
+
* @param options The timeout and abort signal of the request.
|
|
1043
|
+
*/
|
|
1044
|
+
startShard(shardId: number, options?: RequestOptions): Promise<void>;
|
|
1045
|
+
/**
|
|
1046
|
+
* Asks the shard connecting a gateway shard to close it, through its {@link ShardClient.setShardHandler}.
|
|
1047
|
+
*
|
|
1048
|
+
* @param shardId The ID of the gateway shard.
|
|
1049
|
+
* @param options The timeout and abort signal of the request.
|
|
1050
|
+
*/
|
|
1051
|
+
closeShard(shardId: number, options?: RequestOptions): Promise<void>;
|
|
1052
|
+
/**
|
|
1053
|
+
* Closes then starts a gateway shard, see {@link ShardManager.startShard}.
|
|
1054
|
+
*
|
|
1055
|
+
* @param shardId The ID of the gateway shard.
|
|
1056
|
+
* @param options The timeout and abort signal of each request.
|
|
1057
|
+
*/
|
|
1058
|
+
restartShard(shardId: number, options?: RequestOptions): Promise<void>;
|
|
1059
|
+
/**
|
|
1060
|
+
* Waits for a gateway shard's turn to identify, like {@link ShardClient.identifyThrottler} does from a shard.
|
|
1061
|
+
*
|
|
1062
|
+
* @param shardId The ID of the gateway shard.
|
|
1063
|
+
* @param signal Aborts the wait.
|
|
1064
|
+
*/
|
|
1065
|
+
waitForIdentify(shardId: number, signal?: AbortSignal): Promise<void>;
|
|
1066
|
+
/**
|
|
1067
|
+
* Closes every shard for good, and releases the strategy.
|
|
1068
|
+
*/
|
|
1069
|
+
destroy(): Promise<void>;
|
|
1070
|
+
/**
|
|
1071
|
+
* Carries a message a shard sends to another shard, or to every shard.
|
|
1072
|
+
*
|
|
1073
|
+
* @internal
|
|
1074
|
+
*/
|
|
1075
|
+
route(body: unknown, to: ShardTarget, from: number): Promise<void>;
|
|
1076
|
+
/**
|
|
1077
|
+
* Carries a request a shard sends to another shard, or to every shard.
|
|
1078
|
+
*
|
|
1079
|
+
* @internal
|
|
1080
|
+
*/
|
|
1081
|
+
forward(body: unknown, to: ShardTarget, from: number, options: BroadcastRequestOptions): Promise<unknown>;
|
|
1082
|
+
/**
|
|
1083
|
+
* Answers the requests the sharder itself sends.
|
|
1084
|
+
*
|
|
1085
|
+
* @internal
|
|
1086
|
+
*/
|
|
1087
|
+
handleSystem(call: SystemCall, body: unknown, channel: ShardChannel, signal: AbortSignal): Promise<unknown>;
|
|
1088
|
+
/**
|
|
1089
|
+
* Decides what happens to a shard that stopped on its own.
|
|
1090
|
+
*
|
|
1091
|
+
* @internal
|
|
1092
|
+
*/
|
|
1093
|
+
supervise(channel: ShardChannel, previous: ShardStatus): void;
|
|
1094
|
+
/**
|
|
1095
|
+
* @internal
|
|
1096
|
+
*/
|
|
1097
|
+
recordReadyTime(time: number): void;
|
|
1098
|
+
/**
|
|
1099
|
+
* @internal
|
|
1100
|
+
*/
|
|
1101
|
+
reportError(error: unknown): void;
|
|
1102
|
+
/**
|
|
1103
|
+
* @internal
|
|
1104
|
+
*/
|
|
1105
|
+
reportShardError(channel: ShardChannel, error: unknown): void;
|
|
1106
|
+
/**
|
|
1107
|
+
* @internal
|
|
1108
|
+
*/
|
|
1109
|
+
reportInvalidMessage(channel: ShardChannel, error: unknown): void;
|
|
1110
|
+
}
|
|
1111
|
+
//#endregion
|
|
1112
|
+
//#region src/ShardChannel.d.ts
|
|
1113
|
+
/**
|
|
1114
|
+
* The events of a {@link ShardChannel}. The manager emits them too, prefixed with `shard` and with the channel first.
|
|
1115
|
+
*/
|
|
1116
|
+
export interface ShardChannelEvents {
|
|
1117
|
+
/**
|
|
1118
|
+
* The shard was spawned (`shardCreate` on the manager).
|
|
1119
|
+
*/
|
|
1120
|
+
spawn: [];
|
|
1121
|
+
status: [status: ShardStatus];
|
|
1122
|
+
ready: [];
|
|
1123
|
+
disconnect: [];
|
|
1124
|
+
reconnecting: [];
|
|
1125
|
+
/**
|
|
1126
|
+
* The shard answered a ping; `latency` is the round trip, in milliseconds.
|
|
1127
|
+
*/
|
|
1128
|
+
ping: [latency: number];
|
|
1129
|
+
unresponsive: [];
|
|
1130
|
+
/**
|
|
1131
|
+
* The shard takes longer than expected to be ready, see `spawn.readyHint`.
|
|
1132
|
+
*/
|
|
1133
|
+
slowStart: [elapsed: number, estimate: number];
|
|
1134
|
+
exit: [code: number | null];
|
|
1135
|
+
destroy: [];
|
|
1136
|
+
error: [error: unknown];
|
|
1137
|
+
message: [body: any];
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* The options of a restart.
|
|
1141
|
+
*/
|
|
1142
|
+
export interface ShardRestartOptions {
|
|
1143
|
+
/**
|
|
1144
|
+
* Whether to spawn the new shard before closing the old one, which only closes once the new one is ready: close to
|
|
1145
|
+
* no downtime, at the cost of both running for a moment.
|
|
1146
|
+
*
|
|
1147
|
+
* @default false
|
|
1148
|
+
*/
|
|
1149
|
+
rolling?: boolean;
|
|
1150
|
+
/**
|
|
1151
|
+
* How long to wait for the old shard to exit, and for the new one to be ready, in milliseconds.
|
|
1152
|
+
*/
|
|
1153
|
+
timeout?: number;
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* The manager's channel to one shard: a process, cluster worker, worker thread, or remote process, connecting some
|
|
1157
|
+
* gateway shards.
|
|
1158
|
+
*
|
|
1159
|
+
* @remarks
|
|
1160
|
+
* Named after discord.js's sharder: a "shard" is the client a manager spawns, and the channel is how the manager
|
|
1161
|
+
* talks to it, whatever the channel strategy.
|
|
1162
|
+
*/
|
|
1163
|
+
export declare class ShardChannel extends EventEmitter<ShardChannelEvents> {
|
|
1164
|
+
#private;
|
|
1165
|
+
/**
|
|
1166
|
+
* The ID of the channel, its index in {@link ShardManager.channels}.
|
|
1167
|
+
*/
|
|
1168
|
+
readonly id: number;
|
|
1169
|
+
/**
|
|
1170
|
+
* The IDs of the gateway shards the shard connects.
|
|
1171
|
+
*/
|
|
1172
|
+
readonly shards: readonly number[];
|
|
1173
|
+
/**
|
|
1174
|
+
* The total number of gateway shards the shard is told about.
|
|
1175
|
+
*/
|
|
1176
|
+
readonly shardCount: number;
|
|
1177
|
+
readonly manager: ShardManager;
|
|
1178
|
+
/**
|
|
1179
|
+
* The pings of the shard.
|
|
1180
|
+
*/
|
|
1181
|
+
readonly ping: ShardPing;
|
|
1182
|
+
/**
|
|
1183
|
+
* The status of the running shard, `Idle` when none runs.
|
|
1184
|
+
*/
|
|
1185
|
+
status: ShardStatus;
|
|
1186
|
+
/**
|
|
1187
|
+
* @internal
|
|
1188
|
+
*/
|
|
1189
|
+
constructor(manager: ShardManager, id: number, shards: readonly number[], shardCount: number);
|
|
1190
|
+
/**
|
|
1191
|
+
* Whether the shard is running and signalled that it is ready.
|
|
1192
|
+
*/
|
|
1193
|
+
get ready(): boolean;
|
|
1194
|
+
/**
|
|
1195
|
+
* Whether a shard is running: spawned, and not stopped yet.
|
|
1196
|
+
*/
|
|
1197
|
+
get running(): boolean;
|
|
1198
|
+
/**
|
|
1199
|
+
* Whether the channel was stopped for good: closed, exited, or given up on.
|
|
1200
|
+
*/
|
|
1201
|
+
get stopped(): boolean;
|
|
1202
|
+
/**
|
|
1203
|
+
* The ID of the shard's process.
|
|
1204
|
+
*/
|
|
1205
|
+
get pid(): number | null;
|
|
1206
|
+
/**
|
|
1207
|
+
* The ID of the shard's worker thread, for {@link WorkerStrategy}.
|
|
1208
|
+
*/
|
|
1209
|
+
get threadId(): number | null;
|
|
1210
|
+
/**
|
|
1211
|
+
* The host running the shard, for strategies spawning shards elsewhere.
|
|
1212
|
+
*/
|
|
1213
|
+
get host(): string | null;
|
|
1214
|
+
/**
|
|
1215
|
+
* When the running shard was spawned.
|
|
1216
|
+
*/
|
|
1217
|
+
get startedTimestamp(): number | null;
|
|
1218
|
+
/**
|
|
1219
|
+
* Spawns the shard, and waits for it to signal that it is ready.
|
|
1220
|
+
*
|
|
1221
|
+
* @param timeout How long to wait for it, in milliseconds. Past it, the shard is killed and the promise rejects.
|
|
1222
|
+
*/
|
|
1223
|
+
start(timeout?: number): Promise<void>;
|
|
1224
|
+
/**
|
|
1225
|
+
* Stops the shard for good. It is first asked to close, which runs its close handler, and is killed if it did not
|
|
1226
|
+
* exit within the timeout.
|
|
1227
|
+
*
|
|
1228
|
+
* @param timeout How long to wait for the shard to exit by itself, in milliseconds.
|
|
1229
|
+
*/
|
|
1230
|
+
close(timeout?: number): Promise<void>;
|
|
1231
|
+
/**
|
|
1232
|
+
* Restarts the shard through its manager, see {@link ShardManager.restart}.
|
|
1233
|
+
*
|
|
1234
|
+
* @param options Whether to restart it rolling, and the timeout.
|
|
1235
|
+
*/
|
|
1236
|
+
restart(options?: ShardRestartOptions): Promise<void>;
|
|
1237
|
+
/**
|
|
1238
|
+
* Waits for the shard to be ready.
|
|
1239
|
+
*
|
|
1240
|
+
* @param timeout How long to wait, in milliseconds.
|
|
1241
|
+
* @param signal Aborts the wait.
|
|
1242
|
+
* @throws A {@link ShardUnavailableError} when the shard is stopped for good, not ready in time, or expected to be
|
|
1243
|
+
* ready past the timeout (see `spawn.readyHint`).
|
|
1244
|
+
*/
|
|
1245
|
+
waitForReady(timeout?: number, signal?: AbortSignal): Promise<void>;
|
|
1246
|
+
/**
|
|
1247
|
+
* Sends a message to the shard, emitted as `message` by its {@link ShardClient}. Waits for the shard to be ready.
|
|
1248
|
+
*
|
|
1249
|
+
* @param body The message.
|
|
1250
|
+
* @param options How long to wait for the shard to be ready, and an abort signal.
|
|
1251
|
+
* @param from The shard the message comes from, `null` for the manager.
|
|
1252
|
+
*/
|
|
1253
|
+
send(body: unknown, options?: RequestOptions, from?: number | null): Promise<void>;
|
|
1254
|
+
/**
|
|
1255
|
+
* Sends a request to the shard, answered by its {@link ShardClient}'s request handler. Waits for the shard to be
|
|
1256
|
+
* ready.
|
|
1257
|
+
*
|
|
1258
|
+
* @param body The request.
|
|
1259
|
+
* @param options The timeout and abort signal of the request.
|
|
1260
|
+
* @param from The shard the request comes from, `null` for the manager.
|
|
1261
|
+
*/
|
|
1262
|
+
request<Reply = unknown>(body: unknown, options?: RequestOptions, from?: number | null): Promise<Reply>;
|
|
1263
|
+
/**
|
|
1264
|
+
* {@link ShardChannel.send}, resolving with a `Result` rather than rejecting.
|
|
1265
|
+
*/
|
|
1266
|
+
trySend(body: unknown, options?: RequestOptions): Promise<Result$1<void, ShardError>>;
|
|
1267
|
+
/**
|
|
1268
|
+
* {@link ShardChannel.request}, resolving with a `Result` rather than rejecting.
|
|
1269
|
+
*/
|
|
1270
|
+
tryRequest<Reply = unknown>(body: unknown, options?: RequestOptions): Promise<Result$1<Reply, ShardError>>;
|
|
1271
|
+
/**
|
|
1272
|
+
* Asks the shard to start one of its gateway shards, through its shard handler.
|
|
1273
|
+
*
|
|
1274
|
+
* @param shardId The ID of the gateway shard.
|
|
1275
|
+
* @param options The timeout and abort signal of the request.
|
|
1276
|
+
*/
|
|
1277
|
+
startShard(shardId: number, options?: RequestOptions): Promise<void>;
|
|
1278
|
+
/**
|
|
1279
|
+
* Asks the shard to close one of its gateway shards, through its shard handler.
|
|
1280
|
+
*
|
|
1281
|
+
* @param shardId The ID of the gateway shard.
|
|
1282
|
+
* @param options The timeout and abort signal of the request.
|
|
1283
|
+
*/
|
|
1284
|
+
closeShard(shardId: number, options?: RequestOptions): Promise<void>;
|
|
1285
|
+
/**
|
|
1286
|
+
* Restarts the shard, keeping the old one until the new one is ready.
|
|
1287
|
+
*
|
|
1288
|
+
* @internal
|
|
1289
|
+
*/
|
|
1290
|
+
rollingRestart(timeout?: number): Promise<void>;
|
|
1291
|
+
/**
|
|
1292
|
+
* Stops the channel for good without closing anything, when its shard exited or was given up on.
|
|
1293
|
+
*
|
|
1294
|
+
* @internal
|
|
1295
|
+
*/
|
|
1296
|
+
markStopped(reason: string): void;
|
|
1297
|
+
}
|
|
1298
|
+
//#endregion
|
|
1299
|
+
//#region src/ShardClient.d.ts
|
|
1300
|
+
/**
|
|
1301
|
+
* The shard's end of the channel to its manager (or proxy).
|
|
1302
|
+
*/
|
|
1303
|
+
export interface ClientTransport {
|
|
1304
|
+
send(data: unknown): Promise<void>;
|
|
1305
|
+
onMessage(listener: (data: unknown) => void): void;
|
|
1306
|
+
/**
|
|
1307
|
+
* Registers what to do when the channel to the manager closes, i.e. when the manager died.
|
|
1308
|
+
*/
|
|
1309
|
+
onDisconnect(listener: () => void): void;
|
|
1310
|
+
/**
|
|
1311
|
+
* Stops the shard.
|
|
1312
|
+
*/
|
|
1313
|
+
exit(code: number): void;
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* The options of a {@link ShardClient}.
|
|
1317
|
+
*/
|
|
1318
|
+
export interface ShardClientOptions {
|
|
1319
|
+
/**
|
|
1320
|
+
* How messages are serialized. Defaults to the manager's, built from the registry.
|
|
1321
|
+
*/
|
|
1322
|
+
messageHandler?: MessageHandler | string;
|
|
1323
|
+
/**
|
|
1324
|
+
* How serialized messages are transformed. Defaults to the manager's, built from the registry.
|
|
1325
|
+
*/
|
|
1326
|
+
transformers?: readonly (MessageTransformer | string)[];
|
|
1327
|
+
/**
|
|
1328
|
+
* The shard's context. Defaults to the one its manager passed when spawning it.
|
|
1329
|
+
*/
|
|
1330
|
+
context?: ShardContext;
|
|
1331
|
+
/**
|
|
1332
|
+
* The channel to the manager. Defaults to the one of {@link ShardContext.transport}.
|
|
1333
|
+
*/
|
|
1334
|
+
transport?: ClientTransport;
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* Starts and closes the gateway shards of this shard, when the manager asks.
|
|
1338
|
+
*/
|
|
1339
|
+
export interface ShardHandler {
|
|
1340
|
+
start?(shardId: number, context: {
|
|
1341
|
+
signal: AbortSignal;
|
|
1342
|
+
}): unknown;
|
|
1343
|
+
close?(shardId: number, context: {
|
|
1344
|
+
signal: AbortSignal;
|
|
1345
|
+
}): unknown;
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Paces identifies across every shard, the shape of `@discordjs/ws`'s `IIdentifyThrottler`.
|
|
1349
|
+
*/
|
|
1350
|
+
export interface IdentifyThrottler {
|
|
1351
|
+
waitForIdentify(shardId: number, signal: AbortSignal): Promise<void>;
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* The events of a {@link ShardClient}.
|
|
1355
|
+
*/
|
|
1356
|
+
export interface ShardClientEvents {
|
|
1357
|
+
/**
|
|
1358
|
+
* A message from the manager (`from` is `null`) or from another shard.
|
|
1359
|
+
*/
|
|
1360
|
+
message: [body: any, from: number | null];
|
|
1361
|
+
/**
|
|
1362
|
+
* The channel to the manager closed. Without listeners, the shard exits.
|
|
1363
|
+
*/
|
|
1364
|
+
disconnect: [];
|
|
1365
|
+
/**
|
|
1366
|
+
* The manager stopped pinging, e.g. a proxy lost it. The shard keeps running.
|
|
1367
|
+
*/
|
|
1368
|
+
managerUnresponsive: [];
|
|
1369
|
+
/**
|
|
1370
|
+
* The manager sent data that could not be read. Without listeners, it is logged with `console.error`.
|
|
1371
|
+
*/
|
|
1372
|
+
invalidMessage: [error: unknown];
|
|
1373
|
+
/**
|
|
1374
|
+
* Without listeners, errors are logged with `console.error`.
|
|
1375
|
+
*/
|
|
1376
|
+
error: [error: unknown];
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* The shard's side of the sharder: it tells the manager its status, and messages the manager and the other shards.
|
|
1380
|
+
*
|
|
1381
|
+
* @example
|
|
1382
|
+
* ```ts
|
|
1383
|
+
* const shard = new ShardClient();
|
|
1384
|
+
* const client = new GatewayClient({
|
|
1385
|
+
* ...options,
|
|
1386
|
+
* ...shard.gatewayOptions,
|
|
1387
|
+
* gateway: { buildIdentifyThrottler: () => shard.identifyThrottler },
|
|
1388
|
+
* });
|
|
1389
|
+
* // Reuse the manager's `GET /gateway/bot` rather than requesting it again.
|
|
1390
|
+
* client.gateway.fetchGatewayInformation = () => shard.fetchGatewayInformation();
|
|
1391
|
+
* shard.setRequestHandler((body) => ...);
|
|
1392
|
+
* ```
|
|
1393
|
+
*/
|
|
1394
|
+
export declare class ShardClient extends EventEmitter<ShardClientEvents> {
|
|
1395
|
+
#private;
|
|
1396
|
+
/**
|
|
1397
|
+
* The context of this process or thread, when a {@link ShardManager} spawned it; `null` otherwise.
|
|
1398
|
+
*/
|
|
1399
|
+
static get context(): ShardContext | null;
|
|
1400
|
+
/**
|
|
1401
|
+
* Registers a message handler the manager can refer to by name. The sharder RFC's API.
|
|
1402
|
+
*
|
|
1403
|
+
* @param name The name of the handler.
|
|
1404
|
+
* @param factory Builds the handler.
|
|
1405
|
+
*/
|
|
1406
|
+
static registerMessageHandler(name: string, factory: () => MessageHandler): typeof ShardClient;
|
|
1407
|
+
/**
|
|
1408
|
+
* Registers a message transformer the manager can refer to by name. The sharder RFC's API.
|
|
1409
|
+
*
|
|
1410
|
+
* @param name The name of the transformer.
|
|
1411
|
+
* @param factory Builds the transformer.
|
|
1412
|
+
*/
|
|
1413
|
+
static registerMessageTransformer(name: string, factory: () => MessageTransformer): typeof ShardClient;
|
|
1414
|
+
/**
|
|
1415
|
+
* The ID of the shard, its channel's in the manager.
|
|
1416
|
+
*/
|
|
1417
|
+
readonly id: number;
|
|
1418
|
+
/**
|
|
1419
|
+
* The IDs of the gateway shards the shard connects.
|
|
1420
|
+
*/
|
|
1421
|
+
readonly shards: readonly number[];
|
|
1422
|
+
/**
|
|
1423
|
+
* The total number of gateway shards, across every shard.
|
|
1424
|
+
*/
|
|
1425
|
+
readonly shardCount: number;
|
|
1426
|
+
readonly requestTimeout: number;
|
|
1427
|
+
/**
|
|
1428
|
+
* The last status signalled to the manager.
|
|
1429
|
+
*/
|
|
1430
|
+
status: ShardStatus;
|
|
1431
|
+
/**
|
|
1432
|
+
* When the manager last pinged the shard, `null` before its first ping.
|
|
1433
|
+
*/
|
|
1434
|
+
lastPingTimestamp: number | null;
|
|
1435
|
+
constructor(options?: ShardClientOptions);
|
|
1436
|
+
/**
|
|
1437
|
+
* The ID of the shard's process.
|
|
1438
|
+
*/
|
|
1439
|
+
get pid(): number;
|
|
1440
|
+
/**
|
|
1441
|
+
* The ID of the shard's thread, `0` for a process's main thread.
|
|
1442
|
+
*/
|
|
1443
|
+
get threadId(): number;
|
|
1444
|
+
/**
|
|
1445
|
+
* The gateway shards to connect, to spread into `GatewayClient`'s (or `@discordjs/ws`'s) options.
|
|
1446
|
+
*/
|
|
1447
|
+
get gatewayOptions(): {
|
|
1448
|
+
shardIds: number[];
|
|
1449
|
+
shardCount: number;
|
|
1450
|
+
};
|
|
1451
|
+
/**
|
|
1452
|
+
* Paces the identifies of the gateway shards across every shard, through the manager: pass it as `@discordjs/ws`'s
|
|
1453
|
+
* `buildIdentifyThrottler`. The manager then needs no spawn delay.
|
|
1454
|
+
*/
|
|
1455
|
+
get identifyThrottler(): IdentifyThrottler;
|
|
1456
|
+
/**
|
|
1457
|
+
* Gets `GET /gateway/bot` from the manager, fetched once for every shard, e.g. to replace `@discordjs/ws`'s
|
|
1458
|
+
* `WebSocketManager#fetchGatewayInformation`.
|
|
1459
|
+
*/
|
|
1460
|
+
fetchGatewayInformation(): Promise<GatewayInformation>;
|
|
1461
|
+
/**
|
|
1462
|
+
* Tells the manager that the shard is ready, e.g. once its gateway shards are. The manager spawns the next shard
|
|
1463
|
+
* only then.
|
|
1464
|
+
*/
|
|
1465
|
+
ready(): Promise<void>;
|
|
1466
|
+
/**
|
|
1467
|
+
* Tells the manager that the shard lost what it serves, e.g. the gateway. Messages for it wait until it is ready
|
|
1468
|
+
* again.
|
|
1469
|
+
*/
|
|
1470
|
+
disconnected(): Promise<void>;
|
|
1471
|
+
/**
|
|
1472
|
+
* Tells the manager that the shard is reconnecting to what it serves.
|
|
1473
|
+
*/
|
|
1474
|
+
reconnecting(): Promise<void>;
|
|
1475
|
+
/**
|
|
1476
|
+
* Stops the shard for good: the manager does not respawn it.
|
|
1477
|
+
*
|
|
1478
|
+
* @param code The exit code.
|
|
1479
|
+
*/
|
|
1480
|
+
exit(code?: number): Promise<void>;
|
|
1481
|
+
/**
|
|
1482
|
+
* Stops the shard, for the manager to spawn it again.
|
|
1483
|
+
*/
|
|
1484
|
+
restart(): Promise<void>;
|
|
1485
|
+
/**
|
|
1486
|
+
* Sends a message to the manager, emitted as its `message` event, or to other shards.
|
|
1487
|
+
*
|
|
1488
|
+
* @param body The message.
|
|
1489
|
+
* @param to The ID of the shard to send it to, or `"all"`. Left out, it goes to the manager.
|
|
1490
|
+
*/
|
|
1491
|
+
send(body: unknown, to?: ShardTarget): Promise<void>;
|
|
1492
|
+
/**
|
|
1493
|
+
* Sends a request to the manager or to another shard.
|
|
1494
|
+
*
|
|
1495
|
+
* @param body The request.
|
|
1496
|
+
* @param options Where it goes (the manager by default), its timeout, and its abort signal.
|
|
1497
|
+
*/
|
|
1498
|
+
request<Reply = unknown>(body: unknown, options?: RequestOptions & {
|
|
1499
|
+
to?: number;
|
|
1500
|
+
}): Promise<Reply>;
|
|
1501
|
+
/**
|
|
1502
|
+
* Sends a request to every shard, this one included, like discord.js's `broadcastEval` without the `eval`.
|
|
1503
|
+
*
|
|
1504
|
+
* @param body The request.
|
|
1505
|
+
* @param options The timeout and abort signal of the request, and whether to keep partial results.
|
|
1506
|
+
* @returns The replies by shard ID, or with `partial`, the outcome of every request.
|
|
1507
|
+
*/
|
|
1508
|
+
broadcastRequest<Reply = unknown>(body: unknown, options: BroadcastRequestOptions & {
|
|
1509
|
+
partial: true;
|
|
1510
|
+
}): Promise<PromiseSettledResult<Reply>[]>;
|
|
1511
|
+
broadcastRequest<Reply = unknown>(body: unknown, options?: BroadcastRequestOptions): Promise<Reply[]>;
|
|
1512
|
+
/**
|
|
1513
|
+
* {@link ShardClient.send}, resolving with a `Result` rather than rejecting.
|
|
1514
|
+
*/
|
|
1515
|
+
trySend(body: unknown, to?: ShardTarget): Promise<Result$1<void, ShardError>>;
|
|
1516
|
+
/**
|
|
1517
|
+
* {@link ShardClient.request}, resolving with a `Result` rather than rejecting.
|
|
1518
|
+
*/
|
|
1519
|
+
tryRequest<Reply = unknown>(body: unknown, options?: RequestOptions & {
|
|
1520
|
+
to?: number;
|
|
1521
|
+
}): Promise<Result$1<Reply, ShardError>>;
|
|
1522
|
+
/**
|
|
1523
|
+
* {@link ShardClient.broadcastRequest}, with one `Result` per shard, by shard ID. The broadcast itself failing
|
|
1524
|
+
* (e.g. the manager not answering) is the outer `Err`.
|
|
1525
|
+
*/
|
|
1526
|
+
tryBroadcastRequest<Reply = unknown>(body: unknown, options?: RequestOptions): Promise<Result$1<Result$1<Reply, ShardError>[], ShardError>>;
|
|
1527
|
+
/**
|
|
1528
|
+
* {@link ShardClient.control}, resolving with a `Result` rather than rejecting.
|
|
1529
|
+
*/
|
|
1530
|
+
tryControl(request: ControlRequest, options?: RequestOptions): Promise<Result$1<void, ShardError>>;
|
|
1531
|
+
/**
|
|
1532
|
+
* Asks the manager to start, close, or restart shards or gateway shards.
|
|
1533
|
+
*
|
|
1534
|
+
* @param request What to do, and to what.
|
|
1535
|
+
* @param options The timeout and abort signal of the request.
|
|
1536
|
+
* @example
|
|
1537
|
+
* ```ts
|
|
1538
|
+
* await shard.control({ action: "restart", target: { channel: "all" } });
|
|
1539
|
+
* await shard.control({ action: "restart", target: { shard: 12 } });
|
|
1540
|
+
* ```
|
|
1541
|
+
*/
|
|
1542
|
+
control(request: ControlRequest, options?: RequestOptions): Promise<void>;
|
|
1543
|
+
/**
|
|
1544
|
+
* Sets the handler answering the requests of the manager and of the other shards.
|
|
1545
|
+
*
|
|
1546
|
+
* @param handler The handler; its return value is the reply. `from` is the shard asking, `null` for the manager.
|
|
1547
|
+
*/
|
|
1548
|
+
setRequestHandler(handler: RequestHandler<{
|
|
1549
|
+
from: number | null;
|
|
1550
|
+
}> | null): this;
|
|
1551
|
+
/**
|
|
1552
|
+
* Sets what to do when the manager closes the shard, e.g. disconnect from the gateway. The shard exits once it
|
|
1553
|
+
* resolves; without a handler, it exits right away.
|
|
1554
|
+
*
|
|
1555
|
+
* @param handler The handler.
|
|
1556
|
+
*/
|
|
1557
|
+
setCloseHandler(handler: (() => unknown) | null): this;
|
|
1558
|
+
/**
|
|
1559
|
+
* Sets how the manager starts and closes the gateway shards of this shard, for `manager.startShard` & co.
|
|
1560
|
+
*
|
|
1561
|
+
* @param handler Starts or closes a gateway shard, resolving once done.
|
|
1562
|
+
*/
|
|
1563
|
+
setShardHandler(handler: ShardHandler | null): this;
|
|
1564
|
+
}
|
|
1565
|
+
//#endregion
|
|
1566
|
+
//#region src/network/Connection.d.ts
|
|
1567
|
+
/**
|
|
1568
|
+
* Where a proxy accepts peer connections.
|
|
1569
|
+
*/
|
|
1570
|
+
interface PeerAddress {
|
|
1571
|
+
host: string;
|
|
1572
|
+
port: number;
|
|
1573
|
+
}
|
|
1574
|
+
//#endregion
|
|
1575
|
+
//#region src/ShardManagerProxy.d.ts
|
|
1576
|
+
/**
|
|
1577
|
+
* A manager a proxy connects to.
|
|
1578
|
+
*/
|
|
1579
|
+
export interface ProxyManagerAddress {
|
|
1580
|
+
host: string;
|
|
1581
|
+
port: number;
|
|
1582
|
+
/**
|
|
1583
|
+
* The manager's token, when it differs from the proxy's `token`.
|
|
1584
|
+
*/
|
|
1585
|
+
token?: string;
|
|
1586
|
+
/**
|
|
1587
|
+
* The TLS options of this manager, when they differ from the proxy's `tls`.
|
|
1588
|
+
*/
|
|
1589
|
+
tls?: boolean | ConnectionOptions;
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* How a proxy accepts connections from other proxies, to carry the messages between their shards directly.
|
|
1593
|
+
*/
|
|
1594
|
+
export interface ProxyPeerOptions {
|
|
1595
|
+
/**
|
|
1596
|
+
* The port to listen on, `0` for any.
|
|
1597
|
+
*/
|
|
1598
|
+
port: number;
|
|
1599
|
+
host?: string;
|
|
1600
|
+
/**
|
|
1601
|
+
* The host other proxies reach this one at.
|
|
1602
|
+
*
|
|
1603
|
+
* @default host ?? os.hostname()
|
|
1604
|
+
*/
|
|
1605
|
+
advertise?: string;
|
|
1606
|
+
/**
|
|
1607
|
+
* The shared secret of the peers.
|
|
1608
|
+
*
|
|
1609
|
+
* @default the proxy's token
|
|
1610
|
+
*/
|
|
1611
|
+
token?: string;
|
|
1612
|
+
/**
|
|
1613
|
+
* The TLS options of the peer server (`key`, `cert`, ...). Left out, peers talk plain TCP.
|
|
1614
|
+
*/
|
|
1615
|
+
tls?: TlsOptions;
|
|
1616
|
+
/**
|
|
1617
|
+
* The TLS options to connect to other peers with, `true` for the defaults.
|
|
1618
|
+
*/
|
|
1619
|
+
connectTls?: boolean | ConnectionOptions;
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* The options of a {@link ShardManagerProxy}.
|
|
1623
|
+
*/
|
|
1624
|
+
export interface ShardManagerProxyOptions {
|
|
1625
|
+
/**
|
|
1626
|
+
* The managers to connect to, as `{ host, port }` or `"host:port"`.
|
|
1627
|
+
*/
|
|
1628
|
+
managers: readonly (ProxyManagerAddress | string)[];
|
|
1629
|
+
/**
|
|
1630
|
+
* How the proxy serves its managers:
|
|
1631
|
+
*
|
|
1632
|
+
* - `"failover"`: one at a time, the first reachable, failing over to the next ones when it loses it.
|
|
1633
|
+
* - `"all"`: all of them at once, sharing its capacity, e.g. managers each running part of the gateway shards.
|
|
1634
|
+
*
|
|
1635
|
+
* @default "failover"
|
|
1636
|
+
*/
|
|
1637
|
+
mode?: "failover" | "all";
|
|
1638
|
+
/**
|
|
1639
|
+
* The shared secret of the managers' {@link NetworkStrategy}.
|
|
1640
|
+
*/
|
|
1641
|
+
token: string;
|
|
1642
|
+
/**
|
|
1643
|
+
* The name of the proxy, unique across the proxies of a manager. It finds its shards back under it after a
|
|
1644
|
+
* reconnection.
|
|
1645
|
+
*
|
|
1646
|
+
* @default `${os.hostname()}:${process.pid}`
|
|
1647
|
+
*/
|
|
1648
|
+
name?: string;
|
|
1649
|
+
/**
|
|
1650
|
+
* How many shards the proxy runs at most, across all its managers.
|
|
1651
|
+
*
|
|
1652
|
+
* @default os.availableParallelism()
|
|
1653
|
+
*/
|
|
1654
|
+
capacity?: number;
|
|
1655
|
+
/**
|
|
1656
|
+
* How the proxy spawns its shards locally: a strategy, or the name of a registered one.
|
|
1657
|
+
*
|
|
1658
|
+
* @default "fork"
|
|
1659
|
+
*/
|
|
1660
|
+
strategy?: ChannelStrategy | string;
|
|
1661
|
+
strategyOptions?: unknown;
|
|
1662
|
+
/**
|
|
1663
|
+
* Connects to the managers with TLS: `true` with the default options, or the options (`ca`, `servername`, ...).
|
|
1664
|
+
*
|
|
1665
|
+
* @default false
|
|
1666
|
+
*/
|
|
1667
|
+
tls?: boolean | ConnectionOptions;
|
|
1668
|
+
/**
|
|
1669
|
+
* What the proxy does with the shards of a manager it loses: keep them running and reconnect (the manager takes
|
|
1670
|
+
* them back within its `reconnectGrace`), or stop them.
|
|
1671
|
+
*
|
|
1672
|
+
* @default "keep"
|
|
1673
|
+
*/
|
|
1674
|
+
managerLoss?: "keep" | "exit";
|
|
1675
|
+
/**
|
|
1676
|
+
* How long to wait between connection attempts, in milliseconds.
|
|
1677
|
+
*
|
|
1678
|
+
* @default 5_000
|
|
1679
|
+
*/
|
|
1680
|
+
reconnectDelay?: number;
|
|
1681
|
+
/**
|
|
1682
|
+
* Whether to carry the messages and requests between shards of this proxy (and, with `peer`, of other proxies)
|
|
1683
|
+
* without going through the manager. It decodes their packets with the manager's message handler and
|
|
1684
|
+
* transformers, built from the registry: custom ones must be registered in the proxy too.
|
|
1685
|
+
*
|
|
1686
|
+
* @default true
|
|
1687
|
+
*/
|
|
1688
|
+
localRouting?: boolean;
|
|
1689
|
+
/**
|
|
1690
|
+
* Accepts connections from other proxies, and connects to them, to carry the messages between shards of different
|
|
1691
|
+
* proxies directly. Needs `localRouting`.
|
|
1692
|
+
*/
|
|
1693
|
+
peer?: ProxyPeerOptions;
|
|
1694
|
+
heartbeat?: {
|
|
1695
|
+
interval?: number;
|
|
1696
|
+
timeout?: number;
|
|
1697
|
+
};
|
|
1698
|
+
}
|
|
1699
|
+
/**
|
|
1700
|
+
* The events of a {@link ShardManagerProxy}.
|
|
1701
|
+
*/
|
|
1702
|
+
export interface ShardManagerProxyEvents {
|
|
1703
|
+
/**
|
|
1704
|
+
* The proxy connected to a manager.
|
|
1705
|
+
*/
|
|
1706
|
+
connect: [manager: ProxyManagerAddress];
|
|
1707
|
+
/**
|
|
1708
|
+
* The proxy lost a manager.
|
|
1709
|
+
*/
|
|
1710
|
+
disconnect: [manager: ProxyManagerAddress, error: Error | undefined];
|
|
1711
|
+
/**
|
|
1712
|
+
* A manager rejected the proxy, e.g. for a wrong token.
|
|
1713
|
+
*/
|
|
1714
|
+
reject: [manager: ProxyManagerAddress, reason: string];
|
|
1715
|
+
spawn: [context: ShardContext];
|
|
1716
|
+
exit: [context: ShardContext, code: number | null];
|
|
1717
|
+
/**
|
|
1718
|
+
* A peer connection to another proxy opened.
|
|
1719
|
+
*/
|
|
1720
|
+
peerConnect: [name: string];
|
|
1721
|
+
peerDisconnect: [name: string];
|
|
1722
|
+
error: [error: unknown];
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Runs shards for remote {@link ShardManager}s using a {@link NetworkStrategy}: the sharder RFC's
|
|
1726
|
+
* `ShardManagerProxy`. It spawns them locally with its own strategy, carries their messages to their manager, and
|
|
1727
|
+
* carries the messages between shards of the same manager directly, locally or through peer proxies.
|
|
1728
|
+
*
|
|
1729
|
+
* @example
|
|
1730
|
+
* ```ts
|
|
1731
|
+
* const proxy = new ShardManagerProxy({
|
|
1732
|
+
* managers: ["manager.internal:7000", "manager-backup.internal:7000"],
|
|
1733
|
+
* token: process.env.SHARDER_TOKEN!,
|
|
1734
|
+
* tls: { ca: readFileSync("ca.pem") },
|
|
1735
|
+
* strategy: new ForkStrategy({ path: "./bot.js" }),
|
|
1736
|
+
* capacity: 8,
|
|
1737
|
+
* peer: { port: 7001 },
|
|
1738
|
+
* });
|
|
1739
|
+
* await proxy.connect();
|
|
1740
|
+
* ```
|
|
1741
|
+
*/
|
|
1742
|
+
export declare class ShardManagerProxy extends EventEmitter<ShardManagerProxyEvents> {
|
|
1743
|
+
#private;
|
|
1744
|
+
readonly name: string;
|
|
1745
|
+
readonly capacity: number;
|
|
1746
|
+
readonly strategy: ChannelStrategy;
|
|
1747
|
+
readonly managers: readonly ProxyManagerAddress[];
|
|
1748
|
+
readonly mode: "failover" | "all";
|
|
1749
|
+
constructor(options: ShardManagerProxyOptions);
|
|
1750
|
+
/**
|
|
1751
|
+
* The managers the proxy is connected to.
|
|
1752
|
+
*/
|
|
1753
|
+
get connectedManagers(): ProxyManagerAddress[];
|
|
1754
|
+
/**
|
|
1755
|
+
* The manager the proxy is connected to in `"failover"` mode, `null` while it is not.
|
|
1756
|
+
*/
|
|
1757
|
+
get manager(): ProxyManagerAddress | null;
|
|
1758
|
+
/**
|
|
1759
|
+
* The contexts of the shards the proxy runs.
|
|
1760
|
+
*/
|
|
1761
|
+
get shards(): ShardContext[];
|
|
1762
|
+
/**
|
|
1763
|
+
* Where other proxies reach this one, once connected with `peer`.
|
|
1764
|
+
*/
|
|
1765
|
+
get peerAddress(): PeerAddress | null;
|
|
1766
|
+
/**
|
|
1767
|
+
* The names of the proxies this one has a peer connection with.
|
|
1768
|
+
*/
|
|
1769
|
+
get peers(): string[];
|
|
1770
|
+
/**
|
|
1771
|
+
* Connects to the managers, and keeps reconnecting whenever a connection is lost, until
|
|
1772
|
+
* {@link ShardManagerProxy.destroy}. Resolves once connected to a first manager.
|
|
1773
|
+
*/
|
|
1774
|
+
connect(): Promise<void>;
|
|
1775
|
+
/**
|
|
1776
|
+
* Stops every shard, and disconnects for good.
|
|
1777
|
+
*/
|
|
1778
|
+
destroy(): Promise<void>;
|
|
1779
|
+
}
|
|
1780
|
+
//#endregion
|
|
1781
|
+
//#region src/strategies/ProcessStrategy.d.ts
|
|
1782
|
+
/**
|
|
1783
|
+
* The options shared by the strategies spawning processes.
|
|
1784
|
+
*/
|
|
1785
|
+
export interface ProcessStrategyOptions {
|
|
1786
|
+
/**
|
|
1787
|
+
* The arguments passed to the shard's script.
|
|
1788
|
+
*/
|
|
1789
|
+
args?: readonly string[];
|
|
1790
|
+
/**
|
|
1791
|
+
* The arguments passed to Node.js, e.g. `["--enable-source-maps"]`.
|
|
1792
|
+
*/
|
|
1793
|
+
execArgv?: readonly string[];
|
|
1794
|
+
/**
|
|
1795
|
+
* Extra environment variables, on top of the manager's own.
|
|
1796
|
+
*/
|
|
1797
|
+
env?: NodeJS.ProcessEnv;
|
|
1798
|
+
}
|
|
1799
|
+
/**
|
|
1800
|
+
* The base of {@link ForkStrategy} and {@link ClusterStrategy}: a shard is a process with an IPC channel, using the
|
|
1801
|
+
* `advanced` serialization so binary data (and {@link RawMessageHandler}'s values) survive it.
|
|
1802
|
+
*/
|
|
1803
|
+
export declare abstract class ProcessStrategy implements ChannelStrategy {
|
|
1804
|
+
abstract readonly name: string;
|
|
1805
|
+
spawn(context: ShardContext, events: ShardTransportEvents, options: SpawnOptions): ShardTransport;
|
|
1806
|
+
protected abstract createProcess(context: ShardContext, options: SpawnOptions): ChildProcess | Worker$1;
|
|
1807
|
+
}
|
|
1808
|
+
//#endregion
|
|
1809
|
+
//#region src/strategies/ClusterStrategy.d.ts
|
|
1810
|
+
/**
|
|
1811
|
+
* The options of {@link ClusterStrategy}.
|
|
1812
|
+
*/
|
|
1813
|
+
export interface ClusterStrategyOptions extends ProcessStrategyOptions {
|
|
1814
|
+
/**
|
|
1815
|
+
* The script every shard runs. Defaults to the manager's own script, so one file handles both sides: check
|
|
1816
|
+
* `cluster.isPrimary` to tell them apart.
|
|
1817
|
+
*/
|
|
1818
|
+
path?: string | URL;
|
|
1819
|
+
}
|
|
1820
|
+
/**
|
|
1821
|
+
* Spawns every shard as a `node:cluster` worker. Unlike {@link ForkStrategy}, the shards share the ports they listen
|
|
1822
|
+
* on, and the primary balances the connections between them.
|
|
1823
|
+
*/
|
|
1824
|
+
export declare class ClusterStrategy extends ProcessStrategy {
|
|
1825
|
+
readonly name = "cluster";
|
|
1826
|
+
readonly options: ClusterStrategyOptions;
|
|
1827
|
+
constructor(options?: ClusterStrategyOptions);
|
|
1828
|
+
protected createProcess(context: ShardContext, options: SpawnOptions): Worker$1;
|
|
1829
|
+
}
|
|
1830
|
+
//#endregion
|
|
1831
|
+
//#region src/strategies/ForkStrategy.d.ts
|
|
1832
|
+
/**
|
|
1833
|
+
* The options of {@link ForkStrategy}.
|
|
1834
|
+
*/
|
|
1835
|
+
export interface ForkStrategyOptions extends ProcessStrategyOptions {
|
|
1836
|
+
/**
|
|
1837
|
+
* The script every shard runs. Defaults to the manager's own script: check {@link ShardClient.context} to tell the
|
|
1838
|
+
* manager and the shards apart.
|
|
1839
|
+
*/
|
|
1840
|
+
path?: string | URL;
|
|
1841
|
+
}
|
|
1842
|
+
/**
|
|
1843
|
+
* Spawns every shard as a child process with `child_process.fork`. The default strategy.
|
|
1844
|
+
*
|
|
1845
|
+
* @remarks
|
|
1846
|
+
* Every shard is its own process: ports opened by the shards (e.g. an HTTP interactions server) must differ.
|
|
1847
|
+
*/
|
|
1848
|
+
export declare class ForkStrategy extends ProcessStrategy {
|
|
1849
|
+
readonly name = "fork";
|
|
1850
|
+
readonly options: ForkStrategyOptions;
|
|
1851
|
+
constructor(options?: ForkStrategyOptions);
|
|
1852
|
+
protected createProcess(context: ShardContext, options: SpawnOptions): ChildProcess;
|
|
1853
|
+
}
|
|
1854
|
+
//#endregion
|
|
1855
|
+
//#region src/strategies/NetworkStrategy.d.ts
|
|
1856
|
+
/**
|
|
1857
|
+
* The options of {@link NetworkStrategy}.
|
|
1858
|
+
*/
|
|
1859
|
+
export interface NetworkStrategyOptions {
|
|
1860
|
+
/**
|
|
1861
|
+
* The port to listen on for proxies.
|
|
1862
|
+
*/
|
|
1863
|
+
port: number;
|
|
1864
|
+
host?: string;
|
|
1865
|
+
/**
|
|
1866
|
+
* The shared secret proxies authenticate with.
|
|
1867
|
+
*/
|
|
1868
|
+
token: string;
|
|
1869
|
+
/**
|
|
1870
|
+
* The ID of the manager, which proxies serving several managers tell them apart by. Defaults to a random UUID.
|
|
1871
|
+
*/
|
|
1872
|
+
id?: string;
|
|
1873
|
+
/**
|
|
1874
|
+
* The TLS options (`key`, `cert`, ...) to encrypt the connections, recommended. Left out, the connections are plain
|
|
1875
|
+
* TCP: only for trusted networks.
|
|
1876
|
+
*/
|
|
1877
|
+
tls?: TlsOptions;
|
|
1878
|
+
/**
|
|
1879
|
+
* How long a proxy that lost its connection has to come back before its shards are deemed dead and spawned
|
|
1880
|
+
* elsewhere, in milliseconds.
|
|
1881
|
+
*
|
|
1882
|
+
* @default 30_000
|
|
1883
|
+
*/
|
|
1884
|
+
reconnectGrace?: number;
|
|
1885
|
+
heartbeat?: {
|
|
1886
|
+
/**
|
|
1887
|
+
* @default 15_000
|
|
1888
|
+
*/
|
|
1889
|
+
interval?: number;
|
|
1890
|
+
/**
|
|
1891
|
+
* @default 45_000
|
|
1892
|
+
*/
|
|
1893
|
+
timeout?: number;
|
|
1894
|
+
};
|
|
1895
|
+
}
|
|
1896
|
+
/**
|
|
1897
|
+
* A proxy connected to a {@link NetworkStrategy}.
|
|
1898
|
+
*/
|
|
1899
|
+
export interface ProxyInfo {
|
|
1900
|
+
name: string;
|
|
1901
|
+
/**
|
|
1902
|
+
* The address the proxy connected from.
|
|
1903
|
+
*/
|
|
1904
|
+
host: string | null;
|
|
1905
|
+
/**
|
|
1906
|
+
* How many shards it runs at most, across all its managers.
|
|
1907
|
+
*/
|
|
1908
|
+
capacity: number;
|
|
1909
|
+
/**
|
|
1910
|
+
* How many more shards it takes, across all its managers.
|
|
1911
|
+
*/
|
|
1912
|
+
available: number;
|
|
1913
|
+
/**
|
|
1914
|
+
* How many shards it runs for this manager.
|
|
1915
|
+
*/
|
|
1916
|
+
load: number;
|
|
1917
|
+
/**
|
|
1918
|
+
* Where other proxies reach it, when it accepts peers.
|
|
1919
|
+
*/
|
|
1920
|
+
peer: PeerAddress | null;
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
* Spawns shards on other machines, through {@link ShardManagerProxy}s connecting to the manager: the sharder RFC's
|
|
1924
|
+
* network strategy.
|
|
1925
|
+
*
|
|
1926
|
+
* @remarks
|
|
1927
|
+
* Each spawn goes to the connected proxy with the most room, as the proxies report it across all the managers they
|
|
1928
|
+
* serve; without room, it waits for a proxy, or for the spawn timeout. A proxy losing its connection has
|
|
1929
|
+
* `reconnectGrace` to come back with its shards, after which they are spawned elsewhere; its stale shards are killed
|
|
1930
|
+
* when it comes back later. Proxies coming back are not rebalanced: they take the next spawns.
|
|
1931
|
+
*
|
|
1932
|
+
* The strategy keeps the proxies accepting peers informed of which proxy runs which ready shard, so they carry the
|
|
1933
|
+
* messages between their shards directly.
|
|
1934
|
+
*/
|
|
1935
|
+
export declare class NetworkStrategy implements ChannelStrategy {
|
|
1936
|
+
#private;
|
|
1937
|
+
readonly name = "network";
|
|
1938
|
+
readonly options: NetworkStrategyOptions;
|
|
1939
|
+
/**
|
|
1940
|
+
* The ID of the manager, see {@link NetworkStrategyOptions.id}.
|
|
1941
|
+
*/
|
|
1942
|
+
readonly id: string;
|
|
1943
|
+
constructor(options: NetworkStrategyOptions);
|
|
1944
|
+
/**
|
|
1945
|
+
* The proxies, connected or within their reconnect grace.
|
|
1946
|
+
*/
|
|
1947
|
+
get proxies(): ProxyInfo[];
|
|
1948
|
+
/**
|
|
1949
|
+
* The port the strategy listens on, once initialized.
|
|
1950
|
+
*/
|
|
1951
|
+
get port(): number | null;
|
|
1952
|
+
/**
|
|
1953
|
+
* Drops the connection of a proxy, which reconnects: its shards are kept if it comes back within the grace.
|
|
1954
|
+
*
|
|
1955
|
+
* @param name The name of the proxy.
|
|
1956
|
+
* @returns Whether a proxy of that name was connected.
|
|
1957
|
+
*/
|
|
1958
|
+
disconnectProxy(name: string): boolean;
|
|
1959
|
+
init(): Promise<void>;
|
|
1960
|
+
destroy(): Promise<void>;
|
|
1961
|
+
spawn(context: ShardContext, events: ShardTransportEvents, options: SpawnOptions): ShardTransport;
|
|
1962
|
+
}
|
|
1963
|
+
//#endregion
|
|
1964
|
+
//#region src/strategies/WorkerStrategy.d.ts
|
|
1965
|
+
/**
|
|
1966
|
+
* The options of {@link WorkerStrategy}.
|
|
1967
|
+
*/
|
|
1968
|
+
export interface WorkerStrategyOptions {
|
|
1969
|
+
/**
|
|
1970
|
+
* The script every shard runs.
|
|
1971
|
+
*/
|
|
1972
|
+
path: string | URL;
|
|
1973
|
+
/**
|
|
1974
|
+
* Extra options of the `Worker`, e.g. its `resourceLimits`. `workerData` is reserved for the shard's context.
|
|
1975
|
+
*/
|
|
1976
|
+
worker?: Omit<WorkerOptions, "workerData">;
|
|
1977
|
+
}
|
|
1978
|
+
/**
|
|
1979
|
+
* Spawns every shard as a worker thread of the manager's process. Messages are the fastest, but the shards share the
|
|
1980
|
+
* process: a crash of the process stops them all.
|
|
1981
|
+
*/
|
|
1982
|
+
export declare class WorkerStrategy implements ChannelStrategy {
|
|
1983
|
+
readonly name = "worker";
|
|
1984
|
+
readonly options: WorkerStrategyOptions;
|
|
1985
|
+
constructor(options: WorkerStrategyOptions);
|
|
1986
|
+
spawn(context: ShardContext, events: ShardTransportEvents, options: SpawnOptions): ShardTransport;
|
|
1987
|
+
}
|
|
1988
|
+
//#endregion
|
|
1989
|
+
//#region src/strategies/registry.d.ts
|
|
1990
|
+
/**
|
|
1991
|
+
* Registers a strategy under a name, so managers and proxies can be given its name, like the built-in `"fork"`,
|
|
1992
|
+
* `"cluster"`, `"worker"`, and `"network"`.
|
|
1993
|
+
*
|
|
1994
|
+
* @param name The name of the strategy.
|
|
1995
|
+
* @param factory Builds the strategy from the `strategyOptions`.
|
|
1996
|
+
*/
|
|
1997
|
+
export declare function registerStrategy<Options>(name: string, factory: (options: Options) => ChannelStrategy): void;
|
|
1998
|
+
/**
|
|
1999
|
+
* Resolves a strategy, or the name of a registered one.
|
|
2000
|
+
*
|
|
2001
|
+
* @param strategy The strategy, or its name.
|
|
2002
|
+
* @param options The options of a named strategy.
|
|
2003
|
+
*/
|
|
2004
|
+
export declare function resolveStrategy(strategy: ChannelStrategy | string, options?: unknown): ChannelStrategy;
|
|
2005
|
+
//#endregion
|
|
2006
|
+
//#region src/util/commands.d.ts
|
|
2007
|
+
/**
|
|
2008
|
+
* A request naming a command, the optional command layer on top of raw requests.
|
|
2009
|
+
*/
|
|
2010
|
+
export interface CommandRequest<Name extends string = string, Data = unknown> {
|
|
2011
|
+
command: Name;
|
|
2012
|
+
data: Data;
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* The commands a handler answers, by name.
|
|
2016
|
+
*/
|
|
2017
|
+
export type Commands<Context = unknown> = Record<string, (data: any, context: Context & {
|
|
2018
|
+
signal: AbortSignal;
|
|
2019
|
+
}) => unknown>;
|
|
2020
|
+
/**
|
|
2021
|
+
* The reply of a command.
|
|
2022
|
+
*/
|
|
2023
|
+
export type CommandReply<C extends Commands<any>, Name extends keyof C> = Awaited<ReturnType<C[Name]>>;
|
|
2024
|
+
/**
|
|
2025
|
+
* Builds a request handler answering {@link CommandRequest}s: the sharder stays raw data (as the RFC settled), and
|
|
2026
|
+
* this is the optional, typed layer on top.
|
|
2027
|
+
*
|
|
2028
|
+
* @param commands The commands, by name.
|
|
2029
|
+
* @example
|
|
2030
|
+
* ```ts
|
|
2031
|
+
* const commands = {
|
|
2032
|
+
* guildCount: () => guilds.size,
|
|
2033
|
+
* guild: (id: string) => guilds.get(id) ?? null,
|
|
2034
|
+
* } satisfies Commands;
|
|
2035
|
+
*
|
|
2036
|
+
* shard.setRequestHandler(createCommandHandler(commands));
|
|
2037
|
+
* const counts = await manager.broadcastRequest<CommandReply<typeof commands, "guildCount">>(
|
|
2038
|
+
* command<typeof commands>("guildCount"),
|
|
2039
|
+
* );
|
|
2040
|
+
* ```
|
|
2041
|
+
*/
|
|
2042
|
+
export declare function createCommandHandler<Context>(commands: Commands<Context>): RequestHandler<Context>;
|
|
2043
|
+
/**
|
|
2044
|
+
* Builds a {@link CommandRequest}.
|
|
2045
|
+
*
|
|
2046
|
+
* @param name The name of the command.
|
|
2047
|
+
* @param data Its argument.
|
|
2048
|
+
*/
|
|
2049
|
+
export declare function command<C extends Commands<any>, Name extends keyof C & string = keyof C & string>(name: Name, ...data: Parameters<C[Name]>[0] extends undefined ? [] : [data: Parameters<C[Name]>[0]]): CommandRequest<Name, Parameters<C[Name]>[0]>;
|
|
2050
|
+
//#endregion
|
|
2051
|
+
export { type BroadcastRequestOptions, type ControlRequest, type Err, type GatewayInformation, type Ok, type RecommendedShardCountOptions, type RequestHandler, type RequestOptions, Result, type ShardTarget, type SupervisorOptions, type SupervisorStrategy };
|
|
2052
|
+
//# sourceMappingURL=index.d.ts.map
|