import { ChildProcess, Serializable as ChildSerializable } from 'child_process'; import { WorkerThreadOptions } from './classes/worker'; import { ClusterManager } from './core/clusterManager'; import { ChildProcessOptions } from './classes/child'; import { ClusterClient } from './core/clusterClient'; import { ProcessMessage } from './other/message'; import { Cluster } from './core/cluster'; import { Worker } from 'worker_threads'; /** Default options for fetching the bot gateway. */ export const DefaultOptions = { http: { api: 'https://discord.com/api', version: '10', }, }; /** Endpoints for the discord api. */ export const Endpoints = { botGateway: '/gateway/bot', }; /** The types of data that can be sent. */ export enum MessageTypes { 'MissingType' = 0, 'CustomRequest' = 1, 'CustomMessage' = 2, 'CustomReply' = 3, 'Heartbeat' = 4, 'HeartbeatAck' = 5, 'ClientBroadcast' = 6, 'ClientBroadcastRequest' = 7, 'ClientBroadcastResponse' = 8, 'ClientBroadcastResponseError' = 9, 'ClientRespawn' = 10, 'ClientRespawnAll' = 11, 'ClientSpawnNextCluster' = 16, 'ClientReady' = 17, 'ClientEvalRequest' = 18, 'ClientEvalResponse' = 19, 'ClientEvalResponseError' = 20, 'ClientManagerEvalRequest' = 21, 'ClientManagerEvalResponse' = 22, 'ClientManagerEvalResponseError' = 23, 'ManagerReady' = 24, 'Kill' = 25, 'ClientRespawnSpecific' = 26, } /** Recursive array of strings. */ export type RecursiveStringArray = (RecursiveStringArray | string)[]; /** Supported library packages. */ export type PackageType = 'discord.js' | '@discordjs/core'; /** Awaitable type. */ export type Awaitable = T | PromiseLike; /** Mode for clustering. */ export type ClusteringMode = 'worker' | 'process'; /** Any function. */ export type UnknownFunction = (...args: unknown[]) => unknown; /** Data for restart sysytem. */ export type HeartbeatData = { restarts: number; missedBeats: number; killing: boolean; }; /** Type that removes null and undefined from a type. */ export type DeepNonNullable = T extends NonNullable ? T : DeepNonNullable>; /** Check for function's outputs. */ export type ValidIfSerializable = T extends NonNullable ? (T | undefined) : never; /** Check if input is serializable. */ export type SerializableInput = T extends Serializable ? T : T extends unknown ? U : never; /** Output of guild function parser. */ export type DeconstructedFunction = { args: (string | string[])[], body: string, wrapScope: boolean, wrapArgs: boolean; isAsync: boolean; }; /** Any object or data. */ export type Serializable = string | number | boolean | null | undefined | Serializable[] | { [key: string]: Serializable } | object | ChildSerializable; /** Already serialized data. */ export type Serialized = T extends symbol | bigint | UnknownFunction ? never : T extends ValidIfSerializable ? T : (T extends { toJSON(): infer R } ? R : T extends ReadonlyArray ? Serialized[] : (T extends ReadonlyMap | ReadonlySet ? object : (T extends object ? { [K in keyof T]: Serialized } : T))); /** Options for the cluster manager. */ export interface ClusterManagerCreateOptions { /** What mode to use for clustering. */ mode?: T; /** The token of the discord bot. */ token?: string; /** Number of total internal shards or -1. */ totalShards?: number; /** Number of total Clusters/Process to spawn. */ totalClusters?: number; /** Number of shards per cluster. */ shardsPerClusters?: number; /** Arguments to pass to the clustered script when spawning (only available when using the `process` mode). */ shardArgs?: string[]; /** Arguments to pass to the clustered script executable when spawning. */ execArgv?: string[]; /** Whether clusters should automatically respawn upon exiting. */ respawn?: boolean; /** Whether a cluster should acknowledge heartbeat while the internal client is not ready. Defaults to `true`. */ respondToHeartbeatWhenNotReady?: boolean; /** Heartbeat options. */ heartbeat?: ClusterHeartbeatOptions; /** Control the Spawn Queue. */ queueOptions?: QueueOptions; /** Options to pass to the spawn, respawn method. */ spawnOptions?: ClusterSpawnOptions; /** Data, which is passed to the Cluster. */ clusterData?: object; /** Options, which is passed when forking a child or creating a thread. */ clusterOptions?: T extends 'worker' ? WorkerThreadOptions : ChildProcessOptions; /** Advanced. */ advanced?: Partial; } /** Options for the cluster manager. */ export interface ClusterManagerOptions extends ClusterManagerCreateOptions { /** Which mode to use for clustering. */ mode: T; /** Number of total internal shards or -1. */ totalShards: number; /** Number of total Clusters/Process to spawn. */ totalClusters: number; /** Number of shards per cluster. */ shardsPerClusters: number; /** Whether a cluster should acknowledge heartbeat while the internal client is not ready. */ respondToHeartbeatWhenNotReady: boolean; /** An Array of Internal Shards Ids, which should get spawned. */ shardList: number[]; /** An Array of Ids to assign to the spawned Clusters, when the default id scheme is not wanted. */ clusterList: number[]; /** Options to pass to the spawn, respawn method. */ spawnOptions: Required; /** Heartbeat options. */ heartbeat: Required; /** Package type. */ packageType: PackageType | null; } /** Advanced options for cluster manager. */ export interface ClusterManagerAdvancedOptions { /** Whether to spam when debugging. */ logMessagesInDebug: boolean; /** Whether to ignore dead clusters, WARNING: If you have null-checks in your code, this might false trigger that whatever you want to do results in null (ei. getting guild from cluster that is dead). */ proceedBroadcastIfClusterDead: boolean; } /** Data of ClusterClient. */ export interface ClusterClientData { /** List of shards that are assigned to this cluster. */ ShardList: number[]; /** The total amount of shards. */ TotalShards: number; /** The total amount of clusters. */ ClusterCount: number; /** The id of the cluster. */ ClusterId: number; /** Mode of the manager. */ ClusterManagerMode: ClusteringMode; /** Mode of the queue. */ ClusterQueueMode?: 'auto' | 'manual'; /** Whether the client should acknowledge heartbeat while not ready. */ RespondToHeartbeatWhenNotReady: boolean; /** First shard id of the cluster. */ FirstShardId: number; /** Last shard id of the cluster. */ LastShardId: number; } /** Spawn options for the cluster. */ export interface ClusterSpawnOptions { /** How long to wait between spawning each cluster. */ delay?: number; /** How long to wait for a cluster to become ready before killing it and retrying. */ timeout?: number; } /** Data for the heartbeat system. */ export interface ClusterHeartbeatOptions { /** Whether the heartbeat system is enabled. */ enabled: boolean; /** Maximum amount of missed heartbeats a cluster can have in the interval. */ maxMissedHeartbeats?: number; /** Maximum amount of restarts a cluster can have in the interval. */ maxRestarts?: number; /** Interval in milliseconds between each heartbeat. */ interval?: number; /** Timeout in milliseconds after which a cluster will be considered as unresponsive. */ timeout?: number; } /** Options for the queue. */ export interface QueueOptions { /** Whether the spawn queue be automatically managed. */ mode?: 'auto' | 'manual'; /** Time to wait until next item. */ timeout?: number; } /** Kill options for the cluster. */ export interface ClusterKillOptions { /** The reason for killing the cluster. */ reason: string; } /** Eval options for the cluster. */ export interface EvalOptions { /** Only run the script in a single cluster or set of clusters. */ cluster?: number | number[]; /** On what shard to run the script. */ shard?: number | number[]; /** On what guild to run the script. */ guildId?: string; /** Context to use for the script. */ context?: T; /** Timeout before the script is cancelled. */ timeout?: number; /** Whether to continue running the script even if one of the clusters returns an error. */ useAllSettled?: boolean; } /** Mode for reclustering. */ export type ReClusterRestartMode = 'gracefulSwitch' | 'rolling'; /** Options for reclustering. */ export interface ReClusterOptions { /** The new totalShards of the bot. */ totalShards?: number; /** The amount of totalClusters to spread the shards over all clusters. */ totalClusters?: number; /** The amount of shards per cluster. */ shardsPerClusters?: number; /** The restartMode of the clusterManager, gracefulSwitch = waits until all new clusters have spawned, rolling = once the Cluster is ready, the old cluster will be killed. */ restartMode?: ReClusterRestartMode; } /** Options for storing promises. */ export interface StoredPromise { /** Timeout before promise is canceled. */ timeout?: NodeJS.Timeout; /** Resolves the promise. */ resolve(value: unknown): void; /** Return an error if failed. */ reject(error: Error): void; } /** Events that manager emits. */ export interface ClusterManagerEvents { /** Emits when client sends a request via IPC. */ clientRequest: [message: ProcessMessage]; /** Emits when cluster is created. */ clusterCreate: [cluster: Cluster]; /** Emits when cluster is ready. */ clusterReady: [cluster: Cluster]; /** Emits when any message is sent from IPC. */ message: [message: ProcessMessage]; /** Debug events. */ debug: [debugMessage: string]; /** When all manager's clsuters are ready. */ ready: [manager: ClusterManager]; } /** Events that cluster emits. */ export interface ClusterEvents { /** Emits when any message is sent from IPC. */ message: [message: ProcessMessage]; /** Emits when cluster dies. */ death: [cluster: Cluster, thread: ChildProcess | Worker | null]; /** Emits when cluster is spawned. */ spawn: [cluster: Cluster, thread: ChildProcess | Worker | null]; /** Emits when cluster is ready. */ ready: [cluster: Cluster]; /** Emits when debug message is sent. */ debug: [message: string]; /** Emits when there is an error. */ error: [error: Error]; } /** Events that cluster client emits. */ export interface ClusterClientEvents { /** Emits when all clusters are ready. */ managerReady: []; /** Emits when message is sent from IPC. */ message: [message: ProcessMessage]; /** Emits when cluster is ready. */ ready: [clusterClient: ClusterClient]; /** Emits when debug message is sent. */ debug: [message: string]; }