@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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["Result","createTlsServer","createNetServer","sleep","sleep","sleep","connectTls","connectNet","createTlsServer","createNetServer"],"sources":["../../src/ShardPing.ts","../../src/messages/protocol.ts","../../src/util/errors.ts","../../src/util/requests.ts","../../src/ShardChannel.ts","../../src/messages/MessageHandler.ts","../../src/messages/MessageTransformer.ts","../../src/strategies/ChannelStrategy.ts","../../src/ShardClient.ts","../../src/strategies/ProcessStrategy.ts","../../src/strategies/ClusterStrategy.ts","../../src/strategies/ForkStrategy.ts","../../src/network/Connection.ts","../../src/strategies/NetworkStrategy.ts","../../src/strategies/WorkerStrategy.ts","../../src/strategies/registry.ts","../../src/util/gateway.ts","../../src/util/IdentifyQueue.ts","../../src/util/Supervisor.ts","../../src/ShardManager.ts","../../src/ShardManagerProxy.ts","../../src/util/commands.ts"],"sourcesContent":["/**\r\n * The options of the manager's pings.\r\n */\r\nexport interface ShardPingOptions {\r\n /**\r\n * How often the manager pings each ready shard, in milliseconds; `-1` or `Infinity` disables the pings.\r\n *\r\n * @default 45_000\r\n */\r\n interval?: number;\r\n /**\r\n * How long a ready shard may go without answering a ping, in milliseconds, before it is deemed unresponsive:\r\n * emitted as `shardUnresponsive`, or restarted when nothing listens to it.\r\n *\r\n * @default 60_000\r\n */\r\n timeout?: number;\r\n /**\r\n * Whether the next ping is sent `interval` after the last answer, rather than after the last ping.\r\n *\r\n * @default false\r\n */\r\n delaySinceReceived?: boolean;\r\n}\r\n\r\n/**\r\n * Pings a shard, measures its latency, and notices when it stops answering.\r\n */\r\nexport class ShardPing {\r\n /**\r\n * When the last ping was sent, `-1` before the first one.\r\n */\r\n public lastSentTimestamp = -1;\r\n\r\n /**\r\n * When the last answer came, `-1` before the first one.\r\n */\r\n public lastReceivedTimestamp = -1;\r\n\r\n /**\r\n * The round trip of the last ping, in milliseconds; `-1` before the first answer.\r\n */\r\n public latency = -1;\r\n\r\n public readonly interval: number;\r\n public readonly timeout: number;\r\n public readonly delaySinceReceived: boolean;\r\n\r\n readonly #send: (sentAt: number) => Promise<void>;\r\n readonly #onTimeout: () => void;\r\n #timer: NodeJS.Timeout | null = null;\r\n #watchdog: NodeJS.Timeout | null = null;\r\n\r\n /**\r\n * @internal\r\n */\r\n public constructor(\r\n options: ShardPingOptions,\r\n send: (sentAt: number) => Promise<void>,\r\n onTimeout: () => void,\r\n ) {\r\n this.interval = options.interval ?? 45_000;\r\n this.timeout = options.timeout ?? 60_000;\r\n this.delaySinceReceived = options.delaySinceReceived ?? false;\r\n this.#send = send;\r\n this.#onTimeout = onTimeout;\r\n }\r\n\r\n /**\r\n * Whether the pings are running.\r\n */\r\n public get running(): boolean {\r\n return this.#watchdog !== null;\r\n }\r\n\r\n /**\r\n * Whether the last ping was answered.\r\n */\r\n public get hasReceivedResponse(): boolean {\r\n return this.lastReceivedTimestamp >= this.lastSentTimestamp;\r\n }\r\n\r\n public get lastSentAt(): Date | null {\r\n return this.lastSentTimestamp === -1 ? null : new Date(this.lastSentTimestamp);\r\n }\r\n\r\n public get lastReceivedAt(): Date | null {\r\n return this.lastReceivedTimestamp === -1 ? null : new Date(this.lastReceivedTimestamp);\r\n }\r\n\r\n /**\r\n * When the next ping is due, or `null` when the pings are not running.\r\n */\r\n public get nextPingTimestamp(): number | null {\r\n if (!this.running || !this.enabled) return null;\r\n const from = this.delaySinceReceived ? this.lastReceivedTimestamp : this.lastSentTimestamp;\r\n return (from === -1 ? Date.now() : from) + this.interval;\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n public start(): void {\r\n if (this.running || !this.enabled) return;\r\n\r\n this.#watchdog = setTimeout(() => {\r\n this.stop();\r\n this.#onTimeout();\r\n }, this.timeout);\r\n this.#watchdog.unref();\r\n this.#schedule();\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n public stop(): void {\r\n if (this.#timer) clearTimeout(this.#timer);\r\n if (this.#watchdog) clearTimeout(this.#watchdog);\r\n this.#timer = null;\r\n this.#watchdog = null;\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n public receive(sentAt: number): void {\r\n this.lastReceivedTimestamp = Date.now();\r\n this.latency = this.lastReceivedTimestamp - sentAt;\r\n this.#watchdog?.refresh();\r\n if (this.delaySinceReceived && this.running) this.#schedule();\r\n }\r\n\r\n /**\r\n * Whether the manager pings at all.\r\n */\r\n public get enabled(): boolean {\r\n return this.interval !== -1 && this.interval !== Number.POSITIVE_INFINITY;\r\n }\r\n\r\n #schedule(): void {\r\n if (!this.enabled) return;\r\n if (this.#timer) clearTimeout(this.#timer);\r\n this.#timer = setTimeout(() => {\r\n this.#timer = null;\r\n this.lastSentTimestamp = Date.now();\r\n void this.#send(this.lastSentTimestamp).catch(() => undefined);\r\n if (!this.delaySinceReceived) this.#schedule();\r\n }, this.interval);\r\n this.#timer.unref();\r\n }\r\n}\r\n","import type { ChannelData, MessageHandler } from \"./MessageHandler.js\";\r\nimport type { MessageTransformer, TransformerContext } from \"./MessageTransformer.js\";\r\n\r\n/**\r\n * The lifecycle status of a shard, as it signals it to its manager.\r\n */\r\nexport const ShardStatus = {\r\n /**\r\n * Not spawned yet, or stopped.\r\n */\r\n Idle: \"Idle\",\r\n /**\r\n * Spawned, and not ready to answer yet.\r\n */\r\n Starting: \"Starting\",\r\n /**\r\n * Fully operative.\r\n */\r\n Ready: \"Ready\",\r\n /**\r\n * Running, but disconnected from what it serves, e.g. the gateway.\r\n */\r\n Disconnected: \"Disconnected\",\r\n /**\r\n * Running, and reconnecting to what it serves.\r\n */\r\n Reconnecting: \"Reconnecting\",\r\n /**\r\n * Shutting down, not to be restarted.\r\n */\r\n Exiting: \"Exiting\",\r\n /**\r\n * Shutting down, to be restarted.\r\n */\r\n Restarting: \"Restarting\",\r\n} as const;\r\n\r\nexport type ShardStatus = (typeof ShardStatus)[keyof typeof ShardStatus];\r\n\r\n/**\r\n * Where a message or a request goes: a shard's ID, or `\"all\"` for every shard. Left out, it goes to the manager.\r\n */\r\nexport type ShardTarget = number | \"all\";\r\n\r\n/**\r\n * The operation of a packet.\r\n *\r\n * @internal\r\n */\r\nexport const Op = {\r\n Signal: 0,\r\n Ping: 1,\r\n Pong: 2,\r\n Message: 3,\r\n Request: 4,\r\n Reply: 5,\r\n Abort: 6,\r\n Close: 7,\r\n} as const;\r\n\r\n/**\r\n * @internal\r\n */\r\nexport type Op = (typeof Op)[keyof typeof Op];\r\n\r\nconst Ops = new Set<number>(Object.values(Op));\r\n\r\n/**\r\n * The requests the sharder itself sends, rather than the application.\r\n *\r\n * - `identify` (shard → manager): waits for the turn of a gateway shard to identify. Body: the gateway shard ID.\r\n * - `gatewayInformation` (shard → manager): the manager's cached `GET /gateway/bot`.\r\n * - `control` (shard → manager): starts, closes, or restarts shards or gateway shards. Body: {@link ControlRequest}.\r\n * - `startShard` / `closeShard` (manager → shard): starts or closes a gateway shard. Body: the gateway shard ID.\r\n *\r\n * @internal\r\n */\r\nexport type SystemCall =\r\n | \"identify\"\r\n | \"gatewayInformation\"\r\n | \"control\"\r\n | \"startShard\"\r\n | \"closeShard\";\r\n\r\n/**\r\n * What a shard asks its manager to start, close, or restart.\r\n */\r\nexport interface ControlRequest {\r\n action: \"start\" | \"close\" | \"restart\";\r\n /**\r\n * A shard (`{ channel }`, or `\"all\"`), or a gateway shard (`{ shard }`).\r\n */\r\n target: { channel: ShardTarget } | { shard: number };\r\n}\r\n\r\n/**\r\n * The error of a failed request, as sent over the channel.\r\n *\r\n * @internal\r\n */\r\nexport interface SerializedError {\r\n name: string;\r\n message: string;\r\n}\r\n\r\n/**\r\n * The outcome of one request of a partial broadcast, as sent over the channel.\r\n *\r\n * @internal\r\n */\r\nexport type SerializedSettledResult =\r\n | { status: \"fulfilled\"; value: unknown }\r\n | { status: \"rejected\"; reason: SerializedError };\r\n\r\n/**\r\n * The packets exchanged between the manager and its shards, before serialization.\r\n *\r\n * @internal\r\n */\r\nexport type Packet =\r\n | { op: typeof Op.Signal; status: ShardStatus }\r\n | { op: typeof Op.Ping; sentAt: number }\r\n | { op: typeof Op.Pong; sentAt: number }\r\n | { op: typeof Op.Message; body: unknown; to?: ShardTarget; from?: number | null }\r\n | {\r\n op: typeof Op.Request;\r\n nonce: number;\r\n body: unknown;\r\n to?: ShardTarget;\r\n from?: number | null;\r\n timeout?: number;\r\n /**\r\n * For broadcasts: reply with every outcome rather than rejecting on the first failure.\r\n */\r\n partial?: boolean;\r\n system?: SystemCall;\r\n }\r\n | { op: typeof Op.Reply; nonce: number; body?: unknown; error?: SerializedError }\r\n | { op: typeof Op.Abort; nonce: number }\r\n | { op: typeof Op.Close };\r\n\r\n/**\r\n * Serializes packets with a {@link MessageHandler}, then runs them through the {@link MessageTransformer}s, and the\r\n * other way around.\r\n *\r\n * @internal\r\n */\r\nexport class PacketCodec {\r\n public readonly handler: MessageHandler;\r\n public readonly transformers: readonly MessageTransformer[];\r\n\r\n public constructor(handler: MessageHandler, transformers: readonly MessageTransformer[]) {\r\n this.handler = handler;\r\n this.transformers = transformers;\r\n }\r\n\r\n public async encode(packet: Packet, context: TransformerContext): Promise<unknown> {\r\n let data = this.handler.serialize(packet);\r\n for (const transformer of this.transformers) {\r\n data = await transformer.write(assertChannelData(data), context);\r\n }\r\n\r\n return data;\r\n }\r\n\r\n public async decode(data: unknown, context: TransformerContext): Promise<Packet> {\r\n for (let index = this.transformers.length - 1; index >= 0; --index) {\r\n data = await this.transformers[index]!.read(assertChannelData(data), context);\r\n }\r\n\r\n const packet = this.handler.deserialize(data);\r\n if (!isPacket(packet)) throw new TypeError(\"The message is not a sharder packet\");\r\n return packet;\r\n }\r\n}\r\n\r\nfunction assertChannelData(data: unknown): ChannelData {\r\n if (typeof data === \"string\" || data instanceof Uint8Array) return data;\r\n throw new TypeError(\"Transformers need a message handler serializing to strings or bytes\");\r\n}\r\n\r\nfunction isPacket(value: unknown): value is Packet {\r\n return (\r\n typeof value === \"object\" && value !== null && Ops.has((value as { op?: unknown }).op as number)\r\n );\r\n}\r\n\r\n/**\r\n * Serializes an error to send it over the channel.\r\n *\r\n * @internal\r\n */\r\nexport function serializeError(error: unknown): SerializedError {\r\n return error instanceof Error\r\n ? { name: error.name, message: error.message }\r\n : { name: \"Error\", message: String(error) };\r\n}\r\n","/**\r\n * What a sharder operation fails with: the `E` of the `try*` methods' `Result<T, E>`.\r\n */\r\nexport type ShardError =\r\n | ShardRequestError\r\n | ShardRequestTimeoutError\r\n | ShardUnavailableError\r\n | ShardSpawnError\r\n | Error;\r\n\r\n/**\r\n * The handler of a request threw, or there was none: the error is the remote one, rebuilt.\r\n */\r\nexport class ShardRequestError extends Error {\r\n /**\r\n * The name of the remote error, e.g. `TypeError`.\r\n */\r\n public readonly remoteName: string;\r\n\r\n public constructor(remoteName: string, message: string) {\r\n super(message);\r\n this.name = \"ShardRequestError\";\r\n this.remoteName = remoteName;\r\n }\r\n}\r\n\r\n/**\r\n * A request got no reply in time. The other side was told to abort it.\r\n */\r\nexport class ShardRequestTimeoutError extends Error {\r\n public readonly timeout: number;\r\n\r\n public constructor(timeout: number) {\r\n super(`The request got no reply within ${timeout}ms`);\r\n this.name = \"ShardRequestTimeoutError\";\r\n this.timeout = timeout;\r\n }\r\n}\r\n\r\n/**\r\n * A shard stopped, is not ready in time, or does not exist.\r\n */\r\nexport class ShardUnavailableError extends Error {\r\n public readonly channelId: number;\r\n\r\n public constructor(channelId: number, reason: string) {\r\n super(`Shard ${channelId} is unavailable: ${reason}`);\r\n this.name = \"ShardUnavailableError\";\r\n this.channelId = channelId;\r\n }\r\n}\r\n\r\n/**\r\n * A shard failed before it was ready: its process exited, or its worker could not start. The sharder RFC's `error`\r\n * signal.\r\n */\r\nexport class ShardSpawnError extends Error {\r\n public readonly channelId: number;\r\n /**\r\n * The exit code, when the shard exited.\r\n */\r\n public readonly code: number | null;\r\n\r\n public constructor(channelId: number, code: number | null, cause?: unknown) {\r\n super(\r\n cause instanceof Error\r\n ? `Shard ${channelId} failed to start: ${cause.message}`\r\n : `Shard ${channelId} exited with code ${code} before it was ready`,\r\n { cause },\r\n );\r\n this.name = \"ShardSpawnError\";\r\n this.channelId = channelId;\r\n this.code = code;\r\n }\r\n}\r\n","import { Result } from \"@sapphire/result\";\r\nimport {\r\n Op,\r\n serializeError,\r\n type Packet,\r\n type SerializedSettledResult,\r\n} from \"../messages/protocol.js\";\r\nimport { ShardRequestError, ShardRequestTimeoutError, type ShardError } from \"./errors.js\";\r\n\r\n/**\r\n * The options of a request.\r\n */\r\nexport interface RequestOptions {\r\n /**\r\n * How long to wait for the reply, in milliseconds. Defaults to the manager's `requestTimeout`.\r\n */\r\n timeout?: number;\r\n /**\r\n * Aborts the request: dropped from the queue if it waits for a shard to be ready, and aborted on the other side\r\n * otherwise, whose handler gets an aborted `signal`.\r\n */\r\n signal?: AbortSignal;\r\n}\r\n\r\n/**\r\n * The options of a broadcast request.\r\n */\r\nexport interface BroadcastRequestOptions extends RequestOptions {\r\n /**\r\n * Whether to resolve with the outcome of every shard, like `Promise.allSettled`, rather than rejecting on the first\r\n * failure: the replies that came before a timeout or an abort are kept.\r\n */\r\n partial?: boolean;\r\n}\r\n\r\n/**\r\n * Answers the requests of the other side. Its return value (or the value it resolves to) is the reply, and a throw is\r\n * rejected on the other side as a {@link ShardRequestError}. It may also return a `Result`: `Ok` is the reply, `Err`\r\n * the error.\r\n */\r\nexport type RequestHandler<Context> = (\r\n body: any,\r\n context: Context & { signal: AbortSignal },\r\n) => unknown;\r\n\r\ntype Send = (packet: Packet) => Promise<void>;\r\ntype RequestPacket = Extract<Packet, { op: typeof Op.Request }>;\r\ntype RequestFields = Omit<RequestPacket, \"op\" | \"nonce\" | \"timeout\">;\r\n\r\ninterface Pending {\r\n owner: unknown;\r\n resolve(value: unknown): void;\r\n reject(error: unknown): void;\r\n}\r\n\r\n/**\r\n * Tracks the requests sent on a channel until their reply comes, they time out, or they are aborted.\r\n *\r\n * @internal\r\n */\r\nexport class OutgoingRequests {\r\n readonly #pending = new Map<number, Pending>();\r\n readonly #step: 1 | -1;\r\n #nonce = 0;\r\n\r\n /**\r\n * @param negative Whether to count nonces down from -1, so two senders on one channel never collide.\r\n */\r\n public constructor(negative = false) {\r\n this.#step = negative ? -1 : 1;\r\n }\r\n\r\n /**\r\n * Sends a request.\r\n *\r\n * @param send Writes the request.\r\n * @param fields The request.\r\n * @param timeout How long to wait for the reply.\r\n * @param signal Aborts the request.\r\n * @param owner What the request was sent to, to reject it with {@link OutgoingRequests.rejectOwner}.\r\n */\r\n public request(\r\n send: Send,\r\n fields: RequestFields,\r\n timeout: number,\r\n signal?: AbortSignal,\r\n owner?: unknown,\r\n ): Promise<unknown> {\r\n // Rejected rather than thrown, so every caller gets a promise, async or not.\r\n if (signal?.aborted) return Promise.reject(signal.reason);\r\n this.#nonce += this.#step;\r\n const nonce = this.#nonce;\r\n\r\n return new Promise((resolve, reject) => {\r\n const abort = (error: unknown) => {\r\n if (!this.#pending.has(nonce)) return;\r\n settle();\r\n reject(error);\r\n void send({ op: Op.Abort, nonce }).catch(() => undefined);\r\n };\r\n\r\n const timer = setTimeout(() => abort(new ShardRequestTimeoutError(timeout)), timeout);\r\n const onAbort = () => abort(signal!.reason);\r\n signal?.addEventListener(\"abort\", onAbort, { once: true });\r\n const settle = () => {\r\n clearTimeout(timer);\r\n signal?.removeEventListener(\"abort\", onAbort);\r\n this.#pending.delete(nonce);\r\n };\r\n\r\n this.#pending.set(nonce, {\r\n owner,\r\n resolve: (value) => {\r\n settle();\r\n resolve(value);\r\n },\r\n reject: (error) => {\r\n settle();\r\n reject(error);\r\n },\r\n });\r\n\r\n send({ op: Op.Request, nonce, ...fields, timeout }).catch((error: unknown) => {\r\n this.#pending.get(nonce)?.reject(error);\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Settles the request a reply answers. Returns whether it answered one of these requests.\r\n */\r\n public settle(packet: Extract<Packet, { op: typeof Op.Reply }>): boolean {\r\n const pending = this.#pending.get(packet.nonce);\r\n if (!pending) return false;\r\n\r\n if (packet.error)\r\n pending.reject(new ShardRequestError(packet.error.name, packet.error.message));\r\n else pending.resolve(packet.body);\r\n return true;\r\n }\r\n\r\n public rejectOwner(owner: unknown, error: unknown): void {\r\n for (const pending of this.#pending.values()) {\r\n if (pending.owner === owner) pending.reject(error);\r\n }\r\n }\r\n\r\n public rejectAll(error: unknown): void {\r\n for (const pending of this.#pending.values()) pending.reject(error);\r\n }\r\n}\r\n\r\n/**\r\n * Runs the requests received on a channel, and aborts them when the other side does.\r\n *\r\n * @internal\r\n */\r\nexport class IncomingRequests {\r\n readonly #controllers = new Map<number, AbortController>();\r\n\r\n public async handle<Context>(\r\n send: Send,\r\n packet: RequestPacket,\r\n handler: RequestHandler<Context> | null,\r\n context: Context,\r\n ): Promise<void> {\r\n const controller = new AbortController();\r\n this.#controllers.set(packet.nonce, controller);\r\n\r\n let reply: Packet;\r\n try {\r\n if (!handler) throw new Error(\"There is no request handler\");\r\n let body = await handler(packet.body, { ...context, signal: controller.signal });\r\n if (Result.isResult(body)) {\r\n if (body.isErr()) throw body.unwrapErr();\r\n body = body.unwrap();\r\n }\r\n reply = { op: Op.Reply, nonce: packet.nonce, body };\r\n } catch (error) {\r\n reply = { op: Op.Reply, nonce: packet.nonce, error: serializeError(error) };\r\n } finally {\r\n this.#controllers.delete(packet.nonce);\r\n }\r\n\r\n // Nobody waits for the reply of an aborted request.\r\n if (!controller.signal.aborted) await send(reply).catch(() => undefined);\r\n }\r\n\r\n public abort(nonce: number): void {\r\n this.#controllers.get(nonce)?.abort(new Error(\"The request was aborted by its sender\"));\r\n }\r\n\r\n public abortAll(): void {\r\n for (const nonce of this.#controllers.keys()) this.abort(nonce);\r\n }\r\n}\r\n\r\n/**\r\n * Turns an operation into a `Result`, for the `try*` methods.\r\n *\r\n * @internal\r\n */\r\nexport async function toResult<Value>(\r\n operation: () => Promise<Value>,\r\n): Promise<Result<Value, ShardError>> {\r\n return Result.fromAsync(operation) as Promise<Result<Value, ShardError>>;\r\n}\r\n\r\n/**\r\n * Turns the outcomes of a partial broadcast into `Result`s.\r\n *\r\n * @internal\r\n */\r\nexport function settledToResults<Value>(\r\n results: readonly PromiseSettledResult<Value>[],\r\n): Result<Value, ShardError>[] {\r\n return results.map((result) =>\r\n result.status === \"fulfilled\"\r\n ? Result.ok<Value, ShardError>(result.value)\r\n : Result.err<ShardError, Value>(result.reason as ShardError),\r\n );\r\n}\r\n\r\n/**\r\n * Serializes the outcomes of a partial broadcast.\r\n *\r\n * @internal\r\n */\r\nexport function serializeSettled(\r\n results: readonly PromiseSettledResult<unknown>[],\r\n): SerializedSettledResult[] {\r\n return results.map((result) =>\r\n result.status === \"fulfilled\"\r\n ? { status: \"fulfilled\", value: result.value }\r\n : { status: \"rejected\", reason: serializeError(result.reason) },\r\n );\r\n}\r\n\r\n/**\r\n * Rebuilds the outcomes of a partial broadcast.\r\n *\r\n * @internal\r\n */\r\nexport function deserializeSettled<Reply>(\r\n results: readonly SerializedSettledResult[],\r\n): PromiseSettledResult<Reply>[] {\r\n return results.map((result) =>\r\n result.status === \"fulfilled\"\r\n ? { status: \"fulfilled\", value: result.value as Reply }\r\n : {\r\n status: \"rejected\",\r\n reason: new ShardRequestError(result.reason.name, result.reason.message),\r\n },\r\n );\r\n}\r\n","import type { Result } from \"@sapphire/result\";\r\nimport { EventEmitter } from \"node:events\";\r\nimport type { ShardManager } from \"./ShardManager.js\";\r\nimport { ShardPing } from \"./ShardPing.js\";\r\nimport { Op, ShardStatus, type Packet, type SystemCall } from \"./messages/protocol.js\";\r\nimport type { ShardContext, ShardTransport } from \"./strategies/ChannelStrategy.js\";\r\nimport { ShardSpawnError, ShardUnavailableError, type ShardError } from \"./util/errors.js\";\r\nimport {\r\n IncomingRequests,\r\n OutgoingRequests,\r\n toResult,\r\n type RequestOptions,\r\n} from \"./util/requests.js\";\r\n\r\n/**\r\n * The events of a {@link ShardChannel}. The manager emits them too, prefixed with `shard` and with the channel first.\r\n */\r\nexport interface ShardChannelEvents {\r\n /**\r\n * The shard was spawned (`shardCreate` on the manager).\r\n */\r\n spawn: [];\r\n status: [status: ShardStatus];\r\n ready: [];\r\n disconnect: [];\r\n reconnecting: [];\r\n /**\r\n * The shard answered a ping; `latency` is the round trip, in milliseconds.\r\n */\r\n ping: [latency: number];\r\n unresponsive: [];\r\n /**\r\n * The shard takes longer than expected to be ready, see `spawn.readyHint`.\r\n */\r\n slowStart: [elapsed: number, estimate: number];\r\n exit: [code: number | null];\r\n destroy: [];\r\n error: [error: unknown];\r\n message: [body: any];\r\n}\r\n\r\ninterface Instance {\r\n transport: ShardTransport | null;\r\n status: ShardStatus;\r\n startedAt: number;\r\n everReady: boolean;\r\n exited: boolean;\r\n exit: Promise<number | null>;\r\n resolveExit(code: number | null): void;\r\n ready: Promise<void>;\r\n resolveReady(): void;\r\n /**\r\n * Stopped on purpose: its exit is not a crash.\r\n */\r\n stopping: boolean;\r\n /**\r\n * Awaited by whoever spawned it, who handles its failure.\r\n */\r\n awaited: boolean;\r\n incoming: IncomingRequests;\r\n slowStart: NodeJS.Timeout | null;\r\n}\r\n\r\ninterface ReadyWaiter {\r\n resolve(): void;\r\n reject(error: unknown): void;\r\n}\r\n\r\n/**\r\n * The options of a restart.\r\n */\r\nexport interface ShardRestartOptions {\r\n /**\r\n * Whether to spawn the new shard before closing the old one, which only closes once the new one is ready: close to\r\n * no downtime, at the cost of both running for a moment.\r\n *\r\n * @default false\r\n */\r\n rolling?: boolean;\r\n /**\r\n * How long to wait for the old shard to exit, and for the new one to be ready, in milliseconds.\r\n */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * The manager's channel to one shard: a process, cluster worker, worker thread, or remote process, connecting some\r\n * gateway shards.\r\n *\r\n * @remarks\r\n * Named after discord.js's sharder: a \"shard\" is the client a manager spawns, and the channel is how the manager\r\n * talks to it, whatever the channel strategy.\r\n */\r\nexport class ShardChannel extends EventEmitter<ShardChannelEvents> {\r\n /**\r\n * The ID of the channel, its index in {@link ShardManager.channels}.\r\n */\r\n public readonly id: number;\r\n\r\n /**\r\n * The IDs of the gateway shards the shard connects.\r\n */\r\n public readonly shards: readonly number[];\r\n\r\n /**\r\n * The total number of gateway shards the shard is told about.\r\n */\r\n public readonly shardCount: number;\r\n\r\n public readonly manager: ShardManager;\r\n\r\n /**\r\n * The pings of the shard.\r\n */\r\n public readonly ping: ShardPing;\r\n\r\n /**\r\n * The status of the running shard, `Idle` when none runs.\r\n */\r\n public status: ShardStatus = ShardStatus.Idle;\r\n\r\n #active: Instance | null = null;\r\n #replacement: Instance | null = null;\r\n #stopped = false;\r\n readonly #waiters = new Set<ReadyWaiter>();\r\n readonly #outgoing = new OutgoingRequests();\r\n\r\n /**\r\n * @internal\r\n */\r\n public constructor(\r\n manager: ShardManager,\r\n id: number,\r\n shards: readonly number[],\r\n shardCount: number,\r\n ) {\r\n super();\r\n this.manager = manager;\r\n this.id = id;\r\n this.shards = shards;\r\n this.shardCount = shardCount;\r\n this.ping = new ShardPing(\r\n manager.pingOptions,\r\n (sentAt) => this.#write(this.#active, { op: Op.Ping, sentAt }),\r\n () => this.#unresponsive(),\r\n );\r\n }\r\n\r\n /**\r\n * Whether the shard is running and signalled that it is ready.\r\n */\r\n public get ready(): boolean {\r\n return this.status === ShardStatus.Ready;\r\n }\r\n\r\n /**\r\n * Whether a shard is running: spawned, and not stopped yet.\r\n */\r\n public get running(): boolean {\r\n return this.#active !== null;\r\n }\r\n\r\n /**\r\n * Whether the channel was stopped for good: closed, exited, or given up on.\r\n */\r\n public get stopped(): boolean {\r\n return this.#stopped;\r\n }\r\n\r\n /**\r\n * The ID of the shard's process.\r\n */\r\n public get pid(): number | null {\r\n return this.#active?.transport?.pid ?? null;\r\n }\r\n\r\n /**\r\n * The ID of the shard's worker thread, for {@link WorkerStrategy}.\r\n */\r\n public get threadId(): number | null {\r\n return this.#active?.transport?.threadId ?? null;\r\n }\r\n\r\n /**\r\n * The host running the shard, for strategies spawning shards elsewhere.\r\n */\r\n public get host(): string | null {\r\n return this.#active?.transport?.host ?? null;\r\n }\r\n\r\n /**\r\n * When the running shard was spawned.\r\n */\r\n public get startedTimestamp(): number | null {\r\n return this.#active?.startedAt ?? null;\r\n }\r\n\r\n /**\r\n * Spawns the shard, and waits for it to signal that it is ready.\r\n *\r\n * @param timeout How long to wait for it, in milliseconds. Past it, the shard is killed and the promise rejects.\r\n */\r\n public async start(timeout = this.manager.spawnTimeout): Promise<void> {\r\n if (this.#active) throw new Error(`Shard ${this.id} is already running`);\r\n\r\n this.#stopped = false;\r\n const instance = this.#spawn();\r\n this.#active = instance;\r\n this.#setStatus(ShardStatus.Starting);\r\n await this.#awaitReady(instance, timeout);\r\n }\r\n\r\n /**\r\n * Stops the shard for good. It is first asked to close, which runs its close handler, and is killed if it did not\r\n * exit within the timeout.\r\n *\r\n * @param timeout How long to wait for the shard to exit by itself, in milliseconds.\r\n */\r\n public async close(timeout = this.manager.requestTimeout): Promise<void> {\r\n this.#stopped = true;\r\n this.#rejectWaiters(new ShardUnavailableError(this.id, \"it was closed\"));\r\n const instances = [this.#replacement, this.#active].filter((instance) => instance !== null);\r\n if (instances.length === 0) return;\r\n\r\n await Promise.all(instances.map((instance) => this.#stop(instance, timeout)));\r\n this.emit(\"destroy\");\r\n this.manager.emit(\"shardDestroy\", this);\r\n }\r\n\r\n /**\r\n * Restarts the shard through its manager, see {@link ShardManager.restart}.\r\n *\r\n * @param options Whether to restart it rolling, and the timeout.\r\n */\r\n public restart(options?: ShardRestartOptions): Promise<void> {\r\n return this.manager.restart(this.id, options);\r\n }\r\n\r\n /**\r\n * Waits for the shard to be ready.\r\n *\r\n * @param timeout How long to wait, in milliseconds.\r\n * @param signal Aborts the wait.\r\n * @throws A {@link ShardUnavailableError} when the shard is stopped for good, not ready in time, or expected to be\r\n * ready past the timeout (see `spawn.readyHint`).\r\n */\r\n public waitForReady(timeout = this.manager.requestTimeout, signal?: AbortSignal): Promise<void> {\r\n if (this.ready) return Promise.resolve();\r\n if (this.#stopped) {\r\n return Promise.reject(new ShardUnavailableError(this.id, \"it is stopped\"));\r\n }\r\n\r\n signal?.throwIfAborted();\r\n const remaining = this.#estimatedRemaining();\r\n if (remaining !== null && remaining > timeout) {\r\n return Promise.reject(\r\n new ShardUnavailableError(this.id, `it is expected to be ready in ${remaining}ms`),\r\n );\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const settle = () => {\r\n clearTimeout(timer);\r\n signal?.removeEventListener(\"abort\", onAbort);\r\n this.#waiters.delete(waiter);\r\n };\r\n const waiter: ReadyWaiter = {\r\n resolve: () => {\r\n settle();\r\n resolve();\r\n },\r\n reject: (error) => {\r\n settle();\r\n reject(error);\r\n },\r\n };\r\n const onAbort = () => waiter.reject(signal!.reason);\r\n const timer = setTimeout(\r\n () => waiter.reject(new ShardUnavailableError(this.id, `not ready within ${timeout}ms`)),\r\n timeout,\r\n );\r\n signal?.addEventListener(\"abort\", onAbort, { once: true });\r\n this.#waiters.add(waiter);\r\n });\r\n }\r\n\r\n /**\r\n * Sends a message to the shard, emitted as `message` by its {@link ShardClient}. Waits for the shard to be ready.\r\n *\r\n * @param body The message.\r\n * @param options How long to wait for the shard to be ready, and an abort signal.\r\n * @param from The shard the message comes from, `null` for the manager.\r\n */\r\n public async send(\r\n body: unknown,\r\n options: RequestOptions = {},\r\n from: number | null = null,\r\n ): Promise<void> {\r\n await this.waitForReady(options.timeout, options.signal);\r\n await this.#write(this.#active, { op: Op.Message, body, from });\r\n }\r\n\r\n /**\r\n * Sends a request to the shard, answered by its {@link ShardClient}'s request handler. Waits for the shard to be\r\n * ready.\r\n *\r\n * @param body The request.\r\n * @param options The timeout and abort signal of the request.\r\n * @param from The shard the request comes from, `null` for the manager.\r\n */\r\n public async request<Reply = unknown>(\r\n body: unknown,\r\n options: RequestOptions = {},\r\n from: number | null = null,\r\n ): Promise<Reply> {\r\n return this.#request(body, options, { from }) as Promise<Reply>;\r\n }\r\n\r\n /**\r\n * {@link ShardChannel.send}, resolving with a `Result` rather than rejecting.\r\n */\r\n public trySend(body: unknown, options?: RequestOptions): Promise<Result<void, ShardError>> {\r\n return toResult(() => this.send(body, options));\r\n }\r\n\r\n /**\r\n * {@link ShardChannel.request}, resolving with a `Result` rather than rejecting.\r\n */\r\n public tryRequest<Reply = unknown>(\r\n body: unknown,\r\n options?: RequestOptions,\r\n ): Promise<Result<Reply, ShardError>> {\r\n return toResult(() => this.request<Reply>(body, options));\r\n }\r\n\r\n /**\r\n * Asks the shard to start one of its gateway shards, through its shard handler.\r\n *\r\n * @param shardId The ID of the gateway shard.\r\n * @param options The timeout and abort signal of the request.\r\n */\r\n public async startShard(shardId: number, options?: RequestOptions): Promise<void> {\r\n await this.#system(\"startShard\", shardId, options);\r\n }\r\n\r\n /**\r\n * Asks the shard to close one of its gateway shards, through its shard handler.\r\n *\r\n * @param shardId The ID of the gateway shard.\r\n * @param options The timeout and abort signal of the request.\r\n */\r\n public async closeShard(shardId: number, options?: RequestOptions): Promise<void> {\r\n await this.#system(\"closeShard\", shardId, options);\r\n }\r\n\r\n /**\r\n * Restarts the shard, keeping the old one until the new one is ready.\r\n *\r\n * @internal\r\n */\r\n public async rollingRestart(timeout = this.manager.spawnTimeout): Promise<void> {\r\n if (!this.#active) {\r\n await this.start(timeout);\r\n return;\r\n }\r\n\r\n this.#stopped = false;\r\n const replacement = this.#spawn();\r\n this.#replacement = replacement;\r\n try {\r\n await this.#awaitReady(replacement, timeout);\r\n } finally {\r\n if (this.#replacement === replacement) this.#replacement = null;\r\n }\r\n\r\n const previous = this.#active;\r\n this.#active = replacement;\r\n this.ping.stop();\r\n this.status = ShardStatus.Starting;\r\n this.#setStatus(replacement.status);\r\n if (previous) await this.#stop(previous, timeout);\r\n }\r\n\r\n /**\r\n * Stops the channel for good without closing anything, when its shard exited or was given up on.\r\n *\r\n * @internal\r\n */\r\n public markStopped(reason: string): void {\r\n this.#stopped = true;\r\n this.#rejectWaiters(new ShardUnavailableError(this.id, reason));\r\n }\r\n\r\n async #request(\r\n body: unknown,\r\n options: RequestOptions,\r\n fields: { from?: number | null; partial?: boolean; system?: SystemCall },\r\n ): Promise<unknown> {\r\n const timeout = options.timeout ?? this.manager.requestTimeout;\r\n const started = Date.now();\r\n await this.waitForReady(timeout, options.signal);\r\n const active = this.#active;\r\n return this.#outgoing.request(\r\n (packet) => this.#write(active, packet),\r\n { body, ...fields },\r\n Math.max(timeout - (Date.now() - started), 1),\r\n options.signal,\r\n active,\r\n );\r\n }\r\n\r\n #system(call: SystemCall, body: unknown, options: RequestOptions = {}): Promise<unknown> {\r\n return this.#request(body, options, { system: call });\r\n }\r\n\r\n #spawn(): Instance {\r\n let resolveExit!: (code: number | null) => void;\r\n let resolveReady!: () => void;\r\n const instance: Instance = {\r\n transport: null,\r\n status: ShardStatus.Starting,\r\n startedAt: Date.now(),\r\n everReady: false,\r\n exited: false,\r\n exit: new Promise((resolve) => {\r\n resolveExit = resolve;\r\n }),\r\n resolveExit: (code) => resolveExit(code),\r\n ready: new Promise((resolve) => {\r\n resolveReady = resolve;\r\n }),\r\n resolveReady: () => resolveReady(),\r\n stopping: false,\r\n awaited: true,\r\n incoming: new IncomingRequests(),\r\n slowStart: null,\r\n };\r\n\r\n const context: ShardContext = {\r\n id: this.id,\r\n shards: this.shards,\r\n shardCount: this.shardCount,\r\n pingTimeout: this.ping.enabled ? this.ping.timeout + this.ping.interval : null,\r\n requestTimeout: this.manager.requestTimeout,\r\n messageHandler: this.manager.codec.handler.name,\r\n transformers: this.manager.codec.transformers.map((transformer) => transformer.name),\r\n };\r\n instance.transport = this.manager.strategy.spawn(\r\n context,\r\n {\r\n message: (data) => void this.#receive(instance, data),\r\n exit: (code) => this.#exited(instance, code),\r\n error: (error) => this.#failed(instance, error),\r\n },\r\n { env: this.manager.spawnEnv },\r\n );\r\n\r\n const estimate = this.manager.readyEstimate;\r\n if (estimate !== null) {\r\n instance.slowStart = setTimeout(\r\n () => {\r\n instance.slowStart = null;\r\n if (instance.everReady || instance.exited) return;\r\n const elapsed = Date.now() - instance.startedAt;\r\n this.emit(\"slowStart\", elapsed, estimate);\r\n this.manager.emit(\"shardSlowStart\", this, elapsed, estimate);\r\n },\r\n estimate * (1 + this.manager.readyHintMargin),\r\n );\r\n instance.slowStart.unref();\r\n }\r\n\r\n this.emit(\"spawn\");\r\n this.manager.emit(\"shardCreate\", this);\r\n return instance;\r\n }\r\n\r\n async #awaitReady(instance: Instance, timeout: number): Promise<void> {\r\n let timer: NodeJS.Timeout | undefined;\r\n try {\r\n await Promise.race([\r\n instance.ready,\r\n instance.exit.then((code) => {\r\n throw new ShardSpawnError(this.id, code);\r\n }),\r\n new Promise<never>((_resolve, reject) => {\r\n timer = setTimeout(\r\n () => reject(new ShardUnavailableError(this.id, `not ready within ${timeout}ms`)),\r\n timeout,\r\n );\r\n }),\r\n ]);\r\n this.manager.recordReadyTime(Date.now() - instance.startedAt);\r\n } catch (error) {\r\n instance.stopping = true;\r\n await this.#kill(instance);\r\n if (this.#active === instance) this.#active = null;\r\n throw error;\r\n } finally {\r\n clearTimeout(timer);\r\n instance.awaited = false;\r\n }\r\n }\r\n\r\n async #write(instance: Instance | null, packet: Packet): Promise<void> {\r\n const transport = instance?.transport;\r\n if (!transport || instance.exited)\r\n throw new ShardUnavailableError(this.id, \"it is not running\");\r\n await transport.send(await this.manager.codec.encode(packet, { channelId: this.id }));\r\n }\r\n\r\n async #receive(instance: Instance, data: unknown): Promise<void> {\r\n let packet: Packet;\r\n try {\r\n packet = await this.manager.codec.decode(data, { channelId: this.id });\r\n } catch (error) {\r\n this.manager.reportInvalidMessage(this, error);\r\n return;\r\n }\r\n\r\n const write = (reply: Packet) => this.#write(instance, reply);\r\n switch (packet.op) {\r\n case Op.Signal:\r\n instance.status = packet.status;\r\n if (packet.status === ShardStatus.Ready && !instance.everReady) {\r\n instance.everReady = true;\r\n // From now on, a crash is the supervisor's: whoever spawned the shard is done waiting.\r\n instance.awaited = false;\r\n if (instance.slowStart) clearTimeout(instance.slowStart);\r\n instance.resolveReady();\r\n }\r\n\r\n if (instance === this.#active) this.#setStatus(packet.status);\r\n break;\r\n case Op.Pong:\r\n if (instance === this.#active) {\r\n this.ping.receive(packet.sentAt);\r\n this.emit(\"ping\", this.ping.latency);\r\n this.manager.emit(\"shardPing\", this, this.ping.latency);\r\n }\r\n\r\n break;\r\n case Op.Message:\r\n if (packet.to === undefined) {\r\n this.emit(\"message\", packet.body);\r\n this.manager.emit(\"message\", packet.body, this);\r\n } else {\r\n await this.manager\r\n .route(packet.body, packet.to, this.id)\r\n .catch((error: unknown) => this.manager.reportError(error));\r\n }\r\n\r\n break;\r\n case Op.Request: {\r\n const { to, timeout, partial, system } = packet;\r\n const handler = system\r\n ? (body: unknown, { signal }: { signal: AbortSignal }) =>\r\n this.manager.handleSystem(system, body, this, signal)\r\n : to === undefined\r\n ? this.manager.requestHandler\r\n : (body: unknown, { signal }: { signal: AbortSignal }) =>\r\n this.manager.forward(body, to, this.id, { timeout, signal, partial });\r\n await instance.incoming.handle(write, packet, handler, { channel: this });\r\n break;\r\n }\r\n case Op.Reply:\r\n this.#outgoing.settle(packet);\r\n break;\r\n case Op.Abort:\r\n instance.incoming.abort(packet.nonce);\r\n break;\r\n default:\r\n this.manager.reportInvalidMessage(this, new TypeError(`Unexpected packet ${packet.op}`));\r\n }\r\n }\r\n\r\n #setStatus(status: ShardStatus): void {\r\n if (this.status === status) return;\r\n this.status = status;\r\n this.emit(\"status\", status);\r\n this.manager.emit(\"shardStatus\", this, status);\r\n\r\n switch (status) {\r\n case ShardStatus.Ready:\r\n this.manager.supervisor.ready(this.id);\r\n this.ping.start();\r\n for (const waiter of this.#waiters) waiter.resolve();\r\n this.emit(\"ready\");\r\n this.manager.emit(\"shardReady\", this);\r\n break;\r\n case ShardStatus.Disconnected:\r\n this.emit(\"disconnect\");\r\n this.manager.emit(\"shardDisconnect\", this);\r\n break;\r\n case ShardStatus.Reconnecting:\r\n this.emit(\"reconnecting\");\r\n this.manager.emit(\"shardReconnecting\", this);\r\n break;\r\n case ShardStatus.Idle:\r\n this.ping.stop();\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n #estimatedRemaining(): number | null {\r\n const estimate = this.manager.readyEstimate;\r\n const active = this.#active;\r\n if (estimate === null || !active || this.status !== ShardStatus.Starting) return null;\r\n\r\n // Within the margin of error, the shard may still make it: only give up when even the optimistic estimate is late.\r\n const remaining =\r\n estimate - (Date.now() - active.startedAt) - estimate * this.manager.readyHintMargin;\r\n return remaining > 0 ? Math.round(remaining) : null;\r\n }\r\n\r\n #unresponsive(): void {\r\n if (\r\n this.listenerCount(\"unresponsive\") > 0 ||\r\n this.manager.listenerCount(\"shardUnresponsive\") > 0\r\n ) {\r\n this.emit(\"unresponsive\");\r\n this.manager.emit(\"shardUnresponsive\", this);\r\n } else {\r\n void this.restart().catch((error: unknown) => this.manager.reportError(error));\r\n }\r\n }\r\n\r\n async #stop(instance: Instance, timeout: number): Promise<void> {\r\n instance.stopping = true;\r\n if (instance.exited) return;\r\n\r\n const asked = await this.#write(instance, { op: Op.Close }).then(\r\n () => true,\r\n () => false,\r\n );\r\n // A shard that cannot be asked (e.g. still waiting for a proxy) is killed right away.\r\n const timer = setTimeout(() => void this.#kill(instance), asked ? timeout : 0);\r\n await instance.exit;\r\n clearTimeout(timer);\r\n }\r\n\r\n async #kill(instance: Instance): Promise<void> {\r\n instance.stopping = true;\r\n if (!instance.exited) await instance.transport?.kill();\r\n }\r\n\r\n #failed(instance: Instance, error: unknown): void {\r\n const spawnError = new ShardSpawnError(this.id, null, error);\r\n if (instance.everReady) this.manager.reportShardError(this, error);\r\n else this.manager.reportShardError(this, spawnError);\r\n }\r\n\r\n #exited(instance: Instance, code: number | null): void {\r\n if (instance.exited) return;\r\n instance.exited = true;\r\n if (instance.slowStart) clearTimeout(instance.slowStart);\r\n instance.incoming.abortAll();\r\n this.#outgoing.rejectOwner(instance, new ShardUnavailableError(this.id, \"it stopped\"));\r\n instance.resolveExit(code);\r\n\r\n // A replacement failing to start, or the old shard of a rolling restart: nothing else to do.\r\n if (instance !== this.#active) return;\r\n\r\n this.#active = null;\r\n const previous = instance.status;\r\n this.#setStatus(ShardStatus.Idle);\r\n this.emit(\"exit\", code);\r\n this.manager.emit(\"shardExit\", this, code);\r\n\r\n // The sharder RFC's `error` signal: the shard failed before it was ready.\r\n if (!instance.everReady && !instance.stopping && code !== 0) {\r\n this.manager.reportShardError(this, new ShardSpawnError(this.id, code));\r\n }\r\n\r\n // Whoever stopped or spawned the shard handles what comes next.\r\n if (instance.stopping || instance.awaited) return;\r\n this.manager.supervise(this, previous);\r\n }\r\n\r\n #rejectWaiters(error: unknown): void {\r\n for (const waiter of this.#waiters) waiter.reject(error);\r\n }\r\n}\r\n","import { deserialize, serialize } from \"node:v8\";\r\n\r\n/**\r\n * The data a channel carries between the manager and a shard, once serialized and transformed.\r\n */\r\nexport type ChannelData = string | Uint8Array;\r\n\r\n/**\r\n * Turns the packets exchanged by the manager and its shards into data a channel carries, and back.\r\n *\r\n * @remarks\r\n * The manager tells its shards the name of its handler, and {@link ShardClient} builds the same one from the registry\r\n * (see {@link registerMessageHandler}): a custom handler must be registered in the shards too.\r\n */\r\nexport interface MessageHandler {\r\n /**\r\n * The name of the handler in the registry.\r\n */\r\n readonly name: string;\r\n serialize(packet: unknown): unknown;\r\n deserialize(data: unknown): unknown;\r\n}\r\n\r\n/**\r\n * Serializes packets as JSON: every body must be JSON-serializable. The default.\r\n */\r\nexport class JsonMessageHandler implements MessageHandler {\r\n public readonly name = \"json\";\r\n\r\n public serialize(packet: unknown): string {\r\n return JSON.stringify(packet);\r\n }\r\n\r\n public deserialize(data: unknown): unknown {\r\n return JSON.parse(\r\n typeof data === \"string\" ? data : new TextDecoder().decode(data as Uint8Array),\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Serializes packets with `node:v8`, which keeps `Map`s, `Set`s, `Date`s, `BigInt`s, typed arrays, and circular\r\n * references.\r\n */\r\nexport class V8MessageHandler implements MessageHandler {\r\n public readonly name = \"v8\";\r\n\r\n public serialize(packet: unknown): Uint8Array {\r\n return serialize(packet);\r\n }\r\n\r\n public deserialize(data: unknown): unknown {\r\n if (!(data instanceof Uint8Array)) {\r\n throw new TypeError(\"V8MessageHandler can only read binary data\");\r\n }\r\n\r\n return deserialize(data);\r\n }\r\n}\r\n\r\n/**\r\n * Passes packets as they are, for channels that clone values themselves: worker threads, and processes with the\r\n * `advanced` IPC serialization. It cannot be combined with transformers, nor cross the network.\r\n */\r\nexport class RawMessageHandler implements MessageHandler {\r\n public readonly name = \"raw\";\r\n\r\n public serialize(packet: unknown): unknown {\r\n return packet;\r\n }\r\n\r\n public deserialize(data: unknown): unknown {\r\n return data;\r\n }\r\n}\r\n\r\nconst handlers = new Map<string, () => MessageHandler>([\r\n [\"json\", () => new JsonMessageHandler()],\r\n [\"v8\", () => new V8MessageHandler()],\r\n [\"raw\", () => new RawMessageHandler()],\r\n]);\r\n\r\n/**\r\n * Registers a message handler under its name, so managers and shards can refer to it by name.\r\n *\r\n * @param name The name of the handler, the same as its `name`.\r\n * @param factory Builds the handler.\r\n */\r\nexport function registerMessageHandler(name: string, factory: () => MessageHandler): void {\r\n handlers.set(name, factory);\r\n}\r\n\r\n/**\r\n * Resolves a message handler, or the name of a registered one.\r\n *\r\n * @param handler The handler, or its name.\r\n */\r\nexport function resolveMessageHandler(handler: MessageHandler | string): MessageHandler {\r\n if (typeof handler !== \"string\") return handler;\r\n\r\n const factory = handlers.get(handler);\r\n if (!factory) throw new RangeError(`There is no message handler named \"${handler}\"`);\r\n return factory();\r\n}\r\n","import { promisify } from \"node:util\";\r\nimport { brotliCompress, brotliDecompress, gunzip, gzip, type ZlibOptions } from \"node:zlib\";\r\nimport type { ChannelData } from \"./MessageHandler.js\";\r\n\r\n/**\r\n * The channel a transformer reads or writes on.\r\n */\r\nexport interface TransformerContext {\r\n /**\r\n * The ID of the channel: the shard the data comes from or goes to.\r\n */\r\n channelId: number;\r\n}\r\n\r\n/**\r\n * Transforms serialized data on its way to the channel, and back: compression, encryption, signing, ...\r\n *\r\n * @remarks\r\n * Transformers compose: they write in the order they are given, and read in the reverse order. `[gzip, aes]` gzips\r\n * then encrypts when writing, and decrypts then gunzips when reading. A transformer throwing while reading rejects the\r\n * data, which is reported as an invalid message.\r\n *\r\n * Like {@link MessageHandler}s, the manager tells its shards the names of its transformers: custom ones must be\r\n * registered in the shards too, see {@link registerMessageTransformer}.\r\n */\r\nexport interface MessageTransformer {\r\n /**\r\n * The name of the transformer in the registry.\r\n */\r\n readonly name: string;\r\n write(data: ChannelData, context: TransformerContext): ChannelData | Promise<ChannelData>;\r\n read(data: ChannelData, context: TransformerContext): ChannelData | Promise<ChannelData>;\r\n}\r\n\r\nconst gzipAsync = promisify(gzip);\r\nconst gunzipAsync = promisify(gunzip);\r\nconst brotliCompressAsync = promisify(brotliCompress);\r\nconst brotliDecompressAsync = promisify(brotliDecompress);\r\n\r\n/**\r\n * Compresses messages with gzip.\r\n */\r\nexport class GzipTransformer implements MessageTransformer {\r\n public readonly name = \"gzip\";\r\n private readonly options: ZlibOptions;\r\n\r\n /**\r\n * @param options The compression options, e.g. its `level`.\r\n */\r\n public constructor(options: ZlibOptions = {}) {\r\n this.options = options;\r\n }\r\n\r\n public write(data: ChannelData): Promise<Uint8Array> {\r\n return gzipAsync(data, this.options);\r\n }\r\n\r\n public read(data: ChannelData): Promise<Uint8Array> {\r\n return gunzipAsync(data);\r\n }\r\n}\r\n\r\n/**\r\n * Compresses messages with Brotli, smaller than gzip at a higher CPU cost.\r\n */\r\nexport class BrotliTransformer implements MessageTransformer {\r\n public readonly name = \"brotli\";\r\n\r\n public write(data: ChannelData): Promise<Uint8Array> {\r\n return brotliCompressAsync(data);\r\n }\r\n\r\n public read(data: ChannelData): Promise<Uint8Array> {\r\n return brotliDecompressAsync(data);\r\n }\r\n}\r\n\r\nconst transformers = new Map<string, () => MessageTransformer>([\r\n [\"gzip\", () => new GzipTransformer()],\r\n [\"brotli\", () => new BrotliTransformer()],\r\n]);\r\n\r\n/**\r\n * Registers a message transformer under its name, so managers and shards can refer to it by name.\r\n *\r\n * @param name The name of the transformer, the same as its `name`.\r\n * @param factory Builds the transformer, e.g. with a key read from the environment.\r\n */\r\nexport function registerMessageTransformer(name: string, factory: () => MessageTransformer): void {\r\n transformers.set(name, factory);\r\n}\r\n\r\n/**\r\n * Resolves a message transformer, or the name of a registered one.\r\n *\r\n * @param transformer The transformer, or its name.\r\n */\r\nexport function resolveMessageTransformer(\r\n transformer: MessageTransformer | string,\r\n): MessageTransformer {\r\n if (typeof transformer !== \"string\") return transformer;\r\n\r\n const factory = transformers.get(transformer);\r\n if (!factory) throw new RangeError(`There is no message transformer named \"${transformer}\"`);\r\n return factory();\r\n}\r\n","/**\r\n * What a shard is told about itself when spawned, read back by {@link ShardClient}.\r\n */\r\nexport interface ShardContext {\r\n /**\r\n * The ID of the shard: the index of its channel in the manager.\r\n */\r\n id: number;\r\n /**\r\n * The IDs of the gateway shards the shard connects.\r\n */\r\n shards: readonly number[];\r\n /**\r\n * The total number of gateway shards, across every shard (and every manager).\r\n */\r\n shardCount: number;\r\n /**\r\n * How long the ready shard may go without a ping from its manager, in milliseconds, before\r\n * `managerUnresponsive`; `null` when the manager does not ping.\r\n */\r\n pingTimeout: number | null;\r\n /**\r\n * How long the shard waits for the replies of its requests by default, in milliseconds.\r\n */\r\n requestTimeout: number;\r\n /**\r\n * The name of the manager's message handler.\r\n */\r\n messageHandler: string;\r\n /**\r\n * The names of the manager's message transformers, in order.\r\n */\r\n transformers: readonly string[];\r\n /**\r\n * How the shard talks to its parent: the process IPC channel, or its worker thread port. Set by the strategy.\r\n */\r\n transport?: \"process\" | \"worker\";\r\n}\r\n\r\n/**\r\n * The callbacks a {@link ChannelStrategy} reports a spawned shard's activity through.\r\n */\r\nexport interface ShardTransportEvents {\r\n message(data: unknown): void;\r\n /**\r\n * The shard stopped. Called once per spawn.\r\n */\r\n exit(code: number | null): void;\r\n /**\r\n * The shard failed, e.g. a worker that could not start.\r\n */\r\n error(error: unknown): void;\r\n}\r\n\r\n/**\r\n * What a strategy spawns a shard with, on top of its context.\r\n */\r\nexport interface SpawnOptions {\r\n /**\r\n * Environment variables for the shard, e.g. `DISCORD_TOKEN`.\r\n */\r\n env: Record<string, string>;\r\n}\r\n\r\n/**\r\n * The manager's end of the channel to one spawned shard.\r\n */\r\nexport interface ShardTransport {\r\n send(data: unknown): Promise<void>;\r\n /**\r\n * Stops the shard, resolving once it stopped.\r\n */\r\n kill(): Promise<void>;\r\n /**\r\n * The ID of the shard's process, for observability.\r\n */\r\n readonly pid?: number | null;\r\n /**\r\n * The ID of the shard's worker thread.\r\n */\r\n readonly threadId?: number | null;\r\n /**\r\n * The host running the shard, for strategies spawning shards elsewhere.\r\n */\r\n readonly host?: string | null;\r\n}\r\n\r\n/**\r\n * Spawns shards: as child processes, cluster workers, worker threads, on other machines, or anything else. The\r\n * sharder RFC's channel strategy.\r\n */\r\nexport interface ChannelStrategy {\r\n /**\r\n * The name of the strategy in the registry, see {@link registerStrategy}.\r\n */\r\n readonly name: string;\r\n /**\r\n * Prepares the strategy before the first spawn, e.g. starts listening for proxies.\r\n */\r\n init?(): Promise<void>;\r\n /**\r\n * Releases what the strategy holds, once every shard is closed.\r\n */\r\n destroy?(): Promise<void>;\r\n spawn(context: ShardContext, events: ShardTransportEvents, options: SpawnOptions): ShardTransport;\r\n}\r\n\r\n/**\r\n * The environment variable carrying the {@link ShardContext} of a shard.\r\n */\r\nexport const ShardContextVariable = \"WOLFSTAR_SHARDER\";\r\n\r\n/**\r\n * Serializes a shard's context for its environment or worker data.\r\n *\r\n * @internal\r\n */\r\nexport function encodeContext(context: ShardContext): string {\r\n return JSON.stringify(context);\r\n}\r\n","import type { Result } from \"@sapphire/result\";\r\nimport { EventEmitter } from \"node:events\";\r\nimport { isMainThread, parentPort, threadId, workerData } from \"node:worker_threads\";\r\nimport {\r\n registerMessageHandler,\r\n resolveMessageHandler,\r\n type MessageHandler,\r\n} from \"./messages/MessageHandler.js\";\r\nimport {\r\n registerMessageTransformer,\r\n resolveMessageTransformer,\r\n type MessageTransformer,\r\n} from \"./messages/MessageTransformer.js\";\r\nimport {\r\n Op,\r\n PacketCodec,\r\n ShardStatus,\r\n type ControlRequest,\r\n type Packet,\r\n type SerializedSettledResult,\r\n type ShardTarget,\r\n type SystemCall,\r\n} from \"./messages/protocol.js\";\r\nimport { ShardContextVariable, type ShardContext } from \"./strategies/ChannelStrategy.js\";\r\nimport type { ShardError } from \"./util/errors.js\";\r\nimport type { GatewayInformation } from \"./util/gateway.js\";\r\nimport {\r\n IncomingRequests,\r\n OutgoingRequests,\r\n deserializeSettled,\r\n settledToResults,\r\n toResult,\r\n type BroadcastRequestOptions,\r\n type RequestHandler,\r\n type RequestOptions,\r\n} from \"./util/requests.js\";\r\n\r\n// The longest delay `setTimeout` takes: identifies may wait behind every other gateway shard.\r\nconst MaxTimeout = 2_147_483_647;\r\n\r\n/**\r\n * The shard's end of the channel to its manager (or proxy).\r\n */\r\nexport interface ClientTransport {\r\n send(data: unknown): Promise<void>;\r\n onMessage(listener: (data: unknown) => void): void;\r\n /**\r\n * Registers what to do when the channel to the manager closes, i.e. when the manager died.\r\n */\r\n onDisconnect(listener: () => void): void;\r\n /**\r\n * Stops the shard.\r\n */\r\n exit(code: number): void;\r\n}\r\n\r\n/**\r\n * The options of a {@link ShardClient}.\r\n */\r\nexport interface ShardClientOptions {\r\n /**\r\n * How messages are serialized. Defaults to the manager's, built from the registry.\r\n */\r\n messageHandler?: MessageHandler | string;\r\n /**\r\n * How serialized messages are transformed. Defaults to the manager's, built from the registry.\r\n */\r\n transformers?: readonly (MessageTransformer | string)[];\r\n /**\r\n * The shard's context. Defaults to the one its manager passed when spawning it.\r\n */\r\n context?: ShardContext;\r\n /**\r\n * The channel to the manager. Defaults to the one of {@link ShardContext.transport}.\r\n */\r\n transport?: ClientTransport;\r\n}\r\n\r\n/**\r\n * Starts and closes the gateway shards of this shard, when the manager asks.\r\n */\r\nexport interface ShardHandler {\r\n start?(shardId: number, context: { signal: AbortSignal }): unknown;\r\n close?(shardId: number, context: { signal: AbortSignal }): unknown;\r\n}\r\n\r\n/**\r\n * Paces identifies across every shard, the shape of `@discordjs/ws`'s `IIdentifyThrottler`.\r\n */\r\nexport interface IdentifyThrottler {\r\n waitForIdentify(shardId: number, signal: AbortSignal): Promise<void>;\r\n}\r\n\r\n/**\r\n * The events of a {@link ShardClient}.\r\n */\r\nexport interface ShardClientEvents {\r\n /**\r\n * A message from the manager (`from` is `null`) or from another shard.\r\n */\r\n message: [body: any, from: number | null];\r\n /**\r\n * The channel to the manager closed. Without listeners, the shard exits.\r\n */\r\n disconnect: [];\r\n /**\r\n * The manager stopped pinging, e.g. a proxy lost it. The shard keeps running.\r\n */\r\n managerUnresponsive: [];\r\n /**\r\n * The manager sent data that could not be read. Without listeners, it is logged with `console.error`.\r\n */\r\n invalidMessage: [error: unknown];\r\n /**\r\n * Without listeners, errors are logged with `console.error`.\r\n */\r\n error: [error: unknown];\r\n}\r\n\r\n/**\r\n * The shard's side of the sharder: it tells the manager its status, and messages the manager and the other shards.\r\n *\r\n * @example\r\n * ```ts\r\n * const shard = new ShardClient();\r\n * const client = new GatewayClient({\r\n * ...options,\r\n * ...shard.gatewayOptions,\r\n * gateway: { buildIdentifyThrottler: () => shard.identifyThrottler },\r\n * });\r\n * // Reuse the manager's `GET /gateway/bot` rather than requesting it again.\r\n * client.gateway.fetchGatewayInformation = () => shard.fetchGatewayInformation();\r\n * shard.setRequestHandler((body) => ...);\r\n * ```\r\n */\r\nexport class ShardClient extends EventEmitter<ShardClientEvents> {\r\n /**\r\n * The context of this process or thread, when a {@link ShardManager} spawned it; `null` otherwise.\r\n */\r\n public static get context(): ShardContext | null {\r\n const raw: unknown = isMainThread\r\n ? process.env[ShardContextVariable]\r\n : (workerData as Record<string, unknown> | null)?.[ShardContextVariable];\r\n return typeof raw === \"string\" ? (JSON.parse(raw) as ShardContext) : null;\r\n }\r\n\r\n /**\r\n * Registers a message handler the manager can refer to by name. The sharder RFC's API.\r\n *\r\n * @param name The name of the handler.\r\n * @param factory Builds the handler.\r\n */\r\n public static registerMessageHandler(\r\n name: string,\r\n factory: () => MessageHandler,\r\n ): typeof ShardClient {\r\n registerMessageHandler(name, factory);\r\n return ShardClient;\r\n }\r\n\r\n /**\r\n * Registers a message transformer the manager can refer to by name. The sharder RFC's API.\r\n *\r\n * @param name The name of the transformer.\r\n * @param factory Builds the transformer.\r\n */\r\n public static registerMessageTransformer(\r\n name: string,\r\n factory: () => MessageTransformer,\r\n ): typeof ShardClient {\r\n registerMessageTransformer(name, factory);\r\n return ShardClient;\r\n }\r\n\r\n /**\r\n * The ID of the shard, its channel's in the manager.\r\n */\r\n public readonly id: number;\r\n\r\n /**\r\n * The IDs of the gateway shards the shard connects.\r\n */\r\n public readonly shards: readonly number[];\r\n\r\n /**\r\n * The total number of gateway shards, across every shard.\r\n */\r\n public readonly shardCount: number;\r\n\r\n public readonly requestTimeout: number;\r\n\r\n /**\r\n * The last status signalled to the manager.\r\n */\r\n public status: ShardStatus = ShardStatus.Starting;\r\n\r\n /**\r\n * When the manager last pinged the shard, `null` before its first ping.\r\n */\r\n public lastPingTimestamp: number | null = null;\r\n\r\n readonly #transport: ClientTransport;\r\n readonly #codec: PacketCodec;\r\n readonly #outgoing = new OutgoingRequests();\r\n readonly #incoming = new IncomingRequests();\r\n readonly #pingTimeout: number | null;\r\n #watchdog: NodeJS.Timeout | null = null;\r\n #requestHandler: RequestHandler<{ from: number | null }> | null = null;\r\n #closeHandler: (() => unknown) | null = null;\r\n #shardHandler: ShardHandler | null = null;\r\n\r\n public constructor(options: ShardClientOptions = {}) {\r\n super();\r\n const context = options.context ?? ShardClient.context;\r\n if (!context) throw new Error(\"This process or thread was not spawned by a ShardManager\");\r\n\r\n this.id = context.id;\r\n this.shards = context.shards;\r\n this.shardCount = context.shardCount;\r\n this.requestTimeout = context.requestTimeout;\r\n this.#codec = new PacketCodec(\r\n resolveMessageHandler(options.messageHandler ?? context.messageHandler),\r\n (options.transformers ?? context.transformers).map(resolveMessageTransformer),\r\n );\r\n this.#transport = options.transport ?? defaultTransport(context);\r\n this.#transport.onMessage((data) => void this.#receive(data));\r\n this.#transport.onDisconnect(() => {\r\n this.#stopWatchdog();\r\n if (this.listenerCount(\"disconnect\") > 0) this.emit(\"disconnect\");\r\n else this.#transport.exit(0);\r\n });\r\n\r\n this.#pingTimeout = context.pingTimeout;\r\n void this.#signal(ShardStatus.Starting).catch((error: unknown) => this.#report(error));\r\n }\r\n\r\n /**\r\n * The ID of the shard's process.\r\n */\r\n public get pid(): number {\r\n return process.pid;\r\n }\r\n\r\n /**\r\n * The ID of the shard's thread, `0` for a process's main thread.\r\n */\r\n public get threadId(): number {\r\n return threadId;\r\n }\r\n\r\n /**\r\n * The gateway shards to connect, to spread into `GatewayClient`'s (or `@discordjs/ws`'s) options.\r\n */\r\n public get gatewayOptions(): { shardIds: number[]; shardCount: number } {\r\n return { shardIds: [...this.shards], shardCount: this.shardCount };\r\n }\r\n\r\n /**\r\n * Paces the identifies of the gateway shards across every shard, through the manager: pass it as `@discordjs/ws`'s\r\n * `buildIdentifyThrottler`. The manager then needs no spawn delay.\r\n */\r\n public get identifyThrottler(): IdentifyThrottler {\r\n return {\r\n waitForIdentify: async (shardId, signal) => {\r\n await this.#system(\"identify\", shardId, { timeout: MaxTimeout, signal });\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Gets `GET /gateway/bot` from the manager, fetched once for every shard, e.g. to replace `@discordjs/ws`'s\r\n * `WebSocketManager#fetchGatewayInformation`.\r\n */\r\n public fetchGatewayInformation(): Promise<GatewayInformation> {\r\n return this.#system(\"gatewayInformation\", null) as Promise<GatewayInformation>;\r\n }\r\n\r\n /**\r\n * Tells the manager that the shard is ready, e.g. once its gateway shards are. The manager spawns the next shard\r\n * only then.\r\n */\r\n public ready(): Promise<void> {\r\n // The manager pings ready shards only.\r\n if (!this.#watchdog && this.#pingTimeout !== null) {\r\n this.#watchdog = setTimeout(() => {\r\n this.#watchdog = null;\r\n this.emit(\"managerUnresponsive\");\r\n }, this.#pingTimeout);\r\n this.#watchdog.unref();\r\n }\r\n\r\n return this.#signal(ShardStatus.Ready);\r\n }\r\n\r\n /**\r\n * Tells the manager that the shard lost what it serves, e.g. the gateway. Messages for it wait until it is ready\r\n * again.\r\n */\r\n public disconnected(): Promise<void> {\r\n return this.#signal(ShardStatus.Disconnected);\r\n }\r\n\r\n /**\r\n * Tells the manager that the shard is reconnecting to what it serves.\r\n */\r\n public reconnecting(): Promise<void> {\r\n return this.#signal(ShardStatus.Reconnecting);\r\n }\r\n\r\n /**\r\n * Stops the shard for good: the manager does not respawn it.\r\n *\r\n * @param code The exit code.\r\n */\r\n public async exit(code = 0): Promise<void> {\r\n await this.#stop(ShardStatus.Exiting, code);\r\n }\r\n\r\n /**\r\n * Stops the shard, for the manager to spawn it again.\r\n */\r\n public async restart(): Promise<void> {\r\n await this.#stop(ShardStatus.Restarting, 0);\r\n }\r\n\r\n /**\r\n * Sends a message to the manager, emitted as its `message` event, or to other shards.\r\n *\r\n * @param body The message.\r\n * @param to The ID of the shard to send it to, or `\"all\"`. Left out, it goes to the manager.\r\n */\r\n public send(body: unknown, to?: ShardTarget): Promise<void> {\r\n return this.#write({ op: Op.Message, body, to });\r\n }\r\n\r\n /**\r\n * Sends a request to the manager or to another shard.\r\n *\r\n * @param body The request.\r\n * @param options Where it goes (the manager by default), its timeout, and its abort signal.\r\n */\r\n public request<Reply = unknown>(\r\n body: unknown,\r\n options: RequestOptions & { to?: number } = {},\r\n ): Promise<Reply> {\r\n return this.#outgoing.request(\r\n (packet) => this.#write(packet),\r\n { body, to: options.to },\r\n options.timeout ?? this.requestTimeout,\r\n options.signal,\r\n ) as Promise<Reply>;\r\n }\r\n\r\n /**\r\n * Sends a request to every shard, this one included, like discord.js's `broadcastEval` without the `eval`.\r\n *\r\n * @param body The request.\r\n * @param options The timeout and abort signal of the request, and whether to keep partial results.\r\n * @returns The replies by shard ID, or with `partial`, the outcome of every request.\r\n */\r\n public broadcastRequest<Reply = unknown>(\r\n body: unknown,\r\n options: BroadcastRequestOptions & { partial: true },\r\n ): Promise<PromiseSettledResult<Reply>[]>;\r\n public broadcastRequest<Reply = unknown>(\r\n body: unknown,\r\n options?: BroadcastRequestOptions,\r\n ): Promise<Reply[]>;\r\n public async broadcastRequest(\r\n body: unknown,\r\n options: BroadcastRequestOptions = {},\r\n ): Promise<unknown> {\r\n const reply = await this.#outgoing.request(\r\n (packet) => this.#write(packet),\r\n { body, to: \"all\", partial: options.partial },\r\n options.timeout ?? this.requestTimeout,\r\n options.signal,\r\n );\r\n return options.partial ? deserializeSettled(reply as SerializedSettledResult[]) : reply;\r\n }\r\n\r\n /**\r\n * {@link ShardClient.send}, resolving with a `Result` rather than rejecting.\r\n */\r\n public trySend(body: unknown, to?: ShardTarget): Promise<Result<void, ShardError>> {\r\n return toResult(() => this.send(body, to));\r\n }\r\n\r\n /**\r\n * {@link ShardClient.request}, resolving with a `Result` rather than rejecting.\r\n */\r\n public tryRequest<Reply = unknown>(\r\n body: unknown,\r\n options?: RequestOptions & { to?: number },\r\n ): Promise<Result<Reply, ShardError>> {\r\n return toResult(() => this.request<Reply>(body, options));\r\n }\r\n\r\n /**\r\n * {@link ShardClient.broadcastRequest}, with one `Result` per shard, by shard ID. The broadcast itself failing\r\n * (e.g. the manager not answering) is the outer `Err`.\r\n */\r\n public tryBroadcastRequest<Reply = unknown>(\r\n body: unknown,\r\n options?: RequestOptions,\r\n ): Promise<Result<Result<Reply, ShardError>[], ShardError>> {\r\n return toResult(async () =>\r\n settledToResults(await this.broadcastRequest<Reply>(body, { ...options, partial: true })),\r\n );\r\n }\r\n\r\n /**\r\n * {@link ShardClient.control}, resolving with a `Result` rather than rejecting.\r\n */\r\n public tryControl(\r\n request: ControlRequest,\r\n options?: RequestOptions,\r\n ): Promise<Result<void, ShardError>> {\r\n return toResult(() => this.control(request, options));\r\n }\r\n\r\n /**\r\n * Asks the manager to start, close, or restart shards or gateway shards.\r\n *\r\n * @param request What to do, and to what.\r\n * @param options The timeout and abort signal of the request.\r\n * @example\r\n * ```ts\r\n * await shard.control({ action: \"restart\", target: { channel: \"all\" } });\r\n * await shard.control({ action: \"restart\", target: { shard: 12 } });\r\n * ```\r\n */\r\n public async control(request: ControlRequest, options?: RequestOptions): Promise<void> {\r\n await this.#system(\"control\", request, options);\r\n }\r\n\r\n /**\r\n * Sets the handler answering the requests of the manager and of the other shards.\r\n *\r\n * @param handler The handler; its return value is the reply. `from` is the shard asking, `null` for the manager.\r\n */\r\n public setRequestHandler(handler: RequestHandler<{ from: number | null }> | null): this {\r\n this.#requestHandler = handler;\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets what to do when the manager closes the shard, e.g. disconnect from the gateway. The shard exits once it\r\n * resolves; without a handler, it exits right away.\r\n *\r\n * @param handler The handler.\r\n */\r\n public setCloseHandler(handler: (() => unknown) | null): this {\r\n this.#closeHandler = handler;\r\n return this;\r\n }\r\n\r\n /**\r\n * Sets how the manager starts and closes the gateway shards of this shard, for `manager.startShard` & co.\r\n *\r\n * @param handler Starts or closes a gateway shard, resolving once done.\r\n */\r\n public setShardHandler(handler: ShardHandler | null): this {\r\n this.#shardHandler = handler;\r\n return this;\r\n }\r\n\r\n #system(call: SystemCall, body: unknown, options: RequestOptions = {}): Promise<unknown> {\r\n return this.#outgoing.request(\r\n (packet) => this.#write(packet),\r\n { body, system: call },\r\n options.timeout ?? this.requestTimeout,\r\n options.signal,\r\n );\r\n }\r\n\r\n async #signal(status: ShardStatus): Promise<void> {\r\n this.status = status;\r\n await this.#write({ op: Op.Signal, status });\r\n }\r\n\r\n #stopWatchdog(): void {\r\n if (this.#watchdog) clearTimeout(this.#watchdog);\r\n this.#watchdog = null;\r\n }\r\n\r\n async #stop(status: ShardStatus, code: number): Promise<void> {\r\n this.#stopWatchdog();\r\n await this.#signal(status).catch(() => undefined);\r\n this.#transport.exit(code);\r\n }\r\n\r\n async #write(packet: Packet): Promise<void> {\r\n await this.#transport.send(await this.#codec.encode(packet, { channelId: this.id }));\r\n }\r\n\r\n async #receive(data: unknown): Promise<void> {\r\n let packet: Packet;\r\n try {\r\n packet = await this.#codec.decode(data, { channelId: this.id });\r\n } catch (error) {\r\n if (this.listenerCount(\"invalidMessage\") > 0) this.emit(\"invalidMessage\", error);\r\n else console.error(\"The shard manager sent an invalid message:\", error);\r\n return;\r\n }\r\n\r\n switch (packet.op) {\r\n case Op.Ping:\r\n this.lastPingTimestamp = Date.now();\r\n this.#watchdog?.refresh();\r\n await this.#write({ op: Op.Pong, sentAt: packet.sentAt }).catch(() => undefined);\r\n break;\r\n case Op.Message:\r\n this.emit(\"message\", packet.body, packet.from ?? null);\r\n break;\r\n case Op.Request: {\r\n const { system } = packet;\r\n const handler = system\r\n ? (body: number, { signal }: { signal: AbortSignal }) =>\r\n this.#handleSystem(system, body, signal)\r\n : this.#requestHandler;\r\n await this.#incoming.handle((reply) => this.#write(reply), packet, handler, {\r\n from: packet.from ?? null,\r\n });\r\n break;\r\n }\r\n case Op.Reply:\r\n this.#outgoing.settle(packet);\r\n break;\r\n case Op.Abort:\r\n this.#incoming.abort(packet.nonce);\r\n break;\r\n case Op.Close:\r\n try {\r\n await this.#closeHandler?.();\r\n } catch (error) {\r\n this.#report(error);\r\n }\r\n\r\n await this.exit(0);\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n async #handleSystem(call: SystemCall, shardId: number, signal: AbortSignal): Promise<null> {\r\n const action =\r\n call === \"startShard\"\r\n ? this.#shardHandler?.start\r\n : call === \"closeShard\"\r\n ? this.#shardHandler?.close\r\n : null;\r\n if (call !== \"startShard\" && call !== \"closeShard\") {\r\n throw new Error(`The manager cannot send the ${call} system request`);\r\n }\r\n\r\n if (!this.shards.includes(shardId))\r\n throw new RangeError(`This shard does not connect the gateway shard ${shardId}`);\r\n if (!action)\r\n throw new Error(\r\n `There is no shard handler to ${call === \"startShard\" ? \"start\" : \"close\"} gateway shards`,\r\n );\r\n await action.call(this.#shardHandler, shardId, { signal });\r\n return null;\r\n }\r\n\r\n #report(error: unknown): void {\r\n if (this.listenerCount(\"error\") > 0) this.emit(\"error\", error);\r\n else console.error(error);\r\n }\r\n}\r\n\r\nfunction defaultTransport(context: ShardContext): ClientTransport {\r\n if (context.transport === \"worker\") {\r\n if (!parentPort) throw new Error(\"The shard is not running in a worker thread\");\r\n const port = parentPort;\r\n return {\r\n send: async (data) => port.postMessage(data),\r\n onMessage: (listener) => port.on(\"message\", listener),\r\n // A worker thread stops with its manager's process.\r\n onDisconnect: () => undefined,\r\n exit: (code) => process.exit(code),\r\n };\r\n }\r\n\r\n if (!process.send) throw new Error(\"The shard has no IPC channel to its manager\");\r\n return {\r\n send: (data) =>\r\n new Promise((resolve, reject) => {\r\n if (!process.connected) {\r\n reject(new Error(\"The IPC channel to the manager is closed\"));\r\n return;\r\n }\r\n\r\n process.send!(data, undefined, undefined, (error: Error | null) =>\r\n error ? reject(error) : resolve(),\r\n );\r\n }),\r\n onMessage: (listener) => process.on(\"message\", listener),\r\n onDisconnect: (listener) => process.once(\"disconnect\", listener),\r\n exit: (code) => process.exit(code),\r\n };\r\n}\r\n","import type { ChildProcess } from \"node:child_process\";\r\nimport type { Worker as ClusterWorker } from \"node:cluster\";\r\nimport type {\r\n ChannelStrategy,\r\n ShardContext,\r\n ShardTransport,\r\n ShardTransportEvents,\r\n SpawnOptions,\r\n} from \"./ChannelStrategy.js\";\r\n\r\n/**\r\n * The options shared by the strategies spawning processes.\r\n */\r\nexport interface ProcessStrategyOptions {\r\n /**\r\n * The arguments passed to the shard's script.\r\n */\r\n args?: readonly string[];\r\n /**\r\n * The arguments passed to Node.js, e.g. `[\"--enable-source-maps\"]`.\r\n */\r\n execArgv?: readonly string[];\r\n /**\r\n * Extra environment variables, on top of the manager's own.\r\n */\r\n env?: NodeJS.ProcessEnv;\r\n}\r\n\r\n/**\r\n * The base of {@link ForkStrategy} and {@link ClusterStrategy}: a shard is a process with an IPC channel, using the\r\n * `advanced` serialization so binary data (and {@link RawMessageHandler}'s values) survive it.\r\n */\r\nexport abstract class ProcessStrategy implements ChannelStrategy {\r\n public abstract readonly name: string;\r\n\r\n public spawn(\r\n context: ShardContext,\r\n events: ShardTransportEvents,\r\n options: SpawnOptions,\r\n ): ShardTransport {\r\n const child = this.createProcess({ ...context, transport: \"process\" }, options);\r\n // A cluster worker wraps its child process.\r\n const process: ChildProcess = \"process\" in child ? child.process : child;\r\n\r\n process.on(\"message\", (data: unknown) => events.message(data));\r\n process.on(\"error\", (error: unknown) => events.error(error));\r\n let exited = false;\r\n const exit = new Promise<void>((resolve) => {\r\n process.once(\"exit\", (code) => {\r\n exited = true;\r\n events.exit(code);\r\n resolve();\r\n });\r\n });\r\n\r\n return {\r\n pid: process.pid ?? null,\r\n send: (data) =>\r\n new Promise((resolve, reject) => {\r\n if (!process.connected) {\r\n reject(new Error(\"The shard's IPC channel is closed\"));\r\n return;\r\n }\r\n\r\n process.send(data as never, undefined, undefined, (error) =>\r\n error ? reject(error) : resolve(),\r\n );\r\n }),\r\n kill: async () => {\r\n if (!exited) process.kill();\r\n await exit;\r\n },\r\n };\r\n }\r\n\r\n protected abstract createProcess(\r\n context: ShardContext,\r\n options: SpawnOptions,\r\n ): ChildProcess | ClusterWorker;\r\n}\r\n","import cluster, { type Worker as ClusterWorker } from \"node:cluster\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport {\r\n ShardContextVariable,\r\n encodeContext,\r\n type ShardContext,\r\n type SpawnOptions,\r\n} from \"./ChannelStrategy.js\";\r\nimport { ProcessStrategy, type ProcessStrategyOptions } from \"./ProcessStrategy.js\";\r\n\r\n/**\r\n * The options of {@link ClusterStrategy}.\r\n */\r\nexport interface ClusterStrategyOptions extends ProcessStrategyOptions {\r\n /**\r\n * The script every shard runs. Defaults to the manager's own script, so one file handles both sides: check\r\n * `cluster.isPrimary` to tell them apart.\r\n */\r\n path?: string | URL;\r\n}\r\n\r\n/**\r\n * Spawns every shard as a `node:cluster` worker. Unlike {@link ForkStrategy}, the shards share the ports they listen\r\n * on, and the primary balances the connections between them.\r\n */\r\nexport class ClusterStrategy extends ProcessStrategy {\r\n public readonly name = \"cluster\";\r\n public readonly options: ClusterStrategyOptions;\r\n\r\n public constructor(options: ClusterStrategyOptions = {}) {\r\n super();\r\n this.options = options;\r\n }\r\n\r\n protected createProcess(context: ShardContext, options: SpawnOptions): ClusterWorker {\r\n const { path, args, execArgv, env } = this.options;\r\n cluster.setupPrimary({\r\n exec: path instanceof URL ? fileURLToPath(path) : path,\r\n args: args ? [...args] : undefined,\r\n execArgv: execArgv ? [...execArgv] : undefined,\r\n serialization: \"advanced\",\r\n });\r\n return cluster.fork({ ...env, ...options.env, [ShardContextVariable]: encodeContext(context) });\r\n }\r\n}\r\n","import { fork, type ChildProcess } from \"node:child_process\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport {\r\n ShardContextVariable,\r\n encodeContext,\r\n type ShardContext,\r\n type SpawnOptions,\r\n} from \"./ChannelStrategy.js\";\r\nimport { ProcessStrategy, type ProcessStrategyOptions } from \"./ProcessStrategy.js\";\r\n\r\n/**\r\n * The options of {@link ForkStrategy}.\r\n */\r\nexport interface ForkStrategyOptions extends ProcessStrategyOptions {\r\n /**\r\n * The script every shard runs. Defaults to the manager's own script: check {@link ShardClient.context} to tell the\r\n * manager and the shards apart.\r\n */\r\n path?: string | URL;\r\n}\r\n\r\n/**\r\n * Spawns every shard as a child process with `child_process.fork`. The default strategy.\r\n *\r\n * @remarks\r\n * Every shard is its own process: ports opened by the shards (e.g. an HTTP interactions server) must differ.\r\n */\r\nexport class ForkStrategy extends ProcessStrategy {\r\n public readonly name = \"fork\";\r\n public readonly options: ForkStrategyOptions;\r\n\r\n public constructor(options: ForkStrategyOptions = {}) {\r\n super();\r\n this.options = options;\r\n }\r\n\r\n protected createProcess(context: ShardContext, options: SpawnOptions): ChildProcess {\r\n const { path = process.argv[1]!, args = [], execArgv, env } = this.options;\r\n return fork(path instanceof URL ? fileURLToPath(path) : path, args, {\r\n env: {\r\n ...process.env,\r\n ...env,\r\n ...options.env,\r\n [ShardContextVariable]: encodeContext(context),\r\n },\r\n execArgv: execArgv ? [...execArgv] : undefined,\r\n serialization: \"advanced\",\r\n });\r\n }\r\n}\r\n","import { createHash, timingSafeEqual } from \"node:crypto\";\r\nimport { EventEmitter } from \"node:events\";\r\nimport type { Socket } from \"node:net\";\r\n\r\n/**\r\n * The frames exchanged between a manager and its proxies, and between proxies.\r\n *\r\n * @internal\r\n */\r\nexport const FrameType = {\r\n /**\r\n * Proxy → manager, JSON {@link HelloFrame}: authenticates, and lists the shards still running.\r\n */\r\n Hello: 0,\r\n /**\r\n * Manager → proxy, JSON {@link WelcomeFrame}: accepts the proxy, and lists the running shards to kill.\r\n */\r\n Welcome: 1,\r\n /**\r\n * Manager → proxy, JSON `{ reason }`: rejects the proxy.\r\n */\r\n Reject: 2,\r\n /**\r\n * Manager → proxy, JSON {@link SpawnFrame}.\r\n */\r\n Spawn: 3,\r\n /**\r\n * Proxy → manager, JSON `{ spawnId, pid, threadId }`: the shard was spawned.\r\n */\r\n Spawned: 4,\r\n /**\r\n * Manager → proxy, JSON `{ spawnId }`.\r\n */\r\n Kill: 5,\r\n /**\r\n * Proxy → manager, JSON `{ spawnId, code }`.\r\n */\r\n Exit: 6,\r\n /**\r\n * Proxy → manager, JSON `{ spawnId, message }`.\r\n */\r\n Error: 7,\r\n /**\r\n * Both ways: a spawn ID (u32), then the string data.\r\n */\r\n StringData: 8,\r\n /**\r\n * Both ways: a spawn ID (u32), then the binary data.\r\n */\r\n BinaryData: 9,\r\n Heartbeat: 10,\r\n /**\r\n * Proxy → manager, JSON `{ available }`: how many more shards the proxy takes, across all its managers.\r\n */\r\n Load: 11,\r\n /**\r\n * Proxy → manager, JSON `{ spawnId, ready }`: whether a shard is ready, for the peer directory.\r\n */\r\n Status: 12,\r\n /**\r\n * Manager → proxy, JSON {@link DirectoryFrame}: which proxy runs which ready shard, for peer routing.\r\n */\r\n Directory: 13,\r\n /**\r\n * Proxy → proxy, JSON `{ token, name }`: opens a peer connection.\r\n */\r\n PeerHello: 20,\r\n /**\r\n * Proxy → proxy, empty: accepts a peer connection.\r\n */\r\n PeerWelcome: 21,\r\n /**\r\n * Proxy → proxy: a {@link PeerHeader} (length-prefixed JSON), then the packet as a shard encoded it.\r\n */\r\n PeerPacket: 22,\r\n} as const;\r\n\r\n/**\r\n * @internal\r\n */\r\nexport type FrameType = (typeof FrameType)[keyof typeof FrameType];\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface HelloFrame {\r\n token: string;\r\n name: string;\r\n capacity: number;\r\n available: number;\r\n running: number[];\r\n /**\r\n * Where other proxies reach this one, when it accepts peers.\r\n */\r\n peer: PeerAddress | null;\r\n}\r\n\r\n/**\r\n * Where a proxy accepts peer connections.\r\n */\r\nexport interface PeerAddress {\r\n host: string;\r\n port: number;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface WelcomeFrame {\r\n kill: number[];\r\n /**\r\n * The ID of the manager: shards of different managers are never routed to each other.\r\n */\r\n managerId: string;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface DirectoryFrame {\r\n entries: { channel: number; proxy: string; host: string; port: number }[];\r\n}\r\n\r\n/**\r\n * The routing header of a peer packet.\r\n *\r\n * @internal\r\n */\r\nexport interface PeerHeader {\r\n /**\r\n * The ID of the manager of both shards.\r\n */\r\n scope: string;\r\n /**\r\n * The channel of the shard the packet comes from.\r\n */\r\n origin: number;\r\n /**\r\n * The channel of the shard the packet goes to.\r\n */\r\n target: number;\r\n binary: boolean;\r\n /**\r\n * Sent back because the target is not here or not ready: the sender relays it through the manager instead.\r\n */\r\n bounce?: boolean;\r\n}\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface SpawnFrame {\r\n spawnId: number;\r\n context: unknown;\r\n env: Record<string, string>;\r\n}\r\n\r\n/**\r\n * The events of a {@link Connection}.\r\n *\r\n * @internal\r\n */\r\nexport interface ConnectionEvents {\r\n frame: [type: FrameType, payload: Buffer];\r\n close: [error?: Error];\r\n}\r\n\r\n/**\r\n * Carries length-prefixed frames over a socket, with heartbeats.\r\n *\r\n * @internal\r\n */\r\nexport class Connection extends EventEmitter<ConnectionEvents> {\r\n public readonly socket: Socket;\r\n #buffer: Buffer = Buffer.alloc(0);\r\n #closed = false;\r\n readonly #heartbeat: NodeJS.Timeout;\r\n readonly #watchdog: NodeJS.Timeout;\r\n\r\n public constructor(socket: Socket, heartbeat: { interval: number; timeout: number }) {\r\n super();\r\n this.socket = socket;\r\n socket.setNoDelay(true);\r\n socket.on(\"data\", (chunk: Buffer) => this.#read(chunk));\r\n socket.on(\"error\", (error) => this.close(error));\r\n socket.on(\"close\", () => this.close());\r\n\r\n this.#heartbeat = setInterval(\r\n () => void this.send(FrameType.Heartbeat).catch(() => undefined),\r\n heartbeat.interval,\r\n );\r\n this.#heartbeat.unref();\r\n this.#watchdog = setTimeout(\r\n () => this.close(new Error(`No heartbeat for ${heartbeat.timeout}ms`)),\r\n heartbeat.timeout,\r\n );\r\n this.#watchdog.unref();\r\n }\r\n\r\n public get closed(): boolean {\r\n return this.#closed;\r\n }\r\n\r\n public send(type: FrameType, payload: Uint8Array = Buffer.alloc(0)): Promise<void> {\r\n if (this.#closed) return Promise.reject(new Error(\"The connection is closed\"));\r\n\r\n const header = Buffer.allocUnsafe(5);\r\n header.writeUInt32BE(payload.length + 1, 0);\r\n header.writeUInt8(type, 4);\r\n return new Promise((resolve, reject) => {\r\n this.socket.write(Buffer.concat([header, payload]), (error) =>\r\n error ? reject(error) : resolve(),\r\n );\r\n });\r\n }\r\n\r\n public sendJson(type: FrameType, value: unknown): Promise<void> {\r\n return this.send(type, Buffer.from(JSON.stringify(value)));\r\n }\r\n\r\n public sendPeer(header: PeerHeader, data: string | Uint8Array): Promise<void> {\r\n const json = Buffer.from(JSON.stringify(header));\r\n const length = Buffer.allocUnsafe(4);\r\n length.writeUInt32BE(json.length, 0);\r\n const body = typeof data === \"string\" ? Buffer.from(data) : data;\r\n return this.send(FrameType.PeerPacket, Buffer.concat([length, json, body]));\r\n }\r\n\r\n public sendData(spawnId: number, data: unknown): Promise<void> {\r\n const prefix = Buffer.allocUnsafe(4);\r\n prefix.writeUInt32BE(spawnId, 0);\r\n if (typeof data === \"string\") {\r\n return this.send(FrameType.StringData, Buffer.concat([prefix, Buffer.from(data)]));\r\n }\r\n\r\n if (data instanceof Uint8Array) {\r\n return this.send(FrameType.BinaryData, Buffer.concat([prefix, data]));\r\n }\r\n\r\n return Promise.reject(\r\n new TypeError(\r\n \"Only string or binary data crosses the network: the raw message handler cannot\",\r\n ),\r\n );\r\n }\r\n\r\n public close(error?: Error): void {\r\n if (this.#closed) return;\r\n this.#closed = true;\r\n clearInterval(this.#heartbeat);\r\n clearTimeout(this.#watchdog);\r\n this.socket.destroy();\r\n this.emit(\"close\", error);\r\n }\r\n\r\n #read(chunk: Buffer): void {\r\n this.#watchdog.refresh();\r\n this.#buffer = this.#buffer.length === 0 ? chunk : Buffer.concat([this.#buffer, chunk]);\r\n while (this.#buffer.length >= 4) {\r\n const length = this.#buffer.readUInt32BE(0);\r\n if (this.#buffer.length < 4 + length) return;\r\n\r\n const type = this.#buffer.readUInt8(4) as FrameType;\r\n const payload = this.#buffer.subarray(5, 4 + length);\r\n this.#buffer = this.#buffer.subarray(4 + length);\r\n if (type !== FrameType.Heartbeat) this.emit(\"frame\", type, payload);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Reads the spawn ID and the data of a data frame.\r\n *\r\n * @internal\r\n */\r\nexport function readData(\r\n type: FrameType,\r\n payload: Buffer,\r\n): { spawnId: number; data: string | Uint8Array } {\r\n const spawnId = payload.readUInt32BE(0);\r\n const body = payload.subarray(4);\r\n return {\r\n spawnId,\r\n data: type === FrameType.StringData ? body.toString() : new Uint8Array(body),\r\n };\r\n}\r\n\r\n/**\r\n * Reads the header and the data of a peer packet.\r\n *\r\n * @internal\r\n */\r\nexport function readPeer(payload: Buffer): { header: PeerHeader; data: string | Uint8Array } {\r\n const length = payload.readUInt32BE(0);\r\n const header = JSON.parse(payload.subarray(4, 4 + length).toString()) as PeerHeader;\r\n const body = payload.subarray(4 + length);\r\n return { header, data: header.binary ? new Uint8Array(body) : body.toString() };\r\n}\r\n\r\n/**\r\n * Compares two tokens in constant time.\r\n *\r\n * @internal\r\n */\r\nexport function tokensMatch(expected: string, actual: unknown): boolean {\r\n if (typeof actual !== \"string\") return false;\r\n // Hashing gives both the same length, which timingSafeEqual needs.\r\n return timingSafeEqual(sha256(expected), sha256(actual));\r\n}\r\n\r\nfunction sha256(value: string): Buffer {\r\n return createHash(\"sha256\").update(value).digest();\r\n}\r\n","import { randomUUID } from \"node:crypto\";\r\nimport { createServer as createNetServer, type Server, type Socket } from \"node:net\";\r\nimport { createServer as createTlsServer, type TlsOptions } from \"node:tls\";\r\nimport {\r\n Connection,\r\n FrameType,\r\n readData,\r\n tokensMatch,\r\n type DirectoryFrame,\r\n type HelloFrame,\r\n type PeerAddress,\r\n type SpawnFrame,\r\n type WelcomeFrame,\r\n} from \"../network/Connection.js\";\r\nimport type {\r\n ChannelStrategy,\r\n ShardContext,\r\n ShardTransport,\r\n ShardTransportEvents,\r\n SpawnOptions,\r\n} from \"./ChannelStrategy.js\";\r\n\r\n/**\r\n * The options of {@link NetworkStrategy}.\r\n */\r\nexport interface NetworkStrategyOptions {\r\n /**\r\n * The port to listen on for proxies.\r\n */\r\n port: number;\r\n host?: string;\r\n /**\r\n * The shared secret proxies authenticate with.\r\n */\r\n token: string;\r\n /**\r\n * The ID of the manager, which proxies serving several managers tell them apart by. Defaults to a random UUID.\r\n */\r\n id?: string;\r\n /**\r\n * The TLS options (`key`, `cert`, ...) to encrypt the connections, recommended. Left out, the connections are plain\r\n * TCP: only for trusted networks.\r\n */\r\n tls?: TlsOptions;\r\n /**\r\n * How long a proxy that lost its connection has to come back before its shards are deemed dead and spawned\r\n * elsewhere, in milliseconds.\r\n *\r\n * @default 30_000\r\n */\r\n reconnectGrace?: number;\r\n heartbeat?: {\r\n /**\r\n * @default 15_000\r\n */\r\n interval?: number;\r\n /**\r\n * @default 45_000\r\n */\r\n timeout?: number;\r\n };\r\n}\r\n\r\n/**\r\n * A proxy connected to a {@link NetworkStrategy}.\r\n */\r\nexport interface ProxyInfo {\r\n name: string;\r\n /**\r\n * The address the proxy connected from.\r\n */\r\n host: string | null;\r\n /**\r\n * How many shards it runs at most, across all its managers.\r\n */\r\n capacity: number;\r\n /**\r\n * How many more shards it takes, across all its managers.\r\n */\r\n available: number;\r\n /**\r\n * How many shards it runs for this manager.\r\n */\r\n load: number;\r\n /**\r\n * Where other proxies reach it, when it accepts peers.\r\n */\r\n peer: PeerAddress | null;\r\n}\r\n\r\ninterface Spawn {\r\n id: number;\r\n context: ShardContext;\r\n env: Record<string, string>;\r\n events: ShardTransportEvents;\r\n proxy: Proxy | null;\r\n pid: number | null;\r\n threadId: number | null;\r\n ready: boolean;\r\n exited: boolean;\r\n exit: Promise<void>;\r\n resolveExit(): void;\r\n grace: NodeJS.Timeout | null;\r\n}\r\n\r\ninterface Proxy {\r\n name: string;\r\n host: string | null;\r\n capacity: number;\r\n available: number;\r\n peer: PeerAddress | null;\r\n connection: Connection | null;\r\n spawns: Set<Spawn>;\r\n}\r\n\r\n/**\r\n * Spawns shards on other machines, through {@link ShardManagerProxy}s connecting to the manager: the sharder RFC's\r\n * network strategy.\r\n *\r\n * @remarks\r\n * Each spawn goes to the connected proxy with the most room, as the proxies report it across all the managers they\r\n * serve; without room, it waits for a proxy, or for the spawn timeout. A proxy losing its connection has\r\n * `reconnectGrace` to come back with its shards, after which they are spawned elsewhere; its stale shards are killed\r\n * when it comes back later. Proxies coming back are not rebalanced: they take the next spawns.\r\n *\r\n * The strategy keeps the proxies accepting peers informed of which proxy runs which ready shard, so they carry the\r\n * messages between their shards directly.\r\n */\r\nexport class NetworkStrategy implements ChannelStrategy {\r\n public readonly name = \"network\";\r\n public readonly options: NetworkStrategyOptions;\r\n\r\n /**\r\n * The ID of the manager, see {@link NetworkStrategyOptions.id}.\r\n */\r\n public readonly id: string;\r\n\r\n readonly #proxies = new Map<string, Proxy>();\r\n readonly #spawns = new Map<number, Spawn>();\r\n readonly #pending: Spawn[] = [];\r\n #server: Server | null = null;\r\n #nextSpawnId = 1;\r\n #directoryQueued = false;\r\n\r\n public constructor(options: NetworkStrategyOptions) {\r\n this.options = options;\r\n this.id = options.id ?? randomUUID();\r\n }\r\n\r\n /**\r\n * The proxies, connected or within their reconnect grace.\r\n */\r\n public get proxies(): ProxyInfo[] {\r\n return [...this.#proxies.values()].map((proxy) => ({\r\n name: proxy.name,\r\n host: proxy.host,\r\n capacity: proxy.capacity,\r\n available: proxy.available,\r\n load: proxy.spawns.size,\r\n peer: proxy.peer,\r\n }));\r\n }\r\n\r\n /**\r\n * The port the strategy listens on, once initialized.\r\n */\r\n public get port(): number | null {\r\n const address = this.#server?.address();\r\n return typeof address === \"object\" && address ? address.port : null;\r\n }\r\n\r\n /**\r\n * Drops the connection of a proxy, which reconnects: its shards are kept if it comes back within the grace.\r\n *\r\n * @param name The name of the proxy.\r\n * @returns Whether a proxy of that name was connected.\r\n */\r\n public disconnectProxy(name: string): boolean {\r\n const connection = this.#proxies.get(name)?.connection;\r\n connection?.close();\r\n return connection !== undefined && connection !== null;\r\n }\r\n\r\n public async init(): Promise<void> {\r\n if (this.#server) return;\r\n\r\n const onSocket = (socket: Socket) => this.#accept(socket);\r\n const server = this.options.tls\r\n ? createTlsServer(this.options.tls, onSocket)\r\n : createNetServer(onSocket);\r\n await new Promise<void>((resolve, reject) => {\r\n server.once(\"error\", reject);\r\n server.listen(this.options.port, this.options.host, () => {\r\n server.off(\"error\", reject);\r\n resolve();\r\n });\r\n });\r\n this.#server = server;\r\n }\r\n\r\n public async destroy(): Promise<void> {\r\n for (const proxy of this.#proxies.values()) proxy.connection?.close();\r\n this.#proxies.clear();\r\n const server = this.#server;\r\n this.#server = null;\r\n if (server) await new Promise<void>((resolve) => server.close(() => resolve()));\r\n }\r\n\r\n public spawn(\r\n context: ShardContext,\r\n events: ShardTransportEvents,\r\n options: SpawnOptions,\r\n ): ShardTransport {\r\n if (context.messageHandler === \"raw\") {\r\n throw new TypeError(\"The raw message handler cannot cross the network\");\r\n }\r\n\r\n let resolveExit!: () => void;\r\n const spawn: Spawn = {\r\n id: this.#nextSpawnId++,\r\n context,\r\n env: options.env,\r\n events,\r\n proxy: null,\r\n pid: null,\r\n threadId: null,\r\n ready: false,\r\n exited: false,\r\n exit: new Promise((resolve) => {\r\n resolveExit = resolve;\r\n }),\r\n resolveExit: () => resolveExit(),\r\n grace: null,\r\n };\r\n this.#spawns.set(spawn.id, spawn);\r\n this.#place(spawn);\r\n\r\n return {\r\n get pid() {\r\n return spawn.pid;\r\n },\r\n get threadId() {\r\n return spawn.threadId;\r\n },\r\n get host() {\r\n return spawn.proxy?.name ?? null;\r\n },\r\n send: async (data) => {\r\n const connection = spawn.proxy?.connection;\r\n if (!connection || connection.closed) throw new Error(\"The shard's proxy is not connected\");\r\n await connection.sendData(spawn.id, data);\r\n },\r\n kill: async () => {\r\n if (spawn.exited) return;\r\n const connection = spawn.proxy?.connection;\r\n if (connection && !connection.closed) {\r\n await connection.sendJson(FrameType.Kill, { spawnId: spawn.id }).catch(() => undefined);\r\n await Promise.race([\r\n spawn.exit,\r\n new Promise((resolve) => setTimeout(resolve, 10_000).unref()),\r\n ]);\r\n }\r\n\r\n this.#exit(spawn, null);\r\n },\r\n };\r\n }\r\n\r\n #place(spawn: Spawn): void {\r\n let best: Proxy | null = null;\r\n for (const proxy of this.#proxies.values()) {\r\n if (!proxy.connection || proxy.available <= 0) continue;\r\n if (!best || proxy.available / proxy.capacity > best.available / best.capacity) best = proxy;\r\n }\r\n\r\n if (!best) {\r\n this.#pending.push(spawn);\r\n return;\r\n }\r\n\r\n spawn.proxy = best;\r\n best.spawns.add(spawn);\r\n // Until the proxy reports its new load.\r\n best.available--;\r\n const frame: SpawnFrame = { spawnId: spawn.id, context: spawn.context, env: spawn.env };\r\n void best.connection!.sendJson(FrameType.Spawn, frame).catch(() => undefined);\r\n }\r\n\r\n #drain(): void {\r\n const pending = this.#pending.splice(0);\r\n for (const spawn of pending) {\r\n if (!spawn.exited) this.#place(spawn);\r\n }\r\n }\r\n\r\n #exit(spawn: Spawn, code: number | null): void {\r\n if (spawn.exited) return;\r\n spawn.exited = true;\r\n if (spawn.grace) clearTimeout(spawn.grace);\r\n const { proxy } = spawn;\r\n proxy?.spawns.delete(spawn);\r\n if (proxy && !proxy.connection && proxy.spawns.size === 0) this.#proxies.delete(proxy.name);\r\n this.#spawns.delete(spawn.id);\r\n const index = this.#pending.indexOf(spawn);\r\n if (index !== -1) this.#pending.splice(index, 1);\r\n spawn.resolveExit();\r\n spawn.events.exit(code);\r\n if (spawn.ready) this.#queueDirectory();\r\n this.#drain();\r\n }\r\n\r\n #accept(socket: Socket): void {\r\n const heartbeat = {\r\n interval: this.options.heartbeat?.interval ?? 15_000,\r\n timeout: this.options.heartbeat?.timeout ?? 45_000,\r\n };\r\n const connection = new Connection(socket, heartbeat);\r\n let proxy: Proxy | null = null;\r\n\r\n connection.on(\"frame\", (type, payload) => {\r\n if (!proxy) {\r\n proxy = this.#hello(connection, type, payload);\r\n return;\r\n }\r\n\r\n this.#frame(proxy, type, payload);\r\n });\r\n connection.on(\"close\", () => {\r\n if (proxy?.connection === connection) this.#lost(proxy);\r\n });\r\n }\r\n\r\n #hello(connection: Connection, type: FrameType, payload: Buffer): Proxy | null {\r\n let hello: HelloFrame;\r\n try {\r\n hello = JSON.parse(payload.toString()) as HelloFrame;\r\n } catch {\r\n connection.close();\r\n return null;\r\n }\r\n\r\n if (type !== FrameType.Hello || !tokensMatch(this.options.token, hello.token)) {\r\n void connection\r\n .sendJson(FrameType.Reject, { reason: \"Unauthorized\" })\r\n .finally(() => connection.close());\r\n return null;\r\n }\r\n\r\n const known = this.#proxies.get(hello.name);\r\n if (known?.connection && !known.connection.closed) {\r\n void connection\r\n .sendJson(FrameType.Reject, { reason: `A proxy named ${hello.name} is connected` })\r\n .finally(() => connection.close());\r\n return null;\r\n }\r\n\r\n const proxy: Proxy = known ?? {\r\n name: hello.name,\r\n host: null,\r\n capacity: hello.capacity,\r\n available: hello.available,\r\n peer: null,\r\n connection: null,\r\n spawns: new Set(),\r\n };\r\n proxy.connection = connection;\r\n proxy.capacity = hello.capacity;\r\n proxy.available = hello.available;\r\n proxy.peer = hello.peer;\r\n proxy.host = connection.socket.remoteAddress ?? null;\r\n this.#proxies.set(proxy.name, proxy);\r\n\r\n // Shards it still runs come back; the ones deemed dead meanwhile are killed.\r\n const running = new Set(hello.running);\r\n for (const spawn of proxy.spawns) {\r\n if (running.has(spawn.id)) {\r\n if (spawn.grace) clearTimeout(spawn.grace);\r\n spawn.grace = null;\r\n } else {\r\n this.#exit(spawn, null);\r\n }\r\n }\r\n\r\n const welcome: WelcomeFrame = {\r\n kill: hello.running.filter((spawnId) => this.#spawns.get(spawnId)?.proxy !== proxy),\r\n managerId: this.id,\r\n };\r\n void connection.sendJson(FrameType.Welcome, welcome).catch(() => undefined);\r\n this.#queueDirectory();\r\n this.#drain();\r\n return proxy;\r\n }\r\n\r\n #frame(proxy: Proxy, type: FrameType, payload: Buffer): void {\r\n if (type === FrameType.StringData || type === FrameType.BinaryData) {\r\n const { spawnId, data } = readData(type, payload);\r\n const spawn = this.#spawns.get(spawnId);\r\n if (spawn?.proxy === proxy) spawn.events.message(data);\r\n return;\r\n }\r\n\r\n const body = JSON.parse(payload.toString()) as {\r\n spawnId: number;\r\n available?: number;\r\n ready?: boolean;\r\n code?: number | null;\r\n message?: string;\r\n pid?: number | null;\r\n threadId?: number | null;\r\n };\r\n if (type === FrameType.Load) {\r\n proxy.available = body.available ?? proxy.available;\r\n this.#drain();\r\n return;\r\n }\r\n\r\n const spawn = this.#spawns.get(body.spawnId);\r\n if (spawn?.proxy !== proxy) return;\r\n\r\n switch (type) {\r\n case FrameType.Spawned:\r\n spawn.pid = body.pid ?? null;\r\n spawn.threadId = body.threadId ?? null;\r\n break;\r\n case FrameType.Status:\r\n spawn.ready = body.ready ?? false;\r\n this.#queueDirectory();\r\n break;\r\n case FrameType.Exit:\r\n this.#exit(spawn, body.code ?? null);\r\n break;\r\n case FrameType.Error:\r\n spawn.events.error(new Error(body.message));\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n #lost(proxy: Proxy): void {\r\n proxy.connection = null;\r\n const grace = this.options.reconnectGrace ?? 30_000;\r\n for (const spawn of proxy.spawns) {\r\n spawn.grace = setTimeout(() => this.#exit(spawn, null), grace);\r\n spawn.grace.unref();\r\n }\r\n\r\n if (proxy.spawns.size === 0) this.#proxies.delete(proxy.name);\r\n this.#queueDirectory();\r\n }\r\n\r\n // Coalesces the changes of a tick into one directory for every proxy.\r\n #queueDirectory(): void {\r\n if (this.#directoryQueued) return;\r\n this.#directoryQueued = true;\r\n queueMicrotask(() => {\r\n this.#directoryQueued = false;\r\n this.#sendDirectory();\r\n });\r\n }\r\n\r\n #sendDirectory(): void {\r\n // The latest ready spawn of each channel, on a connected proxy accepting peers.\r\n const byChannel = new Map<number, Spawn>();\r\n for (const spawn of this.#spawns.values()) {\r\n if (!spawn.ready || !spawn.proxy?.connection || !spawn.proxy.peer) continue;\r\n const current = byChannel.get(spawn.context.id);\r\n if (!current || current.id < spawn.id) byChannel.set(spawn.context.id, spawn);\r\n }\r\n\r\n const directory: DirectoryFrame = {\r\n entries: [...byChannel.values()].map((spawn) => ({\r\n channel: spawn.context.id,\r\n proxy: spawn.proxy!.name,\r\n host: spawn.proxy!.peer!.host,\r\n port: spawn.proxy!.peer!.port,\r\n })),\r\n };\r\n for (const proxy of this.#proxies.values()) {\r\n if (proxy.connection?.closed === false && proxy.peer) {\r\n void proxy.connection.sendJson(FrameType.Directory, directory).catch(() => undefined);\r\n }\r\n }\r\n }\r\n}\r\n","import { Worker, type WorkerOptions } from \"node:worker_threads\";\r\nimport {\r\n ShardContextVariable,\r\n encodeContext,\r\n type ChannelStrategy,\r\n type ShardContext,\r\n type ShardTransport,\r\n type ShardTransportEvents,\r\n type SpawnOptions,\r\n} from \"./ChannelStrategy.js\";\r\n\r\n/**\r\n * The options of {@link WorkerStrategy}.\r\n */\r\nexport interface WorkerStrategyOptions {\r\n /**\r\n * The script every shard runs.\r\n */\r\n path: string | URL;\r\n /**\r\n * Extra options of the `Worker`, e.g. its `resourceLimits`. `workerData` is reserved for the shard's context.\r\n */\r\n worker?: Omit<WorkerOptions, \"workerData\">;\r\n}\r\n\r\n/**\r\n * Spawns every shard as a worker thread of the manager's process. Messages are the fastest, but the shards share the\r\n * process: a crash of the process stops them all.\r\n */\r\nexport class WorkerStrategy implements ChannelStrategy {\r\n public readonly name = \"worker\";\r\n public readonly options: WorkerStrategyOptions;\r\n\r\n public constructor(options: WorkerStrategyOptions) {\r\n this.options = options;\r\n }\r\n\r\n public spawn(\r\n context: ShardContext,\r\n events: ShardTransportEvents,\r\n options: SpawnOptions,\r\n ): ShardTransport {\r\n const worker = new Worker(this.options.path, {\r\n name: `shard ${context.id}`,\r\n ...this.options.worker,\r\n env: { ...process.env, ...options.env },\r\n workerData: {\r\n [ShardContextVariable]: encodeContext({ ...context, transport: \"worker\" }),\r\n },\r\n });\r\n\r\n worker.on(\"message\", (data: unknown) => events.message(data));\r\n worker.on(\"error\", (error) => events.error(error));\r\n const exit = new Promise<void>((resolve) => {\r\n worker.once(\"exit\", (code) => {\r\n events.exit(code);\r\n resolve();\r\n });\r\n });\r\n\r\n return {\r\n pid: process.pid,\r\n threadId: worker.threadId,\r\n send: async (data) => {\r\n // oxlint-disable-next-line unicorn/require-post-message-target-origin -- a worker thread, not a window\r\n worker.postMessage(data);\r\n },\r\n kill: async () => {\r\n await worker.terminate();\r\n await exit;\r\n },\r\n };\r\n }\r\n}\r\n","import type { ChannelStrategy } from \"./ChannelStrategy.js\";\r\nimport { ClusterStrategy, type ClusterStrategyOptions } from \"./ClusterStrategy.js\";\r\nimport { ForkStrategy, type ForkStrategyOptions } from \"./ForkStrategy.js\";\r\nimport { NetworkStrategy, type NetworkStrategyOptions } from \"./NetworkStrategy.js\";\r\nimport { WorkerStrategy, type WorkerStrategyOptions } from \"./WorkerStrategy.js\";\r\n\r\nconst strategies = new Map<string, (options: any) => ChannelStrategy>([\r\n [\"fork\", (options: ForkStrategyOptions) => new ForkStrategy(options)],\r\n [\"cluster\", (options: ClusterStrategyOptions) => new ClusterStrategy(options)],\r\n [\"worker\", (options: WorkerStrategyOptions) => new WorkerStrategy(options)],\r\n [\"network\", (options: NetworkStrategyOptions) => new NetworkStrategy(options)],\r\n]);\r\n\r\n/**\r\n * Registers a strategy under a name, so managers and proxies can be given its name, like the built-in `\"fork\"`,\r\n * `\"cluster\"`, `\"worker\"`, and `\"network\"`.\r\n *\r\n * @param name The name of the strategy.\r\n * @param factory Builds the strategy from the `strategyOptions`.\r\n */\r\nexport function registerStrategy<Options>(\r\n name: string,\r\n factory: (options: Options) => ChannelStrategy,\r\n): void {\r\n strategies.set(name, factory);\r\n}\r\n\r\n/**\r\n * Resolves a strategy, or the name of a registered one.\r\n *\r\n * @param strategy The strategy, or its name.\r\n * @param options The options of a named strategy.\r\n */\r\nexport function resolveStrategy(\r\n strategy: ChannelStrategy | string,\r\n options?: unknown,\r\n): ChannelStrategy {\r\n if (typeof strategy !== \"string\") return strategy;\r\n\r\n const factory = strategies.get(strategy);\r\n if (!factory) throw new RangeError(`There is no strategy named \"${strategy}\"`);\r\n return factory(options ?? {});\r\n}\r\n","/**\r\n * The `GET /gateway/bot` payload, the same shape as discord-api-types' `APIGatewayBotInfo`, which `@discordjs/ws`'s\r\n * `WebSocketManager#fetchGatewayInformation` returns.\r\n */\r\nexport interface GatewayInformation {\r\n url: string;\r\n shards: number;\r\n session_start_limit: {\r\n total: number;\r\n remaining: number;\r\n /**\r\n * In milliseconds.\r\n */\r\n reset_after: number;\r\n max_concurrency: number;\r\n };\r\n}\r\n\r\n/**\r\n * The options of {@link fetchRecommendedShardCount}.\r\n */\r\nexport interface RecommendedShardCountOptions {\r\n /**\r\n * How many guilds a gateway shard should hold. Discord's recommendation is based on 1000.\r\n *\r\n * @default 1000\r\n */\r\n guildsPerShard?: number;\r\n /**\r\n * Rounds the count up to a multiple of it, e.g. 16 for large bot sharding.\r\n *\r\n * @default 1\r\n */\r\n multipleOf?: number;\r\n}\r\n\r\n/**\r\n * Fetches `GET /gateway/bot`.\r\n *\r\n * @param token The bot token.\r\n */\r\nexport async function fetchGatewayInformation(token: string): Promise<GatewayInformation> {\r\n const response = await fetch(\"https://discord.com/api/v10/gateway/bot\", {\r\n headers: { Authorization: `Bot ${token.replace(/^Bot\\s*/i, \"\")}` },\r\n });\r\n if (!response.ok) {\r\n throw new Error(\r\n `Could not fetch the gateway information: ${response.status} ${response.statusText}`,\r\n );\r\n }\r\n\r\n return (await response.json()) as GatewayInformation;\r\n}\r\n\r\n/**\r\n * Turns Discord's recommended shard count into the one to spawn.\r\n *\r\n * @param recommended The `shards` of `GET /gateway/bot`.\r\n * @param options How many guilds per gateway shard, and what to round the count up to.\r\n */\r\nexport function resolveRecommendedShardCount(\r\n recommended: number,\r\n options: RecommendedShardCountOptions = {},\r\n): number {\r\n const { guildsPerShard = 1000, multipleOf = 1 } = options;\r\n return Math.ceil((recommended * (1000 / guildsPerShard)) / multipleOf) * multipleOf;\r\n}\r\n\r\n/**\r\n * Fetches how many gateway shards Discord recommends for the bot, like discord.js's `fetchRecommendedShardCount`.\r\n *\r\n * @param token The bot token.\r\n * @param options How many guilds per gateway shard, and what to round the count up to.\r\n */\r\nexport async function fetchRecommendedShardCount(\r\n token: string,\r\n options?: RecommendedShardCountOptions,\r\n): Promise<number> {\r\n const { shards } = await fetchGatewayInformation(token);\r\n return resolveRecommendedShardCount(shards, options);\r\n}\r\n\r\n/**\r\n * Gets the gateway shard receiving the events of a guild.\r\n *\r\n * @param guildId The ID of the guild.\r\n * @param shardCount The total number of gateway shards.\r\n */\r\nexport function shardIdForGuild(guildId: string, shardCount: number): number {\r\n return Number((BigInt(guildId) >> 22n) % BigInt(shardCount));\r\n}\r\n\r\n/**\r\n * Caches `GET /gateway/bot`, so the shards share one request instead of each sending theirs, and keeps its session\r\n * start limit up to date with the identifies it grants.\r\n *\r\n * @internal\r\n */\r\nexport class GatewayInformationCache {\r\n readonly #fetch: () => Promise<GatewayInformation>;\r\n readonly #ttl: number;\r\n #value: GatewayInformation | null = null;\r\n #fetchedAt = 0;\r\n #resetAt = 0;\r\n #pending: Promise<GatewayInformation> | null = null;\r\n\r\n public constructor(fetcher: () => Promise<GatewayInformation>, ttl: number) {\r\n this.#fetch = fetcher;\r\n this.#ttl = ttl;\r\n }\r\n\r\n public async get(force = false): Promise<GatewayInformation> {\r\n const now = Date.now();\r\n if (!force && this.#value && now - this.#fetchedAt < this.#ttl) return this.#current(now);\r\n\r\n this.#pending ??= this.#fetch()\r\n .then((value) => {\r\n this.#value = structuredClone(value);\r\n this.#fetchedAt = Date.now();\r\n this.#resetAt = this.#fetchedAt + value.session_start_limit.reset_after;\r\n return value;\r\n })\r\n .finally(() => {\r\n this.#pending = null;\r\n });\r\n await this.#pending;\r\n return this.#current(Date.now());\r\n }\r\n\r\n /**\r\n * Counts an identify against the session start limit.\r\n */\r\n public consume(): void {\r\n if (!this.#value) return;\r\n this.#current(Date.now());\r\n this.#value.session_start_limit.remaining = Math.max(\r\n this.#value.session_start_limit.remaining - 1,\r\n 0,\r\n );\r\n }\r\n\r\n #current(now: number): GatewayInformation {\r\n const value = this.#value!;\r\n const limit = value.session_start_limit;\r\n if (now >= this.#resetAt) {\r\n // The limit reset since the last fetch: Discord resets it every 24 hours.\r\n limit.remaining = limit.total;\r\n this.#resetAt = now + 86_400_000;\r\n }\r\n\r\n limit.reset_after = Math.max(this.#resetAt - now, 0);\r\n return structuredClone(value);\r\n }\r\n}\r\n","import { setTimeout as sleep } from \"node:timers/promises\";\r\n\r\n/**\r\n * Hands out the turns of gateway shards to identify, across every process: Discord allows one identify per\r\n * `max_concurrency` bucket (`shardId % max_concurrency`) every 5 seconds.\r\n *\r\n * @internal\r\n */\r\nexport class IdentifyQueue {\r\n readonly #delay: number;\r\n readonly #buckets = new Map<number, Promise<void>>();\r\n #concurrency: number;\r\n\r\n public constructor(concurrency: number, delay: number) {\r\n this.#concurrency = concurrency;\r\n this.#delay = delay;\r\n }\r\n\r\n public set concurrency(value: number) {\r\n this.#concurrency = Math.max(1, value);\r\n }\r\n\r\n public get concurrency(): number {\r\n return this.#concurrency;\r\n }\r\n\r\n /**\r\n * Resolves once the gateway shard may identify. Aborting it drops it from the queue.\r\n *\r\n * @param shardId The ID of the gateway shard.\r\n * @param signal Aborts the wait.\r\n */\r\n public wait(shardId: number, signal?: AbortSignal): Promise<void> {\r\n const bucket = shardId % this.#concurrency;\r\n const previous = this.#buckets.get(bucket) ?? Promise.resolve();\r\n\r\n let release!: () => void;\r\n const released = new Promise<void>((resolve) => {\r\n release = resolve;\r\n });\r\n // The next shard of the bucket waits for this turn to be over, granted or dropped, plus the delay if granted.\r\n this.#buckets.set(\r\n bucket,\r\n previous.then(() => released),\r\n );\r\n\r\n return new Promise((resolve, reject) => {\r\n const onAbort = () => {\r\n release();\r\n reject(signal!.reason);\r\n };\r\n signal?.addEventListener(\"abort\", onAbort, { once: true });\r\n\r\n void previous.then(() => {\r\n signal?.removeEventListener(\"abort\", onAbort);\r\n if (signal?.aborted) return;\r\n resolve();\r\n void sleep(this.#delay, undefined, { ref: false }).then(release);\r\n });\r\n });\r\n }\r\n}\r\n","/**\r\n * What else restarts when a shard crashes, after Erlang/OTP's supervisor strategies.\r\n *\r\n * - `one-for-one`: only the crashed shard.\r\n * - `one-for-all`: every shard.\r\n * - `rest-for-one`: the crashed shard, and every shard after it.\r\n */\r\nexport type SupervisorStrategy = \"one-for-one\" | \"one-for-all\" | \"rest-for-one\";\r\n\r\n/**\r\n * How a manager restarts crashing shards, after Erlang/OTP's supervisors: a shard crashing more than `intensity`\r\n * times within `period` is given up on.\r\n */\r\nexport interface SupervisorOptions {\r\n /**\r\n * How many crashes are tolerated, `-1` or `Infinity` for no limit.\r\n *\r\n * @default -1\r\n */\r\n intensity?: number;\r\n /**\r\n * The window the crashes are counted in, in milliseconds. `0` counts the crashes in a row instead, until the shard\r\n * is ready again.\r\n *\r\n * @default 0\r\n */\r\n period?: number;\r\n /**\r\n * @default \"one-for-one\"\r\n */\r\n strategy?: SupervisorStrategy;\r\n}\r\n\r\n/**\r\n * Counts the crashes of each shard against the supervisor's intensity.\r\n *\r\n * @internal\r\n */\r\nexport class Supervisor {\r\n public readonly intensity: number;\r\n public readonly period: number;\r\n public readonly strategy: SupervisorStrategy;\r\n readonly #crashes = new Map<number, number[]>();\r\n\r\n public constructor(options: SupervisorOptions = {}) {\r\n const { intensity = -1, period = 0, strategy = \"one-for-one\" } = options;\r\n if (intensity !== -1 && intensity !== Number.POSITIVE_INFINITY) {\r\n if (!Number.isSafeInteger(intensity) || intensity < 0) {\r\n throw new RangeError(\r\n \"supervisor.intensity must be a non-negative integer, -1, or Infinity\",\r\n );\r\n }\r\n }\r\n\r\n this.intensity = intensity === Number.POSITIVE_INFINITY ? -1 : intensity;\r\n this.period = period;\r\n this.strategy = strategy;\r\n }\r\n\r\n /**\r\n * Counts a crash. Returns how many crashes count, and whether the shard may be restarted.\r\n *\r\n * @param channelId The ID of the crashed shard.\r\n */\r\n public crash(channelId: number): { crashes: number; restart: boolean } {\r\n const now = Date.now();\r\n const crashes = (this.#crashes.get(channelId) ?? []).filter(\r\n (timestamp) => this.period === 0 || now - timestamp < this.period,\r\n );\r\n crashes.push(now);\r\n this.#crashes.set(channelId, crashes);\r\n return {\r\n crashes: crashes.length,\r\n restart: this.intensity === -1 || crashes.length <= this.intensity,\r\n };\r\n }\r\n\r\n /**\r\n * Forgets the crashes of a shard that is ready again, when they are counted in a row.\r\n *\r\n * @param channelId The ID of the shard.\r\n */\r\n public ready(channelId: number): void {\r\n if (this.period === 0) this.#crashes.delete(channelId);\r\n }\r\n}\r\n","import type { Result } from \"@sapphire/result\";\r\nimport { EventEmitter } from \"node:events\";\r\nimport { availableParallelism } from \"node:os\";\r\nimport { setTimeout as sleep } from \"node:timers/promises\";\r\nimport { ShardChannel, type ShardRestartOptions } from \"./ShardChannel.js\";\r\nimport type { ShardPingOptions } from \"./ShardPing.js\";\r\nimport { resolveMessageHandler, type MessageHandler } from \"./messages/MessageHandler.js\";\r\nimport {\r\n resolveMessageTransformer,\r\n type MessageTransformer,\r\n} from \"./messages/MessageTransformer.js\";\r\nimport {\r\n PacketCodec,\r\n type ControlRequest,\r\n type ShardStatus,\r\n type ShardTarget,\r\n type SystemCall,\r\n} from \"./messages/protocol.js\";\r\nimport type { ChannelStrategy } from \"./strategies/ChannelStrategy.js\";\r\nimport { resolveStrategy } from \"./strategies/registry.js\";\r\nimport { ShardUnavailableError, type ShardError } from \"./util/errors.js\";\r\nimport {\r\n GatewayInformationCache,\r\n fetchGatewayInformation,\r\n resolveRecommendedShardCount,\r\n shardIdForGuild,\r\n type GatewayInformation,\r\n type RecommendedShardCountOptions,\r\n} from \"./util/gateway.js\";\r\nimport { IdentifyQueue } from \"./util/IdentifyQueue.js\";\r\nimport {\r\n serializeSettled,\r\n settledToResults,\r\n toResult,\r\n type BroadcastRequestOptions,\r\n type RequestHandler,\r\n type RequestOptions,\r\n} from \"./util/requests.js\";\r\nimport { Supervisor, type SupervisorOptions } from \"./util/Supervisor.js\";\r\n\r\n/**\r\n * How the gateway shards are laid out across shards.\r\n */\r\nexport interface ShardLayoutOptions {\r\n /**\r\n * The layout: a number spawns one shard per gateway shard, an array spawns one shard per entry connecting that\r\n * many gateway shards, and `\"auto\"` splits the gateway shards across `clusters` shards.\r\n *\r\n * @default \"auto\"\r\n * @example\r\n * ```ts\r\n * // 9 shards, connecting one gateway shard each.\r\n * new ShardManager({ shards: 9 });\r\n * // 3 shards, connecting 3 gateway shards each: 0-2, 3-5 and 6-8.\r\n * new ShardManager({ shards: [3, 3, 3] });\r\n * // Discord's recommended count, split across 4 shards.\r\n * new ShardManager({ shards: \"auto\", clusters: 4 });\r\n * ```\r\n */\r\n shards?: number | readonly number[] | \"auto\";\r\n /**\r\n * The total number of gateway shards, across every manager: `\"auto\"` is Discord's recommendation. Defaults to the\r\n * number of gateway shards of this manager.\r\n */\r\n totalShards?: number | \"auto\";\r\n /**\r\n * The gateway shards this manager spawns, when several managers split them. Defaults to all of them.\r\n */\r\n shardList?: readonly number[];\r\n /**\r\n * How many shards to split the gateway shards across, with `shards: \"auto\"`.\r\n *\r\n * @default os.availableParallelism()\r\n */\r\n clusters?: number;\r\n /**\r\n * How Discord's recommended count is turned into the total, with `\"auto\"`.\r\n */\r\n recommended?: RecommendedShardCountOptions;\r\n}\r\n\r\n/**\r\n * The options of a {@link ShardManager}.\r\n */\r\nexport interface ShardManagerOptions extends ShardLayoutOptions {\r\n /**\r\n * How to spawn the shards: a {@link ChannelStrategy}, or the name of a registered one (`\"fork\"`, `\"cluster\"`,\r\n * `\"worker\"`, `\"network\"`), built with `strategyOptions`.\r\n *\r\n * @default \"fork\"\r\n */\r\n strategy?: ChannelStrategy | string;\r\n /**\r\n * The options of a strategy given by name.\r\n */\r\n strategyOptions?: unknown;\r\n /**\r\n * The bot token: used for `\"auto\"` layouts and `GET /gateway/bot`, and passed to the shards as `DISCORD_TOKEN`.\r\n *\r\n * @default process.env.DISCORD_TOKEN\r\n */\r\n token?: string;\r\n /**\r\n * How `GET /gateway/bot` is fetched and cached. The shards get it from the manager, so it is fetched once for all.\r\n */\r\n gatewayInformation?: {\r\n /**\r\n * Fetches it, instead of requesting Discord with the token.\r\n */\r\n fetch?: () => Promise<GatewayInformation>;\r\n /**\r\n * How long to reuse it, in milliseconds; the session start limit is kept up to date meanwhile.\r\n *\r\n * @default 86_400_000\r\n */\r\n ttl?: number;\r\n };\r\n /**\r\n * How the identifies of the gateway shards are paced, across every shard. See {@link ShardClient.identifyThrottler}.\r\n */\r\n identify?: {\r\n /**\r\n * How many gateway shards may identify at once: `\"auto\"` is the `max_concurrency` of `GET /gateway/bot`, or `1`\r\n * without a token.\r\n *\r\n * @default \"auto\"\r\n */\r\n concurrency?: number | \"auto\";\r\n /**\r\n * How long a concurrency bucket waits between identifies, in milliseconds.\r\n *\r\n * @default 5_000\r\n */\r\n delay?: number;\r\n };\r\n /**\r\n * How crashing shards are restarted.\r\n */\r\n supervisor?: SupervisorOptions;\r\n spawn?: {\r\n /**\r\n * How long to wait after a shard is ready before spawning the next one, in milliseconds. With\r\n * {@link ShardClient.identifyThrottler} pacing the identifies, it can be `0`.\r\n *\r\n * @default 5_000\r\n */\r\n delay?: number;\r\n /**\r\n * How long a shard has to signal that it is ready, in milliseconds. Past it, it is killed and spawned again at\r\n * the end of the queue.\r\n *\r\n * @default 30_000\r\n */\r\n timeout?: number;\r\n /**\r\n * How long a shard is expected to take to be ready, in milliseconds. Defaults to the average of the shards\r\n * spawned so far. A shard slower than the estimate (plus the margin) is emitted as `shardSlowStart`, and a request\r\n * for a starting shard that is not expected to be ready before its timeout is rejected right away.\r\n */\r\n readyHint?: number;\r\n /**\r\n * The margin of error of the estimate, as a fraction of it.\r\n *\r\n * @default 0.1\r\n */\r\n readyHintMargin?: number;\r\n };\r\n ping?: ShardPingOptions;\r\n /**\r\n * How long requests wait for their reply by default, in milliseconds.\r\n *\r\n * @default ping.timeout\r\n */\r\n requestTimeout?: number;\r\n /**\r\n * How messages are serialized: a handler, or the name of a registered one. The shards build the same one.\r\n *\r\n * @default \"json\"\r\n */\r\n messageHandler?: MessageHandler | string;\r\n /**\r\n * How serialized messages are transformed (compressed, encrypted, ...), in order: transformers, or names of\r\n * registered ones. The shards build the same ones.\r\n *\r\n * @default []\r\n */\r\n transformers?: readonly (MessageTransformer | string)[];\r\n}\r\n\r\n/**\r\n * The events of a {@link ShardManager}.\r\n */\r\nexport interface ShardManagerEvents {\r\n /**\r\n * A shard was spawned.\r\n */\r\n shardCreate: [channel: ShardChannel];\r\n /**\r\n * A shard signalled a new status, or stopped (`Idle`).\r\n */\r\n shardStatus: [channel: ShardChannel, status: ShardStatus];\r\n shardReady: [channel: ShardChannel];\r\n shardDisconnect: [channel: ShardChannel];\r\n shardReconnecting: [channel: ShardChannel];\r\n /**\r\n * A shard answered a ping; `latency` is the round trip, in milliseconds.\r\n */\r\n shardPing: [channel: ShardChannel, latency: number];\r\n /**\r\n * A ready shard did not answer the pings in time. Without listeners, it is restarted.\r\n */\r\n shardUnresponsive: [channel: ShardChannel];\r\n /**\r\n * A shard takes longer than the estimate (plus its margin) to be ready.\r\n */\r\n shardSlowStart: [channel: ShardChannel, elapsed: number, estimate: number];\r\n /**\r\n * A shard is about to be spawned again: it asked for it, crashed, or was restarted.\r\n */\r\n shardRestart: [channel: ShardChannel];\r\n /**\r\n * A shard's process or thread stopped.\r\n */\r\n shardExit: [channel: ShardChannel, code: number | null];\r\n /**\r\n * A shard was closed by its manager.\r\n */\r\n shardDestroy: [channel: ShardChannel];\r\n /**\r\n * A shard failed: it exited before it was ready (a {@link ShardSpawnError}), or its strategy reported an error.\r\n * Without listeners, it goes to `error`.\r\n */\r\n shardError: [channel: ShardChannel, error: unknown];\r\n /**\r\n * A shard crashed more often than the supervisor tolerates, and is not restarted anymore. Without listeners, it\r\n * goes to `error`.\r\n */\r\n shardGiveUp: [channel: ShardChannel, crashes: number];\r\n /**\r\n * A shard sent data that could not be read. Without listeners, it is logged with `console.error`.\r\n */\r\n shardInvalidMessage: [channel: ShardChannel, error: unknown];\r\n /**\r\n * A shard sent a message to the manager.\r\n */\r\n message: [body: any, channel: ShardChannel];\r\n /**\r\n * Without listeners, errors are logged with `console.error`.\r\n */\r\n error: [error: unknown];\r\n}\r\n\r\n/**\r\n * Spawns shards, keeps them alive, and carries messages between them.\r\n *\r\n * @remarks\r\n * Follows discord.js's sharder RFC (discordjs/discord.js#8084): a \"shard\" is a process, cluster worker, worker\r\n * thread, or remote process, which may connect several gateway shards, and the manager talks to each through a\r\n * {@link ShardChannel}. The manager is agnostic of the bot: a shard runs any script using {@link ShardClient}.\r\n *\r\n * @example\r\n * ```ts\r\n * const manager = new ShardManager({ strategy: new ForkStrategy({ path: \"./bot.js\" }), clusters: 4 });\r\n * manager.setRequestHandler((body, { channel }) => ...);\r\n * await manager.spawn();\r\n * const guilds = await manager.broadcastRequest({ type: \"guildCount\" });\r\n * ```\r\n */\r\nexport class ShardManager extends EventEmitter<ShardManagerEvents> {\r\n public readonly strategy: ChannelStrategy;\r\n\r\n /**\r\n * The channels to the shards, by ID. Empty until {@link ShardManager.spawn} for `\"auto\"` layouts.\r\n */\r\n public channels: readonly ShardChannel[] = [];\r\n\r\n /**\r\n * The total number of gateway shards, `0` until resolved for `\"auto\"` layouts.\r\n */\r\n public shardCount = 0;\r\n\r\n public readonly spawnDelay: number;\r\n public readonly spawnTimeout: number;\r\n public readonly readyHint: number | null;\r\n public readonly readyHintMargin: number;\r\n public readonly requestTimeout: number;\r\n public readonly pingOptions: Required<ShardPingOptions>;\r\n\r\n /**\r\n * @internal\r\n */\r\n public readonly codec: PacketCodec;\r\n\r\n /**\r\n * @internal\r\n */\r\n public readonly supervisor: Supervisor;\r\n\r\n /**\r\n * @internal\r\n */\r\n public readonly spawnEnv: Record<string, string>;\r\n\r\n /**\r\n * @internal\r\n */\r\n public requestHandler: RequestHandler<{ channel: ShardChannel }> | null = null;\r\n\r\n readonly #layout: ShardLayoutOptions;\r\n readonly #token: string | null;\r\n readonly #gateway: GatewayInformationCache | null;\r\n readonly #identify: IdentifyQueue;\r\n readonly #identifyConcurrency: number | \"auto\";\r\n readonly #readyTimes: number[] = [];\r\n #queue: Promise<void> = Promise.resolve();\r\n #initialized = false;\r\n\r\n public constructor(options: ShardManagerOptions = {}) {\r\n super();\r\n this.strategy = resolveStrategy(options.strategy ?? \"fork\", options.strategyOptions);\r\n this.supervisor = new Supervisor(options.supervisor);\r\n this.spawnDelay = options.spawn?.delay ?? 5_000;\r\n this.spawnTimeout = options.spawn?.timeout ?? 30_000;\r\n this.readyHint = options.spawn?.readyHint ?? null;\r\n this.readyHintMargin = options.spawn?.readyHintMargin ?? 0.1;\r\n this.pingOptions = {\r\n interval: options.ping?.interval ?? 45_000,\r\n timeout: options.ping?.timeout ?? 60_000,\r\n delaySinceReceived: options.ping?.delaySinceReceived ?? false,\r\n };\r\n this.requestTimeout = options.requestTimeout ?? this.pingOptions.timeout;\r\n this.codec = new PacketCodec(\r\n resolveMessageHandler(options.messageHandler ?? \"json\"),\r\n (options.transformers ?? []).map(resolveMessageTransformer),\r\n );\r\n if (this.codec.handler.name === \"raw\" && this.codec.transformers.length > 0) {\r\n throw new TypeError(\"The raw message handler cannot be combined with transformers\");\r\n }\r\n\r\n this.#token = options.token ?? process.env.DISCORD_TOKEN ?? null;\r\n this.spawnEnv = options.token ? { DISCORD_TOKEN: options.token } : {};\r\n const fetcher =\r\n options.gatewayInformation?.fetch ??\r\n (this.#token ? () => fetchGatewayInformation(this.#token!) : null);\r\n this.#gateway = fetcher\r\n ? new GatewayInformationCache(fetcher, options.gatewayInformation?.ttl ?? 86_400_000)\r\n : null;\r\n this.#identifyConcurrency = options.identify?.concurrency ?? \"auto\";\r\n this.#identify = new IdentifyQueue(\r\n this.#identifyConcurrency === \"auto\" ? 1 : this.#identifyConcurrency,\r\n options.identify?.delay ?? 5_000,\r\n );\r\n\r\n this.#layout = {\r\n shards: options.shards,\r\n totalShards: options.totalShards,\r\n shardList: options.shardList,\r\n clusters: options.clusters,\r\n recommended: options.recommended,\r\n };\r\n if (!needsGateway(this.#layout)) this.#apply(resolveLayout(this.#layout, null));\r\n }\r\n\r\n /**\r\n * How long a shard is expected to take to be ready: `spawn.readyHint`, or the average of the shards so far.\r\n */\r\n public get readyEstimate(): number | null {\r\n if (this.readyHint !== null) return this.readyHint;\r\n if (this.#readyTimes.length === 0) return null;\r\n return this.#readyTimes.reduce((sum, time) => sum + time, 0) / this.#readyTimes.length;\r\n }\r\n\r\n /**\r\n * Spawns every shard, one after the other, each waiting for the previous one to be ready plus the spawn delay. A\r\n * shard not ready in time is killed and tried again at the end of the queue, as long as the supervisor allows.\r\n */\r\n public async spawn(): Promise<void> {\r\n if (this.channels.length === 0) {\r\n const info = needsGateway(this.#layout) ? await this.fetchGatewayInformation() : null;\r\n this.#apply(resolveLayout(this.#layout, info));\r\n }\r\n\r\n await this.#init();\r\n await Promise.all(this.channels.map((channel) => this.#startWithRetries(channel)));\r\n }\r\n\r\n /**\r\n * Fetches `GET /gateway/bot`, cached for every shard, with its session start limit kept up to date.\r\n *\r\n * @param force Whether to skip the cache.\r\n */\r\n public async fetchGatewayInformation(force = false): Promise<GatewayInformation> {\r\n if (!this.#gateway) {\r\n throw new Error(\r\n \"Fetching the gateway information needs a token, or gatewayInformation.fetch\",\r\n );\r\n }\r\n\r\n return this.#gateway.get(force);\r\n }\r\n\r\n /**\r\n * Gets the channel to the shard connecting a gateway shard.\r\n *\r\n * @param shardId The ID of the gateway shard.\r\n */\r\n public channelFor(shardId: number): ShardChannel | undefined {\r\n return this.channels.find((channel) => channel.shards.includes(shardId));\r\n }\r\n\r\n /**\r\n * Gets the channel to the shard receiving the events of a guild.\r\n *\r\n * @param guildId The ID of the guild.\r\n */\r\n public channelForGuild(guildId: string): ShardChannel | undefined {\r\n return this.channelFor(shardIdForGuild(guildId, this.shardCount));\r\n }\r\n\r\n /**\r\n * Sets the handler answering the requests the shards send to the manager.\r\n *\r\n * @param handler The handler; its return value is the reply.\r\n */\r\n public setRequestHandler(handler: RequestHandler<{ channel: ShardChannel }> | null): this {\r\n this.requestHandler = handler;\r\n return this;\r\n }\r\n\r\n /**\r\n * Sends a message to a shard, emitted as `message` by its {@link ShardClient}.\r\n *\r\n * @param channelId The ID of the shard.\r\n * @param body The message.\r\n * @param options How long to wait for the shard to be ready, and an abort signal.\r\n */\r\n public send(channelId: number, body: unknown, options?: RequestOptions): Promise<void> {\r\n return this.#channel(channelId).send(body, options);\r\n }\r\n\r\n /**\r\n * Sends a request to a shard, answered by its {@link ShardClient}'s request handler.\r\n *\r\n * @param channelId The ID of the shard.\r\n * @param body The request.\r\n * @param options The timeout and abort signal of the request.\r\n */\r\n public request<Reply = unknown>(\r\n channelId: number,\r\n body: unknown,\r\n options?: RequestOptions,\r\n ): Promise<Reply> {\r\n return this.#channel(channelId).request<Reply>(body, options);\r\n }\r\n\r\n /**\r\n * Sends a message to every shard.\r\n *\r\n * @param body The message.\r\n * @param options How long to wait for the shards to be ready, and an abort signal.\r\n */\r\n public async broadcast(body: unknown, options?: RequestOptions): Promise<void> {\r\n await Promise.all(this.channels.map((channel) => channel.send(body, options)));\r\n }\r\n\r\n /**\r\n * Sends a request to every shard, like discord.js's `broadcastEval` without the `eval`.\r\n *\r\n * @param body The request.\r\n * @param options The timeout and abort signal of every request, and whether to keep partial results.\r\n * @returns The replies by shard ID, or with `partial`, the outcome of every request.\r\n */\r\n public broadcastRequest<Reply = unknown>(\r\n body: unknown,\r\n options: BroadcastRequestOptions & { partial: true },\r\n ): Promise<PromiseSettledResult<Reply>[]>;\r\n public broadcastRequest<Reply = unknown>(\r\n body: unknown,\r\n options?: BroadcastRequestOptions,\r\n ): Promise<Reply[]>;\r\n public broadcastRequest(body: unknown, options: BroadcastRequestOptions = {}): Promise<unknown> {\r\n const requests = this.channels.map((channel) => channel.request(body, options));\r\n return options.partial ? Promise.allSettled(requests) : Promise.all(requests);\r\n }\r\n\r\n /**\r\n * {@link ShardManager.send}, resolving with a `Result` rather than rejecting.\r\n */\r\n public trySend(\r\n channelId: number,\r\n body: unknown,\r\n options?: RequestOptions,\r\n ): Promise<Result<void, ShardError>> {\r\n return toResult(() => this.send(channelId, body, options));\r\n }\r\n\r\n /**\r\n * {@link ShardManager.request}, resolving with a `Result` rather than rejecting.\r\n */\r\n public tryRequest<Reply = unknown>(\r\n channelId: number,\r\n body: unknown,\r\n options?: RequestOptions,\r\n ): Promise<Result<Reply, ShardError>> {\r\n return toResult(() => this.request<Reply>(channelId, body, options));\r\n }\r\n\r\n /**\r\n * {@link ShardManager.broadcastRequest}, resolving with one `Result` per shard, by shard ID.\r\n */\r\n public async tryBroadcastRequest<Reply = unknown>(\r\n body: unknown,\r\n options?: RequestOptions,\r\n ): Promise<Result<Reply, ShardError>[]> {\r\n return settledToResults(\r\n await this.broadcastRequest<Reply>(body, { ...options, partial: true }),\r\n );\r\n }\r\n\r\n /**\r\n * Restarts a shard: closes it then spawns it again, or with `rolling`, spawns the new one first and closes the old\r\n * one once the new one is ready.\r\n *\r\n * @param channelId The ID of the shard.\r\n * @param options Whether to restart it rolling, and the timeout.\r\n */\r\n public async restart(channelId: number, options: ShardRestartOptions = {}): Promise<void> {\r\n const channel = this.#channel(channelId);\r\n this.emit(\"shardRestart\", channel);\r\n if (options.rolling) {\r\n await this.#enqueue(() => channel.rollingRestart(options.timeout));\r\n return;\r\n }\r\n\r\n await channel.close(options.timeout);\r\n await this.#startWithRetries(channel, true);\r\n }\r\n\r\n /**\r\n * Restarts every shard, one after the other, with the spawn delay between them.\r\n *\r\n * @param options Whether to restart them rolling, and the timeout.\r\n */\r\n public async restartAll(options?: ShardRestartOptions): Promise<void> {\r\n for (const channel of this.channels) await this.restart(channel.id, options);\r\n }\r\n\r\n /**\r\n * Reshards with close to no downtime: spawns the shards of a new layout while the current ones keep running, then\r\n * closes the current ones once every new one is ready.\r\n *\r\n * @param layout The new layout. Left out, Discord's recommendation split across `clusters`.\r\n */\r\n public async reshard(layout: ShardLayoutOptions = { shards: \"auto\" }): Promise<void> {\r\n const info = needsGateway(layout) ? await this.fetchGatewayInformation(true) : null;\r\n const resolved = resolveLayout(layout, info);\r\n const channels = resolved.channels.map(\r\n (shards, id) => new ShardChannel(this, id, shards, resolved.shardCount),\r\n );\r\n\r\n try {\r\n await Promise.all(channels.map((channel) => this.#startWithRetries(channel)));\r\n } catch (error) {\r\n await Promise.all(channels.map((channel) => channel.close()));\r\n throw error;\r\n }\r\n\r\n const previous = this.channels;\r\n this.channels = channels;\r\n this.shardCount = resolved.shardCount;\r\n await Promise.all(previous.map((channel) => channel.close()));\r\n }\r\n\r\n /**\r\n * Asks the shard connecting a gateway shard to start it, through its {@link ShardClient.setShardHandler}.\r\n *\r\n * @param shardId The ID of the gateway shard.\r\n * @param options The timeout and abort signal of the request.\r\n */\r\n public startShard(shardId: number, options?: RequestOptions): Promise<void> {\r\n return this.#channelForShard(shardId).startShard(shardId, options);\r\n }\r\n\r\n /**\r\n * Asks the shard connecting a gateway shard to close it, through its {@link ShardClient.setShardHandler}.\r\n *\r\n * @param shardId The ID of the gateway shard.\r\n * @param options The timeout and abort signal of the request.\r\n */\r\n public closeShard(shardId: number, options?: RequestOptions): Promise<void> {\r\n return this.#channelForShard(shardId).closeShard(shardId, options);\r\n }\r\n\r\n /**\r\n * Closes then starts a gateway shard, see {@link ShardManager.startShard}.\r\n *\r\n * @param shardId The ID of the gateway shard.\r\n * @param options The timeout and abort signal of each request.\r\n */\r\n public async restartShard(shardId: number, options?: RequestOptions): Promise<void> {\r\n await this.closeShard(shardId, options);\r\n await this.startShard(shardId, options);\r\n }\r\n\r\n /**\r\n * Waits for a gateway shard's turn to identify, like {@link ShardClient.identifyThrottler} does from a shard.\r\n *\r\n * @param shardId The ID of the gateway shard.\r\n * @param signal Aborts the wait.\r\n */\r\n public async waitForIdentify(shardId: number, signal?: AbortSignal): Promise<void> {\r\n if (this.#identifyConcurrency === \"auto\" && this.#gateway) {\r\n const info = await this.fetchGatewayInformation();\r\n this.#identify.concurrency = info.session_start_limit.max_concurrency;\r\n }\r\n\r\n await this.#identify.wait(shardId, signal);\r\n this.#gateway?.consume();\r\n }\r\n\r\n /**\r\n * Closes every shard for good, and releases the strategy.\r\n */\r\n public async destroy(): Promise<void> {\r\n await Promise.all(this.channels.map((channel) => channel.close()));\r\n if (this.#initialized) await this.strategy.destroy?.();\r\n this.#initialized = false;\r\n }\r\n\r\n /**\r\n * Carries a message a shard sends to another shard, or to every shard.\r\n *\r\n * @internal\r\n */\r\n public async route(body: unknown, to: ShardTarget, from: number): Promise<void> {\r\n if (to === \"all\")\r\n await Promise.all(this.channels.map((channel) => channel.send(body, {}, from)));\r\n else await this.#channel(to).send(body, {}, from);\r\n }\r\n\r\n /**\r\n * Carries a request a shard sends to another shard, or to every shard.\r\n *\r\n * @internal\r\n */\r\n public async forward(\r\n body: unknown,\r\n to: ShardTarget,\r\n from: number,\r\n options: BroadcastRequestOptions,\r\n ): Promise<unknown> {\r\n // Answer a little before the sender gives up, so partial results still reach it.\r\n const timeout =\r\n options.timeout === undefined ? undefined : Math.max(Math.floor(options.timeout * 0.95), 1);\r\n const forwarded = { timeout, signal: options.signal };\r\n if (to !== \"all\") return this.#channel(to).request(body, forwarded, from);\r\n\r\n const requests = this.channels.map((channel) => channel.request(body, forwarded, from));\r\n return options.partial\r\n ? serializeSettled(await Promise.allSettled(requests))\r\n : Promise.all(requests);\r\n }\r\n\r\n /**\r\n * Answers the requests the sharder itself sends.\r\n *\r\n * @internal\r\n */\r\n public async handleSystem(\r\n call: SystemCall,\r\n body: unknown,\r\n channel: ShardChannel,\r\n signal: AbortSignal,\r\n ): Promise<unknown> {\r\n switch (call) {\r\n case \"identify\":\r\n await this.waitForIdentify(body as number, signal);\r\n return null;\r\n case \"gatewayInformation\":\r\n return this.fetchGatewayInformation();\r\n case \"control\":\r\n return this.#control(body as ControlRequest, channel);\r\n default:\r\n throw new Error(`Shards cannot send the ${call} system request`);\r\n }\r\n }\r\n\r\n /**\r\n * Decides what happens to a shard that stopped on its own.\r\n *\r\n * @internal\r\n */\r\n public supervise(channel: ShardChannel, previous: ShardStatus): void {\r\n if (previous === \"Exiting\") {\r\n channel.markStopped(\"it exited\");\r\n return;\r\n }\r\n\r\n if (previous !== \"Restarting\") {\r\n const { crashes, restart } = this.supervisor.crash(channel.id);\r\n if (!restart) {\r\n channel.markStopped(\"it crashed too often\");\r\n if (this.listenerCount(\"shardGiveUp\") > 0) this.emit(\"shardGiveUp\", channel, crashes);\r\n else this.reportError(new ShardUnavailableError(channel.id, `it crashed ${crashes} times`));\r\n return;\r\n }\r\n\r\n const others =\r\n this.supervisor.strategy === \"one-for-all\"\r\n ? this.channels.filter((other) => other !== channel)\r\n : this.supervisor.strategy === \"rest-for-one\"\r\n ? this.channels.filter((other) => other.id > channel.id)\r\n : [];\r\n for (const other of others) {\r\n if (!other.stopped)\r\n void this.restart(other.id).catch((error: unknown) => this.reportError(error));\r\n }\r\n }\r\n\r\n this.emit(\"shardRestart\", channel);\r\n void this.#startWithRetries(channel).catch((error: unknown) => this.reportError(error));\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n public recordReadyTime(time: number): void {\r\n this.#readyTimes.push(time);\r\n if (this.#readyTimes.length > 20) this.#readyTimes.shift();\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n public reportError(error: unknown): void {\r\n if (this.listenerCount(\"error\") > 0) this.emit(\"error\", error);\r\n else console.error(error);\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n public reportShardError(channel: ShardChannel, error: unknown): void {\r\n if (channel.listenerCount(\"error\") > 0) channel.emit(\"error\", error);\r\n if (this.listenerCount(\"shardError\") > 0) this.emit(\"shardError\", channel, error);\r\n else if (channel.listenerCount(\"error\") === 0) this.reportError(error);\r\n }\r\n\r\n /**\r\n * @internal\r\n */\r\n public reportInvalidMessage(channel: ShardChannel, error: unknown): void {\r\n if (this.listenerCount(\"shardInvalidMessage\") > 0)\r\n this.emit(\"shardInvalidMessage\", channel, error);\r\n else console.error(`Shard ${channel.id} sent an invalid message:`, error);\r\n }\r\n\r\n async #control(request: ControlRequest, from: ShardChannel): Promise<null> {\r\n const { action, target } = request;\r\n if (\"shard\" in target) {\r\n if (action === \"start\") await this.startShard(target.shard);\r\n else if (action === \"close\") await this.closeShard(target.shard);\r\n else await this.restartShard(target.shard);\r\n return null;\r\n }\r\n\r\n const channels = target.channel === \"all\" ? this.channels : [this.#channel(target.channel)];\r\n const run = async () => {\r\n for (const channel of channels) {\r\n if (action === \"restart\") await this.restart(channel.id);\r\n else if (action === \"close\") await channel.close();\r\n else if (!channel.running) await this.#startWithRetries(channel, true);\r\n }\r\n };\r\n\r\n // A shard closing or restarting itself would never get the reply: answer first.\r\n if (action !== \"start\" && channels.includes(from)) {\r\n setImmediate(() => void run().catch((error: unknown) => this.reportError(error)));\r\n } else {\r\n await run();\r\n }\r\n\r\n return null;\r\n }\r\n\r\n async #init(): Promise<void> {\r\n if (this.#initialized) return;\r\n await this.strategy.init?.();\r\n this.#initialized = true;\r\n }\r\n\r\n // `force` starts a shard closed for a restart; otherwise, a shard closed meanwhile is left alone.\r\n async #startWithRetries(channel: ShardChannel, force = false): Promise<void> {\r\n await this.#init();\r\n for (;;) {\r\n try {\r\n await this.#enqueue(async () => {\r\n if ((!force && channel.stopped) || channel.running) return;\r\n await channel.start();\r\n });\r\n return;\r\n } catch (error) {\r\n if (channel.stopped) throw error;\r\n const { restart } = this.supervisor.crash(channel.id);\r\n if (!restart) {\r\n channel.markStopped(\"it failed to start too often\");\r\n throw error;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Shards start one at a time, with the spawn delay after each, so their gateway identifies never overlap.\r\n #enqueue(task: () => Promise<void>): Promise<void> {\r\n const run = this.#queue.then(task);\r\n this.#queue = run.then(\r\n () => sleep(this.spawnDelay),\r\n () => sleep(this.spawnDelay),\r\n );\r\n return run;\r\n }\r\n\r\n #apply(layout: ResolvedLayout): void {\r\n this.shardCount = layout.shardCount;\r\n this.channels = layout.channels.map(\r\n (shards, id) => new ShardChannel(this, id, shards, layout.shardCount),\r\n );\r\n }\r\n\r\n #channel(channelId: number): ShardChannel {\r\n const channel = this.channels[channelId];\r\n if (!channel) throw new ShardUnavailableError(channelId, \"there is no such shard\");\r\n return channel;\r\n }\r\n\r\n #channelForShard(shardId: number): ShardChannel {\r\n const channel = this.channelFor(shardId);\r\n if (!channel) throw new RangeError(`No shard connects the gateway shard ${shardId}`);\r\n return channel;\r\n }\r\n}\r\n\r\ninterface ResolvedLayout {\r\n shardCount: number;\r\n channels: number[][];\r\n}\r\n\r\nfunction needsGateway(layout: ShardLayoutOptions): boolean {\r\n return (\r\n layout.totalShards === \"auto\" ||\r\n (layout.totalShards === undefined && (layout.shards ?? \"auto\") === \"auto\" && !layout.shardList)\r\n );\r\n}\r\n\r\nfunction resolveLayout(\r\n layout: ShardLayoutOptions,\r\n info: GatewayInformation | null,\r\n): ResolvedLayout {\r\n const { shards = \"auto\", shardList, clusters = availableParallelism() } = layout;\r\n const recommended = info ? resolveRecommendedShardCount(info.shards, layout.recommended) : null;\r\n const sizes = Array.isArray(shards) ? (shards as readonly number[]) : null;\r\n if (sizes?.some((size) => !Number.isSafeInteger(size) || size < 1) || sizes?.length === 0) {\r\n throw new RangeError(\"shards must list positive integers\");\r\n }\r\n\r\n const declared =\r\n typeof shards === \"number\" ? shards : sizes ? sizes.reduce((sum, size) => sum + size, 0) : null;\r\n const totalShards =\r\n layout.totalShards === \"auto\"\r\n ? recommended!\r\n : (layout.totalShards ?? declared ?? shardList?.length ?? recommended!);\r\n if (!Number.isSafeInteger(totalShards) || totalShards < 1) {\r\n throw new RangeError(\"The total number of gateway shards must be a positive integer\");\r\n }\r\n\r\n const ids = shardList ? [...shardList] : range(declared ?? totalShards);\r\n if (new Set(ids).size !== ids.length || ids.some((id) => id < 0 || id >= totalShards)) {\r\n throw new RangeError(`shardList must list distinct gateway shards below ${totalShards}`);\r\n }\r\n\r\n let channels: number[][];\r\n if (sizes) {\r\n if (ids.length !== declared)\r\n throw new RangeError(\"shards must add up to the shardList's length\");\r\n let offset = 0;\r\n channels = sizes.map((size) => ids.slice(offset, (offset += size)));\r\n } else if (typeof shards === \"number\") {\r\n if (ids.length !== shards) throw new RangeError(\"shards must be the shardList's length\");\r\n channels = ids.map((id) => [id]);\r\n } else {\r\n if (!Number.isSafeInteger(clusters) || clusters < 1) {\r\n throw new RangeError(\"clusters must be a positive integer\");\r\n }\r\n\r\n const size = Math.ceil(ids.length / clusters);\r\n channels = [];\r\n for (let index = 0; index < ids.length; index += size)\r\n channels.push(ids.slice(index, index + size));\r\n }\r\n\r\n return { shardCount: totalShards, channels };\r\n}\r\n\r\nfunction range(length: number): number[] {\r\n return Array.from({ length }, (_, index) => index);\r\n}\r\n","import { EventEmitter } from \"node:events\";\r\nimport {\r\n connect as connectNet,\r\n createServer as createNetServer,\r\n type Server,\r\n type Socket,\r\n} from \"node:net\";\r\nimport { availableParallelism, hostname } from \"node:os\";\r\nimport { setTimeout as sleep } from \"node:timers/promises\";\r\nimport {\r\n connect as connectTls,\r\n createServer as createTlsServer,\r\n type ConnectionOptions,\r\n type TlsOptions,\r\n} from \"node:tls\";\r\nimport { resolveMessageHandler } from \"./messages/MessageHandler.js\";\r\nimport { resolveMessageTransformer } from \"./messages/MessageTransformer.js\";\r\nimport { Op, PacketCodec, ShardStatus, serializeError, type Packet } from \"./messages/protocol.js\";\r\nimport {\r\n Connection,\r\n FrameType,\r\n readData,\r\n readPeer,\r\n tokensMatch,\r\n type DirectoryFrame,\r\n type HelloFrame,\r\n type PeerAddress,\r\n type PeerHeader,\r\n type SpawnFrame,\r\n type WelcomeFrame,\r\n} from \"./network/Connection.js\";\r\nimport type {\r\n ChannelStrategy,\r\n ShardContext,\r\n ShardTransport,\r\n} from \"./strategies/ChannelStrategy.js\";\r\nimport { resolveStrategy } from \"./strategies/registry.js\";\r\nimport { ShardUnavailableError } from \"./util/errors.js\";\r\n\r\n/**\r\n * A manager a proxy connects to.\r\n */\r\nexport interface ProxyManagerAddress {\r\n host: string;\r\n port: number;\r\n /**\r\n * The manager's token, when it differs from the proxy's `token`.\r\n */\r\n token?: string;\r\n /**\r\n * The TLS options of this manager, when they differ from the proxy's `tls`.\r\n */\r\n tls?: boolean | ConnectionOptions;\r\n}\r\n\r\n/**\r\n * How a proxy accepts connections from other proxies, to carry the messages between their shards directly.\r\n */\r\nexport interface ProxyPeerOptions {\r\n /**\r\n * The port to listen on, `0` for any.\r\n */\r\n port: number;\r\n host?: string;\r\n /**\r\n * The host other proxies reach this one at.\r\n *\r\n * @default host ?? os.hostname()\r\n */\r\n advertise?: string;\r\n /**\r\n * The shared secret of the peers.\r\n *\r\n * @default the proxy's token\r\n */\r\n token?: string;\r\n /**\r\n * The TLS options of the peer server (`key`, `cert`, ...). Left out, peers talk plain TCP.\r\n */\r\n tls?: TlsOptions;\r\n /**\r\n * The TLS options to connect to other peers with, `true` for the defaults.\r\n */\r\n connectTls?: boolean | ConnectionOptions;\r\n}\r\n\r\n/**\r\n * The options of a {@link ShardManagerProxy}.\r\n */\r\nexport interface ShardManagerProxyOptions {\r\n /**\r\n * The managers to connect to, as `{ host, port }` or `\"host:port\"`.\r\n */\r\n managers: readonly (ProxyManagerAddress | string)[];\r\n /**\r\n * How the proxy serves its managers:\r\n *\r\n * - `\"failover\"`: one at a time, the first reachable, failing over to the next ones when it loses it.\r\n * - `\"all\"`: all of them at once, sharing its capacity, e.g. managers each running part of the gateway shards.\r\n *\r\n * @default \"failover\"\r\n */\r\n mode?: \"failover\" | \"all\";\r\n /**\r\n * The shared secret of the managers' {@link NetworkStrategy}.\r\n */\r\n token: string;\r\n /**\r\n * The name of the proxy, unique across the proxies of a manager. It finds its shards back under it after a\r\n * reconnection.\r\n *\r\n * @default `${os.hostname()}:${process.pid}`\r\n */\r\n name?: string;\r\n /**\r\n * How many shards the proxy runs at most, across all its managers.\r\n *\r\n * @default os.availableParallelism()\r\n */\r\n capacity?: number;\r\n /**\r\n * How the proxy spawns its shards locally: a strategy, or the name of a registered one.\r\n *\r\n * @default \"fork\"\r\n */\r\n strategy?: ChannelStrategy | string;\r\n strategyOptions?: unknown;\r\n /**\r\n * Connects to the managers with TLS: `true` with the default options, or the options (`ca`, `servername`, ...).\r\n *\r\n * @default false\r\n */\r\n tls?: boolean | ConnectionOptions;\r\n /**\r\n * What the proxy does with the shards of a manager it loses: keep them running and reconnect (the manager takes\r\n * them back within its `reconnectGrace`), or stop them.\r\n *\r\n * @default \"keep\"\r\n */\r\n managerLoss?: \"keep\" | \"exit\";\r\n /**\r\n * How long to wait between connection attempts, in milliseconds.\r\n *\r\n * @default 5_000\r\n */\r\n reconnectDelay?: number;\r\n /**\r\n * Whether to carry the messages and requests between shards of this proxy (and, with `peer`, of other proxies)\r\n * without going through the manager. It decodes their packets with the manager's message handler and\r\n * transformers, built from the registry: custom ones must be registered in the proxy too.\r\n *\r\n * @default true\r\n */\r\n localRouting?: boolean;\r\n /**\r\n * Accepts connections from other proxies, and connects to them, to carry the messages between shards of different\r\n * proxies directly. Needs `localRouting`.\r\n */\r\n peer?: ProxyPeerOptions;\r\n heartbeat?: { interval?: number; timeout?: number };\r\n}\r\n\r\n/**\r\n * The events of a {@link ShardManagerProxy}.\r\n */\r\nexport interface ShardManagerProxyEvents {\r\n /**\r\n * The proxy connected to a manager.\r\n */\r\n connect: [manager: ProxyManagerAddress];\r\n /**\r\n * The proxy lost a manager.\r\n */\r\n disconnect: [manager: ProxyManagerAddress, error: Error | undefined];\r\n /**\r\n * A manager rejected the proxy, e.g. for a wrong token.\r\n */\r\n reject: [manager: ProxyManagerAddress, reason: string];\r\n spawn: [context: ShardContext];\r\n exit: [context: ShardContext, code: number | null];\r\n /**\r\n * A peer connection to another proxy opened.\r\n */\r\n peerConnect: [name: string];\r\n peerDisconnect: [name: string];\r\n error: [error: unknown];\r\n}\r\n\r\ninterface ManagerLink {\r\n index: number;\r\n addresses: readonly ProxyManagerAddress[];\r\n address: ProxyManagerAddress | null;\r\n connection: Connection | null;\r\n managerId: string | null;\r\n directory: Map<number, PeerAddress & { proxy: string }>;\r\n}\r\n\r\ninterface LocalShard {\r\n key: string;\r\n link: ManagerLink;\r\n scope: string;\r\n spawnId: number;\r\n context: ShardContext;\r\n transport: ShardTransport;\r\n ready: boolean;\r\n exited: boolean;\r\n}\r\n\r\ninterface Peer {\r\n name: string;\r\n connection: Connection;\r\n}\r\n\r\ntype Endpoint = { shard: LocalShard } | { peer: Peer; channel: number };\r\n\r\ninterface Route {\r\n origin: Endpoint;\r\n originNonce: number;\r\n target: LocalShard;\r\n}\r\n\r\ninterface PeerRequest {\r\n origin: LocalShard;\r\n peer: Peer;\r\n header: PeerHeader;\r\n}\r\n\r\n/**\r\n * Runs shards for remote {@link ShardManager}s using a {@link NetworkStrategy}: the sharder RFC's\r\n * `ShardManagerProxy`. It spawns them locally with its own strategy, carries their messages to their manager, and\r\n * carries the messages between shards of the same manager directly, locally or through peer proxies.\r\n *\r\n * @example\r\n * ```ts\r\n * const proxy = new ShardManagerProxy({\r\n * managers: [\"manager.internal:7000\", \"manager-backup.internal:7000\"],\r\n * token: process.env.SHARDER_TOKEN!,\r\n * tls: { ca: readFileSync(\"ca.pem\") },\r\n * strategy: new ForkStrategy({ path: \"./bot.js\" }),\r\n * capacity: 8,\r\n * peer: { port: 7001 },\r\n * });\r\n * await proxy.connect();\r\n * ```\r\n */\r\nexport class ShardManagerProxy extends EventEmitter<ShardManagerProxyEvents> {\r\n public readonly name: string;\r\n public readonly capacity: number;\r\n public readonly strategy: ChannelStrategy;\r\n public readonly managers: readonly ProxyManagerAddress[];\r\n public readonly mode: \"failover\" | \"all\";\r\n\r\n readonly #options: ShardManagerProxyOptions;\r\n readonly #links: ManagerLink[];\r\n readonly #shards = new Map<string, LocalShard>();\r\n readonly #byChannel = new Map<string, LocalShard>();\r\n readonly #routes = new Map<number, Route>();\r\n readonly #peerRequests = new Map<string, PeerRequest>();\r\n readonly #peers = new Map<string, Peer>();\r\n readonly #connecting = new Set<string>();\r\n readonly #inbound = new Set<Peer>();\r\n readonly #codecs = new Map<string, PacketCodec>();\r\n #peerServer: Server | null = null;\r\n #peerAddress: PeerAddress | null = null;\r\n #destroyed = false;\r\n #nextNonce = 0;\r\n\r\n public constructor(options: ShardManagerProxyOptions) {\r\n super();\r\n if (options.managers.length === 0) throw new RangeError(\"A proxy needs at least one manager\");\r\n if (options.peer && options.localRouting === false) {\r\n throw new TypeError(\"Peer routing needs local routing\");\r\n }\r\n\r\n this.#options = options;\r\n this.name = options.name ?? `${hostname()}:${process.pid}`;\r\n this.capacity = options.capacity ?? availableParallelism();\r\n this.strategy = resolveStrategy(options.strategy ?? \"fork\", options.strategyOptions);\r\n this.managers = options.managers.map(parseAddress);\r\n this.mode = options.mode ?? \"failover\";\r\n this.#links =\r\n this.mode === \"all\"\r\n ? this.managers.map((address, index) => createLink([address], index))\r\n : [createLink(this.managers, 0)];\r\n }\r\n\r\n /**\r\n * The managers the proxy is connected to.\r\n */\r\n public get connectedManagers(): ProxyManagerAddress[] {\r\n return this.#links.flatMap((link) => (link.connection && link.address ? [link.address] : []));\r\n }\r\n\r\n /**\r\n * The manager the proxy is connected to in `\"failover\"` mode, `null` while it is not.\r\n */\r\n public get manager(): ProxyManagerAddress | null {\r\n return this.connectedManagers[0] ?? null;\r\n }\r\n\r\n /**\r\n * The contexts of the shards the proxy runs.\r\n */\r\n public get shards(): ShardContext[] {\r\n return [...this.#shards.values()].map((shard) => shard.context);\r\n }\r\n\r\n /**\r\n * Where other proxies reach this one, once connected with `peer`.\r\n */\r\n public get peerAddress(): PeerAddress | null {\r\n return this.#peerAddress;\r\n }\r\n\r\n /**\r\n * The names of the proxies this one has a peer connection with.\r\n */\r\n public get peers(): string[] {\r\n return [...new Set([...this.#peers.values(), ...this.#inbound].map((peer) => peer.name))];\r\n }\r\n\r\n /**\r\n * Connects to the managers, and keeps reconnecting whenever a connection is lost, until\r\n * {@link ShardManagerProxy.destroy}. Resolves once connected to a first manager.\r\n */\r\n public async connect(): Promise<void> {\r\n await this.strategy.init?.();\r\n await this.#listenPeers();\r\n await new Promise<void>((resolve) => {\r\n this.once(\"connect\", () => resolve());\r\n for (const link of this.#links) void this.#loop(link);\r\n });\r\n }\r\n\r\n /**\r\n * Stops every shard, and disconnects for good.\r\n */\r\n public async destroy(): Promise<void> {\r\n this.#destroyed = true;\r\n // Leave the managers first, so they do not hand out new spawns while the shards stop.\r\n for (const link of this.#links) link.connection?.close();\r\n await Promise.all([...this.#shards.values()].map((shard) => shard.transport.kill()));\r\n for (const peer of [...this.#peers.values(), ...this.#inbound]) peer.connection.close();\r\n const server = this.#peerServer;\r\n this.#peerServer = null;\r\n if (server) await new Promise<void>((resolve) => server.close(() => resolve()));\r\n await this.strategy.destroy?.();\r\n }\r\n\r\n async #loop(link: ManagerLink): Promise<void> {\r\n for (let attempt = 0; !this.#destroyed; ++attempt) {\r\n const address = link.addresses[attempt % link.addresses.length]!;\r\n const error = await this.#session(link, address);\r\n if (this.#destroyed) return;\r\n if (error !== undefined) this.emit(\"disconnect\", address, error ?? undefined);\r\n await sleep(this.#options.reconnectDelay ?? 5_000);\r\n }\r\n }\r\n\r\n // Runs one connection to a manager. Resolves when it ends: `undefined` if it never connected.\r\n #session(link: ManagerLink, address: ProxyManagerAddress): Promise<Error | null | undefined> {\r\n return new Promise((resolve) => {\r\n const tls = address.tls ?? this.#options.tls;\r\n const socket = tls\r\n ? connectTls({ ...(tls === true ? {} : tls), host: address.host, port: address.port })\r\n : connectNet({ host: address.host, port: address.port });\r\n socket.once(\"error\", () => resolve(undefined));\r\n\r\n socket.once(tls ? \"secureConnect\" : \"connect\", () => {\r\n socket.removeAllListeners(\"error\");\r\n const connection = new Connection(socket, this.#heartbeat());\r\n let welcomed = false;\r\n\r\n connection.on(\"frame\", (type, payload) => {\r\n if (welcomed) {\r\n this.#frame(link, type, payload);\r\n } else if (type === FrameType.Welcome) {\r\n welcomed = true;\r\n this.#welcome(\r\n link,\r\n address,\r\n connection,\r\n JSON.parse(payload.toString()) as WelcomeFrame,\r\n );\r\n } else if (type === FrameType.Reject) {\r\n const { reason } = JSON.parse(payload.toString()) as { reason: string };\r\n this.emit(\"reject\", address, reason);\r\n connection.close();\r\n }\r\n });\r\n connection.on(\"close\", (error) => {\r\n if (link.connection === connection) this.#lost(link);\r\n resolve(welcomed ? (error ?? null) : undefined);\r\n });\r\n\r\n const hello: HelloFrame = {\r\n token: address.token ?? this.#options.token,\r\n name: this.name,\r\n capacity: this.capacity,\r\n available: this.#available(),\r\n running: [...this.#shards.values()]\r\n .filter((shard) => shard.link === link)\r\n .map((shard) => shard.spawnId),\r\n peer: this.#peerAddress,\r\n };\r\n void connection.sendJson(FrameType.Hello, hello).catch(() => undefined);\r\n });\r\n });\r\n }\r\n\r\n #welcome(\r\n link: ManagerLink,\r\n address: ProxyManagerAddress,\r\n connection: Connection,\r\n welcome: WelcomeFrame,\r\n ): void {\r\n const kill = new Set(welcome.kill);\r\n for (const shard of this.#shards.values()) {\r\n if (shard.link === link && kill.has(shard.spawnId)) void shard.transport.kill();\r\n }\r\n\r\n link.connection = connection;\r\n link.address = address;\r\n link.managerId = welcome.managerId;\r\n this.emit(\"connect\", address);\r\n }\r\n\r\n #lost(link: ManagerLink): void {\r\n link.connection = null;\r\n link.directory.clear();\r\n if (this.#options.managerLoss === \"exit\") {\r\n for (const shard of this.#shards.values()) {\r\n if (shard.link === link) void shard.transport.kill();\r\n }\r\n }\r\n }\r\n\r\n #frame(link: ManagerLink, type: FrameType, payload: Buffer): void {\r\n switch (type) {\r\n case FrameType.StringData:\r\n case FrameType.BinaryData: {\r\n const { spawnId, data } = readData(type, payload);\r\n const shard = this.#shards.get(shardKey(link, spawnId));\r\n void shard?.transport.send(data).catch(() => undefined);\r\n break;\r\n }\r\n case FrameType.Spawn:\r\n this.#spawn(link, JSON.parse(payload.toString()) as SpawnFrame);\r\n break;\r\n case FrameType.Kill: {\r\n const { spawnId } = JSON.parse(payload.toString()) as { spawnId: number };\r\n const shard = this.#shards.get(shardKey(link, spawnId));\r\n if (shard) void shard.transport.kill();\r\n else void this.#report(link, FrameType.Exit, { spawnId, code: null });\r\n break;\r\n }\r\n case FrameType.Directory: {\r\n const { entries } = JSON.parse(payload.toString()) as DirectoryFrame;\r\n link.directory = new Map(entries.map(({ channel, ...entry }) => [channel, entry] as const));\r\n break;\r\n }\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n #spawn(link: ManagerLink, frame: SpawnFrame): void {\r\n const context = frame.context as ShardContext;\r\n const key = shardKey(link, frame.spawnId);\r\n if (this.#shards.size >= this.capacity) {\r\n void this.#report(link, FrameType.Error, {\r\n spawnId: frame.spawnId,\r\n message: \"The proxy is full\",\r\n });\r\n void this.#report(link, FrameType.Exit, { spawnId: frame.spawnId, code: null });\r\n return;\r\n }\r\n\r\n let shard: LocalShard | null = null;\r\n try {\r\n const transport = this.strategy.spawn(\r\n context,\r\n {\r\n message: (data) => void this.#fromShard(shard!, data),\r\n exit: (code) => this.#exited(shard!, code),\r\n error: (error) => {\r\n void this.#report(link, FrameType.Error, {\r\n spawnId: frame.spawnId,\r\n message: serializeError(error).message,\r\n });\r\n },\r\n },\r\n { env: frame.env },\r\n );\r\n shard = {\r\n key,\r\n link,\r\n scope: link.managerId!,\r\n spawnId: frame.spawnId,\r\n context,\r\n transport,\r\n ready: false,\r\n exited: false,\r\n };\r\n } catch (error) {\r\n void this.#report(link, FrameType.Error, {\r\n spawnId: frame.spawnId,\r\n message: serializeError(error).message,\r\n });\r\n void this.#report(link, FrameType.Exit, { spawnId: frame.spawnId, code: null });\r\n return;\r\n }\r\n\r\n this.#shards.set(key, shard);\r\n this.#byChannel.set(channelKey(shard.scope, context.id), shard);\r\n void this.#report(link, FrameType.Spawned, {\r\n spawnId: frame.spawnId,\r\n pid: shard.transport.pid ?? null,\r\n threadId: shard.transport.threadId ?? null,\r\n });\r\n this.#reportLoad();\r\n this.emit(\"spawn\", context);\r\n }\r\n\r\n #exited(shard: LocalShard, code: number | null): void {\r\n shard.exited = true;\r\n this.#shards.delete(shard.key);\r\n const key = channelKey(shard.scope, shard.context.id);\r\n if (this.#byChannel.get(key) === shard) this.#byChannel.delete(key);\r\n\r\n // Requests still waiting on a shard that stopped fail right away; its own requests are abandoned.\r\n const stopped = serializeError(new ShardUnavailableError(shard.context.id, \"it stopped\"));\r\n for (const [nonce, route] of this.#routes) {\r\n if (route.target === shard) {\r\n this.#routes.delete(nonce);\r\n void this.#toEndpoint(route.origin, shard, {\r\n op: Op.Reply,\r\n nonce: route.originNonce,\r\n error: stopped,\r\n });\r\n } else if (\"shard\" in route.origin && route.origin.shard === shard) {\r\n this.#routes.delete(nonce);\r\n void this.#toShard(route.target, { op: Op.Abort, nonce });\r\n }\r\n }\r\n\r\n // Nobody waits for the replies of the stopped shard's requests to peers anymore: the peers abort them.\r\n for (const [requestKey, request] of this.#peerRequests) {\r\n if (request.origin !== shard) continue;\r\n this.#peerRequests.delete(requestKey);\r\n const nonce = Number(requestKey.slice(requestKey.lastIndexOf(\":\") + 1));\r\n void this.#abortPeerRequest(request, nonce);\r\n }\r\n\r\n void this.#report(shard.link, FrameType.Exit, { spawnId: shard.spawnId, code });\r\n this.#reportLoad();\r\n this.emit(\"exit\", shard.context, code);\r\n }\r\n\r\n async #fromShard(shard: LocalShard, data: unknown): Promise<void> {\r\n if (this.#options.localRouting !== false) {\r\n let packet: Packet | null = null;\r\n try {\r\n packet = await this.#codec(shard.context).decode(data, { channelId: shard.context.id });\r\n } catch {\r\n // Not readable here: the manager reports it.\r\n }\r\n\r\n if (packet?.op === Op.Signal) {\r\n const ready = packet.status === ShardStatus.Ready;\r\n if (ready !== shard.ready) {\r\n shard.ready = ready;\r\n void this.#report(shard.link, FrameType.Status, { spawnId: shard.spawnId, ready });\r\n }\r\n } else if (packet && (await this.#route(shard, packet, data))) {\r\n return;\r\n }\r\n }\r\n\r\n await shard.link.connection?.sendData(shard.spawnId, data).catch(() => undefined);\r\n }\r\n\r\n // Carries a packet of a local shard to another shard of the same manager. Returns whether it did.\r\n async #route(origin: LocalShard, packet: Packet, data: unknown): Promise<boolean> {\r\n switch (packet.op) {\r\n case Op.Message:\r\n case Op.Request: {\r\n if (typeof packet.to !== \"number\" || (packet.op === Op.Request && packet.system))\r\n return false;\r\n\r\n const local = this.#byChannel.get(channelKey(origin.scope, packet.to));\r\n if (local?.ready) {\r\n await this.#deliver({ shard: origin }, origin.context.id, local, packet);\r\n return true;\r\n }\r\n\r\n const entry = origin.link.directory.get(packet.to);\r\n if (!entry || entry.proxy === this.name || !isChannelData(data)) return false;\r\n const peer = this.#peer(entry);\r\n if (!peer) return false;\r\n\r\n const header: PeerHeader = {\r\n scope: origin.scope,\r\n origin: origin.context.id,\r\n target: packet.to,\r\n binary: typeof data !== \"string\",\r\n };\r\n if (packet.op === Op.Request) {\r\n this.#peerRequests.set(`${origin.key}:${packet.nonce}`, { origin, peer, header });\r\n }\r\n\r\n await peer.connection.sendPeer(header, data).catch(() => undefined);\r\n return true;\r\n }\r\n case Op.Reply: {\r\n const route = this.#routes.get(packet.nonce);\r\n if (!route || route.target !== origin) return false;\r\n this.#routes.delete(packet.nonce);\r\n await this.#toEndpoint(route.origin, origin, { ...packet, nonce: route.originNonce });\r\n return true;\r\n }\r\n case Op.Abort: {\r\n for (const [nonce, route] of this.#routes) {\r\n if (!(\"shard\" in route.origin) || route.origin.shard !== origin) continue;\r\n if (route.originNonce !== packet.nonce) continue;\r\n this.#routes.delete(nonce);\r\n await this.#toShard(route.target, { op: Op.Abort, nonce });\r\n return true;\r\n }\r\n\r\n const request = this.#peerRequests.get(`${origin.key}:${packet.nonce}`);\r\n if (!request || !isChannelData(data)) return false;\r\n this.#peerRequests.delete(`${origin.key}:${packet.nonce}`);\r\n await request.peer.connection\r\n .sendPeer({ ...request.header, binary: typeof data !== \"string\" }, data)\r\n .catch(() => undefined);\r\n return true;\r\n }\r\n default:\r\n return false;\r\n }\r\n }\r\n\r\n // Delivers a message or request to a local shard, from a local shard or a peer's.\r\n async #deliver(\r\n origin: Endpoint,\r\n from: number,\r\n target: LocalShard,\r\n packet: Packet,\r\n ): Promise<void> {\r\n if (packet.op === Op.Message) {\r\n await this.#toShard(target, { op: Op.Message, body: packet.body, from });\r\n return;\r\n }\r\n\r\n if (packet.op !== Op.Request) return;\r\n // Nonces of the proxy count down, so they never collide with the manager's.\r\n const nonce = --this.#nextNonce;\r\n this.#routes.set(nonce, { origin, originNonce: packet.nonce, target });\r\n await this.#toShard(target, {\r\n op: Op.Request,\r\n nonce,\r\n body: packet.body,\r\n from,\r\n timeout: packet.timeout,\r\n });\r\n }\r\n\r\n async #fromPeer(peer: Peer, header: PeerHeader, data: string | Uint8Array): Promise<void> {\r\n if (header.bounce) {\r\n // The peer could not deliver a packet of one of our shards: it goes through the manager after all.\r\n // The request is sent again through the manager, whose reply the shard still waits for: only the peer route\r\n // of this very request is gone, not the ones of the shard's other requests to this peer.\r\n const origin = this.#byChannel.get(channelKey(header.scope, header.origin));\r\n if (!origin) return;\r\n const packet = await this.#codec(origin.context)\r\n .decode(data, { channelId: origin.context.id })\r\n .catch(() => null);\r\n if (packet?.op === Op.Request) this.#peerRequests.delete(`${origin.key}:${packet.nonce}`);\r\n\r\n await origin.link.connection?.sendData(origin.spawnId, data).catch(() => undefined);\r\n return;\r\n }\r\n\r\n const target = this.#byChannel.get(channelKey(header.scope, header.target));\r\n let packet: Packet | null = null;\r\n if (target) {\r\n try {\r\n packet = await this.#codec(target.context).decode(data, { channelId: header.origin });\r\n } catch {\r\n packet = null;\r\n }\r\n }\r\n\r\n if (!target || !packet) {\r\n await peer.connection.sendPeer({ ...header, bounce: true }, data).catch(() => undefined);\r\n return;\r\n }\r\n\r\n switch (packet.op) {\r\n case Op.Message:\r\n case Op.Request:\r\n if (!target.ready) {\r\n await peer.connection.sendPeer({ ...header, bounce: true }, data).catch(() => undefined);\r\n return;\r\n }\r\n\r\n await this.#deliver({ peer, channel: header.origin }, header.origin, target, packet);\r\n break;\r\n case Op.Abort:\r\n for (const [nonce, route] of this.#routes) {\r\n if (!(\"peer\" in route.origin) || route.origin.peer !== peer) continue;\r\n if (route.origin.channel !== header.origin || route.originNonce !== packet.nonce)\r\n continue;\r\n this.#routes.delete(nonce);\r\n await this.#toShard(route.target, { op: Op.Abort, nonce });\r\n break;\r\n }\r\n\r\n break;\r\n case Op.Reply:\r\n // The reply to a request one of our shards sent to the peer: its nonce is already the shard's.\r\n this.#peerRequests.delete(`${target.key}:${packet.nonce}`);\r\n await this.#toShard(target, packet);\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n async #abortPeerRequest(request: PeerRequest, nonce: number): Promise<void> {\r\n const data = await this.#codec(request.origin.context).encode(\r\n { op: Op.Abort, nonce },\r\n { channelId: request.origin.context.id },\r\n );\r\n if (!isChannelData(data)) return;\r\n await request.peer.connection\r\n .sendPeer({ ...request.header, binary: typeof data !== \"string\" }, data)\r\n .catch(() => undefined);\r\n }\r\n\r\n async #toEndpoint(endpoint: Endpoint, from: LocalShard, packet: Packet): Promise<void> {\r\n if (\"shard\" in endpoint) {\r\n await this.#toShard(endpoint.shard, packet);\r\n return;\r\n }\r\n\r\n const data = await this.#codec(from.context).encode(packet, { channelId: from.context.id });\r\n if (!isChannelData(data)) return;\r\n const header: PeerHeader = {\r\n scope: from.scope,\r\n origin: from.context.id,\r\n target: endpoint.channel,\r\n binary: typeof data !== \"string\",\r\n };\r\n await endpoint.peer.connection.sendPeer(header, data).catch(() => undefined);\r\n }\r\n\r\n async #toShard(shard: LocalShard, packet: Packet): Promise<void> {\r\n if (shard.exited) return;\r\n const data = await this.#codec(shard.context).encode(packet, { channelId: shard.context.id });\r\n await shard.transport.send(data).catch(() => undefined);\r\n }\r\n\r\n // The manager tells its shards its codec's names: the proxy builds the same codec from them.\r\n #codec(context: ShardContext): PacketCodec {\r\n const key = JSON.stringify([context.messageHandler, context.transformers]);\r\n let codec = this.#codecs.get(key);\r\n if (!codec) {\r\n codec = new PacketCodec(\r\n resolveMessageHandler(context.messageHandler),\r\n context.transformers.map(resolveMessageTransformer),\r\n );\r\n this.#codecs.set(key, codec);\r\n }\r\n\r\n return codec;\r\n }\r\n\r\n async #listenPeers(): Promise<void> {\r\n const options = this.#options.peer;\r\n if (!options || this.#peerServer) return;\r\n\r\n const onSocket = (socket: Socket) => this.#acceptPeer(socket);\r\n const server = options.tls ? createTlsServer(options.tls, onSocket) : createNetServer(onSocket);\r\n await new Promise<void>((resolve, reject) => {\r\n server.once(\"error\", reject);\r\n server.listen(options.port, options.host, () => {\r\n server.off(\"error\", reject);\r\n resolve();\r\n });\r\n });\r\n\r\n const address = server.address();\r\n this.#peerServer = server;\r\n this.#peerAddress = {\r\n host: options.advertise ?? options.host ?? hostname(),\r\n port: typeof address === \"object\" && address ? address.port : options.port,\r\n };\r\n }\r\n\r\n #acceptPeer(socket: Socket): void {\r\n const connection = new Connection(socket, this.#heartbeat());\r\n let peer: Peer | null = null;\r\n connection.on(\"frame\", (type, payload) => {\r\n if (peer) {\r\n if (type === FrameType.PeerPacket) {\r\n const { header, data } = readPeer(payload);\r\n void this.#fromPeer(peer, header, data);\r\n }\r\n\r\n return;\r\n }\r\n\r\n const hello =\r\n type === FrameType.PeerHello\r\n ? (JSON.parse(payload.toString()) as { token: string; name: string })\r\n : null;\r\n if (!hello || !tokensMatch(this.#peerToken(), hello.token)) {\r\n connection.close();\r\n return;\r\n }\r\n\r\n peer = { name: hello.name, connection };\r\n this.#inbound.add(peer);\r\n void connection.send(FrameType.PeerWelcome).catch(() => undefined);\r\n this.emit(\"peerConnect\", peer.name);\r\n });\r\n connection.on(\"close\", () => {\r\n if (!peer) return;\r\n this.#inbound.delete(peer);\r\n this.#peerLost(peer);\r\n });\r\n }\r\n\r\n // The peer connection to a proxy, or `null` while it opens: meanwhile, packets go through the manager.\r\n #peer(entry: PeerAddress & { proxy: string }): Peer | null {\r\n const key = `${entry.host}:${entry.port}`;\r\n const peer = this.#peers.get(key);\r\n if (peer && !peer.connection.closed) return peer;\r\n\r\n // A connection the other proxy opened works both ways.\r\n for (const inbound of this.#inbound) {\r\n if (inbound.name === entry.proxy && !inbound.connection.closed) return inbound;\r\n }\r\n\r\n if (this.#connecting.has(key) || this.#destroyed) return null;\r\n\r\n this.#connecting.add(key);\r\n const options = this.#options.peer;\r\n const tls = options?.connectTls;\r\n const socket = tls\r\n ? connectTls({ ...(tls === true ? {} : tls), host: entry.host, port: entry.port })\r\n : connectNet({ host: entry.host, port: entry.port });\r\n socket.once(\"error\", () => this.#connecting.delete(key));\r\n socket.once(tls ? \"secureConnect\" : \"connect\", () => {\r\n socket.removeAllListeners(\"error\");\r\n const connection = new Connection(socket, this.#heartbeat());\r\n const opened: Peer = { name: entry.proxy, connection };\r\n connection.on(\"frame\", (type, payload) => {\r\n if (type === FrameType.PeerWelcome) {\r\n this.#connecting.delete(key);\r\n this.#peers.set(key, opened);\r\n this.emit(\"peerConnect\", opened.name);\r\n } else if (type === FrameType.PeerPacket) {\r\n const { header, data } = readPeer(payload);\r\n void this.#fromPeer(opened, header, data);\r\n }\r\n });\r\n connection.on(\"close\", () => {\r\n this.#connecting.delete(key);\r\n if (this.#peers.get(key) === opened) this.#peers.delete(key);\r\n this.#peerLost(opened);\r\n });\r\n void connection\r\n .sendJson(FrameType.PeerHello, { token: this.#peerToken(), name: this.name })\r\n .catch(() => undefined);\r\n });\r\n return null;\r\n }\r\n\r\n #peerLost(peer: Peer): void {\r\n // Requests of our shards the peer will never answer fail right away; the peer's requests are aborted.\r\n for (const [key, request] of this.#peerRequests) {\r\n if (request.peer !== peer) continue;\r\n this.#peerRequests.delete(key);\r\n const nonce = Number(key.slice(key.lastIndexOf(\":\") + 1));\r\n const error = serializeError(\r\n new ShardUnavailableError(request.header.target, \"its proxy is unreachable\"),\r\n );\r\n void this.#toShard(request.origin, { op: Op.Reply, nonce, error });\r\n }\r\n\r\n for (const [nonce, route] of this.#routes) {\r\n if (!(\"peer\" in route.origin) || route.origin.peer !== peer) continue;\r\n this.#routes.delete(nonce);\r\n void this.#toShard(route.target, { op: Op.Abort, nonce });\r\n }\r\n\r\n this.emit(\"peerDisconnect\", peer.name);\r\n }\r\n\r\n #available(): number {\r\n return Math.max(this.capacity - this.#shards.size, 0);\r\n }\r\n\r\n #reportLoad(): void {\r\n for (const link of this.#links)\r\n void this.#report(link, FrameType.Load, { available: this.#available() });\r\n }\r\n\r\n async #report(link: ManagerLink, type: FrameType, body: unknown): Promise<void> {\r\n await link.connection?.sendJson(type, body).catch(() => undefined);\r\n }\r\n\r\n #peerToken(): string {\r\n return this.#options.peer?.token ?? this.#options.token;\r\n }\r\n\r\n #heartbeat(): { interval: number; timeout: number } {\r\n return {\r\n interval: this.#options.heartbeat?.interval ?? 15_000,\r\n timeout: this.#options.heartbeat?.timeout ?? 45_000,\r\n };\r\n }\r\n}\r\n\r\nfunction createLink(addresses: readonly ProxyManagerAddress[], index: number): ManagerLink {\r\n return {\r\n index,\r\n addresses,\r\n address: null,\r\n connection: null,\r\n managerId: null,\r\n directory: new Map(),\r\n };\r\n}\r\n\r\nfunction shardKey(link: ManagerLink, spawnId: number): string {\r\n return `${link.index}:${spawnId}`;\r\n}\r\n\r\nfunction channelKey(scope: string, channel: number): string {\r\n return `${scope}:${channel}`;\r\n}\r\n\r\nfunction isChannelData(data: unknown): data is string | Uint8Array {\r\n return typeof data === \"string\" || data instanceof Uint8Array;\r\n}\r\n\r\nfunction parseAddress(address: ProxyManagerAddress | string): ProxyManagerAddress {\r\n if (typeof address !== \"string\") return address;\r\n\r\n const separator = address.lastIndexOf(\":\");\r\n const port = Number(address.slice(separator + 1));\r\n if (separator === -1 || !Number.isInteger(port)) {\r\n throw new RangeError(`\"${address}\" is not a host:port address`);\r\n }\r\n\r\n return { host: address.slice(0, separator).replace(/^\\[|\\]$/g, \"\"), port };\r\n}\r\n","import type { RequestHandler } from \"./requests.js\";\r\n\r\n/**\r\n * A request naming a command, the optional command layer on top of raw requests.\r\n */\r\nexport interface CommandRequest<Name extends string = string, Data = unknown> {\r\n command: Name;\r\n data: Data;\r\n}\r\n\r\n/**\r\n * The commands a handler answers, by name.\r\n */\r\nexport type Commands<Context = unknown> = Record<\r\n string,\r\n (data: any, context: Context & { signal: AbortSignal }) => unknown\r\n>;\r\n\r\n/**\r\n * The reply of a command.\r\n */\r\nexport type CommandReply<C extends Commands<any>, Name extends keyof C> = Awaited<\r\n ReturnType<C[Name]>\r\n>;\r\n\r\n/**\r\n * Builds a request handler answering {@link CommandRequest}s: the sharder stays raw data (as the RFC settled), and\r\n * this is the optional, typed layer on top.\r\n *\r\n * @param commands The commands, by name.\r\n * @example\r\n * ```ts\r\n * const commands = {\r\n * guildCount: () => guilds.size,\r\n * guild: (id: string) => guilds.get(id) ?? null,\r\n * } satisfies Commands;\r\n *\r\n * shard.setRequestHandler(createCommandHandler(commands));\r\n * const counts = await manager.broadcastRequest<CommandReply<typeof commands, \"guildCount\">>(\r\n * command<typeof commands>(\"guildCount\"),\r\n * );\r\n * ```\r\n */\r\nexport function createCommandHandler<Context>(\r\n commands: Commands<Context>,\r\n): RequestHandler<Context> {\r\n return (body, context) => {\r\n const request = body as Partial<CommandRequest> | null;\r\n const run = typeof request?.command === \"string\" ? commands[request.command] : undefined;\r\n if (!run || !Object.hasOwn(commands, request!.command!)) {\r\n throw new RangeError(`Unknown command ${String(request?.command)}`);\r\n }\r\n\r\n return run(request!.data, context);\r\n };\r\n}\r\n\r\n/**\r\n * Builds a {@link CommandRequest}.\r\n *\r\n * @param name The name of the command.\r\n * @param data Its argument.\r\n */\r\nexport function command<C extends Commands<any>, Name extends keyof C & string = keyof C & string>(\r\n name: Name,\r\n ...data: Parameters<C[Name]>[0] extends undefined ? [] : [data: Parameters<C[Name]>[0]]\r\n): CommandRequest<Name, Parameters<C[Name]>[0]> {\r\n return { command: name, data: data[0] as Parameters<C[Name]>[0] };\r\n}\r\n"],"mappings":"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"}