lunibee 0.1.8 → 0.2.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.
Files changed (44) hide show
  1. package/README.md +2 -0
  2. package/dist/builders/components.d.ts +5 -0
  3. package/dist/builders/index.js +72 -12
  4. package/dist/builders/index.js.map +5 -5
  5. package/dist/collection/index.d.ts +68 -1
  6. package/dist/collection/index.js +334 -1
  7. package/dist/collection/index.js.map +3 -3
  8. package/dist/core/collector.d.ts +13 -0
  9. package/dist/core/events.d.ts +29 -3
  10. package/dist/core/index.d.ts +22 -8
  11. package/dist/core/index.js +1526 -124
  12. package/dist/core/index.js.map +26 -22
  13. package/dist/core/permissions.d.ts +48 -0
  14. package/dist/index.js +1578 -268
  15. package/dist/index.js.map +30 -29
  16. package/dist/managers/advanced.d.ts +116 -0
  17. package/dist/managers/base.d.ts +13 -2
  18. package/dist/managers/emoji.d.ts +1 -1
  19. package/dist/managers/guild.d.ts +28 -2
  20. package/dist/managers/index.d.ts +37 -5
  21. package/dist/managers/index.js +870 -152
  22. package/dist/managers/index.js.map +18 -16
  23. package/dist/managers/message.d.ts +10 -1
  24. package/dist/rest/errors.d.ts +33 -0
  25. package/dist/rest/index.d.ts +1 -1
  26. package/dist/rest/index.js +52 -6
  27. package/dist/rest/index.js.map +5 -5
  28. package/dist/rest/routes.d.ts +20 -0
  29. package/dist/sharding/index.d.ts +29 -0
  30. package/dist/sharding/index.js +99 -15
  31. package/dist/sharding/index.js.map +8 -8
  32. package/dist/structures/base.d.ts +2 -0
  33. package/dist/structures/index.js +96 -42
  34. package/dist/structures/index.js.map +10 -9
  35. package/dist/structures/interactions.d.ts +26 -0
  36. package/dist/types/gateway.d.ts +16 -0
  37. package/dist/types/index.d.ts +55 -1
  38. package/dist/types/index.js.map +2 -2
  39. package/dist/voice/index.d.ts +3 -0
  40. package/dist/voice/index.js +15 -1
  41. package/dist/voice/index.js.map +3 -3
  42. package/dist/ws/index.js +13 -5
  43. package/dist/ws/index.js.map +6 -6
  44. package/package.json +14 -14
@@ -1,3 +1,5 @@
1
+ import { User } from "./base.js";
2
+ import { GuildMember } from "./resources.js";
1
3
  /** Discord interaction type constants. */
2
4
  export declare const InteractionType: {
3
5
  readonly Ping: 1;
@@ -34,6 +36,8 @@ export interface InteractionClient {
34
36
  /** Edits the original interaction response. @param token Interaction token. @param data Message payload. @returns Discord response. @throws {Error} When REST fails. */ editInteractionReply(token: string, data: InteractionReplyOptions): Promise<unknown>;
35
37
  /** Deletes the original interaction response. @param token Interaction token. @returns Promise fulfilled after deletion. @throws {Error} When REST fails. */ deleteInteractionReply(token: string): Promise<void>;
36
38
  /** Sends a follow-up interaction webhook message. @param token Interaction token. @param data Message payload. @returns Discord response. @throws {Error} When REST fails. */ followUpInteraction(token: string, data: InteractionReplyOptions): Promise<unknown>;
39
+ /** Reads, edits or deletes an interaction webhook message (`@original` or a follow-up ID). Optional; required for {@link Interaction.fetchReply}, {@link Interaction.editFollowUp} and {@link Interaction.deleteFollowUp}. */
40
+ interactionWebhookMessage?(method: "GET" | "PATCH" | "DELETE", applicationId: string, token: string, messageId: string, data?: InteractionReplyOptions): Promise<unknown>;
37
41
  }
38
42
  export { CommandOptions, type APIInteractionDataOption } from "./options.js";
39
43
  import { CommandOptions } from "./options.js";
@@ -76,6 +80,28 @@ export declare class Interaction<TData extends InteractionData = InteractionData
76
80
  /** Whether this is a channel select menu interaction. */ isChannelSelectMenu(): this is ComponentInteraction;
77
81
  /** Whether this is any select menu interaction. */ isAnySelectMenu(): this is ComponentInteraction;
78
82
  /** Ensures the interaction has not already been acknowledged. @returns Nothing. @throws {Error} When already acknowledged. */ protected assertUnacknowledged(): void;
83
+ /**
84
+ * Sends the initial response exactly once. The in-flight flag is set
85
+ * before the request, so two concurrent calls cannot both send; it is
86
+ * cleared if the request fails so the caller may try again.
87
+ */
88
+ protected acknowledge(response: InteractionResponse, state: "replied" | "deferred"): Promise<unknown>;
89
+ /** The invoking user (from `member.user` in guilds, `user` in DMs). */
90
+ get user(): User | null;
91
+ /** The invoking guild member, or null outside a guild. */
92
+ get member(): GuildMember | null;
93
+ /** Unix timestamp (ms) at which the interaction was created, from its snowflake. */
94
+ get createdTimestamp(): number;
95
+ /** When the interaction token stops working (15 minutes after creation). */
96
+ get expiresAt(): Date;
97
+ /** Whether the token has expired; no response, edit or follow-up can succeed after that. */
98
+ get isExpired(): boolean;
99
+ /** Fetches the original response message. */
100
+ fetchReply(): Promise<unknown>;
101
+ /** Edits a follow-up message. @param messageId Follow-up message ID. */
102
+ editFollowUp(messageId: string, options: InteractionReplyOptions | string): Promise<unknown>;
103
+ /** Deletes a follow-up message. @param messageId Follow-up message ID. */
104
+ deleteFollowUp(messageId: string): Promise<void>;
79
105
  /** Ensures the interaction has been acknowledged. @returns Nothing. @throws {Error} When not acknowledged. */ protected assertAcknowledged(): void;
80
106
  /** Posts a raw interaction response callback. */
81
107
  protected postResponse(response: InteractionResponse): Promise<unknown>;
@@ -160,6 +160,22 @@ export interface ClientOptions {
160
160
  intents: GatewayIntentResolvable;
161
161
  gateway?: GatewayOptions;
162
162
  rest?: RESTOptions;
163
+ /** Opt-in bounded per-channel message cache. Messages are not cached by default. */
164
+ messageCache?: {
165
+ maxSize?: number;
166
+ ttl?: number;
167
+ };
168
+ /**
169
+ * Which resources the client keeps from Gateway events. Everything is
170
+ * cached by default; large bots can turn off what they do not read.
171
+ * Events are still emitted either way.
172
+ */
173
+ cache?: {
174
+ users?: boolean;
175
+ members?: boolean;
176
+ roles?: boolean;
177
+ emojis?: boolean;
178
+ };
163
179
  }
164
180
  /** Gateway connection configuration. */
165
181
  export interface GatewayOptions {
@@ -330,7 +330,7 @@ export interface APIChannel {
330
330
  type: number;
331
331
  guild_id?: Snowflake;
332
332
  position?: number;
333
- permission_overwrites?: Array<Record<string, unknown>>;
333
+ permission_overwrites?: APIOverwrite[];
334
334
  name?: string | null;
335
335
  topic?: string | null;
336
336
  nsfw?: boolean;
@@ -793,3 +793,57 @@ export interface ApplicationCommandData {
793
793
  dm_permission?: boolean;
794
794
  nsfw?: boolean;
795
795
  }
796
+ /** A channel permission overwrite for a role (type 0) or member (type 1). */
797
+ export interface APIOverwrite {
798
+ id: Snowflake;
799
+ type: 0 | 1;
800
+ /** Allowed permission bits as a decimal string. */
801
+ allow: string;
802
+ /** Denied permission bits as a decimal string. */
803
+ deny: string;
804
+ }
805
+ /** Raw Discord soundboard sound. */
806
+ export interface APISoundboardSound {
807
+ sound_id: string;
808
+ name: string;
809
+ volume: number;
810
+ emoji_id: string | null;
811
+ emoji_name: string | null;
812
+ guild_id?: string;
813
+ available: boolean;
814
+ user?: UserData;
815
+ }
816
+ /** Raw Discord SKU. */
817
+ export interface APISKU {
818
+ id: string;
819
+ type: number;
820
+ application_id: string;
821
+ name: string;
822
+ slug: string;
823
+ flags: number;
824
+ }
825
+ /** Raw Discord entitlement. */
826
+ export interface APIEntitlement {
827
+ id: string;
828
+ sku_id: string;
829
+ application_id: string;
830
+ user_id?: string;
831
+ guild_id?: string;
832
+ type: number;
833
+ deleted: boolean;
834
+ starts_at?: string | null;
835
+ ends_at?: string | null;
836
+ consumed?: boolean;
837
+ }
838
+ /** Raw Discord subscription. */
839
+ export interface APISubscription {
840
+ id: string;
841
+ user_id: string;
842
+ sku_ids: string[];
843
+ entitlement_ids: string[];
844
+ current_period_start: string;
845
+ current_period_end: string;
846
+ status: number;
847
+ canceled_at: string | null;
848
+ country?: string;
849
+ }
@@ -2,8 +2,8 @@
2
2
  "version": 3,
3
3
  "sources": ["../../packages/types/src/gateway.ts", "../../packages/types/src/index.ts"],
4
4
  "sourcesContent": [
5
- "// ─── Gateway Intents ─────────────────────────────────────────────────────────\n\n/** Gateway intent bit flags supported by Discord (PascalCase). */\nexport const GatewayIntentBits = {\n Guilds: 1 << 0,\n GuildMembers: 1 << 1,\n GuildModeration: 1 << 2,\n GuildExpressions: 1 << 3,\n GuildIntegrations: 1 << 4,\n GuildWebhooks: 1 << 5,\n GuildInvites: 1 << 6,\n GuildVoiceStates: 1 << 7,\n GuildPresences: 1 << 8,\n GuildMessages: 1 << 9,\n GuildMessageReactions: 1 << 10,\n GuildMessageTyping: 1 << 11,\n DirectMessages: 1 << 12,\n DirectMessageReactions: 1 << 13,\n DirectMessageTyping: 1 << 14,\n MessageContent: 1 << 15,\n GuildScheduledEvents: 1 << 16,\n AutoModerationConfiguration: 1 << 20,\n AutoModerationExecution: 1 << 21,\n GuildMessagePolls: 1 << 24,\n DirectMessagePolls: 1 << 25,\n} as const;\n\n/** Idiomatic camelCase Gateway intent bit flags supported by Discord. */\nexport const IntentBits = {\n guild: 1 << 0,\n guilds: 1 << 0,\n guildMembers: 1 << 1,\n guildModeration: 1 << 2,\n guildBans: 1 << 2,\n guildExpressions: 1 << 3,\n guildEmojis: 1 << 3,\n guildEmojisAndStickers: 1 << 3,\n guildIntegrations: 1 << 4,\n guildWebhooks: 1 << 5,\n guildInvites: 1 << 6,\n guildVoiceStates: 1 << 7,\n guildPresences: 1 << 8,\n guildMessages: 1 << 9,\n guildMessage: 1 << 9,\n guildMessageReactions: 1 << 10,\n guildMessageTyping: 1 << 11,\n directMessages: 1 << 12,\n directMessageReactions: 1 << 13,\n directMessageTyping: 1 << 14,\n messageContent: 1 << 15,\n guildScheduledEvents: 1 << 16,\n autoModerationConfiguration: 1 << 20,\n autoModerationExecution: 1 << 21,\n guildMessagePolls: 1 << 24,\n directMessagePolls: 1 << 25,\n} as const;\n\n/** Alias for IntentBits. */\nexport const Intents = IntentBits;\n\n/** Gateway intent resolvable value (single bitfield, enum key, or array of bitfields/strings). */\nexport type GatewayIntentResolvable =\n | number\n | keyof typeof GatewayIntentBits\n | keyof typeof IntentBits\n | (\n | number\n | keyof typeof GatewayIntentBits\n | keyof typeof IntentBits\n | string\n )[]\n | { readonly bitfield: number };\n\n/** Resolves any GatewayIntentResolvable into a raw bitfield integer. */\nexport function resolveGatewayIntents(\n intents: GatewayIntentResolvable,\n): number {\n if (typeof intents === \"number\") return intents;\n if (intents && typeof intents === \"object\" && !Array.isArray(intents))\n return intents.bitfield;\n if (Array.isArray(intents)) {\n return intents.reduce<number>((acc, intent) => {\n return acc | resolveGatewayIntents(intent as any);\n }, 0);\n }\n if (typeof intents === \"string\") {\n if (intents in GatewayIntentBits)\n return (GatewayIntentBits as Record<string, number>)[intents]!;\n if (intents in IntentBits)\n return (IntentBits as Record<string, number>)[intents]!;\n const lower = intents.charAt(0).toLowerCase() + intents.slice(1);\n if (lower in IntentBits)\n return (IntentBits as Record<string, number>)[lower]!;\n const num = Number(intents);\n if (!Number.isNaN(num)) return num;\n }\n return 0;\n}\n\n/**\n * Discord.js-familiar intent bitfield.\n * @example new IntentsBitField([IntentsBitField.Flags.Guilds, \"GuildMessages\"])\n */\nexport class IntentsBitField {\n /** Intent flag values by name. */\n public static readonly Flags = GatewayIntentBits;\n /** Raw intent bitfield. */\n public bitfield: number;\n\n public constructor(bits: GatewayIntentResolvable = 0) {\n this.bitfield = resolveGatewayIntents(bits);\n }\n\n /** Whether every given intent is set. */\n public has(bits: GatewayIntentResolvable): boolean {\n const resolved = resolveGatewayIntents(bits);\n return (this.bitfield & resolved) === resolved;\n }\n\n /** Whether any given intent is set. */\n public any(bits: GatewayIntentResolvable): boolean {\n return (this.bitfield & resolveGatewayIntents(bits)) !== 0;\n }\n\n /** Adds intents in place. @returns This bitfield. */\n public add(...bits: GatewayIntentResolvable[]): this {\n for (const bit of bits) this.bitfield |= resolveGatewayIntents(bit);\n return this;\n }\n\n /** Removes intents in place. @returns This bitfield. */\n public remove(...bits: GatewayIntentResolvable[]): this {\n for (const bit of bits) this.bitfield &= ~resolveGatewayIntents(bit);\n return this;\n }\n\n /** Names of the set intents. */\n public toArray(): (keyof typeof GatewayIntentBits)[] {\n return (\n Object.keys(GatewayIntentBits) as (keyof typeof GatewayIntentBits)[]\n ).filter((name) => this.has(GatewayIntentBits[name]));\n }\n\n /** Whether this equals another bitfield. */\n public equals(bits: GatewayIntentResolvable): boolean {\n return this.bitfield === resolveGatewayIntents(bits);\n }\n\n public valueOf(): number {\n return this.bitfield;\n }\n\n public toJSON(): number {\n return this.bitfield;\n }\n}\n\n// ─── Gateway Config ───────────────────────────────────────────────────────────\n\n/** Gateway connection properties (OS, browser, device). */\nexport interface GatewayProperties {\n os?: string;\n browser?: string;\n device?: string;\n [key: string]: unknown;\n}\n/** Gateway presence activity. */\nexport interface GatewayPresenceActivity {\n name: string;\n type?: number;\n url?: string;\n state?: string;\n}\n/** Gateway presence data. */\nexport interface GatewayPresence {\n status?: \"online\" | \"dnd\" | \"idle\" | \"invisible\" | \"offline\";\n activities?: GatewayPresenceActivity[];\n afk?: boolean;\n since?: number | null;\n}\n/** Client configuration. */\nexport interface ClientOptions {\n token: string;\n intents: GatewayIntentResolvable;\n gateway?: GatewayOptions;\n rest?: RESTOptions;\n}\n/** Gateway connection configuration. */\nexport interface GatewayOptions {\n intents?: GatewayIntentResolvable;\n reconnect?: boolean;\n maxReconnectAttempts?: number;\n reconnectBaseDelay?: number;\n reconnectMaxDelay?: number;\n shardId?: number;\n shardCount?: number;\n properties?: GatewayProperties;\n presence?: GatewayPresence;\n}\n\n/** REST request configuration. */\nexport interface RESTOptions {\n timeout?: number;\n retries?: number;\n baseURL?: string;\n}\n",
6
- "/** Discord API snowflake identifier. */\nexport type Snowflake = string;\n\nexport * from \"./gateway.js\";\nexport * from \"./gateway-events.js\";\n\n// ─── Core Discord Objects ─────────────────────────────────────────────────────\n\n/** Discord user object. */\nexport interface UserData {\n id: Snowflake;\n username: string;\n discriminator?: string;\n global_name?: string | null;\n avatar?: string | null;\n bot?: boolean;\n system?: boolean;\n public_flags?: number;\n}\n/** Current authenticated bot user. */\nexport type ClientUser = UserData;\n/** Discord Gateway payload envelope. */\nexport interface GatewayPayload<T = unknown> {\n op: number;\n d: T | null;\n s: number | null;\n t: string | null;\n}\n/** Generic Discord API error payload. */\nexport interface APIError {\n code?: number;\n message?: string;\n errors?: Record<string, unknown>;\n}\n\n// ─── Discord Flags & Enums ────────────────────────────────────────────────────\n\n/** Discord message flags. */\nexport const MessageFlags = {\n Crossposted: 1,\n IsCrosspost: 2,\n SuppressEmbeds: 4,\n SourceMessageDeleted: 8,\n Urgent: 16,\n HasThread: 32,\n Ephemeral: 64,\n Loading: 128,\n IsComponentsV2: 32768,\n} as const;\n\n/** Discord channel types. */\nexport const ChannelType = {\n GuildText: 0,\n DM: 1,\n GuildVoice: 2,\n GroupDM: 3,\n GuildCategory: 4,\n GuildAnnouncement: 5,\n AnnouncementThread: 10,\n PublicThread: 11,\n PrivateThread: 12,\n GuildStageVoice: 13,\n GuildDirectory: 14,\n GuildForum: 15,\n GuildMedia: 16,\n} as const;\n\n/** Discord component types. */\nexport const ComponentType = {\n ActionRow: 1,\n Button: 2,\n StringSelect: 3,\n TextInput: 4,\n UserSelect: 5,\n RoleSelect: 6,\n MentionableSelect: 7,\n ChannelSelect: 8,\n Section: 9,\n TextDisplay: 10,\n Thumbnail: 11,\n MediaGallery: 12,\n File: 13,\n Separator: 14,\n ContentInventoryEntry: 16,\n Container: 17,\n} as const;\n\n/** Discord button style types. */\nexport const ButtonStyle = {\n Primary: 1,\n Secondary: 2,\n Success: 3,\n Danger: 4,\n Link: 5,\n Premium: 6,\n} as const;\n\n/** Discord text input style types. */\nexport const TextInputStyle = {\n Short: 1,\n Paragraph: 2,\n} as const;\n\n/** Discord interaction response types. */\nexport const InteractionResponseType = {\n Pong: 1,\n ChannelMessage: 4,\n DeferredChannelMessage: 5,\n DeferredMessageUpdate: 6,\n MessageUpdate: 7,\n Autocomplete: 8,\n Modal: 9,\n} as const;\n\n/** Discord sticker format types. */\nexport const StickerFormatType = {\n PNG: 1,\n APNG: 2,\n Lottie: 3,\n GIF: 4,\n} as const;\n\n/** Discord sticker types. */\nexport const StickerType = {\n Standard: 1,\n Guild: 2,\n} as const;\n\n/** Discord verification levels. */\nexport const VerificationLevel = {\n None: 0,\n Low: 1,\n Medium: 2,\n High: 3,\n VeryHigh: 4,\n} as const;\n\n/** Discord premium tiers. */\nexport const PremiumTier = {\n None: 0,\n Tier1: 1,\n Tier2: 2,\n Tier3: 3,\n} as const;\n\n// ─── Embeds ───────────────────────────────────────────────────────────────────\n\n/** Raw Discord embed footer object. */\nexport interface APIEmbedFooter {\n text: string;\n icon_url?: string;\n proxy_icon_url?: string;\n}\n/** Raw Discord embed image/thumbnail/video object. */\nexport interface APIEmbedMedia {\n url: string;\n proxy_url?: string;\n height?: number;\n width?: number;\n}\n/** Raw Discord embed provider object. */\nexport interface APIEmbedProvider {\n name?: string;\n url?: string;\n}\n/** Raw Discord embed author object. */\nexport interface APIEmbedAuthor {\n name: string;\n url?: string;\n icon_url?: string;\n proxy_icon_url?: string;\n}\n/** Raw Discord embed field object. */\nexport interface APIEmbedField {\n name: string;\n value: string;\n inline?: boolean;\n}\n/** Raw Discord embed object. */\nexport interface APIEmbed {\n title?: string;\n type?: string;\n description?: string;\n url?: string;\n timestamp?: string;\n color?: number;\n footer?: APIEmbedFooter;\n image?: APIEmbedMedia;\n thumbnail?: APIEmbedMedia;\n video?: APIEmbedMedia;\n provider?: APIEmbedProvider;\n author?: APIEmbedAuthor;\n fields?: APIEmbedField[];\n}\n\n// ─── Message Components ───────────────────────────────────────────────────────\n\n/** Raw Discord select menu option. */\nexport interface APISelectMenuOption {\n label: string;\n value: string;\n description?: string;\n emoji?: APIPartialEmoji;\n default?: boolean;\n}\n/** Raw Discord emoji (partial, as used in components). */\nexport interface APIPartialEmoji {\n id?: Snowflake | null;\n name?: string | null;\n animated?: boolean;\n}\n/** Raw Discord button component. */\nexport interface APIButtonComponent {\n type: 2;\n style: number;\n label?: string;\n emoji?: APIPartialEmoji;\n custom_id?: string;\n url?: string;\n sku_id?: string;\n disabled?: boolean;\n}\n/** Raw Discord select menu component. */\nexport interface APISelectMenuComponent {\n type: 3 | 5 | 6 | 7 | 8;\n custom_id: string;\n options?: APISelectMenuOption[];\n channel_types?: number[];\n placeholder?: string;\n min_values?: number;\n max_values?: number;\n disabled?: boolean;\n}\n/** Raw Discord text input component. */\nexport interface APITextInputComponent {\n type: 4;\n custom_id: string;\n style: number;\n label: string;\n min_length?: number;\n max_length?: number;\n required?: boolean;\n value?: string;\n placeholder?: string;\n}\n/** Union of all raw message component types. */\nexport type APIMessageActionRowComponent =\n APIButtonComponent | APISelectMenuComponent | APITextInputComponent;\n/** Raw Discord action row component. */\nexport interface APIActionRowComponent {\n type: 1;\n id?: number;\n components: APIMessageActionRowComponent[];\n}\n/** Union including action rows and V2 components. */\nexport type APIMessageComponent =\n APIActionRowComponent | { type: Exclude<number, 1>; [key: string]: any };\n\n// ─── Attachments ─────────────────────────────────────────────────────────────\n\n/** Raw Discord attachment object. */\nexport interface APIAttachment {\n id: Snowflake;\n filename: string;\n description?: string | null;\n content_type?: string;\n size: number;\n url: string;\n proxy_url: string;\n height?: number | null;\n width?: number | null;\n ephemeral?: boolean;\n duration_secs?: number;\n waveform?: string;\n flags?: number;\n}\n\n// ─── Stickers ────────────────────────────────────────────────────────────────\n\n/** Compact sticker item as included in messages. */\nexport interface APIStickerItem {\n id: Snowflake;\n name: string;\n format_type: number;\n}\n/** Full Discord sticker object. */\nexport interface APISticker {\n id: Snowflake;\n pack_id?: Snowflake;\n name: string;\n description?: string | null;\n tags?: string;\n type: number;\n format_type: number;\n available?: boolean;\n guild_id?: Snowflake;\n user?: UserData;\n sort_value?: number;\n}\n\n// ─── Messages ────────────────────────────────────────────────────────────────\n\n/** Raw Discord message reference. */\nexport interface APIMessageReference {\n type?: number;\n message_id?: Snowflake;\n channel_id?: Snowflake;\n guild_id?: Snowflake;\n fail_if_not_exists?: boolean;\n}\n/** Raw Discord message reaction. */\nexport interface APIMessageReaction {\n count: number;\n count_details?: Record<string, number>;\n me?: boolean;\n me_burst?: boolean;\n emoji: APIPartialEmoji;\n burst_colors?: string[];\n}\n/** Raw Discord message object. */\nexport interface APIMessage {\n id: Snowflake;\n channel_id: Snowflake;\n author: UserData;\n content: string;\n timestamp?: string;\n edited_timestamp?: string | null;\n tts?: boolean;\n mention_everyone?: boolean;\n mentions?: UserData[];\n mention_roles?: Snowflake[];\n mention_channels?: Array<Record<string, unknown>>;\n attachments?: APIAttachment[];\n embeds?: APIEmbed[];\n reactions?: APIMessageReaction[];\n nonce?: string | number | null;\n pinned?: boolean;\n webhook_id?: Snowflake;\n type?: number;\n activity?: Record<string, unknown>;\n application?: Record<string, unknown>;\n application_id?: Snowflake;\n message_reference?: APIMessageReference;\n flags?: number;\n referenced_message?: APIMessage | null;\n interaction_metadata?: Record<string, unknown>;\n thread?: Record<string, unknown>;\n components?: APIMessageComponent[];\n sticker_items?: APIStickerItem[];\n stickers?: APISticker[];\n position?: number;\n role_subscription_data?: Record<string, unknown>;\n purchase_notification?: Record<string, unknown>;\n poll?: Record<string, unknown>;\n guild_id?: Snowflake;\n}\n\n// ─── Channels ────────────────────────────────────────────────────────────────\n\n/** Raw Discord channel object. */\nexport interface APIChannel {\n id: Snowflake;\n type: number;\n guild_id?: Snowflake;\n position?: number;\n permission_overwrites?: Array<Record<string, unknown>>;\n name?: string | null;\n topic?: string | null;\n nsfw?: boolean;\n last_message_id?: Snowflake | null;\n bitrate?: number;\n user_limit?: number;\n rate_limit_per_user?: number;\n recipients?: UserData[];\n icon?: string | null;\n owner_id?: Snowflake;\n application_id?: Snowflake;\n parent_id?: Snowflake | null;\n last_pin_timestamp?: string | null;\n rtc_region?: string | null;\n video_quality_mode?: number;\n message_count?: number;\n member_count?: number;\n thread_metadata?: APIThreadMetadata;\n default_auto_archive_duration?: number;\n flags?: number;\n total_message_sent?: number;\n available_tags?: APIForumTag[];\n default_reaction_emoji?: APIPartialEmoji | null;\n default_thread_rate_limit_per_user?: number;\n default_sort_order?: number | null;\n default_forum_layout?: number;\n}\n\n/** Raw Discord thread metadata. */\nexport interface APIThreadMetadata {\n archived: boolean;\n auto_archive_duration: number;\n archive_timestamp: string;\n locked: boolean;\n invitable?: boolean;\n create_timestamp?: string | null;\n}\n\n/** Raw Discord forum tag. */\nexport interface APIForumTag {\n id: Snowflake;\n name: string;\n moderated: boolean;\n emoji_id?: Snowflake | null;\n emoji_name?: string | null;\n}\n\n/** Raw Discord thread member. */\nexport interface APIThreadMember {\n id?: Snowflake;\n user_id?: Snowflake;\n join_timestamp: string;\n flags: number;\n member?: APIGuildMember;\n}\n\n// ─── Roles ────────────────────────────────────────────────────────────────────\n\n/** Raw Discord role object. */\nexport interface APIRole {\n id: Snowflake;\n name: string;\n color: number;\n hoist: boolean;\n icon?: string | null;\n unicode_emoji?: string | null;\n position: number;\n permissions: string;\n managed: boolean;\n mentionable: boolean;\n tags?: Record<string, unknown>;\n flags?: number;\n}\n\n// ─── Emoji ────────────────────────────────────────────────────────────────────\n\n/** Raw Discord emoji object. */\nexport interface APIEmoji {\n id: Snowflake | null;\n name: string | null;\n roles?: Snowflake[];\n user?: UserData;\n require_colons?: boolean;\n managed?: boolean;\n animated?: boolean;\n available?: boolean;\n}\n\n// ─── Guilds ───────────────────────────────────────────────────────────────────\n\n/** Raw Discord guild object. */\nexport interface APIGuild {\n id: Snowflake;\n name: string;\n icon?: string | null;\n icon_hash?: string | null;\n splash?: string | null;\n discovery_splash?: string | null;\n owner?: boolean;\n owner_id?: Snowflake;\n permissions?: string;\n afk_channel_id?: Snowflake | null;\n afk_timeout?: number;\n widget_enabled?: boolean;\n widget_channel_id?: Snowflake | null;\n verification_level?: number;\n default_message_notifications?: number;\n explicit_content_filter?: number;\n roles?: APIRole[];\n emojis?: APIEmoji[];\n stickers?: APISticker[];\n features?: string[];\n mfa_level?: number;\n application_id?: Snowflake | null;\n system_channel_id?: Snowflake | null;\n system_channel_flags?: number;\n rules_channel_id?: Snowflake | null;\n max_presences?: number | null;\n max_members?: number;\n vanity_url_code?: string | null;\n description?: string | null;\n banner?: string | null;\n premium_tier?: number;\n premium_subscription_count?: number;\n preferred_locale?: string;\n public_updates_channel_id?: Snowflake | null;\n max_video_channel_users?: number;\n approximate_member_count?: number;\n approximate_presence_count?: number;\n nsfw_level?: number;\n safety_alerts_channel_id?: Snowflake | null;\n member_count?: number;\n}\n\n// ─── Welcome Screen ───────────────────────────────────────────────────────────\n\nexport interface APIWelcomeScreenChannel {\n channel_id: Snowflake;\n description: string;\n emoji_id: Snowflake | null;\n emoji_name: string | null;\n}\n\nexport interface APIGuildWelcomeScreen {\n description: string | null;\n welcome_channels: APIWelcomeScreenChannel[];\n}\n\n// ─── Guild Onboarding ─────────────────────────────────────────────────────────\n\nexport interface APIOnboardingPromptOption {\n id: Snowflake;\n channel_ids: Snowflake[];\n role_ids: Snowflake[];\n emoji?: APIPartialEmoji;\n title: string;\n description: string | null;\n}\n\nexport interface APIOnboardingPrompt {\n id: Snowflake;\n type: number;\n options: APIOnboardingPromptOption[];\n title: string;\n single_select: boolean;\n required: boolean;\n in_onboarding: boolean;\n}\n\nexport interface APIGuildOnboarding {\n guild_id: Snowflake;\n prompts: APIOnboardingPrompt[];\n default_channel_ids: Snowflake[];\n enabled: boolean;\n mode: number;\n}\n\n/** Raw Discord guild member object. */\nexport interface APIGuildMember {\n user: UserData;\n nick?: string | null;\n avatar?: string | null;\n roles: Snowflake[];\n joined_at: string;\n premium_since?: string | null;\n deaf?: boolean;\n mute?: boolean;\n flags?: number;\n pending?: boolean;\n permissions?: string;\n communication_disabled_until?: string | null;\n guild_id?: Snowflake;\n}\n\n// ─── Voice ────────────────────────────────────────────────────────────────────\n\n/** Raw Discord voice state object. */\nexport interface APIVoiceState {\n guild_id?: Snowflake;\n channel_id?: Snowflake | null;\n user_id: Snowflake;\n member?: APIGuildMember;\n session_id: string;\n deaf: boolean;\n mute: boolean;\n self_deaf: boolean;\n self_mute: boolean;\n self_stream?: boolean;\n self_video: boolean;\n suppress: boolean;\n request_to_speak_timestamp?: string | null;\n}\n\n/** Raw Discord voice server update event. */\nexport interface APIVoiceServerUpdate {\n token: string;\n guild_id: Snowflake;\n endpoint?: string | null;\n}\n\n// ─── Presence ────────────────────────────────────────────────────────────────\n\n/** Raw Discord activity object. */\nexport interface APIActivity {\n name: string;\n type: number;\n url?: string | null;\n created_at: number;\n state?: string | null;\n details?: string | null;\n emoji?: APIPartialEmoji | null;\n}\n\n/** Raw Discord presence update event. */\nexport interface APIPresenceUpdate {\n user: { id: Snowflake } & Partial<UserData>;\n guild_id: Snowflake;\n status: string;\n activities: APIActivity[];\n client_status: { desktop?: string; mobile?: string; web?: string };\n}\n\n// ─── Typing ───────────────────────────────────────────────────────────────────\n\n/** Raw Discord typing start event. */\nexport interface APITypingStart {\n channel_id: Snowflake;\n guild_id?: Snowflake;\n user_id: Snowflake;\n timestamp: number;\n member?: APIGuildMember;\n}\n\n// ─── Guilds ──────────────────────────────────────────────────────────────────\n\n/** Raw Discord guild preview. */\nexport interface APIGuildPreview {\n id: Snowflake;\n name: string;\n icon: string | null;\n splash: string | null;\n discovery_splash: string | null;\n emojis: unknown[];\n features: string[];\n approximate_member_count: number;\n approximate_presence_count: number;\n description: string | null;\n stickers: unknown[];\n}\n\n// ─── Invites ─────────────────────────────────────────────────────────────────\n\n/** Raw Discord invite. */\nexport interface APIInvite {\n code: string;\n guild?: Partial<APIGuild>;\n channel: Partial<APIChannel>;\n inviter?: UserData;\n target_type?: number;\n target_user?: UserData;\n approximate_presence_count?: number;\n approximate_member_count?: number;\n}\n\n/** Raw Discord invite create event. */\nexport interface APIInviteCreate {\n channel_id: Snowflake;\n code: string;\n created_at: string;\n guild_id?: Snowflake;\n inviter?: UserData;\n max_age: number;\n max_uses: number;\n target_type?: number;\n target_user?: UserData;\n temporary: boolean;\n uses: number;\n}\n\n/** Raw Discord invite delete event. */\nexport interface APIInviteDelete {\n channel_id: Snowflake;\n guild_id?: Snowflake;\n code: string;\n}\n\n// ─── Webhooks ────────────────────────────────────────────────────────────────\n\n/** Raw Discord webhooks update event. */\nexport interface APIWebhooksUpdate {\n guild_id: Snowflake;\n channel_id: Snowflake;\n}\n\n/** Raw Discord webhook object. */\nexport interface APIWebhook {\n id: Snowflake;\n type: number;\n guild_id?: Snowflake | null;\n channel_id?: Snowflake | null;\n user?: UserData;\n name?: string | null;\n avatar?: string | null;\n token?: string;\n application_id?: Snowflake | null;\n url?: string;\n}\n\n// ─── AutoMod ─────────────────────────────────────────────────────────────────\n\n/** Raw Discord AutoMod action. */\nexport interface APIAutoModerationAction {\n type: number;\n metadata?: {\n channel_id?: Snowflake;\n duration_seconds?: number;\n custom_message?: string;\n };\n}\n\n// ─── Audit Logs ──────────────────────────────────────────────────────────────\n\n/** Raw Discord audit log change object. */\nexport interface APIAuditLogChange {\n new_value?: unknown;\n old_value?: unknown;\n key: string;\n}\n\n/** Raw Discord audit log entry options object. */\nexport interface APIAuditLogOptions {\n app_id?: Snowflake;\n auto_moderation_rule_name?: string;\n auto_moderation_rule_trigger_type?: string;\n channel_id?: Snowflake;\n count?: string;\n delete_member_days?: string;\n id?: Snowflake;\n members_removed?: string;\n message_id?: Snowflake;\n role_name?: string;\n type?: string;\n integration_type?: string;\n}\n\n/** Raw Discord audit log entry object. */\nexport interface APIAuditLogEntry {\n target_id: string | null;\n changes?: APIAuditLogChange[];\n user_id: Snowflake | null;\n id: Snowflake;\n action_type: number;\n options?: APIAuditLogOptions;\n reason?: string;\n}\n\n/** Raw Discord audit log object. */\nexport interface APIAuditLog {\n audit_log_entries: APIAuditLogEntry[];\n guild_scheduled_events: APIGuildScheduledEvent[];\n integrations: Array<Record<string, unknown>>;\n threads: APIChannel[];\n users: UserData[];\n webhooks: APIWebhook[];\n application_commands: APIApplicationCommand[];\n auto_moderation_rules: APIAutoModerationRule[];\n}\n\n/** Raw Discord AutoMod rule object. */\nexport interface APIAutoModerationRule {\n id: Snowflake;\n guild_id: Snowflake;\n name: string;\n creator_id: Snowflake;\n event_type: number;\n trigger_type: number;\n trigger_metadata: Record<string, unknown>;\n actions: APIAutoModerationAction[];\n enabled: boolean;\n exempt_roles: Snowflake[];\n exempt_channels: Snowflake[];\n}\n\n/** Raw Discord AutoMod action execution event. */\nexport interface APIAutoModerationActionExecution {\n guild_id: Snowflake;\n action: APIAutoModerationAction;\n rule_id: Snowflake;\n rule_trigger_type: number;\n user_id: Snowflake;\n channel_id?: Snowflake;\n message_id?: Snowflake;\n alert_system_message_id?: Snowflake;\n content: string;\n matched_keyword?: string | null;\n matched_content?: string | null;\n}\n\n// ─── Scheduled Events ─────────────────────────────────────────────────────────\n\n/** Raw Discord guild scheduled event entity metadata. */\nexport interface APIGuildScheduledEventEntityMetadata {\n location?: string;\n}\n\n/** Raw Discord guild scheduled event object. */\nexport interface APIGuildScheduledEvent {\n id: Snowflake;\n guild_id: Snowflake;\n channel_id?: Snowflake | null;\n creator_id?: Snowflake | null;\n name: string;\n description?: string | null;\n scheduled_start_time: string;\n scheduled_end_time?: string | null;\n privacy_level: number;\n status: number;\n entity_type: number;\n entity_id?: Snowflake | null;\n entity_metadata?: APIGuildScheduledEventEntityMetadata | null;\n creator?: UserData;\n user_count?: number;\n image?: string | null;\n}\n\n// ─── Stage Instances ─────────────────────────────────────────────────────────\n\n/** Raw Discord stage instance object. */\nexport interface APIStageInstance {\n id: Snowflake;\n guild_id: Snowflake;\n channel_id: Snowflake;\n topic: string;\n privacy_level: number;\n discoverable_disabled?: boolean;\n guild_scheduled_event_id?: Snowflake | null;\n}\n\n// ─── Application Commands ─────────────────────────────────────────────────────\n\n/** Discord application command option types. */\nexport const ApplicationCommandOptionType = {\n SubCommand: 1,\n SubCommandGroup: 2,\n String: 3,\n Integer: 4,\n Boolean: 5,\n User: 6,\n Channel: 7,\n Role: 8,\n Mentionable: 9,\n Number: 10,\n Attachment: 11,\n} as const;\n\n/** Discord application command types. */\nexport const ApplicationCommandType = {\n ChatInput: 1,\n User: 2,\n Message: 3,\n} as const;\n\n/** Raw Discord application command option. */\nexport interface APIApplicationCommandOption {\n type: number;\n name: string;\n description: string;\n required?: boolean;\n choices?: Array<{ name: string; value: string | number }>;\n options?: APIApplicationCommandOption[];\n min_value?: number;\n max_value?: number;\n min_length?: number;\n max_length?: number;\n autocomplete?: boolean;\n channel_types?: number[];\n}\n\n/** Raw Discord application command object (from API). */\nexport interface APIApplicationCommand {\n id: Snowflake;\n type?: number;\n application_id: Snowflake;\n guild_id?: Snowflake;\n name: string;\n description: string;\n options?: APIApplicationCommandOption[];\n default_member_permissions?: string | null;\n dm_permission?: boolean;\n nsfw?: boolean;\n version: Snowflake;\n}\n\n/** Data for creating/overwriting an application command. */\nexport interface ApplicationCommandData {\n name: string;\n description: string;\n type?: number;\n options?: APIApplicationCommandOption[];\n default_member_permissions?: string | null;\n dm_permission?: boolean;\n nsfw?: boolean;\n}\n"
5
+ "// ─── Gateway Intents ─────────────────────────────────────────────────────────\n\n/** Gateway intent bit flags supported by Discord (PascalCase). */\nexport const GatewayIntentBits = {\n Guilds: 1 << 0,\n GuildMembers: 1 << 1,\n GuildModeration: 1 << 2,\n GuildExpressions: 1 << 3,\n GuildIntegrations: 1 << 4,\n GuildWebhooks: 1 << 5,\n GuildInvites: 1 << 6,\n GuildVoiceStates: 1 << 7,\n GuildPresences: 1 << 8,\n GuildMessages: 1 << 9,\n GuildMessageReactions: 1 << 10,\n GuildMessageTyping: 1 << 11,\n DirectMessages: 1 << 12,\n DirectMessageReactions: 1 << 13,\n DirectMessageTyping: 1 << 14,\n MessageContent: 1 << 15,\n GuildScheduledEvents: 1 << 16,\n AutoModerationConfiguration: 1 << 20,\n AutoModerationExecution: 1 << 21,\n GuildMessagePolls: 1 << 24,\n DirectMessagePolls: 1 << 25,\n} as const;\n\n/** Idiomatic camelCase Gateway intent bit flags supported by Discord. */\nexport const IntentBits = {\n guild: 1 << 0,\n guilds: 1 << 0,\n guildMembers: 1 << 1,\n guildModeration: 1 << 2,\n guildBans: 1 << 2,\n guildExpressions: 1 << 3,\n guildEmojis: 1 << 3,\n guildEmojisAndStickers: 1 << 3,\n guildIntegrations: 1 << 4,\n guildWebhooks: 1 << 5,\n guildInvites: 1 << 6,\n guildVoiceStates: 1 << 7,\n guildPresences: 1 << 8,\n guildMessages: 1 << 9,\n guildMessage: 1 << 9,\n guildMessageReactions: 1 << 10,\n guildMessageTyping: 1 << 11,\n directMessages: 1 << 12,\n directMessageReactions: 1 << 13,\n directMessageTyping: 1 << 14,\n messageContent: 1 << 15,\n guildScheduledEvents: 1 << 16,\n autoModerationConfiguration: 1 << 20,\n autoModerationExecution: 1 << 21,\n guildMessagePolls: 1 << 24,\n directMessagePolls: 1 << 25,\n} as const;\n\n/** Alias for IntentBits. */\nexport const Intents = IntentBits;\n\n/** Gateway intent resolvable value (single bitfield, enum key, or array of bitfields/strings). */\nexport type GatewayIntentResolvable =\n | number\n | keyof typeof GatewayIntentBits\n | keyof typeof IntentBits\n | (\n | number\n | keyof typeof GatewayIntentBits\n | keyof typeof IntentBits\n | string\n )[]\n | { readonly bitfield: number };\n\n/** Resolves any GatewayIntentResolvable into a raw bitfield integer. */\nexport function resolveGatewayIntents(\n intents: GatewayIntentResolvable,\n): number {\n if (typeof intents === \"number\") return intents;\n if (intents && typeof intents === \"object\" && !Array.isArray(intents))\n return intents.bitfield;\n if (Array.isArray(intents)) {\n return intents.reduce<number>((acc, intent) => {\n return acc | resolveGatewayIntents(intent as any);\n }, 0);\n }\n if (typeof intents === \"string\") {\n if (intents in GatewayIntentBits)\n return (GatewayIntentBits as Record<string, number>)[intents]!;\n if (intents in IntentBits)\n return (IntentBits as Record<string, number>)[intents]!;\n const lower = intents.charAt(0).toLowerCase() + intents.slice(1);\n if (lower in IntentBits)\n return (IntentBits as Record<string, number>)[lower]!;\n const num = Number(intents);\n if (!Number.isNaN(num)) return num;\n }\n return 0;\n}\n\n/**\n * Discord.js-familiar intent bitfield.\n * @example new IntentsBitField([IntentsBitField.Flags.Guilds, \"GuildMessages\"])\n */\nexport class IntentsBitField {\n /** Intent flag values by name. */\n public static readonly Flags = GatewayIntentBits;\n /** Raw intent bitfield. */\n public bitfield: number;\n\n public constructor(bits: GatewayIntentResolvable = 0) {\n this.bitfield = resolveGatewayIntents(bits);\n }\n\n /** Whether every given intent is set. */\n public has(bits: GatewayIntentResolvable): boolean {\n const resolved = resolveGatewayIntents(bits);\n return (this.bitfield & resolved) === resolved;\n }\n\n /** Whether any given intent is set. */\n public any(bits: GatewayIntentResolvable): boolean {\n return (this.bitfield & resolveGatewayIntents(bits)) !== 0;\n }\n\n /** Adds intents in place. @returns This bitfield. */\n public add(...bits: GatewayIntentResolvable[]): this {\n for (const bit of bits) this.bitfield |= resolveGatewayIntents(bit);\n return this;\n }\n\n /** Removes intents in place. @returns This bitfield. */\n public remove(...bits: GatewayIntentResolvable[]): this {\n for (const bit of bits) this.bitfield &= ~resolveGatewayIntents(bit);\n return this;\n }\n\n /** Names of the set intents. */\n public toArray(): (keyof typeof GatewayIntentBits)[] {\n return (\n Object.keys(GatewayIntentBits) as (keyof typeof GatewayIntentBits)[]\n ).filter((name) => this.has(GatewayIntentBits[name]));\n }\n\n /** Whether this equals another bitfield. */\n public equals(bits: GatewayIntentResolvable): boolean {\n return this.bitfield === resolveGatewayIntents(bits);\n }\n\n public valueOf(): number {\n return this.bitfield;\n }\n\n public toJSON(): number {\n return this.bitfield;\n }\n}\n\n// ─── Gateway Config ───────────────────────────────────────────────────────────\n\n/** Gateway connection properties (OS, browser, device). */\nexport interface GatewayProperties {\n os?: string;\n browser?: string;\n device?: string;\n [key: string]: unknown;\n}\n/** Gateway presence activity. */\nexport interface GatewayPresenceActivity {\n name: string;\n type?: number;\n url?: string;\n state?: string;\n}\n/** Gateway presence data. */\nexport interface GatewayPresence {\n status?: \"online\" | \"dnd\" | \"idle\" | \"invisible\" | \"offline\";\n activities?: GatewayPresenceActivity[];\n afk?: boolean;\n since?: number | null;\n}\n/** Client configuration. */\nexport interface ClientOptions {\n token: string;\n intents: GatewayIntentResolvable;\n gateway?: GatewayOptions;\n rest?: RESTOptions;\n /** Opt-in bounded per-channel message cache. Messages are not cached by default. */\n messageCache?: { maxSize?: number; ttl?: number };\n /**\n * Which resources the client keeps from Gateway events. Everything is\n * cached by default; large bots can turn off what they do not read.\n * Events are still emitted either way.\n */\n cache?: {\n users?: boolean;\n members?: boolean;\n roles?: boolean;\n emojis?: boolean;\n };\n}\n/** Gateway connection configuration. */\nexport interface GatewayOptions {\n intents?: GatewayIntentResolvable;\n reconnect?: boolean;\n maxReconnectAttempts?: number;\n reconnectBaseDelay?: number;\n reconnectMaxDelay?: number;\n shardId?: number;\n shardCount?: number;\n properties?: GatewayProperties;\n presence?: GatewayPresence;\n}\n\n/** REST request configuration. */\nexport interface RESTOptions {\n timeout?: number;\n retries?: number;\n baseURL?: string;\n}\n",
6
+ "/** Discord API snowflake identifier. */\nexport type Snowflake = string;\n\nexport * from \"./gateway.js\";\nexport * from \"./gateway-events.js\";\n\n// ─── Core Discord Objects ─────────────────────────────────────────────────────\n\n/** Discord user object. */\nexport interface UserData {\n id: Snowflake;\n username: string;\n discriminator?: string;\n global_name?: string | null;\n avatar?: string | null;\n bot?: boolean;\n system?: boolean;\n public_flags?: number;\n}\n/** Current authenticated bot user. */\nexport type ClientUser = UserData;\n/** Discord Gateway payload envelope. */\nexport interface GatewayPayload<T = unknown> {\n op: number;\n d: T | null;\n s: number | null;\n t: string | null;\n}\n/** Generic Discord API error payload. */\nexport interface APIError {\n code?: number;\n message?: string;\n errors?: Record<string, unknown>;\n}\n\n// ─── Discord Flags & Enums ────────────────────────────────────────────────────\n\n/** Discord message flags. */\nexport const MessageFlags = {\n Crossposted: 1,\n IsCrosspost: 2,\n SuppressEmbeds: 4,\n SourceMessageDeleted: 8,\n Urgent: 16,\n HasThread: 32,\n Ephemeral: 64,\n Loading: 128,\n IsComponentsV2: 32768,\n} as const;\n\n/** Discord channel types. */\nexport const ChannelType = {\n GuildText: 0,\n DM: 1,\n GuildVoice: 2,\n GroupDM: 3,\n GuildCategory: 4,\n GuildAnnouncement: 5,\n AnnouncementThread: 10,\n PublicThread: 11,\n PrivateThread: 12,\n GuildStageVoice: 13,\n GuildDirectory: 14,\n GuildForum: 15,\n GuildMedia: 16,\n} as const;\n\n/** Discord component types. */\nexport const ComponentType = {\n ActionRow: 1,\n Button: 2,\n StringSelect: 3,\n TextInput: 4,\n UserSelect: 5,\n RoleSelect: 6,\n MentionableSelect: 7,\n ChannelSelect: 8,\n Section: 9,\n TextDisplay: 10,\n Thumbnail: 11,\n MediaGallery: 12,\n File: 13,\n Separator: 14,\n ContentInventoryEntry: 16,\n Container: 17,\n} as const;\n\n/** Discord button style types. */\nexport const ButtonStyle = {\n Primary: 1,\n Secondary: 2,\n Success: 3,\n Danger: 4,\n Link: 5,\n Premium: 6,\n} as const;\n\n/** Discord text input style types. */\nexport const TextInputStyle = {\n Short: 1,\n Paragraph: 2,\n} as const;\n\n/** Discord interaction response types. */\nexport const InteractionResponseType = {\n Pong: 1,\n ChannelMessage: 4,\n DeferredChannelMessage: 5,\n DeferredMessageUpdate: 6,\n MessageUpdate: 7,\n Autocomplete: 8,\n Modal: 9,\n} as const;\n\n/** Discord sticker format types. */\nexport const StickerFormatType = {\n PNG: 1,\n APNG: 2,\n Lottie: 3,\n GIF: 4,\n} as const;\n\n/** Discord sticker types. */\nexport const StickerType = {\n Standard: 1,\n Guild: 2,\n} as const;\n\n/** Discord verification levels. */\nexport const VerificationLevel = {\n None: 0,\n Low: 1,\n Medium: 2,\n High: 3,\n VeryHigh: 4,\n} as const;\n\n/** Discord premium tiers. */\nexport const PremiumTier = {\n None: 0,\n Tier1: 1,\n Tier2: 2,\n Tier3: 3,\n} as const;\n\n// ─── Embeds ───────────────────────────────────────────────────────────────────\n\n/** Raw Discord embed footer object. */\nexport interface APIEmbedFooter {\n text: string;\n icon_url?: string;\n proxy_icon_url?: string;\n}\n/** Raw Discord embed image/thumbnail/video object. */\nexport interface APIEmbedMedia {\n url: string;\n proxy_url?: string;\n height?: number;\n width?: number;\n}\n/** Raw Discord embed provider object. */\nexport interface APIEmbedProvider {\n name?: string;\n url?: string;\n}\n/** Raw Discord embed author object. */\nexport interface APIEmbedAuthor {\n name: string;\n url?: string;\n icon_url?: string;\n proxy_icon_url?: string;\n}\n/** Raw Discord embed field object. */\nexport interface APIEmbedField {\n name: string;\n value: string;\n inline?: boolean;\n}\n/** Raw Discord embed object. */\nexport interface APIEmbed {\n title?: string;\n type?: string;\n description?: string;\n url?: string;\n timestamp?: string;\n color?: number;\n footer?: APIEmbedFooter;\n image?: APIEmbedMedia;\n thumbnail?: APIEmbedMedia;\n video?: APIEmbedMedia;\n provider?: APIEmbedProvider;\n author?: APIEmbedAuthor;\n fields?: APIEmbedField[];\n}\n\n// ─── Message Components ───────────────────────────────────────────────────────\n\n/** Raw Discord select menu option. */\nexport interface APISelectMenuOption {\n label: string;\n value: string;\n description?: string;\n emoji?: APIPartialEmoji;\n default?: boolean;\n}\n/** Raw Discord emoji (partial, as used in components). */\nexport interface APIPartialEmoji {\n id?: Snowflake | null;\n name?: string | null;\n animated?: boolean;\n}\n/** Raw Discord button component. */\nexport interface APIButtonComponent {\n type: 2;\n style: number;\n label?: string;\n emoji?: APIPartialEmoji;\n custom_id?: string;\n url?: string;\n sku_id?: string;\n disabled?: boolean;\n}\n/** Raw Discord select menu component. */\nexport interface APISelectMenuComponent {\n type: 3 | 5 | 6 | 7 | 8;\n custom_id: string;\n options?: APISelectMenuOption[];\n channel_types?: number[];\n placeholder?: string;\n min_values?: number;\n max_values?: number;\n disabled?: boolean;\n}\n/** Raw Discord text input component. */\nexport interface APITextInputComponent {\n type: 4;\n custom_id: string;\n style: number;\n label: string;\n min_length?: number;\n max_length?: number;\n required?: boolean;\n value?: string;\n placeholder?: string;\n}\n/** Union of all raw message component types. */\nexport type APIMessageActionRowComponent =\n APIButtonComponent | APISelectMenuComponent | APITextInputComponent;\n/** Raw Discord action row component. */\nexport interface APIActionRowComponent {\n type: 1;\n id?: number;\n components: APIMessageActionRowComponent[];\n}\n/** Union including action rows and V2 components. */\nexport type APIMessageComponent =\n APIActionRowComponent | { type: Exclude<number, 1>; [key: string]: any };\n\n// ─── Attachments ─────────────────────────────────────────────────────────────\n\n/** Raw Discord attachment object. */\nexport interface APIAttachment {\n id: Snowflake;\n filename: string;\n description?: string | null;\n content_type?: string;\n size: number;\n url: string;\n proxy_url: string;\n height?: number | null;\n width?: number | null;\n ephemeral?: boolean;\n duration_secs?: number;\n waveform?: string;\n flags?: number;\n}\n\n// ─── Stickers ────────────────────────────────────────────────────────────────\n\n/** Compact sticker item as included in messages. */\nexport interface APIStickerItem {\n id: Snowflake;\n name: string;\n format_type: number;\n}\n/** Full Discord sticker object. */\nexport interface APISticker {\n id: Snowflake;\n pack_id?: Snowflake;\n name: string;\n description?: string | null;\n tags?: string;\n type: number;\n format_type: number;\n available?: boolean;\n guild_id?: Snowflake;\n user?: UserData;\n sort_value?: number;\n}\n\n// ─── Messages ────────────────────────────────────────────────────────────────\n\n/** Raw Discord message reference. */\nexport interface APIMessageReference {\n type?: number;\n message_id?: Snowflake;\n channel_id?: Snowflake;\n guild_id?: Snowflake;\n fail_if_not_exists?: boolean;\n}\n/** Raw Discord message reaction. */\nexport interface APIMessageReaction {\n count: number;\n count_details?: Record<string, number>;\n me?: boolean;\n me_burst?: boolean;\n emoji: APIPartialEmoji;\n burst_colors?: string[];\n}\n/** Raw Discord message object. */\nexport interface APIMessage {\n id: Snowflake;\n channel_id: Snowflake;\n author: UserData;\n content: string;\n timestamp?: string;\n edited_timestamp?: string | null;\n tts?: boolean;\n mention_everyone?: boolean;\n mentions?: UserData[];\n mention_roles?: Snowflake[];\n mention_channels?: Array<Record<string, unknown>>;\n attachments?: APIAttachment[];\n embeds?: APIEmbed[];\n reactions?: APIMessageReaction[];\n nonce?: string | number | null;\n pinned?: boolean;\n webhook_id?: Snowflake;\n type?: number;\n activity?: Record<string, unknown>;\n application?: Record<string, unknown>;\n application_id?: Snowflake;\n message_reference?: APIMessageReference;\n flags?: number;\n referenced_message?: APIMessage | null;\n interaction_metadata?: Record<string, unknown>;\n thread?: Record<string, unknown>;\n components?: APIMessageComponent[];\n sticker_items?: APIStickerItem[];\n stickers?: APISticker[];\n position?: number;\n role_subscription_data?: Record<string, unknown>;\n purchase_notification?: Record<string, unknown>;\n poll?: Record<string, unknown>;\n guild_id?: Snowflake;\n}\n\n// ─── Channels ────────────────────────────────────────────────────────────────\n\n/** Raw Discord channel object. */\nexport interface APIChannel {\n id: Snowflake;\n type: number;\n guild_id?: Snowflake;\n position?: number;\n permission_overwrites?: APIOverwrite[];\n name?: string | null;\n topic?: string | null;\n nsfw?: boolean;\n last_message_id?: Snowflake | null;\n bitrate?: number;\n user_limit?: number;\n rate_limit_per_user?: number;\n recipients?: UserData[];\n icon?: string | null;\n owner_id?: Snowflake;\n application_id?: Snowflake;\n parent_id?: Snowflake | null;\n last_pin_timestamp?: string | null;\n rtc_region?: string | null;\n video_quality_mode?: number;\n message_count?: number;\n member_count?: number;\n thread_metadata?: APIThreadMetadata;\n default_auto_archive_duration?: number;\n flags?: number;\n total_message_sent?: number;\n available_tags?: APIForumTag[];\n default_reaction_emoji?: APIPartialEmoji | null;\n default_thread_rate_limit_per_user?: number;\n default_sort_order?: number | null;\n default_forum_layout?: number;\n}\n\n/** Raw Discord thread metadata. */\nexport interface APIThreadMetadata {\n archived: boolean;\n auto_archive_duration: number;\n archive_timestamp: string;\n locked: boolean;\n invitable?: boolean;\n create_timestamp?: string | null;\n}\n\n/** Raw Discord forum tag. */\nexport interface APIForumTag {\n id: Snowflake;\n name: string;\n moderated: boolean;\n emoji_id?: Snowflake | null;\n emoji_name?: string | null;\n}\n\n/** Raw Discord thread member. */\nexport interface APIThreadMember {\n id?: Snowflake;\n user_id?: Snowflake;\n join_timestamp: string;\n flags: number;\n member?: APIGuildMember;\n}\n\n// ─── Roles ────────────────────────────────────────────────────────────────────\n\n/** Raw Discord role object. */\nexport interface APIRole {\n id: Snowflake;\n name: string;\n color: number;\n hoist: boolean;\n icon?: string | null;\n unicode_emoji?: string | null;\n position: number;\n permissions: string;\n managed: boolean;\n mentionable: boolean;\n tags?: Record<string, unknown>;\n flags?: number;\n}\n\n// ─── Emoji ────────────────────────────────────────────────────────────────────\n\n/** Raw Discord emoji object. */\nexport interface APIEmoji {\n id: Snowflake | null;\n name: string | null;\n roles?: Snowflake[];\n user?: UserData;\n require_colons?: boolean;\n managed?: boolean;\n animated?: boolean;\n available?: boolean;\n}\n\n// ─── Guilds ───────────────────────────────────────────────────────────────────\n\n/** Raw Discord guild object. */\nexport interface APIGuild {\n id: Snowflake;\n name: string;\n icon?: string | null;\n icon_hash?: string | null;\n splash?: string | null;\n discovery_splash?: string | null;\n owner?: boolean;\n owner_id?: Snowflake;\n permissions?: string;\n afk_channel_id?: Snowflake | null;\n afk_timeout?: number;\n widget_enabled?: boolean;\n widget_channel_id?: Snowflake | null;\n verification_level?: number;\n default_message_notifications?: number;\n explicit_content_filter?: number;\n roles?: APIRole[];\n emojis?: APIEmoji[];\n stickers?: APISticker[];\n features?: string[];\n mfa_level?: number;\n application_id?: Snowflake | null;\n system_channel_id?: Snowflake | null;\n system_channel_flags?: number;\n rules_channel_id?: Snowflake | null;\n max_presences?: number | null;\n max_members?: number;\n vanity_url_code?: string | null;\n description?: string | null;\n banner?: string | null;\n premium_tier?: number;\n premium_subscription_count?: number;\n preferred_locale?: string;\n public_updates_channel_id?: Snowflake | null;\n max_video_channel_users?: number;\n approximate_member_count?: number;\n approximate_presence_count?: number;\n nsfw_level?: number;\n safety_alerts_channel_id?: Snowflake | null;\n member_count?: number;\n}\n\n// ─── Welcome Screen ───────────────────────────────────────────────────────────\n\nexport interface APIWelcomeScreenChannel {\n channel_id: Snowflake;\n description: string;\n emoji_id: Snowflake | null;\n emoji_name: string | null;\n}\n\nexport interface APIGuildWelcomeScreen {\n description: string | null;\n welcome_channels: APIWelcomeScreenChannel[];\n}\n\n// ─── Guild Onboarding ─────────────────────────────────────────────────────────\n\nexport interface APIOnboardingPromptOption {\n id: Snowflake;\n channel_ids: Snowflake[];\n role_ids: Snowflake[];\n emoji?: APIPartialEmoji;\n title: string;\n description: string | null;\n}\n\nexport interface APIOnboardingPrompt {\n id: Snowflake;\n type: number;\n options: APIOnboardingPromptOption[];\n title: string;\n single_select: boolean;\n required: boolean;\n in_onboarding: boolean;\n}\n\nexport interface APIGuildOnboarding {\n guild_id: Snowflake;\n prompts: APIOnboardingPrompt[];\n default_channel_ids: Snowflake[];\n enabled: boolean;\n mode: number;\n}\n\n/** Raw Discord guild member object. */\nexport interface APIGuildMember {\n user: UserData;\n nick?: string | null;\n avatar?: string | null;\n roles: Snowflake[];\n joined_at: string;\n premium_since?: string | null;\n deaf?: boolean;\n mute?: boolean;\n flags?: number;\n pending?: boolean;\n permissions?: string;\n communication_disabled_until?: string | null;\n guild_id?: Snowflake;\n}\n\n// ─── Voice ────────────────────────────────────────────────────────────────────\n\n/** Raw Discord voice state object. */\nexport interface APIVoiceState {\n guild_id?: Snowflake;\n channel_id?: Snowflake | null;\n user_id: Snowflake;\n member?: APIGuildMember;\n session_id: string;\n deaf: boolean;\n mute: boolean;\n self_deaf: boolean;\n self_mute: boolean;\n self_stream?: boolean;\n self_video: boolean;\n suppress: boolean;\n request_to_speak_timestamp?: string | null;\n}\n\n/** Raw Discord voice server update event. */\nexport interface APIVoiceServerUpdate {\n token: string;\n guild_id: Snowflake;\n endpoint?: string | null;\n}\n\n// ─── Presence ────────────────────────────────────────────────────────────────\n\n/** Raw Discord activity object. */\nexport interface APIActivity {\n name: string;\n type: number;\n url?: string | null;\n created_at: number;\n state?: string | null;\n details?: string | null;\n emoji?: APIPartialEmoji | null;\n}\n\n/** Raw Discord presence update event. */\nexport interface APIPresenceUpdate {\n user: { id: Snowflake } & Partial<UserData>;\n guild_id: Snowflake;\n status: string;\n activities: APIActivity[];\n client_status: { desktop?: string; mobile?: string; web?: string };\n}\n\n// ─── Typing ───────────────────────────────────────────────────────────────────\n\n/** Raw Discord typing start event. */\nexport interface APITypingStart {\n channel_id: Snowflake;\n guild_id?: Snowflake;\n user_id: Snowflake;\n timestamp: number;\n member?: APIGuildMember;\n}\n\n// ─── Guilds ──────────────────────────────────────────────────────────────────\n\n/** Raw Discord guild preview. */\nexport interface APIGuildPreview {\n id: Snowflake;\n name: string;\n icon: string | null;\n splash: string | null;\n discovery_splash: string | null;\n emojis: unknown[];\n features: string[];\n approximate_member_count: number;\n approximate_presence_count: number;\n description: string | null;\n stickers: unknown[];\n}\n\n// ─── Invites ─────────────────────────────────────────────────────────────────\n\n/** Raw Discord invite. */\nexport interface APIInvite {\n code: string;\n guild?: Partial<APIGuild>;\n channel: Partial<APIChannel>;\n inviter?: UserData;\n target_type?: number;\n target_user?: UserData;\n approximate_presence_count?: number;\n approximate_member_count?: number;\n}\n\n/** Raw Discord invite create event. */\nexport interface APIInviteCreate {\n channel_id: Snowflake;\n code: string;\n created_at: string;\n guild_id?: Snowflake;\n inviter?: UserData;\n max_age: number;\n max_uses: number;\n target_type?: number;\n target_user?: UserData;\n temporary: boolean;\n uses: number;\n}\n\n/** Raw Discord invite delete event. */\nexport interface APIInviteDelete {\n channel_id: Snowflake;\n guild_id?: Snowflake;\n code: string;\n}\n\n// ─── Webhooks ────────────────────────────────────────────────────────────────\n\n/** Raw Discord webhooks update event. */\nexport interface APIWebhooksUpdate {\n guild_id: Snowflake;\n channel_id: Snowflake;\n}\n\n/** Raw Discord webhook object. */\nexport interface APIWebhook {\n id: Snowflake;\n type: number;\n guild_id?: Snowflake | null;\n channel_id?: Snowflake | null;\n user?: UserData;\n name?: string | null;\n avatar?: string | null;\n token?: string;\n application_id?: Snowflake | null;\n url?: string;\n}\n\n// ─── AutoMod ─────────────────────────────────────────────────────────────────\n\n/** Raw Discord AutoMod action. */\nexport interface APIAutoModerationAction {\n type: number;\n metadata?: {\n channel_id?: Snowflake;\n duration_seconds?: number;\n custom_message?: string;\n };\n}\n\n// ─── Audit Logs ──────────────────────────────────────────────────────────────\n\n/** Raw Discord audit log change object. */\nexport interface APIAuditLogChange {\n new_value?: unknown;\n old_value?: unknown;\n key: string;\n}\n\n/** Raw Discord audit log entry options object. */\nexport interface APIAuditLogOptions {\n app_id?: Snowflake;\n auto_moderation_rule_name?: string;\n auto_moderation_rule_trigger_type?: string;\n channel_id?: Snowflake;\n count?: string;\n delete_member_days?: string;\n id?: Snowflake;\n members_removed?: string;\n message_id?: Snowflake;\n role_name?: string;\n type?: string;\n integration_type?: string;\n}\n\n/** Raw Discord audit log entry object. */\nexport interface APIAuditLogEntry {\n target_id: string | null;\n changes?: APIAuditLogChange[];\n user_id: Snowflake | null;\n id: Snowflake;\n action_type: number;\n options?: APIAuditLogOptions;\n reason?: string;\n}\n\n/** Raw Discord audit log object. */\nexport interface APIAuditLog {\n audit_log_entries: APIAuditLogEntry[];\n guild_scheduled_events: APIGuildScheduledEvent[];\n integrations: Array<Record<string, unknown>>;\n threads: APIChannel[];\n users: UserData[];\n webhooks: APIWebhook[];\n application_commands: APIApplicationCommand[];\n auto_moderation_rules: APIAutoModerationRule[];\n}\n\n/** Raw Discord AutoMod rule object. */\nexport interface APIAutoModerationRule {\n id: Snowflake;\n guild_id: Snowflake;\n name: string;\n creator_id: Snowflake;\n event_type: number;\n trigger_type: number;\n trigger_metadata: Record<string, unknown>;\n actions: APIAutoModerationAction[];\n enabled: boolean;\n exempt_roles: Snowflake[];\n exempt_channels: Snowflake[];\n}\n\n/** Raw Discord AutoMod action execution event. */\nexport interface APIAutoModerationActionExecution {\n guild_id: Snowflake;\n action: APIAutoModerationAction;\n rule_id: Snowflake;\n rule_trigger_type: number;\n user_id: Snowflake;\n channel_id?: Snowflake;\n message_id?: Snowflake;\n alert_system_message_id?: Snowflake;\n content: string;\n matched_keyword?: string | null;\n matched_content?: string | null;\n}\n\n// ─── Scheduled Events ─────────────────────────────────────────────────────────\n\n/** Raw Discord guild scheduled event entity metadata. */\nexport interface APIGuildScheduledEventEntityMetadata {\n location?: string;\n}\n\n/** Raw Discord guild scheduled event object. */\nexport interface APIGuildScheduledEvent {\n id: Snowflake;\n guild_id: Snowflake;\n channel_id?: Snowflake | null;\n creator_id?: Snowflake | null;\n name: string;\n description?: string | null;\n scheduled_start_time: string;\n scheduled_end_time?: string | null;\n privacy_level: number;\n status: number;\n entity_type: number;\n entity_id?: Snowflake | null;\n entity_metadata?: APIGuildScheduledEventEntityMetadata | null;\n creator?: UserData;\n user_count?: number;\n image?: string | null;\n}\n\n// ─── Stage Instances ─────────────────────────────────────────────────────────\n\n/** Raw Discord stage instance object. */\nexport interface APIStageInstance {\n id: Snowflake;\n guild_id: Snowflake;\n channel_id: Snowflake;\n topic: string;\n privacy_level: number;\n discoverable_disabled?: boolean;\n guild_scheduled_event_id?: Snowflake | null;\n}\n\n// ─── Application Commands ─────────────────────────────────────────────────────\n\n/** Discord application command option types. */\nexport const ApplicationCommandOptionType = {\n SubCommand: 1,\n SubCommandGroup: 2,\n String: 3,\n Integer: 4,\n Boolean: 5,\n User: 6,\n Channel: 7,\n Role: 8,\n Mentionable: 9,\n Number: 10,\n Attachment: 11,\n} as const;\n\n/** Discord application command types. */\nexport const ApplicationCommandType = {\n ChatInput: 1,\n User: 2,\n Message: 3,\n} as const;\n\n/** Raw Discord application command option. */\nexport interface APIApplicationCommandOption {\n type: number;\n name: string;\n description: string;\n required?: boolean;\n choices?: Array<{ name: string; value: string | number }>;\n options?: APIApplicationCommandOption[];\n min_value?: number;\n max_value?: number;\n min_length?: number;\n max_length?: number;\n autocomplete?: boolean;\n channel_types?: number[];\n}\n\n/** Raw Discord application command object (from API). */\nexport interface APIApplicationCommand {\n id: Snowflake;\n type?: number;\n application_id: Snowflake;\n guild_id?: Snowflake;\n name: string;\n description: string;\n options?: APIApplicationCommandOption[];\n default_member_permissions?: string | null;\n dm_permission?: boolean;\n nsfw?: boolean;\n version: Snowflake;\n}\n\n/** Data for creating/overwriting an application command. */\nexport interface ApplicationCommandData {\n name: string;\n description: string;\n type?: number;\n options?: APIApplicationCommandOption[];\n default_member_permissions?: string | null;\n dm_permission?: boolean;\n nsfw?: boolean;\n}\n\n/** A channel permission overwrite for a role (type 0) or member (type 1). */\nexport interface APIOverwrite {\n id: Snowflake;\n type: 0 | 1;\n /** Allowed permission bits as a decimal string. */\n allow: string;\n /** Denied permission bits as a decimal string. */\n deny: string;\n}\n\n// ─── Soundboard & Monetization ───────────────────────────────────────────────\n/** Raw Discord soundboard sound. */\nexport interface APISoundboardSound {\n sound_id: string;\n name: string;\n volume: number;\n emoji_id: string | null;\n emoji_name: string | null;\n guild_id?: string;\n available: boolean;\n user?: UserData;\n}\n\n/** Raw Discord SKU. */\nexport interface APISKU {\n id: string;\n type: number;\n application_id: string;\n name: string;\n slug: string;\n flags: number;\n}\n\n/** Raw Discord entitlement. */\nexport interface APIEntitlement {\n id: string;\n sku_id: string;\n application_id: string;\n user_id?: string;\n guild_id?: string;\n type: number;\n deleted: boolean;\n starts_at?: string | null;\n ends_at?: string | null;\n consumed?: boolean;\n}\n\n/** Raw Discord subscription. */\nexport interface APISubscription {\n id: string;\n user_id: string;\n sku_ids: string[];\n entitlement_ids: string[];\n current_period_start: string;\n current_period_end: string;\n status: number;\n canceled_at: string | null;\n country?: string;\n}\n"
7
7
  ],
8
8
  "mappings": "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",
9
9
  "debugId": "C1043445F681533C64756E2164756E21",
@@ -178,6 +178,9 @@ export declare class VoiceReceiver {
178
178
  mapSsrc(ssrc: number, userId: string): void;
179
179
  /** Subscribes to incoming audio from a specific user. @param userId User identifier. @returns A binary readable stream of the audio. */
180
180
  subscribe(userId: string): AudioStream;
181
+ /** Ends every subscriber stream and forgets SSRC mappings. Called when the
182
+ * connection disconnects or is destroyed, so readers do not wait forever. */
183
+ close(): void;
181
184
  /** Processes an incoming UDP packet, extracting SSRC and routing the audio
182
185
  * payload (RTP header stripped) to every subscriber for the mapped user. */
183
186
  onPacket(packet: Uint8Array): void;
@@ -84,12 +84,14 @@ class VoiceConnection {
84
84
  if (this.state === "destroyed" /* Destroyed */)
85
85
  return;
86
86
  this.#closeTransports();
87
+ this.receiver.close();
87
88
  this.#transition("disconnected" /* Disconnected */);
88
89
  }
89
90
  destroy() {
90
91
  if (this.state === "destroyed" /* Destroyed */)
91
92
  return;
92
93
  this.#closeTransports();
94
+ this.receiver.close();
93
95
  this.channelId = undefined;
94
96
  this.#transition("destroyed" /* Destroyed */);
95
97
  this.#listeners.clear();
@@ -297,6 +299,8 @@ class VoiceReceiver {
297
299
  this.#ssrcMap.set(ssrc, userId);
298
300
  }
299
301
  subscribe(userId) {
302
+ if (this.connection.state === "destroyed" /* Destroyed */)
303
+ throw new VoiceError("Voice connection has been destroyed.");
300
304
  let controllerRef;
301
305
  const stream = new ReadableStream({
302
306
  start: (controller) => {
@@ -317,6 +321,16 @@ class VoiceReceiver {
317
321
  });
318
322
  return new AudioStream(stream, { title: `User ${userId} Audio` });
319
323
  }
324
+ close() {
325
+ for (const controllers of this.#streams.values())
326
+ for (const controller of controllers) {
327
+ try {
328
+ controller.close();
329
+ } catch {}
330
+ }
331
+ this.#streams.clear();
332
+ this.#ssrcMap.clear();
333
+ }
320
334
  onPacket(packet) {
321
335
  if (packet.length < 12)
322
336
  return;
@@ -409,4 +423,4 @@ export {
409
423
  joinVoiceChannel
410
424
  };
411
425
 
412
- //# debugId=C61FD04CD1E9BF4D64756E2164756E21
426
+ //# debugId=9E96BE25F2F4C69B64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../packages/voice/src/index.ts"],
4
4
  "sourcesContent": [
5
- "/** Voice session lifecycle states. */\nexport enum VoiceConnectionState {\n Disconnected = \"disconnected\",\n Connecting = \"connecting\",\n Connected = \"connected\",\n Destroyed = \"destroyed\",\n}\n\n/** Voice protocol transport errors. */\nexport class VoiceError extends Error {\n /** Creates a voice error. @param message Error message. @param options Optional native error options. */\n public constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"VoiceError\";\n }\n}\n\n/** Options used to establish a voice session. */\nexport interface VoiceConnectionOptions {\n /** Guild containing the voice channel. */\n guildId: string;\n /** Voice channel to join. */\n channelId?: string;\n /** Whether the self user should be muted. */\n selfMute?: boolean;\n /** Whether the self user should be deafened. */\n selfDeaf?: boolean;\n}\n\n/** UDP transport supplied by the runtime-specific voice implementation. */\nexport interface VoiceUdpTransport {\n /** Sends an RTP/RTCP packet. @param packet Packet bytes. @param host Destination host. @param port Destination port. @returns Optional completion promise. */\n send(packet: Uint8Array, host: string, port: number): Promise<void> | void;\n /** Closes the UDP socket. @returns Nothing. */\n close(): void;\n /** Optional listener for incoming UDP packets. */\n onMessage?(listener: (packet: Uint8Array) => void): void;\n}\n\n/** Voice Gateway transport abstraction. */\nexport interface VoiceGatewayTransport {\n /** Opens the voice gateway. @param endpoint Voice gateway endpoint. @param sessionId Voice session identifier. @returns Promise fulfilled when connected. */\n connect(endpoint: string, sessionId: string): Promise<void>;\n /** Sends a voice gateway payload. @param payload Gateway payload. @returns Nothing. */\n send(payload: unknown): void;\n /** Closes the voice gateway. @param code Optional close code. @param reason Optional close reason. @returns Nothing. */\n close(code?: number, reason?: string): void;\n}\n\n/** Speaking flags used by the voice gateway. */\nexport const SpeakingFlags = {\n Microphone: 1,\n Soundshare: 2,\n Priority: 4,\n} as const;\n\n/** Voice session event payloads. */\nexport interface VoiceEvents {\n /** State transition event. */\n stateChange: [VoiceConnectionState, VoiceConnectionState];\n /** Speaking flag event. */\n speaking: [number, number];\n /** Voice transport error event. */\n error: [VoiceError];\n}\n\ntype VoiceListener = (...args: any[]) => unknown;\n\n/** Tracks a Discord voice session and exposes transport-independent lifecycle controls. */\nexport class VoiceConnection {\n /** Current voice connection state. */\n public state: VoiceConnectionState = VoiceConnectionState.Disconnected;\n /** Guild associated with this voice session. */\n public readonly guildId: string;\n /** Voice channel associated with this session. */\n public channelId?: string;\n /** Whether the client is self-muted. */\n public selfMute: boolean;\n /** Whether the client is self-deafened. */\n public selfDeaf: boolean;\n /** Active voice gateway transport, when attached. */\n public gateway?: VoiceGatewayTransport;\n /** Active UDP transport, when attached. */\n public udp?: VoiceUdpTransport;\n /** Registered lifecycle listeners. */\n readonly #listeners = new Map<keyof VoiceEvents, Set<VoiceListener>>();\n /** Receives incoming audio. */\n public readonly receiver: VoiceReceiver;\n\n /** Creates a voice connection state manager. @param options Guild ID or connection options. @throws {TypeError} If the guild ID is empty. */\n public constructor(options: string | VoiceConnectionOptions) {\n const resolved =\n typeof options === \"string\" ? { guildId: options } : options;\n if (!resolved.guildId?.trim()) {\n throw new TypeError(\n \"A guild ID is required for a voice connection.\",\n );\n }\n this.guildId = resolved.guildId;\n this.channelId = resolved.channelId;\n this.selfMute = resolved.selfMute ?? false;\n this.selfDeaf = resolved.selfDeaf ?? false;\n this.receiver = new VoiceReceiver(this);\n }\n\n /** Registers a voice lifecycle listener. @param event Event name. @param listener Listener callback. @returns This connection. @throws {TypeError} If listener is not callable. */\n public on<K extends keyof VoiceEvents>(\n event: K,\n listener: (...args: VoiceEvents[K]) => unknown,\n ): this {\n if (typeof listener !== \"function\")\n throw new TypeError(\"Voice listener must be a function.\");\n let listeners = this.#listeners.get(event);\n if (!listeners) this.#listeners.set(event, (listeners = new Set()));\n listeners.add(listener);\n return this;\n }\n\n /** Removes a voice lifecycle listener. @param event Event name. @param listener Listener callback. @returns This connection. */\n public off<K extends keyof VoiceEvents>(\n event: K,\n listener: (...args: VoiceEvents[K]) => unknown,\n ): this {\n this.#listeners.get(event)?.delete(listener);\n return this;\n }\n\n /** Attaches protocol transports, replacing and cleaning up the old pair when present. @param gateway Voice gateway transport. @param udp UDP transport. @returns This connection. @throws {VoiceError} If the connection is destroyed. @throws {TypeError} If a transport is missing. */\n public attachTransports(\n gateway: VoiceGatewayTransport,\n udp: VoiceUdpTransport,\n ): this {\n this.assertUsable();\n if (!gateway || !udp)\n throw new TypeError(\n \"Both voice gateway and UDP transports are required.\",\n );\n if (this.gateway || this.udp) this.#closeTransports();\n this.gateway = gateway;\n this.udp = udp;\n // Capture the transport this listener belongs to so that packets from a\n // later-replaced transport (whose listener cannot be unregistered — the\n // VoiceUdpTransport interface exposes no removal API) are ignored.\n const attachedUdp = udp;\n if (attachedUdp.onMessage) {\n attachedUdp.onMessage((packet) => {\n if (this.udp === attachedUdp) this.receiver.onPacket(packet);\n });\n }\n return this;\n }\n\n /** Begins the connection lifecycle. @returns Nothing. @throws {VoiceError} If the connection is destroyed. */\n public connect(): void {\n this.assertUsable();\n if (this.state === VoiceConnectionState.Connected) return;\n this.#transition(VoiceConnectionState.Connecting);\n if (this.state !== VoiceConnectionState.Connecting) return;\n this.#transition(VoiceConnectionState.Connected);\n }\n\n /** Disconnects the current voice session. @returns Nothing. */\n public disconnect(): void {\n if (this.state === VoiceConnectionState.Destroyed) return;\n this.#closeTransports();\n this.#transition(VoiceConnectionState.Disconnected);\n }\n\n /** Permanently destroys this voice connection. @returns Nothing. */\n public destroy(): void {\n if (this.state === VoiceConnectionState.Destroyed) return;\n this.#closeTransports();\n this.channelId = undefined;\n this.#transition(VoiceConnectionState.Destroyed);\n this.#listeners.clear();\n }\n\n /** Updates the voice channel and connection state. @param channelId Voice channel identifier. @returns Nothing. @throws {VoiceError} If the connection is destroyed. @throws {TypeError} If channelId is empty. */\n public setChannel(channelId: string): void {\n this.assertUsable();\n if (!channelId?.trim())\n throw new TypeError(\"A voice channel ID is required.\");\n this.channelId = channelId;\n }\n\n /** Updates self mute/deaf state. @param options Suppression flags. @returns Nothing. @throws {VoiceError} If the connection is destroyed. */\n public setSuppression(options: {\n selfMute?: boolean;\n selfDeaf?: boolean;\n }): void {\n this.assertUsable();\n if (options.selfMute !== undefined) this.selfMute = options.selfMute;\n if (options.selfDeaf !== undefined) this.selfDeaf = options.selfDeaf;\n }\n\n /** Publishes a speaking state through the attached voice gateway. @param flags Speaking flags. @returns Nothing. @throws {VoiceError} If the connection is destroyed or has no gateway transport. */\n public setSpeaking(flags: number = SpeakingFlags.Microphone): void {\n this.assertUsable();\n if (!this.gateway) {\n throw new VoiceError(\n \"A voice gateway transport is required to change speaking state.\",\n );\n }\n this.gateway.send({ op: 5, d: { speaking: flags, delay: 0, ssrc: 0 } });\n this.#emit(\"speaking\", flags, 0);\n }\n\n /** Ensures the connection is still usable. @returns Nothing. @throws {VoiceError} If destroyed. */\n #assertUsable(): void {\n if (this.state === VoiceConnectionState.Destroyed) {\n throw new VoiceError(\"Voice connection has been destroyed.\");\n }\n }\n\n /** Closes both active transports while isolating cleanup failures. @returns Nothing. */\n #closeTransports(): void {\n try {\n this.gateway?.close(1000, \"Voice connection replaced or closed\");\n } catch (error) {\n this.#emit(\n \"error\",\n error instanceof VoiceError\n ? error\n : new VoiceError(\"Voice gateway cleanup failed.\", {\n cause: error,\n }),\n );\n }\n try {\n this.udp?.close();\n } catch (error) {\n this.#emit(\n \"error\",\n error instanceof VoiceError\n ? error\n : new VoiceError(\"Voice UDP cleanup failed.\", {\n cause: error,\n }),\n );\n }\n this.gateway = undefined;\n this.udp = undefined;\n }\n\n /** Transitions to a new lifecycle state and emits the transition event. @param next Next state. @returns Nothing. */\n #transition(next: VoiceConnectionState): void {\n const previous = this.state;\n this.state = next;\n if (previous === next) return;\n for (const listener of this.#listeners.get(\"stateChange\") ?? []) {\n try {\n void listener(next, previous);\n } catch (error) {\n this.#emit(\n \"error\",\n error instanceof VoiceError\n ? error\n : new VoiceError(\"Voice event listener failed.\", {\n cause: error,\n }),\n );\n }\n if (this.state !== next && next !== VoiceConnectionState.Destroyed)\n return;\n }\n }\n\n /** Emits a voice event while isolating consumer failures. @param event Event name. @param args Event arguments. @returns Nothing. */\n #emit<K extends keyof VoiceEvents>(\n event: K,\n ...args: VoiceEvents[K]\n ): void {\n for (const listener of this.#listeners.get(event) ?? []) {\n try {\n void listener(...args);\n } catch {\n /* Consumer failures are isolated. */\n }\n }\n }\n\n /** Ensures the connection is still usable. @returns Nothing. @throws {VoiceError} If destroyed. */\n private assertUsable(): void {\n this.#assertUsable();\n }\n}\n\n// ─── Audio Pipeline ───────────────────────────────────────────────────────────\n\n/** Audio player lifecycle states. */\nexport type AudioPlayerState = \"idle\" | \"playing\" | \"paused\" | \"stopped\";\n\n/** An audio stream — wraps a `ReadableStream<Uint8Array>` with optional metadata. */\nexport class AudioStream {\n /** Underlying binary stream. */ public readonly stream: ReadableStream<Uint8Array>;\n /** Optional human-readable title for the stream. */ public readonly title?: string;\n /** Optional duration hint in seconds. */ public readonly duration?: number;\n\n /** Creates an audio stream.\n * @param stream Binary audio data stream.\n * @param metadata Optional metadata: title and duration in seconds.\n */\n public constructor(\n stream: ReadableStream<Uint8Array>,\n metadata?: { title?: string; duration?: number },\n ) {\n this.stream = stream;\n this.title = metadata?.title;\n this.duration = metadata?.duration;\n }\n}\n\ntype AudioPlayerListener<K extends keyof AudioPlayerEvents> = (\n ...args: AudioPlayerEvents[K]\n) => unknown;\n\ninterface AudioPlayerEvents {\n stateChange: [from: AudioPlayerState, to: AudioPlayerState];\n error: [error: Error];\n finish: [];\n}\n\n/**\n * Lightweight audio player with a simple state machine.\n *\n * States:\n * - `idle` — no stream loaded.\n * - `playing` — actively feeding audio data.\n * - `paused` — temporarily suspended; can be resumed.\n * - `stopped` — stream was stopped and discarded; load a new stream to play again.\n *\n * Events: `stateChange(from, to)`, `error(err)`, `finish()`.\n */\nexport class AudioPlayer {\n #state: AudioPlayerState = \"idle\";\n #stream?: AudioStream;\n #reader?: ReadableStreamDefaultReader<Uint8Array>;\n /** Resolves the pump's pause await when the player is resumed or stopped. */\n #resumeSignal?: () => void;\n readonly #listeners = new Map<\n string,\n Set<AudioPlayerListener<keyof AudioPlayerEvents>>\n >();\n\n /** Current player state. */\n public get state(): AudioPlayerState {\n return this.#state;\n }\n\n /** The audio stream currently loaded, if any. */\n public get current(): AudioStream | undefined {\n return this.#stream;\n }\n\n /**\n * Begins playing an audio stream.\n * If a stream is already playing, it is stopped first; the previous\n * stream's reader cancellation is awaited before the new stream starts so\n * the old and new pump loops cannot run concurrently.\n * @param audioStream Stream to play.\n */\n public async play(audioStream: AudioStream): Promise<void> {\n if (this.#state === \"playing\" || this.#state === \"paused\")\n await this.stop();\n this.#stream = audioStream;\n this.#reader = audioStream.stream.getReader();\n this.#transition(\"playing\");\n this.#pump().catch((err) => this.#emitError(err));\n }\n\n /** Pauses a currently-playing stream. No-op if not playing. */\n public pause(): void {\n if (this.#state !== \"playing\") return;\n this.#transition(\"paused\");\n }\n\n /** Resumes a paused stream. No-op if not paused. */\n public resume(): void {\n if (this.#state !== \"paused\") return;\n this.#transition(\"playing\");\n // Wake the existing pump loop rather than starting a second one.\n const signal = this.#resumeSignal;\n this.#resumeSignal = undefined;\n signal?.();\n }\n\n /**\n * Stops and discards the current stream. The returned promise resolves once\n * the underlying reader's cancellation has settled, so a subsequent `play`\n * never overlaps with the previous pump loop.\n */\n public async stop(): Promise<void> {\n if (this.#state === \"idle\" || this.#state === \"stopped\") return;\n const reader = this.#reader;\n this.#reader = undefined;\n this.#stream = undefined;\n this.#transition(\"stopped\");\n // Release a pump loop that is currently awaiting a resume.\n const signal = this.#resumeSignal;\n this.#resumeSignal = undefined;\n signal?.();\n if (reader) {\n try {\n await reader.cancel();\n } catch {\n /* Cancellation failures are non-fatal. */\n }\n }\n }\n\n /** Registers an event listener. @returns `this` for chaining. */\n public on<K extends keyof AudioPlayerEvents>(\n event: K,\n listener: AudioPlayerListener<K>,\n ): this {\n let set = this.#listeners.get(event) as\n Set<AudioPlayerListener<K>> | undefined;\n if (!set) {\n this.#listeners.set(\n event,\n (set = new Set() as unknown as Set<\n AudioPlayerListener<keyof AudioPlayerEvents>\n >),\n );\n }\n (set as unknown as Set<AudioPlayerListener<K>>).add(listener);\n return this;\n }\n\n /** Removes an event listener. @returns `this` for chaining. */\n public off<K extends keyof AudioPlayerEvents>(\n event: K,\n listener: AudioPlayerListener<K>,\n ): this {\n (\n this.#listeners.get(event) as\n Set<AudioPlayerListener<K>> | undefined\n )?.delete(listener);\n return this;\n }\n\n /**\n * Handles a decoded audio chunk. The base implementation is a no-op;\n * subclasses override this to pipe audio to a UDP socket or other sink.\n * @param chunk A chunk of audio bytes read from the current stream.\n */\n protected onChunk(chunk: Uint8Array): void {\n void chunk;\n }\n\n /** Reads chunks from the reader while the player is in a playing state. */\n async #pump(): Promise<void> {\n const reader = this.#reader;\n if (!reader) return;\n while (true) {\n // Suspend without polling: park until resume()/stop() signals us.\n if (this.#state === \"paused\") {\n await new Promise<void>((resolve) => {\n this.#resumeSignal = resolve;\n });\n }\n // Abort if stopped/idle (e.g. resolved by stop()).\n if (this.#state !== \"playing\") return;\n const { done, value } = await reader.read();\n if (done) {\n if (this.#state === \"playing\" || this.#state === \"paused\") {\n this.#transition(\"idle\");\n this.#stream = undefined;\n this.#reader = undefined;\n this.#emit(\"finish\");\n }\n return;\n }\n // A stop() during the read wins — drop the chunk and exit.\n if (this.#state !== \"playing\" && this.#state !== \"paused\") return;\n // Deliver the chunk to the sink hook; loop back to honour pause state.\n this.onChunk(value);\n }\n }\n\n #transition(next: AudioPlayerState): void {\n if (this.#state === next) return;\n const from = this.#state;\n this.#state = next;\n this.#emit(\"stateChange\", from, next);\n }\n\n #emitError(err: unknown): void {\n this.#emit(\n \"error\",\n err instanceof Error ? err : new VoiceError(String(err)),\n );\n }\n\n #emit<K extends keyof AudioPlayerEvents>(\n event: K,\n ...args: AudioPlayerEvents[K]\n ): void {\n for (const listener of this.#listeners.get(event) ?? []) {\n try {\n void (listener as (...a: unknown[]) => unknown)(...args);\n } catch {\n /* Listener failures are isolated. */\n }\n }\n }\n}\n\n// ─── Audio Receive Pipeline ───────────────────────────────────────────────────\n\n/** Tracks incoming audio and maps SSRCs to readable streams per user. */\nexport class VoiceReceiver {\n /** The connection this receiver is attached to. */\n public readonly connection: VoiceConnection;\n readonly #ssrcMap = new Map<number, string>();\n /** Active stream controllers per user; a Set so multiple subscribers to the\n * same user all receive audio instead of the last one overwriting earlier ones. */\n readonly #streams = new Map<\n string,\n Set<ReadableStreamDefaultController<Uint8Array>>\n >();\n\n /** Creates a VoiceReceiver. @param connection Voice connection. */\n public constructor(connection: VoiceConnection) {\n this.connection = connection;\n }\n\n /** Maps an SSRC to a User ID (usually from gateway speaking events). */\n public mapSsrc(ssrc: number, userId: string): void {\n this.#ssrcMap.set(ssrc, userId);\n }\n\n /** Subscribes to incoming audio from a specific user. @param userId User identifier. @returns A binary readable stream of the audio. */\n public subscribe(userId: string): AudioStream {\n let controllerRef: ReadableStreamDefaultController<Uint8Array>;\n const stream = new ReadableStream<Uint8Array>({\n start: (controller) => {\n controllerRef = controller;\n let set = this.#streams.get(userId);\n if (!set) this.#streams.set(userId, (set = new Set()));\n set.add(controller);\n },\n cancel: () => {\n const set = this.#streams.get(userId);\n if (set) {\n set.delete(controllerRef);\n if (set.size === 0) this.#streams.delete(userId);\n }\n },\n });\n return new AudioStream(stream, { title: `User ${userId} Audio` });\n }\n\n /** Processes an incoming UDP packet, extracting SSRC and routing the audio\n * payload (RTP header stripped) to every subscriber for the mapped user. */\n public onPacket(packet: Uint8Array): void {\n if (packet.length < 12) return;\n\n const view = new DataView(\n packet.buffer,\n packet.byteOffset,\n packet.byteLength,\n );\n const ssrc = view.getUint32(8, false);\n\n const userId = this.#ssrcMap.get(ssrc);\n if (!userId) return;\n const controllers = this.#streams.get(userId);\n if (!controllers || controllers.size === 0) return;\n\n // Compute the RTP payload offset: 12-byte fixed header + CSRC list, plus\n // the extension header when the X bit is set.\n const csrcCount = packet[0] & 0x0f;\n let offset = 12 + csrcCount * 4;\n const hasExtension = (packet[0] & 0x10) !== 0;\n if (hasExtension) {\n if (packet.length < offset + 4) return;\n const extWords = view.getUint16(offset + 2, false);\n offset += 4 + extWords * 4;\n }\n if (packet.length < offset) return;\n const payload = packet.slice(offset);\n\n for (const controller of controllers) {\n try {\n controller.enqueue(payload);\n } catch {\n // Ignore errors on closed streams.\n }\n }\n }\n}\n\n// ─── Discord.js-familiar helpers (@discordjs/voice) ───────────────────────────\n\n/** Discord.js-familiar alias for {@link VoiceConnectionState}. Member values are Lunibee's. */\nexport { VoiceConnectionState as VoiceConnectionStatus };\n\n/** Active connections by guild, as tracked by {@link joinVoiceChannel}. */\nconst voiceConnections = new Map<string, VoiceConnection>();\n\n/**\n * Joins (or moves to) a voice channel, reusing the guild's tracked connection.\n * Mirrors `@discordjs/voice`'s `joinVoiceChannel`; transports are still attached\n * with {@link VoiceConnection.attachTransports}.\n * @param options Guild, channel and self mute/deaf flags.\n * @returns The guild's voice connection.\n * @throws {TypeError} If the guild or channel ID is empty.\n */\nexport function joinVoiceChannel(\n options: VoiceConnectionOptions & { channelId: string },\n): VoiceConnection {\n let connection = voiceConnections.get(options.guildId);\n if (!connection) {\n connection = new VoiceConnection(options);\n const created = connection;\n // VoiceConnection emits stateChange as (next, previous).\n created.on(\"stateChange\", (next) => {\n if (\n next === VoiceConnectionState.Destroyed &&\n voiceConnections.get(created.guildId) === created\n )\n voiceConnections.delete(created.guildId);\n });\n voiceConnections.set(options.guildId, connection);\n }\n connection.setChannel(options.channelId);\n connection.setSuppression(options);\n connection.connect();\n return connection;\n}\n\n/** Returns the connection tracked by {@link joinVoiceChannel} for a guild, if any. */\nexport function getVoiceConnection(\n guildId: string,\n): VoiceConnection | undefined {\n return voiceConnections.get(guildId);\n}\n\n/** Creates an {@link AudioPlayer}. Mirrors `@discordjs/voice`'s `createAudioPlayer`. */\nexport function createAudioPlayer(): AudioPlayer {\n return new AudioPlayer();\n}\n\n/** Creates an {@link AudioStream}. Mirrors `@discordjs/voice`'s `createAudioResource`. */\nexport function createAudioResource(\n stream: ReadableStream<Uint8Array>,\n metadata?: { title?: string; duration?: number },\n): AudioStream {\n return new AudioStream(stream, metadata);\n}\n\n/**\n * Resolves once a connection or player reaches `status`, or rejects after `timeoutMs`.\n * Mirrors `@discordjs/voice`'s `entersState`.\n * @returns The same target, for chaining.\n * @throws {VoiceError} If the state is not reached in time.\n */\nexport function entersState<T extends VoiceConnection | AudioPlayer>(\n target: T,\n status: T extends VoiceConnection ? VoiceConnectionState : AudioPlayerState,\n timeoutMs: number,\n): Promise<T> {\n if (target.state === status) return Promise.resolve(target);\n const emitter = target as unknown as {\n on(\n event: \"stateChange\",\n fn: (from: unknown, to: unknown) => void,\n ): unknown;\n off(\n event: \"stateChange\",\n fn: (from: unknown, to: unknown) => void,\n ): unknown;\n };\n // VoiceConnection emits (next, previous); AudioPlayer emits (from, to).\n const isConnection = target instanceof VoiceConnection;\n return new Promise<T>((resolve, reject) => {\n const onChange = (first: unknown, second: unknown): void => {\n if ((isConnection ? first : second) !== status) return;\n clearTimeout(timer);\n emitter.off(\"stateChange\", onChange);\n resolve(target);\n };\n const timer = setTimeout(() => {\n emitter.off(\"stateChange\", onChange);\n reject(\n new VoiceError(\n `Did not enter state \"${String(status)}\" within ${timeoutMs}ms.`,\n ),\n );\n }, timeoutMs);\n emitter.on(\"stateChange\", onChange);\n });\n}\n"
5
+ "/** Voice session lifecycle states. */\nexport enum VoiceConnectionState {\n Disconnected = \"disconnected\",\n Connecting = \"connecting\",\n Connected = \"connected\",\n Destroyed = \"destroyed\",\n}\n\n/** Voice protocol transport errors. */\nexport class VoiceError extends Error {\n /** Creates a voice error. @param message Error message. @param options Optional native error options. */\n public constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"VoiceError\";\n }\n}\n\n/** Options used to establish a voice session. */\nexport interface VoiceConnectionOptions {\n /** Guild containing the voice channel. */\n guildId: string;\n /** Voice channel to join. */\n channelId?: string;\n /** Whether the self user should be muted. */\n selfMute?: boolean;\n /** Whether the self user should be deafened. */\n selfDeaf?: boolean;\n}\n\n/** UDP transport supplied by the runtime-specific voice implementation. */\nexport interface VoiceUdpTransport {\n /** Sends an RTP/RTCP packet. @param packet Packet bytes. @param host Destination host. @param port Destination port. @returns Optional completion promise. */\n send(packet: Uint8Array, host: string, port: number): Promise<void> | void;\n /** Closes the UDP socket. @returns Nothing. */\n close(): void;\n /** Optional listener for incoming UDP packets. */\n onMessage?(listener: (packet: Uint8Array) => void): void;\n}\n\n/** Voice Gateway transport abstraction. */\nexport interface VoiceGatewayTransport {\n /** Opens the voice gateway. @param endpoint Voice gateway endpoint. @param sessionId Voice session identifier. @returns Promise fulfilled when connected. */\n connect(endpoint: string, sessionId: string): Promise<void>;\n /** Sends a voice gateway payload. @param payload Gateway payload. @returns Nothing. */\n send(payload: unknown): void;\n /** Closes the voice gateway. @param code Optional close code. @param reason Optional close reason. @returns Nothing. */\n close(code?: number, reason?: string): void;\n}\n\n/** Speaking flags used by the voice gateway. */\nexport const SpeakingFlags = {\n Microphone: 1,\n Soundshare: 2,\n Priority: 4,\n} as const;\n\n/** Voice session event payloads. */\nexport interface VoiceEvents {\n /** State transition event. */\n stateChange: [VoiceConnectionState, VoiceConnectionState];\n /** Speaking flag event. */\n speaking: [number, number];\n /** Voice transport error event. */\n error: [VoiceError];\n}\n\ntype VoiceListener = (...args: any[]) => unknown;\n\n/** Tracks a Discord voice session and exposes transport-independent lifecycle controls. */\nexport class VoiceConnection {\n /** Current voice connection state. */\n public state: VoiceConnectionState = VoiceConnectionState.Disconnected;\n /** Guild associated with this voice session. */\n public readonly guildId: string;\n /** Voice channel associated with this session. */\n public channelId?: string;\n /** Whether the client is self-muted. */\n public selfMute: boolean;\n /** Whether the client is self-deafened. */\n public selfDeaf: boolean;\n /** Active voice gateway transport, when attached. */\n public gateway?: VoiceGatewayTransport;\n /** Active UDP transport, when attached. */\n public udp?: VoiceUdpTransport;\n /** Registered lifecycle listeners. */\n readonly #listeners = new Map<keyof VoiceEvents, Set<VoiceListener>>();\n /** Receives incoming audio. */\n public readonly receiver: VoiceReceiver;\n\n /** Creates a voice connection state manager. @param options Guild ID or connection options. @throws {TypeError} If the guild ID is empty. */\n public constructor(options: string | VoiceConnectionOptions) {\n const resolved =\n typeof options === \"string\" ? { guildId: options } : options;\n if (!resolved.guildId?.trim()) {\n throw new TypeError(\n \"A guild ID is required for a voice connection.\",\n );\n }\n this.guildId = resolved.guildId;\n this.channelId = resolved.channelId;\n this.selfMute = resolved.selfMute ?? false;\n this.selfDeaf = resolved.selfDeaf ?? false;\n this.receiver = new VoiceReceiver(this);\n }\n\n /** Registers a voice lifecycle listener. @param event Event name. @param listener Listener callback. @returns This connection. @throws {TypeError} If listener is not callable. */\n public on<K extends keyof VoiceEvents>(\n event: K,\n listener: (...args: VoiceEvents[K]) => unknown,\n ): this {\n if (typeof listener !== \"function\")\n throw new TypeError(\"Voice listener must be a function.\");\n let listeners = this.#listeners.get(event);\n if (!listeners) this.#listeners.set(event, (listeners = new Set()));\n listeners.add(listener);\n return this;\n }\n\n /** Removes a voice lifecycle listener. @param event Event name. @param listener Listener callback. @returns This connection. */\n public off<K extends keyof VoiceEvents>(\n event: K,\n listener: (...args: VoiceEvents[K]) => unknown,\n ): this {\n this.#listeners.get(event)?.delete(listener);\n return this;\n }\n\n /** Attaches protocol transports, replacing and cleaning up the old pair when present. @param gateway Voice gateway transport. @param udp UDP transport. @returns This connection. @throws {VoiceError} If the connection is destroyed. @throws {TypeError} If a transport is missing. */\n public attachTransports(\n gateway: VoiceGatewayTransport,\n udp: VoiceUdpTransport,\n ): this {\n this.assertUsable();\n if (!gateway || !udp)\n throw new TypeError(\n \"Both voice gateway and UDP transports are required.\",\n );\n if (this.gateway || this.udp) this.#closeTransports();\n this.gateway = gateway;\n this.udp = udp;\n // Capture the transport this listener belongs to so that packets from a\n // later-replaced transport (whose listener cannot be unregistered — the\n // VoiceUdpTransport interface exposes no removal API) are ignored.\n const attachedUdp = udp;\n if (attachedUdp.onMessage) {\n attachedUdp.onMessage((packet) => {\n if (this.udp === attachedUdp) this.receiver.onPacket(packet);\n });\n }\n return this;\n }\n\n /** Begins the connection lifecycle. @returns Nothing. @throws {VoiceError} If the connection is destroyed. */\n public connect(): void {\n this.assertUsable();\n if (this.state === VoiceConnectionState.Connected) return;\n this.#transition(VoiceConnectionState.Connecting);\n if (this.state !== VoiceConnectionState.Connecting) return;\n this.#transition(VoiceConnectionState.Connected);\n }\n\n /** Disconnects the current voice session. @returns Nothing. */\n public disconnect(): void {\n if (this.state === VoiceConnectionState.Destroyed) return;\n this.#closeTransports();\n this.receiver.close();\n this.#transition(VoiceConnectionState.Disconnected);\n }\n\n /** Permanently destroys this voice connection. @returns Nothing. */\n public destroy(): void {\n if (this.state === VoiceConnectionState.Destroyed) return;\n this.#closeTransports();\n this.receiver.close();\n this.channelId = undefined;\n this.#transition(VoiceConnectionState.Destroyed);\n this.#listeners.clear();\n }\n\n /** Updates the voice channel and connection state. @param channelId Voice channel identifier. @returns Nothing. @throws {VoiceError} If the connection is destroyed. @throws {TypeError} If channelId is empty. */\n public setChannel(channelId: string): void {\n this.assertUsable();\n if (!channelId?.trim())\n throw new TypeError(\"A voice channel ID is required.\");\n this.channelId = channelId;\n }\n\n /** Updates self mute/deaf state. @param options Suppression flags. @returns Nothing. @throws {VoiceError} If the connection is destroyed. */\n public setSuppression(options: {\n selfMute?: boolean;\n selfDeaf?: boolean;\n }): void {\n this.assertUsable();\n if (options.selfMute !== undefined) this.selfMute = options.selfMute;\n if (options.selfDeaf !== undefined) this.selfDeaf = options.selfDeaf;\n }\n\n /** Publishes a speaking state through the attached voice gateway. @param flags Speaking flags. @returns Nothing. @throws {VoiceError} If the connection is destroyed or has no gateway transport. */\n public setSpeaking(flags: number = SpeakingFlags.Microphone): void {\n this.assertUsable();\n if (!this.gateway) {\n throw new VoiceError(\n \"A voice gateway transport is required to change speaking state.\",\n );\n }\n this.gateway.send({ op: 5, d: { speaking: flags, delay: 0, ssrc: 0 } });\n this.#emit(\"speaking\", flags, 0);\n }\n\n /** Ensures the connection is still usable. @returns Nothing. @throws {VoiceError} If destroyed. */\n #assertUsable(): void {\n if (this.state === VoiceConnectionState.Destroyed) {\n throw new VoiceError(\"Voice connection has been destroyed.\");\n }\n }\n\n /** Closes both active transports while isolating cleanup failures. @returns Nothing. */\n #closeTransports(): void {\n try {\n this.gateway?.close(1000, \"Voice connection replaced or closed\");\n } catch (error) {\n this.#emit(\n \"error\",\n error instanceof VoiceError\n ? error\n : new VoiceError(\"Voice gateway cleanup failed.\", {\n cause: error,\n }),\n );\n }\n try {\n this.udp?.close();\n } catch (error) {\n this.#emit(\n \"error\",\n error instanceof VoiceError\n ? error\n : new VoiceError(\"Voice UDP cleanup failed.\", {\n cause: error,\n }),\n );\n }\n this.gateway = undefined;\n this.udp = undefined;\n }\n\n /** Transitions to a new lifecycle state and emits the transition event. @param next Next state. @returns Nothing. */\n #transition(next: VoiceConnectionState): void {\n const previous = this.state;\n this.state = next;\n if (previous === next) return;\n for (const listener of this.#listeners.get(\"stateChange\") ?? []) {\n try {\n void listener(next, previous);\n } catch (error) {\n this.#emit(\n \"error\",\n error instanceof VoiceError\n ? error\n : new VoiceError(\"Voice event listener failed.\", {\n cause: error,\n }),\n );\n }\n if (this.state !== next && next !== VoiceConnectionState.Destroyed)\n return;\n }\n }\n\n /** Emits a voice event while isolating consumer failures. @param event Event name. @param args Event arguments. @returns Nothing. */\n #emit<K extends keyof VoiceEvents>(\n event: K,\n ...args: VoiceEvents[K]\n ): void {\n for (const listener of this.#listeners.get(event) ?? []) {\n try {\n void listener(...args);\n } catch {\n /* Consumer failures are isolated. */\n }\n }\n }\n\n /** Ensures the connection is still usable. @returns Nothing. @throws {VoiceError} If destroyed. */\n private assertUsable(): void {\n this.#assertUsable();\n }\n}\n\n// ─── Audio Pipeline ───────────────────────────────────────────────────────────\n\n/** Audio player lifecycle states. */\nexport type AudioPlayerState = \"idle\" | \"playing\" | \"paused\" | \"stopped\";\n\n/** An audio stream — wraps a `ReadableStream<Uint8Array>` with optional metadata. */\nexport class AudioStream {\n /** Underlying binary stream. */ public readonly stream: ReadableStream<Uint8Array>;\n /** Optional human-readable title for the stream. */ public readonly title?: string;\n /** Optional duration hint in seconds. */ public readonly duration?: number;\n\n /** Creates an audio stream.\n * @param stream Binary audio data stream.\n * @param metadata Optional metadata: title and duration in seconds.\n */\n public constructor(\n stream: ReadableStream<Uint8Array>,\n metadata?: { title?: string; duration?: number },\n ) {\n this.stream = stream;\n this.title = metadata?.title;\n this.duration = metadata?.duration;\n }\n}\n\ntype AudioPlayerListener<K extends keyof AudioPlayerEvents> = (\n ...args: AudioPlayerEvents[K]\n) => unknown;\n\ninterface AudioPlayerEvents {\n stateChange: [from: AudioPlayerState, to: AudioPlayerState];\n error: [error: Error];\n finish: [];\n}\n\n/**\n * Lightweight audio player with a simple state machine.\n *\n * States:\n * - `idle` — no stream loaded.\n * - `playing` — actively feeding audio data.\n * - `paused` — temporarily suspended; can be resumed.\n * - `stopped` — stream was stopped and discarded; load a new stream to play again.\n *\n * Events: `stateChange(from, to)`, `error(err)`, `finish()`.\n */\nexport class AudioPlayer {\n #state: AudioPlayerState = \"idle\";\n #stream?: AudioStream;\n #reader?: ReadableStreamDefaultReader<Uint8Array>;\n /** Resolves the pump's pause await when the player is resumed or stopped. */\n #resumeSignal?: () => void;\n readonly #listeners = new Map<\n string,\n Set<AudioPlayerListener<keyof AudioPlayerEvents>>\n >();\n\n /** Current player state. */\n public get state(): AudioPlayerState {\n return this.#state;\n }\n\n /** The audio stream currently loaded, if any. */\n public get current(): AudioStream | undefined {\n return this.#stream;\n }\n\n /**\n * Begins playing an audio stream.\n * If a stream is already playing, it is stopped first; the previous\n * stream's reader cancellation is awaited before the new stream starts so\n * the old and new pump loops cannot run concurrently.\n * @param audioStream Stream to play.\n */\n public async play(audioStream: AudioStream): Promise<void> {\n if (this.#state === \"playing\" || this.#state === \"paused\")\n await this.stop();\n this.#stream = audioStream;\n this.#reader = audioStream.stream.getReader();\n this.#transition(\"playing\");\n this.#pump().catch((err) => this.#emitError(err));\n }\n\n /** Pauses a currently-playing stream. No-op if not playing. */\n public pause(): void {\n if (this.#state !== \"playing\") return;\n this.#transition(\"paused\");\n }\n\n /** Resumes a paused stream. No-op if not paused. */\n public resume(): void {\n if (this.#state !== \"paused\") return;\n this.#transition(\"playing\");\n // Wake the existing pump loop rather than starting a second one.\n const signal = this.#resumeSignal;\n this.#resumeSignal = undefined;\n signal?.();\n }\n\n /**\n * Stops and discards the current stream. The returned promise resolves once\n * the underlying reader's cancellation has settled, so a subsequent `play`\n * never overlaps with the previous pump loop.\n */\n public async stop(): Promise<void> {\n if (this.#state === \"idle\" || this.#state === \"stopped\") return;\n const reader = this.#reader;\n this.#reader = undefined;\n this.#stream = undefined;\n this.#transition(\"stopped\");\n // Release a pump loop that is currently awaiting a resume.\n const signal = this.#resumeSignal;\n this.#resumeSignal = undefined;\n signal?.();\n if (reader) {\n try {\n await reader.cancel();\n } catch {\n /* Cancellation failures are non-fatal. */\n }\n }\n }\n\n /** Registers an event listener. @returns `this` for chaining. */\n public on<K extends keyof AudioPlayerEvents>(\n event: K,\n listener: AudioPlayerListener<K>,\n ): this {\n let set = this.#listeners.get(event) as\n Set<AudioPlayerListener<K>> | undefined;\n if (!set) {\n this.#listeners.set(\n event,\n (set = new Set() as unknown as Set<\n AudioPlayerListener<keyof AudioPlayerEvents>\n >),\n );\n }\n (set as unknown as Set<AudioPlayerListener<K>>).add(listener);\n return this;\n }\n\n /** Removes an event listener. @returns `this` for chaining. */\n public off<K extends keyof AudioPlayerEvents>(\n event: K,\n listener: AudioPlayerListener<K>,\n ): this {\n (\n this.#listeners.get(event) as\n Set<AudioPlayerListener<K>> | undefined\n )?.delete(listener);\n return this;\n }\n\n /**\n * Handles a decoded audio chunk. The base implementation is a no-op;\n * subclasses override this to pipe audio to a UDP socket or other sink.\n * @param chunk A chunk of audio bytes read from the current stream.\n */\n protected onChunk(chunk: Uint8Array): void {\n void chunk;\n }\n\n /** Reads chunks from the reader while the player is in a playing state. */\n async #pump(): Promise<void> {\n const reader = this.#reader;\n if (!reader) return;\n while (true) {\n // Suspend without polling: park until resume()/stop() signals us.\n if (this.#state === \"paused\") {\n await new Promise<void>((resolve) => {\n this.#resumeSignal = resolve;\n });\n }\n // Abort if stopped/idle (e.g. resolved by stop()).\n if (this.#state !== \"playing\") return;\n const { done, value } = await reader.read();\n if (done) {\n if (this.#state === \"playing\" || this.#state === \"paused\") {\n this.#transition(\"idle\");\n this.#stream = undefined;\n this.#reader = undefined;\n this.#emit(\"finish\");\n }\n return;\n }\n // A stop() during the read wins — drop the chunk and exit.\n if (this.#state !== \"playing\" && this.#state !== \"paused\") return;\n // Deliver the chunk to the sink hook; loop back to honour pause state.\n this.onChunk(value);\n }\n }\n\n #transition(next: AudioPlayerState): void {\n if (this.#state === next) return;\n const from = this.#state;\n this.#state = next;\n this.#emit(\"stateChange\", from, next);\n }\n\n #emitError(err: unknown): void {\n this.#emit(\n \"error\",\n err instanceof Error ? err : new VoiceError(String(err)),\n );\n }\n\n #emit<K extends keyof AudioPlayerEvents>(\n event: K,\n ...args: AudioPlayerEvents[K]\n ): void {\n for (const listener of this.#listeners.get(event) ?? []) {\n try {\n void (listener as (...a: unknown[]) => unknown)(...args);\n } catch {\n /* Listener failures are isolated. */\n }\n }\n }\n}\n\n// ─── Audio Receive Pipeline ───────────────────────────────────────────────────\n\n/** Tracks incoming audio and maps SSRCs to readable streams per user. */\nexport class VoiceReceiver {\n /** The connection this receiver is attached to. */\n public readonly connection: VoiceConnection;\n readonly #ssrcMap = new Map<number, string>();\n /** Active stream controllers per user; a Set so multiple subscribers to the\n * same user all receive audio instead of the last one overwriting earlier ones. */\n readonly #streams = new Map<\n string,\n Set<ReadableStreamDefaultController<Uint8Array>>\n >();\n\n /** Creates a VoiceReceiver. @param connection Voice connection. */\n public constructor(connection: VoiceConnection) {\n this.connection = connection;\n }\n\n /** Maps an SSRC to a User ID (usually from gateway speaking events). */\n public mapSsrc(ssrc: number, userId: string): void {\n this.#ssrcMap.set(ssrc, userId);\n }\n\n /** Subscribes to incoming audio from a specific user. @param userId User identifier. @returns A binary readable stream of the audio. */\n public subscribe(userId: string): AudioStream {\n // A destroyed connection never closes its receiver again, so a late\n // subscriber would wait forever.\n if (this.connection.state === VoiceConnectionState.Destroyed)\n throw new VoiceError(\"Voice connection has been destroyed.\");\n let controllerRef: ReadableStreamDefaultController<Uint8Array>;\n const stream = new ReadableStream<Uint8Array>({\n start: (controller) => {\n controllerRef = controller;\n let set = this.#streams.get(userId);\n if (!set) this.#streams.set(userId, (set = new Set()));\n set.add(controller);\n },\n cancel: () => {\n const set = this.#streams.get(userId);\n if (set) {\n set.delete(controllerRef);\n if (set.size === 0) this.#streams.delete(userId);\n }\n },\n });\n return new AudioStream(stream, { title: `User ${userId} Audio` });\n }\n\n /** Ends every subscriber stream and forgets SSRC mappings. Called when the\n * connection disconnects or is destroyed, so readers do not wait forever. */\n public close(): void {\n for (const controllers of this.#streams.values())\n for (const controller of controllers) {\n try {\n controller.close();\n } catch {\n // Already closed or errored by the consumer.\n }\n }\n this.#streams.clear();\n this.#ssrcMap.clear();\n }\n\n /** Processes an incoming UDP packet, extracting SSRC and routing the audio\n * payload (RTP header stripped) to every subscriber for the mapped user. */\n public onPacket(packet: Uint8Array): void {\n if (packet.length < 12) return;\n\n const view = new DataView(\n packet.buffer,\n packet.byteOffset,\n packet.byteLength,\n );\n const ssrc = view.getUint32(8, false);\n\n const userId = this.#ssrcMap.get(ssrc);\n if (!userId) return;\n const controllers = this.#streams.get(userId);\n if (!controllers || controllers.size === 0) return;\n\n // Compute the RTP payload offset: 12-byte fixed header + CSRC list, plus\n // the extension header when the X bit is set.\n const csrcCount = packet[0] & 0x0f;\n let offset = 12 + csrcCount * 4;\n const hasExtension = (packet[0] & 0x10) !== 0;\n if (hasExtension) {\n if (packet.length < offset + 4) return;\n const extWords = view.getUint16(offset + 2, false);\n offset += 4 + extWords * 4;\n }\n if (packet.length < offset) return;\n const payload = packet.slice(offset);\n\n for (const controller of controllers) {\n try {\n controller.enqueue(payload);\n } catch {\n // Ignore errors on closed streams.\n }\n }\n }\n}\n\n// ─── Discord.js-familiar helpers (@discordjs/voice) ───────────────────────────\n\n/** Discord.js-familiar alias for {@link VoiceConnectionState}. Member values are Lunibee's. */\nexport { VoiceConnectionState as VoiceConnectionStatus };\n\n/** Active connections by guild, as tracked by {@link joinVoiceChannel}. */\nconst voiceConnections = new Map<string, VoiceConnection>();\n\n/**\n * Joins (or moves to) a voice channel, reusing the guild's tracked connection.\n * Mirrors `@discordjs/voice`'s `joinVoiceChannel`; transports are still attached\n * with {@link VoiceConnection.attachTransports}.\n * @param options Guild, channel and self mute/deaf flags.\n * @returns The guild's voice connection.\n * @throws {TypeError} If the guild or channel ID is empty.\n */\nexport function joinVoiceChannel(\n options: VoiceConnectionOptions & { channelId: string },\n): VoiceConnection {\n let connection = voiceConnections.get(options.guildId);\n if (!connection) {\n connection = new VoiceConnection(options);\n const created = connection;\n // VoiceConnection emits stateChange as (next, previous).\n created.on(\"stateChange\", (next) => {\n if (\n next === VoiceConnectionState.Destroyed &&\n voiceConnections.get(created.guildId) === created\n )\n voiceConnections.delete(created.guildId);\n });\n voiceConnections.set(options.guildId, connection);\n }\n connection.setChannel(options.channelId);\n connection.setSuppression(options);\n connection.connect();\n return connection;\n}\n\n/** Returns the connection tracked by {@link joinVoiceChannel} for a guild, if any. */\nexport function getVoiceConnection(\n guildId: string,\n): VoiceConnection | undefined {\n return voiceConnections.get(guildId);\n}\n\n/** Creates an {@link AudioPlayer}. Mirrors `@discordjs/voice`'s `createAudioPlayer`. */\nexport function createAudioPlayer(): AudioPlayer {\n return new AudioPlayer();\n}\n\n/** Creates an {@link AudioStream}. Mirrors `@discordjs/voice`'s `createAudioResource`. */\nexport function createAudioResource(\n stream: ReadableStream<Uint8Array>,\n metadata?: { title?: string; duration?: number },\n): AudioStream {\n return new AudioStream(stream, metadata);\n}\n\n/**\n * Resolves once a connection or player reaches `status`, or rejects after `timeoutMs`.\n * Mirrors `@discordjs/voice`'s `entersState`.\n * @returns The same target, for chaining.\n * @throws {VoiceError} If the state is not reached in time.\n */\nexport function entersState<T extends VoiceConnection | AudioPlayer>(\n target: T,\n status: T extends VoiceConnection ? VoiceConnectionState : AudioPlayerState,\n timeoutMs: number,\n): Promise<T> {\n if (target.state === status) return Promise.resolve(target);\n const emitter = target as unknown as {\n on(\n event: \"stateChange\",\n fn: (from: unknown, to: unknown) => void,\n ): unknown;\n off(\n event: \"stateChange\",\n fn: (from: unknown, to: unknown) => void,\n ): unknown;\n };\n // VoiceConnection emits (next, previous); AudioPlayer emits (from, to).\n const isConnection = target instanceof VoiceConnection;\n return new Promise<T>((resolve, reject) => {\n const onChange = (first: unknown, second: unknown): void => {\n if ((isConnection ? first : second) !== status) return;\n clearTimeout(timer);\n emitter.off(\"stateChange\", onChange);\n resolve(target);\n };\n const timer = setTimeout(() => {\n emitter.off(\"stateChange\", onChange);\n reject(\n new VoiceError(\n `Did not enter state \"${String(status)}\" within ${timeoutMs}ms.`,\n ),\n );\n }, timeoutMs);\n emitter.on(\"stateChange\", onChange);\n });\n}\n"
6
6
  ],
7
- "mappings": ";;AACO,IAAK;AAAA,CAAL,CAAK,yBAAL;AAAA,EACH,uCAAe;AAAA,EACf,qCAAa;AAAA,EACb,oCAAY;AAAA,EACZ,oCAAY;AAAA,GAJJ;AAAA;AAQL,MAAM,mBAAmB,MAAM;AAAA,EAE3B,WAAW,CAAC,SAAiB,SAAwB;AAAA,IACxD,MAAM,SAAS,OAAO;AAAA,IACtB,KAAK,OAAO;AAAA;AAEpB;AAmCO,IAAM,gBAAgB;AAAA,EACzB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,UAAU;AACd;AAAA;AAeO,MAAM,gBAAgB;AAAA,EAElB,QAA8B;AAAA,EAErB;AAAA,EAET;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEE,aAAa,IAAI;AAAA,EAEV;AAAA,EAGT,WAAW,CAAC,SAA0C;AAAA,IACzD,MAAM,WACF,OAAO,YAAY,WAAW,EAAE,SAAS,QAAQ,IAAI;AAAA,IACzD,IAAI,CAAC,SAAS,SAAS,KAAK,GAAG;AAAA,MAC3B,MAAM,IAAI,UACN,gDACJ;AAAA,IACJ;AAAA,IACA,KAAK,UAAU,SAAS;AAAA,IACxB,KAAK,YAAY,SAAS;AAAA,IAC1B,KAAK,WAAW,SAAS,YAAY;AAAA,IACrC,KAAK,WAAW,SAAS,YAAY;AAAA,IACrC,KAAK,WAAW,IAAI,cAAc,IAAI;AAAA;AAAA,EAInC,EAA+B,CAClC,OACA,UACI;AAAA,IACJ,IAAI,OAAO,aAAa;AAAA,MACpB,MAAM,IAAI,UAAU,oCAAoC;AAAA,IAC5D,IAAI,YAAY,KAAK,WAAW,IAAI,KAAK;AAAA,IACzC,IAAI,CAAC;AAAA,MAAW,KAAK,WAAW,IAAI,OAAQ,YAAY,IAAI,GAAM;AAAA,IAClE,UAAU,IAAI,QAAQ;AAAA,IACtB,OAAO;AAAA;AAAA,EAIJ,GAAgC,CACnC,OACA,UACI;AAAA,IACJ,KAAK,WAAW,IAAI,KAAK,GAAG,OAAO,QAAQ;AAAA,IAC3C,OAAO;AAAA;AAAA,EAIJ,gBAAgB,CACnB,SACA,KACI;AAAA,IACJ,KAAK,aAAa;AAAA,IAClB,IAAI,CAAC,WAAW,CAAC;AAAA,MACb,MAAM,IAAI,UACN,qDACJ;AAAA,IACJ,IAAI,KAAK,WAAW,KAAK;AAAA,MAAK,KAAK,iBAAiB;AAAA,IACpD,KAAK,UAAU;AAAA,IACf,KAAK,MAAM;AAAA,IAIX,MAAM,cAAc;AAAA,IACpB,IAAI,YAAY,WAAW;AAAA,MACvB,YAAY,UAAU,CAAC,WAAW;AAAA,QAC9B,IAAI,KAAK,QAAQ;AAAA,UAAa,KAAK,SAAS,SAAS,MAAM;AAAA,OAC9D;AAAA,IACL;AAAA,IACA,OAAO;AAAA;AAAA,EAIJ,OAAO,GAAS;AAAA,IACnB,KAAK,aAAa;AAAA,IAClB,IAAI,KAAK,UAAU;AAAA,MAAgC;AAAA,IACnD,KAAK,YAAY,6BAA+B;AAAA,IAChD,IAAI,KAAK,UAAU;AAAA,MAAiC;AAAA,IACpD,KAAK,YAAY,2BAA8B;AAAA;AAAA,EAI5C,UAAU,GAAS;AAAA,IACtB,IAAI,KAAK,UAAU;AAAA,MAAgC;AAAA,IACnD,KAAK,iBAAiB;AAAA,IACtB,KAAK,YAAY,iCAAiC;AAAA;AAAA,EAI/C,OAAO,GAAS;AAAA,IACnB,IAAI,KAAK,UAAU;AAAA,MAAgC;AAAA,IACnD,KAAK,iBAAiB;AAAA,IACtB,KAAK,YAAY;AAAA,IACjB,KAAK,YAAY,2BAA8B;AAAA,IAC/C,KAAK,WAAW,MAAM;AAAA;AAAA,EAInB,UAAU,CAAC,WAAyB;AAAA,IACvC,KAAK,aAAa;AAAA,IAClB,IAAI,CAAC,WAAW,KAAK;AAAA,MACjB,MAAM,IAAI,UAAU,iCAAiC;AAAA,IACzD,KAAK,YAAY;AAAA;AAAA,EAId,cAAc,CAAC,SAGb;AAAA,IACL,KAAK,aAAa;AAAA,IAClB,IAAI,QAAQ,aAAa;AAAA,MAAW,KAAK,WAAW,QAAQ;AAAA,IAC5D,IAAI,QAAQ,aAAa;AAAA,MAAW,KAAK,WAAW,QAAQ;AAAA;AAAA,EAIzD,WAAW,CAAC,QAAgB,cAAc,YAAkB;AAAA,IAC/D,KAAK,aAAa;AAAA,IAClB,IAAI,CAAC,KAAK,SAAS;AAAA,MACf,MAAM,IAAI,WACN,iEACJ;AAAA,IACJ;AAAA,IACA,KAAK,QAAQ,KAAK,EAAE,IAAI,GAAG,GAAG,EAAE,UAAU,OAAO,OAAO,GAAG,MAAM,EAAE,EAAE,CAAC;AAAA,IACtE,KAAK,MAAM,YAAY,OAAO,CAAC;AAAA;AAAA,EAInC,aAAa,GAAS;AAAA,IAClB,IAAI,KAAK,UAAU,6BAAgC;AAAA,MAC/C,MAAM,IAAI,WAAW,sCAAsC;AAAA,IAC/D;AAAA;AAAA,EAIJ,gBAAgB,GAAS;AAAA,IACrB,IAAI;AAAA,MACA,KAAK,SAAS,MAAM,MAAM,qCAAqC;AAAA,MACjE,OAAO,OAAO;AAAA,MACZ,KAAK,MACD,SACA,iBAAiB,aACX,QACA,IAAI,WAAW,iCAAiC;AAAA,QAC5C,OAAO;AAAA,MACX,CAAC,CACX;AAAA;AAAA,IAEJ,IAAI;AAAA,MACA,KAAK,KAAK,MAAM;AAAA,MAClB,OAAO,OAAO;AAAA,MACZ,KAAK,MACD,SACA,iBAAiB,aACX,QACA,IAAI,WAAW,6BAA6B;AAAA,QACxC,OAAO;AAAA,MACX,CAAC,CACX;AAAA;AAAA,IAEJ,KAAK,UAAU;AAAA,IACf,KAAK,MAAM;AAAA;AAAA,EAIf,WAAW,CAAC,MAAkC;AAAA,IAC1C,MAAM,WAAW,KAAK;AAAA,IACtB,KAAK,QAAQ;AAAA,IACb,IAAI,aAAa;AAAA,MAAM;AAAA,IACvB,WAAW,YAAY,KAAK,WAAW,IAAI,aAAa,KAAK,CAAC,GAAG;AAAA,MAC7D,IAAI;AAAA,QACK,SAAS,MAAM,QAAQ;AAAA,QAC9B,OAAO,OAAO;AAAA,QACZ,KAAK,MACD,SACA,iBAAiB,aACX,QACA,IAAI,WAAW,gCAAgC;AAAA,UAC3C,OAAO;AAAA,QACX,CAAC,CACX;AAAA;AAAA,MAEJ,IAAI,KAAK,UAAU,QAAQ,SAAS;AAAA,QAChC;AAAA,IACR;AAAA;AAAA,EAIJ,KAAkC,CAC9B,UACG,MACC;AAAA,IACJ,WAAW,YAAY,KAAK,WAAW,IAAI,KAAK,KAAK,CAAC,GAAG;AAAA,MACrD,IAAI;AAAA,QACK,SAAS,GAAG,IAAI;AAAA,QACvB,MAAM;AAAA,IAGZ;AAAA;AAAA,EAII,YAAY,GAAS;AAAA,IACzB,KAAK,cAAc;AAAA;AAE3B;AAAA;AAQO,MAAM,YAAY;AAAA,EAC4B;AAAA,EACoB;AAAA,EACX;AAAA,EAMnD,WAAW,CACd,QACA,UACF;AAAA,IACE,KAAK,SAAS;AAAA,IACd,KAAK,QAAQ,UAAU;AAAA,IACvB,KAAK,WAAW,UAAU;AAAA;AAElC;AAAA;AAuBO,MAAM,YAAY;AAAA,EACrB,SAA2B;AAAA,EAC3B;AAAA,EACA;AAAA,EAEA;AAAA,EACS,aAAa,IAAI;AAAA,MAMf,KAAK,GAAqB;AAAA,IACjC,OAAO,KAAK;AAAA;AAAA,MAIL,OAAO,GAA4B;AAAA,IAC1C,OAAO,KAAK;AAAA;AAAA,OAUH,KAAI,CAAC,aAAyC;AAAA,IACvD,IAAI,KAAK,WAAW,aAAa,KAAK,WAAW;AAAA,MAC7C,MAAM,KAAK,KAAK;AAAA,IACpB,KAAK,UAAU;AAAA,IACf,KAAK,UAAU,YAAY,OAAO,UAAU;AAAA,IAC5C,KAAK,YAAY,SAAS;AAAA,IAC1B,KAAK,MAAM,EAAE,MAAM,CAAC,QAAQ,KAAK,WAAW,GAAG,CAAC;AAAA;AAAA,EAI7C,KAAK,GAAS;AAAA,IACjB,IAAI,KAAK,WAAW;AAAA,MAAW;AAAA,IAC/B,KAAK,YAAY,QAAQ;AAAA;AAAA,EAItB,MAAM,GAAS;AAAA,IAClB,IAAI,KAAK,WAAW;AAAA,MAAU;AAAA,IAC9B,KAAK,YAAY,SAAS;AAAA,IAE1B,MAAM,SAAS,KAAK;AAAA,IACpB,KAAK,gBAAgB;AAAA,IACrB,SAAS;AAAA;AAAA,OAQA,KAAI,GAAkB;AAAA,IAC/B,IAAI,KAAK,WAAW,UAAU,KAAK,WAAW;AAAA,MAAW;AAAA,IACzD,MAAM,SAAS,KAAK;AAAA,IACpB,KAAK,UAAU;AAAA,IACf,KAAK,UAAU;AAAA,IACf,KAAK,YAAY,SAAS;AAAA,IAE1B,MAAM,SAAS,KAAK;AAAA,IACpB,KAAK,gBAAgB;AAAA,IACrB,SAAS;AAAA,IACT,IAAI,QAAQ;AAAA,MACR,IAAI;AAAA,QACA,MAAM,OAAO,OAAO;AAAA,QACtB,MAAM;AAAA,IAGZ;AAAA;AAAA,EAIG,EAAqC,CACxC,OACA,UACI;AAAA,IACJ,IAAI,MAAM,KAAK,WAAW,IAAI,KAAK;AAAA,IAEnC,IAAI,CAAC,KAAK;AAAA,MACN,KAAK,WAAW,IACZ,OACC,MAAM,IAAI,GAGf;AAAA,IACJ;AAAA,IACC,IAA+C,IAAI,QAAQ;AAAA,IAC5D,OAAO;AAAA;AAAA,EAIJ,GAAsC,CACzC,OACA,UACI;AAAA,IAEA,KAAK,WAAW,IAAI,KAAK,GAE1B,OAAO,QAAQ;AAAA,IAClB,OAAO;AAAA;AAAA,EAQD,OAAO,CAAC,OAAyB;AAAA,OAKrC,KAAK,GAAkB;AAAA,IACzB,MAAM,SAAS,KAAK;AAAA,IACpB,IAAI,CAAC;AAAA,MAAQ;AAAA,IACb,OAAO,MAAM;AAAA,MAET,IAAI,KAAK,WAAW,UAAU;AAAA,QAC1B,MAAM,IAAI,QAAc,CAAC,YAAY;AAAA,UACjC,KAAK,gBAAgB;AAAA,SACxB;AAAA,MACL;AAAA,MAEA,IAAI,KAAK,WAAW;AAAA,QAAW;AAAA,MAC/B,QAAQ,MAAM,UAAU,MAAM,OAAO,KAAK;AAAA,MAC1C,IAAI,MAAM;AAAA,QACN,IAAI,KAAK,WAAW,aAAa,KAAK,WAAW,UAAU;AAAA,UACvD,KAAK,YAAY,MAAM;AAAA,UACvB,KAAK,UAAU;AAAA,UACf,KAAK,UAAU;AAAA,UACf,KAAK,MAAM,QAAQ;AAAA,QACvB;AAAA,QACA;AAAA,MACJ;AAAA,MAEA,IAAI,KAAK,WAAW,aAAa,KAAK,WAAW;AAAA,QAAU;AAAA,MAE3D,KAAK,QAAQ,KAAK;AAAA,IACtB;AAAA;AAAA,EAGJ,WAAW,CAAC,MAA8B;AAAA,IACtC,IAAI,KAAK,WAAW;AAAA,MAAM;AAAA,IAC1B,MAAM,OAAO,KAAK;AAAA,IAClB,KAAK,SAAS;AAAA,IACd,KAAK,MAAM,eAAe,MAAM,IAAI;AAAA;AAAA,EAGxC,UAAU,CAAC,KAAoB;AAAA,IAC3B,KAAK,MACD,SACA,eAAe,QAAQ,MAAM,IAAI,WAAW,OAAO,GAAG,CAAC,CAC3D;AAAA;AAAA,EAGJ,KAAwC,CACpC,UACG,MACC;AAAA,IACJ,WAAW,YAAY,KAAK,WAAW,IAAI,KAAK,KAAK,CAAC,GAAG;AAAA,MACrD,IAAI;AAAA,QACM,SAA0C,GAAG,IAAI;AAAA,QACzD,MAAM;AAAA,IAGZ;AAAA;AAER;AAAA;AAKO,MAAM,cAAc;AAAA,EAEP;AAAA,EACP,WAAW,IAAI;AAAA,EAGf,WAAW,IAAI;AAAA,EAMjB,WAAW,CAAC,YAA6B;AAAA,IAC5C,KAAK,aAAa;AAAA;AAAA,EAIf,OAAO,CAAC,MAAc,QAAsB;AAAA,IAC/C,KAAK,SAAS,IAAI,MAAM,MAAM;AAAA;AAAA,EAI3B,SAAS,CAAC,QAA6B;AAAA,IAC1C,IAAI;AAAA,IACJ,MAAM,SAAS,IAAI,eAA2B;AAAA,MAC1C,OAAO,CAAC,eAAe;AAAA,QACnB,gBAAgB;AAAA,QAChB,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM;AAAA,QAClC,IAAI,CAAC;AAAA,UAAK,KAAK,SAAS,IAAI,QAAS,MAAM,IAAI,GAAM;AAAA,QACrD,IAAI,IAAI,UAAU;AAAA;AAAA,MAEtB,QAAQ,MAAM;AAAA,QACV,MAAM,MAAM,KAAK,SAAS,IAAI,MAAM;AAAA,QACpC,IAAI,KAAK;AAAA,UACL,IAAI,OAAO,aAAa;AAAA,UACxB,IAAI,IAAI,SAAS;AAAA,YAAG,KAAK,SAAS,OAAO,MAAM;AAAA,QACnD;AAAA;AAAA,IAER,CAAC;AAAA,IACD,OAAO,IAAI,YAAY,QAAQ,EAAE,OAAO,QAAQ,eAAe,CAAC;AAAA;AAAA,EAK7D,QAAQ,CAAC,QAA0B;AAAA,IACtC,IAAI,OAAO,SAAS;AAAA,MAAI;AAAA,IAExB,MAAM,OAAO,IAAI,SACb,OAAO,QACP,OAAO,YACP,OAAO,UACX;AAAA,IACA,MAAM,OAAO,KAAK,UAAU,GAAG,KAAK;AAAA,IAEpC,MAAM,SAAS,KAAK,SAAS,IAAI,IAAI;AAAA,IACrC,IAAI,CAAC;AAAA,MAAQ;AAAA,IACb,MAAM,cAAc,KAAK,SAAS,IAAI,MAAM;AAAA,IAC5C,IAAI,CAAC,eAAe,YAAY,SAAS;AAAA,MAAG;AAAA,IAI5C,MAAM,YAAY,OAAO,KAAK;AAAA,IAC9B,IAAI,SAAS,KAAK,YAAY;AAAA,IAC9B,MAAM,gBAAgB,OAAO,KAAK,QAAU;AAAA,IAC5C,IAAI,cAAc;AAAA,MACd,IAAI,OAAO,SAAS,SAAS;AAAA,QAAG;AAAA,MAChC,MAAM,WAAW,KAAK,UAAU,SAAS,GAAG,KAAK;AAAA,MACjD,UAAU,IAAI,WAAW;AAAA,IAC7B;AAAA,IACA,IAAI,OAAO,SAAS;AAAA,MAAQ;AAAA,IAC5B,MAAM,UAAU,OAAO,MAAM,MAAM;AAAA,IAEnC,WAAW,cAAc,aAAa;AAAA,MAClC,IAAI;AAAA,QACA,WAAW,QAAQ,OAAO;AAAA,QAC5B,MAAM;AAAA,IAGZ;AAAA;AAER;AAQA,IAAM,mBAAmB,IAAI;AAUtB,SAAS,gBAAgB,CAC5B,SACe;AAAA,EACf,IAAI,aAAa,iBAAiB,IAAI,QAAQ,OAAO;AAAA,EACrD,IAAI,CAAC,YAAY;AAAA,IACb,aAAa,IAAI,gBAAgB,OAAO;AAAA,IACxC,MAAM,UAAU;AAAA,IAEhB,QAAQ,GAAG,eAAe,CAAC,SAAS;AAAA,MAChC,IACI,SAAS,+BACT,iBAAiB,IAAI,QAAQ,OAAO,MAAM;AAAA,QAE1C,iBAAiB,OAAO,QAAQ,OAAO;AAAA,KAC9C;AAAA,IACD,iBAAiB,IAAI,QAAQ,SAAS,UAAU;AAAA,EACpD;AAAA,EACA,WAAW,WAAW,QAAQ,SAAS;AAAA,EACvC,WAAW,eAAe,OAAO;AAAA,EACjC,WAAW,QAAQ;AAAA,EACnB,OAAO;AAAA;AAIJ,SAAS,kBAAkB,CAC9B,SAC2B;AAAA,EAC3B,OAAO,iBAAiB,IAAI,OAAO;AAAA;AAIhC,SAAS,iBAAiB,GAAgB;AAAA,EAC7C,OAAO,IAAI;AAAA;AAIR,SAAS,mBAAmB,CAC/B,QACA,UACW;AAAA,EACX,OAAO,IAAI,YAAY,QAAQ,QAAQ;AAAA;AASpC,SAAS,WAAoD,CAChE,QACA,QACA,WACU;AAAA,EACV,IAAI,OAAO,UAAU;AAAA,IAAQ,OAAO,QAAQ,QAAQ,MAAM;AAAA,EAC1D,MAAM,UAAU;AAAA,EAWhB,MAAM,eAAe,kBAAkB;AAAA,EACvC,OAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AAAA,IACvC,MAAM,WAAW,CAAC,OAAgB,WAA0B;AAAA,MACxD,KAAK,eAAe,QAAQ,YAAY;AAAA,QAAQ;AAAA,MAChD,aAAa,KAAK;AAAA,MAClB,QAAQ,IAAI,eAAe,QAAQ;AAAA,MACnC,QAAQ,MAAM;AAAA;AAAA,IAElB,MAAM,QAAQ,WAAW,MAAM;AAAA,MAC3B,QAAQ,IAAI,eAAe,QAAQ;AAAA,MACnC,OACI,IAAI,WACA,wBAAwB,OAAO,MAAM,aAAa,cACtD,CACJ;AAAA,OACD,SAAS;AAAA,IACZ,QAAQ,GAAG,eAAe,QAAQ;AAAA,GACrC;AAAA;",
8
- "debugId": "C61FD04CD1E9BF4D64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "9E96BE25F2F4C69B64756E2164756E21",
9
9
  "names": []
10
10
  }