lunibee 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +225 -225
- package/dist/builders/attachment.d.ts +8 -0
- package/dist/builders/commands.d.ts +122 -65
- package/dist/builders/components.d.ts +10 -31
- package/dist/builders/embed.d.ts +66 -33
- package/dist/builders/index.js +97 -131
- package/dist/builders/index.js.map +8 -8
- package/dist/collection/cache.d.ts +13 -6
- package/dist/collection/index.d.ts +90 -17
- package/dist/collection/index.js +442 -266
- package/dist/collection/index.js.map +4 -4
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.js +607 -352
- package/dist/core/index.js.map +47 -47
- package/dist/core/permissions.d.ts +7 -3
- package/dist/formatters/index.js +9 -5
- package/dist/formatters/index.js.map +3 -3
- package/dist/handlers/index.js +5 -10
- package/dist/handlers/index.js.map +3 -3
- package/dist/index.js +769 -587
- package/dist/index.js.map +65 -65
- package/dist/managers/base.d.ts +22 -14
- package/dist/managers/index.d.ts +2 -1
- package/dist/managers/index.js +445 -276
- package/dist/managers/index.js.map +26 -26
- package/dist/managers/message.d.ts +7 -3
- package/dist/rest/errors.d.ts +14 -7
- package/dist/rest/index.d.ts +24 -12
- package/dist/rest/index.js +54 -17
- package/dist/rest/index.js.map +14 -14
- package/dist/rest/redis.d.ts +1 -1
- package/dist/rest/route.d.ts +8 -4
- package/dist/rest/routes.d.ts +102 -48
- package/dist/rest/transport.d.ts +10 -5
- package/dist/rest/webhook.d.ts +9 -5
- package/dist/sharding/bus.d.ts +34 -17
- package/dist/sharding/index.d.ts +34 -17
- package/dist/sharding/index.js +64 -32
- package/dist/sharding/index.js.map +17 -17
- package/dist/structures/base.d.ts +19 -10
- package/dist/structures/channels.d.ts +28 -14
- package/dist/structures/index.js +9 -59
- package/dist/structures/index.js.map +19 -18
- package/dist/structures/interactions.d.ts +96 -48
- package/dist/structures/resources.d.ts +88 -44
- package/dist/types/gateway.d.ts +1 -1
- package/dist/types/index.js +20 -22
- package/dist/types/index.js.map +4 -4
- package/dist/utils/index.js.map +2 -2
- package/dist/voice/index.d.ts +12 -4
- package/dist/voice/index.js +14 -18
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/decoder.d.ts +6 -2
- package/dist/ws/index.d.ts +25 -13
- package/dist/ws/index.js +63 -31
- package/dist/ws/index.js.map +14 -14
- package/dist/ws/protocol.d.ts +10 -2
- package/dist/ws/session.d.ts +14 -4
- package/dist/ws/state.d.ts +22 -11
- package/package.json +15 -14
package/dist/core/index.js.map
CHANGED
|
@@ -2,53 +2,53 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../packages/core/src/permissions.ts", "../../packages/core/src/events.ts", "../../packages/core/src/collector.ts", "../../packages/types/src/gateway.ts", "../../packages/types/src/index.ts", "../../packages/collection/src/index.ts", "../../packages/managers/src/base.ts", "../../packages/rest/src/store.ts", "../../packages/rest/src/errors.ts", "../../packages/rest/src/route.ts", "../../packages/rest/src/scheduler.ts", "../../packages/rest/src/limiter.ts", "../../packages/rest/src/transport.ts", "../../packages/rest/src/decoder.ts", "../../packages/rest/src/routes.ts", "../../packages/rest/src/index.ts", "../../packages/structures/src/base.ts", "../../packages/structures/src/resources.ts", "../../packages/structures/src/channels.ts", "../../packages/structures/src/options.ts", "../../packages/structures/src/interactions.ts", "../../packages/structures/src/index.ts", "../../packages/managers/src/message.ts", "../../packages/managers/src/thread.ts", "../../packages/managers/src/user.ts", "../../packages/managers/src/emoji.ts", "../../packages/managers/src/advanced.ts", "../../packages/managers/src/member.ts", "../../packages/managers/src/role.ts", "../../packages/managers/src/guild-resources.ts", "../../packages/managers/src/guild.ts", "../../packages/managers/src/application.ts", "../../packages/managers/src/index.ts", "../../packages/ws/src/session.ts", "../../packages/ws/src/heartbeat.ts", "../../packages/ws/src/close-codes.ts", "../../packages/ws/src/reconnect.ts", "../../packages/ws/src/decoder.ts", "../../packages/ws/src/transport.ts", "../../packages/ws/src/opcodes.ts", "../../packages/ws/src/protocol.ts", "../../packages/ws/src/state.ts", "../../packages/ws/src/send-budget.ts", "../../packages/ws/src/index.ts", "../../packages/core/src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/** Permission overwrite target types. */\nexport enum PermissionOverwriteEnum {\n Role = 0,\n Member = 1,\n}\n/** @deprecated Use {@link PermissionOverwriteEnum}. Removed in 0.3.0. */\nexport const PermissionOverwriteType = PermissionOverwriteEnum;\n/** @deprecated Use {@link PermissionOverwriteEnum}. Removed in 0.3.0. */\nexport type PermissionOverwriteType = PermissionOverwriteEnum;\n\n/** Lunibee idiomatic camelCase permission bitflags. */\nexport const Permission = {\n createInstantInvite: 1n << 0n,\n kickMembers: 1n << 1n,\n banMembers: 1n << 2n,\n administrator: 1n << 3n,\n manageChannels: 1n << 4n,\n manageGuild: 1n << 5n,\n addReactions: 1n << 6n,\n viewAuditLog: 1n << 7n,\n prioritySpeaker: 1n << 8n,\n stream: 1n << 9n,\n viewChannel: 1n << 10n,\n sendMessages: 1n << 11n,\n sendTTSMessages: 1n << 12n,\n manageMessages: 1n << 13n,\n embedLinks: 1n << 14n,\n attachFiles: 1n << 15n,\n readMessageHistory: 1n << 16n,\n mentionEveryone: 1n << 17n,\n useExternalEmojis: 1n << 18n,\n viewGuildInsights: 1n << 19n,\n connect: 1n << 20n,\n speak: 1n << 21n,\n muteMembers: 1n << 22n,\n deafenMembers: 1n << 23n,\n moveMembers: 1n << 24n,\n useVAD: 1n << 25n,\n changeNickname: 1n << 26n,\n manageNicknames: 1n << 27n,\n manageRoles: 1n << 28n,\n manageWebhooks: 1n << 29n,\n manageGuildExpressions: 1n << 30n,\n useApplicationCommands: 1n << 31n,\n requestToSpeak: 1n << 32n,\n manageEvents: 1n << 33n,\n manageThreads: 1n << 34n,\n createPublicThreads: 1n << 35n,\n createPrivateThreads: 1n << 36n,\n useExternalStickers: 1n << 37n,\n sendMessagesInThreads: 1n << 38n,\n useEmbeddedActivities: 1n << 39n,\n moderateMembers: 1n << 40n,\n viewCreatorMonetizationAnalytics: 1n << 41n,\n useSoundboard: 1n << 42n,\n createGuildExpressions: 1n << 43n,\n createEvents: 1n << 44n,\n useExternalSounds: 1n << 45n,\n sendVoiceMessages: 1n << 46n,\n setVoiceChannelStatus: 1n << 48n,\n sendPolls: 1n << 49n,\n useExternalApps: 1n << 50n,\n pinMessages: 1n << 51n,\n bypassSlowmode: 1n << 52n,\n} as const;\n\n/** Canonical PascalCase permission constants. */\nexport const Permissions = {\n CreateInstantInvite: 1n << 0n,\n KickMembers: 1n << 1n,\n BanMembers: 1n << 2n,\n Administrator: 1n << 3n,\n ManageChannels: 1n << 4n,\n ManageGuild: 1n << 5n,\n AddReactions: 1n << 6n,\n ViewAuditLog: 1n << 7n,\n PrioritySpeaker: 1n << 8n,\n Stream: 1n << 9n,\n ViewChannel: 1n << 10n,\n SendMessages: 1n << 11n,\n SendTTSMessages: 1n << 12n,\n ManageMessages: 1n << 13n,\n EmbedLinks: 1n << 14n,\n AttachFiles: 1n << 15n,\n ReadMessageHistory: 1n << 16n,\n MentionEveryone: 1n << 17n,\n UseExternalEmojis: 1n << 18n,\n ViewGuildInsights: 1n << 19n,\n Connect: 1n << 20n,\n Speak: 1n << 21n,\n MuteMembers: 1n << 22n,\n DeafenMembers: 1n << 23n,\n MoveMembers: 1n << 24n,\n UseVAD: 1n << 25n,\n ChangeNickname: 1n << 26n,\n ManageNicknames: 1n << 27n,\n ManageRoles: 1n << 28n,\n ManageWebhooks: 1n << 29n,\n ManageGuildExpressions: 1n << 30n,\n UseApplicationCommands: 1n << 31n,\n RequestToSpeak: 1n << 32n,\n ManageEvents: 1n << 33n,\n ManageThreads: 1n << 34n,\n CreatePublicThreads: 1n << 35n,\n CreatePrivateThreads: 1n << 36n,\n UseExternalStickers: 1n << 37n,\n SendMessagesInThreads: 1n << 38n,\n UseEmbeddedActivities: 1n << 39n,\n ModerateMembers: 1n << 40n,\n ViewCreatorMonetizationAnalytics: 1n << 41n,\n UseSoundboard: 1n << 42n,\n CreateGuildExpressions: 1n << 43n,\n CreateEvents: 1n << 44n,\n UseExternalSounds: 1n << 45n,\n SendVoiceMessages: 1n << 46n,\n SetVoiceChannelStatus: 1n << 48n,\n SendPolls: 1n << 49n,\n UseExternalApps: 1n << 50n,\n PinMessages: 1n << 51n,\n BypassSlowmode: 1n << 52n,\n} as const;\n\n/**\n * Permission flag bits with **bigint** values matching Discord's permission bit\n * positions. Mirrors discord.js's `PermissionFlagsBits`, so bitwise composition\n * (`Flags.A | Flags.B`) OR-s the bits instead of concatenating strings.\n *\n * Implemented as a `const` object rather than a TS `enum` because enums cannot\n * hold bigint members; the same-named union type below preserves usage as a type.\n */\nexport const PermissionFlagsBits = {\n CreateInstantInvite: 1n << 0n,\n KickMembers: 1n << 1n,\n BanMembers: 1n << 2n,\n Administrator: 1n << 3n,\n ManageChannels: 1n << 4n,\n ManageGuild: 1n << 5n,\n AddReactions: 1n << 6n,\n ViewAuditLog: 1n << 7n,\n PrioritySpeaker: 1n << 8n,\n Stream: 1n << 9n,\n ViewChannel: 1n << 10n,\n SendMessages: 1n << 11n,\n SendTTSMessages: 1n << 12n,\n ManageMessages: 1n << 13n,\n EmbedLinks: 1n << 14n,\n AttachFiles: 1n << 15n,\n ReadMessageHistory: 1n << 16n,\n MentionEveryone: 1n << 17n,\n UseExternalEmojis: 1n << 18n,\n ViewGuildInsights: 1n << 19n,\n Connect: 1n << 20n,\n Speak: 1n << 21n,\n MuteMembers: 1n << 22n,\n DeafenMembers: 1n << 23n,\n MoveMembers: 1n << 24n,\n UseVAD: 1n << 25n,\n ChangeNickname: 1n << 26n,\n ManageNicknames: 1n << 27n,\n ManageRoles: 1n << 28n,\n ManageWebhooks: 1n << 29n,\n ManageGuildExpressions: 1n << 30n,\n UseApplicationCommands: 1n << 31n,\n RequestToSpeak: 1n << 32n,\n ManageEvents: 1n << 33n,\n ManageThreads: 1n << 34n,\n CreatePublicThreads: 1n << 35n,\n CreatePrivateThreads: 1n << 36n,\n UseExternalStickers: 1n << 37n,\n SendMessagesInThreads: 1n << 38n,\n UseEmbeddedActivities: 1n << 39n,\n ModerateMembers: 1n << 40n,\n ViewCreatorMonetizationAnalytics: 1n << 41n,\n UseSoundboard: 1n << 42n,\n CreateGuildExpressions: 1n << 43n,\n CreateEvents: 1n << 44n,\n UseExternalSounds: 1n << 45n,\n SendVoiceMessages: 1n << 46n,\n SetVoiceChannelStatus: 1n << 48n,\n SendPolls: 1n << 49n,\n UseExternalApps: 1n << 50n,\n PinMessages: 1n << 51n,\n BypassSlowmode: 1n << 52n,\n} as const;\n\n/** Union of {@link PermissionFlagsBits} values (all bigint). */\nexport type PermissionFlagsBits =\n (typeof PermissionFlagsBits)[keyof typeof PermissionFlagsBits];\n\nexport type PermissionName =\n | keyof typeof Permission\n | keyof typeof Permissions\n | keyof typeof PermissionFlagsBits;\n\nexport type PermissionResolvable =\n | bigint\n | number\n | string\n | PermissionName\n | PermissionFlagsBits\n | PermissionSet\n | PermissionResolvable[];\n\n/** Immutable permission bitfield with direct boolean getters. */\nexport class PermissionSet {\n /** Permission bitfield. */\n public readonly bitfield: bigint;\n\n /** Creates a permission set. @param value Initial permission bitfield or array of permissions. @throws {RangeError} If the value is negative. @throws {TypeError} If the value is not a valid integer. */\n public constructor(value: PermissionResolvable = 0n) {\n try {\n if (Array.isArray(value)) {\n let bit = 0n;\n for (const item of value) {\n bit |= this.#resolve(item);\n }\n this.bitfield = bit;\n } else if (value instanceof PermissionSet) {\n this.bitfield = value.bitfield;\n } else {\n const bitfield = this.#resolve(value);\n if (bitfield < 0n)\n throw new RangeError(\n \"Permission bitfield cannot be negative.\",\n );\n this.bitfield = bitfield;\n }\n } catch (error) {\n if (error instanceof RangeError) throw error;\n throw new TypeError(\n \"Permission bitfield must be a valid non-negative integer.\",\n { cause: error },\n );\n }\n }\n\n // Direct camelCase boolean getters for instant checks (e.g. member.permissions.kickMembers)\n public get createInstantInvite(): boolean {\n return (\n (this.bitfield & Permission.createInstantInvite) ===\n Permission.createInstantInvite\n );\n }\n public get kickMembers(): boolean {\n return (\n (this.bitfield & Permission.kickMembers) === Permission.kickMembers\n );\n }\n public get banMembers(): boolean {\n return (\n (this.bitfield & Permission.banMembers) === Permission.banMembers\n );\n }\n public get administrator(): boolean {\n return (\n (this.bitfield & Permission.administrator) ===\n Permission.administrator\n );\n }\n public get manageChannels(): boolean {\n return (\n (this.bitfield & Permission.manageChannels) ===\n Permission.manageChannels\n );\n }\n public get manageGuild(): boolean {\n return (\n (this.bitfield & Permission.manageGuild) === Permission.manageGuild\n );\n }\n public get addReactions(): boolean {\n return (\n (this.bitfield & Permission.addReactions) ===\n Permission.addReactions\n );\n }\n public get viewAuditLog(): boolean {\n return (\n (this.bitfield & Permission.viewAuditLog) ===\n Permission.viewAuditLog\n );\n }\n public get prioritySpeaker(): boolean {\n return (\n (this.bitfield & Permission.prioritySpeaker) ===\n Permission.prioritySpeaker\n );\n }\n public get stream(): boolean {\n return (this.bitfield & Permission.stream) === Permission.stream;\n }\n public get viewChannel(): boolean {\n return (\n (this.bitfield & Permission.viewChannel) === Permission.viewChannel\n );\n }\n public get sendMessages(): boolean {\n return (\n (this.bitfield & Permission.sendMessages) ===\n Permission.sendMessages\n );\n }\n public get sendTTSMessages(): boolean {\n return (\n (this.bitfield & Permission.sendTTSMessages) ===\n Permission.sendTTSMessages\n );\n }\n public get manageMessages(): boolean {\n return (\n (this.bitfield & Permission.manageMessages) ===\n Permission.manageMessages\n );\n }\n public get embedLinks(): boolean {\n return (\n (this.bitfield & Permission.embedLinks) === Permission.embedLinks\n );\n }\n public get attachFiles(): boolean {\n return (\n (this.bitfield & Permission.attachFiles) === Permission.attachFiles\n );\n }\n public get readMessageHistory(): boolean {\n return (\n (this.bitfield & Permission.readMessageHistory) ===\n Permission.readMessageHistory\n );\n }\n public get mentionEveryone(): boolean {\n return (\n (this.bitfield & Permission.mentionEveryone) ===\n Permission.mentionEveryone\n );\n }\n public get useExternalEmojis(): boolean {\n return (\n (this.bitfield & Permission.useExternalEmojis) ===\n Permission.useExternalEmojis\n );\n }\n public get viewGuildInsights(): boolean {\n return (\n (this.bitfield & Permission.viewGuildInsights) ===\n Permission.viewGuildInsights\n );\n }\n public get connect(): boolean {\n return (this.bitfield & Permission.connect) === Permission.connect;\n }\n public get speak(): boolean {\n return (this.bitfield & Permission.speak) === Permission.speak;\n }\n public get muteMembers(): boolean {\n return (\n (this.bitfield & Permission.muteMembers) === Permission.muteMembers\n );\n }\n public get deafenMembers(): boolean {\n return (\n (this.bitfield & Permission.deafenMembers) ===\n Permission.deafenMembers\n );\n }\n public get moveMembers(): boolean {\n return (\n (this.bitfield & Permission.moveMembers) === Permission.moveMembers\n );\n }\n public get useVAD(): boolean {\n return (this.bitfield & Permission.useVAD) === Permission.useVAD;\n }\n public get changeNickname(): boolean {\n return (\n (this.bitfield & Permission.changeNickname) ===\n Permission.changeNickname\n );\n }\n public get manageNicknames(): boolean {\n return (\n (this.bitfield & Permission.manageNicknames) ===\n Permission.manageNicknames\n );\n }\n public get manageRoles(): boolean {\n return (\n (this.bitfield & Permission.manageRoles) === Permission.manageRoles\n );\n }\n public get manageWebhooks(): boolean {\n return (\n (this.bitfield & Permission.manageWebhooks) ===\n Permission.manageWebhooks\n );\n }\n public get manageGuildExpressions(): boolean {\n return (\n (this.bitfield & Permission.manageGuildExpressions) ===\n Permission.manageGuildExpressions\n );\n }\n public get useApplicationCommands(): boolean {\n return (\n (this.bitfield & Permission.useApplicationCommands) ===\n Permission.useApplicationCommands\n );\n }\n public get requestToSpeak(): boolean {\n return (\n (this.bitfield & Permission.requestToSpeak) ===\n Permission.requestToSpeak\n );\n }\n public get manageEvents(): boolean {\n return (\n (this.bitfield & Permission.manageEvents) ===\n Permission.manageEvents\n );\n }\n public get manageThreads(): boolean {\n return (\n (this.bitfield & Permission.manageThreads) ===\n Permission.manageThreads\n );\n }\n public get createPublicThreads(): boolean {\n return (\n (this.bitfield & Permission.createPublicThreads) ===\n Permission.createPublicThreads\n );\n }\n public get createPrivateThreads(): boolean {\n return (\n (this.bitfield & Permission.createPrivateThreads) ===\n Permission.createPrivateThreads\n );\n }\n public get useExternalStickers(): boolean {\n return (\n (this.bitfield & Permission.useExternalStickers) ===\n Permission.useExternalStickers\n );\n }\n public get sendMessagesInThreads(): boolean {\n return (\n (this.bitfield & Permission.sendMessagesInThreads) ===\n Permission.sendMessagesInThreads\n );\n }\n public get useEmbeddedActivities(): boolean {\n return (\n (this.bitfield & Permission.useEmbeddedActivities) ===\n Permission.useEmbeddedActivities\n );\n }\n public get moderateMembers(): boolean {\n return (\n (this.bitfield & Permission.moderateMembers) ===\n Permission.moderateMembers\n );\n }\n public get viewCreatorMonetizationAnalytics(): boolean {\n return (\n (this.bitfield & Permission.viewCreatorMonetizationAnalytics) ===\n Permission.viewCreatorMonetizationAnalytics\n );\n }\n public get useSoundboard(): boolean {\n return (\n (this.bitfield & Permission.useSoundboard) ===\n Permission.useSoundboard\n );\n }\n public get createGuildExpressions(): boolean {\n return (\n (this.bitfield & Permission.createGuildExpressions) ===\n Permission.createGuildExpressions\n );\n }\n public get createEvents(): boolean {\n return (\n (this.bitfield & Permission.createEvents) ===\n Permission.createEvents\n );\n }\n public get useExternalSounds(): boolean {\n return (\n (this.bitfield & Permission.useExternalSounds) ===\n Permission.useExternalSounds\n );\n }\n public get sendVoiceMessages(): boolean {\n return (\n (this.bitfield & Permission.sendVoiceMessages) ===\n Permission.sendVoiceMessages\n );\n }\n public get sendPolls(): boolean {\n return (this.bitfield & Permission.sendPolls) === Permission.sendPolls;\n }\n public get useExternalApps(): boolean {\n return (\n (this.bitfield & Permission.useExternalApps) ===\n Permission.useExternalApps\n );\n }\n\n /** Checks whether all supplied permissions are present (AND). @param permissions Permission names or raw bits. @returns True when every requested permission is present. */\n public has(...permissions: PermissionResolvable[]): boolean {\n if (permissions.length === 1) {\n const p = permissions[0]!;\n const bit = typeof p === \"bigint\" ? p : this.#resolve(p);\n return (this.bitfield & bit) === bit;\n }\n for (let i = 0; i < permissions.length; i++) {\n const p = permissions[i]!;\n const bit = typeof p === \"bigint\" ? p : this.#resolve(p);\n if ((this.bitfield & bit) !== bit) return false;\n }\n return true;\n }\n\n /** Checks whether any supplied permission is present (OR). @param permissions Permission names or raw bits. @returns True when at least one requested permission is present. */\n public any(...permissions: PermissionResolvable[]): boolean {\n if (permissions.length === 1) {\n const p = permissions[0]!;\n const bit = typeof p === \"bigint\" ? p : this.#resolve(p);\n return (this.bitfield & bit) !== 0n;\n }\n for (let i = 0; i < permissions.length; i++) {\n const p = permissions[i]!;\n const bit = typeof p === \"bigint\" ? p : this.#resolve(p);\n if ((this.bitfield & bit) !== 0n) return true;\n }\n return false;\n }\n\n /** Returns the known permission names from `permissions` that this set lacks. @param permissions Permission names or raw bits. */\n public missing(...permissions: PermissionResolvable[]): PermissionName[] {\n const wanted = new PermissionSet(permissions);\n return wanted.toArray().filter((name) => !this.has(name));\n }\n\n /** Returns a new set with permissions added. @param permissions Permission names or raw bits. @returns A new permission set. */\n public add(...permissions: PermissionResolvable[]): PermissionSet {\n let bitfield = this.bitfield;\n for (let i = 0; i < permissions.length; i++) {\n const p = permissions[i]!;\n bitfield |= typeof p === \"bigint\" ? p : this.#resolve(p);\n }\n return new PermissionSet(bitfield);\n }\n\n /** Returns a new set with permissions removed. @param permissions Permission names or raw bits. @returns A new permission set. */\n public remove(...permissions: PermissionResolvable[]): PermissionSet {\n let bitfield = this.bitfield;\n for (let i = 0; i < permissions.length; i++) {\n const p = permissions[i]!;\n bitfield &= ~(typeof p === \"bigint\" ? p : this.#resolve(p));\n }\n return new PermissionSet(bitfield);\n }\n\n /** Checks equality with another permission set or raw bitfield. @param other Permission set or raw bitfield. @returns True when both values are equal. */\n public equals(other: PermissionSet | bigint | number | string): boolean {\n return (\n this.bitfield ===\n (other instanceof PermissionSet\n ? other.bitfield\n : new PermissionSet(other).bitfield)\n );\n }\n\n /** Returns the decimal permission representation. @returns Decimal permission bitfield. */\n public toString(): string {\n return this.bitfield.toString();\n }\n\n /** Returns known permission names contained in this set. @returns Names of all enabled known permissions. */\n public toArray(): PermissionName[] {\n return (Object.keys(Permission) as PermissionName[]).filter(\n (permission) => this.has(permission),\n );\n }\n\n /** Resolves a named permission, enum value, or raw bit. @param permission Permission name, enum value, or raw bit. @returns Numeric permission bit. */\n /** Names Discord has since renamed, still accepted when resolving a permission by name. */\n static readonly #renamed: Readonly<Record<string, string>> = {\n ManageEmojisAndStickers: \"ManageGuildExpressions\",\n ManageEmojis: \"ManageGuildExpressions\",\n UseSlashCommands: \"UseApplicationCommands\",\n };\n\n #resolve(permission: PermissionResolvable): bigint {\n if (typeof permission === \"bigint\") return permission;\n if (typeof permission === \"number\") return BigInt(permission);\n if (permission instanceof PermissionSet) return permission.bitfield;\n if (Array.isArray(permission)) {\n let bit = 0n;\n for (let i = 0; i < permission.length; i++)\n bit |= this.#resolve(permission[i]!);\n return bit;\n }\n if (typeof permission === \"string\") {\n const renamed = PermissionSet.#renamed[permission];\n if (renamed) return this.#resolve(renamed);\n if (permission in Permission)\n return (Permission as Record<string, bigint>)[permission]!;\n if (permission in Permissions)\n return (Permissions as Record<string, bigint>)[permission]!;\n if (permission in PermissionFlagsBits)\n return (PermissionFlagsBits as Record<string, bigint>)[\n permission\n ]!;\n const lower =\n permission.charAt(0).toLowerCase() + permission.slice(1);\n if (lower in Permission)\n return (Permission as Record<string, bigint>)[lower]!;\n return BigInt(permission);\n }\n return 0n;\n }\n}\n\n/** Permissions bitfield alias. */\nexport class PermissionsBitField extends PermissionSet {\n /** Permission flags bits enum. */\n public static readonly Flags = PermissionFlagsBits;\n /** Permission flags constants. */\n public static readonly All = Permission;\n\n /** Creates a permissions bitfield. @param value Initial permission bitfield or array of permissions. */\n public constructor(value: PermissionResolvable = 0n) {\n super(value);\n }\n}\n\n/** Every known permission bit. */\nconst ALL_PERMISSIONS = Object.values(Permission).reduce(\n (bits, bit) => bits | bit,\n 0n,\n);\n\n/** A role as needed for permission resolution. */\nexport interface PermissionRole {\n id: string;\n permissions: PermissionResolvable;\n}\n\n/** A channel permission overwrite (Discord's `permission_overwrites` entry). */\nexport interface PermissionOverwrite {\n id: string;\n type: PermissionOverwriteEnum | number;\n allow: PermissionResolvable;\n deny: PermissionResolvable;\n}\n\n/** Everything needed to resolve a member's permissions. */\nexport interface PermissionContext {\n guildId: string;\n /** Guild owner ID; the owner has every permission. */\n ownerId?: string;\n memberId: string;\n memberRoleIds: readonly string[];\n /** Guild roles, including `@everyone` (whose ID is the guild ID). */\n roles: readonly PermissionRole[];\n /** Channel overwrites; omit for guild-level permissions. */\n overwrites?: readonly PermissionOverwrite[];\n}\n\nconst bits = (value: PermissionResolvable): bigint =>\n new PermissionSet(value).bitfield;\n\n/**\n * Resolves a member's effective permissions the way Discord does: base\n * permissions from `@everyone` and the member's roles (owner and\n * administrator get everything), then the channel's `@everyone` overwrite,\n * the combined role overwrites, and finally the member overwrite.\n */\nexport function computePermissions(context: PermissionContext): PermissionSet {\n if (context.ownerId !== undefined && context.ownerId === context.memberId)\n return new PermissionSet(ALL_PERMISSIONS);\n const roles = new Map(context.roles.map((role) => [role.id, role]));\n let base = bits(roles.get(context.guildId)?.permissions ?? 0n);\n for (const id of context.memberRoleIds)\n base |= bits(roles.get(id)?.permissions ?? 0n);\n if (base & Permission.administrator)\n return new PermissionSet(ALL_PERMISSIONS);\n const overwrites = context.overwrites ?? [];\n const everyone = overwrites.find((o) => o.id === context.guildId);\n if (everyone) base = (base & ~bits(everyone.deny)) | bits(everyone.allow);\n const memberRoles = new Set(context.memberRoleIds);\n let allow = 0n;\n let deny = 0n;\n for (const overwrite of overwrites)\n if (\n overwrite.type === PermissionOverwriteEnum.Role &&\n overwrite.id !== context.guildId &&\n memberRoles.has(overwrite.id)\n ) {\n allow |= bits(overwrite.allow);\n deny |= bits(overwrite.deny);\n }\n base = (base & ~deny) | allow;\n const member = overwrites.find(\n (o) =>\n o.type === PermissionOverwriteEnum.Member &&\n o.id === context.memberId,\n );\n if (member) base = (base & ~bits(member.deny)) | bits(member.allow);\n return new PermissionSet(base);\n}\n",
|
|
6
|
-
"import type {\n APIEntitlement,\n APISoundboardSound,\n APISticker,\n} from \"@lunibee/types\";\nimport type {\n APIAutoModerationActionExecution,\n APIAutoModerationRule,\n APIChannel,\n APIChannelPinsUpdate,\n APIGuild,\n APIGuildBanEvent,\n APIGuildEmojisUpdateEvent,\n APIGuildMember,\n APIGuildMembersChunk,\n APIGuildRoleDeleteEvent,\n APIGuildRoleEvent,\n APIGuildScheduledEvent,\n APIGuildScheduledEventUserEvent,\n APIGuildStickersUpdateEvent,\n APIInviteCreate,\n APIInviteDelete,\n APIMessageDeleteBulkEvent,\n APIMessageDeleteEvent,\n APIMessagePollVoteEvent,\n APIMessageReactionEvent,\n APIMessageReactionRemoveEmojiEvent,\n APIPresenceUpdate,\n APIStageInstance,\n APIThreadEvent,\n APIThreadListSync,\n APIThreadMember,\n APIThreadMembersUpdate,\n APITypingStart,\n APIVoiceServerUpdate,\n APIVoiceState,\n APIWebhooksUpdate,\n ClientUser,\n} from \"@lunibee/types\";\nimport type {\n Channel,\n Emoji,\n Guild,\n GuildMember,\n Interaction,\n Message,\n Role,\n} from \"@lunibee/structures\";\n/** Names of events emitted by a Lunibee client. */\nexport enum ClientEvent {\n // ── Lifecycle ──────────────────────────────────────────────────────────────\n Ready = \"ready\",\n Resumed = \"resumed\",\n InvalidSession = \"invalidSession\",\n Raw = \"raw\",\n Error = \"error\",\n Open = \"open\",\n Close = \"close\",\n // ── Messages ───────────────────────────────────────────────────────────────\n MessageCreate = \"messageCreate\",\n MessageUpdate = \"messageUpdate\",\n MessageDelete = \"messageDelete\",\n MessageDeleteBulk = \"messageDeleteBulk\",\n // ── Reactions ─────────────────────────────────────────────────────────────\n MessageReactionAdd = \"messageReactionAdd\",\n MessageReactionRemove = \"messageReactionRemove\",\n MessageReactionRemoveAll = \"messageReactionRemoveAll\",\n MessageReactionRemoveEmoji = \"messageReactionRemoveEmoji\",\n // ── Polls ─────────────────────────────────────────────────────────────────\n MessagePollVoteAdd = \"messagePollVoteAdd\",\n MessagePollVoteRemove = \"messagePollVoteRemove\",\n // ── Guilds ────────────────────────────────────────────────────────────────\n GuildCreate = \"guildCreate\",\n GuildUpdate = \"guildUpdate\",\n GuildDelete = \"guildDelete\",\n GuildAvailable = \"guildAvailable\",\n GuildUnavailable = \"guildUnavailable\",\n // ── Guild Members ──────────────────────────────────────────────────────────\n GuildMemberAdd = \"guildMemberAdd\",\n GuildMemberUpdate = \"guildMemberUpdate\",\n GuildMemberRemove = \"guildMemberRemove\",\n GuildMembersChunk = \"guildMembersChunk\",\n // ── Guild Bans ────────────────────────────────────────────────────────────\n GuildBanAdd = \"guildBanAdd\",\n GuildBanRemove = \"guildBanRemove\",\n // ── Guild Roles ───────────────────────────────────────────────────────────\n GuildRoleCreate = \"guildRoleCreate\",\n GuildRoleUpdate = \"guildRoleUpdate\",\n GuildRoleDelete = \"guildRoleDelete\",\n // ── Guild Emojis & Stickers ───────────────────────────────────────────────\n GuildEmojisUpdate = \"guildEmojisUpdate\",\n GuildStickersUpdate = \"guildStickersUpdate\",\n // ── Monetization ──────────────────────────────────────────────────────────\n EntitlementCreate = \"entitlementCreate\",\n EntitlementUpdate = \"entitlementUpdate\",\n EntitlementDelete = \"entitlementDelete\",\n // ── Soundboard ────────────────────────────────────────────────────────────\n SoundboardSoundCreate = \"soundboardSoundCreate\",\n SoundboardSoundUpdate = \"soundboardSoundUpdate\",\n SoundboardSoundDelete = \"soundboardSoundDelete\",\n SoundboardSoundsUpdate = \"soundboardSoundsUpdate\",\n // ── Guild Integrations ────────────────────────────────────────────────────\n GuildIntegrationsUpdate = \"guildIntegrationsUpdate\",\n // ── Guild Scheduled Events ────────────────────────────────────────────────\n GuildScheduledEventCreate = \"guildScheduledEventCreate\",\n GuildScheduledEventUpdate = \"guildScheduledEventUpdate\",\n GuildScheduledEventDelete = \"guildScheduledEventDelete\",\n GuildScheduledEventUserAdd = \"guildScheduledEventUserAdd\",\n GuildScheduledEventUserRemove = \"guildScheduledEventUserRemove\",\n // ── AutoMod ───────────────────────────────────────────────────────────────\n AutoModerationRuleCreate = \"autoModerationRuleCreate\",\n AutoModerationRuleUpdate = \"autoModerationRuleUpdate\",\n AutoModerationRuleDelete = \"autoModerationRuleDelete\",\n AutoModerationActionExecution = \"autoModerationActionExecution\",\n // ── Channels ──────────────────────────────────────────────────────────────\n ChannelCreate = \"channelCreate\",\n ChannelUpdate = \"channelUpdate\",\n ChannelDelete = \"channelDelete\",\n ChannelPinsUpdate = \"channelPinsUpdate\",\n // ── Threads ───────────────────────────────────────────────────────────────\n ThreadCreate = \"threadCreate\",\n ThreadUpdate = \"threadUpdate\",\n ThreadDelete = \"threadDelete\",\n ThreadListSync = \"threadListSync\",\n ThreadMembersUpdate = \"threadMembersUpdate\",\n ThreadMemberUpdate = \"threadMemberUpdate\",\n // ── Stage Instances ───────────────────────────────────────────────────────\n StageInstanceCreate = \"stageInstanceCreate\",\n StageInstanceUpdate = \"stageInstanceUpdate\",\n StageInstanceDelete = \"stageInstanceDelete\",\n // ── Invites ───────────────────────────────────────────────────────────────\n InviteCreate = \"inviteCreate\",\n InviteDelete = \"inviteDelete\",\n // ── Webhooks ──────────────────────────────────────────────────────────────\n WebhooksUpdate = \"webhooksUpdate\",\n // ── Voice ─────────────────────────────────────────────────────────────────\n VoiceStateUpdate = \"voiceStateUpdate\",\n VoiceServerUpdate = \"voiceServerUpdate\",\n // ── Presence & Typing ─────────────────────────────────────────────────────\n PresenceUpdate = \"presenceUpdate\",\n TypingStart = \"typingStart\",\n // ── Interactions ──────────────────────────────────────────────────────────\n InteractionCreate = \"interactionCreate\",\n}\n\n/** Names of events emitted by a Lunibee client. */\nexport type ClientEventName = keyof ClientEvents;\n\n/** Listener signature for a Lunibee client event. */\nexport type ClientListener<K extends ClientEventName> = (\n ...args: ClientEvents[K]\n) => unknown;\n\n// ─── ClientEvents type map ────────────────────────────────────────────────────\n// Uses string literal keys so client.on(\"ready\", ...) works without using\n// the ClientEvent enum explicitly.\n\nexport type ClientEvents = {\n // ── Lifecycle ──────────────────────────────────────────────────────────────\n ready: [user: ClientUser];\n resumed: [];\n invalidSession: [isRecoverable: boolean];\n raw: [data: { event: string; data: unknown }];\n error: [error: Error];\n open: [];\n close: [data: { code: number; action: string }];\n // ── Messages ───────────────────────────────────────────────────────────────\n messageCreate: [message: Message];\n /** `previous` is the cached version, available when `messageCache` is enabled. */\n messageUpdate: [message: Message, previous?: Message];\n /** `message` is the cached message, available when `messageCache` is enabled. */\n messageDelete: [data: APIMessageDeleteEvent, message?: Message];\n /** `messages` are the cached messages that were deleted (empty without `messageCache`). */\n messageDeleteBulk: [data: APIMessageDeleteBulkEvent, messages: Message[]];\n // ── Reactions ─────────────────────────────────────────────────────────────\n messageReactionAdd: [data: APIMessageReactionEvent];\n messageReactionRemove: [data: APIMessageReactionEvent];\n messageReactionRemoveAll: [data: APIMessageDeleteEvent];\n messageReactionRemoveEmoji: [data: APIMessageReactionRemoveEmojiEvent];\n // ── Polls ─────────────────────────────────────────────────────────────────\n messagePollVoteAdd: [data: APIMessagePollVoteEvent];\n messagePollVoteRemove: [data: APIMessagePollVoteEvent];\n // ── Guilds ────────────────────────────────────────────────────────────────\n guildCreate: [data: APIGuild];\n /** `previous` is a copy of the cached guild before the update, or null when it was not cached. */\n guildUpdate: [data: APIGuild, previous: Guild | null];\n guildDelete: [data: { id: string; unavailable?: boolean }];\n guildAvailable: [data: APIGuild & { unavailable?: boolean }];\n guildUnavailable: [data: { id: string; unavailable?: boolean }];\n // ── Guild Members ──────────────────────────────────────────────────────────\n guildMemberAdd: [member: APIGuildMember];\n /** `previous` is a copy of the cached member before the update, or null when it was not cached. */\n guildMemberUpdate: [member: APIGuildMember, previous: GuildMember | null];\n guildMemberRemove: [member: APIGuildMember];\n guildMembersChunk: [data: APIGuildMembersChunk];\n // ── Guild Bans ────────────────────────────────────────────────────────────\n guildBanAdd: [data: APIGuildBanEvent];\n guildBanRemove: [data: APIGuildBanEvent];\n // ── Guild Roles ───────────────────────────────────────────────────────────\n guildRoleCreate: [data: APIGuildRoleEvent];\n /** `previous` is a copy of the cached role before the update, or null when it was not cached. */\n guildRoleUpdate: [data: APIGuildRoleEvent, previous: Role | null];\n /** `removed` is the role that was cached, or null. */\n guildRoleDelete: [data: APIGuildRoleDeleteEvent, removed: Role | null];\n // ── Guild Emojis & Stickers ───────────────────────────────────────────────\n /** `previous` is the cached emoji list before the update, or null without the emoji cache. */\n guildEmojisUpdate: [\n data: APIGuildEmojisUpdateEvent,\n previous: Emoji[] | null,\n ];\n /** `previous` is the cached sticker list before the update (empty when none were cached). */\n guildStickersUpdate: [\n data: APIGuildStickersUpdateEvent,\n previous: APISticker[],\n ];\n // ── Monetization ──────────────────────────────────────────────────────────\n entitlementCreate: [entitlement: APIEntitlement];\n entitlementUpdate: [entitlement: APIEntitlement];\n entitlementDelete: [entitlement: APIEntitlement];\n // ── Soundboard ────────────────────────────────────────────────────────────\n soundboardSoundCreate: [sound: APISoundboardSound];\n soundboardSoundUpdate: [sound: APISoundboardSound];\n soundboardSoundDelete: [data: { sound_id: string; guild_id: string }];\n soundboardSoundsUpdate: [\n data: { guild_id: string; soundboard_sounds: APISoundboardSound[] },\n ];\n // ── Guild Integrations ────────────────────────────────────────────────────\n guildIntegrationsUpdate: [data: { guild_id: string }];\n // ── Guild Scheduled Events ────────────────────────────────────────────────\n guildScheduledEventCreate: [data: APIGuildScheduledEvent];\n guildScheduledEventUpdate: [data: APIGuildScheduledEvent];\n guildScheduledEventDelete: [data: APIGuildScheduledEvent];\n guildScheduledEventUserAdd: [data: APIGuildScheduledEventUserEvent];\n guildScheduledEventUserRemove: [data: APIGuildScheduledEventUserEvent];\n // ── AutoMod ───────────────────────────────────────────────────────────────\n autoModerationRuleCreate: [data: APIAutoModerationRule];\n autoModerationRuleUpdate: [data: APIAutoModerationRule];\n autoModerationRuleDelete: [data: APIAutoModerationRule];\n autoModerationActionExecution: [data: APIAutoModerationActionExecution];\n // ── Channels ──────────────────────────────────────────────────────────────\n channelCreate: [channel: Channel];\n /** `previous` is a copy of the cached channel before the update, or null when it was not cached. */\n channelUpdate: [channel: Channel, previous: Channel | null];\n /** `removed` is the channel that was cached, or null. */\n channelDelete: [data: APIChannel, removed: Channel | null];\n channelPinsUpdate: [data: APIChannelPinsUpdate];\n // ── Threads ───────────────────────────────────────────────────────────────\n threadCreate: [channel: Channel];\n /** `previous` is a copy of the cached thread before the update, or null when it was not cached. */\n threadUpdate: [channel: Channel, previous: Channel | null];\n /** `removed` is the thread that was cached, or null. */\n threadDelete: [data: APIThreadEvent, removed: Channel | null];\n threadListSync: [data: APIThreadListSync];\n threadMembersUpdate: [data: APIThreadMembersUpdate];\n threadMemberUpdate: [data: APIThreadMember];\n // ── Stage Instances ───────────────────────────────────────────────────────\n stageInstanceCreate: [data: APIStageInstance];\n stageInstanceUpdate: [data: APIStageInstance];\n stageInstanceDelete: [data: APIStageInstance];\n // ── Invites ───────────────────────────────────────────────────────────────\n inviteCreate: [data: APIInviteCreate];\n inviteDelete: [data: APIInviteDelete];\n // ── Webhooks ──────────────────────────────────────────────────────────────\n webhooksUpdate: [data: APIWebhooksUpdate];\n // ── Voice ─────────────────────────────────────────────────────────────────\n voiceStateUpdate: [data: APIVoiceState];\n voiceServerUpdate: [data: APIVoiceServerUpdate];\n // ── Presence & Typing ─────────────────────────────────────────────────────\n presenceUpdate: [data: APIPresenceUpdate];\n typingStart: [data: APITypingStart];\n // ── Interactions ──────────────────────────────────────────────────────────\n interactionCreate: [interaction: Interaction];\n};\n",
|
|
7
|
-
"import { EventEmitter } from \"node:events\";\n\nexport interface CollectorOptions<T> {\n /** Filter predicate to accept or reject items. */\n filter?: (item: T) => boolean | Promise<boolean>;\n /** Lifetime of the collector in milliseconds. */\n time?: number;\n /** Maximum number of elements to collect. */\n max?: number;\n /** Maximum number of processed elements. */\n maxProcessed?: number;\n /** Stop after this many milliseconds without a collected item. */\n idle?: number;\n /** Stop (reason `\"abort\"`) when this signal aborts. */\n signal?: AbortSignal;\n}\n\n/** General-purpose event collector for interactions and messages. */\nexport class Collector<K, V> extends EventEmitter {\n public readonly collected = new Map<K, V>();\n public readonly options: CollectorOptions<V>;\n public ended = false;\n public endReason?: string;\n public totalProcessed = 0;\n readonly #timeoutTimer?: ReturnType<typeof setTimeout>;\n #idleTimer?: ReturnType<typeof setTimeout>;\n readonly #onAbort = (): void => this.stop(\"abort\");\n /** Cleanup hooks run once when the collector ends (e.g. event unsubscription). */\n readonly #cleanup: (() => void)[] = [];\n\n public constructor(options: CollectorOptions<V> = {}) {\n super();\n this.options = options;\n\n if (options.time && options.time > 0) {\n this.#timeoutTimer = setTimeout(() => {\n this.stop(\"time\");\n }, options.time);\n }\n this.#resetIdle();\n if (options.signal?.aborted) this.stop(\"abort\");\n else\n options.signal?.addEventListener(\"abort\", this.#onAbort, {\n once: true,\n });\n }\n\n /** Registers a function to run once when the collector ends. Runs immediately if it already has. */\n public onDispose(cleanup: () => void): this {\n if (this.ended) cleanup();\n else this.#cleanup.push(cleanup);\n return this;\n }\n\n #resetIdle(): void {\n if (!this.options.idle || this.options.idle <= 0) return;\n if (this.#idleTimer) clearTimeout(this.#idleTimer);\n this.#idleTimer = setTimeout(\n () => this.stop(\"idle\"),\n this.options.idle,\n );\n }\n\n /** Handles a candidate item for collection. */\n public async handle(key: K, item: V): Promise<boolean> {\n if (this.ended) return false;\n this.totalProcessed++;\n\n // `maxProcessed` counts every item the collector *sees*, so it has to be\n // evaluated whether or not the filter accepts this one — checking it only\n // on the accepted path means a collector whose filter rejects everything\n // never reaches its processed limit and runs until `time`/`stop()`.\n const reachedProcessed =\n !!this.options.maxProcessed &&\n this.totalProcessed >= this.options.maxProcessed;\n\n let passed = true;\n if (this.options.filter) passed = !!(await this.options.filter(item));\n\n // The filter may be async, so the collector can have been stopped while\n // it was pending. Anything decided before that stop is discarded rather\n // than collected (and emitted) after \"end\".\n if (this.ended) return false;\n\n if (!passed) {\n if (reachedProcessed) this.stop(\"processedLimit\");\n return false;\n }\n\n this.collected.set(key, item);\n this.#resetIdle();\n this.emit(\"collect\", item);\n\n if (this.options.max && this.collected.size >= this.options.max) {\n this.stop(\"limit\");\n return true;\n }\n\n if (reachedProcessed) {\n this.stop(\"processedLimit\");\n return true;\n }\n\n return true;\n }\n\n /** Stops the collector and emits the \"end\" event. */\n public stop(reason = \"user\"): void {\n if (this.ended) return;\n this.ended = true;\n this.endReason = reason;\n if (this.#timeoutTimer) clearTimeout(this.#timeoutTimer);\n if (this.#idleTimer) clearTimeout(this.#idleTimer);\n this.options.signal?.removeEventListener(\"abort\", this.#onAbort);\n for (const cleanup of this.#cleanup.splice(0)) {\n try {\n cleanup();\n } catch {\n // A failing cleanup must not stop the others or the \"end\" event.\n }\n }\n this.emit(\"end\", this.collected, reason);\n this.removeAllListeners();\n }\n\n /** Resolves with everything collected once the collector ends. */\n public wait(): Promise<Map<K, V>> {\n if (this.ended) return Promise.resolve(this.collected);\n return new Promise((resolve) =>\n this.once(\"end\", (collected: Map<K, V>) => resolve(collected)),\n );\n }\n\n /** Yields items as they are collected until the collector ends. Items\n * collected between iterations are buffered, not dropped. */\n public async *[Symbol.asyncIterator](): AsyncGenerator<V, void, undefined> {\n const queue: V[] = [];\n let wake: (() => void) | undefined;\n const onCollect = (item: V): void => {\n queue.push(item);\n wake?.();\n };\n const onEnd = (): void => wake?.();\n if (!this.ended) {\n this.on(\"collect\", onCollect);\n this.on(\"end\", onEnd);\n }\n try {\n for (;;) {\n if (queue.length > 0) {\n yield queue.shift()!;\n continue;\n }\n if (this.ended) return;\n await new Promise<void>((resolve) => (wake = resolve));\n wake = undefined;\n }\n } finally {\n this.off(\"collect\", onCollect);\n this.off(\"end\", onEnd);\n }\n }\n\n /** Stops the collector (reason `\"disposed\"`); enables `using collector = ...`. */\n public [Symbol.dispose](): void {\n this.stop(\"disposed\");\n }\n\n /** Returns a Promise that resolves with the next collected item or rejects on end/timeout. */\n public next(): Promise<V> {\n return new Promise<V>((resolve, reject) => {\n if (this.ended) {\n return reject(\n new Error(\n `Collector already ended: ${this.endReason ?? \"unknown\"}`,\n ),\n );\n }\n\n // Each settled next() must drop its counterpart listener. Polling\n // a long-lived collector in a loop otherwise leaves one dangling\n // \"end\" listener per call, which grows without bound and trips the\n // EventEmitter max-listener warning.\n const onCollect = (item: V): void => {\n this.off(\"end\", onEnd);\n resolve(item);\n };\n const onEnd = (_collected: Map<K, V>, reason: string): void => {\n this.off(\"collect\", onCollect);\n reject(\n new Error(\n `Collector ended before item was collected: ${reason}`,\n ),\n );\n };\n\n this.once(\"collect\", onCollect);\n this.once(\"end\", onEnd);\n });\n }\n}\n",
|
|
8
|
-
"// ─── 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 {\
|
|
9
|
-
"/** 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/** One {@link MessageFlags} value, usable as a type. */\nexport type MessageFlags = (typeof MessageFlags)[keyof typeof MessageFlags];\n\n/** Discord channel types. */\nexport const ChannelEnum = {\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/** One {@link ChannelEnum} value, usable as a type. */\nexport type ChannelEnum = (typeof ChannelEnum)[keyof typeof ChannelEnum];\n\n/** Discord component types. */\nexport const ComponentEnum = {\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/** One {@link ComponentEnum} value, usable as a type. */\nexport type ComponentEnum = (typeof ComponentEnum)[keyof typeof ComponentEnum];\n\n/** Discord button style types. */\nexport const ButtonType = {\n Primary: 1,\n Secondary: 2,\n Success: 3,\n Danger: 4,\n Link: 5,\n Premium: 6,\n} as const;\n/** One {@link ButtonType} value, usable as a type: `style: ButtonType`. */\nexport type ButtonType = (typeof ButtonType)[keyof typeof ButtonType];\n\n/** Discord text input style types. */\nexport const TextInputType = {\n Short: 1,\n Paragraph: 2,\n} as const;\n/** One {@link TextInputType} value, usable as a type. */\nexport type TextInputType = (typeof TextInputType)[keyof typeof TextInputType];\n\n/** Discord interaction response types. */\nexport const InteractionResponseEnum = {\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/** One {@link InteractionResponseEnum} value, usable as a type. */\nexport type InteractionResponseEnum =\n (typeof InteractionResponseEnum)[keyof typeof InteractionResponseEnum];\n\n/** Discord sticker format types. */\nexport const StickerFormatEnum = {\n PNG: 1,\n APNG: 2,\n Lottie: 3,\n GIF: 4,\n} as const;\n/** One {@link StickerFormatEnum} value, usable as a type. */\nexport type StickerFormatEnum =\n (typeof StickerFormatEnum)[keyof typeof StickerFormatEnum];\n\n/** Discord sticker types. */\nexport const StickerEnum = {\n Standard: 1,\n Guild: 2,\n} as const;\n/** One {@link StickerEnum} value, usable as a type. */\nexport type StickerEnum = (typeof StickerEnum)[keyof typeof StickerEnum];\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// ─── Message payloads ────────────────────────────────────────────────────────\n\n/** A Discord payload, or a builder that serialises to one (its `toJSON()` runs when the request is sent). */\nexport type Buildable<T> = T | { toJSON(): T };\n\n/**\n * A message Lunibee sends: channel send and edit, message reply and edit,\n * interaction replies, follow-ups and updates. Embeds and components may be\n * builders or raw objects. Other Discord fields pass through unchanged.\n */\nexport interface MessagePayload {\n content?: string;\n embeds?: Buildable<APIEmbed>[];\n components?: Buildable<APIMessageComponent>[];\n allowed_mentions?: import(\"./gateway.js\").AllowedMentions;\n /** Discord message flags, e.g. `MessageFlags.SuppressEmbeds`. */\n flags?: number;\n tts?: boolean;\n [key: string]: unknown;\n}\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 poll object. */\nexport interface APIPoll {\n question: { text?: string; emoji?: APIPartialEmoji };\n answers: Array<{\n answer_id: number;\n poll_media: { text?: string; emoji?: APIPartialEmoji };\n }>;\n expiry: string | null;\n allow_multiselect: boolean;\n layout_type: number;\n results?: {\n is_finalized: boolean;\n answer_counts: Array<{ id: number; count: number; me_voted: boolean }>;\n };\n}\n/** A forwarded message's snapshot of the original. */\nexport interface APIMessageSnapshot {\n message: Partial<\n Pick<\n APIMessage,\n | \"type\"\n | \"content\"\n | \"embeds\"\n | \"attachments\"\n | \"timestamp\"\n | \"edited_timestamp\"\n | \"flags\"\n | \"mentions\"\n | \"mention_roles\"\n | \"sticker_items\"\n | \"components\"\n >\n >;\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?: APIPoll;\n /** Forwarded messages: a partial copy of the original (content, embeds, attachments, …). */\n message_snapshots?: APIMessageSnapshot[];\n guild_id?: Snowflake;\n /** The author's guild member, on guild messages from the Gateway (without `user`; the author is the user). */\n member?: Omit<APIGuildMember, \"user\"> & { user?: UserData };\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. */\n/** Discord activity types, for presences (`setPresence({ activities: [{ name, type: ActivityEnum.Watching }] })`). */\nexport const ActivityEnum = {\n Playing: 0,\n Streaming: 1,\n Listening: 2,\n Watching: 3,\n Custom: 4,\n Competing: 5,\n} as const;\n/** One {@link ActivityEnum} value, usable as a type. */\nexport type ActivityEnum = (typeof ActivityEnum)[keyof typeof ActivityEnum];\n\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 ApplicationCommandOptionEnum = {\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/** One {@link ApplicationCommandOptionEnum} value, usable as a type. */\nexport type ApplicationCommandOptionEnum =\n (typeof ApplicationCommandOptionEnum)[keyof typeof ApplicationCommandOptionEnum];\n\n/** Discord application command types. */\nexport const ApplicationCommandEnum = {\n ChatInput: 1,\n User: 2,\n Message: 3,\n} as const;\n/** One {@link ApplicationCommandEnum} value, usable as a type. */\nexport type ApplicationCommandEnum =\n (typeof ApplicationCommandEnum)[keyof typeof ApplicationCommandEnum];\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 /** @deprecated Discord deprecated this field. Use `contexts`. Removed in 0.3.0. */\n dm_permission?: boolean;\n /** Where the command can be used: 0 guilds, 1 the bot's DMs, 2 other DMs. */\n contexts?: number[];\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 /** @deprecated Discord deprecated this field. Use `contexts`. Removed in 0.3.0. */\n dm_permission?: boolean;\n /** Where the command can be used: 0 guilds, 1 the bot's DMs, 2 other DMs. */\n contexts?: number[];\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\n// ─── Deprecated names (0.2.2) ────────────────────────────────────────────────\n// Kept so existing bots keep working; removed in 0.3.0. `…Style` became `…Type`\n// and `…Type` became `…Enum`.\n\n/** @deprecated Use {@link ButtonType}. Removed in 0.3.0. */\nexport const ButtonStyle = ButtonType;\n/** @deprecated Use {@link ButtonType}. Removed in 0.3.0. */\nexport type ButtonStyle = ButtonType;\n/** @deprecated Use {@link TextInputType}. Removed in 0.3.0. */\nexport const TextInputStyle = TextInputType;\n/** @deprecated Use {@link TextInputType}. Removed in 0.3.0. */\nexport type TextInputStyle = TextInputType;\n/** @deprecated Use {@link ChannelEnum}. Removed in 0.3.0. */\nexport const ChannelType = ChannelEnum;\n/** @deprecated Use {@link ChannelEnum}. Removed in 0.3.0. */\nexport type ChannelType = ChannelEnum;\n/** @deprecated Use {@link ComponentEnum}. Removed in 0.3.0. */\nexport const ComponentType = ComponentEnum;\n/** @deprecated Use {@link ComponentEnum}. Removed in 0.3.0. */\nexport type ComponentType = ComponentEnum;\n/** @deprecated Use {@link InteractionResponseEnum}. Removed in 0.3.0. */\nexport const InteractionResponseType = InteractionResponseEnum;\n/** @deprecated Use {@link InteractionResponseEnum}. Removed in 0.3.0. */\nexport type InteractionResponseType = InteractionResponseEnum;\n/** @deprecated Use {@link ApplicationCommandEnum}. Removed in 0.3.0. */\nexport const ApplicationCommandType = ApplicationCommandEnum;\n/** @deprecated Use {@link ApplicationCommandEnum}. Removed in 0.3.0. */\nexport type ApplicationCommandType = ApplicationCommandEnum;\n/** @deprecated Use {@link ApplicationCommandOptionEnum}. Removed in 0.3.0. */\nexport const ApplicationCommandOptionType = ApplicationCommandOptionEnum;\n/** @deprecated Use {@link ApplicationCommandOptionEnum}. Removed in 0.3.0. */\nexport type ApplicationCommandOptionType = ApplicationCommandOptionEnum;\n/** @deprecated Use {@link StickerEnum}. Removed in 0.3.0. */\nexport const StickerType = StickerEnum;\n/** @deprecated Use {@link StickerEnum}. Removed in 0.3.0. */\nexport type StickerType = StickerEnum;\n/** @deprecated Use {@link StickerFormatEnum}. Removed in 0.3.0. */\nexport const StickerFormatType = StickerFormatEnum;\n/** @deprecated Use {@link StickerFormatEnum}. Removed in 0.3.0. */\nexport type StickerFormatType = StickerFormatEnum;\n",
|
|
10
|
-
"type RecencyNode<K> = {\n key: K;\n older?: RecencyNode<K>;\n newer?: RecencyNode<K>;\n};\n\n/**\n * Keys in recency order with O(1) touch, promote, delete and oldest. A Set\n * cannot do this: repeatedly removing its first key leaves tombstones that\n * every new iterator scans past.\n */\nclass RecencyList<K> {\n readonly #nodes = new Map<K, RecencyNode<K>>();\n #oldest?: RecencyNode<K>;\n #newest?: RecencyNode<K>;\n\n public get size(): number {\n return this.#nodes.size;\n }\n\n public oldest(): K | undefined {\n return this.#oldest?.key;\n }\n\n /** Adds the key as newest, or moves it there. */\n public touch(key: K): void {\n const node = this.#nodes.get(key);\n if (node) return this.#moveNewest(node);\n const created: RecencyNode<K> = { key, older: this.#newest };\n if (this.#newest) this.#newest.newer = created;\n else this.#oldest = created;\n this.#newest = created;\n this.#nodes.set(key, created);\n }\n\n /** Moves an existing key to newest; ignores unknown keys. */\n public promote(key: K): void {\n const node = this.#nodes.get(key);\n if (node) this.#moveNewest(node);\n }\n\n public delete(key: K): boolean {\n const node = this.#nodes.get(key);\n if (!node) return false;\n this.#unlink(node);\n this.#nodes.delete(key);\n return true;\n }\n\n public clear(): void {\n this.#nodes.clear();\n this.#oldest = this.#newest = undefined;\n }\n\n #unlink(node: RecencyNode<K>): void {\n if (node.older) node.older.newer = node.newer;\n else this.#oldest = node.newer;\n if (node.newer) node.newer.older = node.older;\n else this.#newest = node.older;\n node.older = node.newer = undefined;\n }\n\n #moveNewest(node: RecencyNode<K>): void {\n if (node === this.#newest) return;\n this.#unlink(node);\n node.older = this.#newest;\n if (this.#newest) this.#newest.newer = node;\n else this.#oldest = node;\n this.#newest = node;\n }\n}\n\n/** Retention policy for a {@link Collection}. */\nexport interface CollectionOptions<K = unknown, V = unknown> {\n /** Default sliding TTL in ms for `set()`. Omit for no expiry. */\n ttl?: number;\n /** Maximum entries stored with `set()`; least-recently-used are evicted past it. `setWithoutTTL()` entries are never counted or evicted. */\n maxSize?: number;\n /** Called after an entry is removed automatically, with why. Exceptions are swallowed. */\n onEvict?: (key: K, value: V, reason: EvictionReason) => void;\n}\n\n/** Why an entry was removed automatically. */\nexport type EvictionReason = \"expired\" | \"evicted\";\n\n/** Cumulative counters from {@link Collection.stats}. */\nexport interface CollectionStats {\n /** `get`/`peek` calls that found a value. */ hits: number;\n /** `get`/`peek` calls that found nothing. */ misses: number;\n /** Entries removed because their TTL lapsed. */ expired: number;\n /** Entries removed to stay within `maxSize`. */ evicted: number;\n}\n\ntype Expiry = { deadline: number; window: number; filed: number };\n\nfunction assertTTL(ttl: number | undefined): void {\n if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))\n throw new RangeError(\"TTL must be a positive number, or omitted.\");\n}\n\n/**\n * A keyed collection for Lunibee resource and application state.\n *\n * - `set(key, value, ttl?)` is TTL/LRU-aware: with a TTL (the default from\n * options, or per call) the entry expires after that window of inactivity,\n * and with `maxSize` it counts toward the cap.\n * - `setWithoutTTL(key, value)` never expires: no deadline, no heap record,\n * no timer, and exempt from `maxSize` eviction. Resource managers store\n * Discord state this way, so it leaves only through an explicit delete.\n *\n * Without options, a Collection behaves like a plain Map.\n */\nexport class Collection<K, V> extends Map<K, V> {\n readonly #ttl?: number;\n readonly #maxSize?: number;\n /** Stored loosely typed so the callback does not make Collection invariant in K and V. */\n readonly #onEvict?: (\n key: unknown,\n value: unknown,\n reason: EvictionReason,\n ) => void;\n /** Deadlines of TTL entries only. */\n readonly #expiry = new Map<K, Expiry>();\n /** `set()` keys in recency order (oldest first), tracked only when `maxSize` is set; `setWithoutTTL()` keys are never here. */\n readonly #lru = new RecencyList<K>();\n readonly #stats: CollectionStats = {\n hits: 0,\n misses: 0,\n expired: 0,\n evicted: 0,\n };\n /** Min-heap of filed deadlines; stale records are dropped lazily. */\n readonly #heap: { key: K; deadline: number }[] = [];\n #timer?: ReturnType<typeof setTimeout>;\n #armedFor = Infinity;\n\n /**\n * @param entries Initial entries, stored with `set()`.\n * @param options TTL and size policy.\n * @throws {RangeError} On a non-positive TTL or non-integer `maxSize`.\n */\n public constructor(\n entries?: Iterable<readonly [K, V]> | null,\n options: CollectionOptions<K, V> = {},\n ) {\n super();\n assertTTL(options.ttl);\n if (\n options.maxSize !== undefined &&\n (!Number.isInteger(options.maxSize) || options.maxSize <= 0)\n )\n throw new RangeError(\"maxSize must be a positive integer.\");\n this.#ttl = options.ttl;\n this.#maxSize = options.maxSize;\n this.#onEvict = options.onEvict as\n | ((key: unknown, value: unknown, reason: EvictionReason) => void)\n | undefined;\n if (entries) for (const [key, value] of entries) this.set(key, value);\n }\n\n /**\n * Stores an entry with the default TTL (or `ttl`), marks it most recently\n * used, and enforces `maxSize`. Turns a `setWithoutTTL()` entry back into\n * a TTL/LRU entry.\n */\n public override set(key: K, value: V, ttl?: number): this {\n assertTTL(ttl);\n const window = ttl ?? this.#ttl;\n if (this.#maxSize !== undefined) {\n this.#lru.touch(key);\n }\n super.set(key, value);\n if (window !== undefined) this.#schedule(key, window);\n else if (this.#expiry.size > 0) this.#expiry.delete(key);\n this.#enforceCap();\n return this;\n }\n\n /**\n * Stores an entry that never expires: no deadline, heap record, timer or\n * LRU eviction. It leaves only through `delete`, `sweep`, `clear`, or a\n * later `set()`.\n */\n public setWithoutTTL(key: K, value: V): this {\n if (this.#expiry.size > 0) this.#expiry.delete(key);\n if (this.#lru.size > 0) this.#lru.delete(key);\n super.set(key, value);\n return this;\n }\n\n /** Reads a value; restarts a TTL entry's window and promotes it. */\n public override get(key: K): V | undefined {\n if (this.#expireIfDue(key)) {\n this.#stats.misses++;\n return undefined;\n }\n const value = super.get(key);\n if (value === undefined && !super.has(key)) {\n this.#stats.misses++;\n return undefined;\n }\n this.#stats.hits++;\n const expiry = this.#expiry.get(key);\n if (expiry) expiry.deadline = Date.now() + expiry.window;\n this.#lru.promote(key);\n return value;\n }\n\n /** Reads a value without restarting its TTL or promoting it. */\n public peek(key: K): V | undefined {\n if (!this.#expireIfDue(key) && super.has(key)) {\n this.#stats.hits++;\n return super.get(key);\n }\n this.#stats.misses++;\n return undefined;\n }\n\n /** Cumulative hit, miss, expiry and eviction counters (a copy). */\n public get stats(): CollectionStats {\n return { ...this.#stats };\n }\n\n public override has(key: K): boolean {\n return !this.#expireIfDue(key) && super.has(key);\n }\n\n public override delete(key: K): boolean {\n if (this.#expireIfDue(key)) return false;\n this.#expiry.delete(key);\n this.#lru.delete(key);\n return super.delete(key);\n }\n\n public override clear(): void {\n super.clear();\n this.#expiry.clear();\n this.#lru.clear();\n this.#heap.length = 0;\n if (this.#timer) clearTimeout(this.#timer);\n this.#timer = undefined;\n this.#armedFor = Infinity;\n }\n\n public override get size(): number {\n this.purge();\n return super.size;\n }\n\n public override entries(): MapIterator<[K, V]> {\n this.purge();\n return super.entries();\n }\n\n public override keys(): MapIterator<K> {\n this.purge();\n return super.keys();\n }\n\n public override values(): MapIterator<V> {\n this.purge();\n return super.values();\n }\n\n public override [Symbol.iterator](): MapIterator<[K, V]> {\n return this.entries();\n }\n\n public override forEach(\n callback: (value: V, key: K, map: Map<K, V>) => void,\n thisArg?: unknown,\n ): void {\n this.purge();\n super.forEach(callback, thisArg);\n }\n\n /** Milliseconds until a key lapses, or undefined if absent or never expiring. */\n public ttlRemaining(key: K): number | undefined {\n if (this.#expireIfDue(key)) return undefined;\n const expiry = this.#expiry.get(key);\n return expiry && Math.max(0, expiry.deadline - Date.now());\n }\n\n /** Drops every lapsed TTL entry now. @returns How many were dropped. */\n public purge(): number {\n if (this.#expiry.size === 0) return 0;\n const now = Date.now();\n let removed = 0;\n const dropped: [K, V][] = [];\n while (this.#nextDeadline() <= now) {\n const due = this.#heapPop()!;\n dropped.push([due.key, super.get(due.key)!]);\n this.#remove(due.key);\n removed++;\n }\n this.#stats.expired += removed;\n this.#rearm();\n for (const [key, value] of dropped) this.#notify(key, value, \"expired\");\n return removed;\n }\n\n #expireIfDue(key: K): boolean {\n const expiry = this.#expiry.get(key);\n if (!expiry || expiry.deadline > Date.now()) return false;\n const value = super.get(key)!;\n this.#remove(key);\n this.#stats.expired++;\n this.#notify(key, value, \"expired\");\n return true;\n }\n\n #remove(key: K): void {\n this.#expiry.delete(key);\n this.#lru.delete(key);\n super.delete(key);\n }\n\n #notify(key: K, value: V, reason: EvictionReason): void {\n if (!this.#onEvict) return;\n try {\n this.#onEvict(key, value, reason);\n } catch {\n // A throwing callback must not leave the collection inconsistent.\n }\n }\n\n /** Evicts least-recently-used `set()` entries past `maxSize`; O(1) per eviction. */\n #enforceCap(): void {\n if (this.#maxSize === undefined) return;\n while (this.#lru.size > this.#maxSize) {\n const oldest = this.#lru.oldest()!;\n const value = super.get(oldest)!;\n this.#remove(oldest);\n this.#stats.evicted++;\n this.#notify(oldest, value, \"evicted\");\n }\n }\n\n /**\n * Gives an entry a deadline. Extending one writes a number; the stale\n * heap record re-files itself when it surfaces. Only a deadline that\n * moves earlier (or a new one) is pushed.\n */\n #schedule(key: K, window: number): void {\n const deadline = Date.now() + window;\n const expiry = this.#expiry.get(key);\n if (expiry) {\n expiry.deadline = deadline;\n expiry.window = window;\n if (deadline >= expiry.filed) return;\n expiry.filed = deadline;\n } else this.#expiry.set(key, { deadline, window, filed: deadline });\n this.#heapPush({ key, deadline });\n if (this.#heap.length > 2 * this.#expiry.size + 8) this.#compact();\n this.#rearm();\n }\n\n #nextDeadline(): number {\n for (;;) {\n const top = this.#heap[0];\n if (top === undefined) return Infinity;\n const expiry = this.#expiry.get(top.key);\n if (!expiry || expiry.filed !== top.deadline) {\n this.#heapPop();\n continue;\n }\n if (expiry.deadline === top.deadline) return top.deadline;\n // Extended since it was filed: re-file for its current deadline.\n this.#heapPop();\n expiry.filed = expiry.deadline;\n this.#heapPush({ key: top.key, deadline: expiry.deadline });\n }\n }\n\n #compact(): void {\n const live = this.#heap.filter(\n (record) => this.#expiry.get(record.key)?.filed === record.deadline,\n );\n this.#heap.length = 0;\n for (const record of live) this.#heapPush(record);\n }\n\n #rearm(): void {\n const deadline = this.#nextDeadline();\n if (this.#timer !== undefined && deadline >= this.#armedFor) return;\n if (this.#timer) clearTimeout(this.#timer);\n this.#timer = undefined;\n this.#armedFor = deadline;\n if (deadline === Infinity) return;\n this.#timer = setTimeout(\n () => {\n this.#timer = undefined;\n this.#armedFor = Infinity;\n this.purge();\n },\n Math.max(0, deadline - Date.now()),\n );\n // Pending expiry is housekeeping, not a reason to keep the process alive.\n (this.#timer as { unref?: () => void }).unref?.();\n }\n\n #heapPush(record: { key: K; deadline: number }): void {\n const heap = this.#heap;\n heap.push(record);\n let i = heap.length - 1;\n while (i > 0) {\n const parent = (i - 1) >> 1;\n if (heap[parent]!.deadline <= heap[i]!.deadline) break;\n [heap[parent], heap[i]] = [heap[i]!, heap[parent]!];\n i = parent;\n }\n }\n\n #heapPop(): { key: K; deadline: number } | undefined {\n const heap = this.#heap;\n const top = heap[0];\n const last = heap.pop();\n if (top === undefined || heap.length === 0) return top;\n heap[0] = last!;\n for (let i = 0; ;) {\n const left = 2 * i + 1;\n const right = left + 1;\n let smallest = i;\n if (\n left < heap.length &&\n heap[left]!.deadline < heap[smallest]!.deadline\n )\n smallest = left;\n if (\n right < heap.length &&\n heap[right]!.deadline < heap[smallest]!.deadline\n )\n smallest = right;\n if (smallest === i) break;\n [heap[smallest], heap[i]] = [heap[i]!, heap[smallest]!];\n i = smallest;\n }\n return top;\n }\n\n /** Returns the first stored value. */\n public first(): V | undefined {\n for (const value of this.values()) return value;\n return undefined;\n }\n /** Returns the first stored key. */\n public firstKey(): K | undefined {\n for (const key of this.keys()) return key;\n return undefined;\n }\n /** Returns the last stored value. */\n public last(): V | undefined {\n let value: V | undefined;\n for (const item of this.values()) value = item;\n return value;\n }\n /** Returns the last stored key. */\n public lastKey(): K | undefined {\n let key: K | undefined;\n for (const item of this.keys()) key = item;\n return key;\n }\n /** Finds the first value matching a predicate. */\n public find(\n predicate: (value: V, key: K, collection: this) => boolean,\n ): V | undefined {\n for (const [key, value] of this) {\n if (predicate(value, key, this)) return value;\n }\n return undefined;\n }\n /** Returns all values matching a predicate. */\n public filter(\n predicate: (value: V, key: K, collection: this) => boolean,\n ): Collection<K, V> {\n const result = new Collection<K, V>();\n for (const [key, value] of this) {\n if (predicate(value, key, this)) result.set(key, value);\n }\n return result;\n }\n /** Transforms every stored value into an array. */\n public map<T>(transform: (value: V, key: K, collection: this) => T): T[] {\n const result: T[] = [];\n for (const [key, value] of this) {\n result.push(transform(value, key, this));\n }\n return result;\n }\n /** Returns whether at least one stored value satisfies a predicate. */\n public some(\n predicate: (value: V, key: K, collection: this) => boolean,\n ): boolean {\n for (const [key, value] of this) {\n if (predicate(value, key, this)) return true;\n }\n return false;\n }\n /** Returns whether every stored value satisfies a predicate. */\n public every(\n predicate: (value: V, key: K, collection: this) => boolean,\n ): boolean {\n for (const [key, value] of this) {\n if (!predicate(value, key, this)) return false;\n }\n return true;\n }\n /** Runs a callback for each stored value. */\n public each(\n callback: (value: V, key: K, collection: this) => unknown,\n ): this {\n for (const [key, value] of this) {\n callback(value, key, this);\n }\n return this;\n }\n /** Returns an array containing all stored values. */\n public array(): V[] {\n return [...this.values()];\n }\n /** Returns an array containing all stored keys. */\n public keyArray(): K[] {\n return [...this.keys()];\n }\n /** Returns a plain array of entries. */\n public entriesArray(): [K, V][] {\n return [...this.entries()];\n }\n /** Returns a new collection with the same entries. */\n public clone(): Collection<K, V> {\n const copy = new Collection<K, V>();\n for (const [key, value] of this) copy.set(key, value);\n return copy;\n }\n /** Returns whether all supplied keys are present. */\n public hasAll(...keys: K[]): boolean {\n for (let i = 0; i < keys.length; i++) {\n if (!this.has(keys[i]!)) return false;\n }\n return true;\n }\n /** Returns whether at least one supplied key is present. */\n public hasAny(...keys: K[]): boolean {\n for (let i = 0; i < keys.length; i++) {\n if (this.has(keys[i]!)) return true;\n }\n return false;\n }\n /** Returns the first key whose value matches a predicate. */\n public findKey(\n predicate: (value: V, key: K, collection: this) => boolean,\n ): K | undefined {\n for (const [key, value] of this) {\n if (predicate(value, key, this)) return key;\n }\n return undefined;\n }\n /** Returns whether a predicate matches at least one entry. */\n public someEntry(\n predicate: (value: V, key: K, collection: this) => boolean,\n ): boolean {\n return this.some(predicate);\n }\n /** Removes every entry matching a predicate and returns the number removed. */\n public sweep(\n predicate: (value: V, key: K, collection: this) => boolean,\n ): number {\n let removed = 0;\n for (const [key, value] of this) {\n if (predicate(value, key, this) && this.delete(key)) removed++;\n }\n return removed;\n }\n /** Returns the collection's first matching entry as a tuple. */\n public firstEntry(): [K, V] | undefined {\n for (const [key, value] of this) return [key, value];\n return undefined;\n }\n /** Returns the collection's last matching entry as a tuple. */\n public lastEntry(): [K, V] | undefined {\n let entry: [K, V] | undefined;\n for (const item of this) entry = [item[0], item[1]];\n return entry;\n }\n /** Returns a new Collection containing elements from both collections. */\n public union(other: Collection<K, V>): Collection<K, V> {\n const result = this.clone();\n for (const [key, value] of other) result.set(key, value);\n return result;\n }\n /** Returns a new Collection containing only elements present in both collections. */\n public intersection(other: Collection<K, V>): Collection<K, V> {\n const result = new Collection<K, V>();\n for (const [key, value] of this) {\n if (other.has(key)) result.set(key, value);\n }\n return result;\n }\n /** Returns a new Collection containing elements present in this collection but not the other. */\n public difference(other: Collection<K, V>): Collection<K, V> {\n const result = new Collection<K, V>();\n for (const [key, value] of this) {\n if (!other.has(key)) result.set(key, value);\n }\n return result;\n }\n /** Splits the collection into two collections based on a predicate.\n * @returns `[passing, failing]` — entries satisfying the predicate, then those that don't.\n */\n public partition(\n predicate: (value: V, key: K, collection: this) => boolean,\n ): [Collection<K, V>, Collection<K, V>] {\n const pass = new Collection<K, V>();\n const fail = new Collection<K, V>();\n for (const [key, value] of this) {\n if (predicate(value, key, this)) pass.set(key, value);\n else fail.set(key, value);\n }\n return [pass, fail];\n }\n /** Calls `fn` with this collection and returns the collection unchanged.\n * Useful for inserting debug side-effects in a chain without breaking the flow.\n */\n public tap(fn: (collection: this) => unknown): this {\n fn(this);\n return this;\n }\n /** Maps every entry to an array of items and flattens the results. */\n public flatMap<T>(\n transform: (value: V, key: K, collection: this) => T[],\n ): T[] {\n const result: T[] = [];\n for (const [key, value] of this) {\n for (const item of transform(value, key, this)) result.push(item);\n }\n return result;\n }\n /** Reduces the collection to a single value. */\n public reduce<T>(\n fn: (accumulator: T, value: V, key: K, collection: this) => T,\n initialValue: T,\n ): T {\n let acc = initialValue;\n for (const [key, value] of this) acc = fn(acc, value, key, this);\n return acc;\n }\n /** Returns a new Collection with entries sorted by comparator (non-mutating).\n * Defaults to insertion order if no comparator is provided.\n */\n public sorted(\n comparator?: (a: V, b: V, aKey: K, bKey: K) => number,\n ): Collection<K, V> {\n // Decorate with the original insertion index and use it as a tiebreaker so\n // equal elements keep their insertion order (a stable sort independent of\n // the engine's Array.prototype.sort stability guarantees).\n const decorated = [...this.entries()].map((entry, index) => ({\n entry,\n index,\n }));\n if (comparator)\n decorated.sort((x, y) => {\n const comparison = comparator(\n x.entry[1],\n y.entry[1],\n x.entry[0],\n y.entry[0],\n );\n return comparison !== 0 ? comparison : x.index - y.index;\n });\n const result = new Collection<K, V>();\n for (const { entry } of decorated) result.set(entry[0], entry[1]);\n return result;\n }\n /** Returns a random value from the collection, or `undefined` if empty.\n * Uses `Math.random()` (fast, non-cryptographic) — do not use for security-sensitive\n * selection such as tokens or secrets. */\n public random(): V | undefined {\n const arr = [...this.values()];\n if (!arr.length) return undefined;\n return arr[Math.floor(Math.random() * arr.length)];\n }\n /** Returns a random key from the collection, or `undefined` if empty.\n * Uses `Math.random()` (fast, non-cryptographic) — do not use for security-sensitive\n * selection such as tokens or secrets. */\n public randomKey(): K | undefined {\n const arr = [...this.keys()];\n if (!arr.length) return undefined;\n return arr[Math.floor(Math.random() * arr.length)];\n }\n /** Returns the value at a given insertion-order index (supports negative indices). */\n public at(index: number): V | undefined {\n const arr = [...this.values()];\n const i = index < 0 ? arr.length + index : index;\n return arr[i];\n }\n /** Returns the key at a given insertion-order index (supports negative indices). */\n public keyAt(index: number): K | undefined {\n const arr = [...this.keys()];\n const i = index < 0 ? arr.length + index : index;\n return arr[i];\n }\n /** Serializes the collection to a plain `[key, value]` array. */\n public toJSON(): [K, V][] {\n return [...this.entries()];\n }\n}\n\nexport { Cache } from \"./cache.js\";\nexport type { CacheOptions } from \"./cache.js\";\n",
|
|
11
|
-
"import { Collection } from \"@lunibee/collection\";\n\n/** Splits the audit-log `reason` off an options object, so it becomes a header, not a body field. */\nexport function splitReason<T extends { reason?: string }>(\n options: T,\n): [Omit<T, \"reason\">, string | undefined] {\n const { reason, ...payload } = options;\n return [payload, reason];\n}\n\n/** Generic cache manager. @typeParam K Cache key type. @typeParam V Cached value type. */\nexport class Manager<K, V> {\n /** Authoritative resource state. Entries never expire: see {@link Manager.set}.
|
|
12
|
-
"export interface BucketState {\n remaining: number;\n resetAt: number;\n}\n\n/**\n * Outcome of an atomic reservation.\n *\n * `granted` means one unit of the bucket's allowance now belongs to the caller\n * and to nobody else — the distinction that a read-then-write cannot make when\n * several workers share a store.\n */\nexport type Reservation =\n { granted: true } | { granted: false; retryAfterMs: number };\n\n/** Interface for distributed or local rate limit synchronization. */\nexport interface RateLimitStore {\n /** Gets the server bucket hash for a normalized route. */\n getBucketHash(\n route: string,\n ): Promise<string | undefined> | string | undefined;\n /** Associates a route with a server bucket hash. */\n setBucketHash(route: string, hash: string): Promise<void> | void;\n\n /** Gets the current state for a bucket key. */\n getBucket(\n key: string,\n ): Promise<BucketState | undefined> | BucketState | undefined;\n /** Updates the state for a bucket key. */\n updateBucket(key: string, state: BucketState): Promise<void> | void;\n\n /** Gets the global reset timestamp. */\n getGlobalReset(): Promise<number> | number;\n /** Sets the global reset timestamp. */\n setGlobalReset(resetAt: number): Promise<void> | void;\n\n /**\n * Atomically consumes one unit of a bucket's allowance.\n *\n * Optional: a store that cannot do this atomically must omit it, and the\n * limiter falls back to waiting on observed state. Implementations must\n * grant when the bucket is unknown or its window has elapsed — an unknown\n * bucket is discovered by sending, and refusing would deadlock the route.\n */\n reserve?(key: string): Promise<Reservation> | Reservation;\n\n /**\n * Evicts expired bucket entries. Optional: stores with native key\n * expiry (e.g. Redis) can omit it. `maxAge` (ms) additionally drops\n * buckets whose reset is older than that window; defaults to 0 (only\n * already-reset buckets are removed).\n */\n prune?(maxAge?: number): Promise<void> | void;\n}\n\n/** Local memory implementation of RateLimitStore. */\nexport class MemoryRateLimitStore implements RateLimitStore {\n readonly #buckets = new Map<string, BucketState>();\n readonly #routeBuckets = new Map<string, string>();\n #globalResetAt = 0;\n /** Minimum interval between automatic prunes, in ms. */\n static readonly #PRUNE_INTERVAL = 60_000;\n #lastPruneAt = 0;\n\n public getBucketHash(route: string): string | undefined {\n return this.#routeBuckets.get(route);\n }\n public setBucketHash(route: string, hash: string): void {\n this.#routeBuckets.set(route, hash);\n }\n public getBucket(key: string): BucketState | undefined {\n return this.#buckets.get(key);\n }\n /**\n * Consumes one unit of the bucket's allowance.\n *\n * Single-process reservation is trivially atomic: JavaScript will not\n * interleave this method with another caller's copy of it.\n */\n public reserve(key: string): Reservation {\n const state = this.#buckets.get(key);\n const now = Date.now();\n // Unknown bucket, or a window that has already elapsed: the next\n // response re-establishes the real allowance.\n if (!state || state.resetAt <= now) return { granted: true };\n if (state.remaining > 0) {\n state.remaining -= 1;\n return { granted: true };\n }\n return { granted: false, retryAfterMs: state.resetAt - now };\n }\n public updateBucket(key: string, state: BucketState): void {\n this.#buckets.set(key, state);\n // Amortised eviction: sweep expired buckets at most once per interval\n // so the map cannot grow unbounded across long-lived processes.\n const now = Date.now();\n if (now - this.#lastPruneAt >= MemoryRateLimitStore.#PRUNE_INTERVAL) {\n this.#lastPruneAt = now;\n this.prune();\n }\n }\n /** Removes buckets whose reset is in the past (or older than `maxAge` ms). */\n public prune(maxAge = 0): void {\n const cutoff = Date.now() - Math.max(0, maxAge);\n for (const [key, state] of this.#buckets) {\n if (state.resetAt <= cutoff) this.#buckets.delete(key);\n }\n }\n public getGlobalReset(): number {\n return this.#globalResetAt;\n }\n public setGlobalReset(resetAt: number): void {\n this.#globalResetAt = resetAt;\n }\n}\n",
|
|
13
|
-
"/** Why a REST request failed, for handling without matching on status codes. */\nexport type RESTErrorKind =\n /** Cancelled through an AbortSignal. */\n | \"aborted\"\n /** The attempt exceeded the transport timeout. */\n | \"timeout\"\n /** No response: DNS, TLS, connection reset. */\n | \"network\"\n /** 429 that outlived the retry budget. */\n | \"rateLimited\"\n /** 401: invalid or revoked token. */\n | \"authentication\"\n /** 403: missing access or permissions. */\n | \"permission\"\n /** 404: unknown resource. */\n | \"notFound\"\n /** 400 / 422: the request body or parameters were rejected. */\n | \"validation\"\n /** 5xx: Discord failed to handle the request. */\n | \"server\"\n /** Any other 4xx. */\n | \"client\";\n\nfunction kindFromStatus(status: number): RESTErrorKind {\n if (status === 429) return \"rateLimited\";\n if (status === 401) return \"authentication\";\n if (status === 403) return \"permission\";\n if (status === 404) return \"notFound\";\n if (status === 400 || status === 422) return \"validation\";\n if (status >= 500) return \"server\";\n if (status === 0) return \"network\";\n return \"client\";\n}\n\n/**\n * Replaces the token segment of webhook and interaction paths with `:token`,\n * so request paths can appear in errors, hooks and logs without leaking a\n * credential.\n */\nexport function redactPath(path: string): string {\n return (\n path\n // The ID segment is matched loosely: a malformed ID must not stop the\n // token that follows it from being redacted.\n .replace(/^(\\/webhooks\\/[^/?]+\\/)[^/?]
|
|
14
|
-
"/** Query-string value accepted by a request. */\nexport type RESTQuery =\n | URLSearchParams\n | Record<string, string | number | boolean | null | undefined>\n | string;\n\n/**\n * Identity of a request as Discord's rate limiter sees it.\n *\n * `route` is the shape of the endpoint (ids replaced by `:id`), which is what\n * Discord returns a bucket hash for. `major` is the resource that gives an\n * endpoint its own independent limit. Both are needed: the hash alone would\n * make two channels share one counter.\n */\nexport interface RouteKey {\n /** Uppercased HTTP method.
|
|
15
|
-
"import { abortable } from \"./errors.js\";\n\n/**\n * Serialises work per rate-limit bucket.\n *\n * One request per bucket key is in flight at a time, so each request sees the\n * limit state its predecessor's response wrote. The queue slot is released on\n * every exit path — including an abort raised while still waiting — because a\n * slot that is never released wedges its bucket for the process lifetime.\n */\nexport class RequestScheduler {\n /** Maximum times a request may be moved to a different bucket queue. */\n public static readonly MAX_REMAPS = 2;\n readonly #queues = new Map<string, Promise<void>>();\n\n /** Number of bucket keys currently holding a queue slot. */\n public get size(): number {\n return this.#queues.size;\n }\n\n /**\n * Runs `task` under the bucket key that `resolveKey` reports *at the moment\n * the slot is acquired*, not at enqueue time.\n *\n * Discord can map several routes onto one bucket hash, and a route only\n * learns its hash from a response. A request that queued under its\n * route-derived key while another request discovered the shared hash would\n * otherwise run concurrently with that bucket's other traffic. Re-resolving\n * after the wait moves it onto the right queue instead.\n *\n * @param resolveKey Returns the current bucket key for this request.\n * @param signal Cancellation signal honoured while queued.\n * @param path Request path, used for cancellation error context.\n * @param task Work to run while holding the slot, given the final key and\n * a callback that frees the slot early.\n */\n public async runResolved<T>(\n resolveKey: () => Promise<string>,\n signal: AbortSignal | undefined,\n path: string,\n task: (key: string, release: () => void) => Promise<T>,\n ): Promise<T> {\n let key = await resolveKey();\n // A remap can only chain as far as route key -> shared hash, so a small\n // bound is enough; the final hop runs whatever key it holds.\n for (let hop = 0; hop < RequestScheduler.MAX_REMAPS; hop++) {\n const outcome = await this.run<\n { done: true; value: T } | { done: false; key: string }\n >(key, signal, path, async (release) => {\n const current = await resolveKey();\n if (current !== key) return { done: false, key: current };\n return { done: true, value: await task(key, release) };\n });\n if (outcome.done) return outcome.value;\n key = outcome.key;\n }\n return this.run(key, signal, path, (release) => task(key, release));\n }\n\n /**\n * Runs `task` once every earlier task for `key` has settled, or has freed\n * its slot early through the `release` callback it was given.\n * @param key Bucket key to serialise on.\n * @param signal Cancellation signal honoured while queued.\n * @param path Request path, used for cancellation error context.\n * @param task Work to run while holding the slot, given an idempotent\n * callback that frees the slot before the task settles.\n */\n public async run<T>(\n key: string,\n signal: AbortSignal | undefined,\n path: string,\n task: (release: () => void) => Promise<T>,\n ): Promise<T> {\n const previous = this.#queues.get(key) ?? Promise.resolve();\n let open!: () => void;\n const gate = new Promise<void>((resolve) => {\n open = resolve;\n });\n this.#queues.set(key, gate);\n let released = false;\n const release = (): void => {\n if (released) return;\n released = true;\n open();\n // Drop our entry so idle buckets do not accumulate, but only if it\n // is still ours: a later request may already have replaced it.\n if (this.#queues.get(key) === gate) this.#queues.delete(key);\n };\n try {\n await abortable(previous, signal, path);\n return await task(release);\n } finally {\n release();\n }\n }\n}\n",
|
|
16
|
-
"import { sleep } from \"./errors.js\";\nimport { scopeBucket } from \"./route.js\";\nimport type { RateLimitStore } from \"./store.js\";\n\n/**\n * Owns Discord's rate-limit state: when a request may go out, and what a\n * response says about the bucket it landed in.\n *\n * The limiter holds no queueing logic of its own — {@link RequestScheduler}\n * decides ordering — and no HTTP knowledge beyond reading rate-limit headers.\n */\nexport class RateLimiter {\n readonly #store: RateLimitStore;\n /** Whether responses may arrive out of order for one bucket. */\n readonly #concurrent: boolean;\n\n /**\n * @param store Rate-limit state store.\n * @param options `concurrent`: set when several requests per bucket can be\n * in flight, so a late response cannot raise `remaining` within its window.\n */\n public constructor(\n store: RateLimitStore,\n options: { concurrent?: boolean } = {},\n ) {\n this.#store = store;\n this.#concurrent = options.concurrent ?? false;\n }\n\n /** The backing store, shared across processes when a distributed store is used. */\n public get store(): RateLimitStore {\n return this.#store;\n }\n\n /** Resolves the bucket key a request should be gated on. */\n public async resolveBucketKey(\n route: string,\n major: string,\n ): Promise<string> {\n return scopeBucket(\n (await this.#store.getBucketHash(route)) ?? route,\n major,\n );\n }\n\n /** Whether the backing store can reserve allowance atomically. */\n public get reserves(): boolean {\n return typeof this.#store.reserve === \"function\";\n }\n\n /**\n * Waits until both the route bucket and the global limit permit sending.\n *\n * When the store supports it, allowance is *reserved* rather than merely\n * observed. Reading `remaining` and deciding to send is a race across\n * workers: three processes all read `remaining: 1` and all send. A\n * reservation hands the unit to exactly one of them.\n */\n public async acquire(\n bucketKey: string,\n signal: AbortSignal | undefined,\n path: string,\n ): Promise<void> {\n await this.#waitGlobal(signal, path);\n if (!this.#store.reserve) {\n const bucket = await this.#store.getBucket(bucketKey);\n if (bucket) {\n const delay = bucket.resetAt - Date.now();\n if (bucket.remaining <= 0 && delay > 0)\n await sleep(delay, signal, path);\n }\n return;\n }\n // Each refusal carries the wait until the window resets, so the loop\n // advances by a real interval every time; the bound only guards against\n // a pathological store that keeps refusing with a zero wait.\n for (let attempt = 0; attempt < 8; attempt++) {\n const reservation = await this.#store.reserve(bucketKey);\n if (reservation.granted) return;\n await sleep(Math.max(1, reservation.retryAfterMs), signal, path);\n await this.#waitGlobal(signal, path);\n }\n }\n\n async #waitGlobal(\n signal: AbortSignal | undefined,\n path: string,\n ): Promise<void> {\n const globalDelay = (await this.#store.getGlobalReset()) - Date.now();\n if (globalDelay > 0) await sleep(globalDelay, signal, path);\n }\n\n /** Extends the global limit, never shortening a longer one already recorded. */\n public async noteGlobalReset(resetAt: number): Promise<void> {\n const current = await this.#store.getGlobalReset();\n await this.#store.setGlobalReset(Math.max(current, resetAt));\n }\n\n /**\n * Records a response's rate-limit headers and returns the bucket key the\n * request actually belongs to: Discord may reveal a server bucket hash that\n * differs from the route-derived key used before the first response.\n */\n public async applyResponse(\n response: Response,\n bucketKey: string,\n route: string,\n major: string,\n ): Promise<string> {\n let currentKey = bucketKey;\n const serverBucket = response.headers.get(\"X-RateLimit-Bucket\");\n if (serverBucket) {\n await this.#store.setBucketHash(route, serverBucket);\n currentKey = scopeBucket(serverBucket, major);\n }\n\n const stored = await this.#store.getBucket(currentKey);\n const bucket = stored ? { ...stored } : { remaining: 1, resetAt: 0 };\n const windowActive =\n this.#concurrent && !!stored && stored.resetAt > Date.now();\n const remaining = Number(response.headers.get(\"X-RateLimit-Remaining\"));\n const resetAfter = Number(\n response.headers.get(\"X-RateLimit-Reset-After\"),\n );\n const reset = Number(response.headers.get(\"X-RateLimit-Reset\"));\n\n if (Number.isFinite(remaining))\n bucket.remaining = Math.max(0, remaining);\n if (Number.isFinite(resetAfter))\n bucket.resetAt = Date.now() + Math.max(0, resetAfter) * 1000;\n else if (Number.isFinite(reset)) bucket.resetAt = reset * 1000;\n // With concurrent requests, responses from one window can arrive out of\n // order: never let a late one hand back allowance already reserved.\n if (windowActive && stored) {\n bucket.remaining = Math.min(bucket.remaining, stored.remaining);\n bucket.resetAt = Math.max(bucket.resetAt, stored.resetAt);\n }\n\n if (response.status === 429) {\n const retryAfter = Number(response.headers.get(\"Retry-After\"));\n if (Number.isFinite(retryAfter))\n bucket.resetAt = Math.max(\n bucket.resetAt,\n Date.now() + retryAfter * 1000,\n );\n }\n await this.#store.updateBucket(currentKey, bucket);\n\n if (response.headers.get(\"X-RateLimit-Global\") === \"true\") {\n const retryAfter = Number(response.headers.get(\"Retry-After\"));\n if (Number.isFinite(retryAfter))\n await this.noteGlobalReset(Date.now() + retryAfter * 1000);\n }\n\n return currentKey;\n }\n}\n",
|
|
17
|
-
"import { RESTError, abortError } from \"./errors.js\";\n\n/** Minimal fetch shape the transport depends on, so a stub needs no extras. */\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>;\n\n/** One HTTP attempt, fully resolved: no routing, retry or rate-limit concerns. */\nexport interface TransportRequest {\n /** Uppercased HTTP method.
|
|
18
|
-
"/** Normalised shape of a Discord error payload. */\nexport interface DecodedError {\n message?: string;\n code?: number;\n retry_after?: number;\n global?: boolean;\n}\n\n/** Turns a raw {@link Response} into a payload and the error metadata retries need. */\nexport class ResponseDecoder {\n /** Reads a Discord response payload as JSON, text, or nothing for 204. */\n public async read(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined;\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\"))\n return response.json().catch(() => undefined);\n return response.text().catch(() => undefined);\n }\n\n /** Extracts Discord's error metadata from a decoded payload. */\n public errorData(payload: unknown): DecodedError {\n if (!payload || typeof payload !== \"object\") return {};\n const data = payload as Record<string, unknown>;\n return {\n message:\n typeof data.message === \"string\" ? data.message : undefined,\n code: typeof data.code === \"number\" ? data.code : undefined,\n retry_after:\n typeof data.retry_after === \"number\"\n ? data.retry_after\n : undefined,\n global: data.global === true,\n };\n }\n\n /**\n * Resolves Retry-After (seconds) from the payload, falling back to the\n * header and finally to one second.\n *\n * An absent header is explicitly *not* a zero delay: `Number(null)` is 0,\n * which is finite, so reading it directly would answer a 429 that carries\n * no Retry-After by retrying immediately — exactly when backing off matters.\n */\n public retryAfter(response: Response, data: DecodedError): number {\n const raw = response.headers.get(\"Retry-After\");\n const header = raw === null ? Number.NaN : Number(raw);\n const retryAfter =\n data.retry_after ?? (Number.isFinite(header) ? header : 1);\n return Math.max(0, retryAfter);\n }\n}\n",
|
|
19
|
-
"/** Discord REST API route definitions. */\nexport const Routes = {\n /** Returns the current bot user. @returns User route. */ user: () =>\n \"/users/@me\",\n /** Returns one user. @param userId User identifier. @returns User route. */ userById:\n (userId: string) => `/users/${snowflake(userId, \"User ID\")}`,\n /** Returns a guild. @param guildId Guild identifier. @returns Guild route. */ guild: (\n guildId: string,\n ) => `/guilds/${snowflake(guildId, \"Guild ID\")}`,\n /** Returns a guild preview. @param guildId Guild identifier. */ guildPreview:\n (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/preview`,\n /** Returns active threads for a guild. @param guildId Guild identifier. */ guildActiveThreads:\n (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/threads/active`,\n /** Returns webhooks for a guild. @param guildId Guild identifier. */ guildWebhooks:\n (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/webhooks`,\n /** Returns invites for a guild. @param guildId Guild identifier. */ guildInvites:\n (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/invites`,\n /** Returns channels in a guild. @param guildId Guild identifier. @returns Channel collection route. */ guildChannels:\n (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/channels`,\n /** Returns a guild member. @param guildId Guild identifier. @param userId User identifier. @returns Guild-member route. */ guildMember:\n (guildId: string, userId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/members/${snowflake(userId, \"User ID\")}`,\n /** Returns all guild roles. @param guildId Guild identifier. @returns Guild-role route. */ guildRoles:\n (guildId: string) => `/guilds/${snowflake(guildId, \"Guild ID\")}/roles`,\n /** Returns an individual guild role. */ guildRole: (\n guildId: string,\n roleId: string,\n ) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/roles/${snowflake(roleId, \"Role ID\")}`,\n /** Returns a member role route. */ guildMemberRole: (\n guildId: string,\n userId: string,\n roleId: string,\n ) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/members/${snowflake(userId, \"User ID\")}/roles/${snowflake(roleId, \"Role ID\")}`,\n /** Returns guild bans collection. */ guildBans: (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/bans`,\n /** Returns an individual guild ban. */ guildBan: (\n guildId: string,\n userId: string,\n ) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/bans/${snowflake(userId, \"User ID\")}`,\n /** Returns a channel. @param channelId Channel identifier. @returns Channel route. */ channel:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}`,\n /** Returns messages in a channel. @param channelId Channel identifier. @returns Message collection route. */ channelMessages:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages`,\n /** Returns a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Message route. */ message:\n (channelId: string, messageId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages/${snowflake(messageId, \"Message ID\")}`,\n /** Crossposts a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Crosspost route. */ crosspostMessage:\n (channelId: string, messageId: string) =>\n `${Routes.message(channelId, messageId)}/crosspost`,\n /** Returns reactions for a message and emoji. @param channelId Channel identifier. @param messageId Message identifier. @param emoji Emoji name or ID. @returns Reaction route. */ messageReactions:\n (channelId: string, messageId: string, emoji: string) =>\n `${Routes.message(channelId, messageId)}/reactions/${encodeURIComponent(emoji)}`,\n /** Removes all reactions from a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Reaction collection route. */ messageReactionsAll:\n (channelId: string, messageId: string) =>\n `${Routes.message(channelId, messageId)}/reactions`,\n /** Returns pinned messages, newest first, in pages of up to 50 (`before`, `limit`). @param channelId Channel identifier. @returns Pins route. */ channelMessagesPins:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages/pins`,\n /** Pins (PUT) or unpins (DELETE) a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Pin route. */ channelMessagesPin:\n (channelId: string, messageId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages/pins/${snowflake(messageId, \"Message ID\")}`,\n /** @deprecated Discord deprecated this endpoint. Use {@link Routes.channelMessagesPins}, which returns `{ items, has_more }`. Removed in 0.3.0. */ channelPins:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/pins`,\n /** @deprecated Discord deprecated this endpoint. Use {@link Routes.channelMessagesPin}. Removed in 0.3.0. */ channelPin:\n (channelId: string, messageId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/pins/${snowflake(messageId, \"Message ID\")}`,\n /** Creates a thread from a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Message-thread route. */ messageThread:\n (channelId: string, messageId: string) =>\n `${Routes.message(channelId, messageId)}/threads`,\n /** Bulk deletes messages. @param channelId Channel identifier. @returns Bulk-delete route. */ channelBulkDelete:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages/bulk-delete`,\n /** Returns channel webhooks. @param channelId Channel identifier. @returns Webhook collection route. */ channelWebhooks:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/webhooks`,\n /** Returns channel invites. @param channelId Channel identifier. @returns Invite collection route. */ channelInvites:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/invites`,\n /** Returns a webhook. @param webhookId Webhook identifier. @param token Optional webhook token. @returns Webhook route. */ webhook:\n (webhookId: string, token?: string) =>\n `/webhooks/${snowflake(webhookId, \"Webhook ID\")}${token ? `/${encodeURIComponent(token)}` : \"\"}`,\n /** Returns a webhook message. */ webhookMessage: (\n webhookId: string,\n token: string,\n messageId: string,\n ) =>\n `/webhooks/${snowflake(webhookId, \"Webhook ID\")}/${encodeURIComponent(token)}/messages/${snowflake(messageId, \"Message ID\")}`,\n /** Returns application commands for an application. @param applicationId Application identifier. @returns Global command route. */ applicationCommands:\n (applicationId: string) =>\n `/applications/${snowflake(applicationId, \"Application ID\")}/commands`,\n /** Returns one application command. @param applicationId Application identifier. @param commandId Command identifier. @returns Command route. */ applicationCommand:\n (applicationId: string, commandId: string) =>\n `/applications/${snowflake(applicationId, \"Application ID\")}/commands/${snowflake(commandId, \"Command ID\")}`,\n /** Returns guild application commands. @param applicationId Application identifier. @param guildId Guild identifier. @returns Guild command route. */ guildApplicationCommands:\n (applicationId: string, guildId: string) =>\n `/applications/${snowflake(applicationId, \"Application ID\")}/guilds/${snowflake(guildId, \"Guild ID\")}/commands`,\n /** Returns a single guild application command. @param applicationId Application identifier. @param guildId Guild identifier. @param commandId Command identifier. @returns Guild command route. */ guildApplicationCommand:\n (applicationId: string, guildId: string, commandId: string) =>\n `/applications/${snowflake(applicationId, \"Application ID\")}/guilds/${snowflake(guildId, \"Guild ID\")}/commands/${snowflake(commandId, \"Command ID\")}`,\n /** Returns an interaction callback endpoint. @param interactionId Interaction identifier. @param token Interaction token. @returns Interaction callback route. */ interactionCallback:\n (interactionId: string, token: string) =>\n `/interactions/${snowflake(interactionId, \"Interaction ID\")}/${encodeURIComponent(token)}/callback`,\n /** Returns the original interaction response endpoint. @param applicationId Application identifier. @param token Interaction token. @returns Original-response route. */ interactionOriginalResponse:\n (applicationId: string, token: string) =>\n `/webhooks/${snowflake(applicationId, \"Application ID\")}/${encodeURIComponent(token)}/messages/@original`,\n\n /** Returns public archived threads for a channel. @param channelId Channel identifier. @returns Public-archive route. */ channelPublicArchivedThreads:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/threads/archived/public`,\n /** Returns private archived threads for a channel. @param channelId Channel identifier. @returns Private-archive route. */ channelPrivateArchivedThreads:\n (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/threads/archived/private`,\n /** Returns a thread's members. @param threadId Thread identifier. @returns Thread-member route. */ threadMembers:\n (threadId: string) =>\n `/channels/${snowflake(threadId, \"Thread ID\")}/thread-members`,\n /** Returns guild scheduled events. @param guildId Guild identifier. @returns Scheduled-event collection route. */ guildScheduledEvents:\n (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/scheduled-events`,\n /** Returns one guild scheduled event. @param guildId Guild identifier. @param eventId Event identifier. @returns Scheduled-event route. */ guildScheduledEvent:\n (guildId: string, eventId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/scheduled-events/${snowflake(eventId, \"Event ID\")}`,\n /** Returns users subscribed to a scheduled event. @param guildId Guild identifier. @param eventId Event identifier. @returns Scheduled-event users route. */ guildScheduledEventUsers:\n (guildId: string, eventId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/scheduled-events/${snowflake(eventId, \"Event ID\")}/users`,\n /** Returns a channel permission overwrite. @param channelId Channel identifier. @param overwriteId Role or user identifier. @returns Permission overwrite route. */ channelPermission:\n (channelId: string, overwriteId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/permissions/${snowflake(overwriteId, \"Overwrite ID\")}`,\n /** Returns guild automod rules. @param guildId Guild identifier. @returns Automod-rule collection route. */ guildAutoModerationRules:\n (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/auto-moderation/rules`,\n /** Returns one automod rule. @param guildId Guild identifier. @param ruleId Rule identifier. @returns Automod-rule route. */ guildAutoModerationRule:\n (guildId: string, ruleId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/auto-moderation/rules/${snowflake(ruleId, \"Rule ID\")}`,\n /** Returns current voice regions. @returns Voice-region route. */ voiceRegions:\n () => \"/voice/regions\",\n /** Returns the generic Gateway endpoint. @returns Gateway route. */ gateway:\n () => \"/gateway\",\n /** Returns the Gateway endpoint and recommended shard count for bots. @returns Gateway bot route. */ gatewayBot:\n () => \"/gateway/bot\",\n\n // ─── Audit Logs ──────────────────────────────────────────────────────────────\n /** Returns audit log entries for a guild. @param guildId Guild identifier. @returns Audit log route. */\n guildAuditLog: (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/audit-logs`,\n\n // ─── Guild Members (bulk fetch) ───────────────────────────────────────────────\n /** Returns members in a guild (paginated). @param guildId Guild identifier. @returns Members collection route. */\n guildMembers: (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/members`,\n\n // ─── Welcome Screen & Onboarding ──────────────────────────────────────────────\n /** Returns the welcome screen for a guild. @param guildId Guild identifier. */\n guildWelcomeScreen: (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/welcome-screen`,\n /** Returns the onboarding configuration for a guild. @param guildId Guild identifier. */\n guildOnboarding: (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/onboarding`,\n\n // ─── Guild Prune ──────────────────────────────────────────────────────────────\n /** Returns or executes a prune operation for inactive members. @param guildId Guild identifier. @returns Prune route. */\n guildPrune: (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/prune`,\n\n // ─── Stage Instances ──────────────────────────────────────────────────────────\n /** Returns the stage instances collection. @returns Stage instance root route. */\n stageInstances: () => \"/stage-instances\",\n /** Returns a stage instance by its channel. @param channelId Stage channel identifier. @returns Stage instance route. */\n stageInstanceByChannel: (channelId: string) =>\n `/stage-instances/${snowflake(channelId, \"Channel ID\")}`,\n\n // ─── Invites ──────────────────────────────────────────────────────────────────\n /** Returns an invite by code. @param code Invite code. @returns Invite route. */\n invite: (code: string) => `/invites/${encodeURIComponent(code)}`,\n /** Returns the guild vanity invite metadata. @param guildId Guild identifier. @returns Vanity URL route. */\n guildVanity: (guildId: string) =>\n `/guilds/${snowflake(guildId, \"Guild ID\")}/vanity-url`,\n\n // ─── Emojis ───────────────────────────────────────────────────────────────────\n /** Returns guild emojis, or a specific emoji. @param guildId Guild identifier. @param emojiId Optional emoji identifier. */\n guildEmoji: (guildId: string, emojiId?: string) =>\n emojiId\n ? `/guilds/${snowflake(guildId, \"Guild ID\")}/emojis/${snowflake(emojiId, \"Emoji ID\")}`\n : `/guilds/${snowflake(guildId, \"Guild ID\")}/emojis`,\n /** Returns application emojis, or a specific emoji. @param applicationId Application identifier. @param emojiId Optional emoji identifier. */\n applicationEmoji: (applicationId: string, emojiId?: string) =>\n emojiId\n ? `/applications/${snowflake(applicationId, \"Application ID\")}/emojis/${snowflake(emojiId, \"Emoji ID\")}`\n : `/applications/${snowflake(applicationId, \"Application ID\")}/emojis`,\n\n // ─── Polls ────────────────────────────────────────────────────────────────────\n /** Ends a poll early. @param channelId Channel identifier. @param messageId Poll message identifier. */\n pollExpire: (channelId: string, messageId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/polls/${snowflake(messageId, \"Message ID\")}/expire`,\n /** Returns the users who voted for a poll answer. @param answerId Answer identifier (an integer, not a snowflake). */\n pollAnswerVoters: (\n channelId: string,\n messageId: string,\n answerId: number,\n ) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/polls/${snowflake(messageId, \"Message ID\")}/answers/${integer(answerId, \"Answer ID\")}`,\n\n // ─── Stickers ─────────────────────────────────────────────────────────────────\n /** Returns guild stickers, or one sticker. */\n guildSticker: (guildId: string, stickerId?: string) =>\n stickerId\n ? `/guilds/${snowflake(guildId, \"Guild ID\")}/stickers/${snowflake(stickerId, \"Sticker ID\")}`\n : `/guilds/${snowflake(guildId, \"Guild ID\")}/stickers`,\n\n // ─── Soundboard ───────────────────────────────────────────────────────────────\n /** Plays a soundboard sound in a voice channel. */\n sendSoundboardSound: (channelId: string) =>\n `/channels/${snowflake(channelId, \"Channel ID\")}/send-soundboard-sound`,\n /** Returns Discord's default soundboard sounds. */\n soundboardDefaultSounds: () => \"/soundboard-default-sounds\",\n /** Returns guild soundboard sounds, or one sound. */\n guildSoundboardSound: (guildId: string, soundId?: string) =>\n soundId\n ? `/guilds/${snowflake(guildId, \"Guild ID\")}/soundboard-sounds/${snowflake(soundId, \"Sound ID\")}`\n : `/guilds/${snowflake(guildId, \"Guild ID\")}/soundboard-sounds`,\n\n // ─── Monetization ─────────────────────────────────────────────────────────────\n /** Returns an application's SKUs. */\n applicationSkus: (applicationId: string) =>\n `/applications/${snowflake(applicationId, \"Application ID\")}/skus`,\n /** Returns an application's entitlements, or one entitlement. */\n applicationEntitlement: (applicationId: string, entitlementId?: string) =>\n entitlementId\n ? `/applications/${snowflake(applicationId, \"Application ID\")}/entitlements/${snowflake(entitlementId, \"Entitlement ID\")}`\n : `/applications/${snowflake(applicationId, \"Application ID\")}/entitlements`,\n /** Marks a one-time-purchase entitlement as consumed. */\n consumeEntitlement: (applicationId: string, entitlementId: string) =>\n `/applications/${snowflake(applicationId, \"Application ID\")}/entitlements/${snowflake(entitlementId, \"Entitlement ID\")}/consume`,\n /** Returns a SKU's subscriptions, or one subscription. */\n skuSubscription: (skuId: string, subscriptionId?: string) =>\n subscriptionId\n ? `/skus/${snowflake(skuId, \"SKU ID\")}/subscriptions/${snowflake(subscriptionId, \"Subscription ID\")}`\n : `/skus/${snowflake(skuId, \"SKU ID\")}/subscriptions`,\n} as const;\n\n/** Validates a non-negative integer route parameter. */\nfunction integer(value: number, field: string): string {\n if (!Number.isInteger(value) || value < 0)\n throw new TypeError(`${field} must be a non-negative integer.`);\n return String(value);\n}\n\n/** Validates a Discord snowflake route parameter. Accepts any decimal id that fits an\n * unsigned 64-bit integer, matching the snowflake rule `BaseStructure` applies in\n * `@lunibee/structures`. The guarantee this provides is that no non-numeric segment can\n * reshape the request path; it deliberately does not police id length, because Discord\n * snowflakes are 17 digits for early 2015 ids and reach 20 digits as the epoch advances.\n * @param value Candidate identifier. @param field Human-readable field name. @returns The validated identifier. @throws {TypeError} If the identifier is not a Discord snowflake. */\nfunction snowflake(value: string, field: string): string {\n if (!/^\\d{1,20}$/.test(value))\n throw new TypeError(`${field} must be a valid Discord snowflake.`);\n return value;\n}\n",
|
|
20
|
-
"/** Library version and source URL used for the Discord-compliant User-Agent. */\nimport packageJson from \"../package.json\" with { type: \"json\" };\nconst LIBRARY_VERSION = packageJson.version;\nconst LIBRARY_URL = \"https://github.com/Ekretos/lunibee\";\nconst USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${LIBRARY_VERSION})`;\n\nimport { MemoryRateLimitStore, type RateLimitStore } from \"./store.js\";\nimport { RESTError, abortError, redactPath, sleep } from \"./errors.js\";\nimport {\n createRouteKey,\n serializeQuery,\n type RESTQuery,\n type RouteKey,\n} from \"./route.js\";\nimport { RequestScheduler } from \"./scheduler.js\";\nimport { RateLimiter } from \"./limiter.js\";\nimport { HttpTransport, TransportError } from \"./transport.js\";\nimport { ResponseDecoder } from \"./decoder.js\";\n\n/** A file attachment sent as part of a multipart REST request. */\nexport interface RESTFileAttachment {\n name: string;\n data: Blob | Uint8Array | ArrayBuffer;\n contentType?: string;\n}\n\n/**\n * Options controlling an individual REST request.\n *\n * Lunibee's canonical call shape is positional (`post(path, body)`); these options\n * add the Discord.js-`@discordjs/rest`-familiar per-request knobs (`query`, `headers`,\n * `reason`, `auth`) additively without changing that positional default.\n */\nexport interface RESTRequestOptions {\n /** Abort signal used to cancel the request and any queued wait. */ signal?: AbortSignal;\n /** Query-string appended to the path (`URLSearchParams`, a record, or a raw string). */ query?: RESTQuery;\n /** Extra request headers merged in (library headers such as `Authorization` win). */ headers?: Record<\n string,\n string\n >;\n /** Audit-log reason, sent as the `X-Audit-Log-Reason` header. */ reason?: string;\n /** Set `false` to omit the `Authorization` header for this request. Defaults to `true`. */ auth?: boolean;\n}\n\n/**\n * Discord.js-familiar request payload. Superset of {@link RESTRequestOptions} that also\n * carries the `body` and `files`, matching `@discordjs/rest`'s `RequestData`. It powers the\n * additive `method(path, { body })` overloads without breaking the positional signature.\n */\nexport interface RequestData extends RESTRequestOptions {\n /** Request body. Encoded as JSON unless `files` are present (then multipart). */ body?: unknown;\n /** File attachments; presence upgrades the request to `multipart/form-data`. */ files?: RESTFileAttachment[];\n}\n\n/** Keys recognised on a {@link RequestData} wrapper, used to disambiguate it from a raw body. */\nconst REQUEST_DATA_KEYS = new Set([\n \"body\",\n \"files\",\n \"query\",\n \"headers\",\n \"reason\",\n \"auth\",\n \"signal\",\n]);\n\n/**\n * Detects a Discord.js-style `RequestData` wrapper so verb helpers can accept both\n * `post(path, rawBody)` (Lunibee-canonical) and `post(path, { body })` (Discord.js-familiar).\n * Conservative by design: only a plain object whose every own key is a known `RequestData`\n * key counts — a raw Discord payload (which always carries entity keys like `content`/`name`)\n * never matches, so existing positional callers are unaffected.\n */\nfunction isRequestData(value: unknown): value is RequestData {\n if (value === null || typeof value !== \"object\") return false;\n if (Array.isArray(value)) return false;\n if (typeof FormData !== \"undefined\" && value instanceof FormData)\n return false;\n if (\n value instanceof Blob ||\n value instanceof Uint8Array ||\n value instanceof ArrayBuffer\n )\n return false;\n const keys = Object.keys(value);\n if (keys.length === 0) return false;\n return keys.every((key) => REQUEST_DATA_KEYS.has(key));\n}\n\n// ─── REST Hooks ───────────────────────────────────────────────────────────────\n\n/** Context passed to `RESTHooks.onRequest`. */\nexport interface RESTRequestContext {\n method: string;\n path: string;\n attempt: number;\n}\n/** Context passed to `RESTHooks.onResponse`. */\nexport interface RESTResponseContext {\n method: string;\n path: string;\n status: number;\n durationMs: number;\n}\n/** Context passed to `RESTHooks.onRateLimit`. */\nexport interface RESTRateLimitContext {\n method: string;\n path: string;\n retryAfterMs: number;\n global: boolean;\n bucket?: string;\n}\n/** Context passed to `RESTHooks.onRetry`. */\nexport interface RESTRetryContext {\n method: string;\n path: string;\n attempt: number;\n status: number;\n delayMs: number;\n}\n\n/**\n * Lightweight callback hooks for REST request lifecycle events.\n *\n * All callbacks are optional. They are dispatched in isolation from the request\n * path (deferred to a microtask, and any thrown error is swallowed), so a hook\n * cannot break or reject a request. Even so, hooks **must** be fast and\n * non-blocking: heavy synchronous work in a hook still steals event-loop time\n * from in-flight requests. Offload anything expensive to your own queue.\n */\nexport interface RESTHooks {\n /** Called just before every HTTP attempt. */\n onRequest?(ctx: RESTRequestContext): void;\n /** Called after a successful or failed response is received. */\n onResponse?(ctx: RESTResponseContext): void;\n /** Called when a rate limit is encountered and the client is about to wait. */\n onRateLimit?(ctx: RESTRateLimitContext): void;\n /** Called when a failed request is about to be retried. */\n onRetry?(ctx: RESTRetryContext): void;\n}\n\n/** Configures which REST failures may be retried. */\nexport interface RetryPolicy {\n /** Maximum retry attempts. */ maxRetries: number;\n /** Determines whether a request may be retried. @param method HTTP method. @param status HTTP status, or zero for transport errors. @returns True when retrying is safe under the policy. */ shouldRetry(\n method: string,\n status: number,\n ): boolean;\n /** Calculates delay before the next attempt. @param attempt Zero-based retry number. @param retryAfter Server-provided delay, when available. @returns Delay in milliseconds. */ getDelay(\n attempt: number,\n retryAfter?: number,\n ): number;\n}\n/** Creates the default conservative REST retry policy. @param maxRetries Maximum retries. @returns Retry policy that retries rate limits and idempotent transient failures. @throws {TypeError} If maxRetries is negative or not finite. */\nexport function createRetryPolicy(maxRetries = 2): RetryPolicy {\n if (!Number.isFinite(maxRetries) || maxRetries < 0)\n throw new TypeError(\"maxRetries must be a non-negative finite number.\");\n return {\n maxRetries: Math.floor(maxRetries),\n shouldRetry(method, status) {\n const normalized = method.toUpperCase();\n const idempotent = [\"GET\", \"HEAD\", \"PUT\", \"DELETE\"].includes(\n normalized,\n );\n // Status 0 is a transport failure (DNS, reset connection, TLS):\n // no response reached Discord's handlers, so replaying an\n // idempotent request is as safe as replaying it after a 5xx.\n if (status === 0) return idempotent;\n return (\n status === 429 || (status >= 500 && status <= 599 && idempotent)\n );\n },\n getDelay(attempt, retryAfter) {\n if (retryAfter !== undefined) return Math.max(0, retryAfter * 1000);\n return Math.min(10_000, 500 * 2 ** attempt) + Math.random() * 250;\n },\n };\n}\n\n/** Bun-native REST transport with Discord bucket-aware rate limiting, retries, and cancellation. */\nexport class REST {\n readonly #retryPolicy: RetryPolicy;\n #token?: string;\n /** Rate-limit state: when a request may go out, what a response says. */\n readonly #limiter: RateLimiter;\n /** Per-bucket ordering. */\n readonly #scheduler = new RequestScheduler();\n /** One HTTP attempt, with timeout and cancellation. */\n readonly #transport: HttpTransport;\n /** Response payload and error metadata. */\n readonly #decoder = new ResponseDecoder();\n #hooks: RESTHooks = {};\n /** Whether requests on a known bucket may run concurrently. */\n readonly #concurrentBuckets: boolean;\n /** Creates a REST transport. @param options Transport configuration. @throws {TypeError} If retry configuration is invalid. */\n public constructor(\n options: {\n token?: string;\n timeout?: number;\n retries?: number;\n retryPolicy?: RetryPolicy;\n baseURL?: string;\n hooks?: RESTHooks;\n store?: RateLimitStore;\n /** Replaces the HTTP stage, e.g. with a recording transport in tests. */\n transport?: HttpTransport;\n /**\n * Lets requests on a bucket whose limit is known run concurrently, up\n * to its `remaining` allowance, instead of one at a time. Requires a\n * store with `reserve`. Requests on one bucket may then complete out\n * of order (e.g. messages to one channel). Defaults to `false`.\n */\n concurrentBuckets?: boolean;\n } = {},\n ) {\n this.#token = options.token;\n this.#retryPolicy =\n options.retryPolicy ?? createRetryPolicy(options.retries ?? 2);\n this.#transport =\n options.transport ??\n new HttpTransport({\n baseURL: options.baseURL,\n timeout: options.timeout,\n });\n const store = options.store ?? new MemoryRateLimitStore();\n this.#concurrentBuckets =\n (options.concurrentBuckets ?? false) &&\n typeof store.reserve === \"function\";\n this.#limiter = new RateLimiter(store, {\n concurrent: this.#concurrentBuckets,\n });\n if (options.hooks) this.#hooks = options.hooks;\n }\n /** The rate-limit store backing this transport. */\n public get store(): RateLimitStore {\n return this.#limiter.store;\n }\n /** Replaces the current hook set. Pass an empty object to clear all hooks. */\n public setHooks(hooks: RESTHooks): this {\n this.#hooks = hooks;\n return this;\n }\n /** Sets the authentication token. @param token Discord bot token. @returns Nothing. @throws {TypeError} If token is empty. */\n public setToken(token: string): void {\n if (!token.trim())\n throw new TypeError(\"A Discord bot token is required.\");\n this.#token = token;\n }\n /** Executes an HTTP request with Discord bucket/global rate limits, retry handling, and AbortSignal support.\n * Accepts a JSON body, a FormData body (for file uploads), or undefined.\n * @param method HTTP method.\n * @param path API path.\n * @param body Optional JSON body, FormData for file uploads, or undefined.\n * @param options Request options: cancellation `signal` plus the Discord.js-familiar\n * `query`, `headers`, `reason`, `auth`, and `files` (which upgrade to multipart).\n * @returns Decoded response body.\n * @throws {RESTError} If Discord or transport rejects the request.\n */\n public async request<T>(\n method: string,\n path: string,\n body?: unknown,\n options: RequestData = {},\n ): Promise<T> {\n if (!method.toUpperCase())\n throw new TypeError(\"REST method is required.\");\n if (!path.startsWith(\"/\"))\n throw new TypeError(\"REST paths must start with '/'.\");\n const route = createRouteKey(method, path);\n // Upgrade to multipart when file attachments are supplied via options.\n const files = options.files;\n if (files && files.length > 0 && !(body instanceof FormData))\n body = this.#fileForm(body, files);\n const query = serializeQuery(options.query);\n const requestPath = query ? `${path}${query}` : path;\n\n // Discord scopes a rate limit by (bucket hash, major parameter): two\n // channels sharing an endpoint have independent limits, while two\n // different routes can share one hash. The key is therefore resolved\n // again once the slot is acquired, so a request that queued under its\n // route-derived key joins the shared bucket's queue if one was\n // discovered while it waited.\n return this.#scheduler.runResolved(\n () => this.#limiter.resolveBucketKey(route.route, route.major),\n options.signal,\n path,\n (bucketKey, release) =>\n this.#attempts<T>(\n route,\n requestPath,\n body,\n options,\n bucketKey,\n release,\n ),\n );\n }\n /**\n * Runs the retry loop for one scheduled request: acquire limits, send,\n * record what the response says, decode, and decide whether to try again.\n */\n async #attempts<T>(\n route: RouteKey,\n requestPath: string,\n body: unknown,\n options: RequestData,\n initialBucketKey: string,\n release: () => void,\n ): Promise<T> {\n const { method, path } = route;\n let bucketKey = initialBucketKey;\n for (\n let attempt = 0;\n attempt <= this.#retryPolicy.maxRetries;\n attempt++\n ) {\n await this.#limiter.acquire(bucketKey, options.signal, path);\n // The reservation already claimed this request's unit, so once the\n // bucket's window is known the next request need not wait for our\n // response. An unknown bucket stays serial until a response\n // reveals its limit.\n if (this.#concurrentBuckets) {\n const bucket = await this.#limiter.store.getBucket(bucketKey);\n if (bucket && bucket.resetAt > Date.now()) release();\n }\n this.#emit(this.#hooks.onRequest, { method, path, attempt });\n const requestStart = Date.now();\n let response: Response;\n try {\n response = await this.#transport.send({\n method,\n path: requestPath,\n headers: this.#headers(body, options),\n body: this.#encodeBody(body),\n signal: options.signal,\n });\n } catch (error) {\n if (error instanceof RESTError) throw error;\n if (options.signal?.aborted)\n throw abortError(path, options.signal.reason);\n const failure =\n error instanceof TransportError\n ? error\n : new TransportError(\n \"Discord REST request failed\",\n false,\n error,\n );\n if (\n !failure.timedOut &&\n attempt < this.#retryPolicy.maxRetries &&\n this.#retryPolicy.shouldRetry(method, 0)\n ) {\n await sleep(\n this.#retryPolicy.getDelay(attempt),\n options.signal,\n path,\n );\n continue;\n }\n throw new RESTError(failure.message, 0, undefined, undefined, {\n method,\n path,\n cause: failure.cause ?? failure,\n kind: failure.timedOut ? \"timeout\" : \"network\",\n });\n }\n this.#emit(this.#hooks.onResponse, {\n method,\n path,\n status: response.status,\n durationMs: Date.now() - requestStart,\n });\n bucketKey = await this.#limiter.applyResponse(\n response,\n bucketKey,\n route.route,\n route.major,\n );\n const payload = await this.#decoder.read(response);\n if (response.ok)\n return (response.status === 204 ? undefined : payload) as T;\n\n const data = this.#decoder.errorData(payload);\n const retryAfter =\n response.status === 429\n ? this.#decoder.retryAfter(response, data)\n : undefined;\n if (data.global && retryAfter !== undefined)\n await this.#limiter.noteGlobalReset(\n Date.now() + retryAfter * 1000,\n );\n // Fire for ANY 429, including a global limit that arrives without a\n // Retry-After header; fall back to 1s in that case.\n if (response.status === 429)\n this.#emit(this.#hooks.onRateLimit, {\n method,\n path,\n retryAfterMs: (retryAfter ?? 1) * 1000,\n global: data.global ?? false,\n bucket: await this.#limiter.store.getBucketHash(\n route.route,\n ),\n });\n if (\n attempt < this.#retryPolicy.maxRetries &&\n this.#retryPolicy.shouldRetry(method, response.status)\n ) {\n const delay = this.#retryPolicy.getDelay(attempt, retryAfter);\n this.#emit(this.#hooks.onRetry, {\n method,\n path,\n attempt,\n status: response.status,\n delayMs: delay,\n });\n await sleep(delay, options.signal, path);\n continue;\n }\n throw new RESTError(\n data.message ??\n response.statusText ??\n `Discord REST request failed with status ${response.status}`,\n response.status,\n data.code,\n payload,\n { method, path },\n );\n }\n throw new RESTError(\n \"Discord REST request exhausted its retry attempts\",\n 0,\n undefined,\n undefined,\n { method, path },\n );\n }\n /** Builds the header set for one attempt; library headers win over caller headers. */\n #headers(body: unknown, options: RequestData): Record<string, string> {\n const isFormData =\n typeof FormData !== \"undefined\" && body instanceof FormData;\n const headers: Record<string, string> = { ...options.headers };\n if (options.auth !== false && this.#token)\n headers[\"Authorization\"] = `Bot ${this.#token}`;\n headers[\"User-Agent\"] = USER_AGENT;\n if (options.reason !== undefined)\n headers[\"X-Audit-Log-Reason\"] = encodeURIComponent(options.reason);\n if (!isFormData) headers[\"Content-Type\"] = \"application/json\";\n return headers;\n }\n /** Encodes a body as multipart (passed through) or JSON. */\n #encodeBody(body: unknown): BodyInit | undefined {\n if (typeof FormData !== \"undefined\" && body instanceof FormData)\n return body;\n return body === undefined ? undefined : JSON.stringify(body);\n }\n /**\n * Normalizes a verb helper's second argument into `(body, options)`.\n * Supports both `verb(path, rawBody, options?)` (Lunibee-canonical positional) and the\n * Discord.js-familiar `verb(path, { body, query, headers, reason, files })` wrapper.\n */\n #dispatch<T>(\n method: string,\n path: string,\n bodyOrOptions?: unknown,\n options?: RequestData,\n ): Promise<T> {\n if (options === undefined && isRequestData(bodyOrOptions))\n return this.request<T>(\n method,\n path,\n bodyOrOptions.body,\n bodyOrOptions,\n );\n return this.request<T>(method, path, bodyOrOptions, options);\n }\n /** Sends a GET request. @param path API path. @param options Request options (`query`, `headers`, `signal`, …). @returns Decoded response. @throws {RESTError} When the request fails. */ public get<\n T,\n >(path: string, options?: RequestData): Promise<T> {\n return this.request<T>(\"GET\", path, options?.body, options);\n }\n /** Sends a POST request. Accepts a raw body (`post(path, body)`) or a Discord.js-familiar `post(path, { body })`. @param path API path. @param body Optional JSON body, or a `RequestData` wrapper. @param options Request options. @returns Decoded response. @throws {RESTError} When the request fails. */\n public post<T>(path: string, options: RequestData): Promise<T>;\n public post<T>(\n path: string,\n body?: unknown,\n options?: RequestData,\n ): Promise<T>;\n public post<T>(\n path: string,\n body?: unknown,\n options?: RequestData,\n ): Promise<T> {\n return this.#dispatch<T>(\"POST\", path, body, options);\n }\n /** Sends a PATCH request. Accepts a raw body (`patch(path, body)`) or a Discord.js-familiar `patch(path, { body })`. @param path API path. @param body Optional JSON body, or a `RequestData` wrapper. @param options Request options. @returns Decoded response. @throws {RESTError} When the request fails. */\n public patch<T>(path: string, options: RequestData): Promise<T>;\n public patch<T>(\n path: string,\n body?: unknown,\n options?: RequestData,\n ): Promise<T>;\n public patch<T>(\n path: string,\n body?: unknown,\n options?: RequestData,\n ): Promise<T> {\n return this.#dispatch<T>(\"PATCH\", path, body, options);\n }\n /** Sends a PUT request. Accepts a raw body (`put(path, body)`) or a Discord.js-familiar `put(path, { body })`. @param path API path. @param body Optional JSON body, or a `RequestData` wrapper. @param options Request options. @returns Decoded response. @throws {RESTError} When the request fails. */\n public put<T>(path: string, options: RequestData): Promise<T>;\n public put<T>(\n path: string,\n body?: unknown,\n options?: RequestData,\n ): Promise<T>;\n public put<T>(\n path: string,\n body?: unknown,\n options?: RequestData,\n ): Promise<T> {\n return this.#dispatch<T>(\"PUT\", path, body, options);\n }\n /** Sends a DELETE request. @param path API path. @param options Request options (`reason`, `headers`, `signal`, …). @returns Decoded response. @throws {RESTError} When the request fails. */ public delete<\n T,\n >(path: string, options?: RequestData): Promise<T> {\n return this.request<T>(\"DELETE\", path, options?.body, options);\n }\n /**\n * Builds a multipart form with a JSON payload and file attachments.\n */\n #fileForm(payload: unknown, files: RESTFileAttachment[]): FormData {\n const form = new FormData();\n form.append(\"payload_json\", JSON.stringify(payload));\n for (let i = 0; i < files.length; i++) {\n const file = files[i]!;\n const blob =\n file.data instanceof Blob\n ? file.data\n : new Blob([file.data as ArrayBuffer], {\n type: file.contentType ?? \"application/octet-stream\",\n });\n form.append(`files[${i}]`, blob, file.name);\n }\n return form;\n }\n\n /**\n * Sends a multipart/form-data POST request for file uploads.\n * Attaches a JSON payload as `payload_json` and files as additional fields.\n * @param path API path.\n * @param payload JSON payload (e.g. message content, embeds).\n * @param files Array of file attachments.\n * @param options Cancellation options.\n * @returns Decoded response.\n * @throws {RESTError} When the request fails.\n */\n public postWithFiles<T>(\n path: string,\n payload: unknown,\n files: RESTFileAttachment[],\n options?: RESTRequestOptions,\n ): Promise<T> {\n return this.request<T>(\n \"POST\",\n path,\n this.#fileForm(payload, files),\n options,\n );\n }\n\n /**\n * Sends a multipart/form-data PATCH request for editing messages with files.\n * @param path API path.\n * @param payload JSON payload.\n * @param files Array of file attachments.\n * @param options Cancellation options.\n * @returns Decoded response.\n * @throws {RESTError} When the request fails.\n */\n public patchWithFiles<T>(\n path: string,\n payload: unknown,\n files: RESTFileAttachment[],\n options?: RESTRequestOptions,\n ): Promise<T> {\n return this.request<T>(\n \"PATCH\",\n path,\n this.#fileForm(payload, files),\n options,\n );\n }\n /** Dispatches a lifecycle hook in isolation: deferred to a microtask so it\n * cannot block the request path, with any thrown error swallowed so a faulty\n * hook cannot reject the request. @param hook Optional callback. @param ctx Event context. */\n #emit<C>(hook: ((ctx: C) => void) | undefined, ctx: C): void {\n if (!hook) return;\n const withPath = ctx as { path?: unknown };\n if (typeof withPath.path === \"string\")\n ctx = { ...ctx, path: redactPath(withPath.path) };\n Promise.resolve()\n .then(() => hook(ctx))\n .catch(() => {});\n }\n}\n\nexport { Routes } from \"./routes.js\";\nexport {\n RESTError,\n abortError,\n redactPath,\n type RESTErrorKind,\n} from \"./errors.js\";\nexport { RESTErrorCode } from \"./error-codes.js\";\nexport {\n createRouteKey,\n normalizeRoutePath,\n majorParameter,\n scopeBucket,\n serializeQuery,\n type RouteKey,\n type RESTQuery,\n} from \"./route.js\";\nexport { RequestScheduler } from \"./scheduler.js\";\nexport { RateLimiter } from \"./limiter.js\";\nexport {\n HttpTransport,\n TransportError,\n type TransportRequest,\n type FetchLike,\n} from \"./transport.js\";\nexport { ResponseDecoder, type DecodedError } from \"./decoder.js\";\nexport {\n type RateLimitStore,\n type BucketState,\n type Reservation,\n MemoryRateLimitStore,\n} from \"./store.js\";\nexport {\n RedisRateLimitStore,\n type RedisRateLimitStoreOptions,\n type MinimalRedisClient,\n} from \"./redis.js\";\n\nexport {\n WebhookClient,\n type WebhookClientOptions,\n type WebhookMessageOptions,\n} from \"./webhook.js\";\n\n/**\n * Discord.js-familiar alias for {@link RESTError}. `@discordjs/rest` throws `DiscordAPIError`\n * on a Discord-rejected request; Lunibee keeps `RESTError` as the canonical class and exports\n * this alias so Discord.js-shaped `catch (err) { if (err instanceof DiscordAPIError) … }` works.\n */\nexport { RESTError as DiscordAPIError };\n",
|
|
21
|
-
"/** Common Discord snowflake-backed structure. */\nexport class BaseStructure {\n public readonly id: string;\n public constructor(id: string) {\n if (!/^\\d{1,20}$/.test(id))\n throw new TypeError(\n \"A Discord structure requires a valid snowflake ID.\",\n );\n this.id = id;\n }\n /** Returns the snowflake ID as a string. */\n public toString(): string {\n return this.id;\n }\n /** Returns the timestamp this snowflake was created at. */\n public get createdAt(): Date {\n return new Date(Number((BigInt(this.id) >> 22n) + 1420070400000n));\n }\n}\n\nexport interface ResourceContext {\n sendMessage(\n channelId: string,\n options: Record<string, unknown> & { content?: string },\n ): Promise<import(\"./index.js\").Message>;\n editMessage(\n channelId: string,\n messageId: string,\n options: Record<string, unknown> & { content?: string },\n ): Promise<import(\"./index.js\").Message>;\n deleteMessage(\n channelId: string,\n messageId: string,\n reason?: string,\n ): Promise<void>;\n crosspostMessage(\n channelId: string,\n messageId: string,\n ): Promise<import(\"./index.js\").Message>;\n editChannel?(\n channelId: string,\n options: Record<string, unknown>,\n ): Promise<import(\"./base.js\").Channel>;\n deleteChannel?(channelId: string, reason?: string): Promise<void>;\n addReaction?(\n channelId: string,\n messageId: string,\n emoji: string,\n ): Promise<void>;\n removeOwnReaction?(\n channelId: string,\n messageId: string,\n emoji: string,\n ): Promise<void>;\n removeReaction?(\n channelId: string,\n messageId: string,\n emoji: string,\n userId: string,\n ): Promise<void>;\n removeAllReactions?(channelId: string, messageId: string): Promise<void>;\n pinMessage?(\n channelId: string,\n messageId: string,\n reason?: string,\n ): Promise<void>;\n unpinMessage?(\n channelId: string,\n messageId: string,\n reason?: string,\n ): Promise<void>;\n /**\n * A member's permissions from cached state: guild-level, or channel-level\n * (with overwrites) when a channel ID is given. Null when the guild (or\n * channel) is not cached.\n */\n memberPermissions?(\n guildId: string,\n memberId: string,\n roleIds: readonly string[],\n channelId?: string,\n ): import(\"@lunibee/core\").PermissionSet | null;\n kickMember?(\n guildId: string,\n userId: string,\n reason?: string,\n ): Promise<void>;\n banMember?(\n guildId: string,\n userId: string,\n options?: { reason?: string; deleteMessageSeconds?: number },\n ): Promise<void>;\n editMember?(\n guildId: string,\n userId: string,\n options: Record<string, unknown>,\n reason?: string,\n ): Promise<import(\"./resources.js\").GuildMember>;\n addMemberRole?(\n guildId: string,\n userId: string,\n roleId: string,\n reason?: string,\n ): Promise<void>;\n removeMemberRole?(\n guildId: string,\n userId: string,\n roleId: string,\n reason?: string,\n ): Promise<void>;\n /** Collects the client's interactions (a `Collector` over `interactionCreate`). Used by message and interaction collectors. */\n collectInteractions?(\n options: import(\"@lunibee/core\").CollectorOptions<\n import(\"./interactions.js\").Interaction\n >,\n ): import(\"@lunibee/core\").Collector<\n string,\n import(\"./interactions.js\").Interaction\n >;\n editPermissionOverwrite?(\n channelId: string,\n targetId: string,\n changes: PermissionOverwriteChanges,\n options?: { type?: 0 | 1; reason?: string },\n ): Promise<void>;\n}\n\n/**\n * Permissions to change on one overwrite: `true` allows, `false` denies,\n * `null` goes back to inheriting. Permissions not named keep their state.\n */\nexport type PermissionOverwriteChanges = Partial<\n Record<import(\"@lunibee/core\").PermissionName, boolean | null>\n>;\n\n// ─── CDN helpers ──────────────────────────────────────────────────────────────\n\nexport const CDN_BASE = \"https://cdn.discordapp.com\";\n\n/** Options for CDN image URLs. */\nexport interface ImageURLOptions {\n extension?: \"png\" | \"jpg\" | \"webp\" | \"gif\" | \"jpeg\";\n size?: 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096;\n forceStatic?: boolean;\n}\n\n/** Builds a Discord CDN asset URL from a directory path and asset hash, applying\n * animated-hash (`a_`) gif detection, extension and size options. Shared by all\n * hash-backed asset accessors (user/member/role/webhook) to avoid duplicating the logic.\n * @param path CDN directory path, e.g. `/role-icons/{id}`. @param hash Asset hash. @param options Image URL options. */\nexport function cdnURL(\n path: string,\n hash: string,\n options: ImageURLOptions = {},\n): string {\n const isAnimated = hash.startsWith(\"a_\") && !options.forceStatic;\n const ext = options.extension ?? (isAnimated ? \"gif\" : \"png\");\n const size = options.size ? `?size=${options.size}` : \"\";\n return `${CDN_BASE}${path}/${hash}.${ext}${size}`;\n}\n\n// ─── User ─────────────────────────────────────────────────────────────────────\n\nexport class User extends BaseStructure {\n public username: string;\n public globalName: string | null;\n public avatar: string | null;\n public bot: boolean;\n public system: boolean;\n public flags: number;\n public discriminator: string | null;\n public constructor(data: import(\"@lunibee/types\").UserData) {\n super(data.id);\n if (!data.username)\n throw new TypeError(\"A Discord user requires a username.\");\n this.username = data.username;\n this.globalName = data.global_name ?? null;\n this.avatar = data.avatar ?? null;\n this.bot = data.bot ?? false;\n this.system = data.system ?? false;\n this.flags = data.public_flags ?? 0;\n this.discriminator =\n data.discriminator && data.discriminator !== \"0\"\n ? data.discriminator\n : null;\n }\n /** Effective display name — global name, falling back to username. */\n public get displayName(): string {\n return this.globalName ?? this.username;\n }\n /** Returns the user's avatar URL, or null if they have no avatar. */\n public avatarURL(options: ImageURLOptions = {}): string | null {\n if (!this.avatar) return null;\n return cdnURL(`/avatars/${this.id}`, this.avatar, options);\n }\n /** Returns the default avatar URL based on the user's discriminator/snowflake. */\n public defaultAvatarURL(): string {\n const index = this.discriminator\n ? Number(this.discriminator) % 5\n : Number((BigInt(this.id) >> 22n) % 6n);\n return `${CDN_BASE}/embed/avatars/${index}.png`;\n }\n /** Returns the avatar URL if available, falling back to the default avatar URL. */\n public displayAvatarURL(options: ImageURLOptions = {}): string {\n return this.avatarURL(options) ?? this.defaultAvatarURL();\n }\n /** Returns the Discord mention string. Used automatically in template literals. */\n public override toString(): string {\n return `<@${this.id}>`;\n }\n}\n\n// ─── Channel ──────────────────────────────────────────────────────────────────\n\nexport class Channel extends BaseStructure {\n public type: number;\n public name?: string | null;\n public guildId?: string;\n public topic?: string | null;\n public parentId?: string | null;\n public nsfw?: boolean;\n public rateLimitPerUser?: number;\n public position?: number;\n /** Role and member permission overwrites (empty for DMs and when not provided). */\n public permissionOverwrites: import(\"@lunibee/types\").APIOverwrite[];\n readonly #context?: ResourceContext;\n\n /** Creates a channel structure from Discord channel data. */\n public constructor(\n data: import(\"@lunibee/types\").APIChannel,\n context?: ResourceContext,\n ) {\n super(data.id);\n if (!Number.isInteger(data.type) || data.type < 0)\n throw new RangeError(\n \"A Discord channel requires a valid channel type.\",\n );\n this.type = data.type;\n this.name = data.name;\n this.guildId = data.guild_id;\n this.topic = data.topic;\n this.parentId = data.parent_id;\n this.nsfw = data.nsfw;\n this.rateLimitPerUser = data.rate_limit_per_user;\n this.position = data.position;\n this.permissionOverwrites = (data.permission_overwrites ?? []).map(\n (overwrite) => ({ ...overwrite }),\n );\n this.#context = context;\n }\n\n /** Sends a message to this channel. @param options Message payload. @returns The created message. @throws {Error} If the channel is not attached to a client. */\n public send(\n options: Record<string, unknown> & { content?: string },\n ): Promise<import(\"./index.js\").Message> {\n if (!this.#context)\n throw new Error(\"This channel is not attached to a client.\");\n return this.#context.sendMessage(this.id, options);\n }\n\n /** @deprecated Use {@link Channel.send}. Removed in 0.3.0. */\n public sendMessage(\n options: Record<string, unknown> & { content?: string },\n ): Promise<import(\"./index.js\").Message> {\n return this.send(options);\n }\n\n /** Edits this channel. @param options Channel fields to change. @returns The updated channel. @throws {Error} If the channel is not attached to a client. */\n public edit(options: Record<string, unknown>): Promise<Channel> {\n if (!this.#context?.editChannel)\n throw new Error(\"This channel is not attached to a client.\");\n return this.#context.editChannel(this.id, options);\n }\n\n /** Changes only this channel's name. @param name New channel name. @returns The updated channel. @throws {TypeError} If the name is empty. @throws {Error} If the channel is not attached to a client. */\n public editName(name: string): Promise<Channel> {\n if (!name.trim()) throw new TypeError(\"Channel name cannot be empty.\");\n return this.edit({ name });\n }\n\n /** Changes only this channel's topic. @param topic New topic, or null to clear it. @returns The updated channel. @throws {Error} If the channel is not attached to a client. */\n public editTopic(topic: string | null): Promise<Channel> {\n return this.edit({ topic });\n }\n\n /** Moves this channel to another parent category. @param parentId Parent category ID, or null to remove the parent. @returns The updated channel. @throws {Error} If the channel is not attached to a client. */\n /**\n * Changes some permissions of one overwrite and keeps the rest: `true`\n * allows, `false` denies, `null` resets to inherited.\n * @param targetId Role or member ID. @param changes Permissions to change.\n * @param options `type` (0 role, 1 member) when the overwrite does not exist yet; audit-log `reason`.\n * @example channel.editPermissionOverwrite(userId, { ViewChannel: true, SendMessages: false }, { type: 1 })\n */\n public editPermissionOverwrite(\n targetId: string,\n changes: PermissionOverwriteChanges,\n options?: { type?: 0 | 1; reason?: string },\n ): Promise<void> {\n if (!this.#context?.editPermissionOverwrite)\n throw new Error(\"This channel is not attached to a client.\");\n return this.#context.editPermissionOverwrite(\n this.id,\n targetId,\n changes,\n options,\n );\n }\n\n public editParent(parentId: string | null): Promise<Channel> {\n return this.edit({ parent_id: parentId });\n }\n\n /** Deletes this channel. @param reason Audit-log reason. @returns A promise fulfilled when Discord confirms deletion. @throws {Error} If the channel is not attached to a client. */\n public delete(reason?: string): Promise<void> {\n if (!this.#context?.deleteChannel)\n throw new Error(\"This channel is not attached to a client.\");\n return this.#context.deleteChannel(this.id, reason);\n }\n\n /** Updates this channel using the same resource operation as edit. @param options Channel fields to change. @returns The updated channel. @throws {Error} If the channel is not attached to a client. */\n public update(options: Record<string, unknown>): Promise<Channel> {\n return this.edit(options);\n }\n\n /** Whether this is a thread (announcement, public or private). */\n public isThread(): boolean {\n return this.type === 10 || this.type === 11 || this.type === 12;\n }\n\n /** Whether messages can be sent in this channel (text, DM, announcement, voice, stage, threads). */\n public isTextBased(): boolean {\n return [0, 1, 2, 3, 5, 10, 11, 12, 13].includes(this.type);\n }\n\n /** Whether this is a voice or stage channel. */\n public isVoiceBased(): boolean {\n return this.type === 2 || this.type === 13;\n }\n\n /** Whether this is a direct-message channel (DM or group DM). */\n public isDMBased(): boolean {\n return this.type === 1 || this.type === 3;\n }\n\n /** Returns the Discord channel mention string. Used automatically in template literals. */\n public override toString(): string {\n return `<#${this.id}>`;\n }\n}\n\n// ─── Guild ────────────────────────────────────────────────────────────────────\n\nexport class Guild extends BaseStructure {\n public name: string;\n public icon: string | null;\n public splash: string | null;\n public banner: string | null;\n public description: string | null;\n public preferredLocale: string;\n public ownerId?: string;\n public features: string[];\n public verificationLevel: number;\n public premiumTier: number;\n public premiumSubscriptionCount: number;\n public memberCount?: number;\n public approximateMemberCount?: number;\n public approximatePresenceCount?: number;\n public vanityUrlCode: string | null;\n public nsfwLevel: number;\n public discoverySplash: string | null;\n /** ID of the rules channel for Community guilds. */\n public rulesChannelId: string | null;\n /** ID of the system messages channel. */\n public systemChannelId: string | null;\n /** Bitfield of system channel flags. */\n public systemChannelFlags: number;\n /** Maximum number of members the guild can have. */\n public maxMembers: number;\n /** Required MFA level for administrators. */\n public mfaLevel: number;\n /** Explicit content filter level. */\n public explicitContentFilter: number;\n /** Default notification level for new members. */\n public defaultMessageNotifications: number;\n /** AFK voice channel, or null. */ public afkChannelId: string | null;\n /** Seconds before a silent member is moved to the AFK channel. */ public afkTimeout?: number;\n /** Whether the server widget is on. */ public widgetEnabled: boolean;\n /** Channel the widget invites to, or null. */ public widgetChannelId:\n string | null;\n /** Application that created the guild, if a bot did. */ public applicationId:\n string | null;\n /** Channel for Discord's community updates, or null. */ public publicUpdatesChannelId:\n string | null;\n /** Channel for safety alerts, or null. */ public safetyAlertsChannelId:\n string | null;\n /** Maximum presences (null for the default limit). */ public maxPresences:\n number | null;\n /** Maximum users in a video channel. */ public maxVideoChannelUsers?: number;\n\n public constructor(data: import(\"@lunibee/types\").APIGuild) {\n super(data.id);\n if (!data.name) throw new TypeError(\"A Discord guild requires a name.\");\n this.name = data.name;\n this.icon = data.icon ?? null;\n this.splash = data.splash ?? null;\n this.banner = data.banner ?? null;\n this.description = data.description ?? null;\n this.preferredLocale = data.preferred_locale ?? \"en-US\";\n this.ownerId = data.owner_id;\n this.features = data.features ?? [];\n this.verificationLevel = data.verification_level ?? 0;\n this.premiumTier = data.premium_tier ?? 0;\n this.premiumSubscriptionCount = data.premium_subscription_count ?? 0;\n this.memberCount = data.member_count ?? data.approximate_member_count;\n this.approximateMemberCount = data.approximate_member_count;\n this.approximatePresenceCount = data.approximate_presence_count;\n this.vanityUrlCode = data.vanity_url_code ?? null;\n this.nsfwLevel = data.nsfw_level ?? 0;\n this.discoverySplash = data.discovery_splash ?? null;\n this.rulesChannelId = data.rules_channel_id ?? null;\n this.systemChannelId = data.system_channel_id ?? null;\n this.systemChannelFlags = data.system_channel_flags ?? 0;\n this.maxMembers = data.max_members ?? 0;\n this.mfaLevel = data.mfa_level ?? 0;\n this.explicitContentFilter = data.explicit_content_filter ?? 0;\n this.defaultMessageNotifications =\n data.default_message_notifications ?? 0;\n this.afkChannelId = data.afk_channel_id ?? null;\n this.afkTimeout = data.afk_timeout;\n this.widgetEnabled = data.widget_enabled ?? false;\n this.widgetChannelId = data.widget_channel_id ?? null;\n this.applicationId = data.application_id ?? null;\n this.publicUpdatesChannelId = data.public_updates_channel_id ?? null;\n this.safetyAlertsChannelId = data.safety_alerts_channel_id ?? null;\n this.maxPresences = data.max_presences ?? null;\n this.maxVideoChannelUsers = data.max_video_channel_users;\n }\n\n /** Returns the guild icon URL, or null if no icon is set. */\n public iconURL(options: ImageURLOptions = {}): string | null {\n if (!this.icon) return null;\n return cdnURL(`/icons/${this.id}`, this.icon, options);\n }\n\n /** Returns the guild splash URL, or null if none. */\n public splashURL(options: ImageURLOptions = {}): string | null {\n if (!this.splash) return null;\n return cdnURL(`/splashes/${this.id}`, this.splash, options);\n }\n\n /** Returns the guild banner URL, or null if none. */\n public bannerURL(options: ImageURLOptions = {}): string | null {\n if (!this.banner) return null;\n return cdnURL(`/banners/${this.id}`, this.banner, options);\n }\n\n /** Returns the guild discovery splash URL, or null if none. */\n public discoverySplashURL(options: ImageURLOptions = {}): string | null {\n if (!this.discoverySplash) return null;\n return cdnURL(\n `/discovery-splashes/${this.id}`,\n this.discoverySplash,\n options,\n );\n }\n\n /** Returns a widget image URL for the guild.\n * @param style Widget style: shield (default), banner1, banner2, banner3, banner4.\n */\n public widgetImageURL(\n style:\n \"shield\" | \"banner1\" | \"banner2\" | \"banner3\" | \"banner4\" = \"shield\",\n ): string {\n return `https://discord.com/api/guilds/${this.id}/widget.png?style=${style}`;\n }\n\n /** Whether the guild has a given feature flag. @param feature Feature string, e.g. \"COMMUNITY\". */\n public hasFeature(feature: string): boolean {\n return this.features.includes(feature);\n }\n\n /** Whether the guild is a Community server. */\n public get isCommunity(): boolean {\n return this.hasFeature(\"COMMUNITY\");\n }\n\n /** Whether the guild is an official Discord Partner. */\n public get isPartnered(): boolean {\n return this.hasFeature(\"PARTNERED\");\n }\n\n /** Whether the guild is verified by Discord. */\n public get isVerified(): boolean {\n return this.hasFeature(\"VERIFIED\");\n }\n\n /** Whether the guild has any active boost subscriptions. */\n public get isBoosted(): boolean {\n return this.premiumSubscriptionCount > 0;\n }\n\n /** Alias for premiumTier — the guild's current Nitro boost level (0–3). */\n public get boostLevel(): number {\n return this.premiumTier;\n }\n\n /** Whether the guild has a vanity URL. */\n public get hasVanityUrl(): boolean {\n return this.vanityUrlCode !== null;\n }\n\n /** Returns the guild's vanity invite URL, or null if none. */\n public get vanityURL(): string | null {\n return this.vanityUrlCode\n ? `https://discord.gg/${this.vanityUrlCode}`\n : null;\n }\n\n /** Returns a human-readable string representation. */\n public override toString(): string {\n return this.name;\n }\n}\n",
|
|
22
|
-
"import { BaseStructure, Channel, User, CDN_BASE, cdnURL } from \"./base.js\";\nimport { PermissionsBitField } from \"@lunibee/core\";\nimport type { ImageURLOptions, ResourceContext } from \"./base.js\";\n\n/** Parses a Discord ISO timestamp into a Date, returning null for absent or invalid values. */\nfunction toDateOrNull(value?: string | null): Date | null {\n if (!value) return null;\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\n// ─── GuildMember ───────────────────────────────────────────────────────────────\n\n/** A Discord guild member. */\nexport class GuildMember {\n /** User represented by the member. */ public readonly user: User;\n /** Guild containing the member. */ public readonly guildId: string;\n /** Nickname, if configured. */ public nickname: string | null;\n /** Role IDs assigned to the member. */ public readonly roleIds: string[];\n /** Whether the member is pending membership screening. */ public pending: boolean;\n /** Member join timestamp. */ public joinedAt?: Date;\n /** Member-specific avatar hash, if set. */ public avatarHash:\n string | null;\n /** When the member started boosting the guild. */ public premiumSince: Date | null;\n /** When the member's timeout expires (null if not timed out). */ public timedOutUntil: Date | null;\n /** Member flags bitfield. */ public flags: number;\n /** Permissions Discord sent with the member (interactions only). */\n readonly #suppliedPermissions?: PermissionsBitField;\n readonly #context?: ResourceContext;\n\n /** Creates a guild member from Discord data. @param data Discord guild-member payload. @throws {TypeError} If the guild ID is invalid. @throws {RangeError} If joined_at is invalid. */\n public constructor(\n data: {\n user: {\n id: string;\n username: string;\n global_name?: string | null;\n avatar?: string | null;\n bot?: boolean;\n system?: boolean;\n public_flags?: number;\n discriminator?: string;\n };\n guild_id: string;\n nick?: string | null;\n roles?: string[];\n pending?: boolean;\n joined_at?: string;\n permissions?: string;\n avatar?: string | null;\n premium_since?: string | null;\n communication_disabled_until?: string | null;\n flags?: number;\n },\n context?: ResourceContext,\n ) {\n this.user = new User(data.user);\n this.#context = context;\n if (!/^\\d{1,20}$/.test(data.guild_id))\n throw new TypeError(\"Member guild_id must be a valid snowflake.\");\n this.guildId = data.guild_id;\n this.nickname = data.nick ?? null;\n this.roleIds = [...(data.roles ?? [])];\n this.pending = data.pending ?? false;\n this.joinedAt = data.joined_at ? new Date(data.joined_at) : undefined;\n if (this.joinedAt?.toString() === \"Invalid Date\")\n throw new RangeError(\"Member joined_at must be a valid date.\");\n if (data.permissions !== undefined)\n this.#suppliedPermissions = new PermissionsBitField(\n data.permissions,\n );\n this.avatarHash = data.avatar ?? null;\n // Like joinedAt, coerce malformed timestamps to null instead of an Invalid Date.\n this.premiumSince = toDateOrNull(data.premium_since);\n this.timedOutUntil = toDateOrNull(data.communication_disabled_until);\n this.flags = data.flags ?? 0;\n }\n\n /**\n * The member's permissions. Discord sends them with interactions (already\n * resolved for the channel); anywhere else they are computed at guild\n * level from the cached roles each time they are read, so they follow role\n * changes. Empty when the guild's roles are not cached.\n */\n public get permissions(): PermissionsBitField {\n if (this.#suppliedPermissions) return this.#suppliedPermissions;\n return new PermissionsBitField(\n this.#context?.memberPermissions?.(\n this.guildId,\n this.user.id,\n this.roleIds,\n ) ?? 0n,\n );\n }\n\n /** The member's permissions in a channel, with its overwrites. Null when the channel or guild is not cached. @param channelId Channel ID. */\n public permissionsIn(channelId: string): PermissionsBitField | null {\n const computed = this.#context?.memberPermissions?.(\n this.guildId,\n this.user.id,\n this.roleIds,\n channelId,\n );\n return computed ? new PermissionsBitField(computed) : null;\n }\n\n #action<K extends keyof ResourceContext>(\n name: K,\n ): NonNullable<ResourceContext[K]> {\n const action = this.#context?.[name];\n if (!action)\n throw new Error(\"This member is not attached to a client.\");\n return action as NonNullable<ResourceContext[K]>;\n }\n\n /** Kicks this member. @param reason Audit-log reason. */\n public kick(reason?: string): Promise<void> {\n return this.#action(\"kickMember\")(this.guildId, this.user.id, reason);\n }\n\n /** Bans this member. @param options Audit-log reason and seconds of messages to delete. */\n public ban(\n options: { reason?: string; deleteMessageSeconds?: number } = {},\n ): Promise<void> {\n return this.#action(\"banMember\")(this.guildId, this.user.id, options);\n }\n\n /** Edits this member (nickname, roles, voice state, timeout). @param options Discord member fields. @param reason Audit-log reason. */\n public edit(\n options: Record<string, unknown>,\n reason?: string,\n ): Promise<GuildMember> {\n return this.#action(\"editMember\")(\n this.guildId,\n this.user.id,\n options,\n reason,\n );\n }\n\n /** Times this member out, or clears the timeout with null. @param milliseconds Timeout length (Discord allows up to 28 days). @param reason Audit-log reason. */\n public timeout(\n milliseconds: number | null,\n reason?: string,\n ): Promise<GuildMember> {\n if (milliseconds !== null && !(milliseconds > 0))\n throw new RangeError(\n \"Timeout length must be a positive number of milliseconds.\",\n );\n return this.edit(\n {\n communication_disabled_until:\n milliseconds === null\n ? null\n : new Date(Date.now() + milliseconds).toISOString(),\n },\n reason,\n );\n }\n\n /** Sets or clears (null) this member's nickname. @param nickname New nickname. @param reason Audit-log reason. */\n public setNickname(\n nickname: string | null,\n reason?: string,\n ): Promise<GuildMember> {\n return this.edit({ nick: nickname }, reason);\n }\n\n /** Gives this member a role. @param roleId Role ID. @param reason Audit-log reason. */\n public addRole(roleId: string, reason?: string): Promise<void> {\n return this.#action(\"addMemberRole\")(\n this.guildId,\n this.user.id,\n roleId,\n reason,\n );\n }\n\n /** Takes a role from this member. @param roleId Role ID. @param reason Audit-log reason. */\n public removeRole(roleId: string, reason?: string): Promise<void> {\n return this.#action(\"removeMemberRole\")(\n this.guildId,\n this.user.id,\n roleId,\n reason,\n );\n }\n\n /** Effective member display name — nickname, falling back to user display name. */\n public get displayName(): string {\n return this.nickname ?? this.user.displayName;\n }\n\n /** Whether this member is currently timed out. */\n public get isTimedOut(): boolean {\n return this.timedOutUntil !== null && this.timedOutUntil > new Date();\n }\n\n /** Returns the member-specific avatar URL, falling back to the user's avatar, or null if none. */\n public avatarURL(options: ImageURLOptions = {}): string | null {\n if (this.avatarHash)\n return cdnURL(\n `/guilds/${this.guildId}/users/${this.user.id}/avatars`,\n this.avatarHash,\n options,\n );\n // User always exposes avatarURL(); returns null when the user has no avatar.\n return this.user.avatarURL(options);\n }\n\n /** Returns the resolved avatar URL — member avatar, user avatar, or default. */\n public displayAvatarURL(options: ImageURLOptions = {}): string {\n return this.avatarURL(options) ?? this.user.displayAvatarURL(options);\n }\n\n /** Returns the Discord user mention for this member. */\n public toString(): string {\n return this.user.toString();\n }\n}\n\n// ─── Role ──────────────────────────────────────────────────────────────────────\n\n/** A Discord guild role. */\nexport class Role extends BaseStructure {\n /** Role name. */ public name: string;\n /** Role color as a 24-bit RGB integer. */ public color: number;\n /** Whether the role is hoisted. */ public hoist: boolean;\n /** Permission bitfield. */ public permissions: PermissionsBitField;\n /** Whether the role is managed by an integration. */ public managed: boolean;\n /** Whether the role is mentionable. */ public mentionable: boolean;\n /** Role position in the hierarchy. */ public position: number;\n /** Unicode emoji used as the role icon, if any. */ public unicodeEmoji:\n string | null;\n /** Hash of the role's custom icon image, if any. */ public iconHash:\n string | null;\n /** Role tags metadata (bot, premium subscriber, etc). */ public tags: Record<\n string,\n unknown\n > | null;\n\n /** Creates a role from Discord data. @param data Discord role payload. */\n public constructor(data: {\n id: string;\n name: string;\n color?: number;\n hoist?: boolean;\n permissions?: string;\n managed?: boolean;\n mentionable?: boolean;\n position?: number;\n unicode_emoji?: string | null;\n icon?: string | null;\n tags?: Record<string, unknown> | null;\n }) {\n super(data.id);\n if (!data.name) throw new TypeError(\"Role name cannot be empty.\");\n this.name = data.name;\n this.color = data.color ?? 0;\n this.hoist = data.hoist ?? false;\n this.permissions = new PermissionsBitField(data.permissions ?? 0n);\n this.managed = data.managed ?? false;\n this.mentionable = data.mentionable ?? false;\n this.position = data.position ?? 0;\n this.unicodeEmoji = data.unicode_emoji ?? null;\n this.iconHash = data.icon ?? null;\n this.tags = data.tags ?? null;\n }\n\n /** Returns the role's color as a `#RRGGBB` hex string. Returns `#000000` for colorless roles. */\n public get colorHex(): string {\n return `#${this.color.toString(16).padStart(6, \"0\").toUpperCase()}`;\n }\n\n /** Returns the role's custom icon URL, or null if the role has no icon. */\n public iconURL(options: ImageURLOptions = {}): string | null {\n if (!this.iconHash) return null;\n return cdnURL(`/role-icons/${this.id}`, this.iconHash, options);\n }\n\n /** Whether this is the `@everyone` base role (its ID equals the guild ID). */\n public isEveryone(guildId: string): boolean {\n return this.id === guildId;\n }\n\n /** Discord role mention string. Used automatically in template literals. */\n public override toString(): string {\n return `<@&${this.id}>`;\n }\n}\n\n// ─── TextChannel ──────────────────────────────────────────────────────────────\n\n/** A Discord text-capable channel. */\nexport class TextChannel extends Channel {\n /** Creates a text channel from Discord data. @param data Discord channel payload. */\n public constructor(\n data: {\n id: string;\n type: number;\n name?: string | null;\n parent_id?: string | null;\n guild_id?: string;\n } & Partial<import(\"@lunibee/types\").APIChannel>,\n context?: import(\"./base.js\").ResourceContext,\n ) {\n super(data, context);\n }\n /** Discord channel mention string. Used automatically in template literals. */\n public override toString(): string {\n return `<#${this.id}>`;\n }\n}\n\n// ─── Invite ───────────────────────────────────────────────────────────────────\n\n/** A Discord invite link and its metadata. */\nexport class Invite {\n /** Invite code (the unique part of the URL). */ public readonly code: string;\n /** Guild this invite belongs to, if any. */ public readonly guildId:\n string | null;\n /** Channel this invite points to, if any. */ public readonly channelId:\n string | null;\n /** User who created the invite, if available. */ public readonly inviter: User | null;\n /** Number of times the invite has been used. */ public uses: number;\n /** Maximum number of uses (0 = unlimited). */ public maxUses: number;\n /** Duration in seconds until the invite expires (0 = never). */ public maxAge: number;\n /** Whether the invite is temporary (kicks uninducted members on disconnect). */ public temporary: boolean;\n /** When the invite was created. */ public readonly createdAt: Date | null;\n /** When the invite expires, or null if it never expires. */ public readonly expiresAt: Date | null;\n\n /** Creates an invite from Discord data. */\n public constructor(data: {\n code: string;\n guild?: { id: string } | null;\n channel?: { id: string } | null;\n inviter?: {\n id: string;\n username: string;\n global_name?: string | null;\n avatar?: string | null;\n bot?: boolean;\n system?: boolean;\n public_flags?: number;\n discriminator?: string;\n } | null;\n uses?: number;\n max_uses?: number;\n max_age?: number;\n temporary?: boolean;\n created_at?: string | null;\n expires_at?: string | null;\n }) {\n if (!data.code) throw new TypeError(\"An invite requires a code.\");\n this.code = data.code;\n this.guildId = data.guild?.id ?? null;\n this.channelId = data.channel?.id ?? null;\n this.inviter = data.inviter ? new User(data.inviter) : null;\n this.uses = data.uses ?? 0;\n this.maxUses = data.max_uses ?? 0;\n this.maxAge = data.max_age ?? 0;\n this.temporary = data.temporary ?? false;\n this.createdAt = data.created_at ? new Date(data.created_at) : null;\n this.expiresAt = data.expires_at ? new Date(data.expires_at) : null;\n }\n\n /** The full invite URL. */\n public get url(): string {\n return `https://discord.gg/${this.code}`;\n }\n\n /** Returns the invite URL. Used automatically in template literals. */\n public toString(): string {\n return this.url;\n }\n}\n\n// ─── Webhook ──────────────────────────────────────────────────────────────────\n\n/** Webhook type constants. */\nexport const WebhookEnum = {\n Incoming: 1,\n ChannelFollower: 2,\n Application: 3,\n} as const;\n/** One {@link WebhookEnum} value, usable as a type. */\nexport type WebhookEnum = (typeof WebhookEnum)[keyof typeof WebhookEnum];\n\n/** A Discord webhook — an HTTP endpoint that can post messages to a channel. */\nexport class Webhook extends BaseStructure {\n /** Webhook type. */ public readonly type: number;\n /** Webhook display name. */ public name: string | null;\n /** Webhook avatar hash. */ public avatarHash: string | null;\n /** Channel this webhook posts to. */ public readonly channelId:\n string | null;\n /** Guild this webhook belongs to. */ public readonly guildId:\n string | null;\n /** Application that created this webhook, if any. */ public readonly applicationId:\n string | null;\n /** Webhook token (only present for incoming webhooks). */ public readonly token:\n string | null;\n\n /** Creates a webhook from Discord data. */\n public constructor(data: {\n id: string;\n type?: number;\n name?: string | null;\n avatar?: string | null;\n channel_id?: string | null;\n guild_id?: string | null;\n application_id?: string | null;\n token?: string;\n }) {\n super(data.id);\n this.type = data.type ?? WebhookEnum.Incoming;\n this.name = data.name ?? null;\n this.avatarHash = data.avatar ?? null;\n this.channelId = data.channel_id ?? null;\n this.guildId = data.guild_id ?? null;\n this.applicationId = data.application_id ?? null;\n this.token = data.token ?? null;\n }\n\n /** Returns the webhook avatar URL, or null if no avatar is set. */\n public avatarURL(options: ImageURLOptions = {}): string | null {\n if (!this.avatarHash) return null;\n return cdnURL(`/avatars/${this.id}`, this.avatarHash, options);\n }\n\n /** Returns the webhook execution URL, or null if no token is set. */\n public get url(): string | null {\n return this.token\n ? `https://discord.com/api/webhooks/${this.id}/${this.token}`\n : null;\n }\n\n /** Returns the webhook URL or its ID as a string. */\n public override toString(): string {\n return this.url ?? this.id;\n }\n}\n\n// ─── Emoji ────────────────────────────────────────────────────────────────────\n\n/** A Discord emoji. */\nexport class Emoji extends BaseStructure {\n /** Emoji name. */ public name: string | null;\n /** Roles allowed to use this emoji. */ public roleIds: string[];\n /** User that created this emoji. */ public user: User | null;\n /** Whether this emoji must be wrapped in colons. */ public requireColons: boolean;\n /** Whether this emoji is managed. */ public managed: boolean;\n /** Whether this emoji is animated. */ public animated: boolean;\n /** Whether this emoji can be used, may be false due to loss of Server Boosts. */ public available: boolean;\n\n /** Creates an emoji from Discord data. */\n public constructor(data: {\n id: string | null;\n name: string | null;\n roles?: string[];\n user?: import(\"@lunibee/types\").UserData;\n require_colons?: boolean;\n managed?: boolean;\n animated?: boolean;\n available?: boolean;\n }) {\n // Unicode emoji have no snowflake: pass the base check with a\n // placeholder, then expose the documented \"unicode\" sentinel id.\n super(data.id ?? \"0\");\n if (data.id === null) (this as { id: string }).id = \"unicode\";\n this.name = data.name;\n this.roleIds = data.roles ?? [];\n this.user = data.user ? new User(data.user) : null;\n this.requireColons = data.require_colons ?? false;\n this.managed = data.managed ?? false;\n this.animated = data.animated ?? false;\n this.available = data.available ?? true;\n }\n\n /** Returns the URL for this emoji if it is custom, or null for unicode emojis. */\n public url(options: ImageURLOptions = {}): string | null {\n if (!this.id || this.id === \"unicode\") return null;\n const ext = options.extension ?? (this.animated ? \"gif\" : \"png\");\n const size = options.size ? `?size=${options.size}` : \"\";\n return `${CDN_BASE}/emojis/${this.id}.${ext}${size}`;\n }\n\n /** Returns the text required to render this emoji in Discord. */\n public override toString(): string {\n return this.id !== \"unicode\"\n ? `<${this.animated ? \"a\" : \"\"}:${this.name}:${this.id}>`\n : (this.name ?? \"\");\n }\n}\n\n// --- AutoModerationRule --------------------------------------------------------\n\n/** A Discord AutoModeration Rule. */\nexport class AutoModerationRule extends BaseStructure {\n public guildId: string;\n public name: string;\n public creatorId: string;\n public eventType: number;\n public triggerType: number;\n public triggerMetadata: Record<string, unknown>;\n public actions: import(\"@lunibee/types\").APIAutoModerationAction[];\n public enabled: boolean;\n public exemptRoles: string[];\n public exemptChannels: string[];\n\n /** Creates an auto moderation rule from Discord data. */\n public constructor(data: import(\"@lunibee/types\").APIAutoModerationRule) {\n super(data.id);\n if (!/^\\d{1,20}$/.test(data.guild_id))\n throw new TypeError(\n \"AutoModerationRule guild_id must be a valid snowflake.\",\n );\n this.guildId = data.guild_id;\n this.name = data.name;\n this.creatorId = data.creator_id;\n this.eventType = data.event_type;\n this.triggerType = data.trigger_type;\n this.triggerMetadata = data.trigger_metadata;\n this.actions = data.actions;\n this.enabled = data.enabled;\n this.exemptRoles = data.exempt_roles;\n this.exemptChannels = data.exempt_channels;\n }\n\n public toJSON(): Record<string, unknown> {\n return {\n id: this.id,\n guildId: this.guildId,\n name: this.name,\n creatorId: this.creatorId,\n eventType: this.eventType,\n triggerType: this.triggerType,\n triggerMetadata: this.triggerMetadata,\n actions: this.actions,\n enabled: this.enabled,\n exemptRoles: this.exemptRoles,\n exemptChannels: this.exemptChannels,\n };\n }\n}\n\n// --- Welcome Screen -----------------------------------------------------------\n\n/** A channel listed in a guild's Welcome Screen. */\nexport class WelcomeScreenChannel {\n public channelId: string;\n public description: string;\n public emojiId: string | null;\n public emojiName: string | null;\n\n public constructor(data: import(\"@lunibee/types\").APIWelcomeScreenChannel) {\n this.channelId = data.channel_id;\n this.description = data.description;\n this.emojiId = data.emoji_id;\n this.emojiName = data.emoji_name;\n }\n}\n\n/** A Discord Guild Welcome Screen. */\nexport class GuildWelcomeScreen {\n public description: string | null;\n public channels: WelcomeScreenChannel[];\n\n public constructor(data: import(\"@lunibee/types\").APIGuildWelcomeScreen) {\n this.description = data.description;\n this.channels = data.welcome_channels.map(\n (c) => new WelcomeScreenChannel(c),\n );\n }\n}\n\n// --- Guild Onboarding ---------------------------------------------------------\n\n/** An option within a Guild Onboarding Prompt. */\nexport class OnboardingPromptOption extends BaseStructure {\n public channelIds: string[];\n public roleIds: string[];\n public emoji: import(\"@lunibee/types\").APIPartialEmoji | undefined;\n public title: string;\n public description: string | null;\n\n public constructor(\n data: import(\"@lunibee/types\").APIOnboardingPromptOption,\n ) {\n super(data.id);\n this.channelIds = data.channel_ids;\n this.roleIds = data.role_ids;\n this.emoji = data.emoji;\n this.title = data.title;\n this.description = data.description;\n }\n}\n\n/** A prompt shown during Guild Onboarding. */\nexport class OnboardingPrompt extends BaseStructure {\n public type: number;\n public options: OnboardingPromptOption[];\n public title: string;\n public singleSelect: boolean;\n public required: boolean;\n public inOnboarding: boolean;\n\n public constructor(data: import(\"@lunibee/types\").APIOnboardingPrompt) {\n super(data.id);\n this.type = data.type;\n this.options = data.options.map((o) => new OnboardingPromptOption(o));\n this.title = data.title;\n this.singleSelect = data.single_select;\n this.required = data.required;\n this.inOnboarding = data.in_onboarding;\n }\n}\n\n/** A Discord Guild Onboarding setup. */\nexport class GuildOnboarding extends BaseStructure {\n public prompts: OnboardingPrompt[];\n public defaultChannelIds: string[];\n public enabled: boolean;\n public mode: number;\n\n public constructor(data: import(\"@lunibee/types\").APIGuildOnboarding) {\n super(data.guild_id);\n this.prompts = data.prompts.map((p) => new OnboardingPrompt(p));\n this.defaultChannelIds = data.default_channel_ids;\n this.enabled = data.enabled;\n this.mode = data.mode;\n }\n}\n\n/** @deprecated Use {@link WebhookEnum}. Removed in 0.3.0. */\nexport const WebhookType = WebhookEnum;\n/** @deprecated Use {@link WebhookEnum}. Removed in 0.3.0. */\nexport type WebhookType = WebhookEnum;\n",
|
|
23
|
-
"import { Channel, User, type ResourceContext } from \"./base.js\";\nimport { TextChannel } from \"./resources.js\";\nimport type {\n APIChannel,\n APIForumTag,\n APIPartialEmoji,\n APIThreadMetadata,\n} from \"@lunibee/types\";\n\n// Discord.js-familiar channel subclasses. Every class extends Channel, so\n// existing `instanceof Channel` checks and Channel methods keep working.\n\n/** A guild announcement (news) channel. */\nexport class NewsChannel extends TextChannel {}\n\n/** A direct-message or group DM channel. */\nexport class DMChannel extends Channel {\n /** Users in the conversation.
|
|
24
|
-
"// ─── Raw option type from Discord ────────────────────────────────────────────\n\n/** Raw Discord application command interaction data option. */\nexport interface APIInteractionDataOption {\n name: string;\n type: number;\n value?: string | number | boolean;\n options?: APIInteractionDataOption[];\n focused?: boolean;\n}\n\n// ─── CommandOptions resolver ──────────────────────────────────────────────────\n\n/** Application command option types mirroring Discord's enum. */\nconst OptionType = {\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/**\n * Typed resolver for application command options.\n * Attached as `CommandInteraction.options`.\n */\nexport class CommandOptions {\n readonly #options: APIInteractionDataOption[];\n readonly #resolved: Record<string, unknown>;\n /** `resolved[kind][id]` from Discord's interaction data, if present. */\n #lookup(kind: string, id: string): Record<string, unknown> | undefined {\n const group = this.#resolved?.[kind];\n if (typeof group !== \"object\" || group === null) return undefined;\n const entry = (group as Record<string, unknown>)[id];\n return typeof entry === \"object\" && entry !== null\n ? (entry as Record<string, unknown>)\n : undefined;\n }\n\n /** @internal */\n public constructor(\n options: APIInteractionDataOption[],\n resolved: Record<string, unknown> = {},\n ) {\n let currentOptions = options;\n let group: string | null = null;\n let sub: string | null = null;\n\n // Drill down to the deepest options level for nested subcommands\n while (currentOptions.length === 1) {\n const opt = currentOptions[0]!;\n if (opt.type === OptionType.SubCommandGroup) {\n group = opt.name;\n currentOptions = opt.options ?? [];\n } else if (opt.type === OptionType.SubCommand) {\n sub = opt.name;\n currentOptions = opt.options ?? [];\n } else {\n break;\n }\n }\n\n this.#options = currentOptions;\n this.#resolved = resolved;\n this.#subcommandGroup = group;\n this.#subcommand = sub;\n }\n\n readonly #subcommandGroup: string | null;\n readonly #subcommand: string | null;\n\n /** Finds a raw option by name (case-insensitive). */\n #get(name: string): APIInteractionDataOption | undefined {\n return this.#options.find(\n (o) => o.name.toLowerCase() === name.toLowerCase(),\n );\n }\n\n // ── Subcommand resolution ──────────────────────────────────────────────────\n\n /** Returns the invoked subcommand name, or null if none. */\n public getSubcommand(required?: false): string | null;\n public getSubcommand(required: true): string;\n public getSubcommand(required = false): string | null {\n if (!this.#subcommand && required) {\n throw new TypeError(\"No subcommand was provided.\");\n }\n return this.#subcommand;\n }\n\n /** Returns the invoked subcommand group name, or null if none. */\n public getSubcommandGroup(required?: false): string | null;\n public getSubcommandGroup(required: true): string;\n public getSubcommandGroup(required = false): string | null {\n if (!this.#subcommandGroup && required) {\n throw new TypeError(\"No subcommand group was provided.\");\n }\n return this.#subcommandGroup;\n }\n\n // ── Autocomplete ───────────────────────────────────────────────────────────\n\n /** Returns the focused option's value (autocomplete), or the full option when `full` is true. @throws {TypeError} If no option is focused. */\n public getFocused(full: true): APIInteractionDataOption;\n public getFocused(full?: false): string | number | boolean;\n public getFocused(\n full = false,\n ): APIInteractionDataOption | string | number | boolean {\n const focused = this.#options.find((o) => o.focused);\n if (!focused) throw new TypeError(\"No focused option was provided.\");\n return full ? focused : (focused.value ?? \"\");\n }\n\n // ── Primitive value options ────────────────────────────────────────────────\n\n /** Gets a string option. @param name Option name. @param required If true, throws when missing. */\n public getString(name: string, required?: false): string | null;\n public getString(name: string, required: true): string;\n public getString(name: string, required = false): string | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.String) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (string) is missing.`,\n );\n return null;\n }\n return typeof opt.value === \"string\" ? opt.value : null;\n }\n\n /** Gets an integer option. @param name Option name. @param required If true, throws when missing. */\n public getInteger(name: string, required?: false): number | null;\n public getInteger(name: string, required: true): number;\n public getInteger(name: string, required = false): number | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.Integer) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (integer) is missing.`,\n );\n return null;\n }\n return typeof opt.value === \"number\" ? Math.trunc(opt.value) : null;\n }\n\n /** Gets a number (float) option. @param name Option name. @param required If true, throws when missing. */\n public getNumber(name: string, required?: false): number | null;\n public getNumber(name: string, required: true): number;\n public getNumber(name: string, required = false): number | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.Number) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (number) is missing.`,\n );\n return null;\n }\n return typeof opt.value === \"number\" ? opt.value : null;\n }\n\n /** Gets a boolean option. @param name Option name. @param required If true, throws when missing. */\n public getBoolean(name: string, required?: false): boolean | null;\n public getBoolean(name: string, required: true): boolean;\n public getBoolean(name: string, required = false): boolean | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.Boolean) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (boolean) is missing.`,\n );\n return null;\n }\n return typeof opt.value === \"boolean\" ? opt.value : null;\n }\n\n // ── Resolved entity options ────────────────────────────────────────────────\n\n /** Gets the raw resolved user data for a user option. @param name Option name. @param required If true, throws when missing. */\n public getUser(\n name: string,\n required?: false,\n ): Record<string, unknown> | null;\n public getUser(name: string, required: true): Record<string, unknown>;\n public getUser(\n name: string,\n required = false,\n ): Record<string, unknown> | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.User) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (user) is missing.`,\n );\n return null;\n }\n const userId = String(opt.value);\n const resolved = this.#lookup(\"users\", userId) ?? null;\n if (!resolved && required)\n throw new TypeError(\n `Resolved user for option \"${name}\" is missing.`,\n );\n return resolved;\n }\n\n /** Gets the raw resolved channel data for a channel option. @param name Option name. @param required If true, throws when missing. */\n public getChannel(\n name: string,\n required?: false,\n ): Record<string, unknown> | null;\n public getChannel(name: string, required: true): Record<string, unknown>;\n public getChannel(\n name: string,\n required = false,\n ): Record<string, unknown> | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.Channel) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (channel) is missing.`,\n );\n return null;\n }\n const channelId = String(opt.value);\n const resolved = this.#lookup(\"channels\", channelId) ?? null;\n if (!resolved && required)\n throw new TypeError(\n `Resolved channel for option \"${name}\" is missing.`,\n );\n return resolved;\n }\n\n /** Gets the raw resolved role data for a role option. @param name Option name. @param required If true, throws when missing. */\n public getRole(\n name: string,\n required?: false,\n ): Record<string, unknown> | null;\n public getRole(name: string, required: true): Record<string, unknown>;\n public getRole(\n name: string,\n required = false,\n ): Record<string, unknown> | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.Role) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (role) is missing.`,\n );\n return null;\n }\n const roleId = String(opt.value);\n const resolved = this.#lookup(\"roles\", roleId) ?? null;\n if (!resolved && required)\n throw new TypeError(\n `Resolved role for option \"${name}\" is missing.`,\n );\n return resolved;\n }\n\n /** Gets the raw resolved user or role data for a mentionable option. @param name Option name. @param required If true, throws when missing. */\n public getMentionable(\n name: string,\n required?: false,\n ): Record<string, unknown> | null;\n public getMentionable(\n name: string,\n required: true,\n ): Record<string, unknown>;\n public getMentionable(\n name: string,\n required = false,\n ): Record<string, unknown> | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.Mentionable) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (mentionable) is missing.`,\n );\n return null;\n }\n const id = String(opt.value);\n const resolved =\n this.#lookup(\"users\", id) ?? this.#lookup(\"roles\", id) ?? null;\n if (!resolved && required)\n throw new TypeError(\n `Resolved mentionable for option \"${name}\" is missing.`,\n );\n return resolved;\n }\n\n /** Whether a mentionable option picked a user or a role; null when the option is missing. @param name Option name. */\n public getMentionableType(name: string): \"user\" | \"role\" | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.Mentionable) return null;\n const id = String(opt.value);\n if (this.#lookup(\"users\", id)) return \"user\";\n if (this.#lookup(\"roles\", id)) return \"role\";\n return null;\n }\n\n /** Gets the raw resolved attachment data for an attachment option. @param name Option name. @param required If true, throws when missing. */\n public getAttachment(\n name: string,\n required?: false,\n ): Record<string, unknown> | null;\n public getAttachment(name: string, required: true): Record<string, unknown>;\n public getAttachment(\n name: string,\n required = false,\n ): Record<string, unknown> | null {\n const opt = this.#get(name);\n if (!opt || opt.type !== OptionType.Attachment) {\n if (required)\n throw new TypeError(\n `Required option \"${name}\" (attachment) is missing.`,\n );\n return null;\n }\n const attachmentId = String(opt.value);\n const resolved = this.#lookup(\"attachments\", attachmentId) ?? null;\n if (!resolved && required)\n throw new TypeError(\n `Resolved attachment for option \"${name}\" is missing.`,\n );\n return resolved;\n }\n\n /** Returns the raw option list for advanced use cases. */\n public get raw(): readonly APIInteractionDataOption[] {\n return this.#options;\n }\n}\n",
|
|
25
|
-
"import { InteractionResponseEnum } from \"@lunibee/types\";\nimport { User, type ResourceContext } from \"./base.js\";\nimport { GuildMember } from \"./resources.js\";\n// A cycle with index.ts: Message is only used lazily (in a getter), after both modules loaded.\nimport { Message } from \"./index.js\";\n\n/** Discord interaction type constants. */\nexport const InteractionEnum = {\n Ping: 1,\n ApplicationCommand: 2,\n MessageComponent: 3,\n ApplicationCommandAutocomplete: 4,\n ModalSubmit: 5,\n} as const;\n/** One {@link InteractionEnum} value, usable as a type. */\nexport type InteractionEnum =\n (typeof InteractionEnum)[keyof typeof InteractionEnum];\n// Re-export for consumers who import from structures directly\nexport {\n InteractionResponseEnum,\n InteractionResponseType,\n} from \"@lunibee/types\";\n/** Data shared by Discord interactions. */\nexport interface InteractionData {\n /** Interaction identifier. */ id: string;\n /** Application identifier. */ application_id: string;\n /** Interaction type. */ type: number;\n /** Interaction token. */ token: string;\n /** Gateway/API version. */ version?: number;\n /** Guild identifier. */ guild_id?: string;\n /** Channel identifier. */ channel_id?: string;\n /** Interaction-specific data. */ data?: Record<string, unknown>;\n [key: string]: unknown;\n}\n/** Options for an interaction response message. */\nexport interface InteractionReplyOptions {\n /** Message content. */ content?: string;\n /** Whether the response is ephemeral. */ ephemeral?: boolean;\n /** Message components. */ components?: unknown[];\n /** Message embeds. */ embeds?: unknown[];\n /** Discord message flags. */ flags?: number;\n /** On `reply()` / `update()`: return the created message (one request, no `fetchReply()`). */ withResponse?: boolean;\n [key: string]: unknown;\n}\n/** Transport required by an interaction structure. */\nexport interface InteractionClient {\n /** Sends the initial interaction callback. @param id Interaction identifier. @param token Interaction token. @param response Callback payload. @returns Discord response. @throws {Error} When REST fails. */ postInteractionResponse(\n id: string,\n token: string,\n response: InteractionResponse,\n ): Promise<unknown>;\n /** Edits the original interaction response. @param token Interaction token. @param data Message payload. @returns Discord response. @throws {Error} When REST fails. */ editInteractionReply(\n token: string,\n data: InteractionReplyOptions,\n ): Promise<unknown>;\n /** Deletes the original interaction response. @param token Interaction token. @returns Promise fulfilled after deletion. @throws {Error} When REST fails. */ deleteInteractionReply(\n token: string,\n ): Promise<void>;\n /** Sends a follow-up interaction webhook message. @param token Interaction token. @param data Message payload. @returns Discord response. @throws {Error} When REST fails. */ followUpInteraction(\n token: string,\n data: InteractionReplyOptions,\n ): Promise<unknown>;\n /** 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}. */\n interactionWebhookMessage?(\n method: \"GET\" | \"PATCH\" | \"DELETE\",\n applicationId: string,\n token: string,\n messageId: string,\n data?: InteractionReplyOptions,\n ): Promise<unknown>;\n /** Lets structures built from an interaction (such as {@link Interaction.member}) act through the client. Optional. */\n readonly resourceContext?: ResourceContext;\n}\n\n/** Discord's ephemeral message flag. */\nconst EPHEMERAL = 64;\n/** Application command types (`data.type`): slash, user context menu, message context menu. */\nconst COMMAND_CHAT_INPUT = 1;\nconst COMMAND_USER = 2;\nconst COMMAND_MESSAGE = 3;\n/** Interaction tokens stay valid for 15 minutes. */\nconst TOKEN_LIFETIME_MS = 15 * 60_000;\nconst DISCORD_EPOCH = 1_420_070_400_000n;\n\n/** Takes the local-only `withResponse` key off reply options. */\nfunction splitWithResponse(options: InteractionReplyOptions | string): {\n withResponse: boolean;\n rest: InteractionReplyOptions | string;\n} {\n if (typeof options === \"string\")\n return { withResponse: false, rest: options };\n const { withResponse, ...rest } = options;\n return { withResponse: withResponse === true, rest };\n}\n\n/** Turns `{ ephemeral: true }` into Discord's flag and drops the local-only key. */\nfunction toMessageData(\n options: InteractionReplyOptions | string,\n): InteractionReplyOptions {\n if (typeof options === \"string\") return { content: options };\n const { ephemeral, ...data } = options;\n if (ephemeral)\n data.flags =\n (typeof data.flags === \"number\" ? data.flags : 0) | EPHEMERAL;\n return data;\n}\n\nexport { CommandOptions, type APIInteractionDataOption } from \"./options.js\";\nimport { CommandOptions, type APIInteractionDataOption } from \"./options.js\";\n\n// ─── Response class ───────────────────────────────────────────────────────────\n\n/** A Discord interaction callback payload. */\nexport class InteractionResponse {\n readonly type: number;\n readonly data?: InteractionReplyOptions;\n /** Ask Discord to return the created message (`?with_response=true`); not part of the body. */\n public withResponse = false;\n /** Creates a response payload. @param type Discord callback type. @param data Optional callback data. @throws {TypeError} If type is not finite. */\n public constructor(type: number, data?: InteractionReplyOptions) {\n if (!Number.isFinite(type))\n throw new TypeError(\"Interaction response type must be finite.\");\n this.type = type;\n this.data = data;\n }\n /** Serializes the response for Discord. @returns Discord callback payload. */ public toJSON(): {\n type: number;\n data?: InteractionReplyOptions;\n } {\n return this.data === undefined\n ? { type: this.type }\n : { type: this.type, data: this.data };\n }\n /** Creates an immediate message response. @param options Response message options. @returns Callback payload. */ public static message(\n options: InteractionReplyOptions,\n ): InteractionResponse {\n return new InteractionResponse(\n InteractionResponseEnum.ChannelMessage,\n toMessageData(options),\n );\n }\n /** Creates a deferred channel response. @param ephemeral Whether the eventual response is ephemeral. @returns Callback payload. */ public static defer(\n ephemeral = false,\n ): InteractionResponse {\n return new InteractionResponse(\n InteractionResponseEnum.DeferredChannelMessage,\n ephemeral ? { flags: EPHEMERAL } : undefined,\n );\n }\n /** Creates a Pong response. @returns Callback payload. */ public static pong(): InteractionResponse {\n return new InteractionResponse(InteractionResponseEnum.Pong);\n }\n}\n\n// ─── Base Interaction ─────────────────────────────────────────────────────────\n\n/** Base interaction structure. */\nexport class Interaction<TData extends InteractionData = InteractionData> {\n /** Interaction identifier. */ public readonly id: string;\n /** Application identifier. */ public readonly applicationId: string;\n /** Interaction token. */ public readonly token: string;\n /** Guild identifier. */ public readonly guildId?: string;\n /** Channel identifier. */ public readonly channelId?: string;\n /** Interaction type. */ public readonly type: number;\n /** Raw interaction data. */ public readonly data: TData;\n /** Whether the initial response was sent. */ public replied = false;\n /** Whether the initial response was deferred. */ public deferred = false;\n readonly #client: InteractionClient;\n /** An initial response is in flight; a second one must not be sent. */\n #acknowledging = false;\n /** Creates an interaction from a Gateway payload. @param client Interaction transport. @param data Gateway interaction payload. @throws {TypeError} If required identifiers are missing. */ public constructor(\n client: InteractionClient,\n data: TData,\n ) {\n if (!data.id || !data.token)\n throw new TypeError(\"Interaction ID and token are required.\");\n this.#client = client;\n this.id = data.id;\n this.applicationId = data.application_id;\n this.token = data.token;\n this.guildId = data.guild_id;\n this.channelId = data.channel_id;\n this.type = data.type;\n this.data = data;\n }\n /** The application command's own type (1 chat input, 2 user, 3 message); 0 when this is not a command. */\n #commandType(): number {\n if (this.type !== InteractionEnum.ApplicationCommand) return 0;\n const type = this.data.data?.type;\n return typeof type === \"number\" ? type : COMMAND_CHAT_INPUT;\n }\n /** Whether this interaction is any application command: slash or context menu. */\n public isCommand(): this is CommandInteraction {\n return this.type === InteractionEnum.ApplicationCommand;\n }\n /**\n * Whether this interaction is a slash (chat input) command. Since 0.2.2 this\n * is false for context-menu commands; use {@link isCommand} for both.\n */\n public isChatInputCommand(): this is CommandInteraction {\n return this.#commandType() === COMMAND_CHAT_INPUT;\n }\n /** Whether this interaction is a user or message context-menu command. */\n public isContextMenuCommand(): this is ContextMenuCommandInteraction {\n const type = this.#commandType();\n return type === COMMAND_USER || type === COMMAND_MESSAGE;\n }\n /** Whether this interaction is a user context-menu command (right-click a user). */\n public isUserContextMenuCommand(): this is ContextMenuCommandInteraction {\n return this.#commandType() === COMMAND_USER;\n }\n /** Whether this interaction is a message context-menu command (right-click a message). */\n public isMessageContextMenuCommand(): this is ContextMenuCommandInteraction {\n return this.#commandType() === COMMAND_MESSAGE;\n }\n /** The client context structures built from this interaction act through. */\n protected get resourceContext(): ResourceContext | undefined {\n return this.#client.resourceContext;\n }\n /**\n * Waits for this user to submit a modal, typically one this interaction\n * just opened with {@link showModal}.\n * @param options `time` (required, ms); optional `customId` and `filter`.\n * @returns The submission. @throws {Error} When time runs out first or no client is attached.\n * @example const submitted = await interaction.awaitModalSubmit({ time: 60_000, customId: \"feedback\" });\n */\n public awaitModalSubmit(options: {\n time: number;\n customId?: string;\n filter?: (\n interaction: ModalSubmitInteraction,\n ) => boolean | Promise<boolean>;\n }): Promise<ModalSubmitInteraction> {\n const collect = this.#client.resourceContext?.collectInteractions;\n if (!collect)\n return Promise.reject(\n new Error(\"This interaction is not attached to a client.\"),\n );\n if (!(options.time > 0))\n return Promise.reject(\n new RangeError(\"awaitModalSubmit needs a positive time.\"),\n );\n const userId = this.user?.id;\n const collector = collect({\n time: options.time,\n max: 1,\n filter: async (interaction) =>\n interaction.isModalSubmit() &&\n interaction.user?.id === userId &&\n (options.customId === undefined ||\n interaction.customId === options.customId) &&\n (options.filter ? await options.filter(interaction) : true),\n });\n return collector.next() as Promise<ModalSubmitInteraction>;\n }\n /** Whether this interaction is a message component. @returns True for component interactions. */ public isMessageComponent(): this is ComponentInteraction {\n return this.type === InteractionEnum.MessageComponent;\n }\n /** Whether this interaction is a modal submission. @returns True for modal submissions. */ public isModalSubmit(): this is ModalSubmitInteraction {\n return this.type === InteractionEnum.ModalSubmit;\n }\n /** Whether this interaction is autocomplete. @returns True for autocomplete interactions. */ public isAutocomplete(): this is AutocompleteInteraction {\n return this.type === InteractionEnum.ApplicationCommandAutocomplete;\n }\n /** Message component type of this interaction, or 0 when it is not a component. */\n #componentType(): number {\n return this.isMessageComponent()\n ? ((this.data.data?.component_type as number | undefined) ?? 0)\n : 0;\n }\n /** Whether this is a button interaction. */ public isButton(): this is ComponentInteraction {\n return this.#componentType() === 2;\n }\n /** Whether this is a string select menu interaction. */ public isStringSelectMenu(): this is ComponentInteraction {\n return this.#componentType() === 3;\n }\n /** Whether this is a user select menu interaction. */ public isUserSelectMenu(): this is ComponentInteraction {\n return this.#componentType() === 5;\n }\n /** Whether this is a role select menu interaction. */ public isRoleSelectMenu(): this is ComponentInteraction {\n return this.#componentType() === 6;\n }\n /** Whether this is a mentionable select menu interaction. */ public isMentionableSelectMenu(): this is ComponentInteraction {\n return this.#componentType() === 7;\n }\n /** Whether this is a channel select menu interaction. */ public isChannelSelectMenu(): this is ComponentInteraction {\n return this.#componentType() === 8;\n }\n /** Whether this is any select menu interaction. */ public isAnySelectMenu(): this is ComponentInteraction {\n return [3, 5, 6, 7, 8].includes(this.#componentType());\n }\n /** Ensures the interaction has not already been acknowledged. @returns Nothing. @throws {Error} When already acknowledged. */ protected assertUnacknowledged(): void {\n if (this.replied || this.deferred || this.#acknowledging)\n throw new Error(\"Interaction has already been acknowledged.\");\n }\n /**\n * Sends the initial response exactly once. The in-flight flag is set\n * before the request, so two concurrent calls cannot both send; it is\n * cleared if the request fails so the caller may try again.\n */\n protected async acknowledge(\n response: InteractionResponse,\n state: \"replied\" | \"deferred\",\n ): Promise<unknown> {\n this.assertUnacknowledged();\n this.#acknowledging = true;\n try {\n const result = await this.postResponse(response);\n this[state] = true;\n return result;\n } finally {\n this.#acknowledging = false;\n }\n }\n /** The invoking user (from `member.user` in guilds, `user` in DMs). */\n public get user(): User | null {\n const raw =\n (this.data.member as { user?: unknown } | undefined)?.user ??\n this.data.user;\n return raw\n ? new User(raw as ConstructorParameters<typeof User>[0])\n : null;\n }\n /** The invoking guild member, or null outside a guild. */\n public get member(): GuildMember | null {\n const raw = this.data.member;\n if (!raw || !this.guildId) return null;\n return new GuildMember(\n {\n ...(raw as Omit<\n ConstructorParameters<typeof GuildMember>[0],\n \"guild_id\"\n >),\n guild_id: this.guildId,\n },\n this.#client.resourceContext,\n );\n }\n /** Unix timestamp (ms) at which the interaction was created, from its snowflake. */\n public get createdTimestamp(): number {\n return Number((BigInt(this.id) >> 22n) + DISCORD_EPOCH);\n }\n /** When the interaction token stops working (15 minutes after creation). */\n public get expiresAt(): Date {\n return new Date(this.createdTimestamp + TOKEN_LIFETIME_MS);\n }\n /** Whether the token has expired; no response, edit or follow-up can succeed after that. */\n public get isExpired(): boolean {\n return Date.now() >= this.createdTimestamp + TOKEN_LIFETIME_MS;\n }\n #webhookMessage(\n method: \"GET\" | \"PATCH\" | \"DELETE\",\n messageId: string,\n data?: InteractionReplyOptions,\n ): Promise<unknown> {\n if (!this.#client.interactionWebhookMessage)\n return Promise.reject(\n new Error(\n \"This interaction client does not support webhook message access.\",\n ),\n );\n return this.#client.interactionWebhookMessage(\n method,\n this.applicationId,\n this.token,\n messageId,\n data,\n );\n }\n /** Fetches the original response message. */\n public fetchReply(): Promise<unknown> {\n this.assertAcknowledged();\n return this.#webhookMessage(\"GET\", \"@original\");\n }\n /** Edits a follow-up message. @param messageId Follow-up message ID. */\n public editFollowUp(\n messageId: string,\n options: InteractionReplyOptions | string,\n ): Promise<unknown> {\n return this.#webhookMessage(\"PATCH\", messageId, toMessageData(options));\n }\n /** Deletes a follow-up message. @param messageId Follow-up message ID. */\n public async deleteFollowUp(messageId: string): Promise<void> {\n await this.#webhookMessage(\"DELETE\", messageId);\n }\n /** Ensures the interaction has been acknowledged. @returns Nothing. @throws {Error} When not acknowledged. */ protected assertAcknowledged(): void {\n if (!this.replied && !this.deferred)\n throw new Error(\"Interaction has not been acknowledged.\");\n }\n /** Posts a raw interaction response callback. */\n protected postResponse(response: InteractionResponse): Promise<unknown> {\n return this.#client.postInteractionResponse(\n this.id,\n this.token,\n response,\n );\n }\n /**\n * Sends a response and, when `withResponse` is set, turns the callback\n * resource Discord returns into the created message.\n */\n protected async acknowledgeWith(\n response: InteractionResponse,\n state: \"replied\" | \"deferred\",\n withResponse: boolean,\n ): Promise<unknown> {\n response.withResponse = withResponse;\n const result = await this.acknowledge(response, state);\n if (!withResponse) return result;\n const message = (result as { resource?: { message?: unknown } } | null)\n ?.resource?.message;\n return message\n ? new Message(\n message as ConstructorParameters<typeof Message>[0],\n this.#client.resourceContext,\n )\n : null;\n }\n /**\n * Sends the initial interaction response. With `withResponse: true` it\n * returns the created {@link Message} in the same request (no `fetchReply()`).\n * @throws {Error} When already acknowledged or REST fails.\n */\n public async reply(\n options: InteractionReplyOptions & { withResponse: true },\n ): Promise<Message | null>;\n public async reply(\n options: InteractionReplyOptions | string,\n ): Promise<unknown>;\n public async reply(\n options: InteractionReplyOptions | string,\n ): Promise<unknown> {\n const { withResponse, rest } = splitWithResponse(options);\n return this.acknowledgeWith(\n InteractionResponse.message(toMessageData(rest)),\n \"replied\",\n withResponse,\n );\n }\n /**\n * Defers the initial interaction response. `true` or `{ ephemeral: true }`\n * makes the eventual response private; `withResponse: true` returns the\n * placeholder message. @throws {Error} When already acknowledged or REST fails.\n */\n public async deferReply(options: {\n ephemeral?: boolean;\n withResponse: true;\n }): Promise<Message | null>;\n public async deferReply(\n options?: boolean | { ephemeral?: boolean; withResponse?: boolean },\n ): Promise<void>;\n public async deferReply(\n options:\n boolean | { ephemeral?: boolean; withResponse?: boolean } = false,\n ): Promise<Message | null | void> {\n const ephemeral =\n typeof options === \"boolean\" ? options : options.ephemeral === true;\n const withResponse =\n typeof options === \"object\" && options.withResponse === true;\n const result = await this.acknowledgeWith(\n InteractionResponse.defer(ephemeral),\n \"deferred\",\n withResponse,\n );\n if (withResponse) return result as Message | null;\n }\n /** Edits the original response. @param options Replacement message options. @returns Discord response. @throws {Error} When not acknowledged or REST fails. */ public editReply(\n options: InteractionReplyOptions,\n ): Promise<unknown> {\n this.assertAcknowledged();\n return this.#client.editInteractionReply(\n this.token,\n toMessageData(options),\n );\n }\n /** Deletes the original response. @returns Promise fulfilled after deletion. @throws {Error} When not acknowledged or REST fails. */ public deleteReply(): Promise<void> {\n this.assertAcknowledged();\n return this.#client.deleteInteractionReply(this.token);\n }\n /** Sends a follow-up message using the interaction webhook. @param options Follow-up message options. @returns Discord response. @throws {Error} When REST fails. */ public followUp(\n options: InteractionReplyOptions | string,\n ): Promise<unknown> {\n return this.#client.followUpInteraction(\n this.token,\n toMessageData(options),\n );\n }\n /**\n * Updates the message a component is on. With `withResponse: true` it\n * returns the updated {@link Message}.\n */\n public async update(\n options: InteractionReplyOptions & { withResponse: true },\n ): Promise<Message | null>;\n public async update(\n options: InteractionReplyOptions | string,\n ): Promise<unknown>;\n public async update(\n options: InteractionReplyOptions | string,\n ): Promise<unknown> {\n const { withResponse, rest } = splitWithResponse(options);\n return this.acknowledgeWith(\n new InteractionResponse(\n InteractionResponseEnum.MessageUpdate,\n toMessageData(rest),\n ),\n \"replied\",\n withResponse,\n );\n }\n /** Opens a modal dialog in the user's client. @param modal Modal builder output or raw modal callback data. @returns Discord response. @throws {Error} When already acknowledged or REST fails. */\n public async showModal(\n modal:\n | {\n toJSON(): {\n custom_id: string;\n title: string;\n components: unknown[];\n };\n }\n // No index signature: an interface such as the builder's\n // `APIModalComponent` (what `toJSON()` returns) must be assignable.\n | {\n custom_id: string;\n title: string;\n components: readonly unknown[];\n },\n ): Promise<unknown> {\n const data =\n \"toJSON\" in modal && typeof modal.toJSON === \"function\"\n ? modal.toJSON()\n : modal;\n return this.acknowledge(\n new InteractionResponse(\n InteractionResponseEnum.Modal,\n data as InteractionReplyOptions,\n ),\n \"replied\",\n );\n }\n}\n\n// ─── CommandInteraction ───────────────────────────────────────────────────────\n\n/** Application command interaction with fully typed option resolver. */\nexport class CommandInteraction extends Interaction {\n /** Typed option resolver. Access slash command options with full type safety. */\n public readonly options: CommandOptions;\n\n /** Invoked command name. @returns Command name or an empty string. */ public get commandName(): string {\n return typeof this.data.data?.name === \"string\"\n ? this.data.data.name\n : \"\";\n }\n\n public constructor(client: InteractionClient, data: InteractionData) {\n super(client, data);\n const rawOptions =\n (data.data?.options as APIInteractionDataOption[]) ?? [];\n const resolved = (data.data?.resolved as Record<string, unknown>) ?? {};\n // Hand the resolver the *top-level* options. CommandOptions performs the\n // subcommand/group drill itself and records the names it walks through;\n // pre-drilling here would strip those wrappers before it sees them, so\n // getSubcommand()/getSubcommandGroup() would report null.\n this.options = new CommandOptions(rawOptions, resolved);\n }\n}\n\n// ─── ContextMenuCommandInteraction ───────────────────────────────────────────\n\n/** A user or message context-menu command, with what was right-clicked. */\nexport class ContextMenuCommandInteraction extends CommandInteraction {\n #resolved(): Record<string, Record<string, unknown> | undefined> {\n return (this.data.data?.resolved ?? {}) as Record<\n string,\n Record<string, unknown> | undefined\n >;\n }\n /** ID of the user or message the command was used on. */\n public get targetId(): string | null {\n const id = this.data.data?.target_id;\n return typeof id === \"string\" ? id : null;\n }\n /** The user a user command was used on. */\n public get targetUser(): User | null {\n const id = this.targetId;\n const raw = id ? this.#resolved().users?.[id] : undefined;\n return raw\n ? new User(raw as ConstructorParameters<typeof User>[0])\n : null;\n }\n /** The member a user command was used on (in a guild), with member actions when attached to a client. */\n public get targetMember(): GuildMember | null {\n const id = this.targetId;\n const raw = id ? this.#resolved().members?.[id] : undefined;\n const user = id ? this.#resolved().users?.[id] : undefined;\n if (!raw || !user || !this.guildId) return null;\n return new GuildMember(\n {\n ...(raw as Omit<\n ConstructorParameters<typeof GuildMember>[0],\n \"guild_id\" | \"user\"\n >),\n user: user as ConstructorParameters<\n typeof GuildMember\n >[0][\"user\"],\n guild_id: this.guildId,\n },\n this.resourceContext,\n );\n }\n /** The message a message command was used on. */\n public get targetMessage(): Message | null {\n const id = this.targetId;\n const raw = id ? this.#resolved().messages?.[id] : undefined;\n return raw\n ? new Message(\n raw as unknown as ConstructorParameters<typeof Message>[0],\n this.resourceContext,\n )\n : null;\n }\n}\n\n// ─── ComponentInteraction ─────────────────────────────────────────────────────\n\n/** Message component interaction. */\nexport class ComponentInteraction extends Interaction {\n /** Gets component custom ID. */\n public get customId(): string {\n const id = this.data.data?.custom_id;\n return typeof id === \"string\" ? id : \"\";\n }\n /** ID of the message the component is on. */\n public get messageId(): string | undefined {\n return (this.data.message as { id?: string } | undefined)?.id;\n }\n /** Gets component type. */\n public get componentType(): number {\n const type = this.data.data?.component_type;\n return typeof type === \"number\" ? type : 0;\n }\n /** Gets selected values for select menu component interactions. */\n public get values(): string[] {\n const values = this.data.data?.values;\n return Array.isArray(values) ? (values as string[]) : [];\n }\n /** Defers updating the message to which the component was attached. */\n public async deferUpdate(options: {\n withResponse: true;\n }): Promise<Message | null>;\n public async deferUpdate(options?: {\n withResponse?: boolean;\n }): Promise<void>;\n public async deferUpdate(\n options: { withResponse?: boolean } = {},\n ): Promise<Message | null | void> {\n const withResponse = options.withResponse === true;\n const result = await this.acknowledgeWith(\n new InteractionResponse(\n InteractionResponseEnum.DeferredMessageUpdate,\n ),\n \"deferred\",\n withResponse,\n );\n if (withResponse) return result as Message | null;\n }\n}\n\n// ─── ModalSubmitInteraction ───────────────────────────────────────────────────\n\n/** Represents a Discord modal submission interaction. */\nexport class ModalSubmitInteraction extends Interaction {\n /** Gets the submitted modal custom ID. */\n public get customId(): string {\n const id = this.data.data?.custom_id;\n return typeof id === \"string\" ? id : \"\";\n }\n\n /** Retrieves the text value for a specific text input custom ID. @param customId The custom_id of the text input component. @returns The submitted text, or undefined if not found. */\n public getInputValue(customId: string): string | undefined {\n const rows =\n (this.data.data?.components as\n | { components?: { custom_id?: string; value?: string }[] }[]\n | undefined) ?? [];\n for (const row of rows) {\n for (const comp of row.components ?? []) {\n if (comp.custom_id === customId) return comp.value;\n }\n }\n return undefined;\n }\n\n /** Retrieves the text value for a text input, throwing if missing. @param customId The custom_id of the text input component. @returns The submitted text. @throws {TypeError} If the field is not found. */\n public getRequiredInputValue(customId: string): string {\n const value = this.getInputValue(customId);\n if (value === undefined)\n throw new TypeError(\n `Modal input \"${customId}\" was not found in the submission.`,\n );\n return value;\n }\n}\n\n// ─── AutocompleteInteraction ──────────────────────────────────────────────────\n\n/** Represents a Discord slash command autocomplete interaction. */\nexport class AutocompleteInteraction extends Interaction {\n /** Option resolver; use `options.getFocused()` for the focused value. */\n public readonly options: CommandOptions;\n\n public constructor(client: InteractionClient, data: InteractionData) {\n super(client, data);\n this.options = new CommandOptions(\n (data.data?.options as APIInteractionDataOption[]) ?? [],\n );\n }\n\n /** Gets the target command name. */\n public get commandName(): string {\n const name = this.data.data?.name;\n return typeof name === \"string\" ? name : \"\";\n }\n\n /** Gets the currently focused autocomplete option. */\n public get focusedOption():\n { name: string; value: unknown; type: number } | undefined {\n const options = this.data.data?.options;\n return findFocused(\n Array.isArray(options) ? (options as FocusableOption[]) : [],\n );\n }\n\n /** Responds to Discord with autocomplete choices. @param choices Array of name/value pairs to show. @throws {TypeError} If choices is not an array. */\n public async respond(\n choices: { name: string; value: string | number }[],\n ): Promise<void> {\n if (!Array.isArray(choices))\n throw new TypeError(\"Autocomplete choices must be an array.\");\n const response = new InteractionResponse(\n InteractionResponseEnum.Autocomplete,\n { choices } as InteractionReplyOptions,\n );\n await this.acknowledge(response, \"replied\");\n }\n}\n\n/** An option as Discord sends it in autocomplete data. */\ninterface FocusableOption {\n name: string;\n value?: unknown;\n type: number;\n focused?: boolean;\n options?: FocusableOption[];\n}\n\n/** Recursively finds the focused option in a nested options tree. */\nfunction findFocused(\n options: FocusableOption[],\n): { name: string; value: unknown; type: number } | undefined {\n for (const opt of options) {\n if (opt.focused)\n return { name: opt.name, value: opt.value, type: opt.type };\n if (Array.isArray(opt.options)) {\n const found = findFocused(opt.options);\n if (found) return found;\n }\n }\n return undefined;\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\n/**\n * Creates a specialized interaction structure for a Gateway payload.\n * @param client Interaction transport.\n * @param data Gateway interaction payload.\n * @returns Specialized interaction structure.\n * @throws {TypeError} If required identifiers are missing.\n */\nexport function createInteraction(\n client: InteractionClient,\n data: InteractionData,\n): Interaction {\n switch (data.type) {\n case InteractionEnum.ApplicationCommand: {\n const commandType = data.data?.type;\n return commandType === COMMAND_USER ||\n commandType === COMMAND_MESSAGE\n ? new ContextMenuCommandInteraction(client, data)\n : new CommandInteraction(client, data);\n }\n case InteractionEnum.ApplicationCommandAutocomplete:\n return new AutocompleteInteraction(client, data);\n case InteractionEnum.MessageComponent:\n return new ComponentInteraction(client, data);\n case InteractionEnum.ModalSubmit:\n return new ModalSubmitInteraction(client, data);\n default:\n return new Interaction(client, data);\n }\n}\n\n/** @deprecated Use {@link InteractionEnum}. Removed in 0.3.0. */\nexport const InteractionType = InteractionEnum;\n/** @deprecated Use {@link InteractionEnum}. Removed in 0.3.0. */\nexport type InteractionType = InteractionEnum;\n",
|
|
26
|
-
"/** Resource structures for Discord messages and related entities. */\nimport { BaseStructure, Channel, User } from \"./base.js\";\nimport { GuildMember } from \"./resources.js\";\nimport type { ComponentInteraction } from \"./interactions.js\";\nimport type { Collector, CollectorOptions } from \"@lunibee/core\";\n\n/** Interaction tokens last 15 minutes, so a component collector with no limit of its own stops then. */\nconst COMPONENT_COLLECTOR_DEFAULT_TIME = 15 * 60_000;\n\n/** Options for {@link Message.createComponentCollector}. */\nexport interface ComponentCollectorOptions extends CollectorOptions<ComponentInteraction> {\n /** Only this component type (2 button, 3 string select...). */\n componentType?: number;\n}\nimport type { ResourceContext } from \"./base.js\";\n\n/** discord.js user-authored (non-system) message types: Default, Reply,\n * ChatInputCommand and ContextMenuCommand. Any other type is a system message. */\nconst NON_SYSTEM_MESSAGE_TYPES = new Set([0, 19, 20, 23]);\n\nexport {\n BaseStructure,\n Channel,\n Guild,\n User,\n CDN_BASE,\n cdnURL,\n} from \"./base.js\";\nexport type { ResourceContext, ImageURLOptions } from \"./base.js\";\n\nexport class Message extends BaseStructure {\n public content: string;\n public author: User;\n public channelId: string;\n public readonly channel: Channel;\n public guildId?: string;\n public flags: number;\n /** Message creation timestamp (from timestamp field or snowflake). */\n public readonly timestamp: Date;\n public readonly attachments: import(\"@lunibee/types\").APIAttachment[];\n public readonly embeds: import(\"@lunibee/types\").APIEmbed[];\n public readonly mentions: User[];\n public readonly mentionRoles: string[];\n public pinned: boolean;\n public mentionEveryone: boolean;\n public type: number;\n public readonly reference?: import(\"@lunibee/types\").APIMessageReference;\n public readonly components: import(\"@lunibee/types\").APIMessageComponent[];\n public readonly referencedMessage?: Message | null;\n /** Stickers sent with the message (`sticker_items`). */\n public readonly stickers: import(\"@lunibee/types\").APIStickerItem[];\n /** The poll, when the message is one. */\n public readonly poll: import(\"@lunibee/types\").APIPoll | null;\n /** For a forwarded message, the snapshot of the original. */\n public readonly messageSnapshots: import(\"@lunibee/types\").APIMessageSnapshot[];\n /**\n * The author as a guild member, on guild messages from the Gateway. Its\n * `permissions` are computed from the cached roles; `member.kick()` and the\n * other member actions work when the message came from a client.\n */\n public member: GuildMember | null;\n readonly #context?: ResourceContext;\n\n /** Creates a message structure from Discord message data. */\n public constructor(\n data: import(\"@lunibee/types\").APIMessage,\n context?: ResourceContext,\n ) {\n super(data.id);\n if (!/^\\d{1,20}$/.test(data.channel_id))\n throw new TypeError(\n \"Message channel_id must be a valid snowflake.\",\n );\n this.content = data.content ?? \"\";\n this.author = new User(data.author);\n this.channelId = data.channel_id;\n this.guildId = data.guild_id;\n this.flags = data.flags ?? 0;\n this.timestamp = new Date(\n data.timestamp ?? Number((BigInt(this.id) >> 22n) + 1420070400000n),\n );\n this.attachments = data.attachments ?? [];\n this.embeds = data.embeds ?? [];\n this.components = data.components ?? [];\n this.mentions = (data.mentions ?? []).map((user) => new User(user));\n this.mentionRoles = data.mention_roles ?? [];\n this.pinned = data.pinned ?? false;\n this.mentionEveryone = data.mention_everyone ?? false;\n this.type = data.type ?? 0;\n this.reference = data.message_reference;\n this.stickers =\n data.sticker_items ??\n (data.stickers ?? []).map(({ id, name, format_type }) => ({\n id,\n name,\n format_type,\n }));\n this.poll = data.poll ?? null;\n this.messageSnapshots = data.message_snapshots ?? [];\n this.referencedMessage = data.referenced_message\n ? new Message(data.referenced_message, context)\n : data.referenced_message === null\n ? null\n : undefined;\n this.#context = context;\n this.member =\n data.member && data.guild_id\n ? new GuildMember(\n {\n ...data.member,\n user: data.member.user ?? data.author,\n guild_id: data.guild_id,\n },\n context,\n )\n : null;\n this.channel = new Channel(\n { id: data.channel_id, type: 0, guild_id: data.guild_id },\n context,\n );\n }\n\n /** Whether embeds are suppressed on this message. */\n public get embedsSuppressed(): boolean {\n return (this.flags & 4) !== 0;\n }\n\n /** Unix timestamp (ms) at which the message was created — discord.js parity.\n * Derived from the message `timestamp`, which itself falls back to the id snowflake. */\n public get createdTimestamp(): number {\n return this.timestamp.getTime();\n }\n\n /** Date at which the message was created — discord.js parity. Overrides the\n * snowflake-only `BaseStructure.createdAt` to honour the message `timestamp`. */\n public override get createdAt(): Date {\n return this.timestamp;\n }\n\n /** Edits this message. @param options Message fields to change. @returns The updated message. @throws {Error} If the message is not attached to a client. */\n public edit(\n options: Record<string, unknown> & { content?: string },\n ): Promise<Message> {\n if (!this.#context)\n throw new Error(\"This message is not attached to a client.\");\n return this.#context.editMessage(this.channelId, this.id, options);\n }\n\n /** Updates this message using the same resource operation as edit. @param options Message fields to change. @returns The updated message. @throws {Error} If the message is not attached to a client. */\n public update(\n options: Record<string, unknown> & { content?: string },\n ): Promise<Message> {\n return this.edit(options);\n }\n\n /** Deletes this message. @param reason Audit-log reason (shown when deleting someone else's message). @returns A promise fulfilled when Discord confirms deletion. @throws {Error} If the message is not attached to a client. */\n public delete(reason?: string): Promise<void> {\n if (!this.#context)\n throw new Error(\"This message is not attached to a client.\");\n return this.#context.deleteMessage(this.channelId, this.id, reason);\n }\n\n /** Replies to this message. @param options Message content or payload. @returns The created reply message. @throws {Error} If the message is not attached to a client. */\n public reply(\n options: string | (Record<string, unknown> & { content?: string }),\n ): Promise<Message> {\n if (!this.#context)\n throw new Error(\"This message is not attached to a client.\");\n const payload =\n typeof options === \"string\" ? { content: options } : { ...options };\n payload.message_reference = {\n message_id: this.id,\n channel_id: this.channelId,\n guild_id: this.guildId,\n };\n return this.#context.sendMessage(this.channelId, payload);\n }\n\n /** Crossposts this message. @returns The resulting message. @throws {Error} If the message is not attached to a client. */\n public crosspost(): Promise<Message> {\n if (!this.#context)\n throw new Error(\"This message is not attached to a client.\");\n return this.#context.crosspostMessage(this.channelId, this.id);\n }\n\n /**\n * Collects clicks and picks on this message's components. It always ends:\n * after `time`, or 15 minutes (an interaction token's life) when neither\n * `time` nor `idle` is set.\n * @example\n * const collector = message.createComponentCollector({ filter: (i) => i.user?.id === authorId, time: 60_000 });\n * collector.on(\"collect\", (i) => i.update({ content: `Picked ${i.customId}` }));\n */\n public createComponentCollector(\n options: ComponentCollectorOptions = {},\n ): Collector<string, ComponentInteraction> {\n const collect = this.#context?.collectInteractions;\n if (!collect)\n throw new Error(\"This message is not attached to a client.\");\n const { componentType, filter, ...rest } = options;\n return collect({\n ...rest,\n time:\n rest.time ??\n (rest.idle ? undefined : COMPONENT_COLLECTOR_DEFAULT_TIME),\n filter: async (interaction) =>\n interaction.isMessageComponent() &&\n interaction.messageId === this.id &&\n (componentType === undefined ||\n interaction.componentType === componentType) &&\n (filter ? await filter(interaction) : true),\n }) as unknown as Collector<string, ComponentInteraction>;\n }\n\n /**\n * Waits for the next click or pick on this message's components.\n * @param options `time` (default 15 minutes), `filter`, `componentType`.\n * @returns The interaction. @throws {Error} When time runs out first.\n */\n public awaitComponent(\n options: Omit<ComponentCollectorOptions, \"max\"> = {},\n ): Promise<ComponentInteraction> {\n return this.createComponentCollector({ ...options, max: 1 }).next();\n }\n\n /** Adds a reaction to this message. @param emoji Emoji identifier. @returns A promise fulfilled when the reaction is added. @throws {Error} If reactions are unavailable. */\n public react(emoji: string): Promise<void> {\n if (!this.#context?.addReaction)\n throw new Error(\"This message is not attached to a client.\");\n return this.#context.addReaction(this.channelId, this.id, emoji);\n }\n\n /** Removes a reaction from this message. @param emoji Emoji identifier. @param userId User whose reaction should be removed; omit to remove the current user's reaction. @returns A promise fulfilled when the reaction is removed. @throws {Error} If reaction operations are unavailable. */\n public removeReaction(emoji: string, userId?: string): Promise<void> {\n if (!this.#context)\n throw new Error(\"This message is not attached to a client.\");\n return userId\n ? (this.#context.removeReaction?.(\n this.channelId,\n this.id,\n emoji,\n userId,\n ) ??\n Promise.reject(\n new Error(\"Reaction operations are unavailable.\"),\n ))\n : (this.#context.removeOwnReaction?.(\n this.channelId,\n this.id,\n emoji,\n ) ??\n Promise.reject(\n new Error(\"Reaction operations are unavailable.\"),\n ));\n }\n\n /** Removes all reactions from this message. @returns A promise fulfilled when reactions are removed. @throws {Error} If reaction operations are unavailable. */\n public removeAllReactions(): Promise<void> {\n if (!this.#context?.removeAllReactions)\n throw new Error(\"This message is not attached to a client.\");\n return this.#context.removeAllReactions(this.channelId, this.id);\n }\n\n /** Pins this message. @param reason Audit-log reason. @returns A promise fulfilled when the message is pinned. @throws {Error} If pin operations are unavailable. */\n public pin(reason?: string): Promise<void> {\n if (!this.#context?.pinMessage)\n throw new Error(\"This message is not attached to a client.\");\n return this.#context.pinMessage(this.channelId, this.id, reason);\n }\n\n /** Unpins this message. @param reason Audit-log reason. @returns A promise fulfilled when the message is unpinned. @throws {Error} If pin operations are unavailable. */\n public unpin(reason?: string): Promise<void> {\n if (!this.#context?.unpinMessage)\n throw new Error(\"This message is not attached to a client.\");\n return this.#context.unpinMessage(this.channelId, this.id, reason);\n }\n\n // ─── Flag-based getters ───────────────────────────────────────────────────────\n\n /** Whether this message was sent ephemerally (only visible to the recipient). */\n public get isEphemeral(): boolean {\n return (this.flags & 64) !== 0;\n }\n\n /** Whether this message is currently pinned in its channel. */\n public get isPinned(): boolean {\n return this.pinned;\n }\n\n /** Whether this is a system-generated message (join, boost, etc). Mirrors\n * discord.js: a message is \"system\" unless its type is one of the user-authored\n * types — Default (0), Reply (19), ChatInputCommand (20) or ContextMenuCommand (23). */\n public get isSystemMessage(): boolean {\n return !NON_SYSTEM_MESSAGE_TYPES.has(this.type);\n }\n\n /** Whether this message was crossposted from an announcement channel. */\n public get isCrosspost(): boolean {\n return (this.flags & 2) !== 0;\n }\n\n /** Whether this message has file attachments. */\n public get hasAttachments(): boolean {\n return this.attachments.length > 0;\n }\n\n /** Whether this message contains embeds. */\n public get hasEmbeds(): boolean {\n return this.embeds.length > 0;\n }\n\n /** Whether this message contains interactive components. */\n public get hasComponents(): boolean {\n return this.components.length > 0;\n }\n\n /** Edits this message to suppress its embeds. @returns The updated message. */\n public suppressEmbeds(): Promise<Message> {\n return this.edit({ flags: this.flags | 4 });\n }\n\n /** Returns a plain-object snapshot of all message fields. */\n public toJSON(): Record<string, unknown> {\n return {\n id: this.id,\n content: this.content,\n channelId: this.channelId,\n guildId: this.guildId,\n flags: this.flags,\n pinned: this.pinned,\n mentionEveryone: this.mentionEveryone,\n type: this.type,\n timestamp: this.timestamp.toISOString(),\n author: { id: this.author.id, username: this.author.username },\n attachments: [...this.attachments],\n embeds: [...this.embeds],\n components: [...this.components],\n mentions: this.mentions.map((u) => u.id),\n mentionRoles: [...this.mentionRoles],\n reference: this.reference,\n referencedMessage: this.referencedMessage\n ? this.referencedMessage.id\n : this.referencedMessage,\n };\n }\n}\n\nexport {\n GuildMember,\n Role,\n TextChannel,\n Invite,\n Webhook,\n WebhookEnum,\n WebhookType,\n Emoji,\n AutoModerationRule,\n WelcomeScreenChannel,\n GuildWelcomeScreen,\n OnboardingPromptOption,\n OnboardingPrompt,\n GuildOnboarding,\n} from \"./resources.js\";\nexport {\n NewsChannel,\n DMChannel,\n VoiceChannel,\n StageChannel,\n CategoryChannel,\n ThreadChannel,\n ForumChannel,\n MediaChannel,\n createChannel,\n} from \"./channels.js\";\nexport * from \"./interactions.js\";\nexport { Embed } from \"./embed.js\";\nexport { AuditLog, AuditLogEntry } from \"./audit-log.js\";\n// KI-4: PermissionsBitField lives canonically in @lunibee/core (single source of\n// truth). Re-export it here for discord.js-style top-level access from structures,\n// replacing the former structures-local duplicate.\nexport { PermissionsBitField } from \"@lunibee/core\";\n",
|
|
27
|
-
"import { Collection } from \"@lunibee/collection\";\n\n/** Opt-in per-channel message cache. Messages are temporary data, so they\n * use bounded TTL/LRU storage rather than permanent resource storage. */\nexport interface MessageCacheOptions {\n /** Messages kept per channel; least-recently-used are evicted. Default 100. */\n maxSize?: number;\n /** Sliding TTL in ms. Omit for no expiry. */\n ttl?: number;\n}\nimport { REST, Routes } from \"@lunibee/rest\";\nimport { Message, type ResourceContext } from \"@lunibee/structures\";\n\n/** A file to upload with a message. */\nexport interface MessageFile {\n name: string;\n data: Blob | Uint8Array | ArrayBuffer | string;\n contentType?: string;\n}\n\nexport type MessageCreateOptions = Record<string, unknown> & {\n content?: string;\n /** Files to upload; the message is sent as multipart. */\n files?: MessageFile[];\n};\nexport type MessageEditOptions = MessageCreateOptions;\n\n/**\n * Splits `files` out of a message payload into a REST upload, encoding string\n * data as UTF-8. `allowedMentions` is the client's default, applied only when\n * the payload has no `allowed_mentions` of its own.\n */\nexport function toRequest(\n options: MessageCreateOptions,\n allowedMentions?:
|
|
28
|
-
"import { REST, Routes } from \"@lunibee/rest\";\nimport {\n Channel,\n createChannel,\n type ResourceContext,\n} from \"@lunibee/structures\";\n\n/** Manages thread resources created from a parent channel. */\nexport class ThreadManager {\n readonly #rest: REST;\n readonly #context: ResourceContext;\n readonly #channelId: string;\n /** Creates a thread manager. @param rest REST transport. @param context Structure resource context. @param channelId Parent channel identifier. @throws {TypeError} If channelId is empty. */\n public constructor(\n rest: REST,\n context: ResourceContext,\n channelId: string,\n ) {\n if (!channelId) throw new TypeError(\"Channel ID is required.\");\n this.#rest = rest;\n this.#context = context;\n this.#channelId = channelId;\n }\n /** Creates a thread from a message. @param messageId Message identifier. @param options Thread creation options. @returns Created thread channel. @throws {Error} If REST rejects the request. */\n public async createFromMessage(\n messageId: string,\n options: {\n name: string;\n autoArchiveDuration?: 60 | 1440 | 4320 | 10080;\n rateLimitPerUser?: number;\n },\n ): Promise<Channel> {\n const data = await this.#rest.post<\n ConstructorParameters<typeof Channel>[0]\n >(Routes.messageThread(this.#channelId, messageId), {\n name: options.name,\n auto_archive_duration: options.autoArchiveDuration,\n rate_limit_per_user: options.rateLimitPerUser,\n });\n return createChannel(data, this.#context);\n }\n}\n",
|
|
29
|
-
"import { ResourceManager } from \"./base.js\";\nimport { User } from \"@lunibee/structures\";\nimport { type REST, Routes } from \"@lunibee/rest\";\nimport type { APIChannel } from \"@lunibee/types\";\n\ntype UserData = ConstructorParameters<typeof User>[0];\n\nexport interface UserEditOptions {\n username?: string;\n avatar?: string | null;\n}\n\nexport class UserManager extends ResourceManager<string, User> {\n readonly #rest: REST;\n public constructor(rest: REST) {\n super(\n async (id) =>\n new User(await rest.get<UserData>(Routes.userById(id))),\n (user) => user.id,\n );\n this.#rest = rest;\n }\n\n /** Gets the currently logged-in bot user. */\n public async fetchMe(): Promise<User> {\n const data = await this.#rest.get<UserData>(\"/users/@me\");\n return this.upsert(new User(data));\n }\n\n /** Modifies the currently logged-in bot user. */\n public async editMe(options: UserEditOptions): Promise<User> {\n const data = await this.#rest.patch<UserData>(\"/users/@me\", options);\n return this.upsert(new User(data));\n }\n\n /** Leaves a guild. */\n public async leaveGuild(guildId: string): Promise<void> {\n await this.#rest.delete(
|
|
30
|
-
"import { Manager, splitReason } from \"./base.js\";\nimport { Emoji } from \"@lunibee/structures\";\nimport { Routes, type REST } from \"@lunibee/rest\";\n\n/** Strict payload for creating a custom guild emoji. */\nexport interface EmojiCreateOptions {\n /** Audit-log reason. */\n reason?: string;\n /** Emoji name (1-32 chars, alphanumeric + underscores). */\n name: string;\n /** Base64-encoded 128x128 image data URI. */\n image: string;\n /** Role IDs allowed to use the emoji. */\n roles?: string[];\n}\n\n/** Strict payload for editing a custom guild emoji. */\nexport interface EmojiEditOptions {\n /** Audit-log reason. */\n reason?: string;\n /** New emoji name. */\n name?: string;\n /** Role IDs allowed to use the emoji. */\n roles?: string[];\n}\n\n/** Manages custom emojis for a guild. */\nexport class EmojiManager extends Manager<string, Emoji> {\n readonly #rest: REST;\n readonly #guildId: string;\n\n public constructor(rest: REST, guildId: string) {\n super();\n this.#rest = rest;\n this.#guildId = guildId;\n }\n\n /** Fetches an emoji by ID; concurrent fetches share a request and a stale result never overwrites newer state. */\n public fetch(emojiId: string): Promise<Emoji> {\n return this.fetchOnce(\n emojiId,\n async () =>\n new Emoji(\n await this.#rest.get<\n ConstructorParameters<typeof Emoji>[0]\n >(Routes.guildEmoji(this.#guildId, emojiId)),\n ),\n (emoji) => this.#merge(emojiId, emoji),\n );\n }\n\n /** Fetches all emojis for this guild. */\n public async fetchAll(): Promise<Emoji[]> {\n const data = await this.#rest.get<\n ConstructorParameters<typeof Emoji>[0][]\n >(Routes.guildEmoji(this.#guildId));\n return data.map((item) => this.upsert(item));\n }\n\n /** Creates a new custom emoji. */\n public async create(options: EmojiCreateOptions): Promise<Emoji> {\n const [payload, reason] = splitReason(options);\n return this.upsert(\n await this.#rest.post<ConstructorParameters<typeof Emoji>[0]>(\n Routes.guildEmoji(this.#guildId),\n payload,\n { reason },\n ),\n );\n }\n\n /** Edits an existing custom emoji. */\n public async edit(\n emojiId: string,\n options: EmojiEditOptions,\n ): Promise<Emoji> {\n const [payload, reason] = splitReason(options);\n return this.upsert(\n await this.#rest.patch<ConstructorParameters<typeof Emoji>[0]>(\n Routes.guildEmoji(this.#guildId, emojiId),\n payload,\n { reason },\n ),\n );\n }\n\n /** Deletes a custom emoji. @param reason Audit-log reason. */\n public async remove(emojiId: string, reason?: string): Promise<void> {\n await this.#rest.delete(Routes.guildEmoji(this.#guildId, emojiId), {\n reason,\n });\n this.delete(emojiId);\n }\n\n /** @deprecated Use {@link EmojiManager.remove}, which also takes an audit-log reason. Removed in 0.3.0. */\n public deleteEmoji(emojiId: string): Promise<void> {\n return this.remove(emojiId);\n }\n\n /** Upserts an emoji into the manager cache. Custom emojis are keyed by their\n * snowflake ID; unicode emojis (no ID) are keyed by `unicode:${name}` so repeated\n * upserts reuse the same cached instance instead of allocating a new one each call. */\n public upsert(data: ConstructorParameters<typeof Emoji>[0]): Emoji {\n const key = data.id != null ? data.id : `unicode:${data.name ?? \"\"}`;\n return this.#merge(key, new Emoji(data));\n }\n\n #merge(key: string, emoji: Emoji): Emoji {\n const existing = this.get(key);\n if (existing) {\n Object.assign(existing, emoji);\n return existing;\n }\n this.set(key, emoji);\n return emoji;\n }\n}\n",
|
|
31
|
-
"import { Manager } from \"./base.js\";\nimport { Routes, type REST } from \"@lunibee/rest\";\nimport type {\n APIEntitlement,\n APISKU,\n APISoundboardSound,\n APISticker,\n APISubscription,\n} from \"@lunibee/types\";\n\nexport type {\n APIEntitlement,\n APISKU,\n APISoundboardSound,\n APISubscription,\n} from \"@lunibee/types\";\n\n/** Appends encoded query parameters, skipping undefined values. */\nfunction withQuery(\n path: string,\n query: Record<string, string | number | boolean | undefined>,\n): string {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query))\n if (value !== undefined) params.set(key, String(value));\n const suffix = params.toString();\n return suffix ? `${path}?${suffix}` : path;\n}\n\n// ─── Stickers ────────────────────────────────────────────────────────────────\n\n/** Fields for {@link GuildStickerManager.create}. */\nexport interface GuildStickerCreateOptions {\n name: string;\n description: string;\n /** Autocomplete/suggestion tags (e.g. an emoji name). */\n tags: string;\n /** PNG, APNG, GIF or Lottie JSON file, max 512 KiB. */\n file: Blob;\n reason?: string;\n}\n\n/** Manages a guild's custom stickers, cached by sticker ID. */\nexport class GuildStickerManager extends Manager<string, APISticker> {\n readonly #rest: REST;\n public readonly guildId: string;\n\n public constructor(rest: REST, guildId: string) {\n super();\n this.#rest = rest;\n this.guildId = guildId;\n }\n\n #store(sticker: APISticker): APISticker {\n this.set(sticker.id, sticker);\n return sticker;\n }\n\n /** Fetches every sticker in the guild, replacing the cache. */\n public async fetchAll(): Promise<APISticker[]> {\n const stickers = await this.#rest.get<APISticker[]>(\n Routes.guildSticker(this.guildId),\n );\n this.clear();\n return stickers.map((sticker) => this.#store(sticker));\n }\n\n /** Fetches one sticker. */\n public async fetch(stickerId: string): Promise<APISticker> {\n return this.#store(\n await this.#rest.get<APISticker>(\n Routes.guildSticker(this.guildId, stickerId),\n ),\n );\n }\n\n /** Uploads a sticker (multipart form, as Discord requires). */\n public async create(\n options: GuildStickerCreateOptions,\n ): Promise<APISticker> {\n const form = new FormData();\n form.set(\"name\", options.name);\n form.set(\"description\", options.description);\n form.set(\"tags\", options.tags);\n form.set(\"file\", options.file);\n return this.#store(\n await this.#rest.post<APISticker>(\n Routes.guildSticker(this.guildId),\n form,\n { reason: options.reason },\n ),\n );\n }\n\n /** Edits a sticker's name, description or tags. */\n public async edit(\n stickerId: string,\n options: {\n name?: string;\n description?: string | null;\n tags?: string;\n reason?: string;\n },\n ): Promise<APISticker> {\n const { reason, ...body } = options;\n return this.#store(\n await this.#rest.patch<APISticker>(\n Routes.guildSticker(this.guildId, stickerId),\n body,\n { reason },\n ),\n );\n }\n\n /** Deletes a sticker. */\n public async remove(stickerId: string, reason?: string): Promise<void> {\n await this.#rest.delete(Routes.guildSticker(this.guildId, stickerId), {\n reason,\n });\n this.delete(stickerId);\n }\n\n /** Replaces the cache with the full list from a `GUILD_STICKERS_UPDATE` event. */\n public sync(stickers: readonly APISticker[]): void {\n this.clear();\n for (const sticker of stickers) this.#store(sticker);\n }\n}\n\n// ─── Soundboard ──────────────────────────────────────────────────────────────\n\n/** Fields for {@link GuildSoundboardManager.create}. */\nexport interface SoundboardSoundCreateOptions {\n name: string;\n /** Data URI of an MP3 or OGG file (max 512 KiB, 5.2 s). */\n sound: string;\n /** 0 to 1; defaults to 1. */\n volume?: number;\n emojiId?: string;\n emojiName?: string;\n reason?: string;\n}\n\n/** Manages a guild's soundboard sounds, cached by sound ID. */\nexport class GuildSoundboardManager extends Manager<\n string,\n APISoundboardSound\n> {\n readonly #rest: REST;\n public readonly guildId: string;\n\n public constructor(rest: REST, guildId: string) {\n super();\n this.#rest = rest;\n this.guildId = guildId;\n }\n\n #store(sound: APISoundboardSound): APISoundboardSound {\n this.set(sound.sound_id, sound);\n return sound;\n }\n\n /** Fetches every soundboard sound in the guild, replacing the cache. */\n public async fetchAll(): Promise<APISoundboardSound[]> {\n const { items } = await this.#rest.get<{\n items: APISoundboardSound[];\n }>(Routes.guildSoundboardSound(this.guildId));\n this.clear();\n return items.map((sound) => this.#store(sound));\n }\n\n /** Fetches one sound. */\n public async fetch(soundId: string): Promise<APISoundboardSound> {\n return this.#store(\n await this.#rest.get<APISoundboardSound>(\n Routes.guildSoundboardSound(this.guildId, soundId),\n ),\n );\n }\n\n /** Creates a sound. */\n public async create(\n options: SoundboardSoundCreateOptions,\n ): Promise<APISoundboardSound> {\n if (\n options.volume !== undefined &&\n (options.volume < 0 || options.volume > 1)\n )\n throw new RangeError(\"Soundboard volume must be between 0 and 1.\");\n return this.#store(\n await this.#rest.post<APISoundboardSound>(\n Routes.guildSoundboardSound(this.guildId),\n {\n name: options.name,\n sound: options.sound,\n volume: options.volume,\n emoji_id: options.emojiId,\n emoji_name: options.emojiName,\n },\n { reason: options.reason },\n ),\n );\n }\n\n /** Edits a sound's name, volume or emoji. */\n public async edit(\n soundId: string,\n options: {\n name?: string;\n volume?: number | null;\n emojiId?: string | null;\n emojiName?: string | null;\n reason?: string;\n },\n ): Promise<APISoundboardSound> {\n return this.#store(\n await this.#rest.patch<APISoundboardSound>(\n Routes.guildSoundboardSound(this.guildId, soundId),\n {\n name: options.name,\n volume: options.volume,\n emoji_id: options.emojiId,\n emoji_name: options.emojiName,\n },\n { reason: options.reason },\n ),\n );\n }\n\n /** Deletes a sound. */\n public async remove(soundId: string, reason?: string): Promise<void> {\n await this.#rest.delete(\n Routes.guildSoundboardSound(this.guildId, soundId),\n { reason },\n );\n this.delete(soundId);\n }\n}\n\n// ─── Monetization ────────────────────────────────────────────────────────────\n\n/** Filters for {@link MonetizationManager.fetchEntitlements}. */\nexport interface EntitlementQuery {\n userId?: string;\n skuIds?: string[];\n guildId?: string;\n before?: string;\n after?: string;\n /** 1-100, default 100. */\n limit?: number;\n excludeEnded?: boolean;\n excludeDeleted?: boolean;\n}\n\n/**\n * SKUs, entitlements and subscriptions for one application. Entitlements are\n * cached by ID and kept current by the client's `ENTITLEMENT_*` events.\n */\nexport class MonetizationManager extends Manager<string, APIEntitlement> {\n readonly #rest: REST;\n public readonly applicationId: string;\n\n public constructor(rest: REST, applicationId: string) {\n super();\n this.#rest = rest;\n this.applicationId = applicationId;\n }\n\n /** Fetches the application's SKUs. */\n public fetchSkus(): Promise<APISKU[]> {\n return this.#rest.get<APISKU[]>(\n Routes.applicationSkus(this.applicationId),\n );\n }\n\n /** Fetches entitlements matching the filters and caches them. */\n public async fetchEntitlements(\n query: EntitlementQuery = {},\n ): Promise<APIEntitlement[]> {\n if (\n query.limit !== undefined &&\n (!Number.isInteger(query.limit) ||\n query.limit < 1 ||\n query.limit > 100)\n )\n throw new RangeError(\"Entitlement limit must be 1-100.\");\n const entitlements = await this.#rest.get<APIEntitlement[]>(\n withQuery(Routes.applicationEntitlement(this.applicationId), {\n user_id: query.userId,\n sku_ids: query.skuIds?.join(\",\"),\n guild_id: query.guildId,\n before: query.before,\n after: query.after,\n limit: query.limit,\n exclude_ended: query.excludeEnded,\n exclude_deleted: query.excludeDeleted,\n }),\n );\n for (const entitlement of entitlements)\n this.set(entitlement.id, entitlement);\n return entitlements;\n }\n\n /** Fetches one entitlement. */\n public async fetch(entitlementId: string): Promise<APIEntitlement> {\n const entitlement = await this.#rest.get<APIEntitlement>(\n Routes.applicationEntitlement(this.applicationId, entitlementId),\n );\n this.set(entitlement.id, entitlement);\n return entitlement;\n }\n\n /** Marks a one-time-purchase entitlement as consumed. */\n public async consume(entitlementId: string): Promise<void> {\n await this.#rest.post(\n Routes.consumeEntitlement(this.applicationId, entitlementId),\n );\n const cached = this.get(entitlementId);\n if (cached) cached.consumed = true;\n }\n\n /** Creates a test entitlement for a user or guild (owner type 1 = guild, 2 = user). */\n public async createTestEntitlement(options: {\n skuId: string;\n ownerId: string;\n ownerType: 1 | 2;\n }): Promise<APIEntitlement> {\n const entitlement = await this.#rest.post<APIEntitlement>(\n Routes.applicationEntitlement(this.applicationId),\n {\n sku_id: options.skuId,\n owner_id: options.ownerId,\n owner_type: options.ownerType,\n },\n );\n this.set(entitlement.id, entitlement);\n return entitlement;\n }\n\n /** Deletes a test entitlement. */\n public async deleteTestEntitlement(entitlementId: string): Promise<void> {\n await this.#rest.delete(\n Routes.applicationEntitlement(this.applicationId, entitlementId),\n );\n this.delete(entitlementId);\n }\n\n /** Fetches a SKU's subscriptions for a user, or one subscription. */\n public fetchSubscriptions(\n skuId: string,\n query: {\n userId?: string;\n before?: string;\n after?: string;\n limit?: number;\n } = {},\n ): Promise<APISubscription[]> {\n return this.#rest.get<APISubscription[]>(\n withQuery(Routes.skuSubscription(skuId), {\n user_id: query.userId,\n before: query.before,\n after: query.after,\n limit: query.limit,\n }),\n );\n }\n\n /** Fetches one subscription. */\n public fetchSubscription(\n skuId: string,\n subscriptionId: string,\n ): Promise<APISubscription> {\n return this.#rest.get<APISubscription>(\n Routes.skuSubscription(skuId, subscriptionId),\n );\n }\n}\n",
|
|
32
|
-
"import { REST, Routes } from \"@lunibee/rest\";\nimport { GuildMember, type ResourceContext } from \"@lunibee/structures\";\nimport { ResourceManager, splitReason } from \"./base.js\";\n\nexport interface MemberEditOptions {\n /** Audit-log reason. */\n reason?: string;\n nick?: string | null;\n roles?: string[];\n mute?: boolean;\n deaf?: boolean;\n channel_id?: string | null;\n communication_disabled_until?: string | null;\n}\n\nexport interface BanOptions {\n reason?: string;\n deleteMessageSeconds?: number;\n}\n\n/** Manages Discord guild members. */\nexport class GuildMemberManager extends ResourceManager<string, GuildMember> {\n readonly #rest: REST;\n readonly #context: () => ResourceContext | undefined;\n public readonly guildId: string;\n\n /** @param context Gives fetched members their actions (`member.kick()`...). */\n public constructor(\n guildId: string,\n rest: REST,\n context: () => ResourceContext | undefined = () => undefined,\n ) {\n super(\n (id: string) =>\n rest\n .get(Routes.guildMember(guildId, id))\n .then(\n (data
|
|
33
|
-
"import { REST, Routes } from \"@lunibee/rest\";\nimport { Role } from \"@lunibee/structures\";\nimport { ResourceManager } from \"./base.js\";\n\nexport interface RoleCreateOptions {\n name: string;\n permissions?: bigint | number | string;\n color?: number;\n hoist?: boolean;\n mentionable?: boolean;\n reason?: string;\n}\n\nexport interface RoleEditOptions {\n name?: string;\n permissions?: bigint | number | string;\n color?: number;\n hoist?: boolean;\n mentionable?: boolean;\n position?: number;\n reason?: string;\n}\n\n/** Manages Discord guild roles. */\nexport class RoleManager extends ResourceManager<string, Role> {\n readonly #rest: REST;\n public readonly guildId: string;\n\n public constructor(guildId: string, rest: REST) {\n super(\n (id: string) =>\n rest\n .get(Routes.guildRole(guildId, id))\n .then((data
|
|
34
|
-
"import { Manager, splitReason } from \"./base.js\";\nimport { Routes, type REST } from \"@lunibee/rest\";\nimport type {\n APIChannel,\n APIOverwrite,\n APIGuildScheduledEvent,\n APIStageInstance,\n UserData,\n} from \"@lunibee/types\";\n\n/** Raw Discord ban object. */\nexport interface APIBan {\n user: UserData;\n reason: string | null;\n}\n\n/** Options for {@link GuildBanManager.create}. */\nexport interface GuildBanCreateOptions {\n /** Seconds of message history to delete (0-604800). */\n deleteMessageSeconds?: number;\n /** Audit-log reason. */\n reason?: string;\n}\n\n/** Appends encoded query parameters to a route. */\nfunction withQuery(path: string, params: Record<string, unknown>): string {\n const query = new URLSearchParams();\n for (const [key, value] of Object.entries(params))\n if (value !== undefined) query.set(key, String(value));\n const suffix = query.toString();\n return suffix ? `${path}?${suffix}` : path;\n}\n\n/** Manages a guild's bans, cached by user ID. Discord.js-familiar. */\nexport class GuildBanManager extends Manager<string, APIBan> {\n readonly #rest: REST;\n public readonly guildId: string;\n\n public constructor(rest: REST, guildId: string) {\n super();\n this.#rest = rest;\n this.guildId = guildId;\n }\n\n /** Fetches one ban. */\n public async fetch(userId: string): Promise<APIBan> {\n const ban = await this.#rest.get<APIBan>(\n Routes.guildBan(this.guildId, userId),\n );\n this.set(ban.user.id, ban);\n return ban;\n }\n\n /** Fetches a page of bans (`limit` 1-1000, `before`/`after` user-ID cursors). */\n public async fetchAll(\n options: { limit?: number; before?: string; after?: string } = {},\n ): Promise<APIBan[]> {\n const limit =\n options.limit === undefined\n ? undefined\n : Math.min(1000, Math.max(1, options.limit));\n const bans = await this.#rest.get<APIBan[]>(\n withQuery(Routes.guildBans(this.guildId), {\n limit,\n before: options.before,\n after: options.after,\n }),\n );\n for (const ban of bans) this.set(ban.user.id, ban);\n return bans;\n }\n\n /** Bans a user. */\n public async create(\n userId: string,\n options: GuildBanCreateOptions = {},\n ): Promise<void> {\n await this.#rest.put(\n Routes.guildBan(this.guildId, userId),\n { delete_message_seconds: options.deleteMessageSeconds },\n { reason: options.reason },\n );\n }\n\n /** Lifts a ban. */\n public async remove(userId: string, reason?: string): Promise<void> {\n await this.#rest.delete(Routes.guildBan(this.guildId, userId), {\n reason,\n });\n this.delete(userId);\n }\n}\n\n/** Fields accepted when creating or editing a scheduled event. */\nexport type GuildScheduledEventOptions = Partial<\n Omit<APIGuildScheduledEvent, \"id\" | \"guild_id\" | \"creator\" | \"user_count\">\n> &\n Record<string, unknown> & {\n /** Audit-log reason. */\n reason?: string;\n };\n\n/** Manages a guild's scheduled events, cached by event ID. Discord.js-familiar. */\nexport class GuildScheduledEventManager extends Manager<\n string,\n APIGuildScheduledEvent\n> {\n readonly #rest: REST;\n public readonly guildId: string;\n\n public constructor(rest: REST, guildId: string) {\n super();\n this.#rest = rest;\n this.guildId = guildId;\n }\n\n #store(event: APIGuildScheduledEvent): APIGuildScheduledEvent {\n this.set(event.id, event);\n return event;\n }\n\n /** Fetches one event. */\n public async fetch(\n eventId: string,\n options: { withUserCount?: boolean } = {},\n ): Promise<APIGuildScheduledEvent> {\n return this.#store(\n await this.#rest.get(\n withQuery(Routes.guildScheduledEvent(this.guildId, eventId), {\n with_user_count: options.withUserCount,\n }),\n ),\n );\n }\n\n /** Fetches every event in the guild. */\n public async fetchAll(\n options: { withUserCount?: boolean } = {},\n ): Promise<APIGuildScheduledEvent[]> {\n const events = await this.#rest.get<APIGuildScheduledEvent[]>(\n withQuery(Routes.guildScheduledEvents(this.guildId), {\n with_user_count: options.withUserCount,\n }),\n );\n return events.map((event) => this.#store(event));\n }\n\n /** Creates an event. */\n public async create(\n options: GuildScheduledEventOptions,\n reason?: string,\n ): Promise<APIGuildScheduledEvent> {\n const [payload, optionsReason] = splitReason(options);\n return this.#store(\n await this.#rest.post(\n Routes.guildScheduledEvents(this.guildId),\n payload,\n { reason: optionsReason ?? reason },\n ),\n );\n }\n\n /** Edits an event. */\n public async edit(\n eventId: string,\n options: GuildScheduledEventOptions,\n reason?: string,\n ): Promise<APIGuildScheduledEvent> {\n const [payload, optionsReason] = splitReason(options);\n return this.#store(\n await this.#rest.patch(\n Routes.guildScheduledEvent(this.guildId, eventId),\n payload,\n { reason: optionsReason ?? reason },\n ),\n );\n }\n\n /** Deletes an event. @param reason Audit-log reason. */\n public async remove(eventId: string, reason?: string): Promise<void> {\n await this.#rest.delete(\n Routes.guildScheduledEvent(this.guildId, eventId),\n { reason },\n );\n this.delete(eventId);\n }\n\n /** Fetches users subscribed to an event (`limit` 1-100). */\n public async fetchSubscribers(\n eventId: string,\n options: {\n limit?: number;\n withMember?: boolean;\n before?: string;\n after?: string;\n } = {},\n ): Promise<{ guild_scheduled_event_id: string; user: UserData }[]> {\n const limit =\n options.limit === undefined\n ? undefined\n : Math.min(100, Math.max(1, options.limit));\n return this.#rest.get(\n withQuery(Routes.guildScheduledEventUsers(this.guildId, eventId), {\n limit,\n with_member: options.withMember,\n before: options.before,\n after: options.after,\n }),\n );\n }\n}\n\n/** Options for creating a stage instance. */\nexport interface StageInstanceCreateOptions {\n /** Audit-log reason. */\n reason?: string;\n topic: string;\n privacyLevel?: number;\n sendStartNotification?: boolean;\n guildScheduledEventId?: string;\n}\n\n/** Manages stage instances, cached by stage channel ID. Discord.js-familiar. */\nexport class StageInstanceManager extends Manager<string, APIStageInstance> {\n readonly #rest: REST;\n\n public constructor(rest: REST) {\n super();\n this.#rest = rest;\n }\n\n #store(stage: APIStageInstance): APIStageInstance {\n this.set(stage.channel_id, stage);\n return stage;\n }\n\n /** Starts a stage instance in a stage channel. */\n public async create(\n channelId: string,\n options: StageInstanceCreateOptions,\n reason?: string,\n ): Promise<APIStageInstance> {\n return this.#store(\n await this.#rest.post(\n Routes.stageInstances(),\n {\n channel_id: channelId,\n topic: options.topic,\n privacy_level: options.privacyLevel,\n send_start_notification: options.sendStartNotification,\n guild_scheduled_event_id: options.guildScheduledEventId,\n },\n { reason: options.reason ?? reason },\n ),\n );\n }\n\n /** Fetches the stage instance of a stage channel. */\n public async fetch(channelId: string): Promise<APIStageInstance> {\n return this.#store(\n await this.#rest.get(Routes.stageInstanceByChannel(channelId)),\n );\n }\n\n /** Edits a stage instance's topic or privacy level. */\n public async edit(\n channelId: string,\n options: { topic?: string; privacyLevel?: number; reason?: string },\n reason?: string,\n ): Promise<APIStageInstance> {\n return this.#store(\n await this.#rest.patch(\n Routes.stageInstanceByChannel(channelId),\n { topic: options.topic, privacy_level: options.privacyLevel },\n { reason: options.reason ?? reason },\n ),\n );\n }\n\n /** Ends a stage instance. */\n public async remove(channelId: string, reason?: string): Promise<void> {\n await this.#rest.delete(Routes.stageInstanceByChannel(channelId), {\n reason,\n });\n this.delete(channelId);\n }\n}\n\n/** Overwrite target type: 0 = role, 1 = member. */\nexport type PermissionOverwriteTargetType = 0 | 1;\n\n/** Permission values accepted by {@link PermissionOverwriteManager.edit}. */\nexport interface PermissionOverwriteOptions {\n /** Audit-log reason. */\n reason?: string;\n /** Target type: 0 = role, 1 = member. */\n type: PermissionOverwriteTargetType;\n /** Allowed permission bits. */\n allow?: bigint | number | string;\n /** Denied permission bits. */\n deny?: bigint | number | string;\n}\n\n/** Bits to change on one overwrite by {@link PermissionOverwriteManager.update}; bits in none of them keep their state. */\nexport interface PermissionOverwriteUpdate {\n /** Bits to allow. */\n allow?: bigint;\n /** Bits to deny. */\n deny?: bigint;\n /** Bits to reset to inherited (neither allowed nor denied). */\n inherit?: bigint;\n}\n\n/** Manages a channel's permission overwrites. Discord.js-familiar. */\nexport class PermissionOverwriteManager {\n readonly #rest: REST;\n readonly #current: () => readonly APIOverwrite[] | undefined;\n public readonly channelId: string;\n\n /** @param current The channel's cached overwrites, read by {@link update}; the channel is fetched when they are unknown. */\n public constructor(\n rest: REST,\n channelId: string,\n current: () => readonly APIOverwrite[] | undefined = () => undefined,\n ) {\n this.#rest = rest;\n this.channelId = channelId;\n this.#current = current;\n }\n\n /**\n * Changes some bits of one overwrite and keeps the rest -- unlike\n * {@link edit}, which replaces the whole overwrite. Creates the overwrite\n * when there is none (then `options.type` is required).\n * @throws {TypeError} When the overwrite does not exist and no type is given.\n */\n public async update(\n overwriteId: string,\n changes: PermissionOverwriteUpdate,\n options: { type?: PermissionOverwriteTargetType; reason?: string } = {},\n ): Promise<void> {\n const overwrites =\n this.#current() ??\n (await this.#rest.get<APIChannel>(Routes.channel(this.channelId)))\n .permission_overwrites ??\n [];\n const existing = overwrites.find((entry) => entry.id === overwriteId);\n const type = existing?.type ?? options.type;\n if (type !== 0 && type !== 1)\n throw new TypeError(\n \"A new permission overwrite needs a type: 0 for a role, 1 for a member.\",\n );\n const touched =\n (changes.allow ?? 0n) |\n (changes.deny ?? 0n) |\n (changes.inherit ?? 0n);\n const allow =\n (BigInt(existing?.allow ?? 0) & ~touched) | (changes.allow ?? 0n);\n const deny =\n (BigInt(existing?.deny ?? 0) & ~touched) | (changes.deny ?? 0n);\n await this.edit(overwriteId, { type, allow, deny }, options.reason);\n }\n\n /** Creates or replaces the overwrite for a role or member. */\n public async edit(\n overwriteId: string,\n options: PermissionOverwriteOptions,\n reason?: string,\n ): Promise<void> {\n await this.#rest.put(\n Routes.channelPermission(this.channelId, overwriteId),\n {\n type: options.type,\n allow: BigInt(options.allow ?? 0).toString(),\n deny: BigInt(options.deny ?? 0).toString(),\n },\n { reason: options.reason ?? reason },\n );\n }\n\n /** Deletes the overwrite for a role or member. */\n public async remove(overwriteId: string, reason?: string): Promise<void> {\n await this.#rest.delete(\n Routes.channelPermission(this.channelId, overwriteId),\n { reason },\n );\n }\n}\n",
|
|
35
|
-
"import { Manager, ResourceManager, splitReason } from \"./base.js\";\nimport { EmojiManager } from \"./emoji.js\";\nimport { GuildSoundboardManager, GuildStickerManager } from \"./advanced.js\";\nimport { GuildMemberManager } from \"./member.js\";\nimport { RoleManager } from \"./role.js\";\nimport {\n GuildBanManager,\n GuildScheduledEventManager,\n} from \"./guild-resources.js\";\nimport {\n Guild,\n AutoModerationRule,\n type ResourceContext,\n} from \"@lunibee/structures\";\nimport { type REST, Routes } from \"@lunibee/rest\";\nimport {\n type APIChannel,\n type APIGuildPreview,\n type APIInvite,\n type APIWebhook,\n type APIAutoModerationRule,\n type APIInviteCreate,\n type APIVoiceState,\n} from \"@lunibee/types\";\n\ntype GuildData = ConstructorParameters<typeof Guild>[0];\n\n/** Appends encoded query parameters to a `Routes`-generated path so query building\n * stays centralized and URL-encoded rather than hand-concatenated at each call site.\n * @param path Base path from a `Routes.*` helper. @param params Query parameters (empty → path unchanged). */\nfunction withQuery(path: string, params: URLSearchParams): string {\n const suffix = params.toString();\n return suffix ? `${path}?${suffix}` : path;\n}\n\nexport interface GuildCreateOptions extends Record<string, unknown> {\n name: string;\n}\nexport interface GuildEditOptions extends Record<string, unknown> {\n /** Audit-log reason. */\n reason?: string;\n}\n\nexport class GuildManager extends ResourceManager<string, Guild> {\n readonly #rest: REST;\n readonly #bans = new Map<string, GuildBanManager>();\n readonly #scheduledEvents = new Map<string, GuildScheduledEventManager>();\n readonly #members = new Map<string, GuildMemberManager>();\n readonly #roles = new Map<string, RoleManager>();\n readonly #emojis = new Map<string, EmojiManager>();\n readonly #stickers = new Map<string, GuildStickerManager>();\n readonly #soundboard = new Map<string, GuildSoundboardManager>();\n readonly #voiceStates = new Map<string, Manager<string, APIVoiceState>>();\n readonly #autoModerationRules = new Map<\n string,\n Manager<string, APIAutoModerationRule>\n >();\n readonly #invites = new Map<string, Manager<string, APIInviteCreate>>();\n #context?: ResourceContext;\n\n /** Lets members from this manager act through a client (`member.kick()`...). Called by the client. */\n public attachContext(context: ResourceContext): void {\n this.#context = context;\n }\n\n /** Returns the per-guild entry of `map`, creating it on first use. */\n #perGuild<M>(map: Map<string, M>, guildId: string, create: () => M): M {\n let manager = map.get(guildId);\n if (!manager) map.set(guildId, (manager = create()));\n return manager;\n }\n public constructor(rest: REST) {\n super(\n async (id) =>\n new Guild(await rest.get<GuildData>(Routes.guild(id))),\n (guild) => guild.id,\n );\n this.#rest = rest;\n }\n\n /** Ban manager for a guild (one instance per guild). */\n public bans(guildId: string): GuildBanManager {\n let manager = this.#bans.get(guildId);\n if (!manager)\n this.#bans.set(\n guildId,\n (manager = new GuildBanManager(this.#rest, guildId)),\n );\n return manager;\n }\n\n /** Scheduled-event manager for a guild (one instance per guild). */\n public scheduledEvents(guildId: string): GuildScheduledEventManager {\n let manager = this.#scheduledEvents.get(guildId);\n if (!manager)\n this.#scheduledEvents.set(\n guildId,\n (manager = new GuildScheduledEventManager(this.#rest, guildId)),\n );\n return manager;\n }\n\n /** Member manager for a guild (one instance per guild, kept in sync by the Gateway). */\n public members(guildId: string): GuildMemberManager {\n let manager = this.#members.get(guildId);\n if (!manager)\n this.#members.set(\n guildId,\n (manager = new GuildMemberManager(\n guildId,\n this.#rest,\n () => this.#context,\n )),\n );\n return manager;\n }\n\n /** Role manager for a guild (one instance per guild, kept in sync by the Gateway). */\n public roles(guildId: string): RoleManager {\n let manager = this.#roles.get(guildId);\n if (!manager)\n this.#roles.set(\n guildId,\n (manager = new RoleManager(guildId, this.#rest)),\n );\n return manager;\n }\n\n /** Emoji manager for a guild (one instance per guild, kept in sync by the Gateway). */\n public emojis(guildId: string): EmojiManager {\n let manager = this.#emojis.get(guildId);\n if (!manager)\n this.#emojis.set(\n guildId,\n (manager = new EmojiManager(this.#rest, guildId)),\n );\n return manager;\n }\n\n /** Sticker manager for a guild (one instance per guild, kept in sync by the Gateway). */\n public stickers(guildId: string): GuildStickerManager {\n let manager = this.#stickers.get(guildId);\n if (!manager)\n this.#stickers.set(\n guildId,\n (manager = new GuildStickerManager(this.#rest, guildId)),\n );\n return manager;\n }\n\n /** Soundboard manager for a guild (one instance per guild, kept in sync by the Gateway). */\n public soundboard(guildId: string): GuildSoundboardManager {\n let manager = this.#soundboard.get(guildId);\n if (!manager)\n this.#soundboard.set(\n guildId,\n (manager = new GuildSoundboardManager(this.#rest, guildId)),\n );\n return manager;\n }\n\n /** Voice states by user ID for a guild, kept in sync by `GUILD_CREATE` and `VOICE_STATE_UPDATE`. */\n public voiceStates(guildId: string): Manager<string, APIVoiceState> {\n return this.#perGuild(this.#voiceStates, guildId, () => new Manager());\n }\n\n /** Auto-moderation rules by ID for a guild, kept in sync by `AUTO_MODERATION_RULE_*` events. */\n public autoModerationRules(\n guildId: string,\n ): Manager<string, APIAutoModerationRule> {\n return this.#perGuild(\n this.#autoModerationRules,\n guildId,\n () => new Manager(),\n );\n }\n\n /** Invites by code for a guild, kept in sync by `INVITE_CREATE` / `INVITE_DELETE`. */\n public invites(guildId: string): Manager<string, APIInviteCreate> {\n return this.#perGuild(this.#invites, guildId, () => new Manager());\n }\n\n /** Merges a guild payload into the cached instance, keeping object identity. */\n public patch(data: GuildData): Guild {\n const guild = new Guild(data);\n const existing = this.get(guild.id);\n if (!existing) return this.upsert(guild);\n // Partial payloads (e.g. GUILD_UPDATE has no member_count) leave\n // optional fields undefined; those must not erase known values.\n for (const [key, value] of Object.entries(guild))\n if (value !== undefined)\n (existing as unknown as Record<string, unknown>)[key] = value;\n return existing;\n }\n\n /** Removes a guild and every per-guild manager that belongs to it. */\n public override delete(id: string): boolean {\n this.#bans.delete(id);\n this.#scheduledEvents.delete(id);\n this.#members.delete(id);\n this.#roles.delete(id);\n this.#emojis.delete(id);\n this.#stickers.delete(id);\n this.#soundboard.delete(id);\n this.#voiceStates.delete(id);\n this.#autoModerationRules.delete(id);\n this.#invites.delete(id);\n return super.delete(id);\n }\n\n /** Creates a new guild. (Bot must be in fewer than 10 guilds). */\n public async create(options: GuildCreateOptions): Promise<Guild> {\n const data = await this.#rest.post<GuildData>(\"/guilds\", options);\n return this.upsert(new Guild(data));\n }\n\n /** Modifies a guild's settings. */\n public async edit(id: string, options: GuildEditOptions): Promise<Guild> {\n const [payload, reason] = splitReason(options);\n const data = await this.#rest.patch<GuildData>(\n Routes.guild(id),\n payload,\n { reason },\n );\n return this.upsert(new Guild(data));\n }\n\n /** Deletes a guild permanently. The bot must own it. */\n public async remove(id: string): Promise<void> {\n await this.#rest.delete(Routes.guild(id));\n }\n /** @deprecated Use {@link GuildManager.remove}. Removed in 0.3.0. */\n public deleteGuild(id: string): Promise<void> {\n return this.remove(id);\n }\n\n /** Fetches a guild's preview (even if the bot is not in the guild). */\n public async fetchPreview(id: string): Promise<APIGuildPreview> {\n return this.#rest.get<APIGuildPreview>(Routes.guildPreview(id));\n }\n\n /** Fetches all active threads in the guild. */\n public async fetchActiveThreads(\n id: string,\n ): Promise<{ threads: APIChannel[]; members: unknown[] }> {\n return this.#rest.get<{ threads: APIChannel[]; members: unknown[] }>(\n Routes.guildActiveThreads(id),\n );\n }\n\n /** Fetches all webhooks in the guild. */\n public async fetchWebhooks(id: string): Promise<APIWebhook[]> {\n return this.#rest.get<APIWebhook[]>(Routes.guildWebhooks(id));\n }\n\n /** Fetches all invites in the guild. */\n public async fetchInvites(id: string): Promise<APIInvite[]> {\n return this.#rest.get<APIInvite[]>(Routes.guildInvites(id));\n }\n\n /**\n * Fetches audit log entries for a guild.\n * @param guildId Guild identifier.\n * @param options Filter options: userId (filter by actor), actionType (AuditLogEvent number), before (entry ID cursor), limit (1–100, default 50).\n * @returns Typed audit log response with `audit_log_entries` and related resources.\n */\n public async fetchAuditLog(\n guildId: string,\n options: {\n userId?: string;\n actionType?: number;\n before?: string;\n after?: string;\n limit?: number;\n } = {},\n ): Promise<AuditLogResponse> {\n const params = new URLSearchParams();\n if (options.userId) params.set(\"user_id\", options.userId);\n if (options.actionType !== undefined)\n params.set(\"action_type\", String(options.actionType));\n if (options.before) params.set(\"before\", options.before);\n if (options.after) params.set(\"after\", options.after);\n if (options.limit !== undefined)\n params.set(\n \"limit\",\n String(Math.min(100, Math.max(1, options.limit))),\n );\n return this.#rest.get<AuditLogResponse>(\n withQuery(Routes.guildAuditLog(guildId), params),\n );\n }\n\n /**\n * Fetches members from a guild (paginated).\n * @param guildId Guild identifier.\n * @param options Fetch options: limit (1–1000, default 100), after (member ID cursor).\n * @returns Array of raw member data payloads.\n */\n public async fetchMembers(\n guildId: string,\n options: { limit?: number; after?: string } = {},\n ): Promise<Record<string, unknown>[]> {\n const params = new URLSearchParams();\n if (options.limit !== undefined)\n params.set(\n \"limit\",\n String(Math.min(1000, Math.max(1, options.limit))),\n );\n if (options.after) params.set(\"after\", options.after);\n return this.#rest.get<Record<string, unknown>[]>(\n withQuery(Routes.guildMembers(guildId), params),\n );\n }\n\n /** Fetches a list of all auto moderation rules currently configured for guild. */\n public async fetchAutoModerationRules(\n guildId: string,\n ): Promise<AutoModerationRule[]> {\n const rules = await this.#rest.get<APIAutoModerationRule[]>(\n Routes.guildAutoModerationRules(guildId),\n );\n return rules.map((r) => new AutoModerationRule(r));\n }\n\n /** Fetches a single auto moderation rule. */\n public async fetchAutoModerationRule(\n guildId: string,\n ruleId: string,\n ): Promise<AutoModerationRule> {\n const rule = await this.#rest.get<APIAutoModerationRule>(\n Routes.guildAutoModerationRule(guildId, ruleId),\n );\n return new AutoModerationRule(rule);\n }\n\n /** Creates a new auto moderation rule. */\n public async createAutoModerationRule(\n guildId: string,\n options: Record<string, unknown> & { reason?: string },\n ): Promise<AutoModerationRule> {\n const [payload, reason] = splitReason(options);\n const rule = await this.#rest.post<APIAutoModerationRule>(\n Routes.guildAutoModerationRules(guildId),\n payload,\n { reason },\n );\n return new AutoModerationRule(rule);\n }\n\n /** Modifies an existing auto moderation rule. */\n public async editAutoModerationRule(\n guildId: string,\n ruleId: string,\n options: Record<string, unknown> & { reason?: string },\n ): Promise<AutoModerationRule> {\n const [payload, reason] = splitReason(options);\n const rule = await this.#rest.patch<APIAutoModerationRule>(\n Routes.guildAutoModerationRule(guildId, ruleId),\n payload,\n { reason },\n );\n return new AutoModerationRule(rule);\n }\n\n /** Deletes an auto moderation rule. @param reason Audit-log reason. */\n public async deleteAutoModerationRule(\n guildId: string,\n ruleId: string,\n reason?: string,\n ): Promise<void> {\n await this.#rest.delete(\n Routes.guildAutoModerationRule(guildId, ruleId),\n { reason },\n );\n }\n}\n\n// ─── Audit Log Types ──────────────────────────────────────────────────────────\n\n/** A single audit log entry as returned by the Discord API. */\nexport interface AuditLogEntry {\n id: string;\n action_type: number;\n user_id: string | null;\n target_id: string | null;\n reason?: string;\n changes?: Array<{ key: string; old_value?: unknown; new_value?: unknown }>;\n options?: Record<string, unknown>;\n}\n\n/** Discord API audit log response payload. */\nexport interface AuditLogResponse {\n audit_log_entries: AuditLogEntry[];\n users: Record<string, unknown>[];\n integrations: Record<string, unknown>[];\n webhooks: Record<string, unknown>[];\n guild_scheduled_events: Record<string, unknown>[];\n threads: Record<string, unknown>[];\n application_commands: Record<string, unknown>[];\n}\n\n/** Known Discord audit log event type numbers. */\nexport const AuditLogEvent = {\n GuildUpdate: 1,\n ChannelCreate: 10,\n ChannelUpdate: 11,\n ChannelDelete: 12,\n ChannelOverwriteCreate: 13,\n ChannelOverwriteUpdate: 14,\n ChannelOverwriteDelete: 15,\n MemberKick: 20,\n MemberPrune: 21,\n MemberBanAdd: 22,\n MemberBanRemove: 23,\n MemberUpdate: 24,\n MemberRoleUpdate: 25,\n MemberMove: 26,\n MemberDisconnect: 27,\n BotAdd: 28,\n RoleCreate: 30,\n RoleUpdate: 31,\n RoleDelete: 32,\n InviteCreate: 40,\n InviteUpdate: 41,\n InviteDelete: 42,\n WebhookCreate: 50,\n WebhookUpdate: 51,\n WebhookDelete: 52,\n EmojiCreate: 60,\n EmojiUpdate: 61,\n EmojiDelete: 62,\n MessageDelete: 72,\n MessageBulkDelete: 73,\n MessagePin: 74,\n MessageUnpin: 75,\n IntegrationCreate: 80,\n IntegrationUpdate: 81,\n IntegrationDelete: 82,\n StageInstanceCreate: 83,\n StageInstanceUpdate: 84,\n StageInstanceDelete: 85,\n StickerCreate: 90,\n StickerUpdate: 91,\n StickerDelete: 92,\n ScheduledEventCreate: 100,\n ScheduledEventUpdate: 101,\n ScheduledEventDelete: 102,\n ThreadCreate: 110,\n ThreadUpdate: 111,\n ThreadDelete: 112,\n AutoModerationRuleCreate: 140,\n AutoModerationRuleUpdate: 141,\n AutoModerationRuleDelete: 142,\n AutoModerationBlockMessage: 143,\n} as const;\n",
|
|
36
|
-
"import { REST, Routes } from \"@lunibee/rest\";\nimport type {\n APIApplicationCommand,\n ApplicationCommandData,\n} from \"@lunibee/types\";\n\n/** Manages global and guild-scoped application commands for a Discord application. */\nexport class ApplicationCommandManager {\n readonly #rest: REST;\n readonly #applicationId: string;\n\n /** Creates an application command manager. @param rest REST transport. @param applicationId Application identifier. */\n public constructor(rest: REST, applicationId: string) {\n this.#rest = rest;\n this.#applicationId = applicationId;\n }\n\n // ──────────────────── Global commands ────────────────────\n\n /** Fetches all global application commands. @returns Array of registered commands. */\n public fetch(): Promise<APIApplicationCommand[]> {\n return this.#rest.get<APIApplicationCommand[]>(\n Routes.applicationCommands(this.#applicationId),\n );\n }\n\n /** Creates a single global application command. @param data Command data. @returns Created command. */\n public create(\n data: ApplicationCommandData,\n ): Promise<APIApplicationCommand> {\n return this.#rest.post<APIApplicationCommand>(\n Routes.applicationCommands(this.#applicationId),\n data,\n );\n }\n\n /** Overwrites all global application commands atomically. @param commands Array of command data. @returns New full command list. */\n public set(\n commands: ApplicationCommandData[],\n ): Promise<APIApplicationCommand[]> {\n return this.#rest.put<APIApplicationCommand[]>(\n Routes.applicationCommands(this.#applicationId),\n commands,\n );\n }\n\n /** Edits a global application command. @param commandId Command identifier. @param data Partial command data. @returns Updated command. */\n public edit(\n commandId: string,\n data: Partial<ApplicationCommandData>,\n ): Promise<APIApplicationCommand> {\n return this.#rest.patch<APIApplicationCommand>(\n Routes.applicationCommand(this.#applicationId, commandId),\n data,\n );\n }\n\n /** Deletes a global application command. @param commandId Command identifier. @returns Nothing. */\n public async delete(commandId: string): Promise<void> {\n await this.#rest.delete(\n Routes.applicationCommand(this.#applicationId, commandId),\n );\n }\n\n // ──────────────────── Guild-scoped commands ────────────────────\n\n /** Fetches all guild-scoped application commands. @param guildId Guild identifier. @returns Array of registered guild commands. */\n public fetchGuild(guildId: string): Promise<APIApplicationCommand[]> {\n return this.#rest.get<APIApplicationCommand[]>(\n Routes.guildApplicationCommands(this.#applicationId, guildId),\n );\n }\n\n /** Creates a single guild-scoped application command. @param guildId Guild identifier. @param data Command data. @returns Created command. */\n public createGuild(\n guildId: string,\n data: ApplicationCommandData,\n ): Promise<APIApplicationCommand> {\n return this.#rest.post<APIApplicationCommand>(\n Routes.guildApplicationCommands(this.#applicationId, guildId),\n data,\n );\n }\n\n /** Overwrites all guild-scoped application commands atomically. @param guildId Guild identifier. @param commands Array of command data. @returns New full command list. */\n public setGuild(\n guildId: string,\n commands: ApplicationCommandData[],\n ): Promise<APIApplicationCommand[]> {\n return this.#rest.put<APIApplicationCommand[]>(\n Routes.guildApplicationCommands(this.#applicationId, guildId),\n commands,\n );\n }\n\n /** Edits a guild-scoped application command. @param guildId Guild identifier. @param commandId Command identifier. @param data Partial command data. @returns Updated command. */\n public editGuild(\n guildId: string,\n commandId: string,\n data: Partial<ApplicationCommandData>,\n ): Promise<APIApplicationCommand> {\n return this.#rest.patch<APIApplicationCommand>(\n Routes.guildApplicationCommand(\n this.#applicationId,\n guildId,\n commandId,\n ),\n data,\n );\n }\n\n /** Deletes a guild-scoped application command. @param guildId Guild identifier. @param commandId Command identifier. @returns Nothing. */\n public async deleteGuild(\n guildId: string,\n commandId: string,\n ): Promise<void> {\n await this.#rest.delete(\n Routes.guildApplicationCommand(\n this.#applicationId,\n guildId,\n commandId,\n ),\n );\n }\n}\n",
|
|
37
|
-
"import { Manager, ResourceManager, splitReason } from \"./base.js\";\nexport { Manager, ResourceManager } from \"./base.js\";\n/** Discord.js-familiar alias for {@link ResourceManager}. */\nexport { ResourceManager as CachedManager } from \"./base.js\";\nimport { REST, Routes } from \"@lunibee/rest\";\nimport {\n Channel,\n createChannel,\n Message,\n User,\n type ResourceContext,\n} from \"@lunibee/structures\";\nimport {\n MessageManager,\n toRequest,\n type MessageCacheOptions,\n type MessageCreateOptions as ManagerMessageCreateOptions,\n} from \"./message.js\";\nimport { ThreadManager } from \"./thread.js\";\n\nexport { UserManager } from \"./user.js\";\nexport { GuildManager } from \"./guild.js\";\nexport type { AuditLogEntry, AuditLogResponse } from \"./guild.js\";\nexport { AuditLogEvent } from \"./guild.js\";\n\nexport type MessageCreateOptions = ManagerMessageCreateOptions;\nexport type MessageEditOptions = Record<string, unknown> & { content?: string };\n/** Discord only bulk-deletes messages younger than two weeks. */\nconst BULK_DELETE_MAX_AGE_MS = 14 * 24 * 60 * 60_000;\n/** Creation time (ms) encoded in a snowflake. */\nfunction snowflakeTime(id: string): number {\n return Number((BigInt(id) >> 22n) + 1_420_070_400_000n);\n}\nexport interface MessageFetchOptions {\n cache?: boolean;\n}\nexport interface MessageQueryOptions {\n before?: string;\n after?: string;\n around?: string;\n limit?: number;\n}\nexport interface MessageThreadOptions {\n name: string;\n autoArchiveDuration?: 60 | 1440 | 4320 | 10080;\n rateLimitPerUser?: number;\n}\nexport interface ReactionFetchOptions {\n limit?: number;\n after?: string;\n}\n\nexport interface ChannelCreateOptions extends Record<string, unknown> {\n /** Audit-log reason. */\n reason?: string;\n name: string;\n type: number;\n guild_id?: string;\n parent_id?: string | null;\n}\nexport type ChannelEditOptions = Record<string, unknown> & {\n /** Audit-log reason. */\n reason?: string;\n};\n\nimport { PermissionOverwriteManager } from \"./guild-resources.js\";\n\nexport class ChannelManager extends Manager<string, Channel> {\n readonly #rest: REST;\n readonly #context: ResourceContext;\n readonly #messageManagers = new Map<string, MessageManager>();\n readonly #messageCache?: MessageCacheOptions;\n readonly #allowedMentions?: unknown;\n /**\n * @param options.messageCache Enables a bounded per-channel message cache; messages are not cached by default.\n * @param options.allowedMentions Default `allowed_mentions` for sends and edits without their own.\n */\n public constructor(\n rest: REST,\n options: {\n messageCache?: MessageCacheOptions;\n allowedMentions?: unknown;\n } = {},\n ) {\n super();\n this.#rest = rest;\n this.#messageCache = options.messageCache;\n this.#allowedMentions = options.allowedMentions;\n this.#context = {\n sendMessage: (channelId, options) => this.send(channelId, options),\n editMessage: (channelId, messageId, options) =>\n this.editMessage(channelId, messageId, options),\n deleteMessage: (channelId, messageId, reason) =>\n this.deleteMessage(channelId, messageId, reason),\n crosspostMessage: (channelId, messageId) =>\n this.crosspostMessage(channelId, messageId),\n editChannel: (channelId, options) => this.edit(channelId, options),\n deleteChannel: (channelId, reason) =>\n this.remove(channelId, reason),\n addReaction: (channelId, messageId, emoji) =>\n this.addReaction(channelId, messageId, emoji),\n removeOwnReaction: (channelId, messageId, emoji) =>\n this.removeOwnReaction(channelId, messageId, emoji),\n removeReaction: (channelId, messageId, emoji, userId) =>\n this.removeReaction(channelId, messageId, emoji, userId),\n removeAllReactions: (channelId, messageId) =>\n this.removeAllReactions(channelId, messageId),\n pinMessage: (channelId, messageId, reason) =>\n this.pinMessage(channelId, messageId, reason),\n unpinMessage: (channelId, messageId, reason) =>\n this.unpinMessage(channelId, messageId, reason),\n };\n }\n public messages(channelId: string): MessageManager {\n let manager = this.#messageManagers.get(channelId);\n if (!manager) {\n manager = new MessageManager(\n this.#rest,\n this.#context,\n channelId,\n this.#messageCache,\n this.#allowedMentions,\n );\n this.#messageManagers.set(channelId, manager);\n }\n return manager;\n }\n /** Permission overwrite manager for a channel. */\n public permissionOverwrites(channelId: string): PermissionOverwriteManager {\n return new PermissionOverwriteManager(\n this.#rest,\n channelId,\n () => this.get(channelId)?.permissionOverwrites,\n );\n }\n public threads(channelId: string): ThreadManager {\n return new ThreadManager(this.#rest, this.#context, channelId);\n }\n /** Fetches a channel; concurrent fetches share a request and a stale result never overwrites newer state. */\n public fetch(channelId: string): Promise<Channel> {\n return this.fetchOnce(\n channelId,\n async () =>\n createChannel(\n await this.#rest.get<\n ConstructorParameters<typeof Channel>[0]\n >(Routes.channel(channelId)),\n this.#context,\n ),\n (channel) => this.#merge(channel),\n );\n }\n public async resolve(channelId: string): Promise<Channel> {\n return this.get(channelId) ?? this.fetch(channelId);\n }\n public upsert(data: ConstructorParameters<typeof Channel>[0]): Channel {\n return this.#merge(createChannel(data, this.#context));\n }\n /** Merges into the cached instance; a type change (e.g. text -> announcement) needs the new subclass. */\n #merge(channel: Channel): Channel {\n const existing = this.get(channel.id);\n if (existing && existing.type === channel.type) {\n Object.assign(existing, channel);\n return existing;\n }\n this.set(channel.id, channel);\n return channel;\n }\n public update(channel: Channel): this {\n return this.set(channel.id, channel);\n }\n /** Removes every cached channel that belongs to a guild. @returns Number removed. */\n public deleteGuildChannels(guildId: string): number {\n let removed = 0;\n for (const channel of this.values())\n if (channel.guildId === guildId && this.delete(channel.id))\n removed++;\n return removed;\n }\n /** Ends a poll now; returns the updated message. */\n public async endPoll(\n channelId: string,\n messageId: string,\n ): Promise<Message> {\n return this.messages(channelId).upsert(\n await this.#rest.post<ConstructorParameters<typeof Message>[0]>(\n Routes.pollExpire(channelId, messageId),\n ),\n );\n }\n /** Fetches users who voted for one poll answer. @param options.limit 1-100 (default 25). */\n public async fetchPollVoters(\n channelId: string,\n messageId: string,\n answerId: number,\n options: { after?: string; limit?: number } = {},\n ): Promise<User[]> {\n if (\n options.limit !== undefined &&\n (!Number.isInteger(options.limit) ||\n options.limit < 1 ||\n options.limit > 100)\n )\n throw new RangeError(\"Poll voter limit must be 1-100.\");\n const params = new URLSearchParams();\n if (options.after) params.set(\"after\", options.after);\n if (options.limit !== undefined)\n params.set(\"limit\", String(options.limit));\n const suffix = params.toString();\n const { users } = await this.#rest.get<{\n users: ConstructorParameters<typeof User>[0][];\n }>(\n `${Routes.pollAnswerVoters(channelId, messageId, answerId)}${suffix ? `?${suffix}` : \"\"}`,\n );\n return users.map((user) => new User(user));\n }\n /** Plays a soundboard sound in a voice channel the bot is connected to. */\n public async sendSoundboardSound(\n channelId: string,\n options: { soundId: string; sourceGuildId?: string },\n ): Promise<void> {\n await this.#rest.post(Routes.sendSoundboardSound(channelId), {\n sound_id: options.soundId,\n source_guild_id: options.sourceGuildId,\n });\n }\n /** Returns the message manager for a channel only if one already exists. */\n public cachedMessages(channelId: string): MessageManager | undefined {\n return this.#messageManagers.get(channelId);\n }\n public async create(\n guildId: string,\n options: ChannelCreateOptions,\n ): Promise<Channel> {\n const [payload, reason] = splitReason(options);\n return this.upsert(\n await this.#rest.post<ConstructorParameters<typeof Channel>[0]>(\n Routes.guildChannels(guildId),\n payload,\n { reason },\n ),\n );\n }\n public async edit(\n channelId: string,\n options: ChannelEditOptions,\n ): Promise<Channel> {\n const [payload, reason] = splitReason(options);\n return this.upsert(\n await this.#rest.patch<ConstructorParameters<typeof Channel>[0]>(\n Routes.channel(channelId),\n payload,\n { reason },\n ),\n );\n }\n\n /** Deletes a channel (or closes a DM). @param reason Audit-log reason. */\n public async remove(channelId: string, reason?: string): Promise<void> {\n await this.#rest.delete(Routes.channel(channelId), { reason });\n this.delete(channelId);\n }\n /** @deprecated Use {@link ChannelManager.remove}, which also takes an audit-log reason. Removed in 0.3.0. */\n public deleteChannel(channelId: string): Promise<void> {\n return this.remove(channelId);\n }\n /** Evicts a channel, dropping its per-channel message manager with it.\n * Overrides {@link Manager.delete} so cache eviction driven by a Gateway\n * `CHANNEL_DELETE`/`THREAD_DELETE` — which calls `delete` rather than\n * {@link remove} — releases the message manager and its cached\n * messages too, instead of retaining them for the client's lifetime. */\n public override delete(channelId: string): boolean {\n this.#messageManagers.delete(channelId);\n return super.delete(channelId);\n }\n public send(\n channelId: string,\n options: MessageCreateOptions,\n ): Promise<Message> {\n return this.messages(channelId).send(options);\n }\n /** @deprecated Use {@link ChannelManager.send}. Removed in 0.3.0. */\n public sendMessage(\n channelId: string,\n options: MessageCreateOptions,\n ): Promise<Message> {\n return this.send(channelId, options);\n }\n public async fetchMessage(\n channelId: string,\n messageId: string,\n options: MessageFetchOptions = {},\n ): Promise<Message> {\n void options;\n return this.messages(channelId).fetch(messageId);\n }\n public fetchMessages(\n channelId: string,\n query: MessageQueryOptions | Iterable<string>,\n ): Promise<Message[]> {\n if (isMessageQuery(query)) {\n const params = new URLSearchParams();\n if (query.before) params.set(\"before\", query.before);\n if (query.after) params.set(\"after\", query.after);\n if (query.around) params.set(\"around\", query.around);\n if (query.limit !== undefined)\n params.set(\"limit\", String(query.limit));\n const suffix = params.toString();\n return this.#rest\n .get<ConstructorParameters<typeof Message>[0][]>(\n `${Routes.channelMessages(channelId)}${suffix ? `?${suffix}` : \"\"}`,\n )\n .then((data) =>\n data.map((item) => this.messages(channelId).upsert(item)),\n );\n }\n return this.messages(channelId).fetchMany(query);\n }\n public upsertMessage(\n data: ConstructorParameters<typeof Message>[0],\n ): Message {\n return this.messages(data.channel_id).upsert(data);\n }\n public async editMessage(\n channelId: string,\n messageId: string,\n options: MessageEditOptions,\n ): Promise<Message> {\n return this.messages(channelId).upsert(\n await this.#rest.patch<ConstructorParameters<typeof Message>[0]>(\n Routes.message(channelId, messageId),\n toRequest(options, this.#allowedMentions),\n ),\n );\n }\n /** Deletes a message. @param reason Audit-log reason (shown when deleting someone else's message). */\n public async deleteMessage(\n channelId: string,\n messageId: string,\n reason?: string,\n ): Promise<void> {\n await this.#rest.delete(Routes.message(channelId, messageId), {\n reason,\n });\n this.messages(channelId).delete(messageId);\n }\n public deleteCachedMessage(channelId: string, messageId: string): boolean {\n return this.messages(channelId).delete(messageId);\n }\n public async crosspostMessage(\n channelId: string,\n messageId: string,\n ): Promise<Message> {\n return this.messages(channelId).upsert(\n await this.#rest.post<ConstructorParameters<typeof Message>[0]>(\n Routes.crosspostMessage(channelId, messageId),\n ),\n );\n }\n /** Bulk-deletes messages in a channel. Duplicate IDs are ignored and a\n * single ID falls back to a normal delete.\n * @throws {RangeError} If no IDs or more than 100 are provided, or any\n * message is older than 14 days (Discord refuses to bulk-delete those). */\n public async bulkDeleteMessages(\n channelId: string,\n messageIds: Iterable<string>,\n reason?: string,\n ): Promise<void> {\n const ids = [...new Set(messageIds)];\n if (ids.length < 1 || ids.length > 100)\n throw new RangeError(\n \"bulkDelete requires between 1 and 100 message IDs.\",\n );\n if (ids.length === 1)\n return this.deleteMessage(channelId, ids[0]!, reason);\n const cutoff = Date.now() - BULK_DELETE_MAX_AGE_MS;\n const tooOld = ids.filter((id) => snowflakeTime(id) < cutoff);\n if (tooOld.length)\n throw new RangeError(\n `bulkDelete cannot delete messages older than 14 days: ${tooOld.join(\", \")}`,\n );\n await this.#rest.post(\n Routes.channelBulkDelete(channelId),\n { messages: ids },\n { reason },\n );\n for (const id of ids) this.messages(channelId).delete(id);\n }\n /**\n * Iterates a channel's history newest-first, 100 messages per request,\n * starting before `before` (or the latest message) and stopping after\n * `limit` messages or at the start of the channel.\n */\n public async *iterateMessages(\n channelId: string,\n options: { before?: string; limit?: number } = {},\n ): AsyncGenerator<Message, void, undefined> {\n let before = options.before;\n let remaining = options.limit ?? Infinity;\n while (remaining > 0) {\n const page = await this.fetchMessages(channelId, {\n before,\n limit: Math.min(100, remaining),\n });\n for (const message of page) yield message;\n remaining -= page.length;\n if (page.length < 100) return;\n before = page.at(-1)!.id;\n }\n }\n public async addReaction(\n channelId: string,\n messageId: string,\n emoji: string,\n ): Promise<void> {\n // Discord's create-reaction endpoint is\n // PUT .../reactions/{emoji}/@me — the bare .../reactions/{emoji} path\n // is not a valid target for PUT.\n await this.#rest.put(\n `${Routes.messageReactions(channelId, messageId, emoji)}/@me`,\n );\n }\n public async fetchReactions(\n channelId: string,\n messageId: string,\n emoji: string,\n options: ReactionFetchOptions = {},\n ): Promise<User[]> {\n const params = new URLSearchParams();\n if (options.limit !== undefined)\n params.set(\"limit\", String(options.limit));\n if (options.after) params.set(\"after\", options.after);\n const suffix = params.toString();\n const data = await this.#rest.get<\n ConstructorParameters<typeof User>[0][]\n >(\n `${Routes.messageReactions(channelId, messageId, emoji)}${suffix ? `?${suffix}` : \"\"}`,\n );\n return data.map((user) => new User(user));\n }\n public async removeOwnReaction(\n channelId: string,\n messageId: string,\n emoji: string,\n ): Promise<void> {\n await this.#rest.delete(\n `${Routes.messageReactions(channelId, messageId, emoji)}/@me`,\n );\n }\n public async removeReaction(\n channelId: string,\n messageId: string,\n emoji: string,\n userId: string,\n ): Promise<void> {\n await this.#rest.delete(\n `${Routes.messageReactions(channelId, messageId, emoji)}/${userId}`,\n );\n }\n public async removeAllReactions(\n channelId: string,\n messageId: string,\n ): Promise<void> {\n await this.#rest.delete(\n Routes.messageReactionsAll(channelId, messageId),\n );\n }\n /** Fetches the newest pinned messages (one page, up to 50, like the endpoint it replaces). */\n public async fetchPinnedMessages(channelId: string): Promise<Message[]> {\n const data = await this.#rest.get<{\n items: { message: ConstructorParameters<typeof Message>[0] }[];\n }>(Routes.channelMessagesPins(channelId));\n return data.items.map((item) =>\n this.messages(channelId).upsert(item.message),\n );\n }\n /** Pins a message. @param reason Audit-log reason. */\n public async pinMessage(\n channelId: string,\n messageId: string,\n reason?: string,\n ): Promise<void> {\n await this.#rest.put(\n Routes.channelMessagesPin(channelId, messageId),\n undefined,\n { reason },\n );\n }\n /** Unpins a message. @param reason Audit-log reason. */\n public async unpinMessage(\n channelId: string,\n messageId: string,\n reason?: string,\n ): Promise<void> {\n await this.#rest.delete(\n Routes.channelMessagesPin(channelId, messageId),\n { reason },\n );\n }\n /** Creates a webhook in a channel. @param options Name, optional avatar data URI, and audit-log `reason`. */\n public async createWebhook(\n channelId: string,\n options: { name: string; avatar?: string | null; reason?: string },\n ): Promise<import(\"@lunibee/types\").APIWebhook> {\n const [payload, reason] = splitReason(options);\n return this.#rest.post(Routes.channelWebhooks(channelId), payload, {\n reason,\n });\n }\n public createThreadFromMessage(\n channelId: string,\n messageId: string,\n options: MessageThreadOptions,\n ): Promise<Channel> {\n return this.threads(channelId).createFromMessage(messageId, options);\n }\n /**\n * Fetches a page of messages with cursor metadata.\n * @param channelId Channel to fetch from.\n * @param options Page options — `before`, `after`, `around`, and `limit` (max 100).\n * @returns `{ messages, before, after, hasMore }` — use `before` or `after` as cursors for the next page.\n */\n public async fetchPage(\n channelId: string,\n options: MessageQueryOptions = {},\n ): Promise<{\n messages: Message[];\n before?: string;\n after?: string;\n hasMore: boolean;\n }> {\n const limit = Math.min(100, Math.max(1, options.limit ?? 50));\n const messages = await this.fetchMessages(channelId, {\n ...options,\n limit,\n });\n return {\n messages,\n before: messages[0]?.id,\n after: messages[messages.length - 1]?.id,\n hasMore: messages.length === limit,\n };\n }\n /** @deprecated Use {@link ChannelManager.bulkDeleteMessages}, which also takes an audit-log reason. Removed in 0.3.0. */\n public bulkDelete(channelId: string, messageIds: string[]): Promise<void> {\n return this.bulkDeleteMessages(channelId, messageIds);\n }\n public override clear(): void {\n this.#messageManagers.clear();\n super.clear();\n }\n}\n\nfunction isMessageQuery(\n value: MessageQueryOptions | Iterable<string>,\n): value is MessageQueryOptions {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !(Symbol.iterator in value)\n );\n}\nexport type CreateMessageOptions = MessageCreateOptions;\nexport {\n MessageManager,\n toRequest,\n type MessageCacheOptions,\n type MessageFile,\n} from \"./message.js\";\nexport { ThreadManager } from \"./thread.js\";\nexport {\n RoleManager,\n type RoleCreateOptions,\n type RoleEditOptions,\n} from \"./role.js\";\nexport {\n GuildMemberManager,\n type MemberEditOptions,\n type BanOptions,\n} from \"./member.js\";\nexport { ApplicationCommandManager } from \"./application.js\";\nexport {\n GuildBanManager,\n GuildScheduledEventManager,\n StageInstanceManager,\n PermissionOverwriteManager,\n type APIBan,\n type GuildBanCreateOptions,\n type GuildScheduledEventOptions,\n type StageInstanceCreateOptions,\n type PermissionOverwriteOptions,\n type PermissionOverwriteTargetType,\n type PermissionOverwriteUpdate,\n} from \"./guild-resources.js\";\nexport {\n EmojiManager,\n type EmojiCreateOptions,\n type EmojiEditOptions,\n} from \"./emoji.js\";\nexport {\n GuildStickerManager,\n GuildSoundboardManager,\n MonetizationManager,\n type APIEntitlement,\n type APISKU,\n type APISoundboardSound,\n type APISubscription,\n type EntitlementQuery,\n type GuildStickerCreateOptions,\n type SoundboardSoundCreateOptions,\n} from \"./advanced.js\";\n",
|
|
38
|
-
"/**\n * Identity of a Discord Gateway session, and the decision of how to open the\n * next connection with it.\n *\n * Deliberately owns nothing else: no socket, no timers, no opcode dispatch, no\n * compression, no event emission. Those belong to the transport, heartbeat,\n * reconnect and protocol seams. Keeping this object small is the point —\n * session confusion is what produced both WS-001 and WS-005.\n */\n\n/** Everything needed to send a RESUME, or nothing when one is impossible. */\nexport interface ResumeInfo {\n /** Discord's session identifier from READY.
|
|
39
|
-
"/**\n * Heartbeat and liveness for one Gateway connection.\n *\n * Owns every timer that decides whether a connection is alive: the heartbeat\n * interval, the acknowledgement deadline, and the staleness (zombie) watch.\n * It owns no socket, no session, no reconnect policy and no event emission —\n * it reports through callbacks and lets its owner decide what to close.\n */\n\n/** Why the connection was declared dead. */\nexport type HeartbeatTimeout =\n | {\n /** A heartbeat went unacknowledged within `ackTimeout`. */\n type: \"ack\";\n /** Time since the unacknowledged heartbeat was sent. */\n elapsedMs: number;\n }\n | {\n /** No traffic at all arrived within the staleness deadline. */\n type: \"zombie\";\n /** Time since the last inbound message. */\n silentFor: number;\n /** Deadline that was exceeded. */\n deadline: number;\n };\n\n/** Collaborators the heartbeat needs from its owner. */\nexport interface HeartbeatOptions {\n /** Milliseconds to wait for an ACK before declaring the connection dead. */\n ackTimeout: number;\n /** Minimum silence before the connection is treated as a zombie. */\n zombieTimeout: number;\n /**\n * Writes a heartbeat payload.\n * @returns Whether it reached the wire; `false` is reported as an error.\n */\n send: (sequence: number | null) => boolean;\n /** Current session sequence, sent as the heartbeat's `d`. */\n sequence: () => number | null;\n /** Whether the underlying connection is open. */\n isConnected: () => boolean;\n /** Called when the connection fails a liveness check. */\n onTimeout: (timeout: HeartbeatTimeout) => void;\n /** Called for non-fatal problems, such as a heartbeat that could not be sent. */\n onError: (error: Error) => void;\n /** Clock injection point for tests. */\n now?: () => number;\n}\n\n/** Longest gap between staleness checks. */\nconst MAX_MONITOR_INTERVAL = 1000;\n\n/** Heartbeat lifecycle for one Gateway connection. */\nexport class GatewayHeartbeat {\n readonly #options: HeartbeatOptions;\n readonly #now: () => number;\n #interval = 0;\n #acknowledged = true;\n #sentAt = 0;\n #latency = -1;\n #lastMessageAt = 0;\n #zombieReported = false;\n #timer?: ReturnType<typeof setInterval>;\n #initialTimer?: ReturnType<typeof setTimeout>;\n #ackTimer?: ReturnType<typeof setTimeout>;\n #monitorTimer?: ReturnType<typeof setInterval>;\n\n public constructor(options: HeartbeatOptions) {\n if (options.zombieTimeout <= options.ackTimeout)\n throw new RangeError(\n \"Gateway zombieTimeout must be greater than heartbeatAckTimeout\",\n );\n this.#options = options;\n this.#now = options.now ?? (() => Date.now());\n }\n\n /** Round-trip time of the last acknowledged heartbeat, or -1 before the first. */\n public get latency(): number {\n return this.#latency;\n }\n\n /** Heartbeat interval Discord asked for, or 0 before HELLO. */\n public get interval(): number {\n return this.#interval;\n }\n\n /** Whether the most recent heartbeat has been acknowledged. */\n public get acknowledged(): boolean {\n return this.#acknowledged;\n }\n\n /** Milliseconds since the last inbound message, or 0 when none has arrived. */\n public get silentFor(): number {\n return this.#lastMessageAt === 0\n ? 0\n : this.#now() - this.#lastMessageAt;\n }\n\n /**\n * Deadline beyond which silence means the connection is dead.\n *\n * At least one heartbeat interval plus its ACK budget, so a quiet Gateway\n * is never mistaken for a dead one.\n */\n public get stalenessDeadline(): number {\n return Math.max(\n this.#options.zombieTimeout,\n this.#interval + this.#options.ackTimeout,\n );\n }\n\n /** Whether the connection looks alive: last beat acknowledged and traffic recent. */\n public isHealthy(): boolean {\n if (!this.#acknowledged) return false;\n if (this.#lastMessageAt === 0) return true;\n return this.silentFor < this.stalenessDeadline;\n }\n\n /**\n * Begins watching for silence. Call when the connection opens, before HELLO:\n * a connection that never reaches HELLO must still be detected as dead.\n */\n public watch(): void {\n this.#lastMessageAt = this.#now();\n this.#zombieReported = false;\n this.#startMonitor();\n }\n\n /** Records inbound traffic of any kind. */\n public receivedMessage(): void {\n this.#lastMessageAt = this.#now();\n this.#zombieReported = false;\n }\n\n /**\n * Starts heartbeating at Discord's interval.\n *\n * The first beat is jittered across the interval, as Discord's\n * documentation requires, so a fleet reconnecting together does not\n * heartbeat in lockstep.\n */\n public start(interval: number): void {\n this.#clearBeatTimers();\n this.#interval = interval;\n this.#acknowledged = true;\n // The regular cadence starts from the first beat, not from HELLO:\n // arming both at once can fire two beats back to back when the\n // jitter lands near the full interval.\n this.#initialTimer = setTimeout(() => {\n this.#initialTimer = undefined;\n this.sendHeartbeat();\n this.#timer = setInterval(() => this.sendHeartbeat(), interval);\n }, Math.random() * interval);\n }\n\n /** Stops every timer. Safe to call more than once. */\n public stop(): void {\n this.#clearBeatTimers();\n if (this.#monitorTimer) clearInterval(this.#monitorTimer);\n this.#monitorTimer = undefined;\n }\n\n /** Sends a heartbeat now, and arms the acknowledgement deadline. */\n public sendHeartbeat(): void {\n this.#acknowledged = false;\n this.#sentAt = this.#now();\n if (!this.#options.send(this.#options.sequence())) {\n this.#options.onError(\n new Error(\n \"Unable to send Gateway heartbeat because the WebSocket is not open.\",\n ),\n );\n return;\n }\n this.#clearAckTimer();\n this.#ackTimer = setTimeout(() => {\n if (this.#acknowledged) return;\n this.#options.onTimeout({\n type: \"ack\",\n elapsedMs: this.#now() - this.#sentAt,\n });\n }, this.#options.ackTimeout);\n }\n\n /** Records a heartbeat ACK and updates {@link latency}. */\n public acknowledge(): void {\n // An ACK with no heartbeat outstanding carries no round trip to measure.\n if (this.#acknowledged) return;\n this.#acknowledged = true;\n this.#latency = this.#now() - this.#sentAt;\n this.#clearAckTimer();\n }\n\n #startMonitor(): void {\n if (this.#monitorTimer) clearInterval(this.#monitorTimer);\n // Poll granularity only needs to be a fraction of the staleness\n // deadline. A 1s ceiling keeps detection latency negligible while\n // costing one wakeup per second per shard instead of four.\n const interval = Math.max(\n 1,\n Math.min(\n MAX_MONITOR_INTERVAL,\n this.#options.ackTimeout,\n this.#options.zombieTimeout / 2,\n ),\n );\n this.#monitorTimer = setInterval(\n () => this.#checkStaleness(),\n interval,\n );\n }\n\n #checkStaleness(): void {\n if (!this.#options.isConnected() || this.#lastMessageAt === 0) return;\n const silentFor = this.silentFor;\n const deadline = this.stalenessDeadline;\n if (silentFor < deadline || this.#zombieReported) return;\n // Report once per silence: the owner closes the connection, and the\n // close path stops these timers.\n this.#zombieReported = true;\n this.#options.onTimeout({ type: \"zombie\", silentFor, deadline });\n }\n\n #clearAckTimer(): void {\n if (this.#ackTimer) clearTimeout(this.#ackTimer);\n this.#ackTimer = undefined;\n }\n\n #clearBeatTimers(): void {\n if (this.#timer) clearInterval(this.#timer);\n if (this.#initialTimer) clearTimeout(this.#initialTimer);\n this.#clearAckTimer();\n this.#timer = undefined;\n this.#initialTimer = undefined;\n }\n}\n",
|
|
40
|
-
"/**\n * Discord Gateway close codes.\n *\n * Discord.js-familiar names and numeric values, matching the Discord Gateway\n * protocol. Exposed so consumers can branch on named codes instead of magic\n * numbers; {@link Gateway} uses them internally to decide resume/identify/stop.\n */\nexport const GatewayCloseCodes = {\n UnknownError: 4000,\n UnknownOpcode: 4001,\n DecodeError: 4002,\n NotAuthenticated: 4003,\n AuthenticationFailed: 4004,\n AlreadyAuthenticated: 4005,\n InvalidSeq: 4007,\n RateLimited: 4008,\n SessionTimedOut: 4009,\n InvalidShard: 4010,\n ShardingRequired: 4011,\n InvalidAPIVersion: 4012,\n InvalidIntents: 4013,\n DisallowedIntents: 4014,\n} as const;\n",
|
|
41
|
-
"/**\n * Reconnect policy and scheduling for one Gateway connection.\n *\n * Owns how a close code is classified, whether another attempt is allowed, how\n * long to wait, and the coordination that keeps at most one logical connection\n * attempt in flight. It owns no socket, no session state, no heartbeat and no\n * event emission: it is told a close code and whether a resume is possible, and\n * answers with a decision.\n */\nimport { GatewayCloseCodes } from \"./close-codes.js\";\n\n/** What a closed connection should do next. */\nexport type CloseAction =\n /** Reconnect and RESUME the existing session. */\n | \"resume\"\n /** Reconnect, but IDENTIFY afresh: the session cannot be resumed. */\n | \"identify\"\n /** Do not reconnect; the condition will not fix itself. */\n | \"stop\";\n\n/**\n * Close codes that no reconnect can recover from: bad token, bad shard\n * configuration, bad API version, or intents the application is not approved\n * for. Retrying these hammers Discord with a request that cannot succeed.\n */\nexport const FATAL_CLOSE_CODES: readonly number[] = [\n GatewayCloseCodes.AuthenticationFailed,\n GatewayCloseCodes.InvalidShard,\n GatewayCloseCodes.ShardingRequired,\n GatewayCloseCodes.InvalidAPIVersion,\n GatewayCloseCodes.InvalidIntents,\n GatewayCloseCodes.DisallowedIntents,\n];\n\n/**\n * Close codes that keep the connection recoverable but destroy the session, so\n * the next connection must IDENTIFY rather than RESUME.\n */\nexport const IDENTIFY_CLOSE_CODES: readonly number[] = [\n GatewayCloseCodes.InvalidSeq,\n GatewayCloseCodes.SessionTimedOut,\n];\n\n/**\n * Classifies a close code.\n *\n * Any code outside the two tables above is **reconnectable**: transport-level\n * closes (`1006`), server restarts (`1001`), Discord's own `4000`, and the\n * `1000` the Gateway itself sends after a non-resumable `op 9` all belong here.\n * Whether that reconnect resumes or identifies is not a property of the code —\n * it is whether a session survives, which is why `canResume` is a parameter\n * rather than something this module works out for itself.\n *\n * @param code WebSocket close code.\n * @param canResume Whether the session can still be resumed.\n */\nexport function classifyCloseCode(\n code: number,\n canResume: boolean,\n): CloseAction {\n if (FATAL_CLOSE_CODES.includes(code)) return \"stop\";\n if (IDENTIFY_CLOSE_CODES.includes(code)) return \"identify\";\n return canResume ? \"resume\" : \"identify\";\n}\n\n/** Why a reconnect was not scheduled. */\nexport type ScheduleRefusal =\n /** Automatic reconnect is disabled for this Gateway. */\n | \"disabled\"\n /** A reconnect is already armed; a second would open a second socket. */\n | \"pending\"\n /** The attempt budget is spent. */\n | \"exhausted\";\n\n/** Outcome of asking for a reconnect. */\nexport type ScheduleResult =\n | { scheduled: true; delayMs: number; attempt: number }\n | { scheduled: false; reason: ScheduleRefusal };\n\n/** Configuration for {@link GatewayReconnect}. */\nexport interface ReconnectOptions {\n /** Whether automatic reconnect is permitted at all. */\n enabled: boolean;\n /** Maximum consecutive attempts before giving up. */\n maxAttempts: number;\n /** Delay for the first attempt, doubled per attempt. */\n baseDelay: number;\n /** Ceiling for the backoff. */\n maxDelay: number;\n /** Randomness source for jitter; injected in tests. */\n random?: () => number;\n}\n\n/** Reconnect scheduling, backoff and attempt coordination. */\nexport class GatewayReconnect {\n readonly #options: ReconnectOptions;\n readonly #random: () => number;\n #attempt = 0;\n #timer?: ReturnType<typeof setTimeout>;\n #promise?: Promise<void>;\n #resolve?: () => void;\n #reject?: (error: Error) => void;\n\n public constructor(options: ReconnectOptions) {\n this.#options = options;\n this.#random = options.random ?? Math.random;\n }\n\n /** Whether automatic reconnect is permitted. */\n public get enabled(): boolean {\n return this.#options.enabled;\n }\n\n /** Consecutive attempts made since the last {@link reset}. */\n public get attempts(): number {\n return this.#attempt;\n }\n\n /** Whether a reconnect timer is currently armed. */\n public get pending(): boolean {\n return this.#timer !== undefined;\n }\n\n /** Whether the attempt budget is spent. */\n public get exhausted(): boolean {\n return this.#attempt >= this.#options.maxAttempts;\n }\n\n /** Whether a connection attempt is currently in flight. */\n public get connecting(): boolean {\n return this.#promise !== undefined;\n }\n\n /** The in-flight attempt, or undefined when none is active. */\n public get attemptPromise(): Promise<void> | undefined {\n return this.#promise;\n }\n\n /** Classifies a close code against this Gateway's policy. */\n public classifyClose(code: number, canResume: boolean): CloseAction {\n return classifyCloseCode(code, canResume);\n }\n\n /** Whether another reconnect is currently allowed. */\n public canReconnect(): boolean {\n return this.#options.enabled && !this.exhausted;\n }\n\n /**\n * Arms a reconnect, unless one is already armed or no attempt is allowed.\n *\n * Refusing while `pending` is what keeps repeated closes from stacking\n * timers: several closes in a row produce one reconnect, not several\n * competing sockets.\n */\n public schedule(run: () => void): ScheduleResult {\n if (!this.#options.enabled)\n return { scheduled: false, reason: \"disabled\" };\n if (this.#timer) return { scheduled: false, reason: \"pending\" };\n if (this.exhausted) return { scheduled: false, reason: \"exhausted\" };\n\n const attempt = this.#attempt;\n const delay = Math.min(\n this.#options.maxDelay,\n this.#options.baseDelay * 2 ** this.#attempt++,\n );\n // Jitter must scale with the delay: a fixed ceiling would reconnect\n // every shard inside the same narrow window after a gateway-wide\n // restart, which is exactly when decorrelation matters.\n const jitter = this.#random() * Math.max(1, delay * 0.25);\n const delayMs = delay + jitter;\n this.#timer = setTimeout(() => {\n this.#timer = undefined;\n run();\n }, delayMs);\n return { scheduled: true, delayMs, attempt };\n }\n\n /** Cancels an armed reconnect. Safe to call when none is armed. */\n public cancel(): void {\n if (this.#timer) clearTimeout(this.#timer);\n this.#timer = undefined;\n }\n\n /** Clears the attempt counter after a connection succeeds. */\n public reset(): void {\n this.#attempt = 0;\n }\n\n /**\n * Coordinates one logical connection attempt.\n *\n * Callers that ask while an attempt is in flight join it instead of\n * starting a second: three `connect()` calls produce one socket attempt and\n * one shared promise.\n *\n * @param start Invoked exactly once, when this call begins a new attempt.\n */\n public attempt(start: () => void): Promise<void> {\n if (this.#promise) return this.#promise;\n this.#promise = new Promise<void>((resolve, reject) => {\n this.#resolve = resolve;\n this.#reject = reject;\n start();\n });\n return this.#promise;\n }\n\n /** Settles the in-flight attempt, resolving it or rejecting with `error`. */\n public settle(error?: Error): void {\n const resolve = this.#resolve;\n const reject = this.#reject;\n this.#resolve = undefined;\n this.#reject = undefined;\n this.#promise = undefined;\n if (error) reject?.(error);\n else resolve?.();\n }\n}\n",
|
|
42
|
-
"/**\n * Turns WebSocket data into complete Gateway text frames.\n *\n * The contract is deliberately boring: bytes in, whole frames out. A decoder\n * knows nothing about opcodes, sessions, heartbeats or JSON validity — it only\n * knows when a frame is *complete*. Parsing the text is the protocol layer's\n * job, so malformed JSON is not a decoding failure; malformed *compressed\n * bytes* are.\n */\nimport {\n createInflate,\n constants as zlibConstants,\n type Inflate,\n} from \"node:zlib\";\n\n/** Decodes transport data into complete frames. */\nexport interface GatewayDecoder {\n /**\n * Feeds one WebSocket message.\n *\n * A decoder that can answer synchronously must do so: delivery timing is\n * observable to consumers, and an uncompressed frame has no reason to cost\n * a microtask.\n *\n * @returns Every frame completed by this chunk; empty while a frame is\n * still arriving.\n */\n push(data: unknown): string[] | Promise<string[]>;\n /** Discards buffered state. Call when a connection is replaced. */\n reset(): void;\n}\n\n/** Normalises a binary WebSocket payload into bytes. */\nasync function toBytes(data: unknown): Promise<Uint8Array> {\n if (data instanceof Uint8Array) return data;\n if (data instanceof ArrayBuffer) return new Uint8Array(data);\n if (typeof Blob !== \"undefined\" && data instanceof Blob)\n return new Uint8Array(await data.arrayBuffer());\n throw new TypeError(\n \"Gateway returned an unsupported compressed frame type.\",\n );\n}\n\n/** Passes text frames through unchanged, for an uncompressed connection. */\nexport class PlainTextDecoder implements GatewayDecoder {\n public push(data: unknown): string[] {\n return [String(data)];\n }\n public reset(): void {\n // Stateless: nothing to discard.\n }\n}\n\n/**\n * Decodes Discord's `zlib-stream` transport compression.\n *\n * Discord sends one zlib stream whose logical payloads are separated by the\n * `Z_SYNC_FLUSH` marker `00 00 FF FF`. A payload may span several WebSocket\n * messages, so output is produced only when that marker arrives: a partial\n * payload is retained rather than guessed at.\n *\n * The inflater carries state across frames, so `push` calls must not\n * interleave. {@link WebSocketTransport} serialises them by construction.\n */\nexport class ZlibStreamDecoder implements GatewayDecoder {\n readonly #create: () => Inflate;\n #inflate?: Inflate;\n #chunks: Uint8Array[] = [];\n #failure?: Error;\n /**\n * Rejector for the operation currently awaiting the inflater.\n *\n * zlib does **not** invoke a `write` or `flush` callback once the stream\n * has errored — it emits `error` and abandons the callback — so an\n * awaited callback alone hangs forever on corrupt input. The error handler\n * settles the waiter instead.\n */\n #pendingReject?: (error: Error) => void;\n\n
|
|
43
|
-
"/**\n * The WebSocket a Gateway connection runs on.\n *\n * Owns socket construction, listener wiring, sending, closing, and replacement.\n * It is infrastructure, not Discord semantics: it never inspects an opcode, a\n * session, or a heartbeat. Frames go out as text and come back as text.\n */\nimport { createDecoder, type GatewayDecoder } from \"./decoder.js\";\n\n/** Creates the underlying socket. Injected to support alternative runtimes. */\nexport type SocketFactory = (url: string) => WebSocket;\n\n/** Callbacks a transport reports to its owner. */\nexport interface TransportHandlers {\n /** The socket opened and is ready to send. */\n onOpen: () => void;\n /** A complete frame arrived, already decompressed. */\n onFrame: (raw: string) => void;\n /** The socket closed. */\n onClose: (code: number, reason: string) => void;\n /** A socket or decoding failure. Not a close on its own. */\n onError: (error: Error) => void;\n}\n\n/** Outcome of opening a connection. */\nexport type ConnectResult = { ok: true } | { ok: false; error: Error };\n\n/** Configuration for {@link WebSocketTransport}. */\nexport interface TransportOptions {\n /** Handlers for this transport's lifetime. */\n handlers: TransportHandlers;\n /** Frame decoder. Defaults to plain text, or zlib-stream when compressing. */\n decoder?: GatewayDecoder;\n /** Whether the connection negotiates `zlib-stream` compression. */\n compress?: boolean;\n /** Socket constructor. Defaults to the ambient `WebSocket`. */\n createSocket?: SocketFactory;\n}\n\n/** WebSocket states. Compared numerically so a stub needs no static constants. */\nconst OPEN = 1;\n\n/**\n * A replaceable WebSocket connection.\n *\n * **Generations.** Each {@link connect} takes a generation, and every event is\n * checked against the current one. A socket that has been replaced still holds\n * its listeners and can still fire — especially a frame that finishes\n * decompressing after the swap — and every such event is dropped. The owner\n * therefore never has to ask \"is this still my socket?\".\n */\nexport class WebSocketTransport {\n readonly #handlers: TransportHandlers;\n readonly #decoder: GatewayDecoder;\n readonly #createSocket: SocketFactory;\n readonly #compress: boolean;\n #socket?: WebSocket;\n #generation = 0;\n /** Serialises decoding so stateful decoders never see interleaved chunks. */\n #queue: Promise<void> = Promise.resolve();\n\n public constructor(options: TransportOptions) {\n this.#handlers = options.handlers;\n this.#compress = options.compress ?? false;\n this.#decoder = options.decoder ?? createDecoder(options.compress);\n this.#createSocket =\n options.createSocket ?? ((url: string) => new WebSocket(url));\n }\n\n /** Whether a socket is open and able to send. */\n public get connected(): boolean {\n return this.#socket?.readyState === OPEN;\n }\n\n /** Whether a socket is connecting or open, and therefore still in play. */\n public get live(): boolean {\n return this.#socket !== undefined && this.#socket.readyState <= OPEN;\n }\n\n /** Current connection generation; increments on every {@link connect}. */\n public get generation(): number {\n return this.#generation;\n }\n\n /**\n * Opens a connection, replacing any existing one.\n *\n * A construction failure is returned rather than reported through\n * `onError`: the caller is mid-`connect` and must decide what the failure\n * means for the attempt it is running.\n */\n public connect(url: string): ConnectResult {\n // Never leave a predecessor behind: an orphan keeps its listeners and\n // would go on feeding this transport's owner.\n this.#discard(1000, \"Superseded by a new connection\");\n const generation = ++this.#generation;\n // A replaced connection's decoder state is meaningless to the new one.\n this.#decoder.reset();\n this.#queue = Promise.resolve();\n\n let socket: WebSocket;\n try {\n socket = this.#createSocket(url);\n } catch (error) {\n return { ok: false, error: this.#asError(error) };\n }\n if (this.#compress) {\n try {\n (socket as { binaryType?: string }).binaryType = \"arraybuffer\";\n } catch {\n // Runtimes that pin binaryType are handled by the decoder.\n }\n }\n this.#socket = socket;\n\n socket.addEventListener(\"open\", () => {\n if (!this.#owns(generation)) return;\n this.#handlers.onOpen();\n });\n socket.addEventListener(\"message\", (event) => {\n if (!this.#owns(generation)) return;\n // A decoder that answers synchronously is delivered synchronously:\n // an uncompressed frame must not become a microtask, because\n // dispatch timing is observable to consumers.\n let decoded: string[] | Promise<string[]>;\n try {\n decoded = this.#decoder.push(event.data);\n } catch (error) {\n this.#handlers.onError(this.#asError(error));\n return;\n }\n if (!(decoded instanceof Promise)) {\n for (const frame of decoded) this.#handlers.onFrame(frame);\n return;\n }\n // A stateful decoder must never see interleaved chunks, and the\n // generation is re-checked once the chunk is actually decoded: the\n // socket may have been replaced while this frame was in flight.\n this.#queue = this.#queue\n .then(async () => {\n const frames = await decoded;\n if (!this.#owns(generation)) return;\n for (const frame of frames) this.#handlers.onFrame(frame);\n })\n .catch((error) => {\n if (!this.#owns(generation)) return;\n this.#handlers.onError(this.#asError(error));\n });\n });\n socket.addEventListener(\"close\", (event) => {\n if (!this.#owns(generation)) return;\n this.#socket = undefined;\n // A closed socket owns nothing further. Retiring its generation\n // here is what makes every later event from it — a late frame, a\n // second close, an error — stale by construction, including a\n // frame that was still decompressing when the socket went away.\n this.#generation++;\n this.#decoder.reset();\n this.#handlers.onClose(event.code, event.reason ?? \"\");\n });\n socket.addEventListener(\"error\", () => {\n if (!this.#owns(generation)) return;\n this.#handlers.onError(new Error(\"Gateway WebSocket error\"));\n });\n return { ok: true };\n }\n\n /**\n * Writes a frame.\n * @returns Whether it reached the socket.\n */\n public send(data: string): boolean {\n if (!this.connected) return false;\n try {\n this.#socket!.send(data);\n return true;\n } catch (error) {\n this.#handlers.onError(this.#asError(error));\n return false;\n }\n }\n\n /** Closes the current socket, if any. Its `close` event still fires. */\n public close(code = 1000, reason = \"\"): void {\n const socket = this.#socket;\n if (!socket) return;\n try {\n socket.close(code, reason);\n } catch (error) {\n this.#handlers.onError(this.#asError(error));\n }\n }\n\n /**\n * Abandons the current socket without reporting its close.\n *\n * Used for a deliberate shutdown, where the owner has already decided the\n * connection is over and must not be woken by the resulting close event.\n */\n public destroy(code = 1000, reason = \"\"): void {\n this.#discard(code, reason);\n this.#decoder.reset();\n }\n\n /** Whether `generation` still owns this transport. */\n #owns(generation: number): boolean {\n return generation === this.#generation;\n }\n\n /** Detaches and closes the current socket without emitting its close. */\n #discard(code: number, reason: string): void {\n const socket = this.#socket;\n if (!socket) return;\n // Bumping the generation first makes every event this socket may still\n // fire — including a close caused by the call below — a stale event.\n this.#generation++;\n this.#socket = undefined;\n try {\n socket.close(code, reason);\n } catch (error) {\n this.#handlers.onError(this.#asError(error));\n }\n }\n\n #asError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n }\n}\n",
|
|
44
|
-
"/** Discord Gateway opcodes. */\nexport const GatewayOpcodes = {\n Dispatch: 0,\n Heartbeat: 1,\n Identify: 2,\n PresenceUpdate: 3,\n VoiceStateUpdate: 4,\n Resume: 6,\n Reconnect: 7,\n RequestGuildMembers: 8,\n InvalidSession: 9,\n Hello: 10,\n HeartbeatAck: 11,\n} as const;\n",
|
|
45
|
-
"/**\n * Discord Gateway protocol: what a payload *means*.\n *\n * Pure translation from a received frame to an action, plus construction of\n * the payloads Lunibee sends. It performs nothing: no socket, no timers, no\n * session mutation, no event emission, no sending. The caller decides what to\n * do with an action, which is what lets the whole protocol be tested without a\n * connection.\n */\nimport type { GatewayPayload, GatewayPresence } from \"@lunibee/types\";\nimport { GatewayOpcodes } from \"./opcodes.js\";\nimport type { ResumeInfo } from \"./session.js\";\n\n/** Why a frame could not be understood. */\nexport type ProtocolViolation =\n /** The frame was not valid JSON. */\n | \"invalid-json\"\n /** The frame decoded to something other than a payload object. */\n | \"invalid-payload\"\n /** `HELLO` carried no usable heartbeat interval. */\n | \"invalid-hello\";\n\n/** What a received frame means. */\nexport type GatewayAction =\n /** `op 10`: begin heartbeating and hand shake. */\n | { type: \"hello\"; heartbeatInterval: number }\n /** `op 0`: an event. `event` is null only if Discord omitted `t`. */\n | { type: \"dispatch\"; event: string | null; data: unknown }\n /** `op 1`: Discord asks for a heartbeat now. */\n | { type: \"heartbeat\" }\n /** `op 11`: the last heartbeat was acknowledged. */\n | { type: \"heartbeat-ack\"; data: unknown }\n /** `op 7`: Discord asks the client to reconnect. */\n | { type: \"reconnect\" }\n /** `op 9`: the session is gone. `resumable` decides RESUME vs IDENTIFY. */\n | { type: \"invalid-session\"; resumable: boolean }\n /**\n * An opcode this version does not handle.\n *\n * Ignored rather than treated as an error: Discord adds opcodes, and a\n * client that fails on an unfamiliar one breaks itself on every addition.\n */\n | { type: \"unknown\"; opcode: number }\n /** The frame was malformed. Never silently swallowed. */\n | {\n type: \"invalid\";\n violation: ProtocolViolation;\n message: string;\n cause?: unknown;\n };\n\n/** A classified frame: its sequence, if any, and what it means. */\nexport interface ProtocolResult {\n /**\n * Sequence carried by the frame, or null when it carried none.\n *\n * Reported for every payload type, not just dispatches: recording it is\n * the caller's decision, and the caller records before acting so a RESUME\n * cannot be built from a sequence that was never seen.\n */\n sequence: number | null;\n /** What the frame means. */\n action: GatewayAction;\n}\n\n/**\n * Classifies one received frame.\n *\n * @param raw The frame text, already decompressed by the transport.\n */\nexport function classifyFrame(raw: string): ProtocolResult {\n let payload: GatewayPayload;\n try {\n payload = JSON.parse(raw) as GatewayPayload;\n } catch (error) {\n return {\n sequence: null,\n action: {\n type: \"invalid\",\n violation: \"invalid-json\",\n message: \"Gateway returned invalid JSON\",\n cause: error,\n },\n };\n }\n return classifyPayload(payload);\n}\n\n/** Classifies an already-parsed payload. */\nexport function classifyPayload(payload: unknown): ProtocolResult {\n if (\n payload === null ||\n typeof payload !== \"object\" ||\n typeof (payload as GatewayPayload).op !== \"number\"\n )\n return {\n sequence: null,\n action: {\n type: \"invalid\",\n violation: \"invalid-payload\",\n message: \"Gateway returned an invalid payload\",\n },\n };\n\n const frame = payload as GatewayPayload;\n const sequence = typeof frame.s === \"number\" ? frame.s : null;\n\n switch (frame.op) {\n case GatewayOpcodes.Dispatch:\n return {\n sequence,\n action: {\n type: \"dispatch\",\n event: typeof frame.t === \"string\" ? frame.t : null,\n data: frame.d,\n },\n };\n case GatewayOpcodes.Hello: {\n const interval = (frame.d as { heartbeat_interval?: unknown })\n ?.heartbeat_interval;\n if (\n typeof interval !== \"number\" ||\n !Number.isFinite(interval) ||\n interval <= 0\n )\n return {\n sequence,\n action: {\n type: \"invalid\",\n violation: \"invalid-hello\",\n message:\n \"Gateway HELLO payload contains an invalid heartbeat interval\",\n },\n };\n return {\n sequence,\n action: { type: \"hello\", heartbeatInterval: interval },\n };\n }\n case GatewayOpcodes.Heartbeat:\n return { sequence, action: { type: \"heartbeat\" } };\n case GatewayOpcodes.HeartbeatAck:\n return {\n sequence,\n action: { type: \"heartbeat-ack\", data: frame.d },\n };\n case GatewayOpcodes.Reconnect:\n return { sequence, action: { type: \"reconnect\" } };\n case GatewayOpcodes.InvalidSession:\n // `d` is a boolean: true means the session may still be resumed.\n // Anything else is treated as non-resumable, which is the safe\n // reading — a wrongly-attempted RESUME costs another round trip.\n return {\n sequence,\n action: {\n type: \"invalid-session\",\n resumable: frame.d === true,\n },\n };\n default:\n return { sequence, action: { type: \"unknown\", opcode: frame.op } };\n }\n}\n\n/** Identification properties sent with IDENTIFY. */\nexport interface IdentifyProperties {\n os?: string;\n browser?: string;\n device?: string;\n [key: string]:
|
|
46
|
-
"/** Gateway connection lifecycle states. */\nexport enum GatewayState {\n /** Initial connection state.
|
|
47
|
-
"/**\n * Sliding-window budget for outgoing Gateway payloads.\n *\n * Discord allows 120 sends per 60 seconds. Application traffic is capped at\n * 115 so the remaining headroom is reserved for privileged sends (heartbeats),\n * which are still recorded so the true total stays under Discord's limit.\n */\nexport class SendBudget {\n readonly #timestamps: number[] = [];\n readonly #limit: number;\n readonly #windowMs: number;\n\n public constructor(limit = 115, windowMs = 60_000) {\n this.#limit = limit;\n this.#windowMs = windowMs;\n }\n\n /** Sends recorded within the current window. */\n public get used(): number {\n return this.#timestamps.length;\n }\n\n /** Whether a send may go out now. Privileged sends always may. */\n public allows(privileged: boolean, now = Date.now()): boolean {\n while (\n this.#timestamps.length &&\n now - this.#timestamps[0]! >= this.#windowMs\n )\n this.#timestamps.shift();\n return privileged || this.#timestamps.length < this.#limit;\n }\n\n /** Records a send that went out. */\n public record(now = Date.now()): void {\n this.#timestamps.push(now);\n }\n}\n",
|
|
48
|
-
"import { GatewaySession } from \"./session.js\";\nimport { GatewayHeartbeat, type HeartbeatTimeout } from \"./heartbeat.js\";\nimport { GatewayCloseCodes } from \"./close-codes.js\";\nimport { GatewayReconnect, type CloseAction } from \"./reconnect.js\";\nimport { WebSocketTransport, type SocketFactory } from \"./transport.js\";\nimport { GatewayOpcodes } from \"./opcodes.js\";\nimport {\n classifyFrame,\n identifyPayload,\n resumePayload,\n heartbeatPayload,\n type GatewayAction,\n} from \"./protocol.js\";\nimport {\n resolveGatewayIntents,\n type GatewayPayload,\n type GatewayProperties,\n type GatewayPresence,\n type GatewayIntentResolvable,\n} from \"@lunibee/types\";\n\nexport {\n classifyFrame,\n classifyPayload,\n identifyPayload,\n resumePayload,\n heartbeatPayload,\n type GatewayAction,\n type ProtocolResult,\n type ProtocolViolation,\n type IdentifyOptions,\n type IdentifyProperties,\n} from \"./protocol.js\";\n\nexport {\n WebSocketTransport,\n type TransportHandlers,\n type TransportOptions,\n type SocketFactory,\n} from \"./transport.js\";\n\nexport {\n createDecoder,\n PlainTextDecoder,\n ZlibStreamDecoder,\n type GatewayDecoder,\n} from \"./decoder.js\";\n\nexport {\n GatewayReconnect,\n classifyCloseCode,\n FATAL_CLOSE_CODES,\n IDENTIFY_CLOSE_CODES,\n type CloseAction,\n type ReconnectOptions,\n type ScheduleResult,\n type ScheduleRefusal,\n} from \"./reconnect.js\";\n\nexport {\n GatewayHeartbeat,\n type HeartbeatOptions,\n type HeartbeatTimeout,\n} from \"./heartbeat.js\";\n\nexport {\n GatewaySession,\n type ResumeInfo,\n type HandshakeIntent,\n type InvalidationReason,\n} from \"./session.js\";\n\nexport { GatewayOpcodes } from \"./opcodes.js\";\n\nexport { GatewayCloseCodes } from \"./close-codes.js\";\n\nexport { GatewayState, Status, GatewayError } from \"./state.js\";\nimport { GatewayState, GatewayError } from \"./state.js\";\nimport { SendBudget } from \"./send-budget.js\";\n/** Gateway connection configuration. */\nexport interface GatewayOptions {\n /** Authentication token. */ token: string;\n /** Gateway intent bitfield or resolvable. */ intents: GatewayIntentResolvable;\n /** Shard identifier. */ shardId?: number;\n /** Total shard count. */ shardCount?: number;\n /** Whether automatic reconnect is enabled. */ reconnect?: boolean;\n /** Maximum reconnect attempts. */ maxReconnectAttempts?: number;\n /** Initial reconnect delay. */ reconnectBaseDelay?: number;\n /** Maximum reconnect delay. */ reconnectMaxDelay?: number;\n /** Heartbeat acknowledgement timeout. */ heartbeatAckTimeout?: number;\n /** Zombie connection timeout. */ zombieTimeout?: number;\n /** Identification properties. */ properties?: GatewayProperties;\n /** Presence data. */ presence?: GatewayPresence;\n /**\n * Whether to enable zlib-stream transport compression.\n * Decoded with a persistent `node:zlib` inflate stream, matching\n * Discord's zlib-wrapped stream framing (`Z_SYNC_FLUSH` boundaries).\n * When enabled, appends `&compress=zlib-stream` to the Gateway URL.\n */\n compress?: boolean;\n /**\n * Constructs the underlying socket. Defaults to the ambient `WebSocket`.\n * Injected to run the Gateway on an alternative transport, or on a stub.\n */\n createSocket?: SocketFactory;\n}\n/** Discord's main Gateway endpoint, used when no resume host is known. */\n/**\n * Close code for connections Lunibee means to RESUME. Discord invalidates the\n * session when a client closes with 1000 or 1001, so a reconnect that should\n * keep its session must close with anything else.\n */\nconst RESUMABLE_CLOSE_CODE = 4900;\nconst DEFAULT_GATEWAY_URL = \"wss://gateway.discord.gg/?v=10&encoding=json\";\n\n/** Gateway event listener. */\ntype GatewayListener = (data: unknown) => unknown;\n/** Manages a Discord Gateway connection. */\nexport class Gateway {\n /** Current Gateway lifecycle state. */\n public state: GatewayState = GatewayState.Connect;\n #options: Required<\n Omit<\n GatewayOptions,\n \"properties\" | \"presence\" | \"compress\" | \"createSocket\" | \"intents\"\n >\n > & {\n /** Resolved intent bitfield, never the resolvable form. */\n intents: number;\n properties?: GatewayProperties;\n presence?: GatewayPresence;\n compress?: boolean;\n };\n /**\n * The socket this connection runs on.\n *\n * The Gateway never touches a `WebSocket` directly: construction, listener\n * wiring, replacement and decoding all belong to the transport.\n */\n readonly #transport: WebSocketTransport;\n /**\n * Session identity and the IDENTIFY-vs-RESUME decision.\n *\n * The Gateway holds no session fields of its own: every read and write goes\n * through the session, which rejects mutations from a superseded socket.\n */\n readonly #session = new GatewaySession();\n /** Token of the socket this Gateway currently owns. */\n #token = 0;\n /**\n * Heartbeat, acknowledgement deadline and staleness watch.\n *\n * The Gateway holds no heartbeat timers of its own; it supplies the socket\n * and decides what to close when liveness fails.\n */\n readonly #heartbeat: GatewayHeartbeat;\n #closed = false;\n /**\n * Close classification, backoff, scheduling, and the coordination that\n * keeps at most one logical connection attempt in flight.\n */\n readonly #reconnect: GatewayReconnect;\n readonly #listeners = new Map<string, Set<GatewayListener>>();\n /** Application send budget under Discord's 120-per-60s limit. */\n readonly #sendBudget = new SendBudget();\n public ping: number = -1;\n /** Creates a Gateway connection manager. @param options Gateway configuration. @throws {TypeError|RangeError} If configuration is invalid. */\n public constructor(options: GatewayOptions) {\n if (!options.token?.trim())\n throw new TypeError(\"A Gateway token is required.\");\n const resolvedIntents = resolveGatewayIntents(options.intents);\n if (!Number.isInteger(resolvedIntents) || resolvedIntents < 0)\n throw new TypeError(\n \"Gateway intents must be a non-negative integer.\",\n );\n this.#options = {\n shardId: 0,\n shardCount: 1,\n reconnect: true,\n maxReconnectAttempts: Infinity,\n reconnectBaseDelay: 1000,\n reconnectMaxDelay: 30000,\n heartbeatAckTimeout: 10000,\n zombieTimeout: 30000,\n properties: {\n os: \"Android\",\n browser: \"Discord Android\",\n device: \"Discord Android\",\n },\n presence: {\n status: \"online\",\n activities: [],\n afk: false,\n since: null,\n },\n ...options,\n // Store the *resolved* bitfield, not the resolvable the caller\n // passed. IDENTIFY must carry a number: sending the array or\n // string form verbatim makes Discord answer 4013 (invalid\n // intents), which is a fatal close — so the documented array form\n // would never connect.\n intents: resolvedIntents,\n };\n if (\n this.#options.shardId < 0 ||\n this.#options.shardId >= this.#options.shardCount\n )\n throw new RangeError(\n \"Gateway shardId must be within the configured shard count.\",\n );\n if (this.#options.zombieTimeout <= this.#options.heartbeatAckTimeout)\n throw new RangeError(\n \"Gateway zombieTimeout must be greater than heartbeatAckTimeout\",\n );\n this.#transport = new WebSocketTransport({\n compress: this.#options.compress,\n createSocket: options.createSocket,\n handlers: {\n onOpen: () => this.#onOpen(),\n onFrame: (raw) => this.#message(raw, this.#token),\n onClose: (code) => this.#close(code, this.#token),\n // Transport failures reach consumers as GatewayError, the\n // type every other Gateway error path already uses.\n onError: (error) =>\n this.#emitError(\n error instanceof GatewayError\n ? error\n : new GatewayError(error.message, undefined, {\n cause: error,\n }),\n ),\n },\n });\n this.#reconnect = new GatewayReconnect({\n enabled: this.#options.reconnect,\n maxAttempts: this.#options.maxReconnectAttempts,\n baseDelay: this.#options.reconnectBaseDelay,\n maxDelay: this.#options.reconnectMaxDelay,\n });\n this.#heartbeat = new GatewayHeartbeat({\n ackTimeout: this.#options.heartbeatAckTimeout,\n zombieTimeout: this.#options.zombieTimeout,\n // Heartbeats are privileged: application traffic must never starve\n // the one payload that keeps the connection alive.\n send: (sequence) =>\n this.#dispatch(heartbeatPayload(sequence), true),\n sequence: () => this.#session.sequence,\n isConnected: () => !this.#closed && this.#transport.connected,\n onTimeout: (timeout) => this.#onHeartbeatTimeout(timeout),\n onError: (error) => this.#emitError(error),\n });\n }\n\n /**\n * Closes a connection that failed a liveness check.\n *\n * The heartbeat decides *that* the connection is dead; the Gateway decides\n * what to do about it, because only the Gateway owns the socket.\n */\n #onHeartbeatTimeout(timeout: HeartbeatTimeout): void {\n if (timeout.type === \"zombie\") {\n this.#emit(\"zombie\", {\n silentFor: timeout.silentFor,\n timeout: timeout.deadline,\n });\n this.#emitError(\n new GatewayError(\n `Gateway connection appears stale after ${timeout.silentFor}ms without traffic.`,\n ),\n );\n } else {\n this.#emitError(\n new GatewayError(\n `Gateway heartbeat acknowledgement timed out after ${timeout.elapsedMs}ms.`,\n ),\n );\n }\n this.#transport.close(\n RESUMABLE_CLOSE_CODE,\n timeout.type === \"zombie\"\n ? \"Zombie Gateway connection\"\n : \"Heartbeat timeout\",\n );\n }\n\n /** Opens the Gateway connection. @param url Gateway WebSocket URL. @returns Promise fulfilled when the socket opens. @throws {GatewayError} If permanently closed or unable to connect. */\n public connect(url = DEFAULT_GATEWAY_URL): Promise<void> {\n if (this.state === GatewayState.Closed)\n throw new GatewayError(\"Gateway has been permanently closed.\");\n // At most one logical connection attempt is active: concurrent callers\n // join the in-flight attempt rather than opening competing sockets.\n const inFlight = this.#reconnect.attemptPromise;\n if (inFlight) return inFlight;\n // Connecting an already-live Gateway must be a no-op. Opening a second\n // socket leaves the first one unmanaged but still dispatching, which\n // interleaves two sequence streams (corrupting a later RESUME) and\n // sends a second IDENTIFY on the same session.\n if (this.#transport.live) return Promise.resolve();\n // A manual connect supersedes a scheduled reconnect; leaving the timer\n // armed would open a second socket once it fires.\n this.#reconnect.cancel();\n this.#closed = false;\n this.#setState(GatewayState.Connect);\n // Append compression parameter if enabled\n const connectURL = this.#options.compress\n ? url.includes(\"compress=\")\n ? url\n : `${url}&compress=zlib-stream`\n : url;\n return this.#reconnect.attempt(() => this.#open(connectURL));\n }\n /** Permanently closes the Gateway connection. */\n public close(): void {\n this.#closed = true;\n this.#clearTimers();\n this.#settleConnect(\n new GatewayError(\"Gateway connection closed before socket open.\"),\n );\n // Abandon rather than close-and-listen: the Gateway has already decided\n // the connection is over and must not be woken by its close event.\n this.#transport.destroy(1000, \"Client closed connection\");\n this.#setState(GatewayState.Closed);\n }\n /** Registers a Gateway event listener. @param event Event name. @param listener Event callback. @returns This Gateway. */\n /** Emits an event to all registered listeners. @param event Event name. @param data Event payload. */\n public emit(event: string, data?: unknown): void {\n this.#emit(event, data);\n }\n public on(event: string, listener: GatewayListener): this {\n if (!event || typeof listener !== \"function\")\n throw new TypeError(\"Gateway event and listener are required.\");\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 /** Removes a Gateway event listener. @param event Event name. @param listener Event callback. @returns This Gateway. */\n public off(event: string, listener: GatewayListener): this {\n this.#listeners.get(event)?.delete(listener);\n return this;\n }\n /** Sends a Gateway payload. @param payload Gateway payload. @returns Whether it was sent. */\n public send(payload: GatewayPayload): boolean {\n if (!payload || !Number.isInteger(payload.op))\n throw new TypeError(\n \"Gateway payload must contain an integer opcode.\",\n );\n return this.#dispatch(payload, false);\n }\n /**\n * Writes a payload to the socket. Heartbeats pass `privileged` so they are\n * never starved by application traffic: the 115 budget sits below\n * Discord's real 120/60s limit precisely to leave room for them, so\n * spending that headroom on heartbeats is what it is reserved for. They\n * are still recorded, keeping the true total under Discord's limit.\n */\n #dispatch(payload: GatewayPayload, privileged: boolean): boolean {\n if (!this.#transport.connected) return false;\n const now = Date.now();\n if (!this.#sendBudget.allows(privileged, now)) {\n this.#emitError(\n new GatewayError(\"Gateway send rate budget exhausted.\"),\n );\n return false;\n }\n if (!this.#transport.send(JSON.stringify(payload))) return false;\n this.#sendBudget.record(now);\n return true;\n }\n /** Sends a presence update. @param data Presence payload. @returns Whether it was sent. */\n public setPresence(data: GatewayPresence): boolean {\n this.#options.presence = { ...this.#options.presence, ...data };\n const payload = {\n since: this.#options.presence.since ?? null,\n activities: this.#options.presence.activities ?? [],\n status: this.#options.presence.status ?? \"online\",\n afk: Boolean(this.#options.presence.afk),\n };\n return this.send({\n op: GatewayOpcodes.PresenceUpdate,\n d: payload,\n s: null,\n t: null,\n });\n }\n /** Sends a voice state update. @param data Voice state payload. @returns Whether it was sent. */\n public setVoiceState(data: Record<string, unknown>): boolean {\n return this.send({\n op: GatewayOpcodes.VoiceStateUpdate,\n d: data,\n s: null,\n t: null,\n });\n }\n /** Requests guild members. @param data Guild member request payload. @returns Whether it was sent. */\n public requestGuildMembers(data: Record<string, unknown>): boolean {\n return this.send({\n op: GatewayOpcodes.RequestGuildMembers,\n d: data,\n s: null,\n t: null,\n });\n }\n /**\n * Starts one connection attempt.\n *\n * Ownership of the session moves to this attempt before the socket exists,\n * so a frame from the socket being replaced can never be mistaken for one\n * belonging to this connection.\n */\n #open(url: string): void {\n if (this.#closed) return;\n this.#token = this.#session.beginConnection();\n const result = this.#transport.connect(url);\n if (result.ok) return;\n // The socket could not be constructed. The caller's attempt fails with\n // the underlying reason, so a thrown GatewayError keeps its message.\n const failure = this.#normalizeError(result.error);\n this.#emitError(failure);\n if (this.#options.reconnect) {\n this.#setState(GatewayState.Reconnect);\n this.#scheduleReconnect();\n } else {\n this.#settleConnect(failure);\n }\n }\n #onOpen(): void {\n // Watch for silence from the moment the socket opens: a connection\n // that never reaches HELLO must still be detected as dead.\n this.#heartbeat.watch();\n this.#emit(\"open\", undefined);\n this.#settleConnect();\n }\n #message(raw: string, token: number): void {\n // The transport already drops frames from a replaced socket; this\n // second check keeps the session authoritative about who may mutate it.\n if (!this.#session.owns(token)) return;\n // Any frame from the current socket proves it is alive. Without this the\n // silence clock only moved on open, so every healthy connection was\n // declared a zombie once the staleness deadline passed.\n this.#heartbeat.receivedMessage();\n const { sequence, action } = classifyFrame(raw);\n // Record before acting: a RESUME must never be built from a sequence\n // the connection has not actually observed. The session ignores a\n // sequence from a superseded connection.\n if (sequence !== null) this.#session.recordSequence(sequence, token);\n this.#apply(action, token);\n }\n /**\n * Performs what the protocol says a frame meant.\n *\n * Every branch is an operation the protocol layer deliberately cannot do\n * for itself: closing a socket, mutating the session, running timers,\n * emitting events.\n */\n #apply(action: GatewayAction, token: number): void {\n switch (action.type) {\n case \"dispatch\":\n this.#setState(GatewayState.Dispatch);\n this.#handleDispatch(action.event, action.data, token);\n return;\n case \"hello\":\n this.#handleHello(action.heartbeatInterval);\n return;\n case \"heartbeat\":\n this.#setState(GatewayState.Heartbeat);\n this.#heartbeat.sendHeartbeat();\n return;\n case \"heartbeat-ack\":\n this.#heartbeat.acknowledge();\n this.ping = this.#heartbeat.latency;\n this.#emit(\"heartbeatAck\", action.data);\n return;\n case \"reconnect\":\n this.#transport.close(\n RESUMABLE_CLOSE_CODE,\n \"Server requested reconnect\",\n );\n return;\n case \"invalid-session\": {\n // A resumable invalidation keeps the session; a non-resumable\n // one destroys it, so the next connection must IDENTIFY.\n if (!action.resumable)\n this.#session.invalidate(token, \"invalid-session\");\n this.#emit(\"invalidSession\", action.resumable);\n this.#transport.close(\n action.resumable ? GatewayCloseCodes.UnknownError : 1000,\n action.resumable\n ? \"Invalid session (resumable)\"\n : \"Invalid session\",\n );\n return;\n }\n case \"invalid\":\n this.#emitError(\n new GatewayError(\n action.message,\n undefined,\n action.cause === undefined\n ? undefined\n : { cause: action.cause },\n ),\n );\n this.#transport.close(\n 1002,\n action.violation === \"invalid-json\"\n ? \"Invalid JSON\"\n : action.violation === \"invalid-hello\"\n ? \"Invalid heartbeat interval\"\n : \"Invalid payload\",\n );\n return;\n case \"unknown\":\n // Forward compatibility: Discord may add opcodes, and an\n // unfamiliar one is not a failure.\n return;\n }\n }\n #handleDispatch(event: string | null, data: unknown, token: number): void {\n if (event === \"READY\") {\n if (!this.#session.activate(data, token)) {\n // Either the payload lacked session information or this socket\n // no longer owns the session; only the former is an error.\n if (this.#session.owns(token))\n this.#emitError(\n new GatewayError(\n \"Gateway READY payload is missing session information\",\n ),\n );\n return;\n }\n this.#reconnect.reset();\n this.#setState(GatewayState.Ready);\n this.#emit(\"ready\", data);\n } else if (event === \"RESUMED\") {\n // A successful RESUME ends the reconnect cycle just like READY:\n // reset the backoff counter so a later disconnect starts from the\n // base delay, mark the connection READY, and surface a Discord.js-\n // familiar `resumed` event.\n this.#reconnect.reset();\n this.#setState(GatewayState.Ready);\n this.#emit(\"resumed\", data);\n }\n this.#emit(\"RAW\", { event: event ?? \"UNKNOWN\", data });\n if (this.#closed) return;\n this.#emit(event ?? \"dispatch\", data);\n }\n #handleHello(interval: number): void {\n this.#setState(\n this.#session.canResume ? GatewayState.Resume : GatewayState.Hello,\n );\n this.#heartbeat.start(interval);\n this.#identifyOrResume();\n }\n #identifyOrResume(): void {\n const intent = this.#session.handshake();\n // IDENTIFY/RESUME are privileged for the same reason heartbeats are:\n // dropping one leaves the shard connected but never READY, recoverable\n // only via the zombie timeout. Application traffic must never starve\n // the handshake out of the send budget.\n if (intent.type === \"resume\") {\n this.#setState(GatewayState.Resume);\n this.#dispatch(resumePayload(this.#options.token, intent), true);\n return;\n }\n this.#setState(GatewayState.Identify);\n this.#dispatch(\n identifyPayload({\n token: this.#options.token,\n intents: this.#options.intents,\n shardId: this.#options.shardId,\n shardCount: this.#options.shardCount,\n properties: this.#options.properties,\n presence: this.#options.presence,\n }),\n true,\n );\n }\n #close(code: number, token: number): void {\n this.#clearTimers();\n const action: CloseAction = this.#reconnect.classifyClose(\n code,\n this.#session.canResume,\n );\n this.#emit(\"close\", { code, action });\n if (this.#closed || !this.#reconnect.enabled || action === \"stop\") {\n // A fatal close is terminal: the condition behind 4004/4013/4014\n // cannot fix itself, so the Gateway settles as CLOSED rather than\n // sitting in CONNECT looking like it is about to try again (WS-003).\n if (action === \"stop\") this.#closed = true;\n this.#setState(\n this.#closed ? GatewayState.Closed : GatewayState.Connect,\n );\n if (this.#reconnect.connecting)\n this.#reconnect.settle(\n new GatewayError(\n `Gateway closed before READY (code ${code}).`,\n code,\n ),\n );\n return;\n }\n if (action === \"identify\")\n // Fresh IDENTIFY: drop the session AND its resume host so the\n // reconnect targets the main Gateway, not a stale resume URL.\n this.#session.invalidate(token, \"session-timeout\");\n this.#setState(GatewayState.Reconnect);\n this.#scheduleReconnect();\n }\n #scheduleReconnect(): void {\n if (this.#closed) return;\n const result = this.#reconnect.schedule(() =>\n this.#open(this.#session.connectURL(DEFAULT_GATEWAY_URL)),\n );\n if (result.scheduled || result.reason !== \"exhausted\") return;\n this.#reconnect.settle(\n new GatewayError(\"Gateway reconnect attempts exhausted.\"),\n );\n this.#setState(GatewayState.Connect);\n }\n #settleConnect(error?: GatewayError): void {\n this.#reconnect.settle(error);\n }\n #clearTimers(): void {\n this.#reconnect.cancel();\n this.#heartbeat.stop();\n }\n #normalizeError(error: unknown): GatewayError {\n return error instanceof GatewayError\n ? error\n : new GatewayError(\"Gateway connection failed.\", undefined, {\n cause: error,\n });\n }\n #emitError(error: unknown): void {\n this.#emit(\n \"error\",\n error instanceof Error ? error : new GatewayError(String(error)),\n );\n }\n #emit(event: string, data: unknown): void {\n for (const listener of this.#listeners.get(event) ?? []) {\n try {\n const result = listener(data);\n if (\n result &&\n typeof (result as PromiseLike<unknown>).then === \"function\"\n )\n void Promise.resolve(result).catch((error) => {\n if (event !== \"error\") this.#emitError(error);\n });\n } catch (error) {\n if (event !== \"error\") this.#emitError(error);\n }\n }\n }\n /** Changes the Gateway lifecycle state. @param next Next lifecycle state. */\n #setState(next: GatewayState): void {\n if (this.state === next) return;\n const previous = this.state;\n this.state = next;\n this.#emit(\"stateChange\", { previous, next });\n }\n}\n",
|
|
49
|
-
"export {\n Permission,\n Permissions,\n PermissionFlagsBits,\n PermissionSet,\n PermissionsBitField,\n PermissionOverwriteEnum,\n PermissionOverwriteType,\n computePermissions,\n type PermissionContext,\n type PermissionOverwrite,\n type PermissionRole,\n type PermissionName,\n} from \"./permissions.js\";\nexport {\n ClientEvent,\n /** Discord.js-familiar alias for {@link ClientEvent}. */\n ClientEvent as Events,\n type ClientEventName,\n type ClientEvents,\n type ClientListener,\n} from \"./events.js\";\nexport { Collector, type CollectorOptions } from \"./collector.js\";\nexport {\n GatewayIntentBits,\n IntentBits,\n Intents,\n IntentsBitField,\n resolveGatewayIntents,\n type GatewayIntentResolvable,\n} from \"@lunibee/types\";\n\nimport {\n ApplicationCommandManager,\n ChannelManager,\n GuildManager,\n MonetizationManager,\n StageInstanceManager,\n UserManager,\n toRequest,\n} from \"@lunibee/managers\";\nimport { REST, Routes } from \"@lunibee/rest\";\nimport {\n User,\n GuildMember,\n Role,\n Emoji,\n type Channel,\n createChannel,\n Message,\n createInteraction,\n type InteractionClient,\n type InteractionData,\n type ResourceContext,\n} from \"@lunibee/structures\";\nimport { Gateway } from \"@lunibee/ws\";\nimport type {\n APIEntitlement,\n APISoundboardSound,\n APIChannel,\n APIGuild,\n APIGuildMember,\n APIGuildRoleEvent,\n APIGuildRoleDeleteEvent,\n APIGuildBanEvent,\n APIGuildEmojisUpdateEvent,\n APIGuildStickersUpdateEvent,\n APIMessageDeleteBulkEvent,\n APIMessageDeleteEvent,\n APIMessageReactionEvent,\n APIMessageReactionRemoveEmojiEvent,\n APIReadyEvent,\n APIRole,\n APIThreadEvent,\n APIThreadListSync,\n APIThreadMembersUpdate,\n APIVoiceState,\n APIVoiceServerUpdate,\n APIPresenceUpdate,\n APITypingStart,\n APIInviteCreate,\n APIInviteDelete,\n APIWebhooksUpdate,\n APIAutoModerationRule,\n APIAutoModerationActionExecution,\n APIGuildScheduledEvent,\n APIGuildScheduledEventUserEvent,\n APIStageInstance,\n APIChannelPinsUpdate,\n APIGuildMembersChunk,\n APIMessagePollVoteEvent,\n ClientOptions,\n ClientUser,\n} from \"@lunibee/types\";\nimport { ClientEvent, type ClientEvents } from \"./events.js\";\nimport { Collector, type CollectorOptions } from \"./collector.js\";\nimport { computePermissions, PermissionSet } from \"./permissions.js\";\n\n/** Lifecycle state of a client. */\nexport type ClientState = \"idle\" | \"connecting\" | \"ready\" | \"destroyed\";\ntype Listener<T extends unknown[]> = (...args: T) => unknown;\ntype GuildMemberEvent = APIGuildMember & { guild_id: string };\n\n/** Minimal typed event emitter used by the client. */\nclass EventEmitter<Events extends { [K in keyof Events]: unknown[] }> {\n readonly #listeners = new Map<keyof Events, Set<Listener<any>>>();\n public on<K extends keyof Events>(\n event: K,\n listener: Listener<Events[K]>,\n ): this {\n if (typeof listener !== \"function\")\n throw new TypeError(\"Event 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 public once<K extends keyof Events>(\n event: K,\n listener: Listener<Events[K]>,\n ): this {\n const wrapped: Listener<Events[K]> = (...args) => {\n this.off(event, wrapped);\n return listener(...args);\n };\n return this.on(event, wrapped);\n }\n public off<K extends keyof Events>(\n event: K,\n listener: Listener<Events[K]>,\n ): this {\n this.#listeners.get(event)?.delete(listener);\n return this;\n }\n /** Alias of {@link off}, provided for Node.js/Discord.js familiarity. */\n public removeListener<K extends keyof Events>(\n event: K,\n listener: Listener<Events[K]>,\n ): this {\n return this.off(event, listener);\n }\n public removeAllListeners<K extends keyof Events>(event?: K): this {\n if (event === undefined) this.#listeners.clear();\n else this.#listeners.delete(event);\n return this;\n }\n protected emit<K extends keyof Events>(\n event: K,\n ...args: Events[K]\n ): boolean {\n const listeners = this.#listeners.get(event);\n if (!listeners?.size) return false;\n for (const listener of [...listeners]) {\n try {\n const result = listener(...args);\n if (\n result &&\n typeof (result as PromiseLike<unknown>).then === \"function\"\n )\n void Promise.resolve(result).catch((error) =>\n this.#handleError(event, error),\n );\n } catch (error) {\n this.#handleError(event, error);\n }\n }\n return true;\n }\n /** Sends a listener's error to the `error` listeners. When there are none, or\n * an `error` listener itself fails, it becomes a process warning instead of\n * disappearing (never a new `error` event, so it cannot loop). */\n #handleError(event: keyof Events, error: unknown): void {\n const normalized =\n error instanceof Error\n ? error\n : new Error(String(error), { cause: error });\n const listeners =\n event === ClientEvent.Error\n ? []\n : [\n ...(this.#listeners.get(\n ClientEvent.Error as keyof Events,\n ) ?? []),\n ];\n if (listeners.length === 0) return warnListenerError(event, normalized);\n for (const listener of listeners) {\n try {\n const result = listener(normalized);\n if (\n result &&\n typeof (result as PromiseLike<unknown>).then === \"function\"\n )\n void Promise.resolve(result).catch((failure) =>\n warnListenerError(ClientEvent.Error, failure),\n );\n } catch (failure) {\n warnListenerError(ClientEvent.Error, failure);\n }\n }\n }\n}\n\n/** Reports an error no listener handled as a process warning (stderr by default). */\nfunction warnListenerError(event: PropertyKey, error: unknown): void {\n const failure = error instanceof Error ? error : new Error(String(error));\n process.emitWarning(\n `A \"${String(event)}\" listener threw and no error listener handled it: ${failure.message}`,\n {\n type: \"LunibeeWarning\",\n code: \"LUNIBEE_UNHANDLED_LISTENER_ERROR\",\n detail: failure.stack,\n },\n );\n}\n\n/** Main Lunibee Discord client. */\nexport class Client\n extends EventEmitter<ClientEvents>\n implements InteractionClient\n{\n public readonly rest: REST;\n public readonly users: UserManager;\n public readonly guilds: GuildManager;\n public readonly channels: ChannelManager;\n /** Stage instances, cached by stage channel ID. */\n public readonly stageInstances: StageInstanceManager;\n public readonly application: { commands: ApplicationCommandManager };\n /** SKUs, entitlements and subscriptions; available after READY (application ID known). */\n public monetization?: MonetizationManager;\n public get ws(): Gateway {\n return this.#gateway;\n }\n public get gateway(): Gateway {\n return this.#gateway;\n }\n public user?: ClientUser;\n public readyAt?: Date;\n public state: ClientState = \"idle\";\n /**\n * The bot token this client is authenticated with, or `null` once the\n * client has been destroyed. Mirrors `Client#token` in Discord.js.\n */\n public get token(): string | null {\n return this.state === \"destroyed\" ? null : (this.options.token ?? null);\n }\n public get uptime(): number | null {\n return this.readyAt ? Date.now() - this.readyAt.getTime() : null;\n }\n public get ping(): number {\n return this.#gateway.ping;\n }\n /** Whether the client is ready and connected. */\n public isReady(): boolean {\n return this.state === \"ready\";\n }\n /** Sets the bot's presence / status. @param data Presence payload. @returns Whether the payload was sent. */\n public setPresence(\n data: import(\"@lunibee/types\").GatewayPresence,\n ): boolean {\n return this.#gateway.setPresence(data);\n }\n /** Sends a voice state update. @param data Voice state payload. @returns Whether it was sent. */\n public setVoiceState(data: Record<string, unknown>): boolean {\n return this.#gateway.setVoiceState(data);\n }\n /** Requests guild members. @param data Guild member request payload. @returns Whether it was sent. */\n public requestGuildMembers(data: Record<string, unknown>): boolean {\n return this.#gateway.requestGuildMembers(data);\n }\n readonly #gateway: Gateway;\n /** Which resources Gateway events are allowed to cache. */\n readonly #cache: Required<NonNullable<ClientOptions[\"cache\"]>>;\n readonly #resourceContext: ResourceContext;\n\n public constructor(public readonly options: ClientOptions) {\n super();\n if (!options.token?.trim())\n throw new TypeError(\"Client token is required.\");\n this.rest = new REST({ token: options.token, ...options.rest });\n this.#cache = {\n users: true,\n members: true,\n roles: true,\n emojis: true,\n ...options.cache,\n };\n this.users = new UserManager(this.rest);\n this.guilds = new GuildManager(this.rest);\n this.channels = new ChannelManager(this.rest, {\n messageCache: options.messageCache,\n allowedMentions: options.allowedMentions,\n });\n this.stageInstances = new StageInstanceManager(this.rest);\n const placeholderAppCommands = new ApplicationCommandManager(\n this.rest,\n \"0\",\n );\n this.application = { commands: placeholderAppCommands };\n this.#resourceContext = {\n sendMessage: (channelId, options) =>\n this.channels.send(channelId, options),\n editMessage: (channelId, messageId, options) =>\n this.channels.editMessage(channelId, messageId, options),\n deleteMessage: (channelId, messageId, reason) =>\n this.channels.deleteMessage(channelId, messageId, reason),\n crosspostMessage: (channelId, messageId) =>\n this.channels.crosspostMessage(channelId, messageId),\n editChannel: (channelId, options) =>\n this.channels.edit(channelId, options),\n deleteChannel: (channelId, reason) =>\n this.channels.remove(channelId, reason),\n addReaction: (channelId, messageId, emoji) =>\n this.channels.addReaction(channelId, messageId, emoji),\n removeOwnReaction: (channelId, messageId, emoji) =>\n this.channels.removeOwnReaction(channelId, messageId, emoji),\n removeReaction: (channelId, messageId, emoji, userId) =>\n this.channels.removeReaction(\n channelId,\n messageId,\n emoji,\n userId,\n ),\n removeAllReactions: (channelId, messageId) =>\n this.channels.removeAllReactions(channelId, messageId),\n pinMessage: (channelId, messageId, reason) =>\n this.channels.pinMessage(channelId, messageId, reason),\n unpinMessage: (channelId, messageId, reason) =>\n this.channels.unpinMessage(channelId, messageId, reason),\n collectInteractions: (options) =>\n this.createCollector(ClientEvent.InteractionCreate, options),\n memberPermissions: (guildId, memberId, roleIds, channelId) =>\n this.#memberPermissions(guildId, memberId, roleIds, channelId),\n kickMember: (guildId, userId, reason) =>\n this.guilds.members(guildId).kick(userId, reason),\n banMember: (guildId, userId, options) =>\n this.guilds.members(guildId).ban(userId, options),\n editMember: (guildId, userId, options, reason) =>\n this.guilds.members(guildId).edit(userId, options, reason),\n addMemberRole: (guildId, userId, roleId, reason) =>\n this.guilds.members(guildId).addRole(userId, roleId, reason),\n removeMemberRole: (guildId, userId, roleId, reason) =>\n this.guilds.members(guildId).removeRole(userId, roleId, reason),\n editPermissionOverwrite: async (\n channelId,\n targetId,\n changes,\n options,\n ) => {\n const bits = { allow: 0n, deny: 0n, inherit: 0n };\n for (const [name, value] of Object.entries(changes)) {\n // Names only: a number or bit string here is a mistake, not a permission.\n if (!/^[A-Za-z]+$/.test(name))\n throw new TypeError(`Unknown permission: ${name}`);\n let bit: bigint;\n try {\n bit = new PermissionSet(name).bitfield;\n } catch {\n throw new TypeError(`Unknown permission: ${name}`);\n }\n const key =\n value === true\n ? \"allow\"\n : value === false\n ? \"deny\"\n : \"inherit\";\n bits[key] |= bit;\n }\n return this.channels\n .permissionOverwrites(channelId)\n .update(targetId, bits, options);\n },\n };\n this.guilds.attachContext(this.#resourceContext);\n this.#gateway = new Gateway({\n token: options.token,\n intents: options.intents,\n ...options.gateway,\n });\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n this.#gateway.on(\"READY\", (data) => {\n const ready = data as APIReadyEvent;\n this.user = ready.user;\n this.users.set(this.user.id, new User(this.user));\n this.readyAt = new Date();\n this.state = \"ready\";\n const appId = ready.application?.id ?? this.user.id;\n (\n this.application as { commands: ApplicationCommandManager }\n ).commands = new ApplicationCommandManager(this.rest, appId);\n if (this.monetization?.applicationId !== appId)\n this.monetization = new MonetizationManager(this.rest, appId);\n this.emit(ClientEvent.Ready, this.user);\n });\n this.#gateway.on(\"RESUMED\", () => {\n this.state = \"ready\";\n this.emit(ClientEvent.Resumed);\n });\n this.#gateway.on(\"invalidSession\", (isRecoverable) => {\n this.emit(ClientEvent.InvalidSession, isRecoverable as boolean);\n });\n this.#gateway.on(\"open\", () => this.emit(ClientEvent.Open));\n this.#gateway.on(\"close\", (data) => {\n if (this.state !== \"destroyed\") this.state = \"idle\";\n this.emit(\n ClientEvent.Close,\n data as { code: number; action: string },\n );\n });\n\n // ── Messages ─────────────────────────────────────────────────────────────\n this.#gateway.on(\"MESSAGE_CREATE\", (data) => {\n const payload = data as import(\"@lunibee/types\").APIMessage;\n const message = new Message(payload, this.#resourceContext);\n this.#observeMessage(message);\n // The author's member (roles, nickname) comes with every guild\n // message; keep the cached member current with it.\n if (\n payload.member &&\n payload.guild_id &&\n this.guilds.has(payload.guild_id)\n )\n this.#upsertMember(payload.guild_id, {\n ...payload.member,\n user: payload.member.user ?? payload.author,\n } as APIGuildMember);\n // With messageCache enabled, Gateway messages enter the bounded\n // cache so later edits and deletes can see the previous content;\n // listeners get the cached instance.\n const cached = this.options.messageCache\n ? this.channels\n .messages(message.channelId)\n .upsert(data as import(\"@lunibee/types\").APIMessage)\n : message;\n this.emit(ClientEvent.MessageCreate, cached);\n });\n this.#gateway.on(\"MESSAGE_UPDATE\", (data) => {\n const message = new Message(\n data as import(\"@lunibee/types\").APIMessage,\n this.#resourceContext,\n );\n this.#observeMessage(message);\n // The cached message is replaced, not merged, so listeners receive\n // the previous version intact alongside the new one.\n const messages = this.channels.cachedMessages(message.channelId);\n const previous = messages?.cache.peek(message.id);\n if (previous) messages!.cache.set(message.id, message);\n this.emit(ClientEvent.MessageUpdate, message, previous);\n });\n this.#gateway.on(\"MESSAGE_DELETE\", (data) => {\n const payload = data as APIMessageDeleteEvent;\n const messages = this.channels.cachedMessages(payload.channel_id);\n const removed = messages?.cache.peek(payload.id);\n messages?.delete(payload.id);\n this.emit(ClientEvent.MessageDelete, payload, removed);\n });\n this.#gateway.on(\"MESSAGE_DELETE_BULK\", (data) => {\n const payload = data as APIMessageDeleteBulkEvent;\n const messages = this.channels.cachedMessages(payload.channel_id);\n const removed: Message[] = [];\n if (messages)\n for (const id of payload.ids) {\n const message = messages.cache.peek(id);\n if (message) removed.push(message);\n messages.delete(id);\n }\n this.emit(ClientEvent.MessageDeleteBulk, payload, removed);\n });\n\n // ── Reactions ────────────────────────────────────────────────────────────\n this.#gateway.on(\"MESSAGE_REACTION_ADD\", (data) =>\n this.emit(\n ClientEvent.MessageReactionAdd,\n data as APIMessageReactionEvent,\n ),\n );\n this.#gateway.on(\"MESSAGE_REACTION_REMOVE\", (data) =>\n this.emit(\n ClientEvent.MessageReactionRemove,\n data as APIMessageReactionEvent,\n ),\n );\n this.#gateway.on(\"MESSAGE_REACTION_REMOVE_ALL\", (data) =>\n this.emit(\n ClientEvent.MessageReactionRemoveAll,\n data as APIMessageDeleteEvent,\n ),\n );\n this.#gateway.on(\"MESSAGE_REACTION_REMOVE_EMOJI\", (data) =>\n this.emit(\n ClientEvent.MessageReactionRemoveEmoji,\n data as APIMessageReactionRemoveEmojiEvent,\n ),\n );\n\n // ── Polls ────────────────────────────────────────────────────────────────\n this.#gateway.on(\"MESSAGE_POLL_VOTE_ADD\", (data) =>\n this.emit(\n ClientEvent.MessagePollVoteAdd,\n data as APIMessagePollVoteEvent,\n ),\n );\n this.#gateway.on(\"MESSAGE_POLL_VOTE_REMOVE\", (data) =>\n this.emit(\n ClientEvent.MessagePollVoteRemove,\n data as APIMessagePollVoteEvent,\n ),\n );\n\n // ── Guilds ───────────────────────────────────────────────────────────────\n this.#gateway.on(\"GUILD_CREATE\", (data) => {\n const payload = data as APIGuild & {\n members?: APIGuildMember[];\n voice_states?: APIVoiceState[];\n channels?: APIChannel[];\n threads?: APIChannel[];\n unavailable?: boolean;\n };\n if (payload.unavailable) {\n this.emit(ClientEvent.GuildUnavailable, payload);\n return;\n }\n // A guild already in cache that arrives again (e.g. after an outage\n // or gateway resume) has become *available* rather than newly joined.\n // Mirrors Discord.js' guildAvailable vs. guildCreate distinction.\n const wasCached = this.guilds.has(payload.id);\n this.guilds.patch(payload);\n for (const role of payload.roles ?? [])\n this.#upsertRole(payload.id, role);\n if (this.#cache.emojis) {\n const emojis = this.guilds.emojis(payload.id);\n for (const emoji of payload.emojis ?? []) emojis.upsert(emoji);\n }\n for (const member of payload.members ?? [])\n this.#upsertMember(payload.id, member);\n for (const state of payload.voice_states ?? [])\n this.#storeVoiceState(payload.id, state);\n // Channels in GUILD_CREATE omit guild_id; restore it so the\n // channel can be cleaned up with its guild.\n for (const channelData of [\n ...(payload.channels ?? []),\n ...(payload.threads ?? []),\n ])\n this.channels.upsert({ ...channelData, guild_id: payload.id });\n this.emit(\n wasCached\n ? ClientEvent.GuildAvailable\n : ClientEvent.GuildCreate,\n payload,\n );\n });\n this.#gateway.on(\"GUILD_UPDATE\", (data) => {\n const payload = data as APIGuild;\n const cached = this.guilds.get(payload.id);\n const previous = cached ? this.#snapshot(cached) : null;\n this.guilds.patch(payload);\n this.emit(ClientEvent.GuildUpdate, payload, previous);\n });\n this.#gateway.on(\"GUILD_DELETE\", (data) => {\n const payload = data as { id: string; unavailable?: boolean };\n if (payload.unavailable) {\n this.emit(ClientEvent.GuildUnavailable, payload);\n return;\n }\n this.guilds.delete(payload.id);\n this.channels.deleteGuildChannels(payload.id);\n this.emit(ClientEvent.GuildDelete, payload);\n });\n\n // ── Guild Members ────────────────────────────────────────────────────────\n this.#gateway.on(\"GUILD_MEMBER_ADD\", (data) => {\n const member = data as GuildMemberEvent;\n this.#upsertMember(member.guild_id, member);\n this.emit(ClientEvent.GuildMemberAdd, member);\n });\n this.#gateway.on(\"GUILD_MEMBER_UPDATE\", (data) => {\n const member = data as GuildMemberEvent;\n const cached = this.#cache.members\n ? this.guilds.members(member.guild_id).get(member.user.id)\n : undefined;\n // A fresh instance keeps the client context (a private field).\n const previous = cached\n ? this.#snapshot(\n cached,\n new GuildMember(\n { user: member.user, guild_id: member.guild_id },\n this.#resourceContext,\n ),\n )\n : null;\n this.#upsertMember(member.guild_id, member);\n this.emit(ClientEvent.GuildMemberUpdate, member, previous);\n });\n this.#gateway.on(\"GUILD_MEMBER_REMOVE\", (data) => {\n const member = data as GuildMemberEvent;\n this.guilds.members(member.guild_id).delete(member.user.id);\n this.emit(ClientEvent.GuildMemberRemove, member);\n });\n this.#gateway.on(\"GUILD_MEMBERS_CHUNK\", (data) => {\n const chunk = data as APIGuildMembersChunk;\n for (const member of chunk.members)\n this.#upsertMember(chunk.guild_id, member);\n this.emit(ClientEvent.GuildMembersChunk, chunk);\n });\n\n // ── Guild Bans ───────────────────────────────────────────────────────────\n this.#gateway.on(\"GUILD_BAN_ADD\", (data) => {\n const ban = data as APIGuildBanEvent;\n const bans = this.guilds.bans(ban.guild_id);\n // Keep a reason already fetched over REST; the event carries none.\n bans.set(ban.user.id, {\n reason: bans.get(ban.user.id)?.reason ?? null,\n user: ban.user,\n });\n this.guilds.members(ban.guild_id).delete(ban.user.id);\n this.emit(ClientEvent.GuildBanAdd, ban);\n });\n this.#gateway.on(\"GUILD_BAN_REMOVE\", (data) => {\n const ban = data as APIGuildBanEvent;\n this.guilds.bans(ban.guild_id).delete(ban.user.id);\n this.emit(ClientEvent.GuildBanRemove, ban);\n });\n\n // ── Guild Roles ──────────────────────────────────────────────────────────\n this.#gateway.on(\"GUILD_ROLE_CREATE\", (data) => {\n const event = data as APIGuildRoleEvent;\n this.#upsertRole(event.guild_id, event.role);\n this.emit(ClientEvent.GuildRoleCreate, event);\n });\n this.#gateway.on(\"GUILD_ROLE_UPDATE\", (data) => {\n const event = data as APIGuildRoleEvent;\n const cached = this.#cache.roles\n ? this.guilds.roles(event.guild_id).get(event.role.id)\n : undefined;\n const previous = cached ? this.#snapshot(cached) : null;\n this.#upsertRole(event.guild_id, event.role);\n this.emit(ClientEvent.GuildRoleUpdate, event, previous);\n });\n this.#gateway.on(\"GUILD_ROLE_DELETE\", (data) => {\n const event = data as APIGuildRoleDeleteEvent;\n const roles = this.guilds.roles(event.guild_id);\n const removed = roles.get(event.role_id) ?? null;\n roles.delete(event.role_id);\n this.emit(ClientEvent.GuildRoleDelete, event, removed);\n });\n\n // ── Guild Emojis & Stickers ──────────────────────────────────────────────\n this.#gateway.on(\"GUILD_EMOJIS_UPDATE\", (data) => {\n const event = data as APIGuildEmojisUpdateEvent;\n let previous: Emoji[] | null = null;\n // The event carries the guild's full emoji list.\n if (this.#cache.emojis) {\n const emojis = this.guilds.emojis(event.guild_id);\n previous = [...emojis.cache.values()].map((emoji) =>\n this.#snapshot(emoji),\n );\n const current = new Set(event.emojis.map((emoji) => emoji.id));\n for (const id of [...emojis.cache.keys()])\n if (!current.has(id)) emojis.delete(id);\n for (const emoji of event.emojis) emojis.upsert(emoji);\n }\n this.emit(ClientEvent.GuildEmojisUpdate, event, previous);\n });\n this.#gateway.on(\"GUILD_STICKERS_UPDATE\", (data) => {\n const event = data as APIGuildStickersUpdateEvent;\n // The event carries the guild's full sticker list. `sync` replaces\n // the raw objects, so the previous list needs no copying.\n const stickers = this.guilds.stickers(event.guild_id);\n const previous = [...stickers.cache.values()];\n stickers.sync(event.stickers);\n this.emit(ClientEvent.GuildStickersUpdate, event, previous);\n });\n\n // ── Soundboard ───────────────────────────────────────────────────────────\n this.#gateway.on(\"GUILD_SOUNDBOARD_SOUND_CREATE\", (data) => {\n const sound = data as APISoundboardSound;\n if (sound.guild_id)\n this.guilds\n .soundboard(sound.guild_id)\n .set(sound.sound_id, sound);\n this.emit(ClientEvent.SoundboardSoundCreate, sound);\n });\n this.#gateway.on(\"GUILD_SOUNDBOARD_SOUND_UPDATE\", (data) => {\n const sound = data as APISoundboardSound;\n if (sound.guild_id)\n this.guilds\n .soundboard(sound.guild_id)\n .set(sound.sound_id, sound);\n this.emit(ClientEvent.SoundboardSoundUpdate, sound);\n });\n this.#gateway.on(\"GUILD_SOUNDBOARD_SOUND_DELETE\", (data) => {\n const event = data as { sound_id: string; guild_id: string };\n this.guilds.soundboard(event.guild_id).delete(event.sound_id);\n this.emit(ClientEvent.SoundboardSoundDelete, event);\n });\n this.#gateway.on(\"GUILD_SOUNDBOARD_SOUNDS_UPDATE\", (data) => {\n const event = data as {\n guild_id: string;\n soundboard_sounds: APISoundboardSound[];\n };\n const sounds = this.guilds.soundboard(event.guild_id);\n sounds.clear();\n for (const sound of event.soundboard_sounds)\n sounds.set(sound.sound_id, sound);\n this.emit(ClientEvent.SoundboardSoundsUpdate, event);\n });\n\n // ── Monetization ─────────────────────────────────────────────────────────\n this.#gateway.on(\"ENTITLEMENT_CREATE\", (data) => {\n const entitlement = data as APIEntitlement;\n this.monetization?.set(entitlement.id, entitlement);\n this.emit(ClientEvent.EntitlementCreate, entitlement);\n });\n this.#gateway.on(\"ENTITLEMENT_UPDATE\", (data) => {\n const entitlement = data as APIEntitlement;\n this.monetization?.set(entitlement.id, entitlement);\n this.emit(ClientEvent.EntitlementUpdate, entitlement);\n });\n this.#gateway.on(\"ENTITLEMENT_DELETE\", (data) => {\n const entitlement = data as APIEntitlement;\n this.monetization?.delete(entitlement.id);\n this.emit(ClientEvent.EntitlementDelete, entitlement);\n });\n\n // ── Guild Integrations ───────────────────────────────────────────────────\n this.#gateway.on(\"GUILD_INTEGRATIONS_UPDATE\", (data) =>\n this.emit(\n ClientEvent.GuildIntegrationsUpdate,\n data as { guild_id: string },\n ),\n );\n\n // ── Guild Scheduled Events ───────────────────────────────────────────────\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_CREATE\", (data) => {\n const event = data as APIGuildScheduledEvent;\n this.guilds.scheduledEvents(event.guild_id).set(event.id, event);\n this.emit(ClientEvent.GuildScheduledEventCreate, event);\n });\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_UPDATE\", (data) => {\n const event = data as APIGuildScheduledEvent;\n this.guilds.scheduledEvents(event.guild_id).set(event.id, event);\n this.emit(ClientEvent.GuildScheduledEventUpdate, event);\n });\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_DELETE\", (data) => {\n const event = data as APIGuildScheduledEvent;\n this.guilds.scheduledEvents(event.guild_id).delete(event.id);\n this.emit(ClientEvent.GuildScheduledEventDelete, event);\n });\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_USER_ADD\", (data) =>\n this.emit(\n ClientEvent.GuildScheduledEventUserAdd,\n data as APIGuildScheduledEventUserEvent,\n ),\n );\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_USER_REMOVE\", (data) =>\n this.emit(\n ClientEvent.GuildScheduledEventUserRemove,\n data as APIGuildScheduledEventUserEvent,\n ),\n );\n\n // ── AutoMod ──────────────────────────────────────────────────────────────\n this.#gateway.on(\"AUTO_MODERATION_RULE_CREATE\", (data) => {\n const rule = data as APIAutoModerationRule;\n this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);\n this.emit(ClientEvent.AutoModerationRuleCreate, rule);\n });\n this.#gateway.on(\"AUTO_MODERATION_RULE_UPDATE\", (data) => {\n const rule = data as APIAutoModerationRule;\n this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);\n this.emit(ClientEvent.AutoModerationRuleUpdate, rule);\n });\n this.#gateway.on(\"AUTO_MODERATION_RULE_DELETE\", (data) => {\n const rule = data as APIAutoModerationRule;\n this.guilds.autoModerationRules(rule.guild_id).delete(rule.id);\n this.emit(ClientEvent.AutoModerationRuleDelete, rule);\n });\n this.#gateway.on(\"AUTO_MODERATION_ACTION_EXECUTION\", (data) =>\n this.emit(\n ClientEvent.AutoModerationActionExecution,\n data as APIAutoModerationActionExecution,\n ),\n );\n\n // ── Channels ─────────────────────────────────────────────────────────────\n this.#gateway.on(\"CHANNEL_CREATE\", (data) => {\n const channel = this.channels.upsert(data as APIChannel);\n this.emit(ClientEvent.ChannelCreate, channel);\n });\n this.#gateway.on(\"CHANNEL_UPDATE\", (data) => {\n const previous = this.#previousChannel(data as APIChannel);\n const channel = this.channels.upsert(data as APIChannel);\n this.emit(ClientEvent.ChannelUpdate, channel, previous);\n });\n this.#gateway.on(\"CHANNEL_DELETE\", (data) => {\n const payload = data as APIChannel;\n const removed = this.channels.get(payload.id) ?? null;\n this.channels.delete(payload.id);\n this.emit(ClientEvent.ChannelDelete, payload, removed);\n });\n this.#gateway.on(\"CHANNEL_PINS_UPDATE\", (data) =>\n this.emit(\n ClientEvent.ChannelPinsUpdate,\n data as APIChannelPinsUpdate,\n ),\n );\n\n // ── Threads ──────────────────────────────────────────────────────────────\n this.#gateway.on(\"THREAD_CREATE\", (data) => {\n const channel = this.channels.upsert(data as APIThreadEvent);\n this.emit(ClientEvent.ThreadCreate, channel);\n });\n this.#gateway.on(\"THREAD_UPDATE\", (data) => {\n const previous = this.#previousChannel(data as APIThreadEvent);\n const channel = this.channels.upsert(data as APIThreadEvent);\n this.emit(ClientEvent.ThreadUpdate, channel, previous);\n });\n this.#gateway.on(\"THREAD_DELETE\", (data) => {\n const payload = data as APIThreadEvent;\n const removed = this.channels.get(payload.id) ?? null;\n this.channels.delete(payload.id);\n this.emit(ClientEvent.ThreadDelete, payload, removed);\n });\n this.#gateway.on(\"THREAD_LIST_SYNC\", (data) => {\n const sync = data as APIThreadListSync;\n for (const thread of sync.threads)\n this.channels.upsert({ ...thread, guild_id: sync.guild_id });\n this.emit(ClientEvent.ThreadListSync, sync);\n });\n this.#gateway.on(\"THREAD_MEMBERS_UPDATE\", (data) =>\n this.emit(\n ClientEvent.ThreadMembersUpdate,\n data as APIThreadMembersUpdate,\n ),\n );\n this.#gateway.on(\"THREAD_MEMBER_UPDATE\", (data) =>\n this.emit(\n ClientEvent.ThreadMemberUpdate,\n data as import(\"@lunibee/types\").APIThreadMember,\n ),\n );\n\n // ── Stage Instances ──────────────────────────────────────────────────────\n this.#gateway.on(\"STAGE_INSTANCE_CREATE\", (data) => {\n const stage = data as APIStageInstance;\n this.stageInstances.set(stage.channel_id, stage);\n this.emit(ClientEvent.StageInstanceCreate, stage);\n });\n this.#gateway.on(\"STAGE_INSTANCE_UPDATE\", (data) => {\n const stage = data as APIStageInstance;\n this.stageInstances.set(stage.channel_id, stage);\n this.emit(ClientEvent.StageInstanceUpdate, stage);\n });\n this.#gateway.on(\"STAGE_INSTANCE_DELETE\", (data) => {\n const stage = data as APIStageInstance;\n this.stageInstances.delete(stage.channel_id);\n this.emit(ClientEvent.StageInstanceDelete, stage);\n });\n\n // ── Invites ──────────────────────────────────────────────────────────────\n this.#gateway.on(\"INVITE_CREATE\", (data) => {\n const invite = data as APIInviteCreate;\n if (invite.guild_id)\n this.guilds.invites(invite.guild_id).set(invite.code, invite);\n this.emit(ClientEvent.InviteCreate, invite);\n });\n this.#gateway.on(\"INVITE_DELETE\", (data) => {\n const invite = data as APIInviteDelete;\n if (invite.guild_id)\n this.guilds.invites(invite.guild_id).delete(invite.code);\n this.emit(ClientEvent.InviteDelete, invite);\n });\n\n // ── Webhooks ─────────────────────────────────────────────────────────────\n this.#gateway.on(\"WEBHOOKS_UPDATE\", (data) =>\n this.emit(ClientEvent.WebhooksUpdate, data as APIWebhooksUpdate),\n );\n\n // ── Voice ────────────────────────────────────────────────────────────────\n this.#gateway.on(\"VOICE_STATE_UPDATE\", (data) => {\n const state = data as APIVoiceState;\n if (state.guild_id) this.#storeVoiceState(state.guild_id, state);\n this.emit(ClientEvent.VoiceStateUpdate, state);\n });\n this.#gateway.on(\"VOICE_SERVER_UPDATE\", (data) =>\n this.emit(\n ClientEvent.VoiceServerUpdate,\n data as APIVoiceServerUpdate,\n ),\n );\n\n // ── Presence & Typing ────────────────────────────────────────────────────\n this.#gateway.on(\"PRESENCE_UPDATE\", (data) =>\n this.emit(ClientEvent.PresenceUpdate, data as APIPresenceUpdate),\n );\n this.#gateway.on(\"TYPING_START\", (data) =>\n this.emit(ClientEvent.TypingStart, data as APITypingStart),\n );\n\n // ── Interactions ─────────────────────────────────────────────────────────\n this.#gateway.on(\"INTERACTION_CREATE\", (data) =>\n this.emit(\n ClientEvent.InteractionCreate,\n createInteraction(this, data as InteractionData),\n ),\n );\n\n // ── Raw / Error ───────────────────────────────────────────────────────────\n this.#gateway.on(\"RAW\", (data) =>\n this.emit(\n ClientEvent.Raw,\n data as { event: string; data: unknown },\n ),\n );\n this.#gateway.on(\"error\", (error) =>\n this.emit(ClientEvent.Error, error as Error),\n );\n }\n\n /**\n * Convenience method to connect the bot to Discord.\n * Optionally overrides the configured token.\n * @param token Optional token override.\n * @returns The token used to log in.\n * @throws {TypeError} If the resulting token is empty.\n */\n /** Caches a message's author, and its channel only when none is cached: the\n * message carries a stub channel that must not overwrite a full one. */\n #observeMessage(message: Message): void {\n if (!this.channels.has(message.channelId))\n this.channels.set(message.channelId, message.channel);\n if (this.#cache.users)\n this.#merge(this.users, message.author.id, message.author);\n }\n\n #upsertMember(guildId: string, data: APIGuildMember): GuildMember {\n const member = new GuildMember(\n { ...data, guild_id: guildId },\n this.#resourceContext,\n );\n if (this.#cache.users)\n this.#merge(this.users, member.user.id, member.user);\n if (!this.#cache.members) return member;\n return this.#merge(\n this.guilds.members(guildId),\n member.user.id,\n member,\n );\n }\n\n /** A voice state without a channel means the user left voice. */\n #storeVoiceState(guildId: string, state: APIVoiceState): void {\n const states = this.guilds.voiceStates(guildId);\n if (state.channel_id) states.set(state.user_id, state);\n else states.delete(state.user_id);\n }\n\n #upsertRole(guildId: string, data: APIRole): Role {\n if (!this.#cache.roles) return new Role(data);\n return this.#merge(this.guilds.roles(guildId), data.id, new Role(data));\n }\n\n /**\n * Copies a cached structure's fields before an in-place merge changes them.\n * Pass `blank` (a fresh instance of the same class) when the class has\n * private fields, so the copy keeps them.\n */\n #snapshot<T extends object>(\n cached: T,\n blank: T = Object.create(Object.getPrototypeOf(cached)) as T,\n ): T {\n return Object.assign(blank, cached);\n }\n\n /** A copy of the cached channel an update is about to change, or null. */\n #previousChannel(data: APIChannel): Channel | null {\n const cached = this.channels.get(data.id);\n if (!cached) return null;\n // Channel keeps its client context in a private field; build the copy\n // through the same factory so it keeps the subclass and the context.\n return this.#snapshot(\n cached,\n createChannel(\n { id: cached.id, type: cached.type, guild_id: cached.guildId },\n this.#resourceContext,\n ),\n );\n }\n\n /** Merges `next` into the cached instance so references stay valid.\n * Fields a partial payload left undefined keep their cached value. */\n #merge<T extends object>(\n manager: {\n get(id: string): T | undefined;\n set(id: string, value: T): unknown;\n },\n id: string,\n next: T,\n ): T {\n const existing = manager.get(id);\n if (!existing) {\n manager.set(id, next);\n return next;\n }\n for (const [key, value] of Object.entries(next))\n if (value !== undefined)\n (existing as Record<string, unknown>)[key] = value;\n return existing;\n }\n\n /**\n * Collects the first argument of a client event until a limit, timeout,\n * idle timeout, abort or `stop()`. The collector unsubscribes itself when\n * it ends. Items are keyed by `options.key`, else their `id`, else order.\n */\n public createCollector<E extends keyof ClientEvents>(\n event: E,\n options: CollectorOptions<ClientEvents[E][0]> & {\n key?: (item: ClientEvents[E][0]) => string;\n } = {},\n ): Collector<string, ClientEvents[E][0]> {\n const collector = new Collector<string, ClientEvents[E][0]>(options);\n let order = 0;\n const listener = (...args: ClientEvents[E]): void => {\n const item = args[0];\n const id = (item as { id?: unknown } | null | undefined)?.id;\n const key =\n options.key?.(item) ??\n (typeof id === \"string\" ? id : String(order++));\n collector\n .handle(key, item)\n .catch((error: unknown) =>\n this.emit(\n ClientEvent.Error,\n error instanceof Error\n ? error\n : new Error(String(error)),\n ),\n );\n };\n this.on(event, listener);\n collector.onDispose(() => this.off(event, listener));\n return collector;\n }\n\n /** Structures built by this client (members from interactions...) act through this. */\n public get resourceContext(): ResourceContext {\n return this.#resourceContext;\n }\n\n /** Guild- or channel-level permissions from a member's role IDs and the cached roles and overwrites. */\n #memberPermissions(\n guildId: string,\n memberId: string,\n roleIds: readonly string[],\n channelId?: string,\n ): PermissionSet | null {\n const guild = this.guilds.get(guildId);\n if (!guild) return null;\n let channel = channelId ? this.channels.get(channelId) : undefined;\n if (channelId) {\n // Threads use their parent's overwrites; without it the answer is unknown.\n if (channel?.isThread())\n channel = channel.parentId\n ? this.channels.get(channel.parentId)\n : undefined;\n if (!channel || channel.guildId !== guildId) return null;\n }\n return computePermissions({\n guildId,\n ownerId: guild.ownerId,\n memberId,\n memberRoleIds: [...roleIds],\n roles: this.guilds.roles(guildId).values(),\n overwrites: channel?.permissionOverwrites,\n });\n }\n\n /**\n * Resolves a member's permissions from cached state: guild-level for a\n * guild ID, or channel-level (including overwrites) for a cached channel\n * ID. Returns null when the guild or member is not cached.\n */\n public permissionsFor(\n memberId: string,\n guildOrChannelId: string,\n ): PermissionSet | null {\n let channel = this.channels.get(guildOrChannelId);\n // Threads have no overwrites of their own: they use the parent's.\n // Without a cached parent the answer would be guild-level only, which\n // could wrongly grant access, so report it as unknown instead.\n if (channel?.isThread()) {\n channel = channel.parentId\n ? this.channels.get(channel.parentId)\n : undefined;\n if (!channel) return null;\n }\n const guildId = channel?.guildId ?? guildOrChannelId;\n const guild = this.guilds.get(guildId);\n const member = this.guilds.members(guildId).get(memberId);\n if (!guild || !member) return null;\n return computePermissions({\n guildId,\n ownerId: guild.ownerId,\n memberId,\n memberRoleIds: member.roleIds,\n roles: this.guilds.roles(guildId).values(),\n overwrites: channel?.permissionOverwrites,\n });\n }\n\n /** Fetches Discord's default soundboard sounds. */\n public fetchDefaultSoundboardSounds(): Promise<APISoundboardSound[]> {\n return this.rest.get<APISoundboardSound[]>(\n Routes.soundboardDefaultSounds(),\n );\n }\n\n public async login(token?: string): Promise<string> {\n if (this.state === \"destroyed\")\n throw new Error(\"Cannot login a destroyed client.\");\n if (token?.trim()) {\n this.rest.setToken(token);\n (this as any).options.token = token;\n }\n const usedToken = (this as any).options.token as string;\n if (!usedToken?.trim())\n throw new TypeError(\"A bot token is required to log in.\");\n this.state = \"connecting\";\n await this.#gateway.connect();\n return usedToken;\n }\n\n /**\n * Destroys the client, permanently closing the Gateway connection.\n */\n public destroy(): void {\n this.state = \"destroyed\";\n this.#gateway.close();\n }\n\n // ── InteractionClient implementation ─────────────────────────────────────\n\n public postInteractionResponse(\n id: string,\n token: string,\n response: import(\"@lunibee/structures\").InteractionResponse,\n ): Promise<unknown> {\n const json = response.toJSON();\n // `?with_response=true` makes Discord return the created message.\n const callback = response.withResponse\n ? `${Routes.interactionCallback(id, token)}?with_response=true`\n : Routes.interactionCallback(id, token);\n // Only message responses (4 reply, 7 update) carry mentions; a modal or a deferral does not.\n const carriesMessage = json.type === 4 || json.type === 7;\n // Files in the reply turn the callback into an upload.\n const upload = json.data\n ? toRequest(\n json.data,\n carriesMessage ? this.options.allowedMentions : undefined,\n )\n : undefined;\n if (upload && typeof upload === \"object\" && \"files\" in upload) {\n const { body, files } = upload as { body: unknown; files: never[] };\n return this.rest.post(callback, {\n body: { ...json, data: body },\n files,\n });\n }\n return this.rest.post(\n callback,\n upload === undefined ? json : { ...json, data: upload },\n );\n }\n public editInteractionReply(\n token: string,\n data: Record<string, unknown>,\n ): Promise<unknown> {\n if (!this.user)\n return Promise.reject(new Error(\"Client is unauthenticated.\"));\n return this.rest.patch(\n Routes.interactionOriginalResponse(this.user.id, token),\n toRequest(data, this.options.allowedMentions),\n );\n }\n public deleteInteractionReply(token: string): Promise<void> {\n if (!this.user)\n return Promise.reject(new Error(\"Client is unauthenticated.\"));\n return this.rest.delete(\n Routes.interactionOriginalResponse(this.user.id, token),\n );\n }\n public followUpInteraction(\n token: string,\n data: Record<string, unknown>,\n ): Promise<unknown> {\n if (!this.user)\n return Promise.reject(new Error(\"Client is unauthenticated.\"));\n return this.rest.post(\n `/webhooks/${this.user.id}/${token}`,\n toRequest(data, this.options.allowedMentions),\n );\n }\n public interactionWebhookMessage(\n method: \"GET\" | \"PATCH\" | \"DELETE\",\n applicationId: string,\n token: string,\n messageId: string,\n data?: Record<string, unknown>,\n ): Promise<unknown> {\n const path =\n messageId === \"@original\"\n ? Routes.interactionOriginalResponse(applicationId, token)\n : Routes.webhookMessage(applicationId, token, messageId);\n if (method === \"GET\") return this.rest.get(path);\n if (method === \"PATCH\")\n return this.rest.patch(\n path,\n data ? toRequest(data, this.options.allowedMentions) : data,\n );\n return this.rest.delete(path);\n }\n\n // ── Client Utilities ─────────────────────────────────────────────────────\n\n /** Fetches a webhook from Discord. */\n public fetchWebhook(\n id: string,\n token?: string,\n ): Promise<Record<string, unknown>> {\n return this.rest.get(\n token ? `/webhooks/${id}/${token}` : `/webhooks/${id}`,\n ) as Promise<Record<string, unknown>>;\n }\n\n /** Fetches a guild preview from Discord. */\n public fetchGuildPreview(\n guildId: string,\n ): Promise<Record<string, unknown>> {\n return this.rest.get(`/guilds/${guildId}/preview`) as Promise<\n Record<string, unknown>\n >;\n }\n\n /** Fetches the voice regions from Discord. */\n public fetchVoiceRegions(): Promise<Record<string, unknown>[]> {\n return this.rest.get(\"/voice/regions\") as Promise<\n Record<string, unknown>[]\n >;\n }\n\n /** Fetches an invite from Discord. */\n public fetchInvite(\n code: string,\n options?: {\n withCounts?: boolean;\n /** @deprecated No effect: Discord always returns `expires_at` and deprecated `with_expiration`. Removed in 0.3.0. */\n withExpiration?: boolean;\n guildScheduledEventId?: string;\n },\n ): Promise<Record<string, unknown>> {\n const query = new URLSearchParams();\n if (options?.withCounts) query.set(\"with_counts\", \"true\");\n if (options?.guildScheduledEventId)\n query.set(\n \"guild_scheduled_event_id\",\n options.guildScheduledEventId,\n );\n const qs = query.toString();\n return this.rest.get(\n `/invites/${encodeURIComponent(code)}${qs ? `?${qs}` : \"\"}`,\n ) as Promise<Record<string, unknown>>;\n }\n\n /** Fetches a sticker from Discord. */\n public fetchSticker(id: string): Promise<Record<string, unknown>> {\n return this.rest.get(`/stickers/${id}`) as Promise<\n Record<string, unknown>\n >;\n }\n\n /** Fetches premium sticker packs from Discord. */\n public fetchPremiumStickerPacks(): Promise<Record<string, unknown>> {\n return this.rest.get(`/sticker-packs`) as Promise<\n Record<string, unknown>\n >;\n }\n\n /** Fetches a guild template from Discord. */\n public fetchGuildTemplate(code: string): Promise<Record<string, unknown>> {\n return this.rest.get(\n `/guilds/templates/${encodeURIComponent(code)}`,\n ) as Promise<Record<string, unknown>>;\n }\n\n /** Generates an invite link for this client. */\n public generateInvite(options?: {\n scopes?: string[];\n permissions?: string | bigint;\n }): string {\n if (!this.user)\n throw new Error(\"Client must be ready to generate invite.\");\n const params = new URLSearchParams({\n client_id: this.user.id,\n scope: (options?.scopes ?? [\"bot\"]).join(\" \"),\n });\n if (options?.permissions) {\n params.set(\"permissions\", String(options.permissions));\n }\n return `https://discord.com/api/oauth2/authorize?${params.toString()}`;\n }\n}\n"
|
|
5
|
+
"/** Permission overwrite target types. */\r\nexport enum PermissionOverwriteEnum {\r\n Role = 0,\r\n Member = 1,\r\n}\r\n/** @deprecated Use {@link PermissionOverwriteEnum}. Removed in 0.3.0. */\r\nexport const PermissionOverwriteType = PermissionOverwriteEnum;\r\n/** @deprecated Use {@link PermissionOverwriteEnum}. Removed in 0.3.0. */\r\nexport type PermissionOverwriteType = PermissionOverwriteEnum;\r\n\r\n/** Lunibee idiomatic camelCase permission bitflags. */\r\nexport const Permission = {\r\n createInstantInvite: 1n << 0n,\r\n kickMembers: 1n << 1n,\r\n banMembers: 1n << 2n,\r\n administrator: 1n << 3n,\r\n manageChannels: 1n << 4n,\r\n manageGuild: 1n << 5n,\r\n addReactions: 1n << 6n,\r\n viewAuditLog: 1n << 7n,\r\n prioritySpeaker: 1n << 8n,\r\n stream: 1n << 9n,\r\n viewChannel: 1n << 10n,\r\n sendMessages: 1n << 11n,\r\n sendTTSMessages: 1n << 12n,\r\n manageMessages: 1n << 13n,\r\n embedLinks: 1n << 14n,\r\n attachFiles: 1n << 15n,\r\n readMessageHistory: 1n << 16n,\r\n mentionEveryone: 1n << 17n,\r\n useExternalEmojis: 1n << 18n,\r\n viewGuildInsights: 1n << 19n,\r\n connect: 1n << 20n,\r\n speak: 1n << 21n,\r\n muteMembers: 1n << 22n,\r\n deafenMembers: 1n << 23n,\r\n moveMembers: 1n << 24n,\r\n useVAD: 1n << 25n,\r\n changeNickname: 1n << 26n,\r\n manageNicknames: 1n << 27n,\r\n manageRoles: 1n << 28n,\r\n manageWebhooks: 1n << 29n,\r\n manageGuildExpressions: 1n << 30n,\r\n useApplicationCommands: 1n << 31n,\r\n requestToSpeak: 1n << 32n,\r\n manageEvents: 1n << 33n,\r\n manageThreads: 1n << 34n,\r\n createPublicThreads: 1n << 35n,\r\n createPrivateThreads: 1n << 36n,\r\n useExternalStickers: 1n << 37n,\r\n sendMessagesInThreads: 1n << 38n,\r\n useEmbeddedActivities: 1n << 39n,\r\n moderateMembers: 1n << 40n,\r\n viewCreatorMonetizationAnalytics: 1n << 41n,\r\n useSoundboard: 1n << 42n,\r\n createGuildExpressions: 1n << 43n,\r\n createEvents: 1n << 44n,\r\n useExternalSounds: 1n << 45n,\r\n sendVoiceMessages: 1n << 46n,\r\n setVoiceChannelStatus: 1n << 48n,\r\n sendPolls: 1n << 49n,\r\n useExternalApps: 1n << 50n,\r\n pinMessages: 1n << 51n,\r\n bypassSlowmode: 1n << 52n,\r\n} as const;\r\n\r\n/** Canonical PascalCase permission constants. */\r\nexport const Permissions = {\r\n CreateInstantInvite: 1n << 0n,\r\n KickMembers: 1n << 1n,\r\n BanMembers: 1n << 2n,\r\n Administrator: 1n << 3n,\r\n ManageChannels: 1n << 4n,\r\n ManageGuild: 1n << 5n,\r\n AddReactions: 1n << 6n,\r\n ViewAuditLog: 1n << 7n,\r\n PrioritySpeaker: 1n << 8n,\r\n Stream: 1n << 9n,\r\n ViewChannel: 1n << 10n,\r\n SendMessages: 1n << 11n,\r\n SendTTSMessages: 1n << 12n,\r\n ManageMessages: 1n << 13n,\r\n EmbedLinks: 1n << 14n,\r\n AttachFiles: 1n << 15n,\r\n ReadMessageHistory: 1n << 16n,\r\n MentionEveryone: 1n << 17n,\r\n UseExternalEmojis: 1n << 18n,\r\n ViewGuildInsights: 1n << 19n,\r\n Connect: 1n << 20n,\r\n Speak: 1n << 21n,\r\n MuteMembers: 1n << 22n,\r\n DeafenMembers: 1n << 23n,\r\n MoveMembers: 1n << 24n,\r\n UseVAD: 1n << 25n,\r\n ChangeNickname: 1n << 26n,\r\n ManageNicknames: 1n << 27n,\r\n ManageRoles: 1n << 28n,\r\n ManageWebhooks: 1n << 29n,\r\n ManageGuildExpressions: 1n << 30n,\r\n UseApplicationCommands: 1n << 31n,\r\n RequestToSpeak: 1n << 32n,\r\n ManageEvents: 1n << 33n,\r\n ManageThreads: 1n << 34n,\r\n CreatePublicThreads: 1n << 35n,\r\n CreatePrivateThreads: 1n << 36n,\r\n UseExternalStickers: 1n << 37n,\r\n SendMessagesInThreads: 1n << 38n,\r\n UseEmbeddedActivities: 1n << 39n,\r\n ModerateMembers: 1n << 40n,\r\n ViewCreatorMonetizationAnalytics: 1n << 41n,\r\n UseSoundboard: 1n << 42n,\r\n CreateGuildExpressions: 1n << 43n,\r\n CreateEvents: 1n << 44n,\r\n UseExternalSounds: 1n << 45n,\r\n SendVoiceMessages: 1n << 46n,\r\n SetVoiceChannelStatus: 1n << 48n,\r\n SendPolls: 1n << 49n,\r\n UseExternalApps: 1n << 50n,\r\n PinMessages: 1n << 51n,\r\n BypassSlowmode: 1n << 52n,\r\n} as const;\r\n\r\n/**\r\n * Permission flag bits with **bigint** values matching Discord's permission bit\r\n * positions. Mirrors discord.js's `PermissionFlagsBits`, so bitwise composition\r\n * (`Flags.A | Flags.B`) OR-s the bits instead of concatenating strings.\r\n *\r\n * The same object as {@link Permissions}, under the discord.js name. It is a\r\n * `const` object rather than a TS `enum` because enums cannot hold bigint\r\n * members; the same-named union type below preserves usage as a type.\r\n */\r\nexport const PermissionFlagsBits = Permissions;\r\n\r\n/** Union of {@link PermissionFlagsBits} values (all bigint). */\r\nexport type PermissionFlagsBits =\r\n (typeof PermissionFlagsBits)[keyof typeof PermissionFlagsBits];\r\n\r\nexport type PermissionName =\r\n | keyof typeof Permission\r\n | keyof typeof Permissions\r\n | keyof typeof PermissionFlagsBits;\r\n\r\nexport type PermissionResolvable =\r\n | bigint\r\n | number\r\n | string\r\n | PermissionName\r\n | PermissionFlagsBits\r\n | PermissionSet\r\n | PermissionResolvable[];\r\n\r\n/** Immutable permission bitfield with direct boolean getters. */\r\nexport class PermissionSet {\r\n /** Permission bitfield. */\r\n public readonly bitfield: bigint;\r\n\r\n /** Creates a permission set. @param value Initial permission bitfield or array of permissions. @throws {RangeError} If the value is negative. @throws {TypeError} If the value is not a valid integer. */\r\n public constructor(value: PermissionResolvable = 0n) {\r\n try {\r\n if (Array.isArray(value)) {\r\n let bit = 0n;\r\n for (const item of value) {\r\n bit |= this.#resolve(item);\r\n }\r\n this.bitfield = bit;\r\n } else if (value instanceof PermissionSet) {\r\n this.bitfield = value.bitfield;\r\n } else {\r\n const bitfield = this.#resolve(value);\r\n if (bitfield < 0n)\r\n throw new RangeError(\r\n \"Permission bitfield cannot be negative.\",\r\n );\r\n this.bitfield = bitfield;\r\n }\r\n } catch (error) {\r\n if (error instanceof RangeError) throw error;\r\n throw new TypeError(\r\n \"Permission bitfield must be a valid non-negative integer.\",\r\n { cause: error },\r\n );\r\n }\r\n }\r\n\r\n // Direct camelCase boolean getters for instant checks (e.g. member.permissions.kickMembers)\r\n public get createInstantInvite(): boolean {\r\n return (\r\n (this.bitfield & Permission.createInstantInvite) ===\r\n Permission.createInstantInvite\r\n );\r\n }\r\n public get kickMembers(): boolean {\r\n return (\r\n (this.bitfield & Permission.kickMembers) === Permission.kickMembers\r\n );\r\n }\r\n public get banMembers(): boolean {\r\n return (\r\n (this.bitfield & Permission.banMembers) === Permission.banMembers\r\n );\r\n }\r\n public get administrator(): boolean {\r\n return (\r\n (this.bitfield & Permission.administrator) ===\r\n Permission.administrator\r\n );\r\n }\r\n public get manageChannels(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageChannels) ===\r\n Permission.manageChannels\r\n );\r\n }\r\n public get manageGuild(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageGuild) === Permission.manageGuild\r\n );\r\n }\r\n public get addReactions(): boolean {\r\n return (\r\n (this.bitfield & Permission.addReactions) ===\r\n Permission.addReactions\r\n );\r\n }\r\n public get viewAuditLog(): boolean {\r\n return (\r\n (this.bitfield & Permission.viewAuditLog) ===\r\n Permission.viewAuditLog\r\n );\r\n }\r\n public get prioritySpeaker(): boolean {\r\n return (\r\n (this.bitfield & Permission.prioritySpeaker) ===\r\n Permission.prioritySpeaker\r\n );\r\n }\r\n public get stream(): boolean {\r\n return (this.bitfield & Permission.stream) === Permission.stream;\r\n }\r\n public get viewChannel(): boolean {\r\n return (\r\n (this.bitfield & Permission.viewChannel) === Permission.viewChannel\r\n );\r\n }\r\n public get sendMessages(): boolean {\r\n return (\r\n (this.bitfield & Permission.sendMessages) ===\r\n Permission.sendMessages\r\n );\r\n }\r\n public get sendTTSMessages(): boolean {\r\n return (\r\n (this.bitfield & Permission.sendTTSMessages) ===\r\n Permission.sendTTSMessages\r\n );\r\n }\r\n public get manageMessages(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageMessages) ===\r\n Permission.manageMessages\r\n );\r\n }\r\n public get embedLinks(): boolean {\r\n return (\r\n (this.bitfield & Permission.embedLinks) === Permission.embedLinks\r\n );\r\n }\r\n public get attachFiles(): boolean {\r\n return (\r\n (this.bitfield & Permission.attachFiles) === Permission.attachFiles\r\n );\r\n }\r\n public get readMessageHistory(): boolean {\r\n return (\r\n (this.bitfield & Permission.readMessageHistory) ===\r\n Permission.readMessageHistory\r\n );\r\n }\r\n public get mentionEveryone(): boolean {\r\n return (\r\n (this.bitfield & Permission.mentionEveryone) ===\r\n Permission.mentionEveryone\r\n );\r\n }\r\n public get useExternalEmojis(): boolean {\r\n return (\r\n (this.bitfield & Permission.useExternalEmojis) ===\r\n Permission.useExternalEmojis\r\n );\r\n }\r\n public get viewGuildInsights(): boolean {\r\n return (\r\n (this.bitfield & Permission.viewGuildInsights) ===\r\n Permission.viewGuildInsights\r\n );\r\n }\r\n public get connect(): boolean {\r\n return (this.bitfield & Permission.connect) === Permission.connect;\r\n }\r\n public get speak(): boolean {\r\n return (this.bitfield & Permission.speak) === Permission.speak;\r\n }\r\n public get muteMembers(): boolean {\r\n return (\r\n (this.bitfield & Permission.muteMembers) === Permission.muteMembers\r\n );\r\n }\r\n public get deafenMembers(): boolean {\r\n return (\r\n (this.bitfield & Permission.deafenMembers) ===\r\n Permission.deafenMembers\r\n );\r\n }\r\n public get moveMembers(): boolean {\r\n return (\r\n (this.bitfield & Permission.moveMembers) === Permission.moveMembers\r\n );\r\n }\r\n public get useVAD(): boolean {\r\n return (this.bitfield & Permission.useVAD) === Permission.useVAD;\r\n }\r\n public get changeNickname(): boolean {\r\n return (\r\n (this.bitfield & Permission.changeNickname) ===\r\n Permission.changeNickname\r\n );\r\n }\r\n public get manageNicknames(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageNicknames) ===\r\n Permission.manageNicknames\r\n );\r\n }\r\n public get manageRoles(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageRoles) === Permission.manageRoles\r\n );\r\n }\r\n public get manageWebhooks(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageWebhooks) ===\r\n Permission.manageWebhooks\r\n );\r\n }\r\n public get manageGuildExpressions(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageGuildExpressions) ===\r\n Permission.manageGuildExpressions\r\n );\r\n }\r\n public get useApplicationCommands(): boolean {\r\n return (\r\n (this.bitfield & Permission.useApplicationCommands) ===\r\n Permission.useApplicationCommands\r\n );\r\n }\r\n public get requestToSpeak(): boolean {\r\n return (\r\n (this.bitfield & Permission.requestToSpeak) ===\r\n Permission.requestToSpeak\r\n );\r\n }\r\n public get manageEvents(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageEvents) ===\r\n Permission.manageEvents\r\n );\r\n }\r\n public get manageThreads(): boolean {\r\n return (\r\n (this.bitfield & Permission.manageThreads) ===\r\n Permission.manageThreads\r\n );\r\n }\r\n public get createPublicThreads(): boolean {\r\n return (\r\n (this.bitfield & Permission.createPublicThreads) ===\r\n Permission.createPublicThreads\r\n );\r\n }\r\n public get createPrivateThreads(): boolean {\r\n return (\r\n (this.bitfield & Permission.createPrivateThreads) ===\r\n Permission.createPrivateThreads\r\n );\r\n }\r\n public get useExternalStickers(): boolean {\r\n return (\r\n (this.bitfield & Permission.useExternalStickers) ===\r\n Permission.useExternalStickers\r\n );\r\n }\r\n public get sendMessagesInThreads(): boolean {\r\n return (\r\n (this.bitfield & Permission.sendMessagesInThreads) ===\r\n Permission.sendMessagesInThreads\r\n );\r\n }\r\n public get useEmbeddedActivities(): boolean {\r\n return (\r\n (this.bitfield & Permission.useEmbeddedActivities) ===\r\n Permission.useEmbeddedActivities\r\n );\r\n }\r\n public get moderateMembers(): boolean {\r\n return (\r\n (this.bitfield & Permission.moderateMembers) ===\r\n Permission.moderateMembers\r\n );\r\n }\r\n public get viewCreatorMonetizationAnalytics(): boolean {\r\n return (\r\n (this.bitfield & Permission.viewCreatorMonetizationAnalytics) ===\r\n Permission.viewCreatorMonetizationAnalytics\r\n );\r\n }\r\n public get useSoundboard(): boolean {\r\n return (\r\n (this.bitfield & Permission.useSoundboard) ===\r\n Permission.useSoundboard\r\n );\r\n }\r\n public get createGuildExpressions(): boolean {\r\n return (\r\n (this.bitfield & Permission.createGuildExpressions) ===\r\n Permission.createGuildExpressions\r\n );\r\n }\r\n public get createEvents(): boolean {\r\n return (\r\n (this.bitfield & Permission.createEvents) ===\r\n Permission.createEvents\r\n );\r\n }\r\n public get useExternalSounds(): boolean {\r\n return (\r\n (this.bitfield & Permission.useExternalSounds) ===\r\n Permission.useExternalSounds\r\n );\r\n }\r\n public get sendVoiceMessages(): boolean {\r\n return (\r\n (this.bitfield & Permission.sendVoiceMessages) ===\r\n Permission.sendVoiceMessages\r\n );\r\n }\r\n public get sendPolls(): boolean {\r\n return (this.bitfield & Permission.sendPolls) === Permission.sendPolls;\r\n }\r\n public get useExternalApps(): boolean {\r\n return (\r\n (this.bitfield & Permission.useExternalApps) ===\r\n Permission.useExternalApps\r\n );\r\n }\r\n\r\n /** Checks whether all supplied permissions are present (AND). @param permissions Permission names or raw bits. @returns True when every requested permission is present. */\r\n public has(...permissions: PermissionResolvable[]): boolean {\r\n if (permissions.length === 1) {\r\n const p = permissions[0]!;\r\n const bit = typeof p === \"bigint\" ? p : this.#resolve(p);\r\n return (this.bitfield & bit) === bit;\r\n }\r\n for (let i = 0; i < permissions.length; i++) {\r\n const p = permissions[i]!;\r\n const bit = typeof p === \"bigint\" ? p : this.#resolve(p);\r\n if ((this.bitfield & bit) !== bit) return false;\r\n }\r\n return true;\r\n }\r\n\r\n /** Checks whether any supplied permission is present (OR). @param permissions Permission names or raw bits. @returns True when at least one requested permission is present. */\r\n public any(...permissions: PermissionResolvable[]): boolean {\r\n if (permissions.length === 1) {\r\n const p = permissions[0]!;\r\n const bit = typeof p === \"bigint\" ? p : this.#resolve(p);\r\n return (this.bitfield & bit) !== 0n;\r\n }\r\n for (let i = 0; i < permissions.length; i++) {\r\n const p = permissions[i]!;\r\n const bit = typeof p === \"bigint\" ? p : this.#resolve(p);\r\n if ((this.bitfield & bit) !== 0n) return true;\r\n }\r\n return false;\r\n }\r\n\r\n /** Returns the known permission names from `permissions` that this set lacks. @param permissions Permission names or raw bits. */\r\n public missing(...permissions: PermissionResolvable[]): PermissionName[] {\r\n const wanted = new PermissionSet(permissions);\r\n return wanted.toArray().filter((name) => !this.has(name));\r\n }\r\n\r\n /** Returns a new set with permissions added. @param permissions Permission names or raw bits. @returns A new permission set. */\r\n public add(...permissions: PermissionResolvable[]): PermissionSet {\r\n let bitfield = this.bitfield;\r\n for (let i = 0; i < permissions.length; i++) {\r\n const p = permissions[i]!;\r\n bitfield |= typeof p === \"bigint\" ? p : this.#resolve(p);\r\n }\r\n return new PermissionSet(bitfield);\r\n }\r\n\r\n /** Returns a new set with permissions removed. @param permissions Permission names or raw bits. @returns A new permission set. */\r\n public remove(...permissions: PermissionResolvable[]): PermissionSet {\r\n let bitfield = this.bitfield;\r\n for (let i = 0; i < permissions.length; i++) {\r\n const p = permissions[i]!;\r\n bitfield &= ~(typeof p === \"bigint\" ? p : this.#resolve(p));\r\n }\r\n return new PermissionSet(bitfield);\r\n }\r\n\r\n /** Checks equality with another permission set or raw bitfield. @param other Permission set or raw bitfield. @returns True when both values are equal. */\r\n public equals(other: PermissionSet | bigint | number | string): boolean {\r\n return (\r\n this.bitfield ===\r\n (other instanceof PermissionSet\r\n ? other.bitfield\r\n : new PermissionSet(other).bitfield)\r\n );\r\n }\r\n\r\n /** Returns the decimal permission representation. @returns Decimal permission bitfield. */\r\n public toString(): string {\r\n return this.bitfield.toString();\r\n }\r\n\r\n /** Returns known permission names contained in this set. @returns Names of all enabled known permissions. */\r\n public toArray(): PermissionName[] {\r\n return (Object.keys(Permission) as PermissionName[]).filter(\r\n (permission) => this.has(permission),\r\n );\r\n }\r\n\r\n /** Resolves a named permission, enum value, or raw bit. @param permission Permission name, enum value, or raw bit. @returns Numeric permission bit. */\r\n /** Names Discord has since renamed, still accepted when resolving a permission by name. */\r\n static readonly #renamed: Readonly<Record<string, string>> = {\r\n ManageEmojisAndStickers: \"ManageGuildExpressions\",\r\n ManageEmojis: \"ManageGuildExpressions\",\r\n UseSlashCommands: \"UseApplicationCommands\",\r\n };\r\n\r\n #resolve(permission: PermissionResolvable): bigint {\r\n if (typeof permission === \"bigint\") return permission;\r\n if (typeof permission === \"number\") return BigInt(permission);\r\n if (permission instanceof PermissionSet) return permission.bitfield;\r\n if (Array.isArray(permission)) {\r\n let bit = 0n;\r\n for (let i = 0; i < permission.length; i++)\r\n bit |= this.#resolve(permission[i]!);\r\n return bit;\r\n }\r\n if (typeof permission === \"string\") {\r\n const renamed = PermissionSet.#renamed[permission];\r\n if (renamed) return this.#resolve(renamed);\r\n if (permission in Permission)\r\n return (Permission as Record<string, bigint>)[permission]!;\r\n if (permission in Permissions)\r\n return (Permissions as Record<string, bigint>)[permission]!;\r\n if (permission in PermissionFlagsBits)\r\n return (PermissionFlagsBits as Record<string, bigint>)[\r\n permission\r\n ]!;\r\n const lower =\r\n permission.charAt(0).toLowerCase() + permission.slice(1);\r\n if (lower in Permission)\r\n return (Permission as Record<string, bigint>)[lower]!;\r\n return BigInt(permission);\r\n }\r\n return 0n;\r\n }\r\n}\r\n\r\n/** Permissions bitfield alias. */\r\nexport class PermissionsBitField extends PermissionSet {\r\n /** Permission flags bits enum. */\r\n public static readonly Flags = PermissionFlagsBits;\r\n /** Permission flags constants. */\r\n public static readonly All = Permission;\r\n\r\n /** Creates a permissions bitfield. @param value Initial permission bitfield or array of permissions. */\r\n public constructor(value: PermissionResolvable = 0n) {\r\n super(value);\r\n }\r\n}\r\n\r\n/** Every known permission bit. */\r\nconst ALL_PERMISSIONS = Object.values(Permission).reduce(\r\n (bits, bit) => bits | bit,\r\n 0n,\r\n);\r\n\r\n/** A role as needed for permission resolution. */\r\nexport interface PermissionRole {\r\n id: string;\r\n permissions: PermissionResolvable;\r\n}\r\n\r\n/** A channel permission overwrite (Discord's `permission_overwrites` entry). */\r\nexport interface PermissionOverwrite {\r\n id: string;\r\n type: PermissionOverwriteEnum | number;\r\n allow: PermissionResolvable;\r\n deny: PermissionResolvable;\r\n}\r\n\r\n/** Everything needed to resolve a member's permissions. */\r\nexport interface PermissionContext {\r\n guildId: string;\r\n /** Guild owner ID; the owner has every permission. */\r\n ownerId?: string;\r\n memberId: string;\r\n memberRoleIds: readonly string[];\r\n /** Guild roles, including `@everyone` (whose ID is the guild ID). */\r\n roles: readonly PermissionRole[];\r\n /** Channel overwrites; omit for guild-level permissions. */\r\n overwrites?: readonly PermissionOverwrite[];\r\n /** When the member's timeout ends; while it is in the future the member keeps only View Channel and Read Message History. */\r\n timedOutUntil?: Date | number | null;\r\n}\r\n\r\nconst bits = (value: PermissionResolvable): bigint =>\r\n new PermissionSet(value).bitfield;\r\n\r\n/**\r\n * Resolves a member's effective permissions the way Discord does: base\r\n * permissions from `@everyone` and the member's roles (owner and\r\n * administrator get everything), then the channel's `@everyone` overwrite,\r\n * the combined role overwrites, and finally the member overwrite. A member\r\n * whose timeout has not ended keeps only View Channel and Read Message History.\r\n */\r\nexport function computePermissions(context: PermissionContext): PermissionSet {\r\n if (context.ownerId !== undefined && context.ownerId === context.memberId)\r\n return new PermissionSet(ALL_PERMISSIONS);\r\n const roles = new Map(context.roles.map((role) => [role.id, role]));\r\n let base = bits(roles.get(context.guildId)?.permissions ?? 0n);\r\n for (const id of context.memberRoleIds)\r\n base |= bits(roles.get(id)?.permissions ?? 0n);\r\n if (base & Permission.administrator)\r\n return new PermissionSet(ALL_PERMISSIONS);\r\n const overwrites = context.overwrites ?? [];\r\n const everyone = overwrites.find((o) => o.id === context.guildId);\r\n if (everyone) base = (base & ~bits(everyone.deny)) | bits(everyone.allow);\r\n const memberRoles = new Set(context.memberRoleIds);\r\n let allow = 0n;\r\n let deny = 0n;\r\n for (const overwrite of overwrites)\r\n if (\r\n overwrite.type === PermissionOverwriteEnum.Role &&\r\n overwrite.id !== context.guildId &&\r\n memberRoles.has(overwrite.id)\r\n ) {\r\n allow |= bits(overwrite.allow);\r\n deny |= bits(overwrite.deny);\r\n }\r\n base = (base & ~deny) | allow;\r\n const member = overwrites.find(\r\n (o) =>\r\n o.type === PermissionOverwriteEnum.Member &&\r\n o.id === context.memberId,\r\n );\r\n if (member) base = (base & ~bits(member.deny)) | bits(member.allow);\r\n // Discord: timed-out members lose every permission except View Channel and\r\n // Read Message History. Owners and administrators returned above.\r\n const until =\r\n context.timedOutUntil instanceof Date\r\n ? context.timedOutUntil.getTime()\r\n : (context.timedOutUntil ?? 0);\r\n if (until > Date.now())\r\n base &= Permission.viewChannel | Permission.readMessageHistory;\r\n return new PermissionSet(base);\r\n}\r\n",
|
|
6
|
+
"import type {\r\n APIEntitlement,\r\n APISoundboardSound,\r\n APISticker,\r\n} from \"@lunibee/types\";\r\nimport type {\r\n APIAutoModerationActionExecution,\r\n APIAutoModerationRule,\r\n APIChannel,\r\n APIChannelPinsUpdate,\r\n APIGuild,\r\n APIGuildBanEvent,\r\n APIGuildEmojisUpdateEvent,\r\n APIGuildMember,\r\n APIGuildMembersChunk,\r\n APIGuildRoleDeleteEvent,\r\n APIGuildRoleEvent,\r\n APIGuildScheduledEvent,\r\n APIGuildScheduledEventUserEvent,\r\n APIGuildStickersUpdateEvent,\r\n APIInviteCreate,\r\n APIInviteDelete,\r\n APIMessageDeleteBulkEvent,\r\n APIMessageDeleteEvent,\r\n APIMessagePollVoteEvent,\r\n APIMessageReactionEvent,\r\n APIMessageReactionRemoveEmojiEvent,\r\n APIPresenceUpdate,\r\n APIStageInstance,\r\n APIThreadEvent,\r\n APIThreadListSync,\r\n APIThreadMember,\r\n APIThreadMembersUpdate,\r\n APITypingStart,\r\n APIVoiceServerUpdate,\r\n APIVoiceState,\r\n APIWebhooksUpdate,\r\n ClientUser,\r\n} from \"@lunibee/types\";\r\nimport type {\r\n Channel,\r\n Emoji,\r\n Guild,\r\n GuildMember,\r\n Interaction,\r\n Message,\r\n Role,\r\n} from \"@lunibee/structures\";\r\n/** Names of events emitted by a Lunibee client. */\r\nexport enum ClientEvent {\r\n // ── Lifecycle ──────────────────────────────────────────────────────────────\r\n Ready = \"ready\",\r\n Resumed = \"resumed\",\r\n InvalidSession = \"invalidSession\",\r\n Raw = \"raw\",\r\n Error = \"error\",\r\n Open = \"open\",\r\n Close = \"close\",\r\n // ── Messages ───────────────────────────────────────────────────────────────\r\n MessageCreate = \"messageCreate\",\r\n MessageUpdate = \"messageUpdate\",\r\n MessageDelete = \"messageDelete\",\r\n MessageDeleteBulk = \"messageDeleteBulk\",\r\n // ── Reactions ─────────────────────────────────────────────────────────────\r\n MessageReactionAdd = \"messageReactionAdd\",\r\n MessageReactionRemove = \"messageReactionRemove\",\r\n MessageReactionRemoveAll = \"messageReactionRemoveAll\",\r\n MessageReactionRemoveEmoji = \"messageReactionRemoveEmoji\",\r\n // ── Polls ─────────────────────────────────────────────────────────────────\r\n MessagePollVoteAdd = \"messagePollVoteAdd\",\r\n MessagePollVoteRemove = \"messagePollVoteRemove\",\r\n // ── Guilds ────────────────────────────────────────────────────────────────\r\n GuildCreate = \"guildCreate\",\r\n GuildUpdate = \"guildUpdate\",\r\n GuildDelete = \"guildDelete\",\r\n GuildAvailable = \"guildAvailable\",\r\n GuildUnavailable = \"guildUnavailable\",\r\n // ── Guild Members ──────────────────────────────────────────────────────────\r\n GuildMemberAdd = \"guildMemberAdd\",\r\n GuildMemberUpdate = \"guildMemberUpdate\",\r\n GuildMemberRemove = \"guildMemberRemove\",\r\n GuildMembersChunk = \"guildMembersChunk\",\r\n // ── Guild Bans ────────────────────────────────────────────────────────────\r\n GuildBanAdd = \"guildBanAdd\",\r\n GuildBanRemove = \"guildBanRemove\",\r\n // ── Guild Roles ───────────────────────────────────────────────────────────\r\n GuildRoleCreate = \"guildRoleCreate\",\r\n GuildRoleUpdate = \"guildRoleUpdate\",\r\n GuildRoleDelete = \"guildRoleDelete\",\r\n // ── Guild Emojis & Stickers ───────────────────────────────────────────────\r\n GuildEmojisUpdate = \"guildEmojisUpdate\",\r\n GuildStickersUpdate = \"guildStickersUpdate\",\r\n // ── Monetization ──────────────────────────────────────────────────────────\r\n EntitlementCreate = \"entitlementCreate\",\r\n EntitlementUpdate = \"entitlementUpdate\",\r\n EntitlementDelete = \"entitlementDelete\",\r\n // ── Soundboard ────────────────────────────────────────────────────────────\r\n SoundboardSoundCreate = \"soundboardSoundCreate\",\r\n SoundboardSoundUpdate = \"soundboardSoundUpdate\",\r\n SoundboardSoundDelete = \"soundboardSoundDelete\",\r\n SoundboardSoundsUpdate = \"soundboardSoundsUpdate\",\r\n // ── Guild Integrations ────────────────────────────────────────────────────\r\n GuildIntegrationsUpdate = \"guildIntegrationsUpdate\",\r\n // ── Guild Scheduled Events ────────────────────────────────────────────────\r\n GuildScheduledEventCreate = \"guildScheduledEventCreate\",\r\n GuildScheduledEventUpdate = \"guildScheduledEventUpdate\",\r\n GuildScheduledEventDelete = \"guildScheduledEventDelete\",\r\n GuildScheduledEventUserAdd = \"guildScheduledEventUserAdd\",\r\n GuildScheduledEventUserRemove = \"guildScheduledEventUserRemove\",\r\n // ── AutoMod ───────────────────────────────────────────────────────────────\r\n AutoModerationRuleCreate = \"autoModerationRuleCreate\",\r\n AutoModerationRuleUpdate = \"autoModerationRuleUpdate\",\r\n AutoModerationRuleDelete = \"autoModerationRuleDelete\",\r\n AutoModerationActionExecution = \"autoModerationActionExecution\",\r\n // ── Channels ──────────────────────────────────────────────────────────────\r\n ChannelCreate = \"channelCreate\",\r\n ChannelUpdate = \"channelUpdate\",\r\n ChannelDelete = \"channelDelete\",\r\n ChannelPinsUpdate = \"channelPinsUpdate\",\r\n // ── Threads ───────────────────────────────────────────────────────────────\r\n ThreadCreate = \"threadCreate\",\r\n ThreadUpdate = \"threadUpdate\",\r\n ThreadDelete = \"threadDelete\",\r\n ThreadListSync = \"threadListSync\",\r\n ThreadMembersUpdate = \"threadMembersUpdate\",\r\n ThreadMemberUpdate = \"threadMemberUpdate\",\r\n // ── Stage Instances ───────────────────────────────────────────────────────\r\n StageInstanceCreate = \"stageInstanceCreate\",\r\n StageInstanceUpdate = \"stageInstanceUpdate\",\r\n StageInstanceDelete = \"stageInstanceDelete\",\r\n // ── Invites ───────────────────────────────────────────────────────────────\r\n InviteCreate = \"inviteCreate\",\r\n InviteDelete = \"inviteDelete\",\r\n // ── Webhooks ──────────────────────────────────────────────────────────────\r\n WebhooksUpdate = \"webhooksUpdate\",\r\n // ── Voice ─────────────────────────────────────────────────────────────────\r\n VoiceStateUpdate = \"voiceStateUpdate\",\r\n VoiceServerUpdate = \"voiceServerUpdate\",\r\n // ── Presence & Typing ─────────────────────────────────────────────────────\r\n PresenceUpdate = \"presenceUpdate\",\r\n TypingStart = \"typingStart\",\r\n // ── Interactions ──────────────────────────────────────────────────────────\r\n InteractionCreate = \"interactionCreate\",\r\n}\r\n\r\n/** Names of events emitted by a Lunibee client. */\r\nexport type ClientEventName = keyof ClientEvents;\r\n\r\n/** Listener signature for a Lunibee client event. */\r\nexport type ClientListener<K extends ClientEventName> = (\r\n ...args: ClientEvents[K]\r\n) => unknown;\r\n\r\n// ─── ClientEvents type map ────────────────────────────────────────────────────\r\n// Uses string literal keys so client.on(\"ready\", ...) works without using\r\n// the ClientEvent enum explicitly.\r\n\r\nexport type ClientEvents = {\r\n // ── Lifecycle ──────────────────────────────────────────────────────────────\r\n ready: [user: ClientUser];\r\n resumed: [];\r\n invalidSession: [isRecoverable: boolean];\r\n raw: [data: { event: string; data: unknown }];\r\n error: [error: Error];\r\n open: [];\r\n close: [data: { code: number; action: string }];\r\n // ── Messages ───────────────────────────────────────────────────────────────\r\n messageCreate: [message: Message];\r\n /** `previous` is the cached version, available when `messageCache` is enabled. */\r\n messageUpdate: [message: Message, previous?: Message];\r\n /** `message` is the cached message, available when `messageCache` is enabled. */\r\n messageDelete: [data: APIMessageDeleteEvent, message?: Message];\r\n /** `messages` are the cached messages that were deleted (empty without `messageCache`). */\r\n messageDeleteBulk: [data: APIMessageDeleteBulkEvent, messages: Message[]];\r\n // ── Reactions ─────────────────────────────────────────────────────────────\r\n messageReactionAdd: [data: APIMessageReactionEvent];\r\n messageReactionRemove: [data: APIMessageReactionEvent];\r\n messageReactionRemoveAll: [data: APIMessageDeleteEvent];\r\n messageReactionRemoveEmoji: [data: APIMessageReactionRemoveEmojiEvent];\r\n // ── Polls ─────────────────────────────────────────────────────────────────\r\n messagePollVoteAdd: [data: APIMessagePollVoteEvent];\r\n messagePollVoteRemove: [data: APIMessagePollVoteEvent];\r\n // ── Guilds ────────────────────────────────────────────────────────────────\r\n guildCreate: [data: APIGuild];\r\n /** `previous` is a copy of the cached guild before the update, or null when it was not cached. */\r\n guildUpdate: [data: APIGuild, previous: Guild | null];\r\n guildDelete: [data: { id: string; unavailable?: boolean }];\r\n guildAvailable: [data: APIGuild & { unavailable?: boolean }];\r\n guildUnavailable: [data: { id: string; unavailable?: boolean }];\r\n // ── Guild Members ──────────────────────────────────────────────────────────\r\n guildMemberAdd: [member: APIGuildMember];\r\n /** `previous` is a copy of the cached member before the update, or null when it was not cached. */\r\n guildMemberUpdate: [member: APIGuildMember, previous: GuildMember | null];\r\n guildMemberRemove: [member: APIGuildMember];\r\n guildMembersChunk: [data: APIGuildMembersChunk];\r\n // ── Guild Bans ────────────────────────────────────────────────────────────\r\n guildBanAdd: [data: APIGuildBanEvent];\r\n guildBanRemove: [data: APIGuildBanEvent];\r\n // ── Guild Roles ───────────────────────────────────────────────────────────\r\n guildRoleCreate: [data: APIGuildRoleEvent];\r\n /** `previous` is a copy of the cached role before the update, or null when it was not cached. */\r\n guildRoleUpdate: [data: APIGuildRoleEvent, previous: Role | null];\r\n /** `removed` is the role that was cached, or null. */\r\n guildRoleDelete: [data: APIGuildRoleDeleteEvent, removed: Role | null];\r\n // ── Guild Emojis & Stickers ───────────────────────────────────────────────\r\n /** `previous` is the cached emoji list before the update, or null without the emoji cache. */\r\n guildEmojisUpdate: [\r\n data: APIGuildEmojisUpdateEvent,\r\n previous: Emoji[] | null,\r\n ];\r\n /** `previous` is the cached sticker list before the update (empty when none were cached). */\r\n guildStickersUpdate: [\r\n data: APIGuildStickersUpdateEvent,\r\n previous: APISticker[],\r\n ];\r\n // ── Monetization ──────────────────────────────────────────────────────────\r\n entitlementCreate: [entitlement: APIEntitlement];\r\n entitlementUpdate: [entitlement: APIEntitlement];\r\n entitlementDelete: [entitlement: APIEntitlement];\r\n // ── Soundboard ────────────────────────────────────────────────────────────\r\n soundboardSoundCreate: [sound: APISoundboardSound];\r\n soundboardSoundUpdate: [sound: APISoundboardSound];\r\n soundboardSoundDelete: [data: { sound_id: string; guild_id: string }];\r\n soundboardSoundsUpdate: [\r\n data: { guild_id: string; soundboard_sounds: APISoundboardSound[] },\r\n ];\r\n // ── Guild Integrations ────────────────────────────────────────────────────\r\n guildIntegrationsUpdate: [data: { guild_id: string }];\r\n // ── Guild Scheduled Events ────────────────────────────────────────────────\r\n guildScheduledEventCreate: [data: APIGuildScheduledEvent];\r\n guildScheduledEventUpdate: [data: APIGuildScheduledEvent];\r\n guildScheduledEventDelete: [data: APIGuildScheduledEvent];\r\n guildScheduledEventUserAdd: [data: APIGuildScheduledEventUserEvent];\r\n guildScheduledEventUserRemove: [data: APIGuildScheduledEventUserEvent];\r\n // ── AutoMod ───────────────────────────────────────────────────────────────\r\n autoModerationRuleCreate: [data: APIAutoModerationRule];\r\n autoModerationRuleUpdate: [data: APIAutoModerationRule];\r\n autoModerationRuleDelete: [data: APIAutoModerationRule];\r\n autoModerationActionExecution: [data: APIAutoModerationActionExecution];\r\n // ── Channels ──────────────────────────────────────────────────────────────\r\n channelCreate: [channel: Channel];\r\n /** `previous` is a copy of the cached channel before the update, or null when it was not cached. */\r\n channelUpdate: [channel: Channel, previous: Channel | null];\r\n /** `removed` is the channel that was cached, or null. */\r\n channelDelete: [data: APIChannel, removed: Channel | null];\r\n channelPinsUpdate: [data: APIChannelPinsUpdate];\r\n // ── Threads ───────────────────────────────────────────────────────────────\r\n threadCreate: [channel: Channel];\r\n /** `previous` is a copy of the cached thread before the update, or null when it was not cached. */\r\n threadUpdate: [channel: Channel, previous: Channel | null];\r\n /** `removed` is the thread that was cached, or null. */\r\n threadDelete: [data: APIThreadEvent, removed: Channel | null];\r\n threadListSync: [data: APIThreadListSync];\r\n threadMembersUpdate: [data: APIThreadMembersUpdate];\r\n threadMemberUpdate: [data: APIThreadMember];\r\n // ── Stage Instances ───────────────────────────────────────────────────────\r\n stageInstanceCreate: [data: APIStageInstance];\r\n stageInstanceUpdate: [data: APIStageInstance];\r\n stageInstanceDelete: [data: APIStageInstance];\r\n // ── Invites ───────────────────────────────────────────────────────────────\r\n inviteCreate: [data: APIInviteCreate];\r\n inviteDelete: [data: APIInviteDelete];\r\n // ── Webhooks ──────────────────────────────────────────────────────────────\r\n webhooksUpdate: [data: APIWebhooksUpdate];\r\n // ── Voice ─────────────────────────────────────────────────────────────────\r\n voiceStateUpdate: [data: APIVoiceState];\r\n voiceServerUpdate: [data: APIVoiceServerUpdate];\r\n // ── Presence & Typing ─────────────────────────────────────────────────────\r\n presenceUpdate: [data: APIPresenceUpdate];\r\n typingStart: [data: APITypingStart];\r\n // ── Interactions ──────────────────────────────────────────────────────────\r\n interactionCreate: [interaction: Interaction];\r\n};\r\n",
|
|
7
|
+
"import { EventEmitter } from \"node:events\";\r\n\r\nexport interface CollectorOptions<T> {\r\n /** Filter predicate to accept or reject items. */\r\n filter?: (item: T) => boolean | Promise<boolean>;\r\n /** Lifetime of the collector in milliseconds. */\r\n time?: number;\r\n /** Maximum number of elements to collect. */\r\n max?: number;\r\n /** Maximum number of processed elements. */\r\n maxProcessed?: number;\r\n /** Stop after this many milliseconds without a collected item. */\r\n idle?: number;\r\n /** Stop (reason `\"abort\"`) when this signal aborts. */\r\n signal?: AbortSignal;\r\n}\r\n\r\n/** General-purpose event collector for interactions and messages. */\r\nexport class Collector<K, V> extends EventEmitter {\r\n public readonly collected = new Map<K, V>();\r\n public readonly options: CollectorOptions<V>;\r\n public ended = false;\r\n public endReason?: string;\r\n public totalProcessed = 0;\r\n readonly #timeoutTimer?: ReturnType<typeof setTimeout>;\r\n #idleTimer?: ReturnType<typeof setTimeout>;\r\n readonly #onAbort = (): void => this.stop(\"abort\");\r\n /** Cleanup hooks run once when the collector ends (e.g. event unsubscription). */\r\n readonly #cleanup: (() => void)[] = [];\r\n\r\n public constructor(options: CollectorOptions<V> = {}) {\r\n super();\r\n this.options = options;\r\n\r\n if (options.time && options.time > 0) {\r\n this.#timeoutTimer = setTimeout(() => {\r\n this.stop(\"time\");\r\n }, options.time);\r\n }\r\n this.#resetIdle();\r\n if (options.signal?.aborted) this.stop(\"abort\");\r\n else\r\n options.signal?.addEventListener(\"abort\", this.#onAbort, {\r\n once: true,\r\n });\r\n }\r\n\r\n /** Registers a function to run once when the collector ends. Runs immediately if it already has. */\r\n public onDispose(cleanup: () => void): this {\r\n if (this.ended) cleanup();\r\n else this.#cleanup.push(cleanup);\r\n return this;\r\n }\r\n\r\n #resetIdle(): void {\r\n if (!this.options.idle || this.options.idle <= 0) return;\r\n if (this.#idleTimer) clearTimeout(this.#idleTimer);\r\n this.#idleTimer = setTimeout(\r\n () => this.stop(\"idle\"),\r\n this.options.idle,\r\n );\r\n }\r\n\r\n /** Handles a candidate item for collection. */\r\n public async handle(key: K, item: V): Promise<boolean> {\r\n if (this.ended) return false;\r\n this.totalProcessed++;\r\n\r\n // `maxProcessed` counts every item the collector *sees*, so it has to be\r\n // evaluated whether or not the filter accepts this one — checking it only\r\n // on the accepted path means a collector whose filter rejects everything\r\n // never reaches its processed limit and runs until `time`/`stop()`.\r\n const reachedProcessed =\r\n !!this.options.maxProcessed &&\r\n this.totalProcessed >= this.options.maxProcessed;\r\n\r\n let passed = true;\r\n if (this.options.filter) passed = !!(await this.options.filter(item));\r\n\r\n // The filter may be async, so the collector can have been stopped while\r\n // it was pending. Anything decided before that stop is discarded rather\r\n // than collected (and emitted) after \"end\".\r\n if (this.ended) return false;\r\n\r\n if (!passed) {\r\n if (reachedProcessed) this.stop(\"processedLimit\");\r\n return false;\r\n }\r\n\r\n this.collected.set(key, item);\r\n this.#resetIdle();\r\n this.emit(\"collect\", item);\r\n\r\n if (this.options.max && this.collected.size >= this.options.max) {\r\n this.stop(\"limit\");\r\n return true;\r\n }\r\n\r\n if (reachedProcessed) {\r\n this.stop(\"processedLimit\");\r\n return true;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /** Stops the collector and emits the \"end\" event. */\r\n public stop(reason = \"user\"): void {\r\n if (this.ended) return;\r\n this.ended = true;\r\n this.endReason = reason;\r\n if (this.#timeoutTimer) clearTimeout(this.#timeoutTimer);\r\n if (this.#idleTimer) clearTimeout(this.#idleTimer);\r\n this.options.signal?.removeEventListener(\"abort\", this.#onAbort);\r\n for (const cleanup of this.#cleanup.splice(0)) {\r\n try {\r\n cleanup();\r\n } catch {\r\n // A failing cleanup must not stop the others or the \"end\" event.\r\n }\r\n }\r\n this.emit(\"end\", this.collected, reason);\r\n this.removeAllListeners();\r\n }\r\n\r\n /** Resolves with everything collected once the collector ends. */\r\n public wait(): Promise<Map<K, V>> {\r\n if (this.ended) return Promise.resolve(this.collected);\r\n return new Promise((resolve) =>\r\n this.once(\"end\", (collected: Map<K, V>) => resolve(collected)),\r\n );\r\n }\r\n\r\n /** Yields items as they are collected until the collector ends. Items\r\n * collected between iterations are buffered, not dropped. */\r\n public async *[Symbol.asyncIterator](): AsyncGenerator<V, void, undefined> {\r\n const queue: V[] = [];\r\n let wake: (() => void) | undefined;\r\n const onCollect = (item: V): void => {\r\n queue.push(item);\r\n wake?.();\r\n };\r\n const onEnd = (): void => wake?.();\r\n if (!this.ended) {\r\n this.on(\"collect\", onCollect);\r\n this.on(\"end\", onEnd);\r\n }\r\n try {\r\n for (;;) {\r\n if (queue.length > 0) {\r\n yield queue.shift()!;\r\n continue;\r\n }\r\n if (this.ended) return;\r\n await new Promise<void>((resolve) => (wake = resolve));\r\n wake = undefined;\r\n }\r\n } finally {\r\n this.off(\"collect\", onCollect);\r\n this.off(\"end\", onEnd);\r\n }\r\n }\r\n\r\n /** Stops the collector (reason `\"disposed\"`); enables `using collector = ...`. */\r\n public [Symbol.dispose](): void {\r\n this.stop(\"disposed\");\r\n }\r\n\r\n /** Returns a Promise that resolves with the next collected item or rejects on end/timeout. */\r\n public next(): Promise<V> {\r\n return new Promise<V>((resolve, reject) => {\r\n if (this.ended) {\r\n return reject(\r\n new Error(\r\n `Collector already ended: ${this.endReason ?? \"unknown\"}`,\r\n ),\r\n );\r\n }\r\n\r\n // Each settled next() must drop its counterpart listener. Polling\r\n // a long-lived collector in a loop otherwise leaves one dangling\r\n // \"end\" listener per call, which grows without bound and trips the\r\n // EventEmitter max-listener warning.\r\n const onCollect = (item: V): void => {\r\n this.off(\"end\", onEnd);\r\n resolve(item);\r\n };\r\n const onEnd = (_collected: Map<K, V>, reason: string): void => {\r\n this.off(\"collect\", onCollect);\r\n reject(\r\n new Error(\r\n `Collector ended before item was collected: ${reason}`,\r\n ),\r\n );\r\n };\r\n\r\n this.once(\"collect\", onCollect);\r\n this.once(\"end\", onEnd);\r\n });\r\n }\r\n}\r\n",
|
|
8
|
+
"// ─── Gateway Intents ─────────────────────────────────────────────────────────\r\n\r\n/** Gateway intent bit flags supported by Discord (PascalCase). */\r\nexport const GatewayIntentBits = {\r\n Guilds: 1 << 0,\r\n GuildMembers: 1 << 1,\r\n GuildModeration: 1 << 2,\r\n GuildExpressions: 1 << 3,\r\n GuildIntegrations: 1 << 4,\r\n GuildWebhooks: 1 << 5,\r\n GuildInvites: 1 << 6,\r\n GuildVoiceStates: 1 << 7,\r\n GuildPresences: 1 << 8,\r\n GuildMessages: 1 << 9,\r\n GuildMessageReactions: 1 << 10,\r\n GuildMessageTyping: 1 << 11,\r\n DirectMessages: 1 << 12,\r\n DirectMessageReactions: 1 << 13,\r\n DirectMessageTyping: 1 << 14,\r\n MessageContent: 1 << 15,\r\n GuildScheduledEvents: 1 << 16,\r\n AutoModerationConfiguration: 1 << 20,\r\n AutoModerationExecution: 1 << 21,\r\n GuildMessagePolls: 1 << 24,\r\n DirectMessagePolls: 1 << 25,\r\n} as const;\r\n\r\n/** Idiomatic camelCase Gateway intent bit flags supported by Discord. */\r\nexport const IntentBits = {\r\n guild: 1 << 0,\r\n guilds: 1 << 0,\r\n guildMembers: 1 << 1,\r\n guildModeration: 1 << 2,\r\n guildBans: 1 << 2,\r\n guildExpressions: 1 << 3,\r\n guildEmojis: 1 << 3,\r\n guildEmojisAndStickers: 1 << 3,\r\n guildIntegrations: 1 << 4,\r\n guildWebhooks: 1 << 5,\r\n guildInvites: 1 << 6,\r\n guildVoiceStates: 1 << 7,\r\n guildPresences: 1 << 8,\r\n guildMessages: 1 << 9,\r\n guildMessage: 1 << 9,\r\n guildMessageReactions: 1 << 10,\r\n guildMessageTyping: 1 << 11,\r\n directMessages: 1 << 12,\r\n directMessageReactions: 1 << 13,\r\n directMessageTyping: 1 << 14,\r\n messageContent: 1 << 15,\r\n guildScheduledEvents: 1 << 16,\r\n autoModerationConfiguration: 1 << 20,\r\n autoModerationExecution: 1 << 21,\r\n guildMessagePolls: 1 << 24,\r\n directMessagePolls: 1 << 25,\r\n} as const;\r\n\r\n/** Alias for IntentBits. */\r\nexport const Intents = IntentBits;\r\n\r\n/** Gateway intent resolvable value (single bitfield, enum key, or array of bitfields/strings). */\r\nexport type GatewayIntentResolvable =\r\n | number\r\n | keyof typeof GatewayIntentBits\r\n | keyof typeof IntentBits\r\n | (\r\n | number\r\n | keyof typeof GatewayIntentBits\r\n | keyof typeof IntentBits\r\n | string\r\n )[]\r\n | { readonly bitfield: number };\r\n\r\n/** Resolves any GatewayIntentResolvable into a raw bitfield integer. */\r\nexport function resolveGatewayIntents(\r\n intents: GatewayIntentResolvable,\r\n): number {\r\n if (Array.isArray(intents))\r\n return intents.reduce<number>(\r\n (acc, intent) => acc | resolveIntent(intent),\r\n 0,\r\n );\r\n if (typeof intents === \"object\") return intents.bitfield;\r\n return resolveIntent(intents);\r\n}\r\n\r\n/** Resolves one intent: a bitfield, an intent name in either casing, or a numeric string. */\r\nfunction resolveIntent(intent: number | string): number {\r\n if (typeof intent === \"number\") return intent;\r\n const bits: Record<string, number> = {\r\n ...IntentBits,\r\n ...GatewayIntentBits,\r\n };\r\n const lower = intent.charAt(0).toLowerCase() + intent.slice(1);\r\n if (Object.hasOwn(bits, intent)) return bits[intent]!;\r\n if (Object.hasOwn(bits, lower)) return bits[lower]!;\r\n const num = Number(intent);\r\n return Number.isNaN(num) ? 0 : num;\r\n}\r\n\r\n/**\r\n * Discord.js-familiar intent bitfield.\r\n * @example new IntentsBitField([IntentsBitField.Flags.Guilds, \"GuildMessages\"])\r\n */\r\nexport class IntentsBitField {\r\n /** Intent flag values by name. */\r\n public static readonly Flags = GatewayIntentBits;\r\n /** Raw intent bitfield. */\r\n public bitfield: number;\r\n\r\n public constructor(bits: GatewayIntentResolvable = 0) {\r\n this.bitfield = resolveGatewayIntents(bits);\r\n }\r\n\r\n /** Whether every given intent is set. */\r\n public has(bits: GatewayIntentResolvable): boolean {\r\n const resolved = resolveGatewayIntents(bits);\r\n return (this.bitfield & resolved) === resolved;\r\n }\r\n\r\n /** Whether any given intent is set. */\r\n public any(bits: GatewayIntentResolvable): boolean {\r\n return (this.bitfield & resolveGatewayIntents(bits)) !== 0;\r\n }\r\n\r\n /** Adds intents in place. @returns This bitfield. */\r\n public add(...bits: GatewayIntentResolvable[]): this {\r\n for (const bit of bits) this.bitfield |= resolveGatewayIntents(bit);\r\n return this;\r\n }\r\n\r\n /** Removes intents in place. @returns This bitfield. */\r\n public remove(...bits: GatewayIntentResolvable[]): this {\r\n for (const bit of bits) this.bitfield &= ~resolveGatewayIntents(bit);\r\n return this;\r\n }\r\n\r\n /** Names of the set intents. */\r\n public toArray(): (keyof typeof GatewayIntentBits)[] {\r\n return (\r\n Object.keys(GatewayIntentBits) as (keyof typeof GatewayIntentBits)[]\r\n ).filter((name) => this.has(GatewayIntentBits[name]));\r\n }\r\n\r\n /** Whether this equals another bitfield. */\r\n public equals(bits: GatewayIntentResolvable): boolean {\r\n return this.bitfield === resolveGatewayIntents(bits);\r\n }\r\n\r\n public valueOf(): number {\r\n return this.bitfield;\r\n }\r\n\r\n public toJSON(): number {\r\n return this.bitfield;\r\n }\r\n}\r\n\r\n// ─── Gateway Config ───────────────────────────────────────────────────────────\r\n\r\n/** Gateway connection properties (OS, browser, device). */\r\nexport interface GatewayProperties {\r\n os?: string;\r\n browser?: string;\r\n device?: string;\r\n [key: string]: string | undefined;\r\n}\r\n/** Gateway presence activity. */\r\nexport interface GatewayPresenceActivity {\r\n name: string;\r\n type?: number;\r\n url?: string;\r\n state?: string;\r\n}\r\n/** Gateway presence data. */\r\nexport interface GatewayPresence {\r\n status?: \"online\" | \"dnd\" | \"idle\" | \"invisible\" | \"offline\";\r\n activities?: GatewayPresenceActivity[];\r\n afk?: boolean;\r\n since?: number | null;\r\n}\r\n/** Client configuration. */\r\nexport interface ClientOptions {\r\n token: string;\r\n intents: GatewayIntentResolvable;\r\n gateway?: GatewayOptions;\r\n rest?: RESTOptions;\r\n /** Opt-in bounded per-channel message cache. Messages are not cached by default. */\r\n messageCache?: { maxSize?: number; ttl?: number };\r\n /**\r\n * Which resources the client keeps from Gateway events. Everything is\r\n * cached by default; large bots can turn off what they do not read.\r\n * Events are still emitted either way.\r\n */\r\n cache?: {\r\n users?: boolean;\r\n members?: boolean;\r\n roles?: boolean;\r\n emojis?: boolean;\r\n };\r\n /**\r\n * Default `allowed_mentions` for every message the client sends (channel\r\n * send/edit, replies, interaction replies, edits and follow-ups), e.g.\r\n * `{ parse: [] }` so nothing pings unless a message says so. A message's\r\n * own `allowed_mentions` always wins.\r\n */\r\n allowedMentions?: AllowedMentions;\r\n}\r\n/** Discord's `allowed_mentions` object. */\r\nexport interface AllowedMentions {\r\n parse?: (\"users\" | \"roles\" | \"everyone\")[];\r\n users?: string[];\r\n roles?: string[];\r\n replied_user?: boolean;\r\n}\r\n/** Gateway connection configuration. */\r\nexport interface GatewayOptions {\r\n intents?: GatewayIntentResolvable;\r\n reconnect?: boolean;\r\n maxReconnectAttempts?: number;\r\n reconnectBaseDelay?: number;\r\n reconnectMaxDelay?: number;\r\n shardId?: number;\r\n shardCount?: number;\r\n properties?: GatewayProperties;\r\n presence?: GatewayPresence;\r\n}\r\n\r\n/** REST request configuration. */\r\nexport interface RESTOptions {\r\n timeout?: number;\r\n retries?: number;\r\n baseURL?: string;\r\n}\r\n",
|
|
9
|
+
"/** Discord API snowflake identifier. */\r\nexport type Snowflake = string;\r\n\r\nexport * from \"./gateway.js\";\r\nexport * from \"./gateway-events.js\";\r\n\r\n// ─── Core Discord Objects ─────────────────────────────────────────────────────\r\n\r\n/** Discord user object. */\r\nexport interface UserData {\r\n id: Snowflake;\r\n username: string;\r\n discriminator?: string;\r\n global_name?: string | null;\r\n avatar?: string | null;\r\n bot?: boolean;\r\n system?: boolean;\r\n public_flags?: number;\r\n}\r\n/** Current authenticated bot user. */\r\nexport type ClientUser = UserData;\r\n/** Discord Gateway payload envelope. */\r\nexport interface GatewayPayload<T = unknown> {\r\n op: number;\r\n d: T | null;\r\n s: number | null;\r\n t: string | null;\r\n}\r\n/** Generic Discord API error payload. */\r\nexport interface APIError {\r\n code?: number;\r\n message?: string;\r\n errors?: Record<string, unknown>;\r\n}\r\n\r\n// ─── Discord Flags & Enums ────────────────────────────────────────────────────\r\n\r\n/** Discord message flags. */\r\nexport const MessageFlags = {\r\n Crossposted: 1,\r\n IsCrosspost: 2,\r\n SuppressEmbeds: 4,\r\n SourceMessageDeleted: 8,\r\n Urgent: 16,\r\n HasThread: 32,\r\n Ephemeral: 64,\r\n Loading: 128,\r\n IsComponentsV2: 32768,\r\n} as const;\r\n/** One {@link MessageFlags} value, usable as a type. */\r\nexport type MessageFlags = (typeof MessageFlags)[keyof typeof MessageFlags];\r\n\r\n/** Discord channel types. */\r\nexport const ChannelEnum = {\r\n GuildText: 0,\r\n DM: 1,\r\n GuildVoice: 2,\r\n GroupDM: 3,\r\n GuildCategory: 4,\r\n GuildAnnouncement: 5,\r\n AnnouncementThread: 10,\r\n PublicThread: 11,\r\n PrivateThread: 12,\r\n GuildStageVoice: 13,\r\n GuildDirectory: 14,\r\n GuildForum: 15,\r\n GuildMedia: 16,\r\n} as const;\r\n/** One {@link ChannelEnum} value, usable as a type. */\r\nexport type ChannelEnum = (typeof ChannelEnum)[keyof typeof ChannelEnum];\r\n\r\n/** Discord component types. */\r\nexport const ComponentEnum = {\r\n ActionRow: 1,\r\n Button: 2,\r\n StringSelect: 3,\r\n TextInput: 4,\r\n UserSelect: 5,\r\n RoleSelect: 6,\r\n MentionableSelect: 7,\r\n ChannelSelect: 8,\r\n Section: 9,\r\n TextDisplay: 10,\r\n Thumbnail: 11,\r\n MediaGallery: 12,\r\n File: 13,\r\n Separator: 14,\r\n ContentInventoryEntry: 16,\r\n Container: 17,\r\n} as const;\r\n/** One {@link ComponentEnum} value, usable as a type. */\r\nexport type ComponentEnum = (typeof ComponentEnum)[keyof typeof ComponentEnum];\r\n\r\n/** Discord button style types. */\r\nexport const ButtonType = {\r\n Primary: 1,\r\n Secondary: 2,\r\n Success: 3,\r\n Danger: 4,\r\n Link: 5,\r\n Premium: 6,\r\n} as const;\r\n/** One {@link ButtonType} value, usable as a type: `style: ButtonType`. */\r\nexport type ButtonType = (typeof ButtonType)[keyof typeof ButtonType];\r\n\r\n/** Discord text input style types. */\r\nexport const TextInputType = {\r\n Short: 1,\r\n Paragraph: 2,\r\n} as const;\r\n/** One {@link TextInputType} value, usable as a type. */\r\nexport type TextInputType = (typeof TextInputType)[keyof typeof TextInputType];\r\n\r\n/** Discord interaction response types. */\r\nexport const InteractionResponseEnum = {\r\n Pong: 1,\r\n ChannelMessage: 4,\r\n DeferredChannelMessage: 5,\r\n DeferredMessageUpdate: 6,\r\n MessageUpdate: 7,\r\n Autocomplete: 8,\r\n Modal: 9,\r\n} as const;\r\n/** One {@link InteractionResponseEnum} value, usable as a type. */\r\nexport type InteractionResponseEnum =\r\n (typeof InteractionResponseEnum)[keyof typeof InteractionResponseEnum];\r\n\r\n/** Discord sticker format types. */\r\nexport const StickerFormatEnum = {\r\n PNG: 1,\r\n APNG: 2,\r\n Lottie: 3,\r\n GIF: 4,\r\n} as const;\r\n/** One {@link StickerFormatEnum} value, usable as a type. */\r\nexport type StickerFormatEnum =\r\n (typeof StickerFormatEnum)[keyof typeof StickerFormatEnum];\r\n\r\n/** Discord sticker types. */\r\nexport const StickerEnum = {\r\n Standard: 1,\r\n Guild: 2,\r\n} as const;\r\n/** One {@link StickerEnum} value, usable as a type. */\r\nexport type StickerEnum = (typeof StickerEnum)[keyof typeof StickerEnum];\r\n\r\n/** Discord verification levels. */\r\nexport const VerificationLevel = {\r\n None: 0,\r\n Low: 1,\r\n Medium: 2,\r\n High: 3,\r\n VeryHigh: 4,\r\n} as const;\r\n\r\n/** Discord premium tiers. */\r\nexport const PremiumTier = {\r\n None: 0,\r\n Tier1: 1,\r\n Tier2: 2,\r\n Tier3: 3,\r\n} as const;\r\n\r\n// ─── Embeds ───────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord embed footer object. */\r\nexport interface APIEmbedFooter {\r\n text: string;\r\n icon_url?: string;\r\n proxy_icon_url?: string;\r\n}\r\n/** Raw Discord embed image/thumbnail/video object. */\r\nexport interface APIEmbedMedia {\r\n url: string;\r\n proxy_url?: string;\r\n height?: number;\r\n width?: number;\r\n}\r\n/** Raw Discord embed provider object. */\r\nexport interface APIEmbedProvider {\r\n name?: string;\r\n url?: string;\r\n}\r\n/** Raw Discord embed author object. */\r\nexport interface APIEmbedAuthor {\r\n name: string;\r\n url?: string;\r\n icon_url?: string;\r\n proxy_icon_url?: string;\r\n}\r\n/** Raw Discord embed field object. */\r\nexport interface APIEmbedField {\r\n name: string;\r\n value: string;\r\n inline?: boolean;\r\n}\r\n/** Raw Discord embed object. */\r\nexport interface APIEmbed {\r\n title?: string;\r\n type?: string;\r\n description?: string;\r\n url?: string;\r\n timestamp?: string;\r\n color?: number;\r\n footer?: APIEmbedFooter;\r\n image?: APIEmbedMedia;\r\n thumbnail?: APIEmbedMedia;\r\n video?: APIEmbedMedia;\r\n provider?: APIEmbedProvider;\r\n author?: APIEmbedAuthor;\r\n fields?: APIEmbedField[];\r\n}\r\n\r\n// ─── Message Components ───────────────────────────────────────────────────────\r\n\r\n/** Raw Discord select menu option. */\r\nexport interface APISelectMenuOption {\r\n label: string;\r\n value: string;\r\n description?: string;\r\n emoji?: APIPartialEmoji;\r\n default?: boolean;\r\n}\r\n/** Raw Discord emoji (partial, as used in components). */\r\nexport interface APIPartialEmoji {\r\n id?: Snowflake | null;\r\n name?: string | null;\r\n animated?: boolean;\r\n}\r\n/** Raw Discord button component. */\r\nexport interface APIButtonComponent {\r\n type: 2;\r\n style: number;\r\n label?: string;\r\n emoji?: APIPartialEmoji;\r\n custom_id?: string;\r\n url?: string;\r\n sku_id?: string;\r\n disabled?: boolean;\r\n}\r\n/** Raw Discord select menu component. */\r\nexport interface APISelectMenuComponent {\r\n type: 3 | 5 | 6 | 7 | 8;\r\n custom_id: string;\r\n options?: APISelectMenuOption[];\r\n channel_types?: number[];\r\n placeholder?: string;\r\n min_values?: number;\r\n max_values?: number;\r\n disabled?: boolean;\r\n}\r\n/** Raw Discord text input component. */\r\nexport interface APITextInputComponent {\r\n type: 4;\r\n custom_id: string;\r\n style: number;\r\n label: string;\r\n min_length?: number;\r\n max_length?: number;\r\n required?: boolean;\r\n value?: string;\r\n placeholder?: string;\r\n}\r\n/** Union of all raw message component types. */\r\nexport type APIMessageActionRowComponent =\r\n APIButtonComponent | APISelectMenuComponent | APITextInputComponent;\r\n/** Raw Discord action row component. */\r\nexport interface APIActionRowComponent {\r\n type: 1;\r\n id?: number;\r\n components: APIMessageActionRowComponent[];\r\n}\r\n/** Union including action rows and V2 components. */\r\nexport type APIMessageComponent =\r\n APIActionRowComponent | { type: Exclude<number, 1>; [key: string]: any };\r\n\r\n// ─── Message payloads ────────────────────────────────────────────────────────\r\n\r\n/** A Discord payload, or a builder that serialises to one (its `toJSON()` runs when the request is sent). */\r\nexport type Buildable<T> = T | { toJSON(): T };\r\n\r\n/**\r\n * A message Lunibee sends: channel send and edit, message reply and edit,\r\n * interaction replies, follow-ups and updates. Embeds and components may be\r\n * builders or raw objects. Other Discord fields pass through unchanged.\r\n */\r\nexport interface MessagePayload {\r\n content?: string;\r\n embeds?: Buildable<APIEmbed>[];\r\n components?: Buildable<APIMessageComponent>[];\r\n allowed_mentions?: import(\"./gateway.js\").AllowedMentions;\r\n /** Discord message flags, e.g. `MessageFlags.SuppressEmbeds`. */\r\n flags?: number;\r\n tts?: boolean;\r\n [key: string]: unknown;\r\n}\r\n\r\n// ─── Attachments ─────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord attachment object. */\r\nexport interface APIAttachment {\r\n id: Snowflake;\r\n filename: string;\r\n description?: string | null;\r\n content_type?: string;\r\n size: number;\r\n url: string;\r\n proxy_url: string;\r\n height?: number | null;\r\n width?: number | null;\r\n ephemeral?: boolean;\r\n duration_secs?: number;\r\n waveform?: string;\r\n flags?: number;\r\n}\r\n\r\n// ─── Stickers ────────────────────────────────────────────────────────────────\r\n\r\n/** Compact sticker item as included in messages. */\r\nexport interface APIStickerItem {\r\n id: Snowflake;\r\n name: string;\r\n format_type: number;\r\n}\r\n/** Full Discord sticker object. */\r\nexport interface APISticker {\r\n id: Snowflake;\r\n pack_id?: Snowflake;\r\n name: string;\r\n description?: string | null;\r\n tags?: string;\r\n type: number;\r\n format_type: number;\r\n available?: boolean;\r\n guild_id?: Snowflake;\r\n user?: UserData;\r\n sort_value?: number;\r\n}\r\n\r\n// ─── Messages ────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord message reference. */\r\nexport interface APIMessageReference {\r\n type?: number;\r\n message_id?: Snowflake;\r\n channel_id?: Snowflake;\r\n guild_id?: Snowflake;\r\n fail_if_not_exists?: boolean;\r\n}\r\n/** Raw Discord message reaction. */\r\nexport interface APIMessageReaction {\r\n count: number;\r\n count_details?: Record<string, number>;\r\n me?: boolean;\r\n me_burst?: boolean;\r\n emoji: APIPartialEmoji;\r\n burst_colors?: string[];\r\n}\r\n/** Raw Discord poll object. */\r\nexport interface APIPoll {\r\n question: { text?: string; emoji?: APIPartialEmoji };\r\n answers: Array<{\r\n answer_id: number;\r\n poll_media: { text?: string; emoji?: APIPartialEmoji };\r\n }>;\r\n expiry: string | null;\r\n allow_multiselect: boolean;\r\n layout_type: number;\r\n results?: {\r\n is_finalized: boolean;\r\n answer_counts: Array<{ id: number; count: number; me_voted: boolean }>;\r\n };\r\n}\r\n/** A forwarded message's snapshot of the original. */\r\nexport interface APIMessageSnapshot {\r\n message: Partial<\r\n Pick<\r\n APIMessage,\r\n | \"type\"\r\n | \"content\"\r\n | \"embeds\"\r\n | \"attachments\"\r\n | \"timestamp\"\r\n | \"edited_timestamp\"\r\n | \"flags\"\r\n | \"mentions\"\r\n | \"mention_roles\"\r\n | \"sticker_items\"\r\n | \"components\"\r\n >\r\n >;\r\n}\r\n/** Raw Discord message object. */\r\nexport interface APIMessage {\r\n id: Snowflake;\r\n channel_id: Snowflake;\r\n author: UserData;\r\n content: string;\r\n timestamp?: string;\r\n edited_timestamp?: string | null;\r\n tts?: boolean;\r\n mention_everyone?: boolean;\r\n mentions?: UserData[];\r\n mention_roles?: Snowflake[];\r\n mention_channels?: Array<Record<string, unknown>>;\r\n attachments?: APIAttachment[];\r\n embeds?: APIEmbed[];\r\n reactions?: APIMessageReaction[];\r\n nonce?: string | number | null;\r\n pinned?: boolean;\r\n webhook_id?: Snowflake;\r\n type?: number;\r\n activity?: Record<string, unknown>;\r\n application?: Record<string, unknown>;\r\n application_id?: Snowflake;\r\n message_reference?: APIMessageReference;\r\n flags?: number;\r\n referenced_message?: APIMessage | null;\r\n interaction_metadata?: Record<string, unknown>;\r\n thread?: Record<string, unknown>;\r\n components?: APIMessageComponent[];\r\n sticker_items?: APIStickerItem[];\r\n stickers?: APISticker[];\r\n position?: number;\r\n role_subscription_data?: Record<string, unknown>;\r\n purchase_notification?: Record<string, unknown>;\r\n poll?: APIPoll;\r\n /** Forwarded messages: a partial copy of the original (content, embeds, attachments, …). */\r\n message_snapshots?: APIMessageSnapshot[];\r\n guild_id?: Snowflake;\r\n /** The author's guild member, on guild messages from the Gateway (without `user`; the author is the user). */\r\n member?: Omit<APIGuildMember, \"user\"> & { user?: UserData };\r\n}\r\n\r\n// ─── Channels ────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord channel object. */\r\nexport interface APIChannel {\r\n id: Snowflake;\r\n type: number;\r\n guild_id?: Snowflake;\r\n position?: number;\r\n permission_overwrites?: APIOverwrite[];\r\n name?: string | null;\r\n topic?: string | null;\r\n nsfw?: boolean;\r\n last_message_id?: Snowflake | null;\r\n bitrate?: number;\r\n user_limit?: number;\r\n rate_limit_per_user?: number;\r\n recipients?: UserData[];\r\n icon?: string | null;\r\n owner_id?: Snowflake;\r\n application_id?: Snowflake;\r\n parent_id?: Snowflake | null;\r\n last_pin_timestamp?: string | null;\r\n rtc_region?: string | null;\r\n video_quality_mode?: number;\r\n message_count?: number;\r\n member_count?: number;\r\n thread_metadata?: APIThreadMetadata;\r\n default_auto_archive_duration?: number;\r\n flags?: number;\r\n total_message_sent?: number;\r\n available_tags?: APIForumTag[];\r\n default_reaction_emoji?: APIPartialEmoji | null;\r\n default_thread_rate_limit_per_user?: number;\r\n default_sort_order?: number | null;\r\n default_forum_layout?: number;\r\n}\r\n\r\n/** Raw Discord thread metadata. */\r\nexport interface APIThreadMetadata {\r\n archived: boolean;\r\n auto_archive_duration: number;\r\n archive_timestamp: string;\r\n locked: boolean;\r\n invitable?: boolean;\r\n create_timestamp?: string | null;\r\n}\r\n\r\n/** Raw Discord forum tag. */\r\nexport interface APIForumTag {\r\n id: Snowflake;\r\n name: string;\r\n moderated: boolean;\r\n emoji_id?: Snowflake | null;\r\n emoji_name?: string | null;\r\n}\r\n\r\n/** Raw Discord thread member. */\r\nexport interface APIThreadMember {\r\n id?: Snowflake;\r\n user_id?: Snowflake;\r\n join_timestamp: string;\r\n flags: number;\r\n member?: APIGuildMember;\r\n}\r\n\r\n// ─── Roles ────────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord role object. */\r\nexport interface APIRole {\r\n id: Snowflake;\r\n name: string;\r\n color: number;\r\n hoist: boolean;\r\n icon?: string | null;\r\n unicode_emoji?: string | null;\r\n position: number;\r\n permissions: string;\r\n managed: boolean;\r\n mentionable: boolean;\r\n tags?: Record<string, unknown>;\r\n flags?: number;\r\n}\r\n\r\n// ─── Emoji ────────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord emoji object. */\r\nexport interface APIEmoji {\r\n id: Snowflake | null;\r\n name: string | null;\r\n roles?: Snowflake[];\r\n user?: UserData;\r\n require_colons?: boolean;\r\n managed?: boolean;\r\n animated?: boolean;\r\n available?: boolean;\r\n}\r\n\r\n// ─── Guilds ───────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord guild object. */\r\nexport interface APIGuild {\r\n id: Snowflake;\r\n name: string;\r\n icon?: string | null;\r\n icon_hash?: string | null;\r\n splash?: string | null;\r\n discovery_splash?: string | null;\r\n owner?: boolean;\r\n owner_id?: Snowflake;\r\n permissions?: string;\r\n afk_channel_id?: Snowflake | null;\r\n afk_timeout?: number;\r\n widget_enabled?: boolean;\r\n widget_channel_id?: Snowflake | null;\r\n verification_level?: number;\r\n default_message_notifications?: number;\r\n explicit_content_filter?: number;\r\n roles?: APIRole[];\r\n emojis?: APIEmoji[];\r\n stickers?: APISticker[];\r\n features?: string[];\r\n mfa_level?: number;\r\n application_id?: Snowflake | null;\r\n system_channel_id?: Snowflake | null;\r\n system_channel_flags?: number;\r\n rules_channel_id?: Snowflake | null;\r\n max_presences?: number | null;\r\n max_members?: number;\r\n vanity_url_code?: string | null;\r\n description?: string | null;\r\n banner?: string | null;\r\n premium_tier?: number;\r\n premium_subscription_count?: number;\r\n preferred_locale?: string;\r\n public_updates_channel_id?: Snowflake | null;\r\n max_video_channel_users?: number;\r\n approximate_member_count?: number;\r\n approximate_presence_count?: number;\r\n nsfw_level?: number;\r\n safety_alerts_channel_id?: Snowflake | null;\r\n member_count?: number;\r\n}\r\n\r\n// ─── Welcome Screen ───────────────────────────────────────────────────────────\r\n\r\nexport interface APIWelcomeScreenChannel {\r\n channel_id: Snowflake;\r\n description: string;\r\n emoji_id: Snowflake | null;\r\n emoji_name: string | null;\r\n}\r\n\r\nexport interface APIGuildWelcomeScreen {\r\n description: string | null;\r\n welcome_channels: APIWelcomeScreenChannel[];\r\n}\r\n\r\n// ─── Guild Onboarding ─────────────────────────────────────────────────────────\r\n\r\nexport interface APIOnboardingPromptOption {\r\n id: Snowflake;\r\n channel_ids: Snowflake[];\r\n role_ids: Snowflake[];\r\n emoji?: APIPartialEmoji;\r\n title: string;\r\n description: string | null;\r\n}\r\n\r\nexport interface APIOnboardingPrompt {\r\n id: Snowflake;\r\n type: number;\r\n options: APIOnboardingPromptOption[];\r\n title: string;\r\n single_select: boolean;\r\n required: boolean;\r\n in_onboarding: boolean;\r\n}\r\n\r\nexport interface APIGuildOnboarding {\r\n guild_id: Snowflake;\r\n prompts: APIOnboardingPrompt[];\r\n default_channel_ids: Snowflake[];\r\n enabled: boolean;\r\n mode: number;\r\n}\r\n\r\n/** Raw Discord guild member object. */\r\nexport interface APIGuildMember {\r\n user: UserData;\r\n nick?: string | null;\r\n avatar?: string | null;\r\n roles: Snowflake[];\r\n joined_at: string;\r\n premium_since?: string | null;\r\n deaf?: boolean;\r\n mute?: boolean;\r\n flags?: number;\r\n pending?: boolean;\r\n permissions?: string;\r\n communication_disabled_until?: string | null;\r\n guild_id?: Snowflake;\r\n}\r\n\r\n// ─── Voice ────────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord voice state object. */\r\nexport interface APIVoiceState {\r\n guild_id?: Snowflake;\r\n channel_id?: Snowflake | null;\r\n user_id: Snowflake;\r\n member?: APIGuildMember;\r\n session_id: string;\r\n deaf: boolean;\r\n mute: boolean;\r\n self_deaf: boolean;\r\n self_mute: boolean;\r\n self_stream?: boolean;\r\n self_video: boolean;\r\n suppress: boolean;\r\n request_to_speak_timestamp?: string | null;\r\n}\r\n\r\n/** Raw Discord voice server update event. */\r\nexport interface APIVoiceServerUpdate {\r\n token: string;\r\n guild_id: Snowflake;\r\n endpoint?: string | null;\r\n}\r\n\r\n// ─── Presence ────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord activity object. */\r\n/** Discord activity types, for presences (`setPresence({ activities: [{ name, type: ActivityEnum.Watching }] })`). */\r\nexport const ActivityEnum = {\r\n Playing: 0,\r\n Streaming: 1,\r\n Listening: 2,\r\n Watching: 3,\r\n Custom: 4,\r\n Competing: 5,\r\n} as const;\r\n/** One {@link ActivityEnum} value, usable as a type. */\r\nexport type ActivityEnum = (typeof ActivityEnum)[keyof typeof ActivityEnum];\r\n\r\nexport interface APIActivity {\r\n name: string;\r\n type: number;\r\n url?: string | null;\r\n created_at: number;\r\n state?: string | null;\r\n details?: string | null;\r\n emoji?: APIPartialEmoji | null;\r\n}\r\n\r\n/** Raw Discord presence update event. */\r\nexport interface APIPresenceUpdate {\r\n user: { id: Snowflake } & Partial<UserData>;\r\n guild_id: Snowflake;\r\n status: string;\r\n activities: APIActivity[];\r\n client_status: { desktop?: string; mobile?: string; web?: string };\r\n}\r\n\r\n// ─── Typing ───────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord typing start event. */\r\nexport interface APITypingStart {\r\n channel_id: Snowflake;\r\n guild_id?: Snowflake;\r\n user_id: Snowflake;\r\n timestamp: number;\r\n member?: APIGuildMember;\r\n}\r\n\r\n// ─── Guilds ──────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord guild preview. */\r\nexport interface APIGuildPreview {\r\n id: Snowflake;\r\n name: string;\r\n icon: string | null;\r\n splash: string | null;\r\n discovery_splash: string | null;\r\n emojis: unknown[];\r\n features: string[];\r\n approximate_member_count: number;\r\n approximate_presence_count: number;\r\n description: string | null;\r\n stickers: unknown[];\r\n}\r\n\r\n// ─── Invites ─────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord invite. */\r\nexport interface APIInvite {\r\n code: string;\r\n guild?: Partial<APIGuild>;\r\n channel: Partial<APIChannel>;\r\n inviter?: UserData;\r\n target_type?: number;\r\n target_user?: UserData;\r\n approximate_presence_count?: number;\r\n approximate_member_count?: number;\r\n}\r\n\r\n/** Raw Discord invite create event. */\r\nexport interface APIInviteCreate {\r\n channel_id: Snowflake;\r\n code: string;\r\n created_at: string;\r\n guild_id?: Snowflake;\r\n inviter?: UserData;\r\n max_age: number;\r\n max_uses: number;\r\n target_type?: number;\r\n target_user?: UserData;\r\n temporary: boolean;\r\n uses: number;\r\n}\r\n\r\n/** Raw Discord invite delete event. */\r\nexport interface APIInviteDelete {\r\n channel_id: Snowflake;\r\n guild_id?: Snowflake;\r\n code: string;\r\n}\r\n\r\n// ─── Webhooks ────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord webhooks update event. */\r\nexport interface APIWebhooksUpdate {\r\n guild_id: Snowflake;\r\n channel_id: Snowflake;\r\n}\r\n\r\n/** Raw Discord webhook object. */\r\nexport interface APIWebhook {\r\n id: Snowflake;\r\n type: number;\r\n guild_id?: Snowflake | null;\r\n channel_id?: Snowflake | null;\r\n user?: UserData;\r\n name?: string | null;\r\n avatar?: string | null;\r\n token?: string;\r\n application_id?: Snowflake | null;\r\n url?: string;\r\n}\r\n\r\n// ─── AutoMod ─────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord AutoMod action. */\r\nexport interface APIAutoModerationAction {\r\n type: number;\r\n metadata?: {\r\n channel_id?: Snowflake;\r\n duration_seconds?: number;\r\n custom_message?: string;\r\n };\r\n}\r\n\r\n// ─── Audit Logs ──────────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord audit log change object. */\r\nexport interface APIAuditLogChange {\r\n new_value?: unknown;\r\n old_value?: unknown;\r\n key: string;\r\n}\r\n\r\n/** Raw Discord audit log entry options object. */\r\nexport interface APIAuditLogOptions {\r\n app_id?: Snowflake;\r\n auto_moderation_rule_name?: string;\r\n auto_moderation_rule_trigger_type?: string;\r\n channel_id?: Snowflake;\r\n count?: string;\r\n delete_member_days?: string;\r\n id?: Snowflake;\r\n members_removed?: string;\r\n message_id?: Snowflake;\r\n role_name?: string;\r\n type?: string;\r\n integration_type?: string;\r\n}\r\n\r\n/** Raw Discord audit log entry object. */\r\nexport interface APIAuditLogEntry {\r\n target_id: string | null;\r\n changes?: APIAuditLogChange[];\r\n user_id: Snowflake | null;\r\n id: Snowflake;\r\n action_type: number;\r\n options?: APIAuditLogOptions;\r\n reason?: string;\r\n}\r\n\r\n/** Raw Discord audit log object. */\r\nexport interface APIAuditLog {\r\n audit_log_entries: APIAuditLogEntry[];\r\n guild_scheduled_events: APIGuildScheduledEvent[];\r\n integrations: Array<Record<string, unknown>>;\r\n threads: APIChannel[];\r\n users: UserData[];\r\n webhooks: APIWebhook[];\r\n application_commands: APIApplicationCommand[];\r\n auto_moderation_rules: APIAutoModerationRule[];\r\n}\r\n\r\n/** Raw Discord AutoMod rule object. */\r\nexport interface APIAutoModerationRule {\r\n id: Snowflake;\r\n guild_id: Snowflake;\r\n name: string;\r\n creator_id: Snowflake;\r\n event_type: number;\r\n trigger_type: number;\r\n trigger_metadata: Record<string, unknown>;\r\n actions: APIAutoModerationAction[];\r\n enabled: boolean;\r\n exempt_roles: Snowflake[];\r\n exempt_channels: Snowflake[];\r\n}\r\n\r\n/** Raw Discord AutoMod action execution event. */\r\nexport interface APIAutoModerationActionExecution {\r\n guild_id: Snowflake;\r\n action: APIAutoModerationAction;\r\n rule_id: Snowflake;\r\n rule_trigger_type: number;\r\n user_id: Snowflake;\r\n channel_id?: Snowflake;\r\n message_id?: Snowflake;\r\n alert_system_message_id?: Snowflake;\r\n content: string;\r\n matched_keyword?: string | null;\r\n matched_content?: string | null;\r\n}\r\n\r\n// ─── Scheduled Events ─────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord guild scheduled event entity metadata. */\r\nexport interface APIGuildScheduledEventEntityMetadata {\r\n location?: string;\r\n}\r\n\r\n/** Raw Discord guild scheduled event object. */\r\nexport interface APIGuildScheduledEvent {\r\n id: Snowflake;\r\n guild_id: Snowflake;\r\n channel_id?: Snowflake | null;\r\n creator_id?: Snowflake | null;\r\n name: string;\r\n description?: string | null;\r\n scheduled_start_time: string;\r\n scheduled_end_time?: string | null;\r\n privacy_level: number;\r\n status: number;\r\n entity_type: number;\r\n entity_id?: Snowflake | null;\r\n entity_metadata?: APIGuildScheduledEventEntityMetadata | null;\r\n creator?: UserData;\r\n user_count?: number;\r\n image?: string | null;\r\n}\r\n\r\n// ─── Stage Instances ─────────────────────────────────────────────────────────\r\n\r\n/** Raw Discord stage instance object. */\r\nexport interface APIStageInstance {\r\n id: Snowflake;\r\n guild_id: Snowflake;\r\n channel_id: Snowflake;\r\n topic: string;\r\n privacy_level: number;\r\n discoverable_disabled?: boolean;\r\n guild_scheduled_event_id?: Snowflake | null;\r\n}\r\n\r\n// ─── Application Commands ─────────────────────────────────────────────────────\r\n\r\n/** Discord application command option types. */\r\nexport const ApplicationCommandOptionEnum = {\r\n SubCommand: 1,\r\n SubCommandGroup: 2,\r\n String: 3,\r\n Integer: 4,\r\n Boolean: 5,\r\n User: 6,\r\n Channel: 7,\r\n Role: 8,\r\n Mentionable: 9,\r\n Number: 10,\r\n Attachment: 11,\r\n} as const;\r\n/** One {@link ApplicationCommandOptionEnum} value, usable as a type. */\r\nexport type ApplicationCommandOptionEnum =\r\n (typeof ApplicationCommandOptionEnum)[keyof typeof ApplicationCommandOptionEnum];\r\n\r\n/** Discord application command types. */\r\nexport const ApplicationCommandEnum = {\r\n ChatInput: 1,\r\n User: 2,\r\n Message: 3,\r\n} as const;\r\n/** One {@link ApplicationCommandEnum} value, usable as a type. */\r\nexport type ApplicationCommandEnum =\r\n (typeof ApplicationCommandEnum)[keyof typeof ApplicationCommandEnum];\r\n\r\n/** Raw Discord application command option. */\r\nexport interface APIApplicationCommandOption {\r\n type: number;\r\n name: string;\r\n description: string;\r\n required?: boolean;\r\n choices?: Array<{ name: string; value: string | number }>;\r\n options?: APIApplicationCommandOption[];\r\n min_value?: number;\r\n max_value?: number;\r\n min_length?: number;\r\n max_length?: number;\r\n autocomplete?: boolean;\r\n channel_types?: number[];\r\n}\r\n\r\n/** Raw Discord application command object (from API). */\r\nexport interface APIApplicationCommand {\r\n id: Snowflake;\r\n type?: number;\r\n application_id: Snowflake;\r\n guild_id?: Snowflake;\r\n name: string;\r\n description: string;\r\n options?: APIApplicationCommandOption[];\r\n default_member_permissions?: string | null;\r\n /** @deprecated Discord deprecated this field. Use `contexts`. Removed in 0.3.0. */\r\n dm_permission?: boolean;\r\n /** Where the command can be used: 0 guilds, 1 the bot's DMs, 2 other DMs. */\r\n contexts?: number[];\r\n nsfw?: boolean;\r\n version: Snowflake;\r\n}\r\n\r\n/** Data for creating/overwriting an application command. */\r\nexport interface ApplicationCommandData {\r\n name: string;\r\n description: string;\r\n type?: number;\r\n options?: APIApplicationCommandOption[];\r\n default_member_permissions?: string | null;\r\n /** @deprecated Discord deprecated this field. Use `contexts`. Removed in 0.3.0. */\r\n dm_permission?: boolean;\r\n /** Where the command can be used: 0 guilds, 1 the bot's DMs, 2 other DMs. */\r\n contexts?: number[];\r\n nsfw?: boolean;\r\n}\r\n\r\n/** A channel permission overwrite for a role (type 0) or member (type 1). */\r\nexport interface APIOverwrite {\r\n id: Snowflake;\r\n type: 0 | 1;\r\n /** Allowed permission bits as a decimal string. */\r\n allow: string;\r\n /** Denied permission bits as a decimal string. */\r\n deny: string;\r\n}\r\n\r\n// ─── Soundboard & Monetization ───────────────────────────────────────────────\r\n/** Raw Discord soundboard sound. */\r\nexport interface APISoundboardSound {\r\n sound_id: string;\r\n name: string;\r\n volume: number;\r\n emoji_id: string | null;\r\n emoji_name: string | null;\r\n guild_id?: string;\r\n available: boolean;\r\n user?: UserData;\r\n}\r\n\r\n/** Raw Discord SKU. */\r\nexport interface APISKU {\r\n id: string;\r\n type: number;\r\n application_id: string;\r\n name: string;\r\n slug: string;\r\n flags: number;\r\n}\r\n\r\n/** Raw Discord entitlement. */\r\nexport interface APIEntitlement {\r\n id: string;\r\n sku_id: string;\r\n application_id: string;\r\n user_id?: string;\r\n guild_id?: string;\r\n type: number;\r\n deleted: boolean;\r\n starts_at?: string | null;\r\n ends_at?: string | null;\r\n consumed?: boolean;\r\n}\r\n\r\n/** Raw Discord subscription. */\r\nexport interface APISubscription {\r\n id: string;\r\n user_id: string;\r\n sku_ids: string[];\r\n entitlement_ids: string[];\r\n current_period_start: string;\r\n current_period_end: string;\r\n status: number;\r\n canceled_at: string | null;\r\n country?: string;\r\n}\r\n\r\n// ─── Deprecated names (0.2.2) ────────────────────────────────────────────────\r\n// Kept so existing bots keep working; removed in 0.3.0. `…Style` became `…Type`\r\n// and `…Type` became `…Enum`.\r\n\r\n/** @deprecated Use {@link ButtonType}. Removed in 0.3.0. */\r\nexport const ButtonStyle = ButtonType;\r\n/** @deprecated Use {@link ButtonType}. Removed in 0.3.0. */\r\nexport type ButtonStyle = ButtonType;\r\n/** @deprecated Use {@link TextInputType}. Removed in 0.3.0. */\r\nexport const TextInputStyle = TextInputType;\r\n/** @deprecated Use {@link TextInputType}. Removed in 0.3.0. */\r\nexport type TextInputStyle = TextInputType;\r\n/** @deprecated Use {@link ChannelEnum}. Removed in 0.3.0. */\r\nexport const ChannelType = ChannelEnum;\r\n/** @deprecated Use {@link ChannelEnum}. Removed in 0.3.0. */\r\nexport type ChannelType = ChannelEnum;\r\n/** @deprecated Use {@link ComponentEnum}. Removed in 0.3.0. */\r\nexport const ComponentType = ComponentEnum;\r\n/** @deprecated Use {@link ComponentEnum}. Removed in 0.3.0. */\r\nexport type ComponentType = ComponentEnum;\r\n/** @deprecated Use {@link InteractionResponseEnum}. Removed in 0.3.0. */\r\nexport const InteractionResponseType = InteractionResponseEnum;\r\n/** @deprecated Use {@link InteractionResponseEnum}. Removed in 0.3.0. */\r\nexport type InteractionResponseType = InteractionResponseEnum;\r\n/** @deprecated Use {@link ApplicationCommandEnum}. Removed in 0.3.0. */\r\nexport const ApplicationCommandType = ApplicationCommandEnum;\r\n/** @deprecated Use {@link ApplicationCommandEnum}. Removed in 0.3.0. */\r\nexport type ApplicationCommandType = ApplicationCommandEnum;\r\n/** @deprecated Use {@link ApplicationCommandOptionEnum}. Removed in 0.3.0. */\r\nexport const ApplicationCommandOptionType = ApplicationCommandOptionEnum;\r\n/** @deprecated Use {@link ApplicationCommandOptionEnum}. Removed in 0.3.0. */\r\nexport type ApplicationCommandOptionType = ApplicationCommandOptionEnum;\r\n/** @deprecated Use {@link StickerEnum}. Removed in 0.3.0. */\r\nexport const StickerType = StickerEnum;\r\n/** @deprecated Use {@link StickerEnum}. Removed in 0.3.0. */\r\nexport type StickerType = StickerEnum;\r\n/** @deprecated Use {@link StickerFormatEnum}. Removed in 0.3.0. */\r\nexport const StickerFormatType = StickerFormatEnum;\r\n/** @deprecated Use {@link StickerFormatEnum}. Removed in 0.3.0. */\r\nexport type StickerFormatType = StickerFormatEnum;\r\n",
|
|
10
|
+
"/** Retention policy for a {@link Collection}. */\r\nexport interface CollectionOptions<K = unknown, V = unknown> {\r\n /** Default sliding TTL in ms for `set()`. Omit for no expiry. */\r\n ttl?: number;\r\n /** Maximum entries stored with `set()`; least-recently-used are evicted past it. `setWithoutTTL()` entries are never counted or evicted. */\r\n maxSize?: number;\r\n /** Whether a read restarts a TTL entry's window. Default `true`; with `false` an entry lapses a fixed time after it was set, and reads only mark it recently used. */\r\n slide?: boolean;\r\n /** Called after an entry is removed automatically, with why. Exceptions are swallowed. */\r\n onEvict?: (key: K, value: V, reason: EvictionReason) => void;\r\n}\r\n\r\n/** Why an entry was removed automatically. */\r\nexport type EvictionReason = \"expired\" | \"evicted\";\r\n\r\n/** Cumulative counters from {@link Collection.stats}. */\r\nexport interface CollectionStats {\r\n /** `get`/`peek` calls that found a value. */\r\n hits: number;\r\n /** `get`/`peek` calls that found nothing. */\r\n misses: number;\r\n /** Entries removed because their TTL lapsed. */\r\n expired: number;\r\n /** Entries removed to stay within `maxSize`. */\r\n evicted: number;\r\n}\r\n\r\n/**\r\n * Everything the policy knows about one key: its place in the recency list\r\n * and its TTL. One record serves the policy map, the recency list and the\r\n * expiry heap, so a write touches one extra hash entry and allocates once.\r\n */\r\ntype Entry<K, V> = {\r\n key: K;\r\n /** A copy of the stored value, so a read needs one lookup instead of two. */\r\n value: V;\r\n /** Neighbours in recency order; meaningful while `inLru`. */\r\n older: Entry<K, V> | undefined;\r\n newer: Entry<K, V> | undefined;\r\n inLru: boolean;\r\n /** TTL window in ms; 0 when the entry does not expire (and is not in the heap). */\r\n window: number;\r\n /** The current deadline; a read moves it later without touching the heap. */\r\n deadline: number;\r\n /** The deadline the heap ordered this record by. */\r\n filed: number;\r\n};\r\n\r\n/**\r\n * Everything a retention policy needs. A Collection without `ttl` or\r\n * `maxSize` never creates one, so plain collections cost no more than a Map.\r\n */\r\ntype Policy<K, V> = {\r\n /** Keys with a TTL or a recency position; `setWithoutTTL()` keys are absent. */\r\n entries: Map<K, Entry<K, V>>;\r\n /** Oldest and newest entries of the recency list; only `maxSize` collections use it. */\r\n oldest: Entry<K, V> | undefined;\r\n newest: Entry<K, V> | undefined;\r\n lruSize: number;\r\n /** Min-heap by `filed`. A record that is no longer its key's map value is stale and dropped lazily. */\r\n heap: Entry<K, V>[];\r\n timer?: ReturnType<typeof setTimeout>;\r\n armedFor: number;\r\n /** The options, kept here so a plain collection carries none of them. */\r\n ttl: number | undefined;\r\n maxSize: number | undefined;\r\n slide: boolean;\r\n /** Stored loosely typed so the callback does not make Collection invariant in K and V. */\r\n onEvict:\r\n | ((key: unknown, value: unknown, reason: EvictionReason) => void)\r\n | undefined;\r\n expired: number;\r\n evicted: number;\r\n};\r\n\r\nfunction newPolicy<K, V>(options: CollectionOptions<K, V> = {}): Policy<K, V> {\r\n return {\r\n ttl: options.ttl,\r\n maxSize: options.maxSize,\r\n slide: options.slide ?? true,\r\n onEvict: options.onEvict as Policy<K, V>[\"onEvict\"],\r\n expired: 0,\r\n evicted: 0,\r\n entries: new Map(),\r\n oldest: undefined,\r\n newest: undefined,\r\n lruSize: 0,\r\n heap: [],\r\n armedFor: Infinity,\r\n };\r\n}\r\n\r\n/**\r\n * Reads a value that `has()` just confirmed, without touching a Lunibee\r\n * collection's TTL, recency or hit counters.\r\n */\r\nfunction peekOf<K, V>(\r\n collection: ReadonlyCollection<K, V>,\r\n key: K,\r\n): V | undefined {\r\n return collection instanceof Map\r\n ? (Map.prototype.get.call(collection, key) as V | undefined)\r\n : collection.get(key);\r\n}\r\n\r\n/** What `merge()` does with one entry: keep it with `value`, or drop it. */\r\nexport type Keep<V> = { keep: true; value: V } | { keep: false };\r\n\r\n/**\r\n * A `Collection` seen read-only: every method that does not change it. Pass it\r\n * where you only read, so a function cannot add to or remove from the cache.\r\n */\r\nexport type ReadonlyCollection<K, V> = Omit<\r\n Collection<K, V>,\r\n | \"set\"\r\n | \"setWithoutTTL\"\r\n | \"delete\"\r\n | \"clear\"\r\n | \"ensure\"\r\n | \"forEach\"\r\n | \"get\"\r\n | \"sweep\"\r\n | \"purge\"\r\n> &\r\n ReadonlyMap<K, V>;\r\n\r\nconst mapGet = Map.prototype.get as (\r\n this: Map<unknown, unknown>,\r\n key: unknown,\r\n) => unknown;\r\nconst mapHas = Map.prototype.has as (\r\n this: Map<unknown, unknown>,\r\n key: unknown,\r\n) => boolean;\r\n\r\n/** Picks `amount` different items at random (a partial Fisher-Yates shuffle of `items`). */\r\nfunction sample<T>(items: T[], amount: number): T[] {\r\n if (!Number.isInteger(amount) || amount < 0)\r\n throw new RangeError(\"amount must be a non-negative integer.\");\r\n const count = Math.min(amount, items.length);\r\n for (let i = 0; i < count; i++) {\r\n const j = i + Math.floor(Math.random() * (items.length - i));\r\n [items[i], items[j]] = [items[j]!, items[i]!];\r\n }\r\n items.length = count;\r\n return items;\r\n}\r\n\r\nfunction assertTTL(ttl: number | undefined): void {\r\n if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))\r\n throw new RangeError(\"TTL must be a positive number, or omitted.\");\r\n}\r\n\r\n/**\r\n * A keyed collection for Lunibee resource and application state.\r\n *\r\n * - `set(key, value, ttl?)` is TTL/LRU-aware: with a TTL (the default from\r\n * options, or per call) the entry expires after that window of inactivity,\r\n * and with `maxSize` it counts toward the cap.\r\n * - `setWithoutTTL(key, value)` never expires: no deadline, no heap record,\r\n * no timer, and exempt from `maxSize` eviction. Resource managers store\r\n * Discord state this way, so it leaves only through an explicit delete.\r\n *\r\n * Without options, a Collection behaves like a plain Map.\r\n */\r\nexport class Collection<K, V> extends Map<K, V> {\r\n /** Created with any option, or by the first `set()` with its own TTL. */\r\n #policy?: Policy<K, V>;\r\n #hits = 0;\r\n #misses = 0;\r\n\r\n /**\r\n * @param entries Initial entries, stored with `set()`.\r\n * @param options TTL and size policy.\r\n * @throws {RangeError} On a non-positive TTL or non-integer `maxSize`.\r\n */\r\n public constructor(\r\n entries?: Iterable<readonly [K, V]> | null,\r\n options: CollectionOptions<K, V> = {},\r\n ) {\r\n super();\r\n assertTTL(options.ttl);\r\n if (\r\n options.maxSize !== undefined &&\r\n (!Number.isInteger(options.maxSize) || options.maxSize <= 0)\r\n )\r\n throw new RangeError(\"maxSize must be a positive integer.\");\r\n if (\r\n options.ttl !== undefined ||\r\n options.maxSize !== undefined ||\r\n options.slide !== undefined ||\r\n options.onEvict !== undefined\r\n )\r\n this.#policy = newPolicy(options);\r\n if (entries) for (const [key, value] of entries) this.set(key, value);\r\n }\r\n\r\n /**\r\n * Stores an entry with the default TTL (or `ttl`), marks it most recently\r\n * used, and enforces `maxSize`. Turns a `setWithoutTTL()` entry back into\r\n * a TTL/LRU entry.\r\n */\r\n public override set(key: K, value: V, ttl?: number): this {\r\n if (ttl === undefined && this.#policy === undefined)\r\n return super.set(key, value);\r\n assertTTL(ttl);\r\n const window = ttl ?? this.#policy?.ttl;\r\n if (window !== undefined) this.#policy ??= newPolicy();\r\n if (!this.#policy) return super.set(key, value);\r\n // A key that was not stored before has no policy entry.\r\n const before = super.size;\r\n super.set(key, value);\r\n this.#track(key, value, window, super.size !== before);\r\n this.#enforceCap();\r\n return this;\r\n }\r\n\r\n /**\r\n * Stores an entry that never expires: no deadline, heap record, timer or\r\n * LRU eviction. It leaves only through `delete`, `sweep`, `clear`, or a\r\n * later `set()`.\r\n */\r\n public setWithoutTTL(key: K, value: V): this {\r\n if (this.#policy) this.#forget(key);\r\n super.set(key, value);\r\n return this;\r\n }\r\n\r\n /** Reads a value; restarts a TTL entry's window and promotes it. */\r\n public override get(key: K): V | undefined {\r\n const policy = this.#policy;\r\n const entry = policy?.entries.get(key);\r\n if (entry === undefined) {\r\n const value = mapGet.call(this, key) as V | undefined;\r\n if (value !== undefined || mapHas.call(this, key)) {\r\n this.#hits++;\r\n return value;\r\n }\r\n this.#misses++;\r\n return undefined;\r\n }\r\n const timed = entry.window !== 0;\r\n const now = timed ? Date.now() : 0;\r\n if (timed && entry.deadline <= now) {\r\n this.#expire(entry);\r\n this.#misses++;\r\n return undefined;\r\n }\r\n this.#hits++;\r\n if (timed && policy!.slide) entry.deadline = now + entry.window;\r\n if (entry.inLru) this.#promote(policy!, entry);\r\n return entry.value;\r\n }\r\n\r\n /**\r\n * Returns the value for `key`, or stores and returns what `factory`\r\n * makes. Reading counts as a `get()` (restarts the TTL, marks it recently\r\n * used); creating stores with `set()`, so `ttl` applies.\r\n * @param factory Called with the key and this collection only when the key is missing; if it throws, nothing is stored.\r\n * @param ttl TTL in ms for a created entry; defaults to the collection's.\r\n */\r\n public ensure(\r\n key: K,\r\n factory: (key: K, collection: this) => V,\r\n ttl?: number,\r\n ): V {\r\n const existing = this.get(key);\r\n if (existing !== undefined || super.has(key)) return existing as V;\r\n const created = factory(key, this);\r\n this.set(key, created, ttl);\r\n return created;\r\n }\r\n\r\n /** Reads a value without restarting its TTL or promoting it. */\r\n public peek(key: K): V | undefined {\r\n if (!this.#expireIfDue(key) && super.has(key)) {\r\n this.#hits++;\r\n return super.get(key);\r\n }\r\n this.#misses++;\r\n return undefined;\r\n }\r\n\r\n /** Cumulative hit, miss, expiry and eviction counters (a copy). */\r\n public get stats(): CollectionStats {\r\n return {\r\n hits: this.#hits,\r\n misses: this.#misses,\r\n expired: this.#policy?.expired ?? 0,\r\n evicted: this.#policy?.evicted ?? 0,\r\n };\r\n }\r\n\r\n public override has(key: K): boolean {\r\n return !this.#expireIfDue(key) && super.has(key);\r\n }\r\n\r\n public override delete(key: K): boolean {\r\n if (this.#expireIfDue(key)) return false;\r\n if (this.#policy) this.#forget(key);\r\n return super.delete(key);\r\n }\r\n\r\n public override clear(): void {\r\n super.clear();\r\n const policy = this.#policy;\r\n if (!policy) return;\r\n policy.entries.clear();\r\n policy.oldest = policy.newest = undefined;\r\n policy.lruSize = 0;\r\n policy.heap.length = 0;\r\n if (policy.timer) clearTimeout(policy.timer);\r\n policy.timer = undefined;\r\n policy.armedFor = Infinity;\r\n }\r\n\r\n public override get size(): number {\r\n this.purge();\r\n return super.size;\r\n }\r\n\r\n public override entries(): MapIterator<[K, V]> {\r\n this.purge();\r\n return super.entries();\r\n }\r\n\r\n public override keys(): MapIterator<K> {\r\n this.purge();\r\n return super.keys();\r\n }\r\n\r\n public override values(): MapIterator<V> {\r\n this.purge();\r\n return super.values();\r\n }\r\n\r\n public override [Symbol.iterator](): MapIterator<[K, V]> {\r\n return this.entries();\r\n }\r\n\r\n public override forEach(\r\n callback: (value: V, key: K, map: Map<K, V>) => void,\r\n thisArg?: unknown,\r\n ): void {\r\n this.purge();\r\n super.forEach(callback, thisArg);\r\n }\r\n\r\n /** Milliseconds until a key lapses, or undefined if absent or never expiring. */\r\n public ttlRemaining(key: K): number | undefined {\r\n if (this.#expireIfDue(key)) return undefined;\r\n const entry = this.#policy?.entries.get(key);\r\n return entry && entry.window !== 0\r\n ? Math.max(0, entry.deadline - Date.now())\r\n : undefined;\r\n }\r\n\r\n /** Drops every lapsed TTL entry now. @returns How many were dropped. */\r\n public purge(): number {\r\n if (!this.#policy || this.#policy.heap.length === 0) return 0;\r\n const now = Date.now();\r\n let removed = 0;\r\n const dropped: [K, V][] = [];\r\n while (this.#nextDeadline() <= now) {\r\n const due = this.#heapPop()!;\r\n dropped.push([due.key, super.get(due.key)!]);\r\n this.#remove(due.key);\r\n removed++;\r\n }\r\n this.#policy!.expired += removed;\r\n this.#rearm();\r\n for (const [key, value] of dropped) this.#notify(key, value, \"expired\");\r\n return removed;\r\n }\r\n\r\n /** Drops `key` if its TTL has lapsed. @returns Whether it did. */\r\n #expireIfDue(key: K): boolean {\r\n const entry = this.#policy?.entries.get(key);\r\n if (!entry || entry.window === 0 || entry.deadline > Date.now())\r\n return false;\r\n this.#expire(entry);\r\n return true;\r\n }\r\n\r\n #expire(entry: Entry<K, V>): void {\r\n const value = super.get(entry.key)!;\r\n this.#remove(entry.key);\r\n this.#policy!.expired++;\r\n this.#notify(entry.key, value, \"expired\");\r\n }\r\n\r\n #remove(key: K): void {\r\n this.#forget(key);\r\n super.delete(key);\r\n }\r\n\r\n /** Drops a key's policy entry (recency position and TTL); its heap record goes stale. */\r\n #forget(key: K): void {\r\n const policy = this.#policy!;\r\n const entry = policy.entries.get(key);\r\n if (!entry) return;\r\n if (entry.inLru) this.#unlink(policy, entry);\r\n policy.entries.delete(key);\r\n }\r\n\r\n /**\r\n * Brings the key's policy entry in line with a `set()`: marks it newest\r\n * when `maxSize` is set, and gives it a deadline when `window` is defined.\r\n * Only a new entry, or a deadline that moves earlier, gets a heap record;\r\n * a later one is a number write and the record re-files itself when it\r\n * surfaces.\r\n */\r\n #track(key: K, value: V, window: number | undefined, isNew: boolean): void {\r\n const policy = this.#policy!;\r\n const lru = policy.maxSize !== undefined;\r\n let entry = isNew ? undefined : policy.entries.get(key);\r\n if (entry) entry.value = value;\r\n if (window === undefined) {\r\n if (entry && entry.window !== 0) {\r\n // It had a TTL and now has none.\r\n if (lru) entry = this.#replace(policy, entry, 0, 0);\r\n else {\r\n this.#forget(key);\r\n return;\r\n }\r\n }\r\n if (!entry && lru) {\r\n entry = this.#create(key, value, 0, 0);\r\n policy.entries.set(key, entry);\r\n }\r\n if (entry) this.#promote(policy, entry);\r\n return;\r\n }\r\n const deadline = Date.now() + window;\r\n if (entry && entry.window !== 0) {\r\n entry.deadline = deadline;\r\n entry.window = window;\r\n if (deadline < entry.filed)\r\n // The heap cannot move a record up, and this one is in it: file a fresh one.\r\n entry = this.#replace(policy, entry, window, deadline);\r\n else {\r\n if (entry.inLru) this.#promote(policy, entry);\r\n return;\r\n }\r\n } else if (entry) {\r\n entry.window = window;\r\n entry.deadline = entry.filed = deadline;\r\n } else {\r\n entry = this.#create(key, value, window, deadline);\r\n policy.entries.set(key, entry);\r\n }\r\n if (lru) this.#promote(policy, entry);\r\n this.#heapPush(entry);\r\n if (policy.heap.length > 2 * policy.entries.size + 8) this.#compact();\r\n // A timer already armed for an earlier deadline stays correct.\r\n if (policy.timer === undefined || deadline < policy.armedFor)\r\n this.#rearm();\r\n }\r\n\r\n #create(key: K, value: V, window: number, deadline: number): Entry<K, V> {\r\n return {\r\n key,\r\n value,\r\n older: undefined,\r\n newer: undefined,\r\n inLru: false,\r\n window,\r\n deadline,\r\n filed: deadline,\r\n };\r\n }\r\n\r\n /** Swaps in a fresh record for `old` (which goes stale), keeping its recency position. */\r\n #replace(\r\n policy: Policy<K, V>,\r\n old: Entry<K, V>,\r\n window: number,\r\n deadline: number,\r\n ): Entry<K, V> {\r\n const entry: Entry<K, V> = {\r\n ...old,\r\n window,\r\n deadline,\r\n filed: deadline,\r\n };\r\n if (old.inLru) {\r\n if (old.older) old.older.newer = entry;\r\n else policy.oldest = entry;\r\n if (old.newer) old.newer.older = entry;\r\n else policy.newest = entry;\r\n }\r\n policy.entries.set(old.key, entry);\r\n return entry;\r\n }\r\n\r\n /** Makes an entry the newest in recency order, linking it first if needed. */\r\n #promote(policy: Policy<K, V>, entry: Entry<K, V>): void {\r\n if (entry === policy.newest) return;\r\n if (entry.inLru) this.#unlink(policy, entry, true);\r\n else {\r\n entry.inLru = true;\r\n policy.lruSize++;\r\n }\r\n entry.older = policy.newest;\r\n entry.newer = undefined;\r\n if (policy.newest) policy.newest.newer = entry;\r\n else policy.oldest = entry;\r\n policy.newest = entry;\r\n }\r\n\r\n /** Takes an entry out of the recency list; `keepCount` is for a move within it. */\r\n #unlink(policy: Policy<K, V>, entry: Entry<K, V>, keepCount = false): void {\r\n if (entry.older) entry.older.newer = entry.newer;\r\n else policy.oldest = entry.newer;\r\n if (entry.newer) entry.newer.older = entry.older;\r\n else policy.newest = entry.older;\r\n entry.older = entry.newer = undefined;\r\n if (!keepCount) {\r\n entry.inLru = false;\r\n policy.lruSize--;\r\n }\r\n }\r\n\r\n /**\r\n * An empty collection of the species this one derives, so `filter()` and\r\n * friends on a subclass return the subclass. It is built without\r\n * arguments and carries no `ttl` or `maxSize`.\r\n */\r\n #derived(): this {\r\n const Species =\r\n (\r\n this.constructor as {\r\n [Symbol.species]?: new () => Collection<K, V>;\r\n }\r\n )[Symbol.species] ?? Collection;\r\n return new Species() as this;\r\n }\r\n\r\n #notify(key: K, value: V, reason: EvictionReason): void {\r\n const onEvict = this.#policy?.onEvict;\r\n if (!onEvict) return;\r\n try {\r\n onEvict(key, value, reason);\r\n } catch {\r\n // A throwing callback must not leave the collection inconsistent.\r\n }\r\n }\r\n\r\n /** Evicts least-recently-used `set()` entries past `maxSize`; O(1) per eviction. */\r\n #enforceCap(): void {\r\n const policy = this.#policy!;\r\n const max = policy.maxSize;\r\n if (max === undefined) return;\r\n // Lapsed entries must not push live ones out.\r\n if (\r\n policy.lruSize > max &&\r\n policy.heap.length > 0 &&\r\n policy.heap[0]!.filed <= Date.now()\r\n )\r\n this.purge();\r\n while (policy.lruSize > max) {\r\n const oldest = policy.oldest!;\r\n const value = policy.onEvict ? super.get(oldest.key) : undefined;\r\n this.#unlink(policy, oldest);\r\n policy.entries.delete(oldest.key);\r\n super.delete(oldest.key);\r\n policy.evicted++;\r\n this.#notify(oldest.key, value as V, \"evicted\");\r\n }\r\n }\r\n\r\n #nextDeadline(): number {\r\n const policy = this.#policy!;\r\n for (;;) {\r\n const top = policy.heap[0];\r\n if (top === undefined) return Infinity;\r\n if (policy.entries.get(top.key) !== top) {\r\n this.#heapPop();\r\n continue;\r\n }\r\n if (top.deadline === top.filed) return top.filed;\r\n // Extended since it was filed: re-file for its current deadline.\r\n this.#heapPop();\r\n top.filed = top.deadline;\r\n this.#heapPush(top);\r\n }\r\n }\r\n\r\n #compact(): void {\r\n const policy = this.#policy!;\r\n const live = policy.heap.filter(\r\n (entry) => policy.entries.get(entry.key) === entry,\r\n );\r\n policy.heap.length = 0;\r\n for (const entry of live) this.#heapPush(entry);\r\n }\r\n\r\n #rearm(): void {\r\n const p = this.#policy!;\r\n const deadline = this.#nextDeadline();\r\n if (p.timer !== undefined && deadline >= p.armedFor) return;\r\n if (p.timer) clearTimeout(p.timer);\r\n p.timer = undefined;\r\n p.armedFor = deadline;\r\n if (deadline === Infinity) return;\r\n p.timer = setTimeout(\r\n () => {\r\n p.timer = undefined;\r\n p.armedFor = Infinity;\r\n this.purge();\r\n },\r\n Math.max(0, deadline - Date.now()),\r\n );\r\n // Pending expiry is housekeeping, not a reason to keep the process alive.\r\n (p.timer as { unref?: () => void }).unref?.();\r\n }\r\n\r\n #heapPush(entry: Entry<K, V>): void {\r\n const heap = this.#policy!.heap;\r\n let i = heap.length;\r\n heap.push(entry);\r\n while (i > 0) {\r\n const parent = (i - 1) >> 1;\r\n const above = heap[parent]!;\r\n if (above.filed <= entry.filed) break;\r\n heap[i] = above;\r\n i = parent;\r\n }\r\n heap[i] = entry;\r\n }\r\n\r\n #heapPop(): Entry<K, V> | undefined {\r\n const heap = this.#policy!.heap;\r\n const top = heap[0];\r\n const last = heap.pop();\r\n if (top === undefined || heap.length === 0) return top;\r\n let i = 0;\r\n for (;;) {\r\n let child = 2 * i + 1;\r\n if (child >= heap.length) break;\r\n if (\r\n child + 1 < heap.length &&\r\n heap[child + 1]!.filed < heap[child]!.filed\r\n )\r\n child++;\r\n if (heap[child]!.filed >= last!.filed) break;\r\n heap[i] = heap[child]!;\r\n i = child;\r\n }\r\n heap[i] = last!;\r\n return top;\r\n }\r\n\r\n /** Returns the first stored value. */\r\n public first(): V | undefined {\r\n for (const value of this.values()) return value;\r\n return undefined;\r\n }\r\n /** Returns the first stored key. */\r\n public firstKey(): K | undefined {\r\n for (const key of this.keys()) return key;\r\n return undefined;\r\n }\r\n /** Returns the last stored value. */\r\n public last(): V | undefined {\r\n let value: V | undefined;\r\n for (const item of this.values()) value = item;\r\n return value;\r\n }\r\n /** Returns the last stored key. */\r\n public lastKey(): K | undefined {\r\n let key: K | undefined;\r\n for (const item of this.keys()) key = item;\r\n return key;\r\n }\r\n /** Finds the first value matching a predicate. */\r\n public find(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): V | undefined {\r\n for (const [key, value] of this) {\r\n if (predicate(value, key, this)) return value;\r\n }\r\n return undefined;\r\n }\r\n /** Finds the last value (in insertion order) matching a predicate. */\r\n public findLast(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): V | undefined {\r\n const entries = [...this];\r\n for (let i = entries.length - 1; i >= 0; i--) {\r\n const [key, value] = entries[i]!;\r\n if (predicate(value, key, this)) return value;\r\n }\r\n return undefined;\r\n }\r\n /** Finds the key of the last entry (in insertion order) matching a predicate. */\r\n public findLastKey(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): K | undefined {\r\n const entries = [...this];\r\n for (let i = entries.length - 1; i >= 0; i--) {\r\n const [key, value] = entries[i]!;\r\n if (predicate(value, key, this)) return key;\r\n }\r\n return undefined;\r\n }\r\n /** Returns all values matching a predicate. */\r\n public filter(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): this {\r\n const result = this.#derived();\r\n for (const [key, value] of this) {\r\n if (predicate(value, key, this)) result.set(key, value);\r\n }\r\n return result;\r\n }\r\n /** Transforms every stored value into an array. */\r\n public map<T>(transform: (value: V, key: K, collection: this) => T): T[] {\r\n const result: T[] = [];\r\n for (const [key, value] of this) {\r\n result.push(transform(value, key, this));\r\n }\r\n return result;\r\n }\r\n /** Returns whether at least one stored value satisfies a predicate. */\r\n public some(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): boolean {\r\n for (const [key, value] of this) {\r\n if (predicate(value, key, this)) return true;\r\n }\r\n return false;\r\n }\r\n /** Returns whether every stored value satisfies a predicate. */\r\n public every(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): boolean {\r\n for (const [key, value] of this) {\r\n if (!predicate(value, key, this)) return false;\r\n }\r\n return true;\r\n }\r\n /** Runs a callback for each stored value. */\r\n public each(\r\n callback: (value: V, key: K, collection: this) => unknown,\r\n ): this {\r\n for (const [key, value] of this) {\r\n callback(value, key, this);\r\n }\r\n return this;\r\n }\r\n /** Returns an array containing all stored values. */\r\n public array(): V[] {\r\n return [...this.values()];\r\n }\r\n /** Returns an array containing all stored keys. */\r\n public keyArray(): K[] {\r\n return [...this.keys()];\r\n }\r\n /** Returns a plain array of entries. */\r\n public entriesArray(): [K, V][] {\r\n return [...this.entries()];\r\n }\r\n /** Returns a new collection with the same entries. */\r\n public clone(): this {\r\n const copy = this.#derived();\r\n for (const [key, value] of this) copy.set(key, value);\r\n return copy;\r\n }\r\n /** Returns whether all supplied keys are present. */\r\n public hasAll(...keys: K[]): boolean {\r\n for (let i = 0; i < keys.length; i++) {\r\n if (!this.has(keys[i]!)) return false;\r\n }\r\n return true;\r\n }\r\n /** Returns whether at least one supplied key is present. */\r\n public hasAny(...keys: K[]): boolean {\r\n for (let i = 0; i < keys.length; i++) {\r\n if (this.has(keys[i]!)) return true;\r\n }\r\n return false;\r\n }\r\n /** Returns the first key whose value matches a predicate. */\r\n public findKey(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): K | undefined {\r\n for (const [key, value] of this) {\r\n if (predicate(value, key, this)) return key;\r\n }\r\n return undefined;\r\n }\r\n /** Returns whether a predicate matches at least one entry. */\r\n public someEntry(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): boolean {\r\n return this.some(predicate);\r\n }\r\n /** Removes every entry matching a predicate and returns the number removed. */\r\n public sweep(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): number {\r\n let removed = 0;\r\n for (const [key, value] of this) {\r\n if (predicate(value, key, this) && this.delete(key)) removed++;\r\n }\r\n return removed;\r\n }\r\n /** Returns the collection's first matching entry as a tuple. */\r\n public firstEntry(): [K, V] | undefined {\r\n for (const [key, value] of this) return [key, value];\r\n return undefined;\r\n }\r\n /** Returns the collection's last matching entry as a tuple. */\r\n public lastEntry(): [K, V] | undefined {\r\n let entry: [K, V] | undefined;\r\n for (const item of this) entry = [item[0], item[1]];\r\n return entry;\r\n }\r\n /** Returns a new Collection containing elements from both collections. */\r\n public union(other: ReadonlyCollection<K, V>): this {\r\n const result = this.clone();\r\n for (const [key, value] of other) result.set(key, value);\r\n return result;\r\n }\r\n /** Returns a new Collection containing only elements present in both collections. */\r\n public intersection(other: ReadonlyCollection<K, V>): this {\r\n const result = this.#derived();\r\n for (const [key, value] of this) {\r\n if (other.has(key)) result.set(key, value);\r\n }\r\n return result;\r\n }\r\n /** Returns a new Collection containing elements present in this collection but not the other. */\r\n public difference(other: ReadonlyCollection<K, V>): this {\r\n const result = this.#derived();\r\n for (const [key, value] of this) {\r\n if (!other.has(key)) result.set(key, value);\r\n }\r\n return result;\r\n }\r\n /** Splits the collection into two collections based on a predicate.\r\n * @returns `[passing, failing]` — entries satisfying the predicate, then those that don't.\r\n */\r\n public partition(\r\n predicate: (value: V, key: K, collection: this) => boolean,\r\n ): [this, this] {\r\n const pass = this.#derived();\r\n const fail = this.#derived();\r\n for (const [key, value] of this) {\r\n if (predicate(value, key, this)) pass.set(key, value);\r\n else fail.set(key, value);\r\n }\r\n return [pass, fail];\r\n }\r\n /** Returns the entries of both collections that are in only one of them. */\r\n public symmetricDifference(other: ReadonlyCollection<K, V>): this {\r\n const result = this.#derived();\r\n for (const [key, value] of this)\r\n if (!other.has(key)) result.set(key, value);\r\n for (const [key, value] of other)\r\n if (!this.has(key)) result.set(key, value);\r\n return result;\r\n }\r\n /** Returns a new Collection with this one's entries followed by each of `collections`'; a later collection wins a shared key. */\r\n public concat(...collections: ReadonlyCollection<K, V>[]): this {\r\n const result = this.clone();\r\n for (const collection of collections)\r\n for (const [key, value] of collection) result.set(key, value);\r\n return result;\r\n }\r\n /**\r\n * Combines this collection with `other`, deciding per key what to keep.\r\n * @param whenInSelf Called for a key only in this collection.\r\n * @param whenInOther Called for a key only in `other`.\r\n * @param whenInBoth Called for a key in both.\r\n * @returns A new collection of the entries the callbacks kept, in this collection's order, then `other`'s new keys.\r\n */\r\n public merge<T, R>(\r\n other: ReadonlyCollection<K, T>,\r\n whenInSelf: (value: V, key: K) => Keep<R>,\r\n whenInOther: (valueOther: T, key: K) => Keep<R>,\r\n whenInBoth: (value: V, valueOther: T, key: K) => Keep<R>,\r\n ): Collection<K, R> {\r\n const result = this.#derived() as unknown as Collection<K, R>;\r\n const decide = (key: K, kept: Keep<R>): void => {\r\n if (kept.keep) result.set(key, kept.value);\r\n };\r\n for (const [key, value] of this) {\r\n decide(\r\n key,\r\n other.has(key)\r\n ? whenInBoth(value, peekOf(other, key) as T, key)\r\n : whenInSelf(value, key),\r\n );\r\n }\r\n for (const [key, value] of other)\r\n if (!this.has(key)) decide(key, whenInOther(value, key));\r\n return result;\r\n }\r\n /** Returns whether `other` holds the same keys with `===` equal values. Neither side's TTL or recency is touched. */\r\n public equals(other: ReadonlyCollection<K, V> | null | undefined): boolean {\r\n if (!other) return false;\r\n if (other === (this as unknown)) return true;\r\n if (this.size !== other.size) return false;\r\n for (const [key, value] of this) {\r\n if (!other.has(key)) return false;\r\n if (value !== peekOf(other, key)) return false;\r\n }\r\n return true;\r\n }\r\n /** Returns a new collection with the same keys and each value passed through `transform`. */\r\n public mapValues<T>(\r\n transform: (value: V, key: K, collection: this) => T,\r\n ): Collection<K, T> {\r\n const result = this.#derived() as unknown as Collection<K, T>;\r\n for (const [key, value] of this)\r\n result.set(key, transform(value, key, this));\r\n return result;\r\n }\r\n /** Returns a new collection with the entries in reverse order. */\r\n public toReversed(): this {\r\n const result = this.#derived();\r\n const entries = [...this];\r\n for (let i = entries.length - 1; i >= 0; i--)\r\n result.set(entries[i]![0], entries[i]![1]);\r\n return result;\r\n }\r\n /** Same as {@link sorted}, under the name the standard `Array` uses. */\r\n public toSorted(\r\n comparator?: (a: V, b: V, aKey: K, bKey: K) => number,\r\n ): this {\r\n return this.sorted(comparator);\r\n }\r\n /**\r\n * Groups `items` by the key `keySelector` returns for each.\r\n * @param keySelector Called with each item and its index.\r\n * @returns A new collection from each key to its items, in input order.\r\n */\r\n public static override groupBy<K, V>(\r\n items: Iterable<V>,\r\n keySelector: (item: V, index: number) => K,\r\n ): Collection<K, V[]> {\r\n const groups = new Collection<K, V[]>();\r\n let index = 0;\r\n for (const item of items)\r\n groups.ensure(keySelector(item, index++), () => []).push(item);\r\n return groups;\r\n }\r\n /**\r\n * Builds a collection from `entries`, merging values that share a key.\r\n * @param combine Called with the value stored so far, the new one and the key; its result is stored.\r\n */\r\n public static combineEntries<K, V>(\r\n entries: Iterable<readonly [K, V]>,\r\n combine: (firstValue: V, secondValue: V, key: K) => V,\r\n ): Collection<K, V> {\r\n const result = new Collection<K, V>();\r\n for (const [key, value] of entries)\r\n result.set(\r\n key,\r\n result.has(key) ? combine(result.get(key)!, value, key) : value,\r\n );\r\n return result;\r\n }\r\n /** Calls `fn` with this collection and returns the collection unchanged.\r\n * Useful for inserting debug side-effects in a chain without breaking the flow.\r\n */\r\n public tap(fn: (collection: this) => unknown): this {\r\n fn(this);\r\n return this;\r\n }\r\n /** Maps every entry to an array of items and flattens the results. */\r\n public flatMap<T>(\r\n transform: (value: V, key: K, collection: this) => T[],\r\n ): T[] {\r\n const result: T[] = [];\r\n for (const [key, value] of this) {\r\n for (const item of transform(value, key, this)) result.push(item);\r\n }\r\n return result;\r\n }\r\n /** Reduces the collection to a single value. */\r\n public reduce<T>(\r\n fn: (accumulator: T, value: V, key: K, collection: this) => T,\r\n initialValue: T,\r\n ): T {\r\n let acc = initialValue;\r\n for (const [key, value] of this) acc = fn(acc, value, key, this);\r\n return acc;\r\n }\r\n /** Like {@link reduce}, but from the last entry to the first. */\r\n public reduceRight<T>(\r\n fn: (accumulator: T, value: V, key: K, collection: this) => T,\r\n initialValue: T,\r\n ): T {\r\n const entries = [...this];\r\n let acc = initialValue;\r\n for (let i = entries.length - 1; i >= 0; i--)\r\n acc = fn(acc, entries[i]![1], entries[i]![0], this);\r\n return acc;\r\n }\r\n /** Returns a new Collection with entries sorted by comparator (non-mutating).\r\n * Defaults to insertion order if no comparator is provided.\r\n */\r\n public sorted(comparator?: (a: V, b: V, aKey: K, bKey: K) => number): this {\r\n // Decorate with the original insertion index and use it as a tiebreaker so\r\n // equal elements keep their insertion order (a stable sort independent of\r\n // the engine's Array.prototype.sort stability guarantees).\r\n const decorated = [...this.entries()].map((entry, index) => ({\r\n entry,\r\n index,\r\n }));\r\n if (comparator)\r\n decorated.sort((x, y) => {\r\n const comparison = comparator(\r\n x.entry[1],\r\n y.entry[1],\r\n x.entry[0],\r\n y.entry[0],\r\n );\r\n return comparison !== 0 ? comparison : x.index - y.index;\r\n });\r\n const result = this.#derived();\r\n for (const { entry } of decorated) result.set(entry[0], entry[1]);\r\n return result;\r\n }\r\n /**\r\n * Returns a random value, or `undefined` if empty. With `amount`, returns\r\n * that many different values (all of them, shuffled, when `amount` is at\r\n * least the size).\r\n * Uses `Math.random()` (fast, non-cryptographic): do not use it for\r\n * security-sensitive selection such as tokens or secrets.\r\n * @param amount How many values to pick.\r\n * @throws {RangeError} If `amount` is not a non-negative integer.\r\n */\r\n public random(): V | undefined;\r\n public random(amount: number): V[];\r\n public random(amount?: number): V | V[] | undefined {\r\n if (amount !== undefined) return sample([...this.values()], amount);\r\n const size = this.size;\r\n if (size === 0) return undefined;\r\n let index = Math.floor(Math.random() * size);\r\n for (const value of this.values()) if (index-- === 0) return value;\r\n return undefined;\r\n }\r\n /**\r\n * Returns a random key, or `undefined` if empty. With `amount`, returns\r\n * that many different keys. Same randomness and errors as {@link random}.\r\n * @param amount How many keys to pick.\r\n */\r\n public randomKey(): K | undefined;\r\n public randomKey(amount: number): K[];\r\n public randomKey(amount?: number): K | K[] | undefined {\r\n if (amount !== undefined) return sample([...this.keys()], amount);\r\n const size = this.size;\r\n if (size === 0) return undefined;\r\n let index = Math.floor(Math.random() * size);\r\n for (const key of this.keys()) if (index-- === 0) return key;\r\n return undefined;\r\n }\r\n /** Returns the value at a given insertion-order index (supports negative indices). */\r\n public at(index: number): V | undefined {\r\n const arr = [...this.values()];\r\n const i = index < 0 ? arr.length + index : index;\r\n return arr[i];\r\n }\r\n /** Returns the key at a given insertion-order index (supports negative indices). */\r\n public keyAt(index: number): K | undefined {\r\n const arr = [...this.keys()];\r\n const i = index < 0 ? arr.length + index : index;\r\n return arr[i];\r\n }\r\n /** Serializes the collection to a plain `[key, value]` array. */\r\n public toJSON(): [K, V][] {\r\n return [...this.entries()];\r\n }\r\n}\r\n\r\nexport { Cache } from \"./cache.js\";\r\nexport type { CacheOptions } from \"./cache.js\";\r\n",
|
|
11
|
+
"import { Collection } from \"@lunibee/collection\";\r\n\r\n/** Splits the audit-log `reason` off an options object, so it becomes a header, not a body field. */\r\nexport function splitReason<T extends { reason?: string }>(\r\n options: T,\r\n): [Omit<T, \"reason\">, string | undefined] {\r\n const { reason, ...payload } = options;\r\n return [payload, reason];\r\n}\r\n\r\n/** Generic cache manager. @typeParam K Cache key type. @typeParam V Cached value type. */\r\nexport class Manager<K, V> {\r\n /** Authoritative resource state. Entries never expire: see {@link Manager.set}. */\r\n public readonly cache = new Collection<K, V>();\r\n /** Gets a cached value. @param id Cache key. @returns Cached value. */\r\n public get(id: K): V | undefined {\r\n return this.cache.get(id);\r\n }\r\n /** Checks whether a value is cached. @param id Cache key. @returns True when cached. */\r\n public has(id: K): boolean {\r\n return this.cache.has(id);\r\n }\r\n /** In-flight fetches; `dirty` is set when the key is written or deleted meanwhile. */\r\n readonly #inflight = new Map<K, { promise: Promise<V>; dirty: boolean }>();\r\n\r\n /**\r\n * Runs a REST load for one key. Concurrent loads of that key share a\r\n * single request. If the key is written (e.g. by a Gateway update) or\r\n * deleted while the request is in flight, the result is returned but not\r\n * stored, so it cannot overwrite fresher state or resurrect a deleted\r\n * resource.\r\n * @param store Stores a fresh result and returns the canonical instance.\r\n */\r\n protected fetchOnce(\r\n id: K,\r\n load: () => Promise<V>,\r\n store: (value: V) => V = (value) => {\r\n this.set(id, value);\r\n return value;\r\n },\r\n ): Promise<V> {\r\n const pending = this.#inflight.get(id);\r\n if (pending) return pending.promise;\r\n const entry = {\r\n promise: new Promise<V>((resolve) => resolve(load())),\r\n dirty: false,\r\n };\r\n this.#inflight.set(id, entry);\r\n entry.promise = entry.promise.then(\r\n (value) => {\r\n this.#inflight.delete(id);\r\n return entry.dirty ? (this.get(id) ?? value) : store(value);\r\n },\r\n (error: unknown) => {\r\n this.#inflight.delete(id);\r\n throw error;\r\n },\r\n );\r\n return entry.promise;\r\n }\r\n\r\n #markDirty(id: K): void {\r\n const pending = this.#inflight.get(id);\r\n if (pending) pending.dirty = true;\r\n }\r\n\r\n /** Stores a resource with `setWithoutTTL()`, so it leaves only on an explicit delete (e.g. a Gateway `*_DELETE`), never through TTL. @param id Cache key. @param value Value. @returns This manager. */\r\n public set(id: K, value: V): this {\r\n this.#markDirty(id);\r\n this.cache.setWithoutTTL(id, value);\r\n return this;\r\n }\r\n /** Deletes a cached value. @param id Cache key. @returns True when deleted. */\r\n public delete(id: K): boolean {\r\n this.#markDirty(id);\r\n return this.cache.delete(id);\r\n }\r\n /** Clears the cache. @returns Nothing. */\r\n public clear(): void {\r\n this.cache.clear();\r\n }\r\n /** Gets cache size. @returns Number of cached values. */\r\n public get size(): number {\r\n return this.cache.size;\r\n }\r\n /** Gets the first cached value. @returns First value. */\r\n public first(): V | undefined {\r\n return this.cache.first();\r\n }\r\n /** Returns cached values. @returns Array of values. */\r\n public values(): V[] {\r\n return this.cache.array();\r\n }\r\n /** Finds a cached value. @param predicate Predicate. @returns Matching value. */\r\n public find(predicate: (value: V, key: K) => boolean): V | undefined {\r\n return this.cache.find(predicate);\r\n }\r\n /** Iterates cached entries. @returns Cache iterator. */\r\n public [Symbol.iterator](): IterableIterator<[K, V]> {\r\n return this.cache[Symbol.iterator]();\r\n }\r\n}\r\n\r\n/** Generic REST-backed resource manager. @typeParam K Resource key type. @typeParam V Resource type. */\r\nexport class ResourceManager<K, V> extends Manager<K, V> {\r\n readonly #fetcher: (id: K) => Promise<V>;\r\n readonly #key: (value: V) => K;\r\n\r\n public constructor(fetcher: (id: K) => Promise<V>, key: (value: V) => K) {\r\n super();\r\n if (typeof fetcher !== \"function\" || typeof key !== \"function\")\r\n throw new TypeError(\r\n \"ResourceManager requires fetcher and key functions.\",\r\n );\r\n this.#fetcher = fetcher;\r\n this.#key = key;\r\n }\r\n\r\n public async resolve(id: K): Promise<V> {\r\n return this.get(id) ?? this.fetch(id);\r\n }\r\n\r\n public fetch(id: K): Promise<V> {\r\n return this.fetchOnce(id, () => this.#fetcher(id));\r\n }\r\n\r\n public async fetchMany(ids: Iterable<K>): Promise<V[]> {\r\n return Promise.all([...ids].map((id) => this.resolve(id)));\r\n }\r\n\r\n /** Stores a resource, merging into the cached instance when there is one so existing references stay current. @returns The canonical instance. */\r\n public upsert(resource: V): V {\r\n const key = this.#key(resource);\r\n const existing = this.get(key);\r\n if (\r\n existing !== undefined &&\r\n existing !== resource &&\r\n typeof existing === \"object\" &&\r\n existing !== null\r\n ) {\r\n Object.assign(existing, resource);\r\n this.set(key, existing);\r\n return existing;\r\n }\r\n this.set(key, resource);\r\n return resource;\r\n }\r\n\r\n public update(resource: V): V {\r\n return this.upsert(resource);\r\n }\r\n}\r\n",
|
|
12
|
+
"export interface BucketState {\r\n remaining: number;\r\n resetAt: number;\r\n}\r\n\r\n/**\r\n * Outcome of an atomic reservation.\r\n *\r\n * `granted` means one unit of the bucket's allowance now belongs to the caller\r\n * and to nobody else — the distinction that a read-then-write cannot make when\r\n * several workers share a store.\r\n */\r\nexport type Reservation =\r\n { granted: true } | { granted: false; retryAfterMs: number };\r\n\r\n/** Interface for distributed or local rate limit synchronization. */\r\nexport interface RateLimitStore {\r\n /** Gets the server bucket hash for a normalized route. */\r\n getBucketHash(\r\n route: string,\r\n ): Promise<string | undefined> | string | undefined;\r\n /** Associates a route with a server bucket hash. */\r\n setBucketHash(route: string, hash: string): Promise<void> | void;\r\n\r\n /** Gets the current state for a bucket key. */\r\n getBucket(\r\n key: string,\r\n ): Promise<BucketState | undefined> | BucketState | undefined;\r\n /** Updates the state for a bucket key. */\r\n updateBucket(key: string, state: BucketState): Promise<void> | void;\r\n\r\n /** Gets the global reset timestamp. */\r\n getGlobalReset(): Promise<number> | number;\r\n /** Sets the global reset timestamp. */\r\n setGlobalReset(resetAt: number): Promise<void> | void;\r\n\r\n /**\r\n * Atomically consumes one unit of a bucket's allowance.\r\n *\r\n * Optional: a store that cannot do this atomically must omit it, and the\r\n * limiter falls back to waiting on observed state. Implementations must\r\n * grant when the bucket is unknown or its window has elapsed — an unknown\r\n * bucket is discovered by sending, and refusing would deadlock the route.\r\n */\r\n reserve?(key: string): Promise<Reservation> | Reservation;\r\n\r\n /**\r\n * Evicts expired bucket entries. Optional: stores with native key\r\n * expiry (e.g. Redis) can omit it. `maxAge` (ms) additionally drops\r\n * buckets whose reset is older than that window; defaults to 0 (only\r\n * already-reset buckets are removed).\r\n */\r\n prune?(maxAge?: number): Promise<void> | void;\r\n}\r\n\r\n/** Local memory implementation of RateLimitStore. */\r\nexport class MemoryRateLimitStore implements RateLimitStore {\r\n readonly #buckets = new Map<string, BucketState>();\r\n readonly #routeBuckets = new Map<string, string>();\r\n #globalResetAt = 0;\r\n /** Minimum interval between automatic prunes, in ms. */\r\n static readonly #PRUNE_INTERVAL = 60_000;\r\n #lastPruneAt = 0;\r\n\r\n public getBucketHash(route: string): string | undefined {\r\n return this.#routeBuckets.get(route);\r\n }\r\n public setBucketHash(route: string, hash: string): void {\r\n this.#routeBuckets.set(route, hash);\r\n }\r\n public getBucket(key: string): BucketState | undefined {\r\n return this.#buckets.get(key);\r\n }\r\n /**\r\n * Consumes one unit of the bucket's allowance.\r\n *\r\n * Single-process reservation is trivially atomic: JavaScript will not\r\n * interleave this method with another caller's copy of it.\r\n */\r\n public reserve(key: string): Reservation {\r\n const state = this.#buckets.get(key);\r\n const now = Date.now();\r\n // Unknown bucket, or a window that has already elapsed: the next\r\n // response re-establishes the real allowance.\r\n if (!state || state.resetAt <= now) return { granted: true };\r\n if (state.remaining > 0) {\r\n state.remaining -= 1;\r\n return { granted: true };\r\n }\r\n return { granted: false, retryAfterMs: state.resetAt - now };\r\n }\r\n public updateBucket(key: string, state: BucketState): void {\r\n this.#buckets.set(key, state);\r\n // Amortised eviction: sweep expired buckets at most once per interval\r\n // so the map cannot grow unbounded across long-lived processes.\r\n const now = Date.now();\r\n if (now - this.#lastPruneAt >= MemoryRateLimitStore.#PRUNE_INTERVAL) {\r\n this.#lastPruneAt = now;\r\n this.prune();\r\n }\r\n }\r\n /** Removes buckets whose reset is in the past (or older than `maxAge` ms). */\r\n public prune(maxAge = 0): void {\r\n const cutoff = Date.now() - Math.max(0, maxAge);\r\n for (const [key, state] of this.#buckets) {\r\n if (state.resetAt <= cutoff) this.#buckets.delete(key);\r\n }\r\n }\r\n public getGlobalReset(): number {\r\n return this.#globalResetAt;\r\n }\r\n public setGlobalReset(resetAt: number): void {\r\n this.#globalResetAt = resetAt;\r\n }\r\n}\r\n",
|
|
13
|
+
"/** Why a REST request failed, for handling without matching on status codes. */\r\nexport type RESTErrorKind =\r\n /** Cancelled through an AbortSignal. */\r\n | \"aborted\"\r\n /** The attempt exceeded the transport timeout. */\r\n | \"timeout\"\r\n /** No response: DNS, TLS, connection reset. */\r\n | \"network\"\r\n /** 429 that outlived the retry budget. */\r\n | \"rateLimited\"\r\n /** 401: invalid or revoked token. */\r\n | \"authentication\"\r\n /** 403: missing access or permissions. */\r\n | \"permission\"\r\n /** 404: unknown resource. */\r\n | \"notFound\"\r\n /** 400 / 422: the request body or parameters were rejected. */\r\n | \"validation\"\r\n /** 5xx: Discord failed to handle the request. */\r\n | \"server\"\r\n /** Any other 4xx. */\r\n | \"client\";\r\n\r\nfunction kindFromStatus(status: number): RESTErrorKind {\r\n if (status === 429) return \"rateLimited\";\r\n if (status === 401) return \"authentication\";\r\n if (status === 403) return \"permission\";\r\n if (status === 404) return \"notFound\";\r\n if (status === 400 || status === 422) return \"validation\";\r\n if (status >= 500) return \"server\";\r\n if (status === 0) return \"network\";\r\n return \"client\";\r\n}\r\n\r\n/**\r\n * Replaces the token segment of webhook and interaction paths with `:token`,\r\n * so request paths can appear in errors, hooks and logs without leaking a\r\n * credential.\r\n */\r\nexport function redactPath(path: string): string {\r\n return (\r\n path\r\n // The ID segment is matched loosely: a malformed ID must not stop the\r\n // token that follows it from being redacted.\r\n .replace(/^(\\/webhooks\\/[^/?]+\\/)[^/?]+/i, \"$1:token\")\r\n .replace(/^(\\/interactions\\/[^/?]+\\/)[^/?]+/i, \"$1:token\")\r\n );\r\n}\r\n\r\n/** What to check when Discord refuses an action the bot attempted. */\r\nconst HINTS: Readonly<Record<number, string>> = {\r\n 50001: \"The bot cannot see this resource: check that it is in the guild and has View Channel there.\",\r\n 50013: \"The bot lacks a permission for this action, or the target role or member is at or above the bot's highest role.\",\r\n};\r\n\r\n/** Error thrown when Discord rejects a REST request. */\r\nexport class RESTError extends Error {\r\n /** Failure category. */\r\n public readonly kind: RESTErrorKind;\r\n /** HTTP status returned by Discord. */\r\n public readonly status: number;\r\n /** Discord API error code, when provided. */\r\n public readonly code?: number;\r\n /** Raw Discord validation/error payload. */\r\n public readonly errors?: unknown;\r\n /** HTTP method used for the failed request. */\r\n public readonly method?: string;\r\n /** API path used for the failed request. */\r\n public readonly path?: string;\r\n /** What to check next, for errors with a common cause (missing access or permissions). */\r\n public readonly hint?: string;\r\n /** Creates a REST error with request context. @param message Error message. @param status HTTP status. @param code Discord error code. @param errors Raw error payload. @param options Request context and cause. */\r\n public constructor(\r\n message: string,\r\n status: number,\r\n code?: number,\r\n errors?: unknown,\r\n options: {\r\n method?: string;\r\n path?: string;\r\n cause?: unknown;\r\n kind?: RESTErrorKind;\r\n } = {},\r\n ) {\r\n super(\r\n message,\r\n options.cause === undefined ? undefined : { cause: options.cause },\r\n );\r\n this.name = \"RESTError\";\r\n this.status = status;\r\n this.kind = options.kind ?? kindFromStatus(status);\r\n this.code = code;\r\n this.hint = code === undefined ? undefined : HINTS[code];\r\n this.errors = errors;\r\n this.method = options.method;\r\n this.path =\r\n options.path === undefined ? undefined : redactPath(options.path);\r\n }\r\n\r\n /** Whether sending the same request again later could succeed. Validation,\r\n * permission, authentication and not-found failures never will. */\r\n public get retryable(): boolean {\r\n return (\r\n this.kind === \"rateLimited\" ||\r\n this.kind === \"server\" ||\r\n this.kind === \"network\" ||\r\n this.kind === \"timeout\"\r\n );\r\n }\r\n}\r\n\r\n/** Creates the cancellation error shared by every stage of the request pipeline. */\r\nexport function abortError(path: string, reason: unknown): RESTError {\r\n return new RESTError(\r\n reason instanceof Error\r\n ? reason.message\r\n : \"Discord REST request was aborted\",\r\n 0,\r\n undefined,\r\n undefined,\r\n { path, cause: reason, kind: \"aborted\" },\r\n );\r\n}\r\n\r\n/** Waits for a delay, rejecting early if the signal aborts. */\r\nexport async function sleep(\r\n delay: number,\r\n signal: AbortSignal | undefined,\r\n path: string,\r\n): Promise<void> {\r\n if (delay <= 0) return;\r\n await new Promise<void>((resolve, reject) => {\r\n const timer = setTimeout(resolve, delay);\r\n const abort = (): void => {\r\n clearTimeout(timer);\r\n reject(abortError(path, signal?.reason));\r\n };\r\n if (signal?.aborted) return abort();\r\n signal?.addEventListener(\"abort\", abort, { once: true });\r\n });\r\n}\r\n\r\n/** Awaits a promise, rejecting early if the signal aborts. */\r\nexport async function abortable(\r\n promise: Promise<void>,\r\n signal: AbortSignal | undefined,\r\n path: string,\r\n): Promise<void> {\r\n if (!signal) return promise;\r\n if (signal.aborted) throw abortError(path, signal.reason);\r\n return Promise.race([\r\n promise,\r\n new Promise<void>((_, reject) =>\r\n signal.addEventListener(\r\n \"abort\",\r\n () => reject(abortError(path, signal.reason)),\r\n { once: true },\r\n ),\r\n ),\r\n ]);\r\n}\r\n",
|
|
14
|
+
"import { createHash } from \"node:crypto\";\r\nimport { redactPath } from \"./errors.js\";\r\n\r\n/** Query-string value accepted by a request. */\r\nexport type RESTQuery =\r\n | URLSearchParams\r\n | Record<string, string | number | boolean | null | undefined>\r\n | string;\r\n\r\n/**\r\n * Identity of a request as Discord's rate limiter sees it.\r\n *\r\n * `route` is the shape of the endpoint (ids replaced by `:id`), which is what\r\n * Discord returns a bucket hash for. `major` is the resource that gives an\r\n * endpoint its own independent limit. Both are needed: the hash alone would\r\n * make two channels share one counter.\r\n */\r\nexport interface RouteKey {\r\n /** Uppercased HTTP method. */\r\n method: string;\r\n /** Raw request path, without query string. */\r\n path: string;\r\n /** Normalized `METHOD:/path/:id` route used for bucket-hash lookup. */\r\n route: string;\r\n /** Major parameter scoping the limit (channel, guild, webhook id[:token]). */\r\n major: string;\r\n}\r\n\r\n/** Normalizes Discord routes for stable bucket discovery. */\r\nexport function normalizeRoutePath(path: string): string {\r\n const queryIndex = path.indexOf(\"?\");\r\n const routePath = queryIndex === -1 ? path : path.slice(0, queryIndex);\r\n // Tokens never enter a route key: keys are stored (Redis keeps them for days).\r\n return redactPath(routePath).replace(/\\/\\d+(?=\\/|$)/g, \"/:id\");\r\n}\r\n\r\n/**\r\n * Discord's *major parameters* — the resource ids that give an endpoint its own\r\n * independent rate limit. Per the API documentation these are `channel_id`,\r\n * `guild_id` and `webhook_id`; webhook routes are additionally scoped by\r\n * their token. Any other id in a path shares its limit with sibling resources.\r\n */\r\nexport function majorParameter(path: string): string {\r\n const match = /^\\/(channels|guilds|webhooks)\\/(\\d+)(?:\\/([^/?]+))?/i.exec(\r\n path,\r\n );\r\n if (!match) return \"@none\";\r\n // A webhook's limit is keyed by its id and its token. The token is hashed\r\n // so the key (stored, possibly shared through Redis) never holds it.\r\n if (match[1]!.toLowerCase() === \"webhooks\" && match[3] !== undefined)\r\n return `${match[2]}:${tokenDigest(match[3])}`;\r\n return match[2]!;\r\n}\r\n\r\n/** A short, stable digest of a token, identical in every process. */\r\nfunction tokenDigest(token: string): string {\r\n return createHash(\"sha256\").update(token).digest(\"hex\").slice(0, 16);\r\n}\r\n\r\n/** Combines a bucket hash (or route) with a major parameter into a bucket key. */\r\nexport function scopeBucket(hashOrRoute: string, major: string): string {\r\n return `${hashOrRoute}|${major}`;\r\n}\r\n\r\n/** Builds the routing identity for one request. */\r\nexport function createRouteKey(method: string, path: string): RouteKey {\r\n const normalizedMethod = method.toUpperCase();\r\n return {\r\n method: normalizedMethod,\r\n path,\r\n route: `${normalizedMethod}:${normalizeRoutePath(path)}`,\r\n major: majorParameter(path),\r\n };\r\n}\r\n\r\n/** Serialises a query into a `?...` suffix (empty string when nothing to add). */\r\nexport function serializeQuery(query: RESTQuery | undefined): string {\r\n if (query === undefined) return \"\";\r\n if (typeof query === \"string\")\r\n return query.length === 0 || query.startsWith(\"?\")\r\n ? query\r\n : `?${query}`;\r\n const params =\r\n query instanceof URLSearchParams\r\n ? query\r\n : new URLSearchParams(\r\n Object.entries(query).flatMap(([key, value]) =>\r\n value === undefined || value === null\r\n ? []\r\n : [[key, String(value)] as [string, string]],\r\n ),\r\n );\r\n const serialized = params.toString();\r\n return serialized.length === 0 ? \"\" : `?${serialized}`;\r\n}\r\n",
|
|
15
|
+
"import { abortable } from \"./errors.js\";\r\n\r\n/**\r\n * Serialises work per rate-limit bucket.\r\n *\r\n * One request per bucket key is in flight at a time, so each request sees the\r\n * limit state its predecessor's response wrote. The queue slot is released on\r\n * every exit path — including an abort raised while still waiting — because a\r\n * slot that is never released wedges its bucket for the process lifetime.\r\n */\r\nexport class RequestScheduler {\r\n /** Maximum times a request may be moved to a different bucket queue. */\r\n public static readonly MAX_REMAPS = 2;\r\n readonly #queues = new Map<string, Promise<void>>();\r\n\r\n /** Number of bucket keys currently holding a queue slot. */\r\n public get size(): number {\r\n return this.#queues.size;\r\n }\r\n\r\n /**\r\n * Runs `task` under the bucket key that `resolveKey` reports *at the moment\r\n * the slot is acquired*, not at enqueue time.\r\n *\r\n * Discord can map several routes onto one bucket hash, and a route only\r\n * learns its hash from a response. A request that queued under its\r\n * route-derived key while another request discovered the shared hash would\r\n * otherwise run concurrently with that bucket's other traffic. Re-resolving\r\n * after the wait moves it onto the right queue instead.\r\n *\r\n * @param resolveKey Returns the current bucket key for this request.\r\n * @param signal Cancellation signal honoured while queued.\r\n * @param path Request path, used for cancellation error context.\r\n * @param task Work to run while holding the slot, given the final key and\r\n * a callback that frees the slot early.\r\n */\r\n public async runResolved<T>(\r\n resolveKey: () => Promise<string>,\r\n signal: AbortSignal | undefined,\r\n path: string,\r\n task: (key: string, release: () => void) => Promise<T>,\r\n ): Promise<T> {\r\n let key = await resolveKey();\r\n // A remap can only chain as far as route key -> shared hash, so a small\r\n // bound is enough; the final hop runs whatever key it holds.\r\n for (let hop = 0; hop < RequestScheduler.MAX_REMAPS; hop++) {\r\n const outcome = await this.run<\r\n { done: true; value: T } | { done: false; key: string }\r\n >(key, signal, path, async (release) => {\r\n const current = await resolveKey();\r\n if (current !== key) return { done: false, key: current };\r\n return { done: true, value: await task(key, release) };\r\n });\r\n if (outcome.done) return outcome.value;\r\n key = outcome.key;\r\n }\r\n return this.run(key, signal, path, (release) => task(key, release));\r\n }\r\n\r\n /**\r\n * Runs `task` once every earlier task for `key` has settled, or has freed\r\n * its slot early through the `release` callback it was given.\r\n * @param key Bucket key to serialise on.\r\n * @param signal Cancellation signal honoured while queued.\r\n * @param path Request path, used for cancellation error context.\r\n * @param task Work to run while holding the slot, given an idempotent\r\n * callback that frees the slot before the task settles.\r\n */\r\n public async run<T>(\r\n key: string,\r\n signal: AbortSignal | undefined,\r\n path: string,\r\n task: (release: () => void) => Promise<T>,\r\n ): Promise<T> {\r\n const previous = this.#queues.get(key) ?? Promise.resolve();\r\n let open!: () => void;\r\n const gate = new Promise<void>((resolve) => {\r\n open = resolve;\r\n });\r\n this.#queues.set(key, gate);\r\n let released = false;\r\n const release = (): void => {\r\n if (released) return;\r\n released = true;\r\n open();\r\n // Drop our entry so idle buckets do not accumulate, but only if it\r\n // is still ours: a later request may already have replaced it.\r\n if (this.#queues.get(key) === gate) this.#queues.delete(key);\r\n };\r\n try {\r\n await abortable(previous, signal, path);\r\n return await task(release);\r\n } finally {\r\n release();\r\n }\r\n }\r\n}\r\n",
|
|
16
|
+
"import { sleep } from \"./errors.js\";\r\nimport { scopeBucket } from \"./route.js\";\r\nimport type { RateLimitStore } from \"./store.js\";\r\n\r\n/**\r\n * Owns Discord's rate-limit state: when a request may go out, and what a\r\n * response says about the bucket it landed in.\r\n *\r\n * The limiter holds no queueing logic of its own — {@link RequestScheduler}\r\n * decides ordering — and no HTTP knowledge beyond reading rate-limit headers.\r\n */\r\nexport class RateLimiter {\r\n readonly #store: RateLimitStore;\r\n /** Whether responses may arrive out of order for one bucket. */\r\n readonly #concurrent: boolean;\r\n\r\n /**\r\n * @param store Rate-limit state store.\r\n * @param options `concurrent`: set when several requests per bucket can be\r\n * in flight, so a late response cannot raise `remaining` within its window.\r\n */\r\n public constructor(\r\n store: RateLimitStore,\r\n options: { concurrent?: boolean } = {},\r\n ) {\r\n this.#store = store;\r\n this.#concurrent = options.concurrent ?? false;\r\n }\r\n\r\n /** The backing store, shared across processes when a distributed store is used. */\r\n public get store(): RateLimitStore {\r\n return this.#store;\r\n }\r\n\r\n /** Resolves the bucket key a request should be gated on. */\r\n public async resolveBucketKey(\r\n route: string,\r\n major: string,\r\n ): Promise<string> {\r\n return scopeBucket(\r\n (await this.#store.getBucketHash(route)) ?? route,\r\n major,\r\n );\r\n }\r\n\r\n /** Whether the backing store can reserve allowance atomically. */\r\n public get reserves(): boolean {\r\n return typeof this.#store.reserve === \"function\";\r\n }\r\n\r\n /**\r\n * Waits until both the route bucket and the global limit permit sending.\r\n *\r\n * When the store supports it, allowance is *reserved* rather than merely\r\n * observed. Reading `remaining` and deciding to send is a race across\r\n * workers: three processes all read `remaining: 1` and all send. A\r\n * reservation hands the unit to exactly one of them.\r\n */\r\n public async acquire(\r\n bucketKey: string,\r\n signal: AbortSignal | undefined,\r\n path: string,\r\n ): Promise<void> {\r\n await this.#waitGlobal(signal, path);\r\n if (!this.#store.reserve) {\r\n const bucket = await this.#store.getBucket(bucketKey);\r\n if (bucket) {\r\n const delay = bucket.resetAt - Date.now();\r\n if (bucket.remaining <= 0 && delay > 0)\r\n await sleep(delay, signal, path);\r\n }\r\n return;\r\n }\r\n // Each refusal carries the wait until the window resets, so the loop\r\n // advances by a real interval every time; the bound only guards against\r\n // a pathological store that keeps refusing with a zero wait.\r\n for (let attempt = 0; attempt < 8; attempt++) {\r\n const reservation = await this.#store.reserve(bucketKey);\r\n if (reservation.granted) return;\r\n await sleep(Math.max(1, reservation.retryAfterMs), signal, path);\r\n await this.#waitGlobal(signal, path);\r\n }\r\n }\r\n\r\n async #waitGlobal(\r\n signal: AbortSignal | undefined,\r\n path: string,\r\n ): Promise<void> {\r\n const globalDelay = (await this.#store.getGlobalReset()) - Date.now();\r\n if (globalDelay > 0) await sleep(globalDelay, signal, path);\r\n }\r\n\r\n /** Extends the global limit, never shortening a longer one already recorded. */\r\n public async noteGlobalReset(resetAt: number): Promise<void> {\r\n const current = await this.#store.getGlobalReset();\r\n await this.#store.setGlobalReset(Math.max(current, resetAt));\r\n }\r\n\r\n /**\r\n * Records a response's rate-limit headers and returns the bucket key the\r\n * request actually belongs to: Discord may reveal a server bucket hash that\r\n * differs from the route-derived key used before the first response.\r\n */\r\n public async applyResponse(\r\n response: Response,\r\n bucketKey: string,\r\n route: string,\r\n major: string,\r\n ): Promise<string> {\r\n let currentKey = bucketKey;\r\n const serverBucket = response.headers.get(\"X-RateLimit-Bucket\");\r\n if (serverBucket) {\r\n await this.#store.setBucketHash(route, serverBucket);\r\n currentKey = scopeBucket(serverBucket, major);\r\n }\r\n\r\n const stored = await this.#store.getBucket(currentKey);\r\n const bucket = stored ? { ...stored } : { remaining: 1, resetAt: 0 };\r\n const windowActive =\r\n this.#concurrent && !!stored && stored.resetAt > Date.now();\r\n const remaining = Number(response.headers.get(\"X-RateLimit-Remaining\"));\r\n const resetAfter = Number(\r\n response.headers.get(\"X-RateLimit-Reset-After\"),\r\n );\r\n const reset = Number(response.headers.get(\"X-RateLimit-Reset\"));\r\n\r\n if (Number.isFinite(remaining))\r\n bucket.remaining = Math.max(0, remaining);\r\n if (Number.isFinite(resetAfter))\r\n bucket.resetAt = Date.now() + Math.max(0, resetAfter) * 1000;\r\n else if (Number.isFinite(reset)) bucket.resetAt = reset * 1000;\r\n // With concurrent requests, responses from one window can arrive out of\r\n // order: never let a late one hand back allowance already reserved.\r\n if (windowActive && stored) {\r\n bucket.remaining = Math.min(bucket.remaining, stored.remaining);\r\n bucket.resetAt = Math.max(bucket.resetAt, stored.resetAt);\r\n }\r\n\r\n if (response.status === 429) {\r\n const retryAfter = Number(response.headers.get(\"Retry-After\"));\r\n if (Number.isFinite(retryAfter))\r\n bucket.resetAt = Math.max(\r\n bucket.resetAt,\r\n Date.now() + retryAfter * 1000,\r\n );\r\n }\r\n await this.#store.updateBucket(currentKey, bucket);\r\n\r\n if (response.headers.get(\"X-RateLimit-Global\") === \"true\") {\r\n const retryAfter = Number(response.headers.get(\"Retry-After\"));\r\n if (Number.isFinite(retryAfter))\r\n await this.noteGlobalReset(Date.now() + retryAfter * 1000);\r\n }\r\n\r\n return currentKey;\r\n }\r\n}\r\n",
|
|
17
|
+
"import { RESTError, abortError } from \"./errors.js\";\r\n\r\n/** Minimal fetch shape the transport depends on, so a stub needs no extras. */\r\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>;\r\n\r\n/** One HTTP attempt, fully resolved: no routing, retry or rate-limit concerns. */\r\nexport interface TransportRequest {\r\n /** Uppercased HTTP method. */\r\n method: string;\r\n /** Path with query string, relative to the transport's base URL. */\r\n path: string;\r\n /** Request headers, already including authorization. */\r\n headers: Record<string, string>;\r\n /** Encoded body, or undefined for a bodyless request. */\r\n body?: BodyInit;\r\n /** Caller cancellation signal. */\r\n signal?: AbortSignal;\r\n}\r\n\r\n/** Thrown by {@link HttpTransport} when the attempt never produced a response. */\r\nexport class TransportError extends Error {\r\n /** Whether the attempt was cut short by the transport timeout or an abort. */\r\n public readonly timedOut: boolean;\r\n public constructor(message: string, timedOut: boolean, cause?: unknown) {\r\n super(message, cause === undefined ? undefined : { cause });\r\n this.name = \"TransportError\";\r\n this.timedOut = timedOut;\r\n }\r\n}\r\n\r\n/**\r\n * Sends one HTTP attempt and returns the raw {@link Response}.\r\n *\r\n * Everything above it — routing, rate limiting, retries, decoding — is somebody\r\n * else's job, which is what makes the layer substitutable in tests.\r\n */\r\nexport class HttpTransport {\r\n readonly #baseURL: string;\r\n readonly #timeout: number;\r\n readonly #fetch: FetchLike;\r\n\r\n public constructor(\r\n options: {\r\n baseURL?: string;\r\n timeout?: number;\r\n fetch?: FetchLike;\r\n } = {},\r\n ) {\r\n this.#baseURL = (\r\n options.baseURL ?? \"https://discord.com/api/v10\"\r\n ).replace(/\\/$/, \"\");\r\n this.#timeout = Math.max(1, options.timeout ?? 15_000);\r\n this.#fetch =\r\n options.fetch ?? ((input, init) => globalThis.fetch(input, init));\r\n }\r\n\r\n /** Base URL every request path is resolved against. */\r\n public get baseURL(): string {\r\n return this.#baseURL;\r\n }\r\n /** Per-attempt timeout in milliseconds. */\r\n public get timeout(): number {\r\n return this.#timeout;\r\n }\r\n\r\n /**\r\n * Performs the attempt.\r\n * @throws {RESTError} If the caller's signal was already aborted.\r\n * @throws {TransportError} If the attempt times out or the transport fails.\r\n */\r\n public async send(request: TransportRequest): Promise<Response> {\r\n if (request.signal?.aborted)\r\n throw abortError(request.path, request.signal.reason);\r\n\r\n const controller = new AbortController();\r\n const onAbort = (): void => controller.abort(request.signal?.reason);\r\n request.signal?.addEventListener(\"abort\", onAbort, { once: true });\r\n const timer = setTimeout(\r\n () =>\r\n controller.abort(\r\n new DOMException(\"REST request timeout\", \"TimeoutError\"),\r\n ),\r\n this.#timeout,\r\n );\r\n try {\r\n return await this.#fetch(`${this.#baseURL}${request.path}`, {\r\n method: request.method,\r\n headers: request.headers,\r\n body: request.body,\r\n signal: controller.signal,\r\n });\r\n } catch (error) {\r\n if (error instanceof RESTError) throw error;\r\n const timedOut =\r\n error instanceof DOMException &&\r\n (error.name === \"TimeoutError\" || error.name === \"AbortError\");\r\n throw new TransportError(\r\n timedOut\r\n ? `Discord REST request timed out after ${this.#timeout}ms`\r\n : \"Discord REST request failed\",\r\n timedOut,\r\n error,\r\n );\r\n } finally {\r\n clearTimeout(timer);\r\n request.signal?.removeEventListener(\"abort\", onAbort);\r\n }\r\n }\r\n}\r\n",
|
|
18
|
+
"/** Normalised shape of a Discord error payload. */\r\nexport interface DecodedError {\r\n message?: string;\r\n code?: number;\r\n retry_after?: number;\r\n global?: boolean;\r\n}\r\n\r\n/** Turns a raw {@link Response} into a payload and the error metadata retries need. */\r\nexport class ResponseDecoder {\r\n /** Reads a Discord response payload as JSON, text, or nothing for 204. */\r\n public async read(response: Response): Promise<unknown> {\r\n if (response.status === 204) return undefined;\r\n const contentType = response.headers.get(\"content-type\") ?? \"\";\r\n if (contentType.includes(\"application/json\"))\r\n return response.json().catch(() => undefined);\r\n return response.text().catch(() => undefined);\r\n }\r\n\r\n /** Extracts Discord's error metadata from a decoded payload. */\r\n public errorData(payload: unknown): DecodedError {\r\n if (!payload || typeof payload !== \"object\") return {};\r\n const data = payload as Record<string, unknown>;\r\n return {\r\n message:\r\n typeof data.message === \"string\" ? data.message : undefined,\r\n code: typeof data.code === \"number\" ? data.code : undefined,\r\n retry_after:\r\n typeof data.retry_after === \"number\"\r\n ? data.retry_after\r\n : undefined,\r\n global: data.global === true,\r\n };\r\n }\r\n\r\n /**\r\n * Resolves Retry-After (seconds) from the payload, falling back to the\r\n * header and finally to one second.\r\n *\r\n * An absent header is explicitly *not* a zero delay: `Number(null)` is 0,\r\n * which is finite, so reading it directly would answer a 429 that carries\r\n * no Retry-After by retrying immediately — exactly when backing off matters.\r\n */\r\n public retryAfter(response: Response, data: DecodedError): number {\r\n const raw = response.headers.get(\"Retry-After\");\r\n const header = raw === null ? Number.NaN : Number(raw);\r\n const retryAfter =\r\n data.retry_after ?? (Number.isFinite(header) ? header : 1);\r\n return Math.max(0, retryAfter);\r\n }\r\n}\r\n",
|
|
19
|
+
"/** Discord REST API route definitions. */\r\nexport const Routes = {\r\n /** Returns the current bot user. @returns User route. */\r\n user: () => \"/users/@me\",\r\n /** Returns one user. @param userId User identifier. @returns User route. */\r\n userById: (userId: string) => `/users/${snowflake(userId, \"User ID\")}`,\r\n /** Returns a guild. @param guildId Guild identifier. @returns Guild route. */\r\n guild: (guildId: string) => `/guilds/${snowflake(guildId, \"Guild ID\")}`,\r\n /** Leaves a guild as the current user (DELETE). @param guildId Guild identifier. @returns Current-user guild route. */\r\n currentUserGuild: (guildId: string) =>\r\n `/users/@me/guilds/${snowflake(guildId, \"Guild ID\")}`,\r\n /** Returns a sticker. @param stickerId Sticker identifier. @returns Sticker route. */\r\n sticker: (stickerId: string) =>\r\n `/stickers/${snowflake(stickerId, \"Sticker ID\")}`,\r\n /** Removes one user's reaction (DELETE). @param channelId Channel identifier. @param messageId Message identifier. @param emoji Emoji name or ID. @param userId User identifier. @returns Reaction-user route. */\r\n messageReactionUser: (\r\n channelId: string,\r\n messageId: string,\r\n emoji: string,\r\n userId: string,\r\n ) =>\r\n `${Routes.messageReactions(channelId, messageId, emoji)}/${snowflake(userId, \"User ID\")}`,\r\n /** Returns a guild preview. @param guildId Guild identifier. */\r\n guildPreview: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/preview`,\r\n /** Returns active threads for a guild. @param guildId Guild identifier. */\r\n guildActiveThreads: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/threads/active`,\r\n /** Returns webhooks for a guild. @param guildId Guild identifier. */\r\n guildWebhooks: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/webhooks`,\r\n /** Returns invites for a guild. @param guildId Guild identifier. */\r\n guildInvites: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/invites`,\r\n /** Returns channels in a guild. @param guildId Guild identifier. @returns Channel collection route. */\r\n guildChannels: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/channels`,\r\n /** Returns a guild member. @param guildId Guild identifier. @param userId User identifier. @returns Guild-member route. */\r\n guildMember: (guildId: string, userId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/members/${snowflake(userId, \"User ID\")}`,\r\n /** Returns all guild roles. @param guildId Guild identifier. @returns Guild-role route. */\r\n guildRoles: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/roles`,\r\n /** Returns an individual guild role. */\r\n guildRole: (guildId: string, roleId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/roles/${snowflake(roleId, \"Role ID\")}`,\r\n /** Returns a member role route. */\r\n guildMemberRole: (guildId: string, userId: string, roleId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/members/${snowflake(userId, \"User ID\")}/roles/${snowflake(roleId, \"Role ID\")}`,\r\n /** Returns guild bans collection. */\r\n guildBans: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/bans`,\r\n /** Returns an individual guild ban. */\r\n guildBan: (guildId: string, userId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/bans/${snowflake(userId, \"User ID\")}`,\r\n /** Returns a channel. @param channelId Channel identifier. @returns Channel route. */\r\n channel: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}`,\r\n /** Returns messages in a channel. @param channelId Channel identifier. @returns Message collection route. */\r\n channelMessages: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages`,\r\n /** Returns a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Message route. */\r\n message: (channelId: string, messageId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages/${snowflake(messageId, \"Message ID\")}`,\r\n /** Crossposts a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Crosspost route. */\r\n crosspostMessage: (channelId: string, messageId: string) =>\r\n `${Routes.message(channelId, messageId)}/crosspost`,\r\n /** Returns reactions for a message and emoji. @param channelId Channel identifier. @param messageId Message identifier. @param emoji Emoji name or ID. @returns Reaction route. */\r\n messageReactions: (channelId: string, messageId: string, emoji: string) =>\r\n `${Routes.message(channelId, messageId)}/reactions/${encodeURIComponent(emoji)}`,\r\n /** Removes all reactions from a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Reaction collection route. */\r\n messageReactionsAll: (channelId: string, messageId: string) =>\r\n `${Routes.message(channelId, messageId)}/reactions`,\r\n /** Returns pinned messages, newest first, in pages of up to 50 (`before`, `limit`). @param channelId Channel identifier. @returns Pins route. */\r\n channelMessagesPins: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages/pins`,\r\n /** Pins (PUT) or unpins (DELETE) a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Pin route. */\r\n channelMessagesPin: (channelId: string, messageId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages/pins/${snowflake(messageId, \"Message ID\")}`,\r\n /** @deprecated Discord deprecated this endpoint. Use {@link Routes.channelMessagesPins}, which returns `{ items, has_more }`. Removed in 0.3.0. */\r\n channelPins: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/pins`,\r\n /** @deprecated Discord deprecated this endpoint. Use {@link Routes.channelMessagesPin}. Removed in 0.3.0. */\r\n channelPin: (channelId: string, messageId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/pins/${snowflake(messageId, \"Message ID\")}`,\r\n /** Creates a thread from a message. @param channelId Channel identifier. @param messageId Message identifier. @returns Message-thread route. */\r\n messageThread: (channelId: string, messageId: string) =>\r\n `${Routes.message(channelId, messageId)}/threads`,\r\n /** Bulk deletes messages. @param channelId Channel identifier. @returns Bulk-delete route. */\r\n channelBulkDelete: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/messages/bulk-delete`,\r\n /** Returns channel webhooks. @param channelId Channel identifier. @returns Webhook collection route. */\r\n channelWebhooks: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/webhooks`,\r\n /** Returns channel invites. @param channelId Channel identifier. @returns Invite collection route. */\r\n channelInvites: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/invites`,\r\n /** Returns a webhook. @param webhookId Webhook identifier. @param token Optional webhook token. @returns Webhook route. */\r\n webhook: (webhookId: string, token?: string) =>\r\n `/webhooks/${snowflake(webhookId, \"Webhook ID\")}${token ? `/${encodeURIComponent(token)}` : \"\"}`,\r\n /** Returns a webhook message. */\r\n webhookMessage: (webhookId: string, token: string, messageId: string) =>\r\n `/webhooks/${snowflake(webhookId, \"Webhook ID\")}/${encodeURIComponent(token)}/messages/${snowflake(messageId, \"Message ID\")}`,\r\n /** Returns application commands for an application. @param applicationId Application identifier. @returns Global command route. */\r\n applicationCommands: (applicationId: string) =>\r\n `/applications/${snowflake(applicationId, \"Application ID\")}/commands`,\r\n /** Returns one application command. @param applicationId Application identifier. @param commandId Command identifier. @returns Command route. */\r\n applicationCommand: (applicationId: string, commandId: string) =>\r\n `/applications/${snowflake(applicationId, \"Application ID\")}/commands/${snowflake(commandId, \"Command ID\")}`,\r\n /** Returns guild application commands. @param applicationId Application identifier. @param guildId Guild identifier. @returns Guild command route. */\r\n guildApplicationCommands: (applicationId: string, guildId: string) =>\r\n `/applications/${snowflake(applicationId, \"Application ID\")}/guilds/${snowflake(guildId, \"Guild ID\")}/commands`,\r\n /** Returns a single guild application command. @param applicationId Application identifier. @param guildId Guild identifier. @param commandId Command identifier. @returns Guild command route. */\r\n guildApplicationCommand: (\r\n applicationId: string,\r\n guildId: string,\r\n commandId: string,\r\n ) =>\r\n `/applications/${snowflake(applicationId, \"Application ID\")}/guilds/${snowflake(guildId, \"Guild ID\")}/commands/${snowflake(commandId, \"Command ID\")}`,\r\n /** Returns an interaction callback endpoint. @param interactionId Interaction identifier. @param token Interaction token. @returns Interaction callback route. */\r\n interactionCallback: (interactionId: string, token: string) =>\r\n `/interactions/${snowflake(interactionId, \"Interaction ID\")}/${encodeURIComponent(token)}/callback`,\r\n /** Returns the original interaction response endpoint. @param applicationId Application identifier. @param token Interaction token. @returns Original-response route. */\r\n interactionOriginalResponse: (applicationId: string, token: string) =>\r\n `/webhooks/${snowflake(applicationId, \"Application ID\")}/${encodeURIComponent(token)}/messages/@original`,\r\n\r\n /** Returns public archived threads for a channel. @param channelId Channel identifier. @returns Public-archive route. */\r\n channelPublicArchivedThreads: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/threads/archived/public`,\r\n /** Returns private archived threads for a channel. @param channelId Channel identifier. @returns Private-archive route. */\r\n channelPrivateArchivedThreads: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/threads/archived/private`,\r\n /** Returns a thread's members. @param threadId Thread identifier. @returns Thread-member route. */\r\n threadMembers: (threadId: string) =>\r\n `/channels/${snowflake(threadId, \"Thread ID\")}/thread-members`,\r\n /** Returns guild scheduled events. @param guildId Guild identifier. @returns Scheduled-event collection route. */\r\n guildScheduledEvents: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/scheduled-events`,\r\n /** Returns one guild scheduled event. @param guildId Guild identifier. @param eventId Event identifier. @returns Scheduled-event route. */\r\n guildScheduledEvent: (guildId: string, eventId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/scheduled-events/${snowflake(eventId, \"Event ID\")}`,\r\n /** Returns users subscribed to a scheduled event. @param guildId Guild identifier. @param eventId Event identifier. @returns Scheduled-event users route. */\r\n guildScheduledEventUsers: (guildId: string, eventId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/scheduled-events/${snowflake(eventId, \"Event ID\")}/users`,\r\n /** Returns a channel permission overwrite. @param channelId Channel identifier. @param overwriteId Role or user identifier. @returns Permission overwrite route. */\r\n channelPermission: (channelId: string, overwriteId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/permissions/${snowflake(overwriteId, \"Overwrite ID\")}`,\r\n /** Returns guild automod rules. @param guildId Guild identifier. @returns Automod-rule collection route. */\r\n guildAutoModerationRules: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/auto-moderation/rules`,\r\n /** Returns one automod rule. @param guildId Guild identifier. @param ruleId Rule identifier. @returns Automod-rule route. */\r\n guildAutoModerationRule: (guildId: string, ruleId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/auto-moderation/rules/${snowflake(ruleId, \"Rule ID\")}`,\r\n /** Returns current voice regions. @returns Voice-region route. */\r\n voiceRegions: () => \"/voice/regions\",\r\n /** Returns the generic Gateway endpoint. @returns Gateway route. */\r\n gateway: () => \"/gateway\",\r\n /** Returns the Gateway endpoint and recommended shard count for bots. @returns Gateway bot route. */\r\n gatewayBot: () => \"/gateway/bot\",\r\n\r\n // ─── Audit Logs ──────────────────────────────────────────────────────────────\r\n /** Returns audit log entries for a guild. @param guildId Guild identifier. @returns Audit log route. */\r\n guildAuditLog: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/audit-logs`,\r\n\r\n // ─── Guild Members (bulk fetch) ───────────────────────────────────────────────\r\n /** Returns members in a guild (paginated). @param guildId Guild identifier. @returns Members collection route. */\r\n guildMembers: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/members`,\r\n\r\n // ─── Welcome Screen & Onboarding ──────────────────────────────────────────────\r\n /** Returns the welcome screen for a guild. @param guildId Guild identifier. */\r\n guildWelcomeScreen: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/welcome-screen`,\r\n /** Returns the onboarding configuration for a guild. @param guildId Guild identifier. */\r\n guildOnboarding: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/onboarding`,\r\n\r\n // ─── Guild Prune ──────────────────────────────────────────────────────────────\r\n /** Returns or executes a prune operation for inactive members. @param guildId Guild identifier. @returns Prune route. */\r\n guildPrune: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/prune`,\r\n\r\n // ─── Stage Instances ──────────────────────────────────────────────────────────\r\n /** Returns the stage instances collection. @returns Stage instance root route. */\r\n stageInstances: () => \"/stage-instances\",\r\n /** Returns a stage instance by its channel. @param channelId Stage channel identifier. @returns Stage instance route. */\r\n stageInstanceByChannel: (channelId: string) =>\r\n `/stage-instances/${snowflake(channelId, \"Channel ID\")}`,\r\n\r\n // ─── Invites ──────────────────────────────────────────────────────────────────\r\n /** Returns an invite by code. @param code Invite code. @returns Invite route. */\r\n invite: (code: string) => `/invites/${encodeURIComponent(code)}`,\r\n /** Returns the guild vanity invite metadata. @param guildId Guild identifier. @returns Vanity URL route. */\r\n guildVanity: (guildId: string) =>\r\n `/guilds/${snowflake(guildId, \"Guild ID\")}/vanity-url`,\r\n\r\n // ─── Emojis ───────────────────────────────────────────────────────────────────\r\n /** Returns guild emojis, or a specific emoji. @param guildId Guild identifier. @param emojiId Optional emoji identifier. */\r\n guildEmoji: (guildId: string, emojiId?: string) =>\r\n emojiId\r\n ? `/guilds/${snowflake(guildId, \"Guild ID\")}/emojis/${snowflake(emojiId, \"Emoji ID\")}`\r\n : `/guilds/${snowflake(guildId, \"Guild ID\")}/emojis`,\r\n /** Returns application emojis, or a specific emoji. @param applicationId Application identifier. @param emojiId Optional emoji identifier. */\r\n applicationEmoji: (applicationId: string, emojiId?: string) =>\r\n emojiId\r\n ? `/applications/${snowflake(applicationId, \"Application ID\")}/emojis/${snowflake(emojiId, \"Emoji ID\")}`\r\n : `/applications/${snowflake(applicationId, \"Application ID\")}/emojis`,\r\n\r\n // ─── Polls ────────────────────────────────────────────────────────────────────\r\n /** Ends a poll early. @param channelId Channel identifier. @param messageId Poll message identifier. */\r\n pollExpire: (channelId: string, messageId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/polls/${snowflake(messageId, \"Message ID\")}/expire`,\r\n /** Returns the users who voted for a poll answer. @param answerId Answer identifier (an integer, not a snowflake). */\r\n pollAnswerVoters: (\r\n channelId: string,\r\n messageId: string,\r\n answerId: number,\r\n ) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/polls/${snowflake(messageId, \"Message ID\")}/answers/${integer(answerId, \"Answer ID\")}`,\r\n\r\n // ─── Stickers ─────────────────────────────────────────────────────────────────\r\n /** Returns guild stickers, or one sticker. */\r\n guildSticker: (guildId: string, stickerId?: string) =>\r\n stickerId\r\n ? `/guilds/${snowflake(guildId, \"Guild ID\")}/stickers/${snowflake(stickerId, \"Sticker ID\")}`\r\n : `/guilds/${snowflake(guildId, \"Guild ID\")}/stickers`,\r\n\r\n // ─── Soundboard ───────────────────────────────────────────────────────────────\r\n /** Plays a soundboard sound in a voice channel. */\r\n sendSoundboardSound: (channelId: string) =>\r\n `/channels/${snowflake(channelId, \"Channel ID\")}/send-soundboard-sound`,\r\n /** Returns Discord's default soundboard sounds. */\r\n soundboardDefaultSounds: () => \"/soundboard-default-sounds\",\r\n /** Returns guild soundboard sounds, or one sound. */\r\n guildSoundboardSound: (guildId: string, soundId?: string) =>\r\n soundId\r\n ? `/guilds/${snowflake(guildId, \"Guild ID\")}/soundboard-sounds/${snowflake(soundId, \"Sound ID\")}`\r\n : `/guilds/${snowflake(guildId, \"Guild ID\")}/soundboard-sounds`,\r\n\r\n // ─── Monetization ─────────────────────────────────────────────────────────────\r\n /** Returns an application's SKUs. */\r\n applicationSkus: (applicationId: string) =>\r\n `/applications/${snowflake(applicationId, \"Application ID\")}/skus`,\r\n /** Returns an application's entitlements, or one entitlement. */\r\n applicationEntitlement: (applicationId: string, entitlementId?: string) =>\r\n entitlementId\r\n ? `/applications/${snowflake(applicationId, \"Application ID\")}/entitlements/${snowflake(entitlementId, \"Entitlement ID\")}`\r\n : `/applications/${snowflake(applicationId, \"Application ID\")}/entitlements`,\r\n /** Marks a one-time-purchase entitlement as consumed. */\r\n consumeEntitlement: (applicationId: string, entitlementId: string) =>\r\n `/applications/${snowflake(applicationId, \"Application ID\")}/entitlements/${snowflake(entitlementId, \"Entitlement ID\")}/consume`,\r\n /** Returns a SKU's subscriptions, or one subscription. */\r\n skuSubscription: (skuId: string, subscriptionId?: string) =>\r\n subscriptionId\r\n ? `/skus/${snowflake(skuId, \"SKU ID\")}/subscriptions/${snowflake(subscriptionId, \"Subscription ID\")}`\r\n : `/skus/${snowflake(skuId, \"SKU ID\")}/subscriptions`,\r\n} as const;\r\n\r\n/** Validates a non-negative integer route parameter. */\r\nfunction integer(value: number, field: string): string {\r\n if (!Number.isInteger(value) || value < 0)\r\n throw new TypeError(`${field} must be a non-negative integer.`);\r\n return String(value);\r\n}\r\n\r\n/** Validates a Discord snowflake route parameter. Accepts any decimal id that fits an\r\n * unsigned 64-bit integer, matching the snowflake rule `BaseStructure` applies in\r\n * `@lunibee/structures`. The guarantee this provides is that no non-numeric segment can\r\n * reshape the request path; it deliberately does not police id length, because Discord\r\n * snowflakes are 17 digits for early 2015 ids and reach 20 digits as the epoch advances.\r\n * @param value Candidate identifier. @param field Human-readable field name. @returns The validated identifier. @throws {TypeError} If the identifier is not a Discord snowflake. */\r\nfunction snowflake(value: string, field: string): string {\r\n if (!/^\\d{1,20}$/.test(value))\r\n throw new TypeError(`${field} must be a valid Discord snowflake.`);\r\n return value;\r\n}\r\n",
|
|
20
|
+
"/** Library version and source URL used for the Discord-compliant User-Agent. */\r\nimport packageJson from \"../package.json\" with { type: \"json\" };\r\nconst LIBRARY_VERSION = packageJson.version;\r\nconst LIBRARY_URL = \"https://github.com/Ekretos/lunibee\";\r\nconst USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${LIBRARY_VERSION})`;\r\n\r\nimport { MemoryRateLimitStore, type RateLimitStore } from \"./store.js\";\r\nimport { RESTError, abortError, redactPath, sleep } from \"./errors.js\";\r\nimport {\r\n createRouteKey,\r\n serializeQuery,\r\n type RESTQuery,\r\n type RouteKey,\r\n} from \"./route.js\";\r\nimport { RequestScheduler } from \"./scheduler.js\";\r\nimport { RateLimiter } from \"./limiter.js\";\r\nimport { HttpTransport, TransportError } from \"./transport.js\";\r\nimport { ResponseDecoder } from \"./decoder.js\";\r\n\r\n/**\r\n * Refuses a path that URL normalization would rewrite into another route:\r\n * `.` / `..` segments (also percent-encoded) and backslashes. Without this,\r\n * an id like `../../channels/1` sends the bot token to a route the caller\r\n * never asked for. The path is left out of the message: it may hold a token.\r\n */\r\nfunction assertSafePath(path: string): void {\r\n const end = path.search(/[?#]/);\r\n const pathname = end === -1 ? path : path.slice(0, end);\r\n if (pathname.includes(\"\\\\\"))\r\n throw new TypeError(\"REST paths must not contain backslashes.\");\r\n for (const segment of pathname.split(\"/\")) {\r\n let decoded: string;\r\n try {\r\n decoded = decodeURIComponent(segment);\r\n } catch {\r\n throw new TypeError(\"REST path has malformed percent-encoding.\");\r\n }\r\n if (decoded === \".\" || decoded === \"..\")\r\n throw new TypeError(\r\n \"REST paths must not contain '.' or '..' segments.\",\r\n );\r\n }\r\n}\r\n\r\n/** A file attachment sent as part of a multipart REST request. */\r\nexport interface RESTFileAttachment {\r\n name: string;\r\n data: Blob | Uint8Array | ArrayBuffer;\r\n contentType?: string;\r\n}\r\n\r\n/**\r\n * Options controlling an individual REST request.\r\n *\r\n * Lunibee's canonical call shape is positional (`post(path, body)`); these options\r\n * add the Discord.js-`@discordjs/rest`-familiar per-request knobs (`query`, `headers`,\r\n * `reason`, `auth`) additively without changing that positional default.\r\n */\r\nexport interface RESTRequestOptions {\r\n /** Abort signal used to cancel the request and any queued wait. */\r\n signal?: AbortSignal;\r\n /** Query-string appended to the path (`URLSearchParams`, a record, or a raw string). */\r\n query?: RESTQuery;\r\n /** Extra request headers merged in (library headers such as `Authorization` win). */\r\n headers?: Record<string, string>;\r\n /** Audit-log reason, sent as the `X-Audit-Log-Reason` header. */\r\n reason?: string;\r\n /** Set `false` to omit the `Authorization` header for this request. Defaults to `true`. */\r\n auth?: boolean;\r\n}\r\n\r\n/**\r\n * Discord.js-familiar request payload. Superset of {@link RESTRequestOptions} that also\r\n * carries the `body` and `files`, matching `@discordjs/rest`'s `RequestData`. It powers the\r\n * additive `method(path, { body })` overloads without breaking the positional signature.\r\n */\r\nexport interface RequestData extends RESTRequestOptions {\r\n /** Request body. Encoded as JSON unless `files` are present (then multipart). */\r\n body?: unknown;\r\n /** File attachments; presence upgrades the request to `multipart/form-data`. */\r\n files?: RESTFileAttachment[];\r\n}\r\n\r\n/** Keys recognised on a {@link RequestData} wrapper, used to disambiguate it from a raw body. */\r\nconst REQUEST_DATA_KEYS = new Set([\r\n \"body\",\r\n \"files\",\r\n \"query\",\r\n \"headers\",\r\n \"reason\",\r\n \"auth\",\r\n \"signal\",\r\n]);\r\n\r\n/**\r\n * Detects a Discord.js-style `RequestData` wrapper so verb helpers can accept both\r\n * `post(path, rawBody)` (Lunibee-canonical) and `post(path, { body })` (Discord.js-familiar).\r\n * Conservative by design: only a plain object whose every own key is a known `RequestData`\r\n * key counts — a raw Discord payload (which always carries entity keys like `content`/`name`)\r\n * never matches, so existing positional callers are unaffected.\r\n */\r\nfunction isRequestData(value: unknown): value is RequestData {\r\n if (value === null || typeof value !== \"object\") return false;\r\n if (Array.isArray(value)) return false;\r\n if (typeof FormData !== \"undefined\" && value instanceof FormData)\r\n return false;\r\n if (\r\n value instanceof Blob ||\r\n value instanceof Uint8Array ||\r\n value instanceof ArrayBuffer\r\n )\r\n return false;\r\n const keys = Object.keys(value);\r\n if (keys.length === 0) return false;\r\n return keys.every((key) => REQUEST_DATA_KEYS.has(key));\r\n}\r\n\r\n// ─── REST Hooks ───────────────────────────────────────────────────────────────\r\n\r\n/** Context passed to `RESTHooks.onRequest`. */\r\nexport interface RESTRequestContext {\r\n method: string;\r\n path: string;\r\n attempt: number;\r\n}\r\n/** Context passed to `RESTHooks.onResponse`. */\r\nexport interface RESTResponseContext {\r\n method: string;\r\n path: string;\r\n status: number;\r\n durationMs: number;\r\n}\r\n/** Context passed to `RESTHooks.onRateLimit`. */\r\nexport interface RESTRateLimitContext {\r\n method: string;\r\n path: string;\r\n retryAfterMs: number;\r\n global: boolean;\r\n bucket?: string;\r\n}\r\n/** Context passed to `RESTHooks.onRetry`. */\r\nexport interface RESTRetryContext {\r\n method: string;\r\n path: string;\r\n attempt: number;\r\n status: number;\r\n delayMs: number;\r\n}\r\n\r\n/**\r\n * Lightweight callback hooks for REST request lifecycle events.\r\n *\r\n * All callbacks are optional. They are dispatched in isolation from the request\r\n * path (deferred to a microtask, and any thrown error is swallowed), so a hook\r\n * cannot break or reject a request. Even so, hooks **must** be fast and\r\n * non-blocking: heavy synchronous work in a hook still steals event-loop time\r\n * from in-flight requests. Offload anything expensive to your own queue.\r\n */\r\nexport interface RESTHooks {\r\n /** Called just before every HTTP attempt. */\r\n onRequest?(ctx: RESTRequestContext): void;\r\n /** Called after a successful or failed response is received. */\r\n onResponse?(ctx: RESTResponseContext): void;\r\n /** Called when a rate limit is encountered and the client is about to wait. */\r\n onRateLimit?(ctx: RESTRateLimitContext): void;\r\n /** Called when a failed request is about to be retried. */\r\n onRetry?(ctx: RESTRetryContext): void;\r\n}\r\n\r\n/** Configures which REST failures may be retried. */\r\nexport interface RetryPolicy {\r\n /** Maximum retry attempts. */\r\n maxRetries: number;\r\n /** Determines whether a request may be retried. @param method HTTP method. @param status HTTP status, or zero for transport errors. @returns True when retrying is safe under the policy. */\r\n shouldRetry(method: string, status: number): boolean;\r\n /** Calculates delay before the next attempt. @param attempt Zero-based retry number. @param retryAfter Server-provided delay, when available. @returns Delay in milliseconds. */\r\n getDelay(attempt: number, retryAfter?: number): number;\r\n}\r\n/** Creates the default conservative REST retry policy. @param maxRetries Maximum retries. @returns Retry policy that retries rate limits and idempotent transient failures. @throws {TypeError} If maxRetries is negative or not finite. */\r\nexport function createRetryPolicy(maxRetries = 2): RetryPolicy {\r\n if (!Number.isFinite(maxRetries) || maxRetries < 0)\r\n throw new TypeError(\"maxRetries must be a non-negative finite number.\");\r\n return {\r\n maxRetries: Math.floor(maxRetries),\r\n shouldRetry(method, status) {\r\n const normalized = method.toUpperCase();\r\n const idempotent = [\"GET\", \"HEAD\", \"PUT\", \"DELETE\"].includes(\r\n normalized,\r\n );\r\n // Status 0 is a transport failure (DNS, reset connection, TLS):\r\n // no response reached Discord's handlers, so replaying an\r\n // idempotent request is as safe as replaying it after a 5xx.\r\n if (status === 0) return idempotent;\r\n return (\r\n status === 429 || (status >= 500 && status <= 599 && idempotent)\r\n );\r\n },\r\n getDelay(attempt, retryAfter) {\r\n if (retryAfter !== undefined) return Math.max(0, retryAfter * 1000);\r\n return Math.min(10_000, 500 * 2 ** attempt) + Math.random() * 250;\r\n },\r\n };\r\n}\r\n\r\n/** Bun-native REST transport with Discord bucket-aware rate limiting, retries, and cancellation. */\r\nexport class REST {\r\n readonly #retryPolicy: RetryPolicy;\r\n #token?: string;\r\n /** Rate-limit state: when a request may go out, what a response says. */\r\n readonly #limiter: RateLimiter;\r\n /** Per-bucket ordering. */\r\n readonly #scheduler = new RequestScheduler();\r\n /** One HTTP attempt, with timeout and cancellation. */\r\n readonly #transport: HttpTransport;\r\n /** Response payload and error metadata. */\r\n readonly #decoder = new ResponseDecoder();\r\n #hooks: RESTHooks = {};\r\n /** Whether requests on a known bucket may run concurrently. */\r\n readonly #concurrentBuckets: boolean;\r\n /** Creates a REST transport. @param options Transport configuration. @throws {TypeError} If retry configuration is invalid. */\r\n public constructor(\r\n options: {\r\n token?: string;\r\n timeout?: number;\r\n retries?: number;\r\n retryPolicy?: RetryPolicy;\r\n baseURL?: string;\r\n hooks?: RESTHooks;\r\n store?: RateLimitStore;\r\n /** Replaces the HTTP stage, e.g. with a recording transport in tests. */\r\n transport?: HttpTransport;\r\n /**\r\n * Lets requests on a bucket whose limit is known run concurrently, up\r\n * to its `remaining` allowance, instead of one at a time. Requires a\r\n * store with `reserve`. Requests on one bucket may then complete out\r\n * of order (e.g. messages to one channel). Defaults to `false`.\r\n */\r\n concurrentBuckets?: boolean;\r\n } = {},\r\n ) {\r\n this.#token = options.token;\r\n this.#retryPolicy =\r\n options.retryPolicy ?? createRetryPolicy(options.retries ?? 2);\r\n this.#transport =\r\n options.transport ??\r\n new HttpTransport({\r\n baseURL: options.baseURL,\r\n timeout: options.timeout,\r\n });\r\n const store = options.store ?? new MemoryRateLimitStore();\r\n this.#concurrentBuckets =\r\n (options.concurrentBuckets ?? false) &&\r\n typeof store.reserve === \"function\";\r\n this.#limiter = new RateLimiter(store, {\r\n concurrent: this.#concurrentBuckets,\r\n });\r\n if (options.hooks) this.#hooks = options.hooks;\r\n }\r\n /** The rate-limit store backing this transport. */\r\n public get store(): RateLimitStore {\r\n return this.#limiter.store;\r\n }\r\n /** Replaces the current hook set. Pass an empty object to clear all hooks. */\r\n public setHooks(hooks: RESTHooks): this {\r\n this.#hooks = hooks;\r\n return this;\r\n }\r\n /** Sets the authentication token. @param token Discord bot token. @returns Nothing. @throws {TypeError} If token is empty. */\r\n public setToken(token: string): void {\r\n if (!token.trim())\r\n throw new TypeError(\"A Discord bot token is required.\");\r\n this.#token = token;\r\n }\r\n /** Executes an HTTP request with Discord bucket/global rate limits, retry handling, and AbortSignal support.\r\n * Accepts a JSON body, a FormData body (for file uploads), or undefined.\r\n * @param method HTTP method.\r\n * @param path API path.\r\n * @param body Optional JSON body, FormData for file uploads, or undefined.\r\n * @param options Request options: cancellation `signal` plus the Discord.js-familiar\r\n * `query`, `headers`, `reason`, `auth`, and `files` (which upgrade to multipart).\r\n * @returns Decoded response body.\r\n * @throws {RESTError} If Discord or transport rejects the request.\r\n */\r\n public async request<T>(\r\n method: string,\r\n path: string,\r\n body?: unknown,\r\n options: RequestData = {},\r\n ): Promise<T> {\r\n if (!method.toUpperCase())\r\n throw new TypeError(\"REST method is required.\");\r\n if (!path.startsWith(\"/\"))\r\n throw new TypeError(\"REST paths must start with '/'.\");\r\n assertSafePath(path);\r\n const route = createRouteKey(method, path);\r\n // Upgrade to multipart when file attachments are supplied via options.\r\n const files = options.files;\r\n if (files && files.length > 0 && !(body instanceof FormData))\r\n body = this.#fileForm(body, files);\r\n const query = serializeQuery(options.query);\r\n const requestPath = query ? `${path}${query}` : path;\r\n\r\n // Discord scopes a rate limit by (bucket hash, major parameter): two\r\n // channels sharing an endpoint have independent limits, while two\r\n // different routes can share one hash. The key is therefore resolved\r\n // again once the slot is acquired, so a request that queued under its\r\n // route-derived key joins the shared bucket's queue if one was\r\n // discovered while it waited.\r\n return this.#scheduler.runResolved(\r\n () => this.#limiter.resolveBucketKey(route.route, route.major),\r\n options.signal,\r\n path,\r\n (bucketKey, release) =>\r\n this.#attempts<T>(\r\n route,\r\n requestPath,\r\n body,\r\n options,\r\n bucketKey,\r\n release,\r\n ),\r\n );\r\n }\r\n /**\r\n * Runs the retry loop for one scheduled request: acquire limits, send,\r\n * record what the response says, decode, and decide whether to try again.\r\n */\r\n async #attempts<T>(\r\n route: RouteKey,\r\n requestPath: string,\r\n body: unknown,\r\n options: RequestData,\r\n initialBucketKey: string,\r\n release: () => void,\r\n ): Promise<T> {\r\n const { method, path } = route;\r\n let bucketKey = initialBucketKey;\r\n for (\r\n let attempt = 0;\r\n attempt <= this.#retryPolicy.maxRetries;\r\n attempt++\r\n ) {\r\n await this.#limiter.acquire(bucketKey, options.signal, path);\r\n // The reservation already claimed this request's unit, so once the\r\n // bucket's window is known the next request need not wait for our\r\n // response. An unknown bucket stays serial until a response\r\n // reveals its limit.\r\n if (this.#concurrentBuckets) {\r\n const bucket = await this.#limiter.store.getBucket(bucketKey);\r\n if (bucket && bucket.resetAt > Date.now()) release();\r\n }\r\n this.#emit(this.#hooks.onRequest, { method, path, attempt });\r\n const requestStart = Date.now();\r\n let response: Response;\r\n try {\r\n response = await this.#transport.send({\r\n method,\r\n path: requestPath,\r\n headers: this.#headers(body, options),\r\n body: this.#encodeBody(body),\r\n signal: options.signal,\r\n });\r\n } catch (error) {\r\n if (error instanceof RESTError) throw error;\r\n if (options.signal?.aborted)\r\n throw abortError(path, options.signal.reason);\r\n const failure =\r\n error instanceof TransportError\r\n ? error\r\n : new TransportError(\r\n \"Discord REST request failed\",\r\n false,\r\n error,\r\n );\r\n if (\r\n !failure.timedOut &&\r\n attempt < this.#retryPolicy.maxRetries &&\r\n this.#retryPolicy.shouldRetry(method, 0)\r\n ) {\r\n await sleep(\r\n this.#retryPolicy.getDelay(attempt),\r\n options.signal,\r\n path,\r\n );\r\n continue;\r\n }\r\n throw new RESTError(failure.message, 0, undefined, undefined, {\r\n method,\r\n path,\r\n cause: failure.cause ?? failure,\r\n kind: failure.timedOut ? \"timeout\" : \"network\",\r\n });\r\n }\r\n this.#emit(this.#hooks.onResponse, {\r\n method,\r\n path,\r\n status: response.status,\r\n durationMs: Date.now() - requestStart,\r\n });\r\n bucketKey = await this.#limiter.applyResponse(\r\n response,\r\n bucketKey,\r\n route.route,\r\n route.major,\r\n );\r\n const payload = await this.#decoder.read(response);\r\n if (response.ok)\r\n return (response.status === 204 ? undefined : payload) as T;\r\n\r\n const data = this.#decoder.errorData(payload);\r\n const retryAfter =\r\n response.status === 429\r\n ? this.#decoder.retryAfter(response, data)\r\n : undefined;\r\n if (data.global && retryAfter !== undefined)\r\n await this.#limiter.noteGlobalReset(\r\n Date.now() + retryAfter * 1000,\r\n );\r\n // Fire for ANY 429, including a global limit that arrives without a\r\n // Retry-After header; fall back to 1s in that case.\r\n if (response.status === 429)\r\n this.#emit(this.#hooks.onRateLimit, {\r\n method,\r\n path,\r\n retryAfterMs: (retryAfter ?? 1) * 1000,\r\n global: data.global ?? false,\r\n bucket: await this.#limiter.store.getBucketHash(\r\n route.route,\r\n ),\r\n });\r\n if (\r\n attempt < this.#retryPolicy.maxRetries &&\r\n this.#retryPolicy.shouldRetry(method, response.status)\r\n ) {\r\n const delay = this.#retryPolicy.getDelay(attempt, retryAfter);\r\n this.#emit(this.#hooks.onRetry, {\r\n method,\r\n path,\r\n attempt,\r\n status: response.status,\r\n delayMs: delay,\r\n });\r\n await sleep(delay, options.signal, path);\r\n continue;\r\n }\r\n throw new RESTError(\r\n data.message ??\r\n response.statusText ??\r\n `Discord REST request failed with status ${response.status}`,\r\n response.status,\r\n data.code,\r\n payload,\r\n { method, path },\r\n );\r\n }\r\n throw new RESTError(\r\n \"Discord REST request exhausted its retry attempts\",\r\n 0,\r\n undefined,\r\n undefined,\r\n { method, path },\r\n );\r\n }\r\n /** Builds the header set for one attempt; library headers win over caller headers. */\r\n #headers(body: unknown, options: RequestData): Record<string, string> {\r\n const isFormData =\r\n typeof FormData !== \"undefined\" && body instanceof FormData;\r\n const headers: Record<string, string> = { ...options.headers };\r\n // Header names are case-insensitive: drop the caller's spelling first,\r\n // or `authorization` and `Authorization` are joined into one value.\r\n const set = (name: string, value: string): void => {\r\n for (const key of Object.keys(headers))\r\n if (key.toLowerCase() === name.toLowerCase())\r\n delete headers[key];\r\n headers[name] = value;\r\n };\r\n if (options.auth !== false && this.#token)\r\n set(\"Authorization\", `Bot ${this.#token}`);\r\n set(\"User-Agent\", USER_AGENT);\r\n if (options.reason !== undefined)\r\n set(\"X-Audit-Log-Reason\", encodeURIComponent(options.reason));\r\n if (!isFormData) set(\"Content-Type\", \"application/json\");\r\n return headers;\r\n }\r\n /** Encodes a body as multipart (passed through) or JSON. */\r\n #encodeBody(body: unknown): BodyInit | undefined {\r\n if (typeof FormData !== \"undefined\" && body instanceof FormData)\r\n return body;\r\n return body === undefined ? undefined : JSON.stringify(body);\r\n }\r\n /**\r\n * Normalizes a verb helper's second argument into `(body, options)`.\r\n * Supports both `verb(path, rawBody, options?)` (Lunibee-canonical positional) and the\r\n * Discord.js-familiar `verb(path, { body, query, headers, reason, files })` wrapper.\r\n */\r\n #dispatch<T>(\r\n method: string,\r\n path: string,\r\n bodyOrOptions?: unknown,\r\n options?: RequestData,\r\n ): Promise<T> {\r\n if (options === undefined && isRequestData(bodyOrOptions))\r\n return this.request<T>(\r\n method,\r\n path,\r\n bodyOrOptions.body,\r\n bodyOrOptions,\r\n );\r\n return this.request<T>(method, path, bodyOrOptions, options);\r\n }\r\n /** Sends a GET request. @param path API path. @param options Request options (`query`, `headers`, `signal`, …). @returns Decoded response. @throws {RESTError} When the request fails. */\r\n public get<T>(path: string, options?: RequestData): Promise<T> {\r\n return this.request<T>(\"GET\", path, options?.body, options);\r\n }\r\n /** Sends a POST request. Accepts a raw body (`post(path, body)`) or a Discord.js-familiar `post(path, { body })`. @param path API path. @param body Optional JSON body, or a `RequestData` wrapper. @param options Request options. @returns Decoded response. @throws {RESTError} When the request fails. */\r\n public post<T>(path: string, options: RequestData): Promise<T>;\r\n public post<T>(\r\n path: string,\r\n body?: unknown,\r\n options?: RequestData,\r\n ): Promise<T>;\r\n public post<T>(\r\n path: string,\r\n body?: unknown,\r\n options?: RequestData,\r\n ): Promise<T> {\r\n return this.#dispatch<T>(\"POST\", path, body, options);\r\n }\r\n /** Sends a PATCH request. Accepts a raw body (`patch(path, body)`) or a Discord.js-familiar `patch(path, { body })`. @param path API path. @param body Optional JSON body, or a `RequestData` wrapper. @param options Request options. @returns Decoded response. @throws {RESTError} When the request fails. */\r\n public patch<T>(path: string, options: RequestData): Promise<T>;\r\n public patch<T>(\r\n path: string,\r\n body?: unknown,\r\n options?: RequestData,\r\n ): Promise<T>;\r\n public patch<T>(\r\n path: string,\r\n body?: unknown,\r\n options?: RequestData,\r\n ): Promise<T> {\r\n return this.#dispatch<T>(\"PATCH\", path, body, options);\r\n }\r\n /** Sends a PUT request. Accepts a raw body (`put(path, body)`) or a Discord.js-familiar `put(path, { body })`. @param path API path. @param body Optional JSON body, or a `RequestData` wrapper. @param options Request options. @returns Decoded response. @throws {RESTError} When the request fails. */\r\n public put<T>(path: string, options: RequestData): Promise<T>;\r\n public put<T>(\r\n path: string,\r\n body?: unknown,\r\n options?: RequestData,\r\n ): Promise<T>;\r\n public put<T>(\r\n path: string,\r\n body?: unknown,\r\n options?: RequestData,\r\n ): Promise<T> {\r\n return this.#dispatch<T>(\"PUT\", path, body, options);\r\n }\r\n /** Sends a DELETE request. @param path API path. @param options Request options (`reason`, `headers`, `signal`, …). @returns Decoded response. @throws {RESTError} When the request fails. */\r\n public delete<T>(path: string, options?: RequestData): Promise<T> {\r\n return this.request<T>(\"DELETE\", path, options?.body, options);\r\n }\r\n /**\r\n * Builds a multipart form with a JSON payload and file attachments.\r\n */\r\n #fileForm(payload: unknown, files: RESTFileAttachment[]): FormData {\r\n const form = new FormData();\r\n form.append(\"payload_json\", JSON.stringify(payload));\r\n for (let i = 0; i < files.length; i++) {\r\n const file = files[i]!;\r\n const blob =\r\n file.data instanceof Blob\r\n ? file.data\r\n : new Blob([file.data as ArrayBuffer], {\r\n type: file.contentType ?? \"application/octet-stream\",\r\n });\r\n form.append(`files[${i}]`, blob, file.name);\r\n }\r\n return form;\r\n }\r\n\r\n /**\r\n * Sends a multipart/form-data POST request for file uploads.\r\n * Attaches a JSON payload as `payload_json` and files as additional fields.\r\n * @param path API path.\r\n * @param payload JSON payload (e.g. message content, embeds).\r\n * @param files Array of file attachments.\r\n * @param options Cancellation options.\r\n * @returns Decoded response.\r\n * @throws {RESTError} When the request fails.\r\n */\r\n public postWithFiles<T>(\r\n path: string,\r\n payload: unknown,\r\n files: RESTFileAttachment[],\r\n options?: RESTRequestOptions,\r\n ): Promise<T> {\r\n return this.request<T>(\r\n \"POST\",\r\n path,\r\n this.#fileForm(payload, files),\r\n options,\r\n );\r\n }\r\n\r\n /**\r\n * Sends a multipart/form-data PATCH request for editing messages with files.\r\n * @param path API path.\r\n * @param payload JSON payload.\r\n * @param files Array of file attachments.\r\n * @param options Cancellation options.\r\n * @returns Decoded response.\r\n * @throws {RESTError} When the request fails.\r\n */\r\n public patchWithFiles<T>(\r\n path: string,\r\n payload: unknown,\r\n files: RESTFileAttachment[],\r\n options?: RESTRequestOptions,\r\n ): Promise<T> {\r\n return this.request<T>(\r\n \"PATCH\",\r\n path,\r\n this.#fileForm(payload, files),\r\n options,\r\n );\r\n }\r\n /** Dispatches a lifecycle hook in isolation: deferred to a microtask so it\r\n * cannot block the request path, with any thrown error swallowed so a faulty\r\n * hook cannot reject the request. @param hook Optional callback. @param ctx Event context. */\r\n #emit<C>(hook: ((ctx: C) => void) | undefined, ctx: C): void {\r\n if (!hook) return;\r\n const withPath = ctx as { path?: unknown };\r\n if (typeof withPath.path === \"string\")\r\n ctx = { ...ctx, path: redactPath(withPath.path) };\r\n Promise.resolve()\r\n .then(() => hook(ctx))\r\n .catch(() => {});\r\n }\r\n}\r\n\r\nexport { Routes } from \"./routes.js\";\r\nexport {\r\n RESTError,\r\n abortError,\r\n redactPath,\r\n type RESTErrorKind,\r\n} from \"./errors.js\";\r\nexport { RESTErrorCode } from \"./error-codes.js\";\r\nexport {\r\n createRouteKey,\r\n normalizeRoutePath,\r\n majorParameter,\r\n scopeBucket,\r\n serializeQuery,\r\n type RouteKey,\r\n type RESTQuery,\r\n} from \"./route.js\";\r\nexport { RequestScheduler } from \"./scheduler.js\";\r\nexport { RateLimiter } from \"./limiter.js\";\r\nexport {\r\n HttpTransport,\r\n TransportError,\r\n type TransportRequest,\r\n type FetchLike,\r\n} from \"./transport.js\";\r\nexport { ResponseDecoder, type DecodedError } from \"./decoder.js\";\r\nexport {\r\n type RateLimitStore,\r\n type BucketState,\r\n type Reservation,\r\n MemoryRateLimitStore,\r\n} from \"./store.js\";\r\nexport {\r\n RedisRateLimitStore,\r\n type RedisRateLimitStoreOptions,\r\n type MinimalRedisClient,\r\n} from \"./redis.js\";\r\n\r\nexport {\r\n WebhookClient,\r\n type WebhookClientOptions,\r\n type WebhookMessageOptions,\r\n} from \"./webhook.js\";\r\n\r\n/**\r\n * Discord.js-familiar alias for {@link RESTError}. `@discordjs/rest` throws `DiscordAPIError`\r\n * on a Discord-rejected request; Lunibee keeps `RESTError` as the canonical class and exports\r\n * this alias so Discord.js-shaped `catch (err) { if (err instanceof DiscordAPIError) … }` works.\r\n */\r\nexport { RESTError as DiscordAPIError };\r\n",
|
|
21
|
+
"/** Common Discord snowflake-backed structure. */\r\nexport class BaseStructure {\r\n public readonly id: string;\r\n public constructor(id: string) {\r\n if (!/^\\d{1,20}$/.test(id))\r\n throw new TypeError(\r\n \"A Discord structure requires a valid snowflake ID.\",\r\n );\r\n this.id = id;\r\n }\r\n /** Returns the snowflake ID as a string. */\r\n public toString(): string {\r\n return this.id;\r\n }\r\n /** Returns the timestamp this snowflake was created at. */\r\n public get createdAt(): Date {\r\n return new Date(Number((BigInt(this.id) >> 22n) + 1420070400000n));\r\n }\r\n}\r\n\r\nexport interface ResourceContext {\r\n sendMessage(\r\n channelId: string,\r\n options: Record<string, unknown> & { content?: string },\r\n ): Promise<import(\"./index.js\").Message>;\r\n editMessage(\r\n channelId: string,\r\n messageId: string,\r\n options: Record<string, unknown> & { content?: string },\r\n ): Promise<import(\"./index.js\").Message>;\r\n deleteMessage(\r\n channelId: string,\r\n messageId: string,\r\n reason?: string,\r\n ): Promise<void>;\r\n crosspostMessage(\r\n channelId: string,\r\n messageId: string,\r\n ): Promise<import(\"./index.js\").Message>;\r\n editChannel?(\r\n channelId: string,\r\n options: Record<string, unknown>,\r\n ): Promise<import(\"./base.js\").Channel>;\r\n deleteChannel?(channelId: string, reason?: string): Promise<void>;\r\n addReaction?(\r\n channelId: string,\r\n messageId: string,\r\n emoji: string,\r\n ): Promise<void>;\r\n removeOwnReaction?(\r\n channelId: string,\r\n messageId: string,\r\n emoji: string,\r\n ): Promise<void>;\r\n removeReaction?(\r\n channelId: string,\r\n messageId: string,\r\n emoji: string,\r\n userId: string,\r\n ): Promise<void>;\r\n removeAllReactions?(channelId: string, messageId: string): Promise<void>;\r\n pinMessage?(\r\n channelId: string,\r\n messageId: string,\r\n reason?: string,\r\n ): Promise<void>;\r\n unpinMessage?(\r\n channelId: string,\r\n messageId: string,\r\n reason?: string,\r\n ): Promise<void>;\r\n /**\r\n * A member's permissions from cached state: guild-level, or channel-level\r\n * (with overwrites) when a channel ID is given. Null when the guild (or\r\n * channel) is not cached.\r\n */\r\n memberPermissions?(\r\n guildId: string,\r\n memberId: string,\r\n roleIds: readonly string[],\r\n channelId?: string,\r\n timedOutUntil?: Date | null,\r\n ): import(\"@lunibee/core\").PermissionSet | null;\r\n kickMember?(\r\n guildId: string,\r\n userId: string,\r\n reason?: string,\r\n ): Promise<void>;\r\n banMember?(\r\n guildId: string,\r\n userId: string,\r\n options?: { reason?: string; deleteMessageSeconds?: number },\r\n ): Promise<void>;\r\n editMember?(\r\n guildId: string,\r\n userId: string,\r\n options: Record<string, unknown>,\r\n reason?: string,\r\n ): Promise<import(\"./resources.js\").GuildMember>;\r\n addMemberRole?(\r\n guildId: string,\r\n userId: string,\r\n roleId: string,\r\n reason?: string,\r\n ): Promise<void>;\r\n removeMemberRole?(\r\n guildId: string,\r\n userId: string,\r\n roleId: string,\r\n reason?: string,\r\n ): Promise<void>;\r\n /** Collects the client's interactions (a `Collector` over `interactionCreate`). Used by message and interaction collectors. */\r\n collectInteractions?(\r\n options: import(\"@lunibee/core\").CollectorOptions<\r\n import(\"./interactions.js\").Interaction\r\n >,\r\n ): import(\"@lunibee/core\").Collector<\r\n string,\r\n import(\"./interactions.js\").Interaction\r\n >;\r\n editPermissionOverwrite?(\r\n channelId: string,\r\n targetId: string,\r\n changes: PermissionOverwriteChanges,\r\n options?: { type?: 0 | 1; reason?: string },\r\n ): Promise<void>;\r\n}\r\n\r\n/**\r\n * Permissions to change on one overwrite: `true` allows, `false` denies,\r\n * `null` goes back to inheriting. Permissions not named keep their state.\r\n */\r\nexport type PermissionOverwriteChanges = Partial<\r\n Record<import(\"@lunibee/core\").PermissionName, boolean | null>\r\n>;\r\n\r\n// ─── CDN helpers ──────────────────────────────────────────────────────────────\r\n\r\nexport const CDN_BASE = \"https://cdn.discordapp.com\";\r\n\r\n/** Options for CDN image URLs. */\r\nexport interface ImageURLOptions {\r\n extension?: \"png\" | \"jpg\" | \"webp\" | \"gif\" | \"jpeg\";\r\n size?: 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096;\r\n forceStatic?: boolean;\r\n}\r\n\r\n/** Builds a Discord CDN asset URL from a directory path and asset hash, applying\r\n * animated-hash (`a_`) gif detection, extension and size options. Shared by all\r\n * hash-backed asset accessors (user/member/role/webhook) to avoid duplicating the logic.\r\n * @param path CDN directory path, e.g. `/role-icons/{id}`. @param hash Asset hash. @param options Image URL options. */\r\nexport function cdnURL(\r\n path: string,\r\n hash: string,\r\n options: ImageURLOptions = {},\r\n): string {\r\n const isAnimated = hash.startsWith(\"a_\") && !options.forceStatic;\r\n const ext = options.extension ?? (isAnimated ? \"gif\" : \"png\");\r\n const size = options.size ? `?size=${options.size}` : \"\";\r\n // Encoded, so a hash holding `/`, `?` or `#` cannot change the CDN path.\r\n return `${CDN_BASE}${path}/${encodeURIComponent(hash)}.${ext}${size}`;\r\n}\r\n\r\n// ─── User ─────────────────────────────────────────────────────────────────────\r\n\r\nexport class User extends BaseStructure {\r\n public username: string;\r\n public globalName: string | null;\r\n public avatar: string | null;\r\n public bot: boolean;\r\n public system: boolean;\r\n public flags: number;\r\n public discriminator: string | null;\r\n public constructor(data: import(\"@lunibee/types\").UserData) {\r\n super(data.id);\r\n if (!data.username)\r\n throw new TypeError(\"A Discord user requires a username.\");\r\n this.username = data.username;\r\n this.globalName = data.global_name ?? null;\r\n this.avatar = data.avatar ?? null;\r\n this.bot = data.bot ?? false;\r\n this.system = data.system ?? false;\r\n this.flags = data.public_flags ?? 0;\r\n this.discriminator =\r\n data.discriminator && data.discriminator !== \"0\"\r\n ? data.discriminator\r\n : null;\r\n }\r\n /** Effective display name — global name, falling back to username. */\r\n public get displayName(): string {\r\n return this.globalName ?? this.username;\r\n }\r\n /** Returns the user's avatar URL, or null if they have no avatar. */\r\n public avatarURL(options: ImageURLOptions = {}): string | null {\r\n if (!this.avatar) return null;\r\n return cdnURL(`/avatars/${this.id}`, this.avatar, options);\r\n }\r\n /** Returns the default avatar URL based on the user's discriminator/snowflake. */\r\n public defaultAvatarURL(): string {\r\n const index = this.discriminator\r\n ? Number(this.discriminator) % 5\r\n : Number((BigInt(this.id) >> 22n) % 6n);\r\n return `${CDN_BASE}/embed/avatars/${index}.png`;\r\n }\r\n /** Returns the avatar URL if available, falling back to the default avatar URL. */\r\n public displayAvatarURL(options: ImageURLOptions = {}): string {\r\n return this.avatarURL(options) ?? this.defaultAvatarURL();\r\n }\r\n /** Returns the Discord mention string. Used automatically in template literals. */\r\n public override toString(): string {\r\n return `<@${this.id}>`;\r\n }\r\n}\r\n\r\n// ─── Channel ──────────────────────────────────────────────────────────────────\r\n\r\nexport class Channel extends BaseStructure {\r\n public type: number;\r\n public name?: string | null;\r\n public guildId?: string;\r\n public topic?: string | null;\r\n public parentId?: string | null;\r\n public nsfw?: boolean;\r\n public rateLimitPerUser?: number;\r\n public position?: number;\r\n /** Role and member permission overwrites (empty for DMs and when not provided). */\r\n public permissionOverwrites: import(\"@lunibee/types\").APIOverwrite[];\r\n readonly #context?: ResourceContext;\r\n\r\n /** Creates a channel structure from Discord channel data. */\r\n public constructor(\r\n data: import(\"@lunibee/types\").APIChannel,\r\n context?: ResourceContext,\r\n ) {\r\n super(data.id);\r\n if (!Number.isInteger(data.type) || data.type < 0)\r\n throw new RangeError(\r\n \"A Discord channel requires a valid channel type.\",\r\n );\r\n this.type = data.type;\r\n this.name = data.name;\r\n this.guildId = data.guild_id;\r\n this.topic = data.topic;\r\n this.parentId = data.parent_id;\r\n this.nsfw = data.nsfw;\r\n this.rateLimitPerUser = data.rate_limit_per_user;\r\n this.position = data.position;\r\n this.permissionOverwrites = (data.permission_overwrites ?? []).map(\r\n (overwrite) => ({ ...overwrite }),\r\n );\r\n this.#context = context;\r\n }\r\n\r\n /** Sends a message to this channel. @param options Message payload. @returns The created message. @throws {Error} If the channel is not attached to a client. */\r\n public send(\r\n options: Record<string, unknown> & { content?: string },\r\n ): Promise<import(\"./index.js\").Message> {\r\n if (!this.#context)\r\n throw new Error(\"This channel is not attached to a client.\");\r\n return this.#context.sendMessage(this.id, options);\r\n }\r\n\r\n /** @deprecated Use {@link Channel.send}. Removed in 0.3.0. */\r\n public sendMessage(\r\n options: Record<string, unknown> & { content?: string },\r\n ): Promise<import(\"./index.js\").Message> {\r\n return this.send(options);\r\n }\r\n\r\n /** Edits this channel. @param options Channel fields to change. @returns The updated channel. @throws {Error} If the channel is not attached to a client. */\r\n public edit(options: Record<string, unknown>): Promise<Channel> {\r\n if (!this.#context?.editChannel)\r\n throw new Error(\"This channel is not attached to a client.\");\r\n return this.#context.editChannel(this.id, options);\r\n }\r\n\r\n /** Changes only this channel's name. @param name New channel name. @returns The updated channel. @throws {TypeError} If the name is empty. @throws {Error} If the channel is not attached to a client. */\r\n public editName(name: string): Promise<Channel> {\r\n if (!name.trim()) throw new TypeError(\"Channel name cannot be empty.\");\r\n return this.edit({ name });\r\n }\r\n\r\n /** Changes only this channel's topic. @param topic New topic, or null to clear it. @returns The updated channel. @throws {Error} If the channel is not attached to a client. */\r\n public editTopic(topic: string | null): Promise<Channel> {\r\n return this.edit({ topic });\r\n }\r\n\r\n /** Moves this channel to another parent category. @param parentId Parent category ID, or null to remove the parent. @returns The updated channel. @throws {Error} If the channel is not attached to a client. */\r\n /**\r\n * Changes some permissions of one overwrite and keeps the rest: `true`\r\n * allows, `false` denies, `null` resets to inherited.\r\n * @param targetId Role or member ID. @param changes Permissions to change.\r\n * @param options `type` (0 role, 1 member) when the overwrite does not exist yet; audit-log `reason`.\r\n * @example channel.editPermissionOverwrite(userId, { ViewChannel: true, SendMessages: false }, { type: 1 })\r\n */\r\n public editPermissionOverwrite(\r\n targetId: string,\r\n changes: PermissionOverwriteChanges,\r\n options?: { type?: 0 | 1; reason?: string },\r\n ): Promise<void> {\r\n if (!this.#context?.editPermissionOverwrite)\r\n throw new Error(\"This channel is not attached to a client.\");\r\n return this.#context.editPermissionOverwrite(\r\n this.id,\r\n targetId,\r\n changes,\r\n options,\r\n );\r\n }\r\n\r\n public editParent(parentId: string | null): Promise<Channel> {\r\n return this.edit({ parent_id: parentId });\r\n }\r\n\r\n /** Deletes this channel. @param reason Audit-log reason. @returns A promise fulfilled when Discord confirms deletion. @throws {Error} If the channel is not attached to a client. */\r\n public delete(reason?: string): Promise<void> {\r\n if (!this.#context?.deleteChannel)\r\n throw new Error(\"This channel is not attached to a client.\");\r\n return this.#context.deleteChannel(this.id, reason);\r\n }\r\n\r\n /** Updates this channel using the same resource operation as edit. @param options Channel fields to change. @returns The updated channel. @throws {Error} If the channel is not attached to a client. */\r\n public update(options: Record<string, unknown>): Promise<Channel> {\r\n return this.edit(options);\r\n }\r\n\r\n /** Whether this is a thread (announcement, public or private). */\r\n public isThread(): boolean {\r\n return this.type === 10 || this.type === 11 || this.type === 12;\r\n }\r\n\r\n /** Whether messages can be sent in this channel (text, DM, announcement, voice, stage, threads). */\r\n public isTextBased(): boolean {\r\n return [0, 1, 2, 3, 5, 10, 11, 12, 13].includes(this.type);\r\n }\r\n\r\n /** Whether this is a voice or stage channel. */\r\n public isVoiceBased(): boolean {\r\n return this.type === 2 || this.type === 13;\r\n }\r\n\r\n /** Whether this is a direct-message channel (DM or group DM). */\r\n public isDMBased(): boolean {\r\n return this.type === 1 || this.type === 3;\r\n }\r\n\r\n /** Returns the Discord channel mention string. Used automatically in template literals. */\r\n public override toString(): string {\r\n return `<#${this.id}>`;\r\n }\r\n}\r\n\r\n// ─── Guild ────────────────────────────────────────────────────────────────────\r\n\r\nexport class Guild extends BaseStructure {\r\n public name: string;\r\n public icon: string | null;\r\n public splash: string | null;\r\n public banner: string | null;\r\n public description: string | null;\r\n public preferredLocale: string;\r\n public ownerId?: string;\r\n public features: string[];\r\n public verificationLevel: number;\r\n public premiumTier: number;\r\n public premiumSubscriptionCount: number;\r\n public memberCount?: number;\r\n public approximateMemberCount?: number;\r\n public approximatePresenceCount?: number;\r\n public vanityUrlCode: string | null;\r\n public nsfwLevel: number;\r\n public discoverySplash: string | null;\r\n /** ID of the rules channel for Community guilds. */\r\n public rulesChannelId: string | null;\r\n /** ID of the system messages channel. */\r\n public systemChannelId: string | null;\r\n /** Bitfield of system channel flags. */\r\n public systemChannelFlags: number;\r\n /** Maximum number of members the guild can have. */\r\n public maxMembers: number;\r\n /** Required MFA level for administrators. */\r\n public mfaLevel: number;\r\n /** Explicit content filter level. */\r\n public explicitContentFilter: number;\r\n /** Default notification level for new members. */\r\n public defaultMessageNotifications: number;\r\n /** AFK voice channel, or null. */\r\n public afkChannelId: string | null;\r\n /** Seconds before a silent member is moved to the AFK channel. */\r\n public afkTimeout?: number;\r\n /** Whether the server widget is on. */\r\n public widgetEnabled: boolean;\r\n /** Channel the widget invites to, or null. */\r\n public widgetChannelId: string | null;\r\n /** Application that created the guild, if a bot did. */\r\n public applicationId: string | null;\r\n /** Channel for Discord's community updates, or null. */\r\n public publicUpdatesChannelId: string | null;\r\n /** Channel for safety alerts, or null. */\r\n public safetyAlertsChannelId: string | null;\r\n /** Maximum presences (null for the default limit). */\r\n public maxPresences: number | null;\r\n /** Maximum users in a video channel. */\r\n public maxVideoChannelUsers?: number;\r\n\r\n public constructor(data: import(\"@lunibee/types\").APIGuild) {\r\n super(data.id);\r\n if (!data.name) throw new TypeError(\"A Discord guild requires a name.\");\r\n this.name = data.name;\r\n this.icon = data.icon ?? null;\r\n this.splash = data.splash ?? null;\r\n this.banner = data.banner ?? null;\r\n this.description = data.description ?? null;\r\n this.preferredLocale = data.preferred_locale ?? \"en-US\";\r\n this.ownerId = data.owner_id;\r\n this.features = data.features ?? [];\r\n this.verificationLevel = data.verification_level ?? 0;\r\n this.premiumTier = data.premium_tier ?? 0;\r\n this.premiumSubscriptionCount = data.premium_subscription_count ?? 0;\r\n this.memberCount = data.member_count ?? data.approximate_member_count;\r\n this.approximateMemberCount = data.approximate_member_count;\r\n this.approximatePresenceCount = data.approximate_presence_count;\r\n this.vanityUrlCode = data.vanity_url_code ?? null;\r\n this.nsfwLevel = data.nsfw_level ?? 0;\r\n this.discoverySplash = data.discovery_splash ?? null;\r\n this.rulesChannelId = data.rules_channel_id ?? null;\r\n this.systemChannelId = data.system_channel_id ?? null;\r\n this.systemChannelFlags = data.system_channel_flags ?? 0;\r\n this.maxMembers = data.max_members ?? 0;\r\n this.mfaLevel = data.mfa_level ?? 0;\r\n this.explicitContentFilter = data.explicit_content_filter ?? 0;\r\n this.defaultMessageNotifications =\r\n data.default_message_notifications ?? 0;\r\n this.afkChannelId = data.afk_channel_id ?? null;\r\n this.afkTimeout = data.afk_timeout;\r\n this.widgetEnabled = data.widget_enabled ?? false;\r\n this.widgetChannelId = data.widget_channel_id ?? null;\r\n this.applicationId = data.application_id ?? null;\r\n this.publicUpdatesChannelId = data.public_updates_channel_id ?? null;\r\n this.safetyAlertsChannelId = data.safety_alerts_channel_id ?? null;\r\n this.maxPresences = data.max_presences ?? null;\r\n this.maxVideoChannelUsers = data.max_video_channel_users;\r\n }\r\n\r\n /** Returns the guild icon URL, or null if no icon is set. */\r\n public iconURL(options: ImageURLOptions = {}): string | null {\r\n if (!this.icon) return null;\r\n return cdnURL(`/icons/${this.id}`, this.icon, options);\r\n }\r\n\r\n /** Returns the guild splash URL, or null if none. */\r\n public splashURL(options: ImageURLOptions = {}): string | null {\r\n if (!this.splash) return null;\r\n return cdnURL(`/splashes/${this.id}`, this.splash, options);\r\n }\r\n\r\n /** Returns the guild banner URL, or null if none. */\r\n public bannerURL(options: ImageURLOptions = {}): string | null {\r\n if (!this.banner) return null;\r\n return cdnURL(`/banners/${this.id}`, this.banner, options);\r\n }\r\n\r\n /** Returns the guild discovery splash URL, or null if none. */\r\n public discoverySplashURL(options: ImageURLOptions = {}): string | null {\r\n if (!this.discoverySplash) return null;\r\n return cdnURL(\r\n `/discovery-splashes/${this.id}`,\r\n this.discoverySplash,\r\n options,\r\n );\r\n }\r\n\r\n /** Returns a widget image URL for the guild.\r\n * @param style Widget style: shield (default), banner1, banner2, banner3, banner4.\r\n */\r\n public widgetImageURL(\r\n style:\r\n \"shield\" | \"banner1\" | \"banner2\" | \"banner3\" | \"banner4\" = \"shield\",\r\n ): string {\r\n return `https://discord.com/api/guilds/${this.id}/widget.png?style=${style}`;\r\n }\r\n\r\n /** Whether the guild has a given feature flag. @param feature Feature string, e.g. \"COMMUNITY\". */\r\n public hasFeature(feature: string): boolean {\r\n return this.features.includes(feature);\r\n }\r\n\r\n /** Whether the guild is a Community server. */\r\n public get isCommunity(): boolean {\r\n return this.hasFeature(\"COMMUNITY\");\r\n }\r\n\r\n /** Whether the guild is an official Discord Partner. */\r\n public get isPartnered(): boolean {\r\n return this.hasFeature(\"PARTNERED\");\r\n }\r\n\r\n /** Whether the guild is verified by Discord. */\r\n public get isVerified(): boolean {\r\n return this.hasFeature(\"VERIFIED\");\r\n }\r\n\r\n /** Whether the guild has any active boost subscriptions. */\r\n public get isBoosted(): boolean {\r\n return this.premiumSubscriptionCount > 0;\r\n }\r\n\r\n /** Alias for premiumTier — the guild's current Nitro boost level (0–3). */\r\n public get boostLevel(): number {\r\n return this.premiumTier;\r\n }\r\n\r\n /** Whether the guild has a vanity URL. */\r\n public get hasVanityUrl(): boolean {\r\n return this.vanityUrlCode !== null;\r\n }\r\n\r\n /** Returns the guild's vanity invite URL, or null if none. */\r\n public get vanityURL(): string | null {\r\n return this.vanityUrlCode\r\n ? `https://discord.gg/${this.vanityUrlCode}`\r\n : null;\r\n }\r\n\r\n /** Returns a human-readable string representation. */\r\n public override toString(): string {\r\n return this.name;\r\n }\r\n}\r\n",
|
|
22
|
+
"import { BaseStructure, Channel, User, CDN_BASE, cdnURL } from \"./base.js\";\r\nimport { PermissionsBitField } from \"@lunibee/core\";\r\nimport type { ImageURLOptions, ResourceContext } from \"./base.js\";\r\n\r\n/** Parses a Discord ISO timestamp into a Date, returning null for absent or invalid values. */\r\nfunction toDateOrNull(value?: string | null): Date | null {\r\n if (!value) return null;\r\n const date = new Date(value);\r\n return Number.isNaN(date.getTime()) ? null : date;\r\n}\r\n\r\n// ─── GuildMember ───────────────────────────────────────────────────────────────\r\n\r\n/** A Discord guild member. */\r\nexport class GuildMember {\r\n /** User represented by the member. */\r\n public readonly user: User;\r\n /** Guild containing the member. */\r\n public readonly guildId: string;\r\n /** Nickname, if configured. */\r\n public nickname: string | null;\r\n /** Role IDs assigned to the member. */\r\n public readonly roleIds: string[];\r\n /** Whether the member is pending membership screening. */\r\n public pending: boolean;\r\n /** Member join timestamp. */\r\n public joinedAt?: Date;\r\n /** Member-specific avatar hash, if set. */\r\n public avatarHash: string | null;\r\n /** When the member started boosting the guild. */\r\n public premiumSince: Date | null;\r\n /** When the member's timeout expires (null if not timed out). */\r\n public timedOutUntil: Date | null;\r\n /** Member flags bitfield. */\r\n public flags: number;\r\n /** Permissions Discord sent with the member (interactions only). */\r\n readonly #suppliedPermissions?: PermissionsBitField;\r\n readonly #context?: ResourceContext;\r\n\r\n /** Creates a guild member from Discord data. @param data Discord guild-member payload. @throws {TypeError} If the guild ID is invalid. @throws {RangeError} If joined_at is invalid. */\r\n public constructor(\r\n data: {\r\n user: {\r\n id: string;\r\n username: string;\r\n global_name?: string | null;\r\n avatar?: string | null;\r\n bot?: boolean;\r\n system?: boolean;\r\n public_flags?: number;\r\n discriminator?: string;\r\n };\r\n guild_id: string;\r\n nick?: string | null;\r\n roles?: string[];\r\n pending?: boolean;\r\n joined_at?: string;\r\n permissions?: string;\r\n avatar?: string | null;\r\n premium_since?: string | null;\r\n communication_disabled_until?: string | null;\r\n flags?: number;\r\n },\r\n context?: ResourceContext,\r\n ) {\r\n this.user = new User(data.user);\r\n this.#context = context;\r\n if (!/^\\d{1,20}$/.test(data.guild_id))\r\n throw new TypeError(\"Member guild_id must be a valid snowflake.\");\r\n this.guildId = data.guild_id;\r\n this.nickname = data.nick ?? null;\r\n this.roleIds = [...(data.roles ?? [])];\r\n this.pending = data.pending ?? false;\r\n this.joinedAt = data.joined_at ? new Date(data.joined_at) : undefined;\r\n if (this.joinedAt?.toString() === \"Invalid Date\")\r\n throw new RangeError(\"Member joined_at must be a valid date.\");\r\n if (data.permissions !== undefined)\r\n this.#suppliedPermissions = new PermissionsBitField(\r\n data.permissions,\r\n );\r\n this.avatarHash = data.avatar ?? null;\r\n // Like joinedAt, coerce malformed timestamps to null instead of an Invalid Date.\r\n this.premiumSince = toDateOrNull(data.premium_since);\r\n this.timedOutUntil = toDateOrNull(data.communication_disabled_until);\r\n this.flags = data.flags ?? 0;\r\n }\r\n\r\n /**\r\n * The member's permissions. Discord sends them with interactions (already\r\n * resolved for the channel); anywhere else they are computed at guild\r\n * level from the cached roles each time they are read, so they follow role\r\n * changes. Empty when the guild's roles are not cached.\r\n */\r\n public get permissions(): PermissionsBitField {\r\n if (this.#suppliedPermissions) return this.#suppliedPermissions;\r\n return new PermissionsBitField(\r\n this.#context?.memberPermissions?.(\r\n this.guildId,\r\n this.user.id,\r\n this.roleIds,\r\n undefined,\r\n this.timedOutUntil,\r\n ) ?? 0n,\r\n );\r\n }\r\n\r\n /** The member's permissions in a channel, with its overwrites. Null when the channel or guild is not cached. @param channelId Channel ID. */\r\n public permissionsIn(channelId: string): PermissionsBitField | null {\r\n const computed = this.#context?.memberPermissions?.(\r\n this.guildId,\r\n this.user.id,\r\n this.roleIds,\r\n channelId,\r\n this.timedOutUntil,\r\n );\r\n return computed ? new PermissionsBitField(computed) : null;\r\n }\r\n\r\n #action<K extends keyof ResourceContext>(\r\n name: K,\r\n ): NonNullable<ResourceContext[K]> {\r\n const action = this.#context?.[name];\r\n if (!action)\r\n throw new Error(\"This member is not attached to a client.\");\r\n return action as NonNullable<ResourceContext[K]>;\r\n }\r\n\r\n /** Kicks this member. @param reason Audit-log reason. */\r\n public kick(reason?: string): Promise<void> {\r\n return this.#action(\"kickMember\")(this.guildId, this.user.id, reason);\r\n }\r\n\r\n /** Bans this member. @param options Audit-log reason and seconds of messages to delete. */\r\n public ban(\r\n options: { reason?: string; deleteMessageSeconds?: number } = {},\r\n ): Promise<void> {\r\n return this.#action(\"banMember\")(this.guildId, this.user.id, options);\r\n }\r\n\r\n /** Edits this member (nickname, roles, voice state, timeout). @param options Discord member fields. @param reason Audit-log reason. */\r\n public edit(\r\n options: Record<string, unknown>,\r\n reason?: string,\r\n ): Promise<GuildMember> {\r\n return this.#action(\"editMember\")(\r\n this.guildId,\r\n this.user.id,\r\n options,\r\n reason,\r\n );\r\n }\r\n\r\n /** Times this member out, or clears the timeout with null. @param milliseconds Timeout length (Discord allows up to 28 days). @param reason Audit-log reason. */\r\n public timeout(\r\n milliseconds: number | null,\r\n reason?: string,\r\n ): Promise<GuildMember> {\r\n if (milliseconds !== null && !(milliseconds > 0))\r\n throw new RangeError(\r\n \"Timeout length must be a positive number of milliseconds.\",\r\n );\r\n return this.edit(\r\n {\r\n communication_disabled_until:\r\n milliseconds === null\r\n ? null\r\n : new Date(Date.now() + milliseconds).toISOString(),\r\n },\r\n reason,\r\n );\r\n }\r\n\r\n /** Sets or clears (null) this member's nickname. @param nickname New nickname. @param reason Audit-log reason. */\r\n public setNickname(\r\n nickname: string | null,\r\n reason?: string,\r\n ): Promise<GuildMember> {\r\n return this.edit({ nick: nickname }, reason);\r\n }\r\n\r\n /** Gives this member a role. @param roleId Role ID. @param reason Audit-log reason. */\r\n public addRole(roleId: string, reason?: string): Promise<void> {\r\n return this.#action(\"addMemberRole\")(\r\n this.guildId,\r\n this.user.id,\r\n roleId,\r\n reason,\r\n );\r\n }\r\n\r\n /** Takes a role from this member. @param roleId Role ID. @param reason Audit-log reason. */\r\n public removeRole(roleId: string, reason?: string): Promise<void> {\r\n return this.#action(\"removeMemberRole\")(\r\n this.guildId,\r\n this.user.id,\r\n roleId,\r\n reason,\r\n );\r\n }\r\n\r\n /** Effective member display name — nickname, falling back to user display name. */\r\n public get displayName(): string {\r\n return this.nickname ?? this.user.displayName;\r\n }\r\n\r\n /** Whether this member is currently timed out. */\r\n public get isTimedOut(): boolean {\r\n return this.timedOutUntil !== null && this.timedOutUntil > new Date();\r\n }\r\n\r\n /** Returns the member-specific avatar URL, falling back to the user's avatar, or null if none. */\r\n public avatarURL(options: ImageURLOptions = {}): string | null {\r\n if (this.avatarHash)\r\n return cdnURL(\r\n `/guilds/${this.guildId}/users/${this.user.id}/avatars`,\r\n this.avatarHash,\r\n options,\r\n );\r\n // User always exposes avatarURL(); returns null when the user has no avatar.\r\n return this.user.avatarURL(options);\r\n }\r\n\r\n /** Returns the resolved avatar URL — member avatar, user avatar, or default. */\r\n public displayAvatarURL(options: ImageURLOptions = {}): string {\r\n return this.avatarURL(options) ?? this.user.displayAvatarURL(options);\r\n }\r\n\r\n /** Returns the Discord user mention for this member. */\r\n public toString(): string {\r\n return this.user.toString();\r\n }\r\n}\r\n\r\n// ─── Role ──────────────────────────────────────────────────────────────────────\r\n\r\n/** A Discord guild role. */\r\nexport class Role extends BaseStructure {\r\n /** Role name. */\r\n public name: string;\r\n /** Role color as a 24-bit RGB integer. */\r\n public color: number;\r\n /** Whether the role is hoisted. */\r\n public hoist: boolean;\r\n /** Permission bitfield. */\r\n public permissions: PermissionsBitField;\r\n /** Whether the role is managed by an integration. */\r\n public managed: boolean;\r\n /** Whether the role is mentionable. */\r\n public mentionable: boolean;\r\n /** Role position in the hierarchy. */\r\n public position: number;\r\n /** Unicode emoji used as the role icon, if any. */\r\n public unicodeEmoji: string | null;\r\n /** Hash of the role's custom icon image, if any. */\r\n public iconHash: string | null;\r\n /** Role tags metadata (bot, premium subscriber, etc). */\r\n public tags: Record<string, unknown> | null;\r\n\r\n /** Creates a role from Discord data. @param data Discord role payload. */\r\n public constructor(data: {\r\n id: string;\r\n name: string;\r\n color?: number;\r\n hoist?: boolean;\r\n permissions?: string;\r\n managed?: boolean;\r\n mentionable?: boolean;\r\n position?: number;\r\n unicode_emoji?: string | null;\r\n icon?: string | null;\r\n tags?: Record<string, unknown> | null;\r\n }) {\r\n super(data.id);\r\n if (!data.name) throw new TypeError(\"Role name cannot be empty.\");\r\n this.name = data.name;\r\n this.color = data.color ?? 0;\r\n this.hoist = data.hoist ?? false;\r\n this.permissions = new PermissionsBitField(data.permissions ?? 0n);\r\n this.managed = data.managed ?? false;\r\n this.mentionable = data.mentionable ?? false;\r\n this.position = data.position ?? 0;\r\n this.unicodeEmoji = data.unicode_emoji ?? null;\r\n this.iconHash = data.icon ?? null;\r\n this.tags = data.tags ?? null;\r\n }\r\n\r\n /** Returns the role's color as a `#RRGGBB` hex string. Returns `#000000` for colorless roles. */\r\n public get colorHex(): string {\r\n return `#${this.color.toString(16).padStart(6, \"0\").toUpperCase()}`;\r\n }\r\n\r\n /** Returns the role's custom icon URL, or null if the role has no icon. */\r\n public iconURL(options: ImageURLOptions = {}): string | null {\r\n if (!this.iconHash) return null;\r\n return cdnURL(`/role-icons/${this.id}`, this.iconHash, options);\r\n }\r\n\r\n /** Whether this is the `@everyone` base role (its ID equals the guild ID). */\r\n public isEveryone(guildId: string): boolean {\r\n return this.id === guildId;\r\n }\r\n\r\n /** Discord role mention string. Used automatically in template literals. */\r\n public override toString(): string {\r\n return `<@&${this.id}>`;\r\n }\r\n}\r\n\r\n// ─── TextChannel ──────────────────────────────────────────────────────────────\r\n\r\n/** A Discord text-capable channel. */\r\nexport class TextChannel extends Channel {\r\n /** Creates a text channel from Discord data. @param data Discord channel payload. */\r\n public constructor(\r\n data: {\r\n id: string;\r\n type: number;\r\n name?: string | null;\r\n parent_id?: string | null;\r\n guild_id?: string;\r\n } & Partial<import(\"@lunibee/types\").APIChannel>,\r\n context?: import(\"./base.js\").ResourceContext,\r\n ) {\r\n super(data, context);\r\n }\r\n /** Discord channel mention string. Used automatically in template literals. */\r\n public override toString(): string {\r\n return `<#${this.id}>`;\r\n }\r\n}\r\n\r\n// ─── Invite ───────────────────────────────────────────────────────────────────\r\n\r\n/** A Discord invite link and its metadata. */\r\nexport class Invite {\r\n /** Invite code (the unique part of the URL). */\r\n public readonly code: string;\r\n /** Guild this invite belongs to, if any. */\r\n public readonly guildId: string | null;\r\n /** Channel this invite points to, if any. */\r\n public readonly channelId: string | null;\r\n /** User who created the invite, if available. */\r\n public readonly inviter: User | null;\r\n /** Number of times the invite has been used. */\r\n public uses: number;\r\n /** Maximum number of uses (0 = unlimited). */\r\n public maxUses: number;\r\n /** Duration in seconds until the invite expires (0 = never). */\r\n public maxAge: number;\r\n /** Whether the invite is temporary (kicks uninducted members on disconnect). */\r\n public temporary: boolean;\r\n /** When the invite was created. */\r\n public readonly createdAt: Date | null;\r\n /** When the invite expires, or null if it never expires. */\r\n public readonly expiresAt: Date | null;\r\n\r\n /** Creates an invite from Discord data. */\r\n public constructor(data: {\r\n code: string;\r\n guild?: { id: string } | null;\r\n channel?: { id: string } | null;\r\n inviter?: {\r\n id: string;\r\n username: string;\r\n global_name?: string | null;\r\n avatar?: string | null;\r\n bot?: boolean;\r\n system?: boolean;\r\n public_flags?: number;\r\n discriminator?: string;\r\n } | null;\r\n uses?: number;\r\n max_uses?: number;\r\n max_age?: number;\r\n temporary?: boolean;\r\n created_at?: string | null;\r\n expires_at?: string | null;\r\n }) {\r\n if (!data.code) throw new TypeError(\"An invite requires a code.\");\r\n this.code = data.code;\r\n this.guildId = data.guild?.id ?? null;\r\n this.channelId = data.channel?.id ?? null;\r\n this.inviter = data.inviter ? new User(data.inviter) : null;\r\n this.uses = data.uses ?? 0;\r\n this.maxUses = data.max_uses ?? 0;\r\n this.maxAge = data.max_age ?? 0;\r\n this.temporary = data.temporary ?? false;\r\n this.createdAt = data.created_at ? new Date(data.created_at) : null;\r\n this.expiresAt = data.expires_at ? new Date(data.expires_at) : null;\r\n }\r\n\r\n /** The full invite URL. */\r\n public get url(): string {\r\n return `https://discord.gg/${this.code}`;\r\n }\r\n\r\n /** Returns the invite URL. Used automatically in template literals. */\r\n public toString(): string {\r\n return this.url;\r\n }\r\n}\r\n\r\n// ─── Webhook ──────────────────────────────────────────────────────────────────\r\n\r\n/** Webhook type constants. */\r\nexport const WebhookEnum = {\r\n Incoming: 1,\r\n ChannelFollower: 2,\r\n Application: 3,\r\n} as const;\r\n/** One {@link WebhookEnum} value, usable as a type. */\r\nexport type WebhookEnum = (typeof WebhookEnum)[keyof typeof WebhookEnum];\r\n\r\n/** A Discord webhook — an HTTP endpoint that can post messages to a channel. */\r\nexport class Webhook extends BaseStructure {\r\n /** Webhook type. */\r\n public readonly type: number;\r\n /** Webhook display name. */\r\n public name: string | null;\r\n /** Webhook avatar hash. */\r\n public avatarHash: string | null;\r\n /** Channel this webhook posts to. */\r\n public readonly channelId: string | null;\r\n /** Guild this webhook belongs to. */\r\n public readonly guildId: string | null;\r\n /** Application that created this webhook, if any. */\r\n public readonly applicationId: string | null;\r\n /** Webhook token (only present for incoming webhooks). */\r\n public readonly token: string | null;\r\n\r\n /** Creates a webhook from Discord data. */\r\n public constructor(data: {\r\n id: string;\r\n type?: number;\r\n name?: string | null;\r\n avatar?: string | null;\r\n channel_id?: string | null;\r\n guild_id?: string | null;\r\n application_id?: string | null;\r\n token?: string;\r\n }) {\r\n super(data.id);\r\n this.type = data.type ?? WebhookEnum.Incoming;\r\n this.name = data.name ?? null;\r\n this.avatarHash = data.avatar ?? null;\r\n this.channelId = data.channel_id ?? null;\r\n this.guildId = data.guild_id ?? null;\r\n this.applicationId = data.application_id ?? null;\r\n this.token = data.token ?? null;\r\n }\r\n\r\n /** Returns the webhook avatar URL, or null if no avatar is set. */\r\n public avatarURL(options: ImageURLOptions = {}): string | null {\r\n if (!this.avatarHash) return null;\r\n return cdnURL(`/avatars/${this.id}`, this.avatarHash, options);\r\n }\r\n\r\n /** Returns the webhook execution URL, or null if no token is set. */\r\n public get url(): string | null {\r\n return this.token\r\n ? `https://discord.com/api/webhooks/${this.id}/${this.token}`\r\n : null;\r\n }\r\n\r\n /** Returns the webhook URL or its ID as a string. */\r\n public override toString(): string {\r\n return this.url ?? this.id;\r\n }\r\n}\r\n\r\n// ─── Emoji ────────────────────────────────────────────────────────────────────\r\n\r\n/** A Discord emoji. */\r\nexport class Emoji extends BaseStructure {\r\n /** Emoji name. */\r\n public name: string | null;\r\n /** Roles allowed to use this emoji. */\r\n public roleIds: string[];\r\n /** User that created this emoji. */\r\n public user: User | null;\r\n /** Whether this emoji must be wrapped in colons. */\r\n public requireColons: boolean;\r\n /** Whether this emoji is managed. */\r\n public managed: boolean;\r\n /** Whether this emoji is animated. */\r\n public animated: boolean;\r\n /** Whether this emoji can be used, may be false due to loss of Server Boosts. */\r\n public available: boolean;\r\n\r\n /** Creates an emoji from Discord data. */\r\n public constructor(data: {\r\n id: string | null;\r\n name: string | null;\r\n roles?: string[];\r\n user?: import(\"@lunibee/types\").UserData;\r\n require_colons?: boolean;\r\n managed?: boolean;\r\n animated?: boolean;\r\n available?: boolean;\r\n }) {\r\n // Unicode emoji have no snowflake: pass the base check with a\r\n // placeholder, then expose the documented \"unicode\" sentinel id.\r\n super(data.id ?? \"0\");\r\n if (data.id === null) (this as { id: string }).id = \"unicode\";\r\n this.name = data.name;\r\n this.roleIds = data.roles ?? [];\r\n this.user = data.user ? new User(data.user) : null;\r\n this.requireColons = data.require_colons ?? false;\r\n this.managed = data.managed ?? false;\r\n this.animated = data.animated ?? false;\r\n this.available = data.available ?? true;\r\n }\r\n\r\n /** Returns the URL for this emoji if it is custom, or null for unicode emojis. */\r\n public url(options: ImageURLOptions = {}): string | null {\r\n if (!this.id || this.id === \"unicode\") return null;\r\n const ext = options.extension ?? (this.animated ? \"gif\" : \"png\");\r\n const size = options.size ? `?size=${options.size}` : \"\";\r\n return `${CDN_BASE}/emojis/${this.id}.${ext}${size}`;\r\n }\r\n\r\n /** Returns the text required to render this emoji in Discord. */\r\n public override toString(): string {\r\n return this.id !== \"unicode\"\r\n ? `<${this.animated ? \"a\" : \"\"}:${this.name}:${this.id}>`\r\n : (this.name ?? \"\");\r\n }\r\n}\r\n\r\n// --- AutoModerationRule --------------------------------------------------------\r\n\r\n/** A Discord AutoModeration Rule. */\r\nexport class AutoModerationRule extends BaseStructure {\r\n public guildId: string;\r\n public name: string;\r\n public creatorId: string;\r\n public eventType: number;\r\n public triggerType: number;\r\n public triggerMetadata: Record<string, unknown>;\r\n public actions: import(\"@lunibee/types\").APIAutoModerationAction[];\r\n public enabled: boolean;\r\n public exemptRoles: string[];\r\n public exemptChannels: string[];\r\n\r\n /** Creates an auto moderation rule from Discord data. */\r\n public constructor(data: import(\"@lunibee/types\").APIAutoModerationRule) {\r\n super(data.id);\r\n if (!/^\\d{1,20}$/.test(data.guild_id))\r\n throw new TypeError(\r\n \"AutoModerationRule guild_id must be a valid snowflake.\",\r\n );\r\n this.guildId = data.guild_id;\r\n this.name = data.name;\r\n this.creatorId = data.creator_id;\r\n this.eventType = data.event_type;\r\n this.triggerType = data.trigger_type;\r\n this.triggerMetadata = data.trigger_metadata;\r\n this.actions = data.actions;\r\n this.enabled = data.enabled;\r\n this.exemptRoles = data.exempt_roles;\r\n this.exemptChannels = data.exempt_channels;\r\n }\r\n\r\n public toJSON(): Record<string, unknown> {\r\n return {\r\n id: this.id,\r\n guildId: this.guildId,\r\n name: this.name,\r\n creatorId: this.creatorId,\r\n eventType: this.eventType,\r\n triggerType: this.triggerType,\r\n triggerMetadata: this.triggerMetadata,\r\n actions: this.actions,\r\n enabled: this.enabled,\r\n exemptRoles: this.exemptRoles,\r\n exemptChannels: this.exemptChannels,\r\n };\r\n }\r\n}\r\n\r\n// --- Welcome Screen -----------------------------------------------------------\r\n\r\n/** A channel listed in a guild's Welcome Screen. */\r\nexport class WelcomeScreenChannel {\r\n public channelId: string;\r\n public description: string;\r\n public emojiId: string | null;\r\n public emojiName: string | null;\r\n\r\n public constructor(data: import(\"@lunibee/types\").APIWelcomeScreenChannel) {\r\n this.channelId = data.channel_id;\r\n this.description = data.description;\r\n this.emojiId = data.emoji_id;\r\n this.emojiName = data.emoji_name;\r\n }\r\n}\r\n\r\n/** A Discord Guild Welcome Screen. */\r\nexport class GuildWelcomeScreen {\r\n public description: string | null;\r\n public channels: WelcomeScreenChannel[];\r\n\r\n public constructor(data: import(\"@lunibee/types\").APIGuildWelcomeScreen) {\r\n this.description = data.description;\r\n this.channels = data.welcome_channels.map(\r\n (c) => new WelcomeScreenChannel(c),\r\n );\r\n }\r\n}\r\n\r\n// --- Guild Onboarding ---------------------------------------------------------\r\n\r\n/** An option within a Guild Onboarding Prompt. */\r\nexport class OnboardingPromptOption extends BaseStructure {\r\n public channelIds: string[];\r\n public roleIds: string[];\r\n public emoji: import(\"@lunibee/types\").APIPartialEmoji | undefined;\r\n public title: string;\r\n public description: string | null;\r\n\r\n public constructor(\r\n data: import(\"@lunibee/types\").APIOnboardingPromptOption,\r\n ) {\r\n super(data.id);\r\n this.channelIds = data.channel_ids;\r\n this.roleIds = data.role_ids;\r\n this.emoji = data.emoji;\r\n this.title = data.title;\r\n this.description = data.description;\r\n }\r\n}\r\n\r\n/** A prompt shown during Guild Onboarding. */\r\nexport class OnboardingPrompt extends BaseStructure {\r\n public type: number;\r\n public options: OnboardingPromptOption[];\r\n public title: string;\r\n public singleSelect: boolean;\r\n public required: boolean;\r\n public inOnboarding: boolean;\r\n\r\n public constructor(data: import(\"@lunibee/types\").APIOnboardingPrompt) {\r\n super(data.id);\r\n this.type = data.type;\r\n this.options = data.options.map((o) => new OnboardingPromptOption(o));\r\n this.title = data.title;\r\n this.singleSelect = data.single_select;\r\n this.required = data.required;\r\n this.inOnboarding = data.in_onboarding;\r\n }\r\n}\r\n\r\n/** A Discord Guild Onboarding setup. */\r\nexport class GuildOnboarding extends BaseStructure {\r\n public prompts: OnboardingPrompt[];\r\n public defaultChannelIds: string[];\r\n public enabled: boolean;\r\n public mode: number;\r\n\r\n public constructor(data: import(\"@lunibee/types\").APIGuildOnboarding) {\r\n super(data.guild_id);\r\n this.prompts = data.prompts.map((p) => new OnboardingPrompt(p));\r\n this.defaultChannelIds = data.default_channel_ids;\r\n this.enabled = data.enabled;\r\n this.mode = data.mode;\r\n }\r\n}\r\n\r\n/** @deprecated Use {@link WebhookEnum}. Removed in 0.3.0. */\r\nexport const WebhookType = WebhookEnum;\r\n/** @deprecated Use {@link WebhookEnum}. Removed in 0.3.0. */\r\nexport type WebhookType = WebhookEnum;\r\n",
|
|
23
|
+
"import { Channel, User, type ResourceContext } from \"./base.js\";\r\nimport { TextChannel } from \"./resources.js\";\r\nimport type {\r\n APIChannel,\r\n APIForumTag,\r\n APIPartialEmoji,\r\n APIThreadMetadata,\r\n} from \"@lunibee/types\";\r\n\r\n// Discord.js-familiar channel subclasses. Every class extends Channel, so\r\n// existing `instanceof Channel` checks and Channel methods keep working.\r\n\r\n/** A guild announcement (news) channel. */\r\nexport class NewsChannel extends TextChannel {}\r\n\r\n/** A direct-message or group DM channel. */\r\nexport class DMChannel extends Channel {\r\n /** Users in the conversation. */\r\n public readonly recipients: User[];\r\n /** Owner of a group DM. */\r\n public readonly ownerId: string | null;\r\n\r\n public constructor(data: APIChannel, context?: ResourceContext) {\r\n super(data, context);\r\n this.recipients = (data.recipients ?? []).map((u) => new User(u));\r\n this.ownerId = data.owner_id ?? null;\r\n }\r\n}\r\n\r\n/** A guild voice channel. */\r\nexport class VoiceChannel extends Channel {\r\n /** Bitrate in bits per second. */\r\n public bitrate: number;\r\n /** User limit (0 = unlimited). */\r\n public userLimit: number;\r\n /** Voice region override, or null for automatic. */\r\n public rtcRegion: string | null;\r\n /** Camera video quality mode. */\r\n public videoQualityMode: number;\r\n\r\n public constructor(data: APIChannel, context?: ResourceContext) {\r\n super(data, context);\r\n this.bitrate = data.bitrate ?? 64000;\r\n this.userLimit = data.user_limit ?? 0;\r\n this.rtcRegion = data.rtc_region ?? null;\r\n this.videoQualityMode = data.video_quality_mode ?? 1;\r\n }\r\n}\r\n\r\n/** A guild stage channel. */\r\nexport class StageChannel extends VoiceChannel {}\r\n\r\n/** A guild category. */\r\nexport class CategoryChannel extends Channel {}\r\n\r\n/** A thread (announcement, public or private). */\r\nexport class ThreadChannel extends Channel {\r\n /** User who created the thread. */\r\n public readonly ownerId: string | null;\r\n /** Approximate message count. */\r\n public messageCount: number;\r\n /** Approximate member count (stops counting at 50). */\r\n public memberCount: number;\r\n /** Thread metadata. */\r\n public metadata: APIThreadMetadata | null;\r\n\r\n public constructor(data: APIChannel, context?: ResourceContext) {\r\n super(data, context);\r\n this.ownerId = data.owner_id ?? null;\r\n this.messageCount = data.message_count ?? 0;\r\n this.memberCount = data.member_count ?? 0;\r\n this.metadata = data.thread_metadata ?? null;\r\n }\r\n\r\n /** Whether the thread is archived. */\r\n public get archived(): boolean {\r\n return this.metadata?.archived ?? false;\r\n }\r\n\r\n /** Whether the thread is locked. */\r\n public get locked(): boolean {\r\n return this.metadata?.locked ?? false;\r\n }\r\n\r\n /** Minutes of inactivity before the thread auto-archives. */\r\n public get autoArchiveDuration(): number | null {\r\n return this.metadata?.auto_archive_duration ?? null;\r\n }\r\n}\r\n\r\n/** A guild forum channel. */\r\nexport class ForumChannel extends Channel {\r\n /** Tags that threads can apply. */\r\n public availableTags: APIForumTag[];\r\n /** Default reaction for new threads. */\r\n public defaultReactionEmoji: APIPartialEmoji | null;\r\n /** Default slowmode for new threads. */\r\n public defaultThreadRateLimitPerUser: number;\r\n /** Default auto-archive duration for new threads. */\r\n public defaultAutoArchiveDuration: number | null;\r\n\r\n public constructor(data: APIChannel, context?: ResourceContext) {\r\n super(data, context);\r\n this.availableTags = data.available_tags ?? [];\r\n this.defaultReactionEmoji = data.default_reaction_emoji ?? null;\r\n this.defaultThreadRateLimitPerUser =\r\n data.default_thread_rate_limit_per_user ?? 0;\r\n this.defaultAutoArchiveDuration =\r\n data.default_auto_archive_duration ?? null;\r\n }\r\n}\r\n\r\n/** A guild media channel. */\r\nexport class MediaChannel extends ForumChannel {}\r\n\r\n/**\r\n * Builds the most specific channel class for a payload's `type`, falling back\r\n * to {@link Channel} for types without a dedicated class.\r\n */\r\nexport function createChannel(\r\n data: APIChannel,\r\n context?: ResourceContext,\r\n): Channel {\r\n switch (data.type) {\r\n case 0:\r\n return new TextChannel(data, context);\r\n case 1:\r\n case 3:\r\n return new DMChannel(data, context);\r\n case 2:\r\n return new VoiceChannel(data, context);\r\n case 4:\r\n return new CategoryChannel(data, context);\r\n case 5:\r\n return new NewsChannel(data, context);\r\n case 10:\r\n case 11:\r\n case 12:\r\n return new ThreadChannel(data, context);\r\n case 13:\r\n return new StageChannel(data, context);\r\n case 15:\r\n return new ForumChannel(data, context);\r\n case 16:\r\n return new MediaChannel(data, context);\r\n default:\r\n return new Channel(data, context);\r\n }\r\n}\r\n",
|
|
24
|
+
"// ─── Raw option type from Discord ────────────────────────────────────────────\r\n\r\n/** Raw Discord application command interaction data option. */\r\nexport interface APIInteractionDataOption {\r\n name: string;\r\n type: number;\r\n value?: string | number | boolean;\r\n options?: APIInteractionDataOption[];\r\n focused?: boolean;\r\n}\r\n\r\n// ─── CommandOptions resolver ──────────────────────────────────────────────────\r\n\r\n/** Application command option types mirroring Discord's enum. */\r\nconst OptionType = {\r\n SubCommand: 1,\r\n SubCommandGroup: 2,\r\n String: 3,\r\n Integer: 4,\r\n Boolean: 5,\r\n User: 6,\r\n Channel: 7,\r\n Role: 8,\r\n Mentionable: 9,\r\n Number: 10,\r\n Attachment: 11,\r\n} as const;\r\n\r\n/**\r\n * Typed resolver for application command options.\r\n * Attached as `CommandInteraction.options`.\r\n */\r\nexport class CommandOptions {\r\n readonly #options: APIInteractionDataOption[];\r\n readonly #resolved: Record<string, unknown>;\r\n /** `resolved[kind][id]` from Discord's interaction data, if present. */\r\n #lookup(kind: string, id: string): Record<string, unknown> | undefined {\r\n const group = this.#resolved?.[kind];\r\n if (typeof group !== \"object\" || group === null) return undefined;\r\n const entry = (group as Record<string, unknown>)[id];\r\n return typeof entry === \"object\" && entry !== null\r\n ? (entry as Record<string, unknown>)\r\n : undefined;\r\n }\r\n\r\n /** @internal */\r\n public constructor(\r\n options: APIInteractionDataOption[],\r\n resolved: Record<string, unknown> = {},\r\n ) {\r\n let currentOptions = options;\r\n let group: string | null = null;\r\n let sub: string | null = null;\r\n\r\n // Drill down to the deepest options level for nested subcommands\r\n while (currentOptions.length === 1) {\r\n const opt = currentOptions[0]!;\r\n if (opt.type === OptionType.SubCommandGroup) {\r\n group = opt.name;\r\n currentOptions = opt.options ?? [];\r\n } else if (opt.type === OptionType.SubCommand) {\r\n sub = opt.name;\r\n currentOptions = opt.options ?? [];\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n this.#options = currentOptions;\r\n this.#resolved = resolved;\r\n this.#subcommandGroup = group;\r\n this.#subcommand = sub;\r\n }\r\n\r\n readonly #subcommandGroup: string | null;\r\n readonly #subcommand: string | null;\r\n\r\n /** Finds a raw option by name (case-insensitive). */\r\n #get(name: string): APIInteractionDataOption | undefined {\r\n return this.#options.find(\r\n (o) => o.name.toLowerCase() === name.toLowerCase(),\r\n );\r\n }\r\n\r\n // ── Subcommand resolution ──────────────────────────────────────────────────\r\n\r\n /** Returns the invoked subcommand name, or null if none. */\r\n public getSubcommand(required?: false): string | null;\r\n public getSubcommand(required: true): string;\r\n public getSubcommand(required = false): string | null {\r\n if (!this.#subcommand && required) {\r\n throw new TypeError(\"No subcommand was provided.\");\r\n }\r\n return this.#subcommand;\r\n }\r\n\r\n /** Returns the invoked subcommand group name, or null if none. */\r\n public getSubcommandGroup(required?: false): string | null;\r\n public getSubcommandGroup(required: true): string;\r\n public getSubcommandGroup(required = false): string | null {\r\n if (!this.#subcommandGroup && required) {\r\n throw new TypeError(\"No subcommand group was provided.\");\r\n }\r\n return this.#subcommandGroup;\r\n }\r\n\r\n // ── Autocomplete ───────────────────────────────────────────────────────────\r\n\r\n /** Returns the focused option's value (autocomplete), or the full option when `full` is true. @throws {TypeError} If no option is focused. */\r\n public getFocused(full: true): APIInteractionDataOption;\r\n public getFocused(full?: false): string | number | boolean;\r\n public getFocused(\r\n full = false,\r\n ): APIInteractionDataOption | string | number | boolean {\r\n const focused = this.#options.find((o) => o.focused);\r\n if (!focused) throw new TypeError(\"No focused option was provided.\");\r\n return full ? focused : (focused.value ?? \"\");\r\n }\r\n\r\n // ── Primitive value options ────────────────────────────────────────────────\r\n\r\n /** Gets a string option. @param name Option name. @param required If true, throws when missing. */\r\n public getString(name: string, required?: false): string | null;\r\n public getString(name: string, required: true): string;\r\n public getString(name: string, required = false): string | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.String) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (string) is missing.`,\r\n );\r\n return null;\r\n }\r\n return typeof opt.value === \"string\" ? opt.value : null;\r\n }\r\n\r\n /** Gets an integer option. @param name Option name. @param required If true, throws when missing. */\r\n public getInteger(name: string, required?: false): number | null;\r\n public getInteger(name: string, required: true): number;\r\n public getInteger(name: string, required = false): number | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.Integer) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (integer) is missing.`,\r\n );\r\n return null;\r\n }\r\n return typeof opt.value === \"number\" ? Math.trunc(opt.value) : null;\r\n }\r\n\r\n /** Gets a number (float) option. @param name Option name. @param required If true, throws when missing. */\r\n public getNumber(name: string, required?: false): number | null;\r\n public getNumber(name: string, required: true): number;\r\n public getNumber(name: string, required = false): number | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.Number) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (number) is missing.`,\r\n );\r\n return null;\r\n }\r\n return typeof opt.value === \"number\" ? opt.value : null;\r\n }\r\n\r\n /** Gets a boolean option. @param name Option name. @param required If true, throws when missing. */\r\n public getBoolean(name: string, required?: false): boolean | null;\r\n public getBoolean(name: string, required: true): boolean;\r\n public getBoolean(name: string, required = false): boolean | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.Boolean) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (boolean) is missing.`,\r\n );\r\n return null;\r\n }\r\n return typeof opt.value === \"boolean\" ? opt.value : null;\r\n }\r\n\r\n // ── Resolved entity options ────────────────────────────────────────────────\r\n\r\n /** Gets the raw resolved user data for a user option. @param name Option name. @param required If true, throws when missing. */\r\n public getUser(\r\n name: string,\r\n required?: false,\r\n ): Record<string, unknown> | null;\r\n public getUser(name: string, required: true): Record<string, unknown>;\r\n public getUser(\r\n name: string,\r\n required = false,\r\n ): Record<string, unknown> | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.User) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (user) is missing.`,\r\n );\r\n return null;\r\n }\r\n const userId = String(opt.value);\r\n const resolved = this.#lookup(\"users\", userId) ?? null;\r\n if (!resolved && required)\r\n throw new TypeError(\r\n `Resolved user for option \"${name}\" is missing.`,\r\n );\r\n return resolved;\r\n }\r\n\r\n /** Gets the raw resolved channel data for a channel option. @param name Option name. @param required If true, throws when missing. */\r\n public getChannel(\r\n name: string,\r\n required?: false,\r\n ): Record<string, unknown> | null;\r\n public getChannel(name: string, required: true): Record<string, unknown>;\r\n public getChannel(\r\n name: string,\r\n required = false,\r\n ): Record<string, unknown> | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.Channel) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (channel) is missing.`,\r\n );\r\n return null;\r\n }\r\n const channelId = String(opt.value);\r\n const resolved = this.#lookup(\"channels\", channelId) ?? null;\r\n if (!resolved && required)\r\n throw new TypeError(\r\n `Resolved channel for option \"${name}\" is missing.`,\r\n );\r\n return resolved;\r\n }\r\n\r\n /** Gets the raw resolved role data for a role option. @param name Option name. @param required If true, throws when missing. */\r\n public getRole(\r\n name: string,\r\n required?: false,\r\n ): Record<string, unknown> | null;\r\n public getRole(name: string, required: true): Record<string, unknown>;\r\n public getRole(\r\n name: string,\r\n required = false,\r\n ): Record<string, unknown> | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.Role) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (role) is missing.`,\r\n );\r\n return null;\r\n }\r\n const roleId = String(opt.value);\r\n const resolved = this.#lookup(\"roles\", roleId) ?? null;\r\n if (!resolved && required)\r\n throw new TypeError(\r\n `Resolved role for option \"${name}\" is missing.`,\r\n );\r\n return resolved;\r\n }\r\n\r\n /** Gets the raw resolved user or role data for a mentionable option. @param name Option name. @param required If true, throws when missing. */\r\n public getMentionable(\r\n name: string,\r\n required?: false,\r\n ): Record<string, unknown> | null;\r\n public getMentionable(\r\n name: string,\r\n required: true,\r\n ): Record<string, unknown>;\r\n public getMentionable(\r\n name: string,\r\n required = false,\r\n ): Record<string, unknown> | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.Mentionable) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (mentionable) is missing.`,\r\n );\r\n return null;\r\n }\r\n const id = String(opt.value);\r\n const resolved =\r\n this.#lookup(\"users\", id) ?? this.#lookup(\"roles\", id) ?? null;\r\n if (!resolved && required)\r\n throw new TypeError(\r\n `Resolved mentionable for option \"${name}\" is missing.`,\r\n );\r\n return resolved;\r\n }\r\n\r\n /** Whether a mentionable option picked a user or a role; null when the option is missing. @param name Option name. */\r\n public getMentionableType(name: string): \"user\" | \"role\" | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.Mentionable) return null;\r\n const id = String(opt.value);\r\n if (this.#lookup(\"users\", id)) return \"user\";\r\n if (this.#lookup(\"roles\", id)) return \"role\";\r\n return null;\r\n }\r\n\r\n /** Gets the raw resolved attachment data for an attachment option. @param name Option name. @param required If true, throws when missing. */\r\n public getAttachment(\r\n name: string,\r\n required?: false,\r\n ): Record<string, unknown> | null;\r\n public getAttachment(name: string, required: true): Record<string, unknown>;\r\n public getAttachment(\r\n name: string,\r\n required = false,\r\n ): Record<string, unknown> | null {\r\n const opt = this.#get(name);\r\n if (!opt || opt.type !== OptionType.Attachment) {\r\n if (required)\r\n throw new TypeError(\r\n `Required option \"${name}\" (attachment) is missing.`,\r\n );\r\n return null;\r\n }\r\n const attachmentId = String(opt.value);\r\n const resolved = this.#lookup(\"attachments\", attachmentId) ?? null;\r\n if (!resolved && required)\r\n throw new TypeError(\r\n `Resolved attachment for option \"${name}\" is missing.`,\r\n );\r\n return resolved;\r\n }\r\n\r\n /** Returns the raw option list for advanced use cases. */\r\n public get raw(): readonly APIInteractionDataOption[] {\r\n return this.#options;\r\n }\r\n}\r\n",
|
|
25
|
+
"import { InteractionResponseEnum } from \"@lunibee/types\";\r\nimport { User, type ResourceContext } from \"./base.js\";\r\nimport { GuildMember } from \"./resources.js\";\r\n// A cycle with index.ts: Message is only used lazily (in a getter), after both modules loaded.\r\nimport { Message } from \"./index.js\";\r\n\r\n/** Discord interaction type constants. */\r\nexport const InteractionEnum = {\r\n Ping: 1,\r\n ApplicationCommand: 2,\r\n MessageComponent: 3,\r\n ApplicationCommandAutocomplete: 4,\r\n ModalSubmit: 5,\r\n} as const;\r\n/** One {@link InteractionEnum} value, usable as a type. */\r\nexport type InteractionEnum =\r\n (typeof InteractionEnum)[keyof typeof InteractionEnum];\r\n// Re-export for consumers who import from structures directly\r\nexport {\r\n InteractionResponseEnum,\r\n InteractionResponseType,\r\n} from \"@lunibee/types\";\r\n/** Data shared by Discord interactions. */\r\nexport interface InteractionData {\r\n /** Interaction identifier. */\r\n id: string;\r\n /** Application identifier. */\r\n application_id: string;\r\n /** Interaction type. */\r\n type: number;\r\n /** Interaction token. */\r\n token: string;\r\n /** Gateway/API version. */\r\n version?: number;\r\n /** Guild identifier. */\r\n guild_id?: string;\r\n /** Channel identifier. */\r\n channel_id?: string;\r\n /** Interaction-specific data. */\r\n data?: Record<string, unknown>;\r\n [key: string]: unknown;\r\n}\r\n/** Options for an interaction response message. */\r\nexport interface InteractionReplyOptions {\r\n /** Message content. */\r\n content?: string;\r\n /** Whether the response is ephemeral. */\r\n ephemeral?: boolean;\r\n /** Message components. */\r\n components?: unknown[];\r\n /** Message embeds. */\r\n embeds?: unknown[];\r\n /** Discord message flags. */\r\n flags?: number;\r\n /** On `reply()` / `update()`: return the created message (one request, no `fetchReply()`). */\r\n withResponse?: boolean;\r\n [key: string]: unknown;\r\n}\r\n/** Transport required by an interaction structure. */\r\nexport interface InteractionClient {\r\n /** Sends the initial interaction callback. @param id Interaction identifier. @param token Interaction token. @param response Callback payload. @returns Discord response. @throws {Error} When REST fails. */\r\n postInteractionResponse(\r\n id: string,\r\n token: string,\r\n response: InteractionResponse,\r\n ): Promise<unknown>;\r\n /** Edits the original interaction response. @param token Interaction token. @param data Message payload. @returns Discord response. @throws {Error} When REST fails. */\r\n editInteractionReply(\r\n token: string,\r\n data: InteractionReplyOptions,\r\n ): Promise<unknown>;\r\n /** Deletes the original interaction response. @param token Interaction token. @returns Promise fulfilled after deletion. @throws {Error} When REST fails. */\r\n deleteInteractionReply(token: string): Promise<void>;\r\n /** Sends a follow-up interaction webhook message. @param token Interaction token. @param data Message payload. @returns Discord response. @throws {Error} When REST fails. */\r\n followUpInteraction(\r\n token: string,\r\n data: InteractionReplyOptions,\r\n ): Promise<unknown>;\r\n /** 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}. */\r\n interactionWebhookMessage?(\r\n method: \"GET\" | \"PATCH\" | \"DELETE\",\r\n applicationId: string,\r\n token: string,\r\n messageId: string,\r\n data?: InteractionReplyOptions,\r\n ): Promise<unknown>;\r\n /** Lets structures built from an interaction (such as {@link Interaction.member}) act through the client. Optional. */\r\n readonly resourceContext?: ResourceContext;\r\n}\r\n\r\n/** Discord's ephemeral message flag. */\r\nconst EPHEMERAL = 64;\r\n/** Application command types (`data.type`): slash, user context menu, message context menu. */\r\nconst COMMAND_CHAT_INPUT = 1;\r\nconst COMMAND_USER = 2;\r\nconst COMMAND_MESSAGE = 3;\r\n/** Interaction tokens stay valid for 15 minutes. */\r\nconst TOKEN_LIFETIME_MS = 15 * 60_000;\r\nconst DISCORD_EPOCH = 1_420_070_400_000n;\r\n\r\n/** Takes the local-only `withResponse` key off reply options. */\r\nfunction splitWithResponse(options: InteractionReplyOptions | string): {\r\n withResponse: boolean;\r\n rest: InteractionReplyOptions | string;\r\n} {\r\n if (typeof options === \"string\")\r\n return { withResponse: false, rest: options };\r\n const { withResponse, ...rest } = options;\r\n return { withResponse: withResponse === true, rest };\r\n}\r\n\r\n/** Turns `{ ephemeral: true }` into Discord's flag and drops the local-only key. */\r\nfunction toMessageData(\r\n options: InteractionReplyOptions | string,\r\n): InteractionReplyOptions {\r\n if (typeof options === \"string\") return { content: options };\r\n const { ephemeral, ...data } = options;\r\n if (ephemeral)\r\n data.flags =\r\n (typeof data.flags === \"number\" ? data.flags : 0) | EPHEMERAL;\r\n return data;\r\n}\r\n\r\nexport { CommandOptions, type APIInteractionDataOption } from \"./options.js\";\r\nimport { CommandOptions, type APIInteractionDataOption } from \"./options.js\";\r\n\r\n// ─── Response class ───────────────────────────────────────────────────────────\r\n\r\n/** A Discord interaction callback payload. */\r\nexport class InteractionResponse {\r\n readonly type: number;\r\n readonly data?: InteractionReplyOptions;\r\n /** Ask Discord to return the created message (`?with_response=true`); not part of the body. */\r\n public withResponse = false;\r\n /** Creates a response payload. @param type Discord callback type. @param data Optional callback data. @throws {TypeError} If type is not finite. */\r\n public constructor(type: number, data?: InteractionReplyOptions) {\r\n if (!Number.isFinite(type))\r\n throw new TypeError(\"Interaction response type must be finite.\");\r\n this.type = type;\r\n this.data = data;\r\n }\r\n /** Serializes the response for Discord. @returns Discord callback payload. */\r\n public toJSON(): {\r\n type: number;\r\n data?: InteractionReplyOptions;\r\n } {\r\n return this.data === undefined\r\n ? { type: this.type }\r\n : { type: this.type, data: this.data };\r\n }\r\n /** Creates an immediate message response. @param options Response message options. @returns Callback payload. */\r\n public static message(\r\n options: InteractionReplyOptions,\r\n ): InteractionResponse {\r\n return new InteractionResponse(\r\n InteractionResponseEnum.ChannelMessage,\r\n toMessageData(options),\r\n );\r\n }\r\n /** Creates a deferred channel response. @param ephemeral Whether the eventual response is ephemeral. @returns Callback payload. */\r\n public static defer(ephemeral = false): InteractionResponse {\r\n return new InteractionResponse(\r\n InteractionResponseEnum.DeferredChannelMessage,\r\n ephemeral ? { flags: EPHEMERAL } : undefined,\r\n );\r\n }\r\n /** Creates a Pong response. @returns Callback payload. */\r\n public static pong(): InteractionResponse {\r\n return new InteractionResponse(InteractionResponseEnum.Pong);\r\n }\r\n}\r\n\r\n// ─── Base Interaction ─────────────────────────────────────────────────────────\r\n\r\n/** Base interaction structure. */\r\nexport class Interaction<TData extends InteractionData = InteractionData> {\r\n /** Interaction identifier. */\r\n public readonly id: string;\r\n /** Application identifier. */\r\n public readonly applicationId: string;\r\n /** Interaction token. */\r\n public readonly token: string;\r\n /** Guild identifier. */\r\n public readonly guildId?: string;\r\n /** Channel identifier. */\r\n public readonly channelId?: string;\r\n /** Interaction type. */\r\n public readonly type: number;\r\n /** Raw interaction data. */\r\n public readonly data: TData;\r\n /** Whether the initial response was sent. */\r\n public replied = false;\r\n /** Whether the initial response was deferred. */\r\n public deferred = false;\r\n readonly #client: InteractionClient;\r\n /** An initial response is in flight; a second one must not be sent. */\r\n #acknowledging = false;\r\n /** Creates an interaction from a Gateway payload. @param client Interaction transport. @param data Gateway interaction payload. @throws {TypeError} If required identifiers are missing. */\r\n public constructor(client: InteractionClient, data: TData) {\r\n if (!data.id || !data.token)\r\n throw new TypeError(\"Interaction ID and token are required.\");\r\n this.#client = client;\r\n this.id = data.id;\r\n this.applicationId = data.application_id;\r\n this.token = data.token;\r\n this.guildId = data.guild_id;\r\n this.channelId = data.channel_id;\r\n this.type = data.type;\r\n this.data = data;\r\n }\r\n /** The application command's own type (1 chat input, 2 user, 3 message); 0 when this is not a command. */\r\n #commandType(): number {\r\n if (this.type !== InteractionEnum.ApplicationCommand) return 0;\r\n const type = this.data.data?.type;\r\n return typeof type === \"number\" ? type : COMMAND_CHAT_INPUT;\r\n }\r\n /** Whether this interaction is any application command: slash or context menu. */\r\n public isCommand(): this is CommandInteraction {\r\n return this.type === InteractionEnum.ApplicationCommand;\r\n }\r\n /**\r\n * Whether this interaction is a slash (chat input) command. Since 0.2.2 this\r\n * is false for context-menu commands; use {@link isCommand} for both.\r\n */\r\n public isChatInputCommand(): this is CommandInteraction {\r\n return this.#commandType() === COMMAND_CHAT_INPUT;\r\n }\r\n /** Whether this interaction is a user or message context-menu command. */\r\n public isContextMenuCommand(): this is ContextMenuCommandInteraction {\r\n const type = this.#commandType();\r\n return type === COMMAND_USER || type === COMMAND_MESSAGE;\r\n }\r\n /** Whether this interaction is a user context-menu command (right-click a user). */\r\n public isUserContextMenuCommand(): this is ContextMenuCommandInteraction {\r\n return this.#commandType() === COMMAND_USER;\r\n }\r\n /** Whether this interaction is a message context-menu command (right-click a message). */\r\n public isMessageContextMenuCommand(): this is ContextMenuCommandInteraction {\r\n return this.#commandType() === COMMAND_MESSAGE;\r\n }\r\n /** The client context structures built from this interaction act through. */\r\n protected get resourceContext(): ResourceContext | undefined {\r\n return this.#client.resourceContext;\r\n }\r\n /**\r\n * Waits for this user to submit a modal, typically one this interaction\r\n * just opened with {@link showModal}.\r\n * @param options `time` (required, ms); optional `customId` and `filter`.\r\n * @returns The submission. @throws {Error} When time runs out first or no client is attached.\r\n * @example const submitted = await interaction.awaitModalSubmit({ time: 60_000, customId: \"feedback\" });\r\n */\r\n public awaitModalSubmit(options: {\r\n time: number;\r\n customId?: string;\r\n filter?: (\r\n interaction: ModalSubmitInteraction,\r\n ) => boolean | Promise<boolean>;\r\n }): Promise<ModalSubmitInteraction> {\r\n const collect = this.#client.resourceContext?.collectInteractions;\r\n if (!collect)\r\n return Promise.reject(\r\n new Error(\"This interaction is not attached to a client.\"),\r\n );\r\n if (!(options.time > 0))\r\n return Promise.reject(\r\n new RangeError(\"awaitModalSubmit needs a positive time.\"),\r\n );\r\n const userId = this.user?.id;\r\n const collector = collect({\r\n time: options.time,\r\n max: 1,\r\n filter: async (interaction) =>\r\n interaction.isModalSubmit() &&\r\n interaction.user?.id === userId &&\r\n (options.customId === undefined ||\r\n interaction.customId === options.customId) &&\r\n (options.filter ? await options.filter(interaction) : true),\r\n });\r\n return collector.next() as Promise<ModalSubmitInteraction>;\r\n }\r\n /** Whether this interaction is a message component. @returns True for component interactions. */\r\n public isMessageComponent(): this is ComponentInteraction {\r\n return this.type === InteractionEnum.MessageComponent;\r\n }\r\n /** Whether this interaction is a modal submission. @returns True for modal submissions. */\r\n public isModalSubmit(): this is ModalSubmitInteraction {\r\n return this.type === InteractionEnum.ModalSubmit;\r\n }\r\n /** Whether this interaction is autocomplete. @returns True for autocomplete interactions. */\r\n public isAutocomplete(): this is AutocompleteInteraction {\r\n return this.type === InteractionEnum.ApplicationCommandAutocomplete;\r\n }\r\n /** Message component type of this interaction, or 0 when it is not a component. */\r\n #componentType(): number {\r\n return this.isMessageComponent()\r\n ? ((this.data.data?.component_type as number | undefined) ?? 0)\r\n : 0;\r\n }\r\n /** Whether this is a button interaction. */\r\n public isButton(): this is ComponentInteraction {\r\n return this.#componentType() === 2;\r\n }\r\n /** Whether this is a string select menu interaction. */\r\n public isStringSelectMenu(): this is ComponentInteraction {\r\n return this.#componentType() === 3;\r\n }\r\n /** Whether this is a user select menu interaction. */\r\n public isUserSelectMenu(): this is ComponentInteraction {\r\n return this.#componentType() === 5;\r\n }\r\n /** Whether this is a role select menu interaction. */\r\n public isRoleSelectMenu(): this is ComponentInteraction {\r\n return this.#componentType() === 6;\r\n }\r\n /** Whether this is a mentionable select menu interaction. */\r\n public isMentionableSelectMenu(): this is ComponentInteraction {\r\n return this.#componentType() === 7;\r\n }\r\n /** Whether this is a channel select menu interaction. */\r\n public isChannelSelectMenu(): this is ComponentInteraction {\r\n return this.#componentType() === 8;\r\n }\r\n /** Whether this is any select menu interaction. */\r\n public isAnySelectMenu(): this is ComponentInteraction {\r\n return [3, 5, 6, 7, 8].includes(this.#componentType());\r\n }\r\n /** Ensures the interaction has not already been acknowledged. @returns Nothing. @throws {Error} When already acknowledged. */\r\n protected assertUnacknowledged(): void {\r\n if (this.replied || this.deferred || this.#acknowledging)\r\n throw new Error(\"Interaction has already been acknowledged.\");\r\n }\r\n /**\r\n * Sends the initial response exactly once. The in-flight flag is set\r\n * before the request, so two concurrent calls cannot both send; it is\r\n * cleared if the request fails so the caller may try again.\r\n */\r\n protected async acknowledge(\r\n response: InteractionResponse,\r\n state: \"replied\" | \"deferred\",\r\n ): Promise<unknown> {\r\n this.assertUnacknowledged();\r\n this.#acknowledging = true;\r\n try {\r\n const result = await this.postResponse(response);\r\n this[state] = true;\r\n return result;\r\n } finally {\r\n this.#acknowledging = false;\r\n }\r\n }\r\n /** The invoking user (from `member.user` in guilds, `user` in DMs). */\r\n public get user(): User | null {\r\n const raw =\r\n (this.data.member as { user?: unknown } | undefined)?.user ??\r\n this.data.user;\r\n return raw\r\n ? new User(raw as ConstructorParameters<typeof User>[0])\r\n : null;\r\n }\r\n /** The invoking guild member, or null outside a guild. */\r\n public get member(): GuildMember | null {\r\n const raw = this.data.member;\r\n if (!raw || !this.guildId) return null;\r\n return new GuildMember(\r\n {\r\n ...(raw as Omit<\r\n ConstructorParameters<typeof GuildMember>[0],\r\n \"guild_id\"\r\n >),\r\n guild_id: this.guildId,\r\n },\r\n this.#client.resourceContext,\r\n );\r\n }\r\n /** Unix timestamp (ms) at which the interaction was created, from its snowflake. */\r\n public get createdTimestamp(): number {\r\n return Number((BigInt(this.id) >> 22n) + DISCORD_EPOCH);\r\n }\r\n /** When the interaction token stops working (15 minutes after creation). */\r\n public get expiresAt(): Date {\r\n return new Date(this.createdTimestamp + TOKEN_LIFETIME_MS);\r\n }\r\n /** Whether the token has expired; no response, edit or follow-up can succeed after that. */\r\n public get isExpired(): boolean {\r\n return Date.now() >= this.createdTimestamp + TOKEN_LIFETIME_MS;\r\n }\r\n #webhookMessage(\r\n method: \"GET\" | \"PATCH\" | \"DELETE\",\r\n messageId: string,\r\n data?: InteractionReplyOptions,\r\n ): Promise<unknown> {\r\n if (!this.#client.interactionWebhookMessage)\r\n return Promise.reject(\r\n new Error(\r\n \"This interaction client does not support webhook message access.\",\r\n ),\r\n );\r\n return this.#client.interactionWebhookMessage(\r\n method,\r\n this.applicationId,\r\n this.token,\r\n messageId,\r\n data,\r\n );\r\n }\r\n /** Fetches the original response message. */\r\n public fetchReply(): Promise<unknown> {\r\n this.assertAcknowledged();\r\n return this.#webhookMessage(\"GET\", \"@original\");\r\n }\r\n /** Edits a follow-up message. @param messageId Follow-up message ID. */\r\n public editFollowUp(\r\n messageId: string,\r\n options: InteractionReplyOptions | string,\r\n ): Promise<unknown> {\r\n return this.#webhookMessage(\"PATCH\", messageId, toMessageData(options));\r\n }\r\n /** Deletes a follow-up message. @param messageId Follow-up message ID. */\r\n public async deleteFollowUp(messageId: string): Promise<void> {\r\n await this.#webhookMessage(\"DELETE\", messageId);\r\n }\r\n /** Ensures the interaction has been acknowledged. @returns Nothing. @throws {Error} When not acknowledged. */\r\n protected assertAcknowledged(): void {\r\n if (!this.replied && !this.deferred)\r\n throw new Error(\"Interaction has not been acknowledged.\");\r\n }\r\n /** Posts a raw interaction response callback. */\r\n protected postResponse(response: InteractionResponse): Promise<unknown> {\r\n return this.#client.postInteractionResponse(\r\n this.id,\r\n this.token,\r\n response,\r\n );\r\n }\r\n /**\r\n * Sends a response and, when `withResponse` is set, turns the callback\r\n * resource Discord returns into the created message.\r\n */\r\n protected async acknowledgeWith(\r\n response: InteractionResponse,\r\n state: \"replied\" | \"deferred\",\r\n withResponse: boolean,\r\n ): Promise<unknown> {\r\n response.withResponse = withResponse;\r\n const result = await this.acknowledge(response, state);\r\n if (!withResponse) return result;\r\n const message = (result as { resource?: { message?: unknown } } | null)\r\n ?.resource?.message;\r\n return message\r\n ? new Message(\r\n message as ConstructorParameters<typeof Message>[0],\r\n this.#client.resourceContext,\r\n )\r\n : null;\r\n }\r\n /**\r\n * Sends the initial interaction response. With `withResponse: true` it\r\n * returns the created {@link Message} in the same request (no `fetchReply()`).\r\n * @throws {Error} When already acknowledged or REST fails.\r\n */\r\n public async reply(\r\n options: InteractionReplyOptions & { withResponse: true },\r\n ): Promise<Message | null>;\r\n public async reply(\r\n options: InteractionReplyOptions | string,\r\n ): Promise<unknown>;\r\n public async reply(\r\n options: InteractionReplyOptions | string,\r\n ): Promise<unknown> {\r\n const { withResponse, rest } = splitWithResponse(options);\r\n return this.acknowledgeWith(\r\n InteractionResponse.message(toMessageData(rest)),\r\n \"replied\",\r\n withResponse,\r\n );\r\n }\r\n /**\r\n * Defers the initial interaction response. `true` or `{ ephemeral: true }`\r\n * makes the eventual response private; `withResponse: true` returns the\r\n * placeholder message. @throws {Error} When already acknowledged or REST fails.\r\n */\r\n public async deferReply(options: {\r\n ephemeral?: boolean;\r\n withResponse: true;\r\n }): Promise<Message | null>;\r\n public async deferReply(\r\n options?: boolean | { ephemeral?: boolean; withResponse?: boolean },\r\n ): Promise<void>;\r\n public async deferReply(\r\n options:\r\n boolean | { ephemeral?: boolean; withResponse?: boolean } = false,\r\n ): Promise<Message | null | void> {\r\n const ephemeral =\r\n typeof options === \"boolean\" ? options : options.ephemeral === true;\r\n const withResponse =\r\n typeof options === \"object\" && options.withResponse === true;\r\n const result = await this.acknowledgeWith(\r\n InteractionResponse.defer(ephemeral),\r\n \"deferred\",\r\n withResponse,\r\n );\r\n if (withResponse) return result as Message | null;\r\n }\r\n /** Edits the original response. @param options Replacement message options. @returns Discord response. @throws {Error} When not acknowledged or REST fails. */\r\n public editReply(options: InteractionReplyOptions): Promise<unknown> {\r\n this.assertAcknowledged();\r\n return this.#client.editInteractionReply(\r\n this.token,\r\n toMessageData(options),\r\n );\r\n }\r\n /** Deletes the original response. @returns Promise fulfilled after deletion. @throws {Error} When not acknowledged or REST fails. */\r\n public deleteReply(): Promise<void> {\r\n this.assertAcknowledged();\r\n return this.#client.deleteInteractionReply(this.token);\r\n }\r\n /** Sends a follow-up message using the interaction webhook. @param options Follow-up message options. @returns Discord response. @throws {Error} When REST fails. */\r\n public followUp(\r\n options: InteractionReplyOptions | string,\r\n ): Promise<unknown> {\r\n return this.#client.followUpInteraction(\r\n this.token,\r\n toMessageData(options),\r\n );\r\n }\r\n /**\r\n * Updates the message a component is on. With `withResponse: true` it\r\n * returns the updated {@link Message}.\r\n */\r\n public async update(\r\n options: InteractionReplyOptions & { withResponse: true },\r\n ): Promise<Message | null>;\r\n public async update(\r\n options: InteractionReplyOptions | string,\r\n ): Promise<unknown>;\r\n public async update(\r\n options: InteractionReplyOptions | string,\r\n ): Promise<unknown> {\r\n const { withResponse, rest } = splitWithResponse(options);\r\n return this.acknowledgeWith(\r\n new InteractionResponse(\r\n InteractionResponseEnum.MessageUpdate,\r\n toMessageData(rest),\r\n ),\r\n \"replied\",\r\n withResponse,\r\n );\r\n }\r\n /** Opens a modal dialog in the user's client. @param modal Modal builder output or raw modal callback data. @returns Discord response. @throws {Error} When already acknowledged or REST fails. */\r\n public async showModal(\r\n modal:\r\n | {\r\n toJSON(): {\r\n custom_id: string;\r\n title: string;\r\n components: unknown[];\r\n };\r\n }\r\n // No index signature: an interface such as the builder's\r\n // `APIModalComponent` (what `toJSON()` returns) must be assignable.\r\n | {\r\n custom_id: string;\r\n title: string;\r\n components: readonly unknown[];\r\n },\r\n ): Promise<unknown> {\r\n const data =\r\n \"toJSON\" in modal && typeof modal.toJSON === \"function\"\r\n ? modal.toJSON()\r\n : modal;\r\n return this.acknowledge(\r\n new InteractionResponse(\r\n InteractionResponseEnum.Modal,\r\n data as InteractionReplyOptions,\r\n ),\r\n \"replied\",\r\n );\r\n }\r\n}\r\n\r\n// ─── CommandInteraction ───────────────────────────────────────────────────────\r\n\r\n/** Application command interaction with fully typed option resolver. */\r\nexport class CommandInteraction extends Interaction {\r\n /** Typed option resolver. Access slash command options with full type safety. */\r\n public readonly options: CommandOptions;\r\n\r\n /** Invoked command name. @returns Command name or an empty string. */\r\n public get commandName(): string {\r\n return typeof this.data.data?.name === \"string\"\r\n ? this.data.data.name\r\n : \"\";\r\n }\r\n\r\n public constructor(client: InteractionClient, data: InteractionData) {\r\n super(client, data);\r\n const rawOptions =\r\n (data.data?.options as APIInteractionDataOption[]) ?? [];\r\n const resolved = (data.data?.resolved as Record<string, unknown>) ?? {};\r\n // Hand the resolver the *top-level* options. CommandOptions performs the\r\n // subcommand/group drill itself and records the names it walks through;\r\n // pre-drilling here would strip those wrappers before it sees them, so\r\n // getSubcommand()/getSubcommandGroup() would report null.\r\n this.options = new CommandOptions(rawOptions, resolved);\r\n }\r\n}\r\n\r\n// ─── ContextMenuCommandInteraction ───────────────────────────────────────────\r\n\r\n/** A user or message context-menu command, with what was right-clicked. */\r\nexport class ContextMenuCommandInteraction extends CommandInteraction {\r\n #resolved(): Record<string, Record<string, unknown> | undefined> {\r\n return (this.data.data?.resolved ?? {}) as Record<\r\n string,\r\n Record<string, unknown> | undefined\r\n >;\r\n }\r\n /** ID of the user or message the command was used on. */\r\n public get targetId(): string | null {\r\n const id = this.data.data?.target_id;\r\n return typeof id === \"string\" ? id : null;\r\n }\r\n /** The user a user command was used on. */\r\n public get targetUser(): User | null {\r\n const id = this.targetId;\r\n const raw = id ? this.#resolved().users?.[id] : undefined;\r\n return raw\r\n ? new User(raw as ConstructorParameters<typeof User>[0])\r\n : null;\r\n }\r\n /** The member a user command was used on (in a guild), with member actions when attached to a client. */\r\n public get targetMember(): GuildMember | null {\r\n const id = this.targetId;\r\n const raw = id ? this.#resolved().members?.[id] : undefined;\r\n const user = id ? this.#resolved().users?.[id] : undefined;\r\n if (!raw || !user || !this.guildId) return null;\r\n return new GuildMember(\r\n {\r\n ...(raw as Omit<\r\n ConstructorParameters<typeof GuildMember>[0],\r\n \"guild_id\" | \"user\"\r\n >),\r\n user: user as ConstructorParameters<\r\n typeof GuildMember\r\n >[0][\"user\"],\r\n guild_id: this.guildId,\r\n },\r\n this.resourceContext,\r\n );\r\n }\r\n /** The message a message command was used on. */\r\n public get targetMessage(): Message | null {\r\n const id = this.targetId;\r\n const raw = id ? this.#resolved().messages?.[id] : undefined;\r\n return raw\r\n ? new Message(\r\n raw as unknown as ConstructorParameters<typeof Message>[0],\r\n this.resourceContext,\r\n )\r\n : null;\r\n }\r\n}\r\n\r\n// ─── ComponentInteraction ─────────────────────────────────────────────────────\r\n\r\n/** Message component interaction. */\r\nexport class ComponentInteraction extends Interaction {\r\n /** Gets component custom ID. */\r\n public get customId(): string {\r\n const id = this.data.data?.custom_id;\r\n return typeof id === \"string\" ? id : \"\";\r\n }\r\n /** ID of the message the component is on. */\r\n public get messageId(): string | undefined {\r\n return (this.data.message as { id?: string } | undefined)?.id;\r\n }\r\n /** Gets component type. */\r\n public get componentType(): number {\r\n const type = this.data.data?.component_type;\r\n return typeof type === \"number\" ? type : 0;\r\n }\r\n /** Gets selected values for select menu component interactions. */\r\n public get values(): string[] {\r\n const values = this.data.data?.values;\r\n return Array.isArray(values) ? (values as string[]) : [];\r\n }\r\n /** Defers updating the message to which the component was attached. */\r\n public async deferUpdate(options: {\r\n withResponse: true;\r\n }): Promise<Message | null>;\r\n public async deferUpdate(options?: {\r\n withResponse?: boolean;\r\n }): Promise<void>;\r\n public async deferUpdate(\r\n options: { withResponse?: boolean } = {},\r\n ): Promise<Message | null | void> {\r\n const withResponse = options.withResponse === true;\r\n const result = await this.acknowledgeWith(\r\n new InteractionResponse(\r\n InteractionResponseEnum.DeferredMessageUpdate,\r\n ),\r\n \"deferred\",\r\n withResponse,\r\n );\r\n if (withResponse) return result as Message | null;\r\n }\r\n}\r\n\r\n// ─── ModalSubmitInteraction ───────────────────────────────────────────────────\r\n\r\n/** Represents a Discord modal submission interaction. */\r\nexport class ModalSubmitInteraction extends Interaction {\r\n /** Gets the submitted modal custom ID. */\r\n public get customId(): string {\r\n const id = this.data.data?.custom_id;\r\n return typeof id === \"string\" ? id : \"\";\r\n }\r\n\r\n /** Retrieves the text value for a specific text input custom ID. @param customId The custom_id of the text input component. @returns The submitted text, or undefined if not found. */\r\n public getInputValue(customId: string): string | undefined {\r\n const rows =\r\n (this.data.data?.components as\r\n | { components?: { custom_id?: string; value?: string }[] }[]\r\n | undefined) ?? [];\r\n for (const row of rows) {\r\n for (const comp of row.components ?? []) {\r\n if (comp.custom_id === customId) return comp.value;\r\n }\r\n }\r\n return undefined;\r\n }\r\n\r\n /** Retrieves the text value for a text input, throwing if missing. @param customId The custom_id of the text input component. @returns The submitted text. @throws {TypeError} If the field is not found. */\r\n public getRequiredInputValue(customId: string): string {\r\n const value = this.getInputValue(customId);\r\n if (value === undefined)\r\n throw new TypeError(\r\n `Modal input \"${customId}\" was not found in the submission.`,\r\n );\r\n return value;\r\n }\r\n}\r\n\r\n// ─── AutocompleteInteraction ──────────────────────────────────────────────────\r\n\r\n/** Represents a Discord slash command autocomplete interaction. */\r\nexport class AutocompleteInteraction extends Interaction {\r\n /** Option resolver; use `options.getFocused()` for the focused value. */\r\n public readonly options: CommandOptions;\r\n\r\n public constructor(client: InteractionClient, data: InteractionData) {\r\n super(client, data);\r\n this.options = new CommandOptions(\r\n (data.data?.options as APIInteractionDataOption[]) ?? [],\r\n );\r\n }\r\n\r\n /** Gets the target command name. */\r\n public get commandName(): string {\r\n const name = this.data.data?.name;\r\n return typeof name === \"string\" ? name : \"\";\r\n }\r\n\r\n /** Gets the currently focused autocomplete option. */\r\n public get focusedOption():\r\n { name: string; value: unknown; type: number } | undefined {\r\n const options = this.data.data?.options;\r\n return findFocused(\r\n Array.isArray(options) ? (options as FocusableOption[]) : [],\r\n );\r\n }\r\n\r\n /** Responds to Discord with autocomplete choices. @param choices Array of name/value pairs to show. @throws {TypeError} If choices is not an array. */\r\n public async respond(\r\n choices: { name: string; value: string | number }[],\r\n ): Promise<void> {\r\n if (!Array.isArray(choices))\r\n throw new TypeError(\"Autocomplete choices must be an array.\");\r\n const response = new InteractionResponse(\r\n InteractionResponseEnum.Autocomplete,\r\n { choices } as InteractionReplyOptions,\r\n );\r\n await this.acknowledge(response, \"replied\");\r\n }\r\n}\r\n\r\n/** An option as Discord sends it in autocomplete data. */\r\ninterface FocusableOption {\r\n name: string;\r\n value?: unknown;\r\n type: number;\r\n focused?: boolean;\r\n options?: FocusableOption[];\r\n}\r\n\r\n/** Recursively finds the focused option in a nested options tree. */\r\nfunction findFocused(\r\n options: FocusableOption[],\r\n): { name: string; value: unknown; type: number } | undefined {\r\n for (const opt of options) {\r\n if (opt.focused)\r\n return { name: opt.name, value: opt.value, type: opt.type };\r\n if (Array.isArray(opt.options)) {\r\n const found = findFocused(opt.options);\r\n if (found) return found;\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\n// ─── Factory ──────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Creates a specialized interaction structure for a Gateway payload.\r\n * @param client Interaction transport.\r\n * @param data Gateway interaction payload.\r\n * @returns Specialized interaction structure.\r\n * @throws {TypeError} If required identifiers are missing.\r\n */\r\nexport function createInteraction(\r\n client: InteractionClient,\r\n data: InteractionData,\r\n): Interaction {\r\n switch (data.type) {\r\n case InteractionEnum.ApplicationCommand: {\r\n const commandType = data.data?.type;\r\n return commandType === COMMAND_USER ||\r\n commandType === COMMAND_MESSAGE\r\n ? new ContextMenuCommandInteraction(client, data)\r\n : new CommandInteraction(client, data);\r\n }\r\n case InteractionEnum.ApplicationCommandAutocomplete:\r\n return new AutocompleteInteraction(client, data);\r\n case InteractionEnum.MessageComponent:\r\n return new ComponentInteraction(client, data);\r\n case InteractionEnum.ModalSubmit:\r\n return new ModalSubmitInteraction(client, data);\r\n default:\r\n return new Interaction(client, data);\r\n }\r\n}\r\n\r\n/** @deprecated Use {@link InteractionEnum}. Removed in 0.3.0. */\r\nexport const InteractionType = InteractionEnum;\r\n/** @deprecated Use {@link InteractionEnum}. Removed in 0.3.0. */\r\nexport type InteractionType = InteractionEnum;\r\n",
|
|
26
|
+
"/** Resource structures for Discord messages and related entities. */\r\nimport { BaseStructure, Channel, User } from \"./base.js\";\r\nimport { GuildMember } from \"./resources.js\";\r\nimport type { ComponentInteraction } from \"./interactions.js\";\r\nimport type { Collector, CollectorOptions } from \"@lunibee/core\";\r\n\r\n/** Interaction tokens last 15 minutes, so a component collector with no limit of its own stops then. */\r\nconst COMPONENT_COLLECTOR_DEFAULT_TIME = 15 * 60_000;\r\n\r\n/** Options for {@link Message.createComponentCollector}. */\r\nexport interface ComponentCollectorOptions extends CollectorOptions<ComponentInteraction> {\r\n /** Only this component type (2 button, 3 string select...). */\r\n componentType?: number;\r\n}\r\nimport type { ResourceContext } from \"./base.js\";\r\n\r\n/** discord.js user-authored (non-system) message types: Default, Reply,\r\n * ChatInputCommand and ContextMenuCommand. Any other type is a system message. */\r\nconst NON_SYSTEM_MESSAGE_TYPES = new Set([0, 19, 20, 23]);\r\n\r\nexport {\r\n BaseStructure,\r\n Channel,\r\n Guild,\r\n User,\r\n CDN_BASE,\r\n cdnURL,\r\n} from \"./base.js\";\r\nexport type { ResourceContext, ImageURLOptions } from \"./base.js\";\r\n\r\nexport class Message extends BaseStructure {\r\n public content: string;\r\n public author: User;\r\n public channelId: string;\r\n public readonly channel: Channel;\r\n public guildId?: string;\r\n public flags: number;\r\n /** Message creation timestamp (from timestamp field or snowflake). */\r\n public readonly timestamp: Date;\r\n public readonly attachments: import(\"@lunibee/types\").APIAttachment[];\r\n public readonly embeds: import(\"@lunibee/types\").APIEmbed[];\r\n public readonly mentions: User[];\r\n public readonly mentionRoles: string[];\r\n public pinned: boolean;\r\n public mentionEveryone: boolean;\r\n public type: number;\r\n public readonly reference?: import(\"@lunibee/types\").APIMessageReference;\r\n public readonly components: import(\"@lunibee/types\").APIMessageComponent[];\r\n public readonly referencedMessage?: Message | null;\r\n /** Stickers sent with the message (`sticker_items`). */\r\n public readonly stickers: import(\"@lunibee/types\").APIStickerItem[];\r\n /** The poll, when the message is one. */\r\n public readonly poll: import(\"@lunibee/types\").APIPoll | null;\r\n /** For a forwarded message, the snapshot of the original. */\r\n public readonly messageSnapshots: import(\"@lunibee/types\").APIMessageSnapshot[];\r\n /**\r\n * The author as a guild member, on guild messages from the Gateway. Its\r\n * `permissions` are computed from the cached roles; `member.kick()` and the\r\n * other member actions work when the message came from a client.\r\n */\r\n public member: GuildMember | null;\r\n readonly #context?: ResourceContext;\r\n\r\n /** Creates a message structure from Discord message data. */\r\n public constructor(\r\n data: import(\"@lunibee/types\").APIMessage,\r\n context?: ResourceContext,\r\n ) {\r\n super(data.id);\r\n if (!/^\\d{1,20}$/.test(data.channel_id))\r\n throw new TypeError(\r\n \"Message channel_id must be a valid snowflake.\",\r\n );\r\n this.content = data.content ?? \"\";\r\n this.author = new User(data.author);\r\n this.channelId = data.channel_id;\r\n this.guildId = data.guild_id;\r\n this.flags = data.flags ?? 0;\r\n this.timestamp = new Date(\r\n data.timestamp ?? Number((BigInt(this.id) >> 22n) + 1420070400000n),\r\n );\r\n this.attachments = data.attachments ?? [];\r\n this.embeds = data.embeds ?? [];\r\n this.components = data.components ?? [];\r\n this.mentions = (data.mentions ?? []).map((user) => new User(user));\r\n this.mentionRoles = data.mention_roles ?? [];\r\n this.pinned = data.pinned ?? false;\r\n this.mentionEveryone = data.mention_everyone ?? false;\r\n this.type = data.type ?? 0;\r\n this.reference = data.message_reference;\r\n this.stickers =\r\n data.sticker_items ??\r\n (data.stickers ?? []).map(({ id, name, format_type }) => ({\r\n id,\r\n name,\r\n format_type,\r\n }));\r\n this.poll = data.poll ?? null;\r\n this.messageSnapshots = data.message_snapshots ?? [];\r\n this.referencedMessage = data.referenced_message\r\n ? new Message(data.referenced_message, context)\r\n : data.referenced_message === null\r\n ? null\r\n : undefined;\r\n this.#context = context;\r\n this.member =\r\n data.member && data.guild_id\r\n ? new GuildMember(\r\n {\r\n ...data.member,\r\n user: data.member.user ?? data.author,\r\n guild_id: data.guild_id,\r\n },\r\n context,\r\n )\r\n : null;\r\n this.channel = new Channel(\r\n { id: data.channel_id, type: 0, guild_id: data.guild_id },\r\n context,\r\n );\r\n }\r\n\r\n /** Whether embeds are suppressed on this message. */\r\n public get embedsSuppressed(): boolean {\r\n return (this.flags & 4) !== 0;\r\n }\r\n\r\n /** Unix timestamp (ms) at which the message was created — discord.js parity.\r\n * Derived from the message `timestamp`, which itself falls back to the id snowflake. */\r\n public get createdTimestamp(): number {\r\n return this.timestamp.getTime();\r\n }\r\n\r\n /** Date at which the message was created — discord.js parity. Overrides the\r\n * snowflake-only `BaseStructure.createdAt` to honour the message `timestamp`. */\r\n public override get createdAt(): Date {\r\n return this.timestamp;\r\n }\r\n\r\n /** Edits this message. @param options Message fields to change. @returns The updated message. @throws {Error} If the message is not attached to a client. */\r\n public edit(\r\n options: Record<string, unknown> & { content?: string },\r\n ): Promise<Message> {\r\n if (!this.#context)\r\n throw new Error(\"This message is not attached to a client.\");\r\n return this.#context.editMessage(this.channelId, this.id, options);\r\n }\r\n\r\n /** Updates this message using the same resource operation as edit. @param options Message fields to change. @returns The updated message. @throws {Error} If the message is not attached to a client. */\r\n public update(\r\n options: Record<string, unknown> & { content?: string },\r\n ): Promise<Message> {\r\n return this.edit(options);\r\n }\r\n\r\n /** Deletes this message. @param reason Audit-log reason (shown when deleting someone else's message). @returns A promise fulfilled when Discord confirms deletion. @throws {Error} If the message is not attached to a client. */\r\n public delete(reason?: string): Promise<void> {\r\n if (!this.#context)\r\n throw new Error(\"This message is not attached to a client.\");\r\n return this.#context.deleteMessage(this.channelId, this.id, reason);\r\n }\r\n\r\n /** Replies to this message. @param options Message content or payload. @returns The created reply message. @throws {Error} If the message is not attached to a client. */\r\n public reply(\r\n options: string | (Record<string, unknown> & { content?: string }),\r\n ): Promise<Message> {\r\n if (!this.#context)\r\n throw new Error(\"This message is not attached to a client.\");\r\n const payload =\r\n typeof options === \"string\" ? { content: options } : { ...options };\r\n payload.message_reference = {\r\n message_id: this.id,\r\n channel_id: this.channelId,\r\n guild_id: this.guildId,\r\n };\r\n return this.#context.sendMessage(this.channelId, payload);\r\n }\r\n\r\n /** Crossposts this message. @returns The resulting message. @throws {Error} If the message is not attached to a client. */\r\n public crosspost(): Promise<Message> {\r\n if (!this.#context)\r\n throw new Error(\"This message is not attached to a client.\");\r\n return this.#context.crosspostMessage(this.channelId, this.id);\r\n }\r\n\r\n /**\r\n * Collects clicks and picks on this message's components. It always ends:\r\n * after `time`, or 15 minutes (an interaction token's life) when neither\r\n * `time` nor `idle` is set.\r\n * @example\r\n * const collector = message.createComponentCollector({ filter: (i) => i.user?.id === authorId, time: 60_000 });\r\n * collector.on(\"collect\", (i) => i.update({ content: `Picked ${i.customId}` }));\r\n */\r\n public createComponentCollector(\r\n options: ComponentCollectorOptions = {},\r\n ): Collector<string, ComponentInteraction> {\r\n const collect = this.#context?.collectInteractions;\r\n if (!collect)\r\n throw new Error(\"This message is not attached to a client.\");\r\n const { componentType, filter, ...rest } = options;\r\n return collect({\r\n ...rest,\r\n time:\r\n rest.time ??\r\n (rest.idle ? undefined : COMPONENT_COLLECTOR_DEFAULT_TIME),\r\n filter: async (interaction) =>\r\n interaction.isMessageComponent() &&\r\n interaction.messageId === this.id &&\r\n (componentType === undefined ||\r\n interaction.componentType === componentType) &&\r\n (filter ? await filter(interaction) : true),\r\n }) as unknown as Collector<string, ComponentInteraction>;\r\n }\r\n\r\n /**\r\n * Waits for the next click or pick on this message's components.\r\n * @param options `time` (default 15 minutes), `filter`, `componentType`.\r\n * @returns The interaction. @throws {Error} When time runs out first.\r\n */\r\n public awaitComponent(\r\n options: Omit<ComponentCollectorOptions, \"max\"> = {},\r\n ): Promise<ComponentInteraction> {\r\n return this.createComponentCollector({ ...options, max: 1 }).next();\r\n }\r\n\r\n /** Adds a reaction to this message. @param emoji Emoji identifier. @returns A promise fulfilled when the reaction is added. @throws {Error} If reactions are unavailable. */\r\n public react(emoji: string): Promise<void> {\r\n if (!this.#context?.addReaction)\r\n throw new Error(\"This message is not attached to a client.\");\r\n return this.#context.addReaction(this.channelId, this.id, emoji);\r\n }\r\n\r\n /** Removes a reaction from this message. @param emoji Emoji identifier. @param userId User whose reaction should be removed; omit to remove the current user's reaction. @returns A promise fulfilled when the reaction is removed. @throws {Error} If reaction operations are unavailable. */\r\n public removeReaction(emoji: string, userId?: string): Promise<void> {\r\n if (!this.#context)\r\n throw new Error(\"This message is not attached to a client.\");\r\n return userId\r\n ? (this.#context.removeReaction?.(\r\n this.channelId,\r\n this.id,\r\n emoji,\r\n userId,\r\n ) ??\r\n Promise.reject(\r\n new Error(\"Reaction operations are unavailable.\"),\r\n ))\r\n : (this.#context.removeOwnReaction?.(\r\n this.channelId,\r\n this.id,\r\n emoji,\r\n ) ??\r\n Promise.reject(\r\n new Error(\"Reaction operations are unavailable.\"),\r\n ));\r\n }\r\n\r\n /** Removes all reactions from this message. @returns A promise fulfilled when reactions are removed. @throws {Error} If reaction operations are unavailable. */\r\n public removeAllReactions(): Promise<void> {\r\n if (!this.#context?.removeAllReactions)\r\n throw new Error(\"This message is not attached to a client.\");\r\n return this.#context.removeAllReactions(this.channelId, this.id);\r\n }\r\n\r\n /** Pins this message. @param reason Audit-log reason. @returns A promise fulfilled when the message is pinned. @throws {Error} If pin operations are unavailable. */\r\n public pin(reason?: string): Promise<void> {\r\n if (!this.#context?.pinMessage)\r\n throw new Error(\"This message is not attached to a client.\");\r\n return this.#context.pinMessage(this.channelId, this.id, reason);\r\n }\r\n\r\n /** Unpins this message. @param reason Audit-log reason. @returns A promise fulfilled when the message is unpinned. @throws {Error} If pin operations are unavailable. */\r\n public unpin(reason?: string): Promise<void> {\r\n if (!this.#context?.unpinMessage)\r\n throw new Error(\"This message is not attached to a client.\");\r\n return this.#context.unpinMessage(this.channelId, this.id, reason);\r\n }\r\n\r\n // ─── Flag-based getters ───────────────────────────────────────────────────────\r\n\r\n /** Whether this message was sent ephemerally (only visible to the recipient). */\r\n public get isEphemeral(): boolean {\r\n return (this.flags & 64) !== 0;\r\n }\r\n\r\n /** Whether this message is currently pinned in its channel. */\r\n public get isPinned(): boolean {\r\n return this.pinned;\r\n }\r\n\r\n /** Whether this is a system-generated message (join, boost, etc). Mirrors\r\n * discord.js: a message is \"system\" unless its type is one of the user-authored\r\n * types — Default (0), Reply (19), ChatInputCommand (20) or ContextMenuCommand (23). */\r\n public get isSystemMessage(): boolean {\r\n return !NON_SYSTEM_MESSAGE_TYPES.has(this.type);\r\n }\r\n\r\n /** Whether this message was crossposted from an announcement channel. */\r\n public get isCrosspost(): boolean {\r\n return (this.flags & 2) !== 0;\r\n }\r\n\r\n /** Whether this message has file attachments. */\r\n public get hasAttachments(): boolean {\r\n return this.attachments.length > 0;\r\n }\r\n\r\n /** Whether this message contains embeds. */\r\n public get hasEmbeds(): boolean {\r\n return this.embeds.length > 0;\r\n }\r\n\r\n /** Whether this message contains interactive components. */\r\n public get hasComponents(): boolean {\r\n return this.components.length > 0;\r\n }\r\n\r\n /** Edits this message to suppress its embeds. @returns The updated message. */\r\n public suppressEmbeds(): Promise<Message> {\r\n return this.edit({ flags: this.flags | 4 });\r\n }\r\n\r\n /** Returns a plain-object snapshot of all message fields. */\r\n public toJSON(): Record<string, unknown> {\r\n return {\r\n id: this.id,\r\n content: this.content,\r\n channelId: this.channelId,\r\n guildId: this.guildId,\r\n flags: this.flags,\r\n pinned: this.pinned,\r\n mentionEveryone: this.mentionEveryone,\r\n type: this.type,\r\n timestamp: this.timestamp.toISOString(),\r\n author: { id: this.author.id, username: this.author.username },\r\n attachments: [...this.attachments],\r\n embeds: [...this.embeds],\r\n components: [...this.components],\r\n mentions: this.mentions.map((u) => u.id),\r\n mentionRoles: [...this.mentionRoles],\r\n reference: this.reference,\r\n referencedMessage: this.referencedMessage\r\n ? this.referencedMessage.id\r\n : this.referencedMessage,\r\n };\r\n }\r\n}\r\n\r\nexport {\r\n GuildMember,\r\n Role,\r\n TextChannel,\r\n Invite,\r\n Webhook,\r\n WebhookEnum,\r\n WebhookType,\r\n Emoji,\r\n AutoModerationRule,\r\n WelcomeScreenChannel,\r\n GuildWelcomeScreen,\r\n OnboardingPromptOption,\r\n OnboardingPrompt,\r\n GuildOnboarding,\r\n} from \"./resources.js\";\r\nexport {\r\n NewsChannel,\r\n DMChannel,\r\n VoiceChannel,\r\n StageChannel,\r\n CategoryChannel,\r\n ThreadChannel,\r\n ForumChannel,\r\n MediaChannel,\r\n createChannel,\r\n} from \"./channels.js\";\r\nexport * from \"./interactions.js\";\r\nexport { Embed } from \"./embed.js\";\r\nexport { AuditLog, AuditLogEntry } from \"./audit-log.js\";\r\nexport { PermissionsBitField } from \"@lunibee/core\";\r\n",
|
|
27
|
+
"import { Collection } from \"@lunibee/collection\";\r\n\r\n/** Opt-in per-channel message cache. Messages are temporary data, so they\r\n * use bounded TTL/LRU storage rather than permanent resource storage. */\r\nexport interface MessageCacheOptions {\r\n /** Messages kept per channel; least-recently-used are evicted. Default 100. */\r\n maxSize?: number;\r\n /** Sliding TTL in ms. Omit for no expiry. */\r\n ttl?: number;\r\n}\r\nimport { REST, Routes, type RESTFileAttachment } from \"@lunibee/rest\";\r\nimport type { AllowedMentions } from \"@lunibee/types\";\r\nimport { Message, type ResourceContext } from \"@lunibee/structures\";\r\n\r\n/** A file to upload with a message. */\r\nexport interface MessageFile {\r\n name: string;\r\n data: Blob | Uint8Array | ArrayBuffer | string;\r\n contentType?: string;\r\n}\r\n\r\nexport type MessageCreateOptions = Record<string, unknown> & {\r\n content?: string;\r\n /** Files to upload; the message is sent as multipart. */\r\n files?: MessageFile[];\r\n};\r\nexport type MessageEditOptions = MessageCreateOptions;\r\n\r\n/**\r\n * Splits `files` out of a message payload into a REST upload, encoding string\r\n * data as UTF-8. `allowedMentions` is the client's default, applied only when\r\n * the payload has no `allowed_mentions` of its own.\r\n */\r\nexport function toRequest(\r\n options: MessageCreateOptions,\r\n allowedMentions?: AllowedMentions,\r\n):\r\n | Omit<MessageCreateOptions, \"files\">\r\n | {\r\n body: Omit<MessageCreateOptions, \"files\">;\r\n files: RESTFileAttachment[];\r\n } {\r\n const { files, ...body } = options;\r\n if (allowedMentions !== undefined && body.allowed_mentions === undefined)\r\n body.allowed_mentions = allowedMentions;\r\n if (!files?.length) return body;\r\n return {\r\n body,\r\n files: files.map((file) => ({\r\n name: file.name,\r\n data:\r\n typeof file.data === \"string\"\r\n ? new TextEncoder().encode(file.data)\r\n : file.data,\r\n contentType: file.contentType,\r\n })),\r\n };\r\n}\r\n\r\nexport class MessageManager {\r\n /** Cached messages; always empty unless a message cache is configured. */\r\n public readonly cache: Collection<string, Message>;\r\n readonly #caching: boolean;\r\n readonly #rest: REST;\r\n readonly #context: ResourceContext;\r\n readonly #channelId: string;\r\n\r\n /** The client's default `allowed_mentions`, for payloads without their own. */\r\n readonly #allowedMentions?: AllowedMentions;\r\n\r\n public constructor(\r\n rest: REST,\r\n context: ResourceContext,\r\n channelId: string,\r\n cache?: MessageCacheOptions,\r\n allowedMentions?: AllowedMentions,\r\n ) {\r\n if (!channelId) throw new TypeError(\"Channel ID is required.\");\r\n this.#allowedMentions = allowedMentions;\r\n this.#rest = rest;\r\n this.#context = context;\r\n this.#channelId = channelId;\r\n this.#caching = cache !== undefined;\r\n this.cache = new Collection<string, Message>(null, {\r\n ttl: cache?.ttl,\r\n maxSize: cache ? (cache.maxSize ?? 100) : undefined,\r\n });\r\n }\r\n public async resolve(messageId: string): Promise<Message> {\r\n return this.cache.get(messageId) ?? this.fetch(messageId);\r\n }\r\n public async send(options: MessageCreateOptions): Promise<Message> {\r\n const data = await this.#rest.post<\r\n ConstructorParameters<typeof Message>[0]\r\n >(\r\n Routes.channelMessages(this.#channelId),\r\n toRequest(options, this.#allowedMentions),\r\n );\r\n return this.upsert(data);\r\n }\r\n public async fetch(messageId: string): Promise<Message> {\r\n const data = await this.#rest.get<\r\n ConstructorParameters<typeof Message>[0]\r\n >(Routes.message(this.#channelId, messageId));\r\n return this.upsert(data);\r\n }\r\n public fetchMany(messageIds: Iterable<string>): Promise<Message[]> {\r\n return Promise.all(\r\n Array.from(messageIds, (messageId) => this.fetch(messageId)),\r\n );\r\n }\r\n public upsert(data: ConstructorParameters<typeof Message>[0]): Message {\r\n const existing = this.cache.peek(data.id);\r\n const message = new Message(data, this.#context);\r\n if (existing) {\r\n Object.assign(existing, message);\r\n return existing;\r\n }\r\n if (this.#caching) this.cache.set(message.id, message);\r\n return message;\r\n }\r\n public delete(messageId: string): boolean {\r\n return this.cache.delete(messageId);\r\n }\r\n}\r\n",
|
|
28
|
+
"import { REST, Routes } from \"@lunibee/rest\";\r\nimport {\r\n Channel,\r\n createChannel,\r\n type ResourceContext,\r\n} from \"@lunibee/structures\";\r\n\r\n/** Manages thread resources created from a parent channel. */\r\nexport class ThreadManager {\r\n readonly #rest: REST;\r\n readonly #context: ResourceContext;\r\n readonly #channelId: string;\r\n /** Creates a thread manager. @param rest REST transport. @param context Structure resource context. @param channelId Parent channel identifier. @throws {TypeError} If channelId is empty. */\r\n public constructor(\r\n rest: REST,\r\n context: ResourceContext,\r\n channelId: string,\r\n ) {\r\n if (!channelId) throw new TypeError(\"Channel ID is required.\");\r\n this.#rest = rest;\r\n this.#context = context;\r\n this.#channelId = channelId;\r\n }\r\n /** Creates a thread from a message. @param messageId Message identifier. @param options Thread creation options. @returns Created thread channel. @throws {Error} If REST rejects the request. */\r\n public async createFromMessage(\r\n messageId: string,\r\n options: {\r\n name: string;\r\n autoArchiveDuration?: 60 | 1440 | 4320 | 10080;\r\n rateLimitPerUser?: number;\r\n },\r\n ): Promise<Channel> {\r\n const data = await this.#rest.post<\r\n ConstructorParameters<typeof Channel>[0]\r\n >(Routes.messageThread(this.#channelId, messageId), {\r\n name: options.name,\r\n auto_archive_duration: options.autoArchiveDuration,\r\n rate_limit_per_user: options.rateLimitPerUser,\r\n });\r\n return createChannel(data, this.#context);\r\n }\r\n}\r\n",
|
|
29
|
+
"import { ResourceManager } from \"./base.js\";\r\nimport { User } from \"@lunibee/structures\";\r\nimport { type REST, Routes } from \"@lunibee/rest\";\r\nimport type { APIChannel } from \"@lunibee/types\";\r\n\r\ntype UserData = ConstructorParameters<typeof User>[0];\r\n\r\nexport interface UserEditOptions {\r\n username?: string;\r\n avatar?: string | null;\r\n}\r\n\r\nexport class UserManager extends ResourceManager<string, User> {\r\n readonly #rest: REST;\r\n public constructor(rest: REST) {\r\n super(\r\n async (id) =>\r\n new User(await rest.get<UserData>(Routes.userById(id))),\r\n (user) => user.id,\r\n );\r\n this.#rest = rest;\r\n }\r\n\r\n /** Gets the currently logged-in bot user. */\r\n public async fetchMe(): Promise<User> {\r\n const data = await this.#rest.get<UserData>(\"/users/@me\");\r\n return this.upsert(new User(data));\r\n }\r\n\r\n /** Modifies the currently logged-in bot user. */\r\n public async editMe(options: UserEditOptions): Promise<User> {\r\n const data = await this.#rest.patch<UserData>(\"/users/@me\", options);\r\n return this.upsert(new User(data));\r\n }\r\n\r\n /** Leaves a guild. */\r\n public async leaveGuild(guildId: string): Promise<void> {\r\n await this.#rest.delete(Routes.currentUserGuild(guildId));\r\n }\r\n\r\n /** Creates a DM channel with a user. */\r\n public async createDM(userId: string): Promise<APIChannel> {\r\n return this.#rest.post<APIChannel>(\"/users/@me/channels\", {\r\n recipient_id: userId,\r\n });\r\n }\r\n}\r\n",
|
|
30
|
+
"import { Manager, splitReason } from \"./base.js\";\r\nimport { Emoji } from \"@lunibee/structures\";\r\nimport { Routes, type REST } from \"@lunibee/rest\";\r\n\r\n/** Strict payload for creating a custom guild emoji. */\r\nexport interface EmojiCreateOptions {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n /** Emoji name (1-32 chars, alphanumeric + underscores). */\r\n name: string;\r\n /** Base64-encoded 128x128 image data URI. */\r\n image: string;\r\n /** Role IDs allowed to use the emoji. */\r\n roles?: string[];\r\n}\r\n\r\n/** Strict payload for editing a custom guild emoji. */\r\nexport interface EmojiEditOptions {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n /** New emoji name. */\r\n name?: string;\r\n /** Role IDs allowed to use the emoji. */\r\n roles?: string[];\r\n}\r\n\r\n/** Manages custom emojis for a guild. */\r\nexport class EmojiManager extends Manager<string, Emoji> {\r\n readonly #rest: REST;\r\n readonly #guildId: string;\r\n\r\n public constructor(rest: REST, guildId: string) {\r\n super();\r\n this.#rest = rest;\r\n this.#guildId = guildId;\r\n }\r\n\r\n /** Fetches an emoji by ID; concurrent fetches share a request and a stale result never overwrites newer state. */\r\n public fetch(emojiId: string): Promise<Emoji> {\r\n return this.fetchOnce(\r\n emojiId,\r\n async () =>\r\n new Emoji(\r\n await this.#rest.get<\r\n ConstructorParameters<typeof Emoji>[0]\r\n >(Routes.guildEmoji(this.#guildId, emojiId)),\r\n ),\r\n (emoji) => this.#merge(emojiId, emoji),\r\n );\r\n }\r\n\r\n /** Fetches all emojis for this guild. */\r\n public async fetchAll(): Promise<Emoji[]> {\r\n const data = await this.#rest.get<\r\n ConstructorParameters<typeof Emoji>[0][]\r\n >(Routes.guildEmoji(this.#guildId));\r\n return data.map((item) => this.upsert(item));\r\n }\r\n\r\n /** Creates a new custom emoji. */\r\n public async create(options: EmojiCreateOptions): Promise<Emoji> {\r\n const [payload, reason] = splitReason(options);\r\n return this.upsert(\r\n await this.#rest.post<ConstructorParameters<typeof Emoji>[0]>(\r\n Routes.guildEmoji(this.#guildId),\r\n payload,\r\n { reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Edits an existing custom emoji. */\r\n public async edit(\r\n emojiId: string,\r\n options: EmojiEditOptions,\r\n ): Promise<Emoji> {\r\n const [payload, reason] = splitReason(options);\r\n return this.upsert(\r\n await this.#rest.patch<ConstructorParameters<typeof Emoji>[0]>(\r\n Routes.guildEmoji(this.#guildId, emojiId),\r\n payload,\r\n { reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Deletes a custom emoji. @param reason Audit-log reason. */\r\n public async remove(emojiId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(Routes.guildEmoji(this.#guildId, emojiId), {\r\n reason,\r\n });\r\n this.delete(emojiId);\r\n }\r\n\r\n /** @deprecated Use {@link EmojiManager.remove}, which also takes an audit-log reason. Removed in 0.3.0. */\r\n public deleteEmoji(emojiId: string): Promise<void> {\r\n return this.remove(emojiId);\r\n }\r\n\r\n /** Upserts an emoji into the manager cache. Custom emojis are keyed by their\r\n * snowflake ID; unicode emojis (no ID) are keyed by `unicode:${name}` so repeated\r\n * upserts reuse the same cached instance instead of allocating a new one each call. */\r\n public upsert(data: ConstructorParameters<typeof Emoji>[0]): Emoji {\r\n const key = data.id != null ? data.id : `unicode:${data.name ?? \"\"}`;\r\n return this.#merge(key, new Emoji(data));\r\n }\r\n\r\n #merge(key: string, emoji: Emoji): Emoji {\r\n const existing = this.get(key);\r\n if (existing) {\r\n Object.assign(existing, emoji);\r\n return existing;\r\n }\r\n this.set(key, emoji);\r\n return emoji;\r\n }\r\n}\r\n",
|
|
31
|
+
"import { Manager } from \"./base.js\";\r\nimport { Routes, type REST } from \"@lunibee/rest\";\r\nimport type {\r\n APIEntitlement,\r\n APISKU,\r\n APISoundboardSound,\r\n APISticker,\r\n APISubscription,\r\n} from \"@lunibee/types\";\r\n\r\nexport type {\r\n APIEntitlement,\r\n APISKU,\r\n APISoundboardSound,\r\n APISubscription,\r\n} from \"@lunibee/types\";\r\n\r\n/** Appends encoded query parameters, skipping undefined values. */\r\nfunction withQuery(\r\n path: string,\r\n query: Record<string, string | number | boolean | undefined>,\r\n): string {\r\n const params = new URLSearchParams();\r\n for (const [key, value] of Object.entries(query))\r\n if (value !== undefined) params.set(key, String(value));\r\n const suffix = params.toString();\r\n return suffix ? `${path}?${suffix}` : path;\r\n}\r\n\r\n// ─── Stickers ────────────────────────────────────────────────────────────────\r\n\r\n/** Fields for {@link GuildStickerManager.create}. */\r\nexport interface GuildStickerCreateOptions {\r\n name: string;\r\n description: string;\r\n /** Autocomplete/suggestion tags (e.g. an emoji name). */\r\n tags: string;\r\n /** PNG, APNG, GIF or Lottie JSON file, max 512 KiB. */\r\n file: Blob;\r\n reason?: string;\r\n}\r\n\r\n/** Manages a guild's custom stickers, cached by sticker ID. */\r\nexport class GuildStickerManager extends Manager<string, APISticker> {\r\n readonly #rest: REST;\r\n public readonly guildId: string;\r\n\r\n public constructor(rest: REST, guildId: string) {\r\n super();\r\n this.#rest = rest;\r\n this.guildId = guildId;\r\n }\r\n\r\n #store(sticker: APISticker): APISticker {\r\n this.set(sticker.id, sticker);\r\n return sticker;\r\n }\r\n\r\n /** Fetches every sticker in the guild, replacing the cache. */\r\n public async fetchAll(): Promise<APISticker[]> {\r\n const stickers = await this.#rest.get<APISticker[]>(\r\n Routes.guildSticker(this.guildId),\r\n );\r\n this.clear();\r\n return stickers.map((sticker) => this.#store(sticker));\r\n }\r\n\r\n /** Fetches one sticker. */\r\n public async fetch(stickerId: string): Promise<APISticker> {\r\n return this.#store(\r\n await this.#rest.get<APISticker>(\r\n Routes.guildSticker(this.guildId, stickerId),\r\n ),\r\n );\r\n }\r\n\r\n /** Uploads a sticker (multipart form, as Discord requires). */\r\n public async create(\r\n options: GuildStickerCreateOptions,\r\n ): Promise<APISticker> {\r\n const form = new FormData();\r\n form.set(\"name\", options.name);\r\n form.set(\"description\", options.description);\r\n form.set(\"tags\", options.tags);\r\n form.set(\"file\", options.file);\r\n return this.#store(\r\n await this.#rest.post<APISticker>(\r\n Routes.guildSticker(this.guildId),\r\n form,\r\n { reason: options.reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Edits a sticker's name, description or tags. */\r\n public async edit(\r\n stickerId: string,\r\n options: {\r\n name?: string;\r\n description?: string | null;\r\n tags?: string;\r\n reason?: string;\r\n },\r\n ): Promise<APISticker> {\r\n const { reason, ...body } = options;\r\n return this.#store(\r\n await this.#rest.patch<APISticker>(\r\n Routes.guildSticker(this.guildId, stickerId),\r\n body,\r\n { reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Deletes a sticker. */\r\n public async remove(stickerId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(Routes.guildSticker(this.guildId, stickerId), {\r\n reason,\r\n });\r\n this.delete(stickerId);\r\n }\r\n\r\n /** Replaces the cache with the full list from a `GUILD_STICKERS_UPDATE` event. */\r\n public sync(stickers: readonly APISticker[]): void {\r\n this.clear();\r\n for (const sticker of stickers) this.#store(sticker);\r\n }\r\n}\r\n\r\n// ─── Soundboard ──────────────────────────────────────────────────────────────\r\n\r\n/** Fields for {@link GuildSoundboardManager.create}. */\r\nexport interface SoundboardSoundCreateOptions {\r\n name: string;\r\n /** Data URI of an MP3 or OGG file (max 512 KiB, 5.2 s). */\r\n sound: string;\r\n /** 0 to 1; defaults to 1. */\r\n volume?: number;\r\n emojiId?: string;\r\n emojiName?: string;\r\n reason?: string;\r\n}\r\n\r\n/** Manages a guild's soundboard sounds, cached by sound ID. */\r\nexport class GuildSoundboardManager extends Manager<\r\n string,\r\n APISoundboardSound\r\n> {\r\n readonly #rest: REST;\r\n public readonly guildId: string;\r\n\r\n public constructor(rest: REST, guildId: string) {\r\n super();\r\n this.#rest = rest;\r\n this.guildId = guildId;\r\n }\r\n\r\n #store(sound: APISoundboardSound): APISoundboardSound {\r\n this.set(sound.sound_id, sound);\r\n return sound;\r\n }\r\n\r\n /** Fetches every soundboard sound in the guild, replacing the cache. */\r\n public async fetchAll(): Promise<APISoundboardSound[]> {\r\n const { items } = await this.#rest.get<{\r\n items: APISoundboardSound[];\r\n }>(Routes.guildSoundboardSound(this.guildId));\r\n this.clear();\r\n return items.map((sound) => this.#store(sound));\r\n }\r\n\r\n /** Fetches one sound. */\r\n public async fetch(soundId: string): Promise<APISoundboardSound> {\r\n return this.#store(\r\n await this.#rest.get<APISoundboardSound>(\r\n Routes.guildSoundboardSound(this.guildId, soundId),\r\n ),\r\n );\r\n }\r\n\r\n /** Creates a sound. */\r\n public async create(\r\n options: SoundboardSoundCreateOptions,\r\n ): Promise<APISoundboardSound> {\r\n if (\r\n options.volume !== undefined &&\r\n (options.volume < 0 || options.volume > 1)\r\n )\r\n throw new RangeError(\"Soundboard volume must be between 0 and 1.\");\r\n return this.#store(\r\n await this.#rest.post<APISoundboardSound>(\r\n Routes.guildSoundboardSound(this.guildId),\r\n {\r\n name: options.name,\r\n sound: options.sound,\r\n volume: options.volume,\r\n emoji_id: options.emojiId,\r\n emoji_name: options.emojiName,\r\n },\r\n { reason: options.reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Edits a sound's name, volume or emoji. */\r\n public async edit(\r\n soundId: string,\r\n options: {\r\n name?: string;\r\n volume?: number | null;\r\n emojiId?: string | null;\r\n emojiName?: string | null;\r\n reason?: string;\r\n },\r\n ): Promise<APISoundboardSound> {\r\n return this.#store(\r\n await this.#rest.patch<APISoundboardSound>(\r\n Routes.guildSoundboardSound(this.guildId, soundId),\r\n {\r\n name: options.name,\r\n volume: options.volume,\r\n emoji_id: options.emojiId,\r\n emoji_name: options.emojiName,\r\n },\r\n { reason: options.reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Deletes a sound. */\r\n public async remove(soundId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.guildSoundboardSound(this.guildId, soundId),\r\n { reason },\r\n );\r\n this.delete(soundId);\r\n }\r\n}\r\n\r\n// ─── Monetization ────────────────────────────────────────────────────────────\r\n\r\n/** Filters for {@link MonetizationManager.fetchEntitlements}. */\r\nexport interface EntitlementQuery {\r\n userId?: string;\r\n skuIds?: string[];\r\n guildId?: string;\r\n before?: string;\r\n after?: string;\r\n /** 1-100, default 100. */\r\n limit?: number;\r\n excludeEnded?: boolean;\r\n excludeDeleted?: boolean;\r\n}\r\n\r\n/**\r\n * SKUs, entitlements and subscriptions for one application. Entitlements are\r\n * cached by ID and kept current by the client's `ENTITLEMENT_*` events.\r\n */\r\nexport class MonetizationManager extends Manager<string, APIEntitlement> {\r\n readonly #rest: REST;\r\n public readonly applicationId: string;\r\n\r\n public constructor(rest: REST, applicationId: string) {\r\n super();\r\n this.#rest = rest;\r\n this.applicationId = applicationId;\r\n }\r\n\r\n /** Fetches the application's SKUs. */\r\n public fetchSkus(): Promise<APISKU[]> {\r\n return this.#rest.get<APISKU[]>(\r\n Routes.applicationSkus(this.applicationId),\r\n );\r\n }\r\n\r\n /** Fetches entitlements matching the filters and caches them. */\r\n public async fetchEntitlements(\r\n query: EntitlementQuery = {},\r\n ): Promise<APIEntitlement[]> {\r\n if (\r\n query.limit !== undefined &&\r\n (!Number.isInteger(query.limit) ||\r\n query.limit < 1 ||\r\n query.limit > 100)\r\n )\r\n throw new RangeError(\"Entitlement limit must be 1-100.\");\r\n const entitlements = await this.#rest.get<APIEntitlement[]>(\r\n withQuery(Routes.applicationEntitlement(this.applicationId), {\r\n user_id: query.userId,\r\n sku_ids: query.skuIds?.join(\",\"),\r\n guild_id: query.guildId,\r\n before: query.before,\r\n after: query.after,\r\n limit: query.limit,\r\n exclude_ended: query.excludeEnded,\r\n exclude_deleted: query.excludeDeleted,\r\n }),\r\n );\r\n for (const entitlement of entitlements)\r\n this.set(entitlement.id, entitlement);\r\n return entitlements;\r\n }\r\n\r\n /** Fetches one entitlement. */\r\n public async fetch(entitlementId: string): Promise<APIEntitlement> {\r\n const entitlement = await this.#rest.get<APIEntitlement>(\r\n Routes.applicationEntitlement(this.applicationId, entitlementId),\r\n );\r\n this.set(entitlement.id, entitlement);\r\n return entitlement;\r\n }\r\n\r\n /** Marks a one-time-purchase entitlement as consumed. */\r\n public async consume(entitlementId: string): Promise<void> {\r\n await this.#rest.post(\r\n Routes.consumeEntitlement(this.applicationId, entitlementId),\r\n );\r\n const cached = this.get(entitlementId);\r\n if (cached) cached.consumed = true;\r\n }\r\n\r\n /** Creates a test entitlement for a user or guild (owner type 1 = guild, 2 = user). */\r\n public async createTestEntitlement(options: {\r\n skuId: string;\r\n ownerId: string;\r\n ownerType: 1 | 2;\r\n }): Promise<APIEntitlement> {\r\n const entitlement = await this.#rest.post<APIEntitlement>(\r\n Routes.applicationEntitlement(this.applicationId),\r\n {\r\n sku_id: options.skuId,\r\n owner_id: options.ownerId,\r\n owner_type: options.ownerType,\r\n },\r\n );\r\n this.set(entitlement.id, entitlement);\r\n return entitlement;\r\n }\r\n\r\n /** Deletes a test entitlement. */\r\n public async deleteTestEntitlement(entitlementId: string): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.applicationEntitlement(this.applicationId, entitlementId),\r\n );\r\n this.delete(entitlementId);\r\n }\r\n\r\n /** Fetches a SKU's subscriptions for a user, or one subscription. */\r\n public fetchSubscriptions(\r\n skuId: string,\r\n query: {\r\n userId?: string;\r\n before?: string;\r\n after?: string;\r\n limit?: number;\r\n } = {},\r\n ): Promise<APISubscription[]> {\r\n return this.#rest.get<APISubscription[]>(\r\n withQuery(Routes.skuSubscription(skuId), {\r\n user_id: query.userId,\r\n before: query.before,\r\n after: query.after,\r\n limit: query.limit,\r\n }),\r\n );\r\n }\r\n\r\n /** Fetches one subscription. */\r\n public fetchSubscription(\r\n skuId: string,\r\n subscriptionId: string,\r\n ): Promise<APISubscription> {\r\n return this.#rest.get<APISubscription>(\r\n Routes.skuSubscription(skuId, subscriptionId),\r\n );\r\n }\r\n}\r\n",
|
|
32
|
+
"import { REST, Routes } from \"@lunibee/rest\";\r\nimport { GuildMember, type ResourceContext } from \"@lunibee/structures\";\r\nimport { ResourceManager, splitReason } from \"./base.js\";\r\nimport type { APIGuildMember } from \"@lunibee/types\";\r\n\r\nexport interface MemberEditOptions {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n nick?: string | null;\r\n roles?: string[];\r\n mute?: boolean;\r\n deaf?: boolean;\r\n channel_id?: string | null;\r\n communication_disabled_until?: string | null;\r\n}\r\n\r\nexport interface BanOptions {\r\n reason?: string;\r\n deleteMessageSeconds?: number;\r\n}\r\n\r\n/** Manages Discord guild members. */\r\nexport class GuildMemberManager extends ResourceManager<string, GuildMember> {\r\n readonly #rest: REST;\r\n readonly #context: () => ResourceContext | undefined;\r\n public readonly guildId: string;\r\n\r\n /** @param context Gives fetched members their actions (`member.kick()`...). */\r\n public constructor(\r\n guildId: string,\r\n rest: REST,\r\n context: () => ResourceContext | undefined = () => undefined,\r\n ) {\r\n super(\r\n (id: string) =>\r\n rest\r\n .get<APIGuildMember>(Routes.guildMember(guildId, id))\r\n .then(\r\n (data) =>\r\n new GuildMember(\r\n { ...data, guild_id: guildId },\r\n context(),\r\n ),\r\n ),\r\n (member: GuildMember) => member.user.id,\r\n );\r\n this.guildId = guildId;\r\n this.#rest = rest;\r\n this.#context = context;\r\n }\r\n\r\n /** Kicks a member from the guild. @param reason Audit-log reason. */\r\n public async kick(userId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(Routes.guildMember(this.guildId, userId), {\r\n reason,\r\n });\r\n this.delete(userId);\r\n }\r\n\r\n /** Bans a user from the guild. */\r\n public async ban(userId: string, options: BanOptions = {}): Promise<void> {\r\n await this.#rest.put(\r\n Routes.guildBan(this.guildId, userId),\r\n { delete_message_seconds: options.deleteMessageSeconds },\r\n { reason: options.reason },\r\n );\r\n this.delete(userId);\r\n }\r\n\r\n /** Unbans a user from the guild. @param reason Audit-log reason. */\r\n public async unban(userId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(Routes.guildBan(this.guildId, userId), {\r\n reason,\r\n });\r\n }\r\n\r\n /** Edits a guild member (nickname, roles, timeout, mute, deaf). Put the audit-log reason in `options.reason`. @param reason Deprecated: use `options.reason`. Removed in 0.3.0. */\r\n public async edit(\r\n userId: string,\r\n options: MemberEditOptions,\r\n reason?: string,\r\n ): Promise<GuildMember> {\r\n const [payload, optionsReason] = splitReason(options);\r\n const data = await this.#rest.patch<\r\n import(\"@lunibee/types\").APIGuildMember\r\n >(Routes.guildMember(this.guildId, userId), payload, {\r\n reason: optionsReason ?? reason,\r\n });\r\n const member = new GuildMember(\r\n { ...data, guild_id: this.guildId },\r\n this.#context(),\r\n );\r\n this.set(member.user.id, member);\r\n return member;\r\n }\r\n\r\n /** Adds a role to a member. @param reason Audit-log reason. */\r\n public async addRole(\r\n userId: string,\r\n roleId: string,\r\n reason?: string,\r\n ): Promise<void> {\r\n await this.#rest.put(\r\n Routes.guildMemberRole(this.guildId, userId, roleId),\r\n undefined,\r\n { reason },\r\n );\r\n }\r\n\r\n /** Removes a role from a member. @param reason Audit-log reason. */\r\n public async removeRole(\r\n userId: string,\r\n roleId: string,\r\n reason?: string,\r\n ): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.guildMemberRole(this.guildId, userId, roleId),\r\n { reason },\r\n );\r\n }\r\n\r\n /** Times out a member for a given duration in milliseconds (or clears timeout if null). @param reason Audit-log reason. */\r\n public async timeout(\r\n userId: string,\r\n milliseconds: number | null,\r\n reason?: string,\r\n ): Promise<GuildMember> {\r\n const timeoutDate =\r\n milliseconds === null\r\n ? null\r\n : new Date(Date.now() + milliseconds).toISOString();\r\n return this.edit(\r\n userId,\r\n { communication_disabled_until: timeoutDate },\r\n reason,\r\n );\r\n }\r\n}\r\n",
|
|
33
|
+
"import { REST, Routes } from \"@lunibee/rest\";\r\nimport { Role } from \"@lunibee/structures\";\r\nimport type { APIRole } from \"@lunibee/types\";\r\nimport { ResourceManager } from \"./base.js\";\r\n\r\nexport interface RoleCreateOptions {\r\n name: string;\r\n permissions?: bigint | number | string;\r\n color?: number;\r\n hoist?: boolean;\r\n mentionable?: boolean;\r\n reason?: string;\r\n}\r\n\r\nexport interface RoleEditOptions {\r\n name?: string;\r\n permissions?: bigint | number | string;\r\n color?: number;\r\n hoist?: boolean;\r\n mentionable?: boolean;\r\n position?: number;\r\n reason?: string;\r\n}\r\n\r\n/** Manages Discord guild roles. */\r\nexport class RoleManager extends ResourceManager<string, Role> {\r\n readonly #rest: REST;\r\n public readonly guildId: string;\r\n\r\n public constructor(guildId: string, rest: REST) {\r\n super(\r\n (id: string) =>\r\n rest\r\n .get<APIRole>(Routes.guildRole(guildId, id))\r\n .then((data) => new Role(data)),\r\n (role: Role) => role.id,\r\n );\r\n this.guildId = guildId;\r\n this.#rest = rest;\r\n }\r\n\r\n /** Fetches all roles in the guild. */\r\n public async fetchAll(): Promise<Role[]> {\r\n const data = await this.#rest.get<APIRole[]>(\r\n Routes.guildRoles(this.guildId),\r\n );\r\n return data.map((item) => {\r\n const role = new Role(item);\r\n this.set(role.id, role);\r\n return role;\r\n });\r\n }\r\n\r\n /** Creates a new role in the guild. */\r\n public async create(options: RoleCreateOptions): Promise<Role> {\r\n const { reason, ...payload } = options;\r\n const data = await this.#rest.post<APIRole>(\r\n Routes.guildRoles(this.guildId),\r\n rolePayload(payload),\r\n { reason },\r\n );\r\n return this.#store(data);\r\n }\r\n\r\n /** Edits an existing role. */\r\n public async edit(roleId: string, options: RoleEditOptions): Promise<Role> {\r\n const { reason, ...payload } = options;\r\n const data = await this.#rest.patch<APIRole>(\r\n Routes.guildRole(this.guildId, roleId),\r\n rolePayload(payload),\r\n { reason },\r\n );\r\n return this.#store(data);\r\n }\r\n\r\n #store(data: APIRole): Role {\r\n const role = new Role(data);\r\n this.set(role.id, role);\r\n return role;\r\n }\r\n\r\n /** Deletes a role. @param reason Audit-log reason. */\r\n public async remove(roleId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(Routes.guildRole(this.guildId, roleId), {\r\n reason,\r\n });\r\n this.delete(roleId);\r\n }\r\n /**\r\n * Moves roles in the hierarchy. Discord shifts the other roles around them.\r\n * @param positions Each role's ID and its new position.\r\n * @param reason Audit-log reason.\r\n * @returns Every role in the guild, in their new order.\r\n */\r\n public async setPositions(\r\n positions: readonly { id: string; position: number }[],\r\n reason?: string,\r\n ): Promise<Role[]> {\r\n const data = await this.#rest.patch<\r\n ConstructorParameters<typeof Role>[0][]\r\n >(\r\n Routes.guildRoles(this.guildId),\r\n positions.map(({ id, position }) => ({ id, position })),\r\n { reason },\r\n );\r\n return data.map((item) => {\r\n const role = new Role(item);\r\n this.set(role.id, role);\r\n return role;\r\n });\r\n }\r\n /** @deprecated Use {@link RoleManager.remove}, which also takes an audit-log reason. Removed in 0.3.0. */\r\n public deleteRole(roleId: string): Promise<void> {\r\n return this.remove(roleId);\r\n }\r\n}\r\n\r\n/** Role options as Discord expects them: `permissions` as a decimal string. */\r\nfunction rolePayload(options: Omit<RoleEditOptions, \"reason\">) {\r\n const { permissions, ...rest } = options;\r\n return {\r\n ...rest,\r\n permissions:\r\n permissions !== undefined ? String(permissions) : undefined,\r\n };\r\n}\r\n",
|
|
34
|
+
"import { Manager, splitReason } from \"./base.js\";\r\nimport { Routes, type REST } from \"@lunibee/rest\";\r\nimport type {\r\n APIChannel,\r\n APIOverwrite,\r\n APIGuildScheduledEvent,\r\n APIStageInstance,\r\n UserData,\r\n} from \"@lunibee/types\";\r\n\r\n/** Raw Discord ban object. */\r\nexport interface APIBan {\r\n user: UserData;\r\n reason: string | null;\r\n}\r\n\r\n/** Options for {@link GuildBanManager.create}. */\r\nexport interface GuildBanCreateOptions {\r\n /** Seconds of message history to delete (0-604800). */\r\n deleteMessageSeconds?: number;\r\n /** Audit-log reason. */\r\n reason?: string;\r\n}\r\n\r\n/** Appends encoded query parameters to a route. */\r\nfunction withQuery(path: string, params: Record<string, unknown>): string {\r\n const query = new URLSearchParams();\r\n for (const [key, value] of Object.entries(params))\r\n if (value !== undefined) query.set(key, String(value));\r\n const suffix = query.toString();\r\n return suffix ? `${path}?${suffix}` : path;\r\n}\r\n\r\n/** Manages a guild's bans, cached by user ID. Discord.js-familiar. */\r\nexport class GuildBanManager extends Manager<string, APIBan> {\r\n readonly #rest: REST;\r\n public readonly guildId: string;\r\n\r\n public constructor(rest: REST, guildId: string) {\r\n super();\r\n this.#rest = rest;\r\n this.guildId = guildId;\r\n }\r\n\r\n /** Fetches one ban. */\r\n public async fetch(userId: string): Promise<APIBan> {\r\n const ban = await this.#rest.get<APIBan>(\r\n Routes.guildBan(this.guildId, userId),\r\n );\r\n this.set(ban.user.id, ban);\r\n return ban;\r\n }\r\n\r\n /** Fetches a page of bans (`limit` 1-1000, `before`/`after` user-ID cursors). */\r\n public async fetchAll(\r\n options: { limit?: number; before?: string; after?: string } = {},\r\n ): Promise<APIBan[]> {\r\n const limit =\r\n options.limit === undefined\r\n ? undefined\r\n : Math.min(1000, Math.max(1, options.limit));\r\n const bans = await this.#rest.get<APIBan[]>(\r\n withQuery(Routes.guildBans(this.guildId), {\r\n limit,\r\n before: options.before,\r\n after: options.after,\r\n }),\r\n );\r\n for (const ban of bans) this.set(ban.user.id, ban);\r\n return bans;\r\n }\r\n\r\n /** Bans a user. */\r\n public async create(\r\n userId: string,\r\n options: GuildBanCreateOptions = {},\r\n ): Promise<void> {\r\n await this.#rest.put(\r\n Routes.guildBan(this.guildId, userId),\r\n { delete_message_seconds: options.deleteMessageSeconds },\r\n { reason: options.reason },\r\n );\r\n }\r\n\r\n /** Lifts a ban. */\r\n public async remove(userId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(Routes.guildBan(this.guildId, userId), {\r\n reason,\r\n });\r\n this.delete(userId);\r\n }\r\n}\r\n\r\n/** Fields accepted when creating or editing a scheduled event. */\r\nexport type GuildScheduledEventOptions = Partial<\r\n Omit<APIGuildScheduledEvent, \"id\" | \"guild_id\" | \"creator\" | \"user_count\">\r\n> &\r\n Record<string, unknown> & {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n };\r\n\r\n/** Manages a guild's scheduled events, cached by event ID. Discord.js-familiar. */\r\nexport class GuildScheduledEventManager extends Manager<\r\n string,\r\n APIGuildScheduledEvent\r\n> {\r\n readonly #rest: REST;\r\n public readonly guildId: string;\r\n\r\n public constructor(rest: REST, guildId: string) {\r\n super();\r\n this.#rest = rest;\r\n this.guildId = guildId;\r\n }\r\n\r\n #store(event: APIGuildScheduledEvent): APIGuildScheduledEvent {\r\n this.set(event.id, event);\r\n return event;\r\n }\r\n\r\n /** Fetches one event. */\r\n public async fetch(\r\n eventId: string,\r\n options: { withUserCount?: boolean } = {},\r\n ): Promise<APIGuildScheduledEvent> {\r\n return this.#store(\r\n await this.#rest.get(\r\n withQuery(Routes.guildScheduledEvent(this.guildId, eventId), {\r\n with_user_count: options.withUserCount,\r\n }),\r\n ),\r\n );\r\n }\r\n\r\n /** Fetches every event in the guild. */\r\n public async fetchAll(\r\n options: { withUserCount?: boolean } = {},\r\n ): Promise<APIGuildScheduledEvent[]> {\r\n const events = await this.#rest.get<APIGuildScheduledEvent[]>(\r\n withQuery(Routes.guildScheduledEvents(this.guildId), {\r\n with_user_count: options.withUserCount,\r\n }),\r\n );\r\n return events.map((event) => this.#store(event));\r\n }\r\n\r\n /** Creates an event. */\r\n public async create(\r\n options: GuildScheduledEventOptions,\r\n reason?: string,\r\n ): Promise<APIGuildScheduledEvent> {\r\n const [payload, optionsReason] = splitReason(options);\r\n return this.#store(\r\n await this.#rest.post(\r\n Routes.guildScheduledEvents(this.guildId),\r\n payload,\r\n { reason: optionsReason ?? reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Edits an event. */\r\n public async edit(\r\n eventId: string,\r\n options: GuildScheduledEventOptions,\r\n reason?: string,\r\n ): Promise<APIGuildScheduledEvent> {\r\n const [payload, optionsReason] = splitReason(options);\r\n return this.#store(\r\n await this.#rest.patch(\r\n Routes.guildScheduledEvent(this.guildId, eventId),\r\n payload,\r\n { reason: optionsReason ?? reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Deletes an event. @param reason Audit-log reason. */\r\n public async remove(eventId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.guildScheduledEvent(this.guildId, eventId),\r\n { reason },\r\n );\r\n this.delete(eventId);\r\n }\r\n\r\n /** Fetches users subscribed to an event (`limit` 1-100). */\r\n public async fetchSubscribers(\r\n eventId: string,\r\n options: {\r\n limit?: number;\r\n withMember?: boolean;\r\n before?: string;\r\n after?: string;\r\n } = {},\r\n ): Promise<{ guild_scheduled_event_id: string; user: UserData }[]> {\r\n const limit =\r\n options.limit === undefined\r\n ? undefined\r\n : Math.min(100, Math.max(1, options.limit));\r\n return this.#rest.get(\r\n withQuery(Routes.guildScheduledEventUsers(this.guildId, eventId), {\r\n limit,\r\n with_member: options.withMember,\r\n before: options.before,\r\n after: options.after,\r\n }),\r\n );\r\n }\r\n}\r\n\r\n/** Options for creating a stage instance. */\r\nexport interface StageInstanceCreateOptions {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n topic: string;\r\n privacyLevel?: number;\r\n sendStartNotification?: boolean;\r\n guildScheduledEventId?: string;\r\n}\r\n\r\n/** Manages stage instances, cached by stage channel ID. Discord.js-familiar. */\r\nexport class StageInstanceManager extends Manager<string, APIStageInstance> {\r\n readonly #rest: REST;\r\n\r\n public constructor(rest: REST) {\r\n super();\r\n this.#rest = rest;\r\n }\r\n\r\n #store(stage: APIStageInstance): APIStageInstance {\r\n this.set(stage.channel_id, stage);\r\n return stage;\r\n }\r\n\r\n /** Starts a stage instance in a stage channel. */\r\n public async create(\r\n channelId: string,\r\n options: StageInstanceCreateOptions,\r\n reason?: string,\r\n ): Promise<APIStageInstance> {\r\n return this.#store(\r\n await this.#rest.post(\r\n Routes.stageInstances(),\r\n {\r\n channel_id: channelId,\r\n topic: options.topic,\r\n privacy_level: options.privacyLevel,\r\n send_start_notification: options.sendStartNotification,\r\n guild_scheduled_event_id: options.guildScheduledEventId,\r\n },\r\n { reason: options.reason ?? reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Fetches the stage instance of a stage channel. */\r\n public async fetch(channelId: string): Promise<APIStageInstance> {\r\n return this.#store(\r\n await this.#rest.get(Routes.stageInstanceByChannel(channelId)),\r\n );\r\n }\r\n\r\n /** Edits a stage instance's topic or privacy level. */\r\n public async edit(\r\n channelId: string,\r\n options: { topic?: string; privacyLevel?: number; reason?: string },\r\n reason?: string,\r\n ): Promise<APIStageInstance> {\r\n return this.#store(\r\n await this.#rest.patch(\r\n Routes.stageInstanceByChannel(channelId),\r\n { topic: options.topic, privacy_level: options.privacyLevel },\r\n { reason: options.reason ?? reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Ends a stage instance. */\r\n public async remove(channelId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(Routes.stageInstanceByChannel(channelId), {\r\n reason,\r\n });\r\n this.delete(channelId);\r\n }\r\n}\r\n\r\n/** Overwrite target type: 0 = role, 1 = member. */\r\nexport type PermissionOverwriteTargetType = 0 | 1;\r\n\r\n/** Permission values accepted by {@link PermissionOverwriteManager.edit}. */\r\nexport interface PermissionOverwriteOptions {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n /** Target type: 0 = role, 1 = member. */\r\n type: PermissionOverwriteTargetType;\r\n /** Allowed permission bits. */\r\n allow?: bigint | number | string;\r\n /** Denied permission bits. */\r\n deny?: bigint | number | string;\r\n}\r\n\r\n/** Bits to change on one overwrite by {@link PermissionOverwriteManager.update}; bits in none of them keep their state. */\r\nexport interface PermissionOverwriteUpdate {\r\n /** Bits to allow. */\r\n allow?: bigint;\r\n /** Bits to deny. */\r\n deny?: bigint;\r\n /** Bits to reset to inherited (neither allowed nor denied). */\r\n inherit?: bigint;\r\n}\r\n\r\n/** Manages a channel's permission overwrites. Discord.js-familiar. */\r\nexport class PermissionOverwriteManager {\r\n readonly #rest: REST;\r\n readonly #current: () => readonly APIOverwrite[] | undefined;\r\n public readonly channelId: string;\r\n\r\n /** @param current The channel's cached overwrites, read by {@link update}; the channel is fetched when they are unknown. */\r\n public constructor(\r\n rest: REST,\r\n channelId: string,\r\n current: () => readonly APIOverwrite[] | undefined = () => undefined,\r\n ) {\r\n this.#rest = rest;\r\n this.channelId = channelId;\r\n this.#current = current;\r\n }\r\n\r\n /**\r\n * Changes some bits of one overwrite and keeps the rest -- unlike\r\n * {@link edit}, which replaces the whole overwrite. Creates the overwrite\r\n * when there is none (then `options.type` is required).\r\n * @throws {TypeError} When the overwrite does not exist and no type is given.\r\n */\r\n public async update(\r\n overwriteId: string,\r\n changes: PermissionOverwriteUpdate,\r\n options: { type?: PermissionOverwriteTargetType; reason?: string } = {},\r\n ): Promise<void> {\r\n const overwrites =\r\n this.#current() ??\r\n (await this.#rest.get<APIChannel>(Routes.channel(this.channelId)))\r\n .permission_overwrites ??\r\n [];\r\n const existing = overwrites.find((entry) => entry.id === overwriteId);\r\n const type = existing?.type ?? options.type;\r\n if (type !== 0 && type !== 1)\r\n throw new TypeError(\r\n \"A new permission overwrite needs a type: 0 for a role, 1 for a member.\",\r\n );\r\n const touched =\r\n (changes.allow ?? 0n) |\r\n (changes.deny ?? 0n) |\r\n (changes.inherit ?? 0n);\r\n const allow =\r\n (BigInt(existing?.allow ?? 0) & ~touched) | (changes.allow ?? 0n);\r\n const deny =\r\n (BigInt(existing?.deny ?? 0) & ~touched) | (changes.deny ?? 0n);\r\n await this.edit(overwriteId, { type, allow, deny }, options.reason);\r\n }\r\n\r\n /** Creates or replaces the overwrite for a role or member. */\r\n public async edit(\r\n overwriteId: string,\r\n options: PermissionOverwriteOptions,\r\n reason?: string,\r\n ): Promise<void> {\r\n await this.#rest.put(\r\n Routes.channelPermission(this.channelId, overwriteId),\r\n {\r\n type: options.type,\r\n allow: BigInt(options.allow ?? 0).toString(),\r\n deny: BigInt(options.deny ?? 0).toString(),\r\n },\r\n { reason: options.reason ?? reason },\r\n );\r\n }\r\n\r\n /** Deletes the overwrite for a role or member. */\r\n public async remove(overwriteId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.channelPermission(this.channelId, overwriteId),\r\n { reason },\r\n );\r\n }\r\n}\r\n",
|
|
35
|
+
"import { Manager, ResourceManager, splitReason } from \"./base.js\";\r\nimport { EmojiManager } from \"./emoji.js\";\r\nimport { GuildSoundboardManager, GuildStickerManager } from \"./advanced.js\";\r\nimport { GuildMemberManager } from \"./member.js\";\r\nimport { RoleManager } from \"./role.js\";\r\nimport {\r\n GuildBanManager,\r\n GuildScheduledEventManager,\r\n} from \"./guild-resources.js\";\r\nimport {\r\n Guild,\r\n AutoModerationRule,\r\n type ResourceContext,\r\n} from \"@lunibee/structures\";\r\nimport { type REST, Routes } from \"@lunibee/rest\";\r\nimport {\r\n type APIChannel,\r\n type APIGuildPreview,\r\n type APIInvite,\r\n type APIWebhook,\r\n type APIAutoModerationRule,\r\n type APIInviteCreate,\r\n type APIVoiceState,\r\n} from \"@lunibee/types\";\r\n\r\ntype GuildData = ConstructorParameters<typeof Guild>[0];\r\n\r\n/** Appends encoded query parameters to a `Routes`-generated path so query building\r\n * stays centralized and URL-encoded rather than hand-concatenated at each call site.\r\n * @param path Base path from a `Routes.*` helper. @param params Query parameters (empty → path unchanged). */\r\nfunction withQuery(path: string, params: URLSearchParams): string {\r\n const suffix = params.toString();\r\n return suffix ? `${path}?${suffix}` : path;\r\n}\r\n\r\nexport interface GuildCreateOptions extends Record<string, unknown> {\r\n name: string;\r\n}\r\nexport interface GuildEditOptions extends Record<string, unknown> {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n}\r\n\r\nexport class GuildManager extends ResourceManager<string, Guild> {\r\n readonly #rest: REST;\r\n readonly #bans = new Map<string, GuildBanManager>();\r\n readonly #scheduledEvents = new Map<string, GuildScheduledEventManager>();\r\n readonly #members = new Map<string, GuildMemberManager>();\r\n readonly #roles = new Map<string, RoleManager>();\r\n readonly #emojis = new Map<string, EmojiManager>();\r\n readonly #stickers = new Map<string, GuildStickerManager>();\r\n readonly #soundboard = new Map<string, GuildSoundboardManager>();\r\n readonly #voiceStates = new Map<string, Manager<string, APIVoiceState>>();\r\n readonly #autoModerationRules = new Map<\r\n string,\r\n Manager<string, APIAutoModerationRule>\r\n >();\r\n readonly #invites = new Map<string, Manager<string, APIInviteCreate>>();\r\n #context?: ResourceContext;\r\n\r\n /** Lets members from this manager act through a client (`member.kick()`...). Called by the client. */\r\n public attachContext(context: ResourceContext): void {\r\n this.#context = context;\r\n }\r\n\r\n /** Returns the per-guild entry of `map`, creating it on first use. */\r\n #perGuild<M>(map: Map<string, M>, guildId: string, create: () => M): M {\r\n let manager = map.get(guildId);\r\n if (!manager) map.set(guildId, (manager = create()));\r\n return manager;\r\n }\r\n public constructor(rest: REST) {\r\n super(\r\n async (id) =>\r\n new Guild(await rest.get<GuildData>(Routes.guild(id))),\r\n (guild) => guild.id,\r\n );\r\n this.#rest = rest;\r\n }\r\n\r\n /** Ban manager for a guild (one instance per guild). */\r\n public bans(guildId: string): GuildBanManager {\r\n let manager = this.#bans.get(guildId);\r\n if (!manager)\r\n this.#bans.set(\r\n guildId,\r\n (manager = new GuildBanManager(this.#rest, guildId)),\r\n );\r\n return manager;\r\n }\r\n\r\n /** Scheduled-event manager for a guild (one instance per guild). */\r\n public scheduledEvents(guildId: string): GuildScheduledEventManager {\r\n let manager = this.#scheduledEvents.get(guildId);\r\n if (!manager)\r\n this.#scheduledEvents.set(\r\n guildId,\r\n (manager = new GuildScheduledEventManager(this.#rest, guildId)),\r\n );\r\n return manager;\r\n }\r\n\r\n /** Member manager for a guild (one instance per guild, kept in sync by the Gateway). */\r\n public members(guildId: string): GuildMemberManager {\r\n let manager = this.#members.get(guildId);\r\n if (!manager)\r\n this.#members.set(\r\n guildId,\r\n (manager = new GuildMemberManager(\r\n guildId,\r\n this.#rest,\r\n () => this.#context,\r\n )),\r\n );\r\n return manager;\r\n }\r\n\r\n /** Role manager for a guild (one instance per guild, kept in sync by the Gateway). */\r\n public roles(guildId: string): RoleManager {\r\n let manager = this.#roles.get(guildId);\r\n if (!manager)\r\n this.#roles.set(\r\n guildId,\r\n (manager = new RoleManager(guildId, this.#rest)),\r\n );\r\n return manager;\r\n }\r\n\r\n /** Emoji manager for a guild (one instance per guild, kept in sync by the Gateway). */\r\n public emojis(guildId: string): EmojiManager {\r\n let manager = this.#emojis.get(guildId);\r\n if (!manager)\r\n this.#emojis.set(\r\n guildId,\r\n (manager = new EmojiManager(this.#rest, guildId)),\r\n );\r\n return manager;\r\n }\r\n\r\n /** Sticker manager for a guild (one instance per guild, kept in sync by the Gateway). */\r\n public stickers(guildId: string): GuildStickerManager {\r\n let manager = this.#stickers.get(guildId);\r\n if (!manager)\r\n this.#stickers.set(\r\n guildId,\r\n (manager = new GuildStickerManager(this.#rest, guildId)),\r\n );\r\n return manager;\r\n }\r\n\r\n /** Soundboard manager for a guild (one instance per guild, kept in sync by the Gateway). */\r\n public soundboard(guildId: string): GuildSoundboardManager {\r\n let manager = this.#soundboard.get(guildId);\r\n if (!manager)\r\n this.#soundboard.set(\r\n guildId,\r\n (manager = new GuildSoundboardManager(this.#rest, guildId)),\r\n );\r\n return manager;\r\n }\r\n\r\n /** Voice states by user ID for a guild, kept in sync by `GUILD_CREATE` and `VOICE_STATE_UPDATE`. */\r\n public voiceStates(guildId: string): Manager<string, APIVoiceState> {\r\n return this.#perGuild(this.#voiceStates, guildId, () => new Manager());\r\n }\r\n\r\n /** Auto-moderation rules by ID for a guild, kept in sync by `AUTO_MODERATION_RULE_*` events. */\r\n public autoModerationRules(\r\n guildId: string,\r\n ): Manager<string, APIAutoModerationRule> {\r\n return this.#perGuild(\r\n this.#autoModerationRules,\r\n guildId,\r\n () => new Manager(),\r\n );\r\n }\r\n\r\n /** Invites by code for a guild, kept in sync by `INVITE_CREATE` / `INVITE_DELETE`. */\r\n public invites(guildId: string): Manager<string, APIInviteCreate> {\r\n return this.#perGuild(this.#invites, guildId, () => new Manager());\r\n }\r\n\r\n /** Merges a guild payload into the cached instance, keeping object identity. */\r\n public patch(data: GuildData): Guild {\r\n const guild = new Guild(data);\r\n const existing = this.get(guild.id);\r\n if (!existing) return this.upsert(guild);\r\n // Partial payloads (e.g. GUILD_UPDATE has no member_count) leave\r\n // optional fields undefined; those must not erase known values.\r\n for (const [key, value] of Object.entries(guild))\r\n if (value !== undefined)\r\n (existing as unknown as Record<string, unknown>)[key] = value;\r\n return existing;\r\n }\r\n\r\n /** Removes a guild and every per-guild manager that belongs to it. */\r\n public override delete(id: string): boolean {\r\n this.#bans.delete(id);\r\n this.#scheduledEvents.delete(id);\r\n this.#members.delete(id);\r\n this.#roles.delete(id);\r\n this.#emojis.delete(id);\r\n this.#stickers.delete(id);\r\n this.#soundboard.delete(id);\r\n this.#voiceStates.delete(id);\r\n this.#autoModerationRules.delete(id);\r\n this.#invites.delete(id);\r\n return super.delete(id);\r\n }\r\n\r\n /** Creates a new guild. (Bot must be in fewer than 10 guilds). */\r\n public async create(options: GuildCreateOptions): Promise<Guild> {\r\n const data = await this.#rest.post<GuildData>(\"/guilds\", options);\r\n return this.upsert(new Guild(data));\r\n }\r\n\r\n /** Modifies a guild's settings. */\r\n public async edit(id: string, options: GuildEditOptions): Promise<Guild> {\r\n const [payload, reason] = splitReason(options);\r\n const data = await this.#rest.patch<GuildData>(\r\n Routes.guild(id),\r\n payload,\r\n { reason },\r\n );\r\n return this.upsert(new Guild(data));\r\n }\r\n\r\n /** Deletes a guild permanently. The bot must own it. */\r\n public async remove(id: string): Promise<void> {\r\n await this.#rest.delete(Routes.guild(id));\r\n }\r\n /** @deprecated Use {@link GuildManager.remove}. Removed in 0.3.0. */\r\n public deleteGuild(id: string): Promise<void> {\r\n return this.remove(id);\r\n }\r\n\r\n /** Fetches a guild's preview (even if the bot is not in the guild). */\r\n public async fetchPreview(id: string): Promise<APIGuildPreview> {\r\n return this.#rest.get<APIGuildPreview>(Routes.guildPreview(id));\r\n }\r\n\r\n /** Fetches all active threads in the guild. */\r\n public async fetchActiveThreads(\r\n id: string,\r\n ): Promise<{ threads: APIChannel[]; members: unknown[] }> {\r\n return this.#rest.get<{ threads: APIChannel[]; members: unknown[] }>(\r\n Routes.guildActiveThreads(id),\r\n );\r\n }\r\n\r\n /** Fetches all webhooks in the guild. */\r\n public async fetchWebhooks(id: string): Promise<APIWebhook[]> {\r\n return this.#rest.get<APIWebhook[]>(Routes.guildWebhooks(id));\r\n }\r\n\r\n /** Fetches all invites in the guild. */\r\n public async fetchInvites(id: string): Promise<APIInvite[]> {\r\n return this.#rest.get<APIInvite[]>(Routes.guildInvites(id));\r\n }\r\n\r\n /**\r\n * Fetches audit log entries for a guild.\r\n * @param guildId Guild identifier.\r\n * @param options Filter options: userId (filter by actor), actionType (AuditLogEvent number), before (entry ID cursor), limit (1–100, default 50).\r\n * @returns Typed audit log response with `audit_log_entries` and related resources.\r\n */\r\n public async fetchAuditLog(\r\n guildId: string,\r\n options: {\r\n userId?: string;\r\n actionType?: number;\r\n before?: string;\r\n after?: string;\r\n limit?: number;\r\n } = {},\r\n ): Promise<AuditLogResponse> {\r\n const params = new URLSearchParams();\r\n if (options.userId) params.set(\"user_id\", options.userId);\r\n if (options.actionType !== undefined)\r\n params.set(\"action_type\", String(options.actionType));\r\n if (options.before) params.set(\"before\", options.before);\r\n if (options.after) params.set(\"after\", options.after);\r\n if (options.limit !== undefined)\r\n params.set(\r\n \"limit\",\r\n String(Math.min(100, Math.max(1, options.limit))),\r\n );\r\n return this.#rest.get<AuditLogResponse>(\r\n withQuery(Routes.guildAuditLog(guildId), params),\r\n );\r\n }\r\n\r\n /**\r\n * Fetches members from a guild (paginated).\r\n * @param guildId Guild identifier.\r\n * @param options Fetch options: limit (1–1000, default 100), after (member ID cursor).\r\n * @returns Array of raw member data payloads.\r\n */\r\n public async fetchMembers(\r\n guildId: string,\r\n options: { limit?: number; after?: string } = {},\r\n ): Promise<Record<string, unknown>[]> {\r\n const params = new URLSearchParams();\r\n if (options.limit !== undefined)\r\n params.set(\r\n \"limit\",\r\n String(Math.min(1000, Math.max(1, options.limit))),\r\n );\r\n if (options.after) params.set(\"after\", options.after);\r\n return this.#rest.get<Record<string, unknown>[]>(\r\n withQuery(Routes.guildMembers(guildId), params),\r\n );\r\n }\r\n\r\n /** Fetches a list of all auto moderation rules currently configured for guild. */\r\n public async fetchAutoModerationRules(\r\n guildId: string,\r\n ): Promise<AutoModerationRule[]> {\r\n const rules = await this.#rest.get<APIAutoModerationRule[]>(\r\n Routes.guildAutoModerationRules(guildId),\r\n );\r\n return rules.map((r) => new AutoModerationRule(r));\r\n }\r\n\r\n /** Fetches a single auto moderation rule. */\r\n public async fetchAutoModerationRule(\r\n guildId: string,\r\n ruleId: string,\r\n ): Promise<AutoModerationRule> {\r\n const rule = await this.#rest.get<APIAutoModerationRule>(\r\n Routes.guildAutoModerationRule(guildId, ruleId),\r\n );\r\n return new AutoModerationRule(rule);\r\n }\r\n\r\n /** Creates a new auto moderation rule. */\r\n public async createAutoModerationRule(\r\n guildId: string,\r\n options: Record<string, unknown> & { reason?: string },\r\n ): Promise<AutoModerationRule> {\r\n const [payload, reason] = splitReason(options);\r\n const rule = await this.#rest.post<APIAutoModerationRule>(\r\n Routes.guildAutoModerationRules(guildId),\r\n payload,\r\n { reason },\r\n );\r\n return new AutoModerationRule(rule);\r\n }\r\n\r\n /** Modifies an existing auto moderation rule. */\r\n public async editAutoModerationRule(\r\n guildId: string,\r\n ruleId: string,\r\n options: Record<string, unknown> & { reason?: string },\r\n ): Promise<AutoModerationRule> {\r\n const [payload, reason] = splitReason(options);\r\n const rule = await this.#rest.patch<APIAutoModerationRule>(\r\n Routes.guildAutoModerationRule(guildId, ruleId),\r\n payload,\r\n { reason },\r\n );\r\n return new AutoModerationRule(rule);\r\n }\r\n\r\n /** Deletes an auto moderation rule. @param reason Audit-log reason. */\r\n public async deleteAutoModerationRule(\r\n guildId: string,\r\n ruleId: string,\r\n reason?: string,\r\n ): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.guildAutoModerationRule(guildId, ruleId),\r\n { reason },\r\n );\r\n }\r\n}\r\n\r\n// ─── Audit Log Types ──────────────────────────────────────────────────────────\r\n\r\n/** A single audit log entry as returned by the Discord API. */\r\nexport interface AuditLogEntry {\r\n id: string;\r\n action_type: number;\r\n user_id: string | null;\r\n target_id: string | null;\r\n reason?: string;\r\n changes?: Array<{ key: string; old_value?: unknown; new_value?: unknown }>;\r\n options?: Record<string, unknown>;\r\n}\r\n\r\n/** Discord API audit log response payload. */\r\nexport interface AuditLogResponse {\r\n audit_log_entries: AuditLogEntry[];\r\n users: Record<string, unknown>[];\r\n integrations: Record<string, unknown>[];\r\n webhooks: Record<string, unknown>[];\r\n guild_scheduled_events: Record<string, unknown>[];\r\n threads: Record<string, unknown>[];\r\n application_commands: Record<string, unknown>[];\r\n}\r\n\r\n/** Known Discord audit log event type numbers. */\r\nexport const AuditLogEvent = {\r\n GuildUpdate: 1,\r\n ChannelCreate: 10,\r\n ChannelUpdate: 11,\r\n ChannelDelete: 12,\r\n ChannelOverwriteCreate: 13,\r\n ChannelOverwriteUpdate: 14,\r\n ChannelOverwriteDelete: 15,\r\n MemberKick: 20,\r\n MemberPrune: 21,\r\n MemberBanAdd: 22,\r\n MemberBanRemove: 23,\r\n MemberUpdate: 24,\r\n MemberRoleUpdate: 25,\r\n MemberMove: 26,\r\n MemberDisconnect: 27,\r\n BotAdd: 28,\r\n RoleCreate: 30,\r\n RoleUpdate: 31,\r\n RoleDelete: 32,\r\n InviteCreate: 40,\r\n InviteUpdate: 41,\r\n InviteDelete: 42,\r\n WebhookCreate: 50,\r\n WebhookUpdate: 51,\r\n WebhookDelete: 52,\r\n EmojiCreate: 60,\r\n EmojiUpdate: 61,\r\n EmojiDelete: 62,\r\n MessageDelete: 72,\r\n MessageBulkDelete: 73,\r\n MessagePin: 74,\r\n MessageUnpin: 75,\r\n IntegrationCreate: 80,\r\n IntegrationUpdate: 81,\r\n IntegrationDelete: 82,\r\n StageInstanceCreate: 83,\r\n StageInstanceUpdate: 84,\r\n StageInstanceDelete: 85,\r\n StickerCreate: 90,\r\n StickerUpdate: 91,\r\n StickerDelete: 92,\r\n ScheduledEventCreate: 100,\r\n ScheduledEventUpdate: 101,\r\n ScheduledEventDelete: 102,\r\n ThreadCreate: 110,\r\n ThreadUpdate: 111,\r\n ThreadDelete: 112,\r\n AutoModerationRuleCreate: 140,\r\n AutoModerationRuleUpdate: 141,\r\n AutoModerationRuleDelete: 142,\r\n AutoModerationBlockMessage: 143,\r\n} as const;\r\n",
|
|
36
|
+
"import { REST, Routes } from \"@lunibee/rest\";\r\nimport type {\r\n APIApplicationCommand,\r\n ApplicationCommandData,\r\n} from \"@lunibee/types\";\r\n\r\n/** Manages global and guild-scoped application commands for a Discord application. */\r\nexport class ApplicationCommandManager {\r\n readonly #rest: REST;\r\n readonly #applicationId: string;\r\n\r\n /** Creates an application command manager. @param rest REST transport. @param applicationId Application identifier. */\r\n public constructor(rest: REST, applicationId: string) {\r\n this.#rest = rest;\r\n this.#applicationId = applicationId;\r\n }\r\n\r\n // ──────────────────── Global commands ────────────────────\r\n\r\n /** Fetches all global application commands. @returns Array of registered commands. */\r\n public fetch(): Promise<APIApplicationCommand[]> {\r\n return this.#rest.get<APIApplicationCommand[]>(\r\n Routes.applicationCommands(this.#applicationId),\r\n );\r\n }\r\n\r\n /** Creates a single global application command. @param data Command data. @returns Created command. */\r\n public create(\r\n data: ApplicationCommandData,\r\n ): Promise<APIApplicationCommand> {\r\n return this.#rest.post<APIApplicationCommand>(\r\n Routes.applicationCommands(this.#applicationId),\r\n data,\r\n );\r\n }\r\n\r\n /** Overwrites all global application commands atomically. @param commands Array of command data. @returns New full command list. */\r\n public set(\r\n commands: ApplicationCommandData[],\r\n ): Promise<APIApplicationCommand[]> {\r\n return this.#rest.put<APIApplicationCommand[]>(\r\n Routes.applicationCommands(this.#applicationId),\r\n commands,\r\n );\r\n }\r\n\r\n /** Edits a global application command. @param commandId Command identifier. @param data Partial command data. @returns Updated command. */\r\n public edit(\r\n commandId: string,\r\n data: Partial<ApplicationCommandData>,\r\n ): Promise<APIApplicationCommand> {\r\n return this.#rest.patch<APIApplicationCommand>(\r\n Routes.applicationCommand(this.#applicationId, commandId),\r\n data,\r\n );\r\n }\r\n\r\n /** Deletes a global application command. @param commandId Command identifier. @returns Nothing. */\r\n public async delete(commandId: string): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.applicationCommand(this.#applicationId, commandId),\r\n );\r\n }\r\n\r\n // ──────────────────── Guild-scoped commands ────────────────────\r\n\r\n /** Fetches all guild-scoped application commands. @param guildId Guild identifier. @returns Array of registered guild commands. */\r\n public fetchGuild(guildId: string): Promise<APIApplicationCommand[]> {\r\n return this.#rest.get<APIApplicationCommand[]>(\r\n Routes.guildApplicationCommands(this.#applicationId, guildId),\r\n );\r\n }\r\n\r\n /** Creates a single guild-scoped application command. @param guildId Guild identifier. @param data Command data. @returns Created command. */\r\n public createGuild(\r\n guildId: string,\r\n data: ApplicationCommandData,\r\n ): Promise<APIApplicationCommand> {\r\n return this.#rest.post<APIApplicationCommand>(\r\n Routes.guildApplicationCommands(this.#applicationId, guildId),\r\n data,\r\n );\r\n }\r\n\r\n /** Overwrites all guild-scoped application commands atomically. @param guildId Guild identifier. @param commands Array of command data. @returns New full command list. */\r\n public setGuild(\r\n guildId: string,\r\n commands: ApplicationCommandData[],\r\n ): Promise<APIApplicationCommand[]> {\r\n return this.#rest.put<APIApplicationCommand[]>(\r\n Routes.guildApplicationCommands(this.#applicationId, guildId),\r\n commands,\r\n );\r\n }\r\n\r\n /** Edits a guild-scoped application command. @param guildId Guild identifier. @param commandId Command identifier. @param data Partial command data. @returns Updated command. */\r\n public editGuild(\r\n guildId: string,\r\n commandId: string,\r\n data: Partial<ApplicationCommandData>,\r\n ): Promise<APIApplicationCommand> {\r\n return this.#rest.patch<APIApplicationCommand>(\r\n Routes.guildApplicationCommand(\r\n this.#applicationId,\r\n guildId,\r\n commandId,\r\n ),\r\n data,\r\n );\r\n }\r\n\r\n /** Deletes a guild-scoped application command. @param guildId Guild identifier. @param commandId Command identifier. @returns Nothing. */\r\n public async deleteGuild(\r\n guildId: string,\r\n commandId: string,\r\n ): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.guildApplicationCommand(\r\n this.#applicationId,\r\n guildId,\r\n commandId,\r\n ),\r\n );\r\n }\r\n}\r\n",
|
|
37
|
+
"import { Manager, ResourceManager, splitReason } from \"./base.js\";\r\nexport { Manager, ResourceManager } from \"./base.js\";\r\n/** Discord.js-familiar alias for {@link ResourceManager}. */\r\nexport { ResourceManager as CachedManager } from \"./base.js\";\r\nimport { REST, Routes } from \"@lunibee/rest\";\r\nimport type { AllowedMentions } from \"@lunibee/types\";\r\nimport {\r\n Channel,\r\n createChannel,\r\n Message,\r\n User,\r\n type ResourceContext,\r\n} from \"@lunibee/structures\";\r\nimport {\r\n MessageManager,\r\n toRequest,\r\n type MessageCacheOptions,\r\n type MessageCreateOptions as ManagerMessageCreateOptions,\r\n} from \"./message.js\";\r\nimport { ThreadManager } from \"./thread.js\";\r\n\r\nexport { UserManager } from \"./user.js\";\r\nexport { GuildManager } from \"./guild.js\";\r\nexport type { AuditLogEntry, AuditLogResponse } from \"./guild.js\";\r\nexport { AuditLogEvent } from \"./guild.js\";\r\n\r\nexport type MessageCreateOptions = ManagerMessageCreateOptions;\r\nexport type MessageEditOptions = Record<string, unknown> & { content?: string };\r\n/** Discord only bulk-deletes messages younger than two weeks. */\r\nconst BULK_DELETE_MAX_AGE_MS = 14 * 24 * 60 * 60_000;\r\n/** Creation time (ms) encoded in a snowflake. */\r\nfunction snowflakeTime(id: string): number {\r\n return Number((BigInt(id) >> 22n) + 1_420_070_400_000n);\r\n}\r\nexport interface MessageFetchOptions {\r\n cache?: boolean;\r\n}\r\nexport interface MessageQueryOptions {\r\n before?: string;\r\n after?: string;\r\n around?: string;\r\n limit?: number;\r\n}\r\nexport interface MessageThreadOptions {\r\n name: string;\r\n autoArchiveDuration?: 60 | 1440 | 4320 | 10080;\r\n rateLimitPerUser?: number;\r\n}\r\nexport interface ReactionFetchOptions {\r\n limit?: number;\r\n after?: string;\r\n}\r\n\r\nexport interface ChannelCreateOptions extends Record<string, unknown> {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n name: string;\r\n type: number;\r\n guild_id?: string;\r\n parent_id?: string | null;\r\n}\r\nexport type ChannelEditOptions = Record<string, unknown> & {\r\n /** Audit-log reason. */\r\n reason?: string;\r\n};\r\n\r\nimport { PermissionOverwriteManager } from \"./guild-resources.js\";\r\n\r\nexport class ChannelManager extends Manager<string, Channel> {\r\n readonly #rest: REST;\r\n readonly #context: ResourceContext;\r\n readonly #messageManagers = new Map<string, MessageManager>();\r\n readonly #messageCache?: MessageCacheOptions;\r\n readonly #allowedMentions?: AllowedMentions;\r\n /**\r\n * @param options.messageCache Enables a bounded per-channel message cache; messages are not cached by default.\r\n * @param options.allowedMentions Default `allowed_mentions` for sends and edits without their own.\r\n */\r\n public constructor(\r\n rest: REST,\r\n options: {\r\n messageCache?: MessageCacheOptions;\r\n allowedMentions?: AllowedMentions;\r\n } = {},\r\n ) {\r\n super();\r\n this.#rest = rest;\r\n this.#messageCache = options.messageCache;\r\n this.#allowedMentions = options.allowedMentions;\r\n this.#context = {\r\n sendMessage: (channelId, options) => this.send(channelId, options),\r\n editMessage: (channelId, messageId, options) =>\r\n this.editMessage(channelId, messageId, options),\r\n deleteMessage: (channelId, messageId, reason) =>\r\n this.deleteMessage(channelId, messageId, reason),\r\n crosspostMessage: (channelId, messageId) =>\r\n this.crosspostMessage(channelId, messageId),\r\n editChannel: (channelId, options) => this.edit(channelId, options),\r\n deleteChannel: (channelId, reason) =>\r\n this.remove(channelId, reason),\r\n addReaction: (channelId, messageId, emoji) =>\r\n this.addReaction(channelId, messageId, emoji),\r\n removeOwnReaction: (channelId, messageId, emoji) =>\r\n this.removeOwnReaction(channelId, messageId, emoji),\r\n removeReaction: (channelId, messageId, emoji, userId) =>\r\n this.removeReaction(channelId, messageId, emoji, userId),\r\n removeAllReactions: (channelId, messageId) =>\r\n this.removeAllReactions(channelId, messageId),\r\n pinMessage: (channelId, messageId, reason) =>\r\n this.pinMessage(channelId, messageId, reason),\r\n unpinMessage: (channelId, messageId, reason) =>\r\n this.unpinMessage(channelId, messageId, reason),\r\n };\r\n }\r\n public messages(channelId: string): MessageManager {\r\n let manager = this.#messageManagers.get(channelId);\r\n if (!manager) {\r\n manager = new MessageManager(\r\n this.#rest,\r\n this.#context,\r\n channelId,\r\n this.#messageCache,\r\n this.#allowedMentions,\r\n );\r\n this.#messageManagers.set(channelId, manager);\r\n }\r\n return manager;\r\n }\r\n /** Permission overwrite manager for a channel. */\r\n public permissionOverwrites(channelId: string): PermissionOverwriteManager {\r\n return new PermissionOverwriteManager(\r\n this.#rest,\r\n channelId,\r\n () => this.get(channelId)?.permissionOverwrites,\r\n );\r\n }\r\n public threads(channelId: string): ThreadManager {\r\n return new ThreadManager(this.#rest, this.#context, channelId);\r\n }\r\n /** Fetches a channel; concurrent fetches share a request and a stale result never overwrites newer state. */\r\n public fetch(channelId: string): Promise<Channel> {\r\n return this.fetchOnce(\r\n channelId,\r\n async () =>\r\n createChannel(\r\n await this.#rest.get<\r\n ConstructorParameters<typeof Channel>[0]\r\n >(Routes.channel(channelId)),\r\n this.#context,\r\n ),\r\n (channel) => this.#merge(channel),\r\n );\r\n }\r\n public async resolve(channelId: string): Promise<Channel> {\r\n return this.get(channelId) ?? this.fetch(channelId);\r\n }\r\n public upsert(data: ConstructorParameters<typeof Channel>[0]): Channel {\r\n return this.#merge(createChannel(data, this.#context));\r\n }\r\n /** Merges into the cached instance; a type change (e.g. text -> announcement) needs the new subclass. */\r\n #merge(channel: Channel): Channel {\r\n const existing = this.get(channel.id);\r\n if (existing && existing.type === channel.type) {\r\n Object.assign(existing, channel);\r\n return existing;\r\n }\r\n this.set(channel.id, channel);\r\n return channel;\r\n }\r\n public update(channel: Channel): this {\r\n return this.set(channel.id, channel);\r\n }\r\n /** Removes every cached channel that belongs to a guild. @returns Number removed. */\r\n public deleteGuildChannels(guildId: string): number {\r\n let removed = 0;\r\n for (const channel of this.values())\r\n if (channel.guildId === guildId && this.delete(channel.id))\r\n removed++;\r\n return removed;\r\n }\r\n /** Ends a poll now; returns the updated message. */\r\n public async endPoll(\r\n channelId: string,\r\n messageId: string,\r\n ): Promise<Message> {\r\n return this.messages(channelId).upsert(\r\n await this.#rest.post<ConstructorParameters<typeof Message>[0]>(\r\n Routes.pollExpire(channelId, messageId),\r\n ),\r\n );\r\n }\r\n /** Fetches users who voted for one poll answer. @param options.limit 1-100 (default 25). */\r\n public async fetchPollVoters(\r\n channelId: string,\r\n messageId: string,\r\n answerId: number,\r\n options: { after?: string; limit?: number } = {},\r\n ): Promise<User[]> {\r\n if (\r\n options.limit !== undefined &&\r\n (!Number.isInteger(options.limit) ||\r\n options.limit < 1 ||\r\n options.limit > 100)\r\n )\r\n throw new RangeError(\"Poll voter limit must be 1-100.\");\r\n const params = new URLSearchParams();\r\n if (options.after) params.set(\"after\", options.after);\r\n if (options.limit !== undefined)\r\n params.set(\"limit\", String(options.limit));\r\n const suffix = params.toString();\r\n const { users } = await this.#rest.get<{\r\n users: ConstructorParameters<typeof User>[0][];\r\n }>(\r\n `${Routes.pollAnswerVoters(channelId, messageId, answerId)}${suffix ? `?${suffix}` : \"\"}`,\r\n );\r\n return users.map((user) => new User(user));\r\n }\r\n /** Plays a soundboard sound in a voice channel the bot is connected to. */\r\n public async sendSoundboardSound(\r\n channelId: string,\r\n options: { soundId: string; sourceGuildId?: string },\r\n ): Promise<void> {\r\n await this.#rest.post(Routes.sendSoundboardSound(channelId), {\r\n sound_id: options.soundId,\r\n source_guild_id: options.sourceGuildId,\r\n });\r\n }\r\n /** Returns the message manager for a channel only if one already exists. */\r\n public cachedMessages(channelId: string): MessageManager | undefined {\r\n return this.#messageManagers.get(channelId);\r\n }\r\n public async create(\r\n guildId: string,\r\n options: ChannelCreateOptions,\r\n ): Promise<Channel> {\r\n const [payload, reason] = splitReason(options);\r\n return this.upsert(\r\n await this.#rest.post<ConstructorParameters<typeof Channel>[0]>(\r\n Routes.guildChannels(guildId),\r\n payload,\r\n { reason },\r\n ),\r\n );\r\n }\r\n public async edit(\r\n channelId: string,\r\n options: ChannelEditOptions,\r\n ): Promise<Channel> {\r\n const [payload, reason] = splitReason(options);\r\n return this.upsert(\r\n await this.#rest.patch<ConstructorParameters<typeof Channel>[0]>(\r\n Routes.channel(channelId),\r\n payload,\r\n { reason },\r\n ),\r\n );\r\n }\r\n\r\n /** Deletes a channel (or closes a DM). @param reason Audit-log reason. */\r\n public async remove(channelId: string, reason?: string): Promise<void> {\r\n await this.#rest.delete(Routes.channel(channelId), { reason });\r\n this.delete(channelId);\r\n }\r\n /** @deprecated Use {@link ChannelManager.remove}, which also takes an audit-log reason. Removed in 0.3.0. */\r\n public deleteChannel(channelId: string): Promise<void> {\r\n return this.remove(channelId);\r\n }\r\n /** Evicts a channel, dropping its per-channel message manager with it.\r\n * Overrides {@link Manager.delete} so cache eviction driven by a Gateway\r\n * `CHANNEL_DELETE`/`THREAD_DELETE` — which calls `delete` rather than\r\n * {@link remove} — releases the message manager and its cached\r\n * messages too, instead of retaining them for the client's lifetime. */\r\n public override delete(channelId: string): boolean {\r\n this.#messageManagers.delete(channelId);\r\n return super.delete(channelId);\r\n }\r\n public send(\r\n channelId: string,\r\n options: MessageCreateOptions,\r\n ): Promise<Message> {\r\n return this.messages(channelId).send(options);\r\n }\r\n /** @deprecated Use {@link ChannelManager.send}. Removed in 0.3.0. */\r\n public sendMessage(\r\n channelId: string,\r\n options: MessageCreateOptions,\r\n ): Promise<Message> {\r\n return this.send(channelId, options);\r\n }\r\n public async fetchMessage(\r\n channelId: string,\r\n messageId: string,\r\n options: MessageFetchOptions = {},\r\n ): Promise<Message> {\r\n void options;\r\n return this.messages(channelId).fetch(messageId);\r\n }\r\n public fetchMessages(\r\n channelId: string,\r\n query: MessageQueryOptions | Iterable<string>,\r\n ): Promise<Message[]> {\r\n if (isMessageQuery(query)) {\r\n const params = new URLSearchParams();\r\n if (query.before) params.set(\"before\", query.before);\r\n if (query.after) params.set(\"after\", query.after);\r\n if (query.around) params.set(\"around\", query.around);\r\n if (query.limit !== undefined)\r\n params.set(\"limit\", String(query.limit));\r\n const suffix = params.toString();\r\n return this.#rest\r\n .get<ConstructorParameters<typeof Message>[0][]>(\r\n `${Routes.channelMessages(channelId)}${suffix ? `?${suffix}` : \"\"}`,\r\n )\r\n .then((data) =>\r\n data.map((item) => this.messages(channelId).upsert(item)),\r\n );\r\n }\r\n return this.messages(channelId).fetchMany(query);\r\n }\r\n public upsertMessage(\r\n data: ConstructorParameters<typeof Message>[0],\r\n ): Message {\r\n return this.messages(data.channel_id).upsert(data);\r\n }\r\n public async editMessage(\r\n channelId: string,\r\n messageId: string,\r\n options: MessageEditOptions,\r\n ): Promise<Message> {\r\n return this.messages(channelId).upsert(\r\n await this.#rest.patch<ConstructorParameters<typeof Message>[0]>(\r\n Routes.message(channelId, messageId),\r\n toRequest(options, this.#allowedMentions),\r\n ),\r\n );\r\n }\r\n /** Deletes a message. @param reason Audit-log reason (shown when deleting someone else's message). */\r\n public async deleteMessage(\r\n channelId: string,\r\n messageId: string,\r\n reason?: string,\r\n ): Promise<void> {\r\n await this.#rest.delete(Routes.message(channelId, messageId), {\r\n reason,\r\n });\r\n this.messages(channelId).delete(messageId);\r\n }\r\n public deleteCachedMessage(channelId: string, messageId: string): boolean {\r\n return this.messages(channelId).delete(messageId);\r\n }\r\n public async crosspostMessage(\r\n channelId: string,\r\n messageId: string,\r\n ): Promise<Message> {\r\n return this.messages(channelId).upsert(\r\n await this.#rest.post<ConstructorParameters<typeof Message>[0]>(\r\n Routes.crosspostMessage(channelId, messageId),\r\n ),\r\n );\r\n }\r\n /** Bulk-deletes messages in a channel. Duplicate IDs are ignored and a\r\n * single ID falls back to a normal delete.\r\n * @throws {RangeError} If no IDs or more than 100 are provided, or any\r\n * message is older than 14 days (Discord refuses to bulk-delete those). */\r\n public async bulkDeleteMessages(\r\n channelId: string,\r\n messageIds: Iterable<string>,\r\n reason?: string,\r\n ): Promise<void> {\r\n const ids = [...new Set(messageIds)];\r\n if (ids.length < 1 || ids.length > 100)\r\n throw new RangeError(\r\n \"bulkDelete requires between 1 and 100 message IDs.\",\r\n );\r\n if (ids.length === 1)\r\n return this.deleteMessage(channelId, ids[0]!, reason);\r\n const cutoff = Date.now() - BULK_DELETE_MAX_AGE_MS;\r\n const tooOld = ids.filter((id) => snowflakeTime(id) < cutoff);\r\n if (tooOld.length)\r\n throw new RangeError(\r\n `bulkDelete cannot delete messages older than 14 days: ${tooOld.join(\", \")}`,\r\n );\r\n await this.#rest.post(\r\n Routes.channelBulkDelete(channelId),\r\n { messages: ids },\r\n { reason },\r\n );\r\n for (const id of ids) this.messages(channelId).delete(id);\r\n }\r\n /**\r\n * Iterates a channel's history newest-first, 100 messages per request,\r\n * starting before `before` (or the latest message) and stopping after\r\n * `limit` messages or at the start of the channel.\r\n */\r\n public async *iterateMessages(\r\n channelId: string,\r\n options: { before?: string; limit?: number } = {},\r\n ): AsyncGenerator<Message, void, undefined> {\r\n let before = options.before;\r\n let remaining = options.limit ?? Infinity;\r\n while (remaining > 0) {\r\n const page = await this.fetchMessages(channelId, {\r\n before,\r\n limit: Math.min(100, remaining),\r\n });\r\n for (const message of page) yield message;\r\n remaining -= page.length;\r\n if (page.length < 100) return;\r\n before = page.at(-1)!.id;\r\n }\r\n }\r\n public async addReaction(\r\n channelId: string,\r\n messageId: string,\r\n emoji: string,\r\n ): Promise<void> {\r\n // Discord's create-reaction endpoint is\r\n // PUT .../reactions/{emoji}/@me — the bare .../reactions/{emoji} path\r\n // is not a valid target for PUT.\r\n await this.#rest.put(\r\n `${Routes.messageReactions(channelId, messageId, emoji)}/@me`,\r\n );\r\n }\r\n public async fetchReactions(\r\n channelId: string,\r\n messageId: string,\r\n emoji: string,\r\n options: ReactionFetchOptions = {},\r\n ): Promise<User[]> {\r\n const params = new URLSearchParams();\r\n if (options.limit !== undefined)\r\n params.set(\"limit\", String(options.limit));\r\n if (options.after) params.set(\"after\", options.after);\r\n const suffix = params.toString();\r\n const data = await this.#rest.get<\r\n ConstructorParameters<typeof User>[0][]\r\n >(\r\n `${Routes.messageReactions(channelId, messageId, emoji)}${suffix ? `?${suffix}` : \"\"}`,\r\n );\r\n return data.map((user) => new User(user));\r\n }\r\n public async removeOwnReaction(\r\n channelId: string,\r\n messageId: string,\r\n emoji: string,\r\n ): Promise<void> {\r\n await this.#rest.delete(\r\n `${Routes.messageReactions(channelId, messageId, emoji)}/@me`,\r\n );\r\n }\r\n public async removeReaction(\r\n channelId: string,\r\n messageId: string,\r\n emoji: string,\r\n userId: string,\r\n ): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.messageReactionUser(channelId, messageId, emoji, userId),\r\n );\r\n }\r\n public async removeAllReactions(\r\n channelId: string,\r\n messageId: string,\r\n ): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.messageReactionsAll(channelId, messageId),\r\n );\r\n }\r\n /** Fetches the newest pinned messages (one page, up to 50, like the endpoint it replaces). */\r\n public async fetchPinnedMessages(channelId: string): Promise<Message[]> {\r\n const data = await this.#rest.get<{\r\n items: { message: ConstructorParameters<typeof Message>[0] }[];\r\n }>(Routes.channelMessagesPins(channelId));\r\n return data.items.map((item) =>\r\n this.messages(channelId).upsert(item.message),\r\n );\r\n }\r\n /** Pins a message. @param reason Audit-log reason. */\r\n public async pinMessage(\r\n channelId: string,\r\n messageId: string,\r\n reason?: string,\r\n ): Promise<void> {\r\n await this.#rest.put(\r\n Routes.channelMessagesPin(channelId, messageId),\r\n undefined,\r\n { reason },\r\n );\r\n }\r\n /** Unpins a message. @param reason Audit-log reason. */\r\n public async unpinMessage(\r\n channelId: string,\r\n messageId: string,\r\n reason?: string,\r\n ): Promise<void> {\r\n await this.#rest.delete(\r\n Routes.channelMessagesPin(channelId, messageId),\r\n { reason },\r\n );\r\n }\r\n /** Creates a webhook in a channel. @param options Name, optional avatar data URI, and audit-log `reason`. */\r\n public async createWebhook(\r\n channelId: string,\r\n options: { name: string; avatar?: string | null; reason?: string },\r\n ): Promise<import(\"@lunibee/types\").APIWebhook> {\r\n const [payload, reason] = splitReason(options);\r\n return this.#rest.post(Routes.channelWebhooks(channelId), payload, {\r\n reason,\r\n });\r\n }\r\n public createThreadFromMessage(\r\n channelId: string,\r\n messageId: string,\r\n options: MessageThreadOptions,\r\n ): Promise<Channel> {\r\n return this.threads(channelId).createFromMessage(messageId, options);\r\n }\r\n /**\r\n * Fetches a page of messages with cursor metadata.\r\n * @param channelId Channel to fetch from.\r\n * @param options Page options — `before`, `after`, `around`, and `limit` (max 100).\r\n * @returns `{ messages, before, after, hasMore }` — use `before` or `after` as cursors for the next page.\r\n */\r\n public async fetchPage(\r\n channelId: string,\r\n options: MessageQueryOptions = {},\r\n ): Promise<{\r\n messages: Message[];\r\n before?: string;\r\n after?: string;\r\n hasMore: boolean;\r\n }> {\r\n const limit = Math.min(100, Math.max(1, options.limit ?? 50));\r\n const messages = await this.fetchMessages(channelId, {\r\n ...options,\r\n limit,\r\n });\r\n return {\r\n messages,\r\n before: messages[0]?.id,\r\n after: messages[messages.length - 1]?.id,\r\n hasMore: messages.length === limit,\r\n };\r\n }\r\n /** @deprecated Use {@link ChannelManager.bulkDeleteMessages}, which also takes an audit-log reason. Removed in 0.3.0. */\r\n public bulkDelete(channelId: string, messageIds: string[]): Promise<void> {\r\n return this.bulkDeleteMessages(channelId, messageIds);\r\n }\r\n public override clear(): void {\r\n this.#messageManagers.clear();\r\n super.clear();\r\n }\r\n}\r\n\r\nfunction isMessageQuery(\r\n value: MessageQueryOptions | Iterable<string>,\r\n): value is MessageQueryOptions {\r\n return (\r\n typeof value === \"object\" &&\r\n value !== null &&\r\n !(Symbol.iterator in value)\r\n );\r\n}\r\nexport type CreateMessageOptions = MessageCreateOptions;\r\nexport {\r\n MessageManager,\r\n toRequest,\r\n type MessageCacheOptions,\r\n type MessageFile,\r\n} from \"./message.js\";\r\nexport { ThreadManager } from \"./thread.js\";\r\nexport {\r\n RoleManager,\r\n type RoleCreateOptions,\r\n type RoleEditOptions,\r\n} from \"./role.js\";\r\nexport {\r\n GuildMemberManager,\r\n type MemberEditOptions,\r\n type BanOptions,\r\n} from \"./member.js\";\r\nexport { ApplicationCommandManager } from \"./application.js\";\r\nexport {\r\n GuildBanManager,\r\n GuildScheduledEventManager,\r\n StageInstanceManager,\r\n PermissionOverwriteManager,\r\n type APIBan,\r\n type GuildBanCreateOptions,\r\n type GuildScheduledEventOptions,\r\n type StageInstanceCreateOptions,\r\n type PermissionOverwriteOptions,\r\n type PermissionOverwriteTargetType,\r\n type PermissionOverwriteUpdate,\r\n} from \"./guild-resources.js\";\r\nexport {\r\n EmojiManager,\r\n type EmojiCreateOptions,\r\n type EmojiEditOptions,\r\n} from \"./emoji.js\";\r\nexport {\r\n GuildStickerManager,\r\n GuildSoundboardManager,\r\n MonetizationManager,\r\n type APIEntitlement,\r\n type APISKU,\r\n type APISoundboardSound,\r\n type APISubscription,\r\n type EntitlementQuery,\r\n type GuildStickerCreateOptions,\r\n type SoundboardSoundCreateOptions,\r\n} from \"./advanced.js\";\r\n",
|
|
38
|
+
"/**\r\n * Identity of a Discord Gateway session, and the decision of how to open the\r\n * next connection with it.\r\n *\r\n * Deliberately owns nothing else: no socket, no timers, no opcode dispatch, no\r\n * compression, no event emission. Those belong to the transport, heartbeat,\r\n * reconnect and protocol seams. Keeping this object small is the point —\r\n * session confusion is what produced both WS-001 and WS-005.\r\n */\r\n\r\n/** Everything needed to send a RESUME, or nothing when one is impossible. */\r\nexport interface ResumeInfo {\r\n /** Discord's session identifier from READY. */\r\n sessionId: string;\r\n /** Last sequence number observed on this session. */\r\n sequence: number;\r\n /** Host READY nominated for resuming this session. */\r\n resumeURL: string;\r\n}\r\n\r\n/**\r\n * What the next connection must do.\r\n *\r\n * A discriminated union rather than a boolean plus three nullable fields: the\r\n * caller cannot reach for a session id on the identify branch, so \"resume with\r\n * an undefined session\" is not a state this codebase can express.\r\n */\r\nexport type HandshakeIntent =\r\n ({ type: \"resume\" } & ResumeInfo) | { type: \"identify\" };\r\n\r\n/** Internal session state. `none` and `established` are the only possibilities. */\r\ntype SessionState =\r\n | { status: \"none\" }\r\n | { status: \"established\"; sessionId: string; resumeURL: string };\r\n\r\n/** Why a session was discarded. */\r\nexport type InvalidationReason =\r\n /** Discord sent `op 9` with `d: false`. */\r\n | \"invalid-session\"\r\n /** The connection closed with a code that forbids resuming. */\r\n | \"session-timeout\"\r\n /** Discarded by the owner without a protocol cause. */\r\n | \"explicit\";\r\n\r\n/**\r\n * Session state for one Gateway shard.\r\n *\r\n * **Generations.** Every connection attempt takes a token from\r\n * {@link GatewaySession.beginConnection}, and every mutation must present it.\r\n * A socket that has been superseded still holds the old token, so a late\r\n * dispatch arriving on it cannot advance the new connection's sequence or\r\n * overwrite its session id. Ownership is therefore structural rather than a\r\n * chain of `if (this.#ws === ws)` checks at each call site.\r\n */\r\nexport class GatewaySession {\r\n #state: SessionState = { status: \"none\" };\r\n /**\r\n * Last sequence observed in the current generation.\r\n *\r\n * Held beside the state rather than inside the `established` variant\r\n * because READY *is* a dispatch: its own `s` is recorded a moment before\r\n * the session exists. Storing it only on an established session would\r\n * discard the very first sequence and make the next RESUME impossible.\r\n */\r\n #sequence: number | null = null;\r\n #generation = 0;\r\n #lastInvalidation?: InvalidationReason;\r\n\r\n /** Why the last session was discarded, for diagnostics and reconnect policy. */\r\n public get lastInvalidation(): InvalidationReason | undefined {\r\n return this.#lastInvalidation;\r\n }\r\n\r\n /** Token of the current connection attempt; mutations must match it. */\r\n public get generation(): number {\r\n return this.#generation;\r\n }\r\n\r\n /** Discord's session id, or undefined when no session is established. */\r\n public get sessionId(): string | undefined {\r\n return this.#state.status === \"established\"\r\n ? this.#state.sessionId\r\n : undefined;\r\n }\r\n\r\n /** Host to reconnect to for a RESUME, or undefined when none is known. */\r\n public get resumeURL(): string | undefined {\r\n return this.#state.status === \"established\"\r\n ? this.#state.resumeURL\r\n : undefined;\r\n }\r\n\r\n /**\r\n * Last sequence number seen, or null when none has been observed.\r\n *\r\n * Null, never zero, marks \"nothing seen\": sequence `0` is a legitimate\r\n * value that must survive into a RESUME.\r\n */\r\n public get sequence(): number | null {\r\n return this.#sequence;\r\n }\r\n\r\n /** Whether a RESUME is possible: a session, a resume host, and a sequence. */\r\n public get canResume(): boolean {\r\n return this.#state.status === \"established\" && this.#sequence !== null;\r\n }\r\n\r\n /**\r\n * Opens a new connection generation and returns its token.\r\n *\r\n * The session itself is untouched: reconnecting to resume must keep the\r\n * session id and sequence. Only ownership moves.\r\n */\r\n public beginConnection(): number {\r\n return ++this.#generation;\r\n }\r\n\r\n /** Whether `token` still owns this session. */\r\n public owns(token: number): boolean {\r\n return token === this.#generation;\r\n }\r\n\r\n /**\r\n * Records a sequence number from a payload.\r\n * @returns Whether the token owned the session and the value was stored.\r\n */\r\n public recordSequence(sequence: number, token: number): boolean {\r\n if (!this.owns(token)) return false;\r\n if (!Number.isInteger(sequence)) return false;\r\n // Sequences only move forward within a session; a lower one is a\r\n // stale frame and must not roll back the point a RESUME replays from.\r\n if (this.#sequence !== null && sequence < this.#sequence) return false;\r\n this.#sequence = sequence;\r\n return true;\r\n }\r\n\r\n /**\r\n * Establishes the session from a READY payload.\r\n * @returns Whether the token owned the session and READY was well-formed.\r\n */\r\n public activate(payload: unknown, token: number): boolean {\r\n if (!this.owns(token)) return false;\r\n const ready = payload as {\r\n session_id?: unknown;\r\n resume_gateway_url?: unknown;\r\n };\r\n if (\r\n typeof ready?.session_id !== \"string\" ||\r\n typeof ready?.resume_gateway_url !== \"string\"\r\n )\r\n return false;\r\n this.#state = {\r\n status: \"established\",\r\n sessionId: ready.session_id,\r\n resumeURL: ready.resume_gateway_url,\r\n };\r\n return true;\r\n }\r\n\r\n /**\r\n * Discards the session so the next connection must IDENTIFY.\r\n *\r\n * Resumable invalidation (`op 9` with `d: true`) is *not* an invalidation:\r\n * the session survives and the caller simply reconnects, so this is only\r\n * called for the non-resumable cases.\r\n *\r\n * @returns Whether the token owned the session and state was discarded.\r\n */\r\n public invalidate(\r\n token: number,\r\n reason: InvalidationReason = \"explicit\",\r\n ): boolean {\r\n if (!this.owns(token)) return false;\r\n this.#lastInvalidation = reason;\r\n // The sequence belongs to the discarded session; carrying it into a\r\n // fresh IDENTIFY would resume numbering that Discord has forgotten.\r\n this.#state = { status: \"none\" };\r\n this.#sequence = null;\r\n return true;\r\n }\r\n\r\n /** Resume material, or undefined when a RESUME is not possible. */\r\n public resumeInfo(): ResumeInfo | undefined {\r\n if (this.#state.status !== \"established\") return undefined;\r\n if (this.#sequence === null) return undefined;\r\n const { sessionId, resumeURL } = this.#state;\r\n return { sessionId, sequence: this.#sequence, resumeURL };\r\n }\r\n\r\n /** What the next connection must send: RESUME with material, or IDENTIFY. */\r\n public handshake(): HandshakeIntent {\r\n const resume = this.resumeInfo();\r\n return resume ? { type: \"resume\", ...resume } : { type: \"identify\" };\r\n }\r\n\r\n /**\r\n * Host the next connection should dial: the resume host, else `fallback`.\r\n * The resume host comes from READY, so it is used only when it is a `wss:`\r\n * URL on discord.gg (or a subdomain), or on the fallback's own host; any\r\n * other host would receive the bot token in the RESUME frame.\r\n */\r\n public connectURL(fallback: string): string {\r\n const resume = this.resumeInfo()?.resumeURL;\r\n return resume !== undefined && isTrustedGatewayURL(resume, fallback)\r\n ? resume\r\n : fallback;\r\n }\r\n}\r\n\r\n/** Whether `url` is a `wss:` URL on discord.gg (or a subdomain) or on `fallback`'s host. */\r\nexport function isTrustedGatewayURL(url: string, fallback: string): boolean {\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(url);\r\n } catch {\r\n return false;\r\n }\r\n if (parsed.protocol !== \"wss:\" || parsed.username || parsed.password)\r\n return false;\r\n const host = parsed.hostname.toLowerCase();\r\n if (host === \"discord.gg\" || host.endsWith(\".discord.gg\")) return true;\r\n try {\r\n return host === new URL(fallback).hostname.toLowerCase();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n",
|
|
39
|
+
"/**\r\n * Heartbeat and liveness for one Gateway connection.\r\n *\r\n * Owns every timer that decides whether a connection is alive: the heartbeat\r\n * interval, the acknowledgement deadline, and the staleness (zombie) watch.\r\n * It owns no socket, no session, no reconnect policy and no event emission —\r\n * it reports through callbacks and lets its owner decide what to close.\r\n */\r\n\r\n/** Why the connection was declared dead. */\r\nexport type HeartbeatTimeout =\r\n | {\r\n /** A heartbeat went unacknowledged within `ackTimeout`. */\r\n type: \"ack\";\r\n /** Time since the unacknowledged heartbeat was sent. */\r\n elapsedMs: number;\r\n }\r\n | {\r\n /** No traffic at all arrived within the staleness deadline. */\r\n type: \"zombie\";\r\n /** Time since the last inbound message. */\r\n silentFor: number;\r\n /** Deadline that was exceeded. */\r\n deadline: number;\r\n };\r\n\r\n/** Collaborators the heartbeat needs from its owner. */\r\nexport interface HeartbeatOptions {\r\n /** Milliseconds to wait for an ACK before declaring the connection dead. */\r\n ackTimeout: number;\r\n /** Minimum silence before the connection is treated as a zombie. */\r\n zombieTimeout: number;\r\n /**\r\n * Writes a heartbeat payload.\r\n * @returns Whether it reached the wire; `false` is reported as an error.\r\n */\r\n send: (sequence: number | null) => boolean;\r\n /** Current session sequence, sent as the heartbeat's `d`. */\r\n sequence: () => number | null;\r\n /** Whether the underlying connection is open. */\r\n isConnected: () => boolean;\r\n /** Called when the connection fails a liveness check. */\r\n onTimeout: (timeout: HeartbeatTimeout) => void;\r\n /** Called for non-fatal problems, such as a heartbeat that could not be sent. */\r\n onError: (error: Error) => void;\r\n /** Clock injection point for tests. */\r\n now?: () => number;\r\n}\r\n\r\n/** Longest gap between staleness checks. */\r\nconst MAX_MONITOR_INTERVAL = 1000;\r\n\r\n/** Heartbeat lifecycle for one Gateway connection. */\r\nexport class GatewayHeartbeat {\r\n readonly #options: HeartbeatOptions;\r\n readonly #now: () => number;\r\n #interval = 0;\r\n #acknowledged = true;\r\n #sentAt = 0;\r\n #latency = -1;\r\n #lastMessageAt = 0;\r\n #zombieReported = false;\r\n #timer?: ReturnType<typeof setInterval>;\r\n #initialTimer?: ReturnType<typeof setTimeout>;\r\n #ackTimer?: ReturnType<typeof setTimeout>;\r\n #monitorTimer?: ReturnType<typeof setInterval>;\r\n\r\n public constructor(options: HeartbeatOptions) {\r\n if (options.zombieTimeout <= options.ackTimeout)\r\n throw new RangeError(\r\n \"Gateway zombieTimeout must be greater than heartbeatAckTimeout\",\r\n );\r\n this.#options = options;\r\n this.#now = options.now ?? (() => Date.now());\r\n }\r\n\r\n /** Round-trip time of the last acknowledged heartbeat, or -1 before the first. */\r\n public get latency(): number {\r\n return this.#latency;\r\n }\r\n\r\n /** Heartbeat interval Discord asked for, or 0 before HELLO. */\r\n public get interval(): number {\r\n return this.#interval;\r\n }\r\n\r\n /** Whether the most recent heartbeat has been acknowledged. */\r\n public get acknowledged(): boolean {\r\n return this.#acknowledged;\r\n }\r\n\r\n /** Milliseconds since the last inbound message, or 0 when none has arrived. */\r\n public get silentFor(): number {\r\n return this.#lastMessageAt === 0\r\n ? 0\r\n : this.#now() - this.#lastMessageAt;\r\n }\r\n\r\n /**\r\n * Deadline beyond which silence means the connection is dead.\r\n *\r\n * At least one heartbeat interval plus its ACK budget, so a quiet Gateway\r\n * is never mistaken for a dead one.\r\n */\r\n public get stalenessDeadline(): number {\r\n return Math.max(\r\n this.#options.zombieTimeout,\r\n this.#interval + this.#options.ackTimeout,\r\n );\r\n }\r\n\r\n /** Whether the connection looks alive: last beat acknowledged and traffic recent. */\r\n public isHealthy(): boolean {\r\n if (!this.#acknowledged) return false;\r\n if (this.#lastMessageAt === 0) return true;\r\n return this.silentFor < this.stalenessDeadline;\r\n }\r\n\r\n /**\r\n * Begins watching for silence. Call when the connection opens, before HELLO:\r\n * a connection that never reaches HELLO must still be detected as dead.\r\n */\r\n public watch(): void {\r\n this.#lastMessageAt = this.#now();\r\n this.#zombieReported = false;\r\n this.#startMonitor();\r\n }\r\n\r\n /** Records inbound traffic of any kind. */\r\n public receivedMessage(): void {\r\n this.#lastMessageAt = this.#now();\r\n this.#zombieReported = false;\r\n }\r\n\r\n /**\r\n * Starts heartbeating at Discord's interval.\r\n *\r\n * The first beat is jittered across the interval, as Discord's\r\n * documentation requires, so a fleet reconnecting together does not\r\n * heartbeat in lockstep.\r\n */\r\n public start(interval: number): void {\r\n this.#clearBeatTimers();\r\n this.#interval = interval;\r\n this.#acknowledged = true;\r\n // The regular cadence starts from the first beat, not from HELLO:\r\n // arming both at once can fire two beats back to back when the\r\n // jitter lands near the full interval.\r\n this.#initialTimer = setTimeout(() => {\r\n this.#initialTimer = undefined;\r\n this.sendHeartbeat();\r\n this.#timer = setInterval(() => this.sendHeartbeat(), interval);\r\n }, Math.random() * interval);\r\n }\r\n\r\n /** Stops every timer. Safe to call more than once. */\r\n public stop(): void {\r\n this.#clearBeatTimers();\r\n if (this.#monitorTimer) clearInterval(this.#monitorTimer);\r\n this.#monitorTimer = undefined;\r\n }\r\n\r\n /** Sends a heartbeat now, and arms the acknowledgement deadline. */\r\n public sendHeartbeat(): void {\r\n this.#acknowledged = false;\r\n this.#sentAt = this.#now();\r\n if (!this.#options.send(this.#options.sequence())) {\r\n this.#options.onError(\r\n new Error(\r\n \"Unable to send Gateway heartbeat because the WebSocket is not open.\",\r\n ),\r\n );\r\n return;\r\n }\r\n this.#clearAckTimer();\r\n this.#ackTimer = setTimeout(() => {\r\n if (this.#acknowledged) return;\r\n this.#options.onTimeout({\r\n type: \"ack\",\r\n elapsedMs: this.#now() - this.#sentAt,\r\n });\r\n }, this.#options.ackTimeout);\r\n }\r\n\r\n /** Records a heartbeat ACK and updates {@link latency}. */\r\n public acknowledge(): void {\r\n // An ACK with no heartbeat outstanding carries no round trip to measure.\r\n if (this.#acknowledged) return;\r\n this.#acknowledged = true;\r\n this.#latency = this.#now() - this.#sentAt;\r\n this.#clearAckTimer();\r\n }\r\n\r\n #startMonitor(): void {\r\n if (this.#monitorTimer) clearInterval(this.#monitorTimer);\r\n // Poll granularity only needs to be a fraction of the staleness\r\n // deadline. A 1s ceiling keeps detection latency negligible while\r\n // costing one wakeup per second per shard instead of four.\r\n const interval = Math.max(\r\n 1,\r\n Math.min(\r\n MAX_MONITOR_INTERVAL,\r\n this.#options.ackTimeout,\r\n this.#options.zombieTimeout / 2,\r\n ),\r\n );\r\n this.#monitorTimer = setInterval(\r\n () => this.#checkStaleness(),\r\n interval,\r\n );\r\n }\r\n\r\n #checkStaleness(): void {\r\n if (!this.#options.isConnected() || this.#lastMessageAt === 0) return;\r\n const silentFor = this.silentFor;\r\n const deadline = this.stalenessDeadline;\r\n if (silentFor < deadline || this.#zombieReported) return;\r\n // Report once per silence: the owner closes the connection, and the\r\n // close path stops these timers.\r\n this.#zombieReported = true;\r\n this.#options.onTimeout({ type: \"zombie\", silentFor, deadline });\r\n }\r\n\r\n #clearAckTimer(): void {\r\n if (this.#ackTimer) clearTimeout(this.#ackTimer);\r\n this.#ackTimer = undefined;\r\n }\r\n\r\n #clearBeatTimers(): void {\r\n if (this.#timer) clearInterval(this.#timer);\r\n if (this.#initialTimer) clearTimeout(this.#initialTimer);\r\n this.#clearAckTimer();\r\n this.#timer = undefined;\r\n this.#initialTimer = undefined;\r\n }\r\n}\r\n",
|
|
40
|
+
"/**\r\n * Discord Gateway close codes.\r\n *\r\n * Discord.js-familiar names and numeric values, matching the Discord Gateway\r\n * protocol. Exposed so consumers can branch on named codes instead of magic\r\n * numbers; {@link Gateway} uses them internally to decide resume/identify/stop.\r\n */\r\nexport const GatewayCloseCodes = {\r\n UnknownError: 4000,\r\n UnknownOpcode: 4001,\r\n DecodeError: 4002,\r\n NotAuthenticated: 4003,\r\n AuthenticationFailed: 4004,\r\n AlreadyAuthenticated: 4005,\r\n InvalidSeq: 4007,\r\n RateLimited: 4008,\r\n SessionTimedOut: 4009,\r\n InvalidShard: 4010,\r\n ShardingRequired: 4011,\r\n InvalidAPIVersion: 4012,\r\n InvalidIntents: 4013,\r\n DisallowedIntents: 4014,\r\n} as const;\r\n",
|
|
41
|
+
"/**\r\n * Reconnect policy and scheduling for one Gateway connection.\r\n *\r\n * Owns how a close code is classified, whether another attempt is allowed, how\r\n * long to wait, and the coordination that keeps at most one logical connection\r\n * attempt in flight. It owns no socket, no session state, no heartbeat and no\r\n * event emission: it is told a close code and whether a resume is possible, and\r\n * answers with a decision.\r\n */\r\nimport { GatewayCloseCodes } from \"./close-codes.js\";\r\n\r\n/** What a closed connection should do next. */\r\nexport type CloseAction =\r\n /** Reconnect and RESUME the existing session. */\r\n | \"resume\"\r\n /** Reconnect, but IDENTIFY afresh: the session cannot be resumed. */\r\n | \"identify\"\r\n /** Do not reconnect; the condition will not fix itself. */\r\n | \"stop\";\r\n\r\n/**\r\n * Close codes that no reconnect can recover from: bad token, bad shard\r\n * configuration, bad API version, or intents the application is not approved\r\n * for. Retrying these hammers Discord with a request that cannot succeed.\r\n */\r\nexport const FATAL_CLOSE_CODES: readonly number[] = [\r\n GatewayCloseCodes.AuthenticationFailed,\r\n GatewayCloseCodes.InvalidShard,\r\n GatewayCloseCodes.ShardingRequired,\r\n GatewayCloseCodes.InvalidAPIVersion,\r\n GatewayCloseCodes.InvalidIntents,\r\n GatewayCloseCodes.DisallowedIntents,\r\n];\r\n\r\n/**\r\n * Close codes that keep the connection recoverable but destroy the session, so\r\n * the next connection must IDENTIFY rather than RESUME.\r\n */\r\nexport const IDENTIFY_CLOSE_CODES: readonly number[] = [\r\n GatewayCloseCodes.InvalidSeq,\r\n GatewayCloseCodes.SessionTimedOut,\r\n];\r\n\r\n/**\r\n * Classifies a close code.\r\n *\r\n * Any code outside the two tables above is **reconnectable**: transport-level\r\n * closes (`1006`), server restarts (`1001`), Discord's own `4000`, and the\r\n * `1000` the Gateway itself sends after a non-resumable `op 9` all belong here.\r\n * Whether that reconnect resumes or identifies is not a property of the code —\r\n * it is whether a session survives, which is why `canResume` is a parameter\r\n * rather than something this module works out for itself.\r\n *\r\n * @param code WebSocket close code.\r\n * @param canResume Whether the session can still be resumed.\r\n */\r\nexport function classifyCloseCode(\r\n code: number,\r\n canResume: boolean,\r\n): CloseAction {\r\n if (FATAL_CLOSE_CODES.includes(code)) return \"stop\";\r\n if (IDENTIFY_CLOSE_CODES.includes(code)) return \"identify\";\r\n return canResume ? \"resume\" : \"identify\";\r\n}\r\n\r\n/** Why a reconnect was not scheduled. */\r\nexport type ScheduleRefusal =\r\n /** Automatic reconnect is disabled for this Gateway. */\r\n | \"disabled\"\r\n /** A reconnect is already armed; a second would open a second socket. */\r\n | \"pending\"\r\n /** The attempt budget is spent. */\r\n | \"exhausted\";\r\n\r\n/** Outcome of asking for a reconnect. */\r\nexport type ScheduleResult =\r\n | { scheduled: true; delayMs: number; attempt: number }\r\n | { scheduled: false; reason: ScheduleRefusal };\r\n\r\n/** Configuration for {@link GatewayReconnect}. */\r\nexport interface ReconnectOptions {\r\n /** Whether automatic reconnect is permitted at all. */\r\n enabled: boolean;\r\n /** Maximum consecutive attempts before giving up. */\r\n maxAttempts: number;\r\n /** Delay for the first attempt, doubled per attempt. */\r\n baseDelay: number;\r\n /** Ceiling for the backoff. */\r\n maxDelay: number;\r\n /** Randomness source for jitter; injected in tests. */\r\n random?: () => number;\r\n}\r\n\r\n/** Reconnect scheduling, backoff and attempt coordination. */\r\nexport class GatewayReconnect {\r\n readonly #options: ReconnectOptions;\r\n readonly #random: () => number;\r\n #attempt = 0;\r\n #timer?: ReturnType<typeof setTimeout>;\r\n #promise?: Promise<void>;\r\n #resolve?: () => void;\r\n #reject?: (error: Error) => void;\r\n\r\n public constructor(options: ReconnectOptions) {\r\n this.#options = options;\r\n this.#random = options.random ?? Math.random;\r\n }\r\n\r\n /** Whether automatic reconnect is permitted. */\r\n public get enabled(): boolean {\r\n return this.#options.enabled;\r\n }\r\n\r\n /** Consecutive attempts made since the last {@link reset}. */\r\n public get attempts(): number {\r\n return this.#attempt;\r\n }\r\n\r\n /** Whether a reconnect timer is currently armed. */\r\n public get pending(): boolean {\r\n return this.#timer !== undefined;\r\n }\r\n\r\n /** Whether the attempt budget is spent. */\r\n public get exhausted(): boolean {\r\n return this.#attempt >= this.#options.maxAttempts;\r\n }\r\n\r\n /** Whether a connection attempt is currently in flight. */\r\n public get connecting(): boolean {\r\n return this.#promise !== undefined;\r\n }\r\n\r\n /** The in-flight attempt, or undefined when none is active. */\r\n public get attemptPromise(): Promise<void> | undefined {\r\n return this.#promise;\r\n }\r\n\r\n /** Classifies a close code against this Gateway's policy. */\r\n public classifyClose(code: number, canResume: boolean): CloseAction {\r\n return classifyCloseCode(code, canResume);\r\n }\r\n\r\n /** Whether another reconnect is currently allowed. */\r\n public canReconnect(): boolean {\r\n return this.#options.enabled && !this.exhausted;\r\n }\r\n\r\n /**\r\n * Arms a reconnect, unless one is already armed or no attempt is allowed.\r\n *\r\n * Refusing while `pending` is what keeps repeated closes from stacking\r\n * timers: several closes in a row produce one reconnect, not several\r\n * competing sockets.\r\n */\r\n public schedule(run: () => void): ScheduleResult {\r\n if (!this.#options.enabled)\r\n return { scheduled: false, reason: \"disabled\" };\r\n if (this.#timer) return { scheduled: false, reason: \"pending\" };\r\n if (this.exhausted) return { scheduled: false, reason: \"exhausted\" };\r\n\r\n const attempt = this.#attempt;\r\n const delay = Math.min(\r\n this.#options.maxDelay,\r\n this.#options.baseDelay * 2 ** this.#attempt++,\r\n );\r\n // Jitter must scale with the delay: a fixed ceiling would reconnect\r\n // every shard inside the same narrow window after a gateway-wide\r\n // restart, which is exactly when decorrelation matters.\r\n const jitter = this.#random() * Math.max(1, delay * 0.25);\r\n const delayMs = delay + jitter;\r\n this.#timer = setTimeout(() => {\r\n this.#timer = undefined;\r\n run();\r\n }, delayMs);\r\n return { scheduled: true, delayMs, attempt };\r\n }\r\n\r\n /** Cancels an armed reconnect. Safe to call when none is armed. */\r\n public cancel(): void {\r\n if (this.#timer) clearTimeout(this.#timer);\r\n this.#timer = undefined;\r\n }\r\n\r\n /** Clears the attempt counter after a connection succeeds. */\r\n public reset(): void {\r\n this.#attempt = 0;\r\n }\r\n\r\n /**\r\n * Coordinates one logical connection attempt.\r\n *\r\n * Callers that ask while an attempt is in flight join it instead of\r\n * starting a second: three `connect()` calls produce one socket attempt and\r\n * one shared promise.\r\n *\r\n * @param start Invoked exactly once, when this call begins a new attempt.\r\n */\r\n public attempt(start: () => void): Promise<void> {\r\n if (this.#promise) return this.#promise;\r\n this.#promise = new Promise<void>((resolve, reject) => {\r\n this.#resolve = resolve;\r\n this.#reject = reject;\r\n start();\r\n });\r\n return this.#promise;\r\n }\r\n\r\n /** Settles the in-flight attempt, resolving it or rejecting with `error`. */\r\n public settle(error?: Error): void {\r\n const resolve = this.#resolve;\r\n const reject = this.#reject;\r\n this.#resolve = undefined;\r\n this.#reject = undefined;\r\n this.#promise = undefined;\r\n if (error) reject?.(error);\r\n else resolve?.();\r\n }\r\n}\r\n",
|
|
42
|
+
"/**\r\n * Turns WebSocket data into complete Gateway text frames.\r\n *\r\n * The contract is deliberately boring: bytes in, whole frames out. A decoder\r\n * knows nothing about opcodes, sessions, heartbeats or JSON validity — it only\r\n * knows when a frame is *complete*. Parsing the text is the protocol layer's\r\n * job, so malformed JSON is not a decoding failure; malformed *compressed\r\n * bytes* are.\r\n */\r\nimport {\r\n createInflate,\r\n constants as zlibConstants,\r\n type Inflate,\r\n} from \"node:zlib\";\r\n\r\n/** Decodes transport data into complete frames. */\r\nexport interface GatewayDecoder {\r\n /**\r\n * Feeds one WebSocket message.\r\n *\r\n * A decoder that can answer synchronously must do so: delivery timing is\r\n * observable to consumers, and an uncompressed frame has no reason to cost\r\n * a microtask.\r\n *\r\n * @returns Every frame completed by this chunk; empty while a frame is\r\n * still arriving.\r\n */\r\n push(data: unknown): string[] | Promise<string[]>;\r\n /** Discards buffered state. Call when a connection is replaced. */\r\n reset(): void;\r\n}\r\n\r\n/** Normalises a binary WebSocket payload into bytes. */\r\nasync function toBytes(data: unknown): Promise<Uint8Array> {\r\n if (data instanceof Uint8Array) return data;\r\n if (data instanceof ArrayBuffer) return new Uint8Array(data);\r\n if (typeof Blob !== \"undefined\" && data instanceof Blob)\r\n return new Uint8Array(await data.arrayBuffer());\r\n throw new TypeError(\r\n \"Gateway returned an unsupported compressed frame type.\",\r\n );\r\n}\r\n\r\n/** Passes text frames through unchanged, for an uncompressed connection. */\r\nexport class PlainTextDecoder implements GatewayDecoder {\r\n public push(data: unknown): string[] {\r\n return [String(data)];\r\n }\r\n public reset(): void {\r\n // Stateless: nothing to discard.\r\n }\r\n}\r\n\r\n/**\r\n * Decodes Discord's `zlib-stream` transport compression.\r\n *\r\n * Discord sends one zlib stream whose logical payloads are separated by the\r\n * `Z_SYNC_FLUSH` marker `00 00 FF FF`. A payload may span several WebSocket\r\n * messages, so output is produced only when that marker arrives: a partial\r\n * payload is retained rather than guessed at.\r\n *\r\n * The inflater carries state across frames, so `push` calls must not\r\n * interleave. {@link WebSocketTransport} serialises them by construction.\r\n */\r\nexport class ZlibStreamDecoder implements GatewayDecoder {\r\n readonly #create: () => Inflate;\r\n readonly #maxFrameBytes: number;\r\n #inflate?: Inflate;\r\n #chunks: Uint8Array[] = [];\r\n /** Bytes inflated for the frame being assembled. */\r\n #size = 0;\r\n #failure?: Error;\r\n /**\r\n * Rejector for the operation currently awaiting the inflater.\r\n *\r\n * zlib does **not** invoke a `write` or `flush` callback once the stream\r\n * has errored — it emits `error` and abandons the callback — so an\r\n * awaited callback alone hangs forever on corrupt input. The error handler\r\n * settles the waiter instead.\r\n */\r\n #pendingReject?: (error: Error) => void;\r\n\r\n /**\r\n * @param create Inflater factory; injected in tests.\r\n * @param maxFrameBytes Largest inflated frame accepted (default 64 MiB);\r\n * past it the stream fails instead of growing until memory runs out.\r\n */\r\n public constructor(\r\n create: () => Inflate = () => createInflate(),\r\n maxFrameBytes = 64 * 1024 * 1024,\r\n ) {\r\n this.#create = create;\r\n this.#maxFrameBytes = maxFrameBytes;\r\n }\r\n\r\n /**\r\n * A text frame on a compressed connection is already a complete frame, so\r\n * it is returned synchronously and never touches the inflater. Discord\r\n * sends everything binary under `zlib-stream`; tolerating a string costs\r\n * nothing, and treating one as a decode failure — or delaying it by a\r\n * microtask — would both change observable behaviour.\r\n */\r\n public push(data: unknown): string[] | Promise<string[]> {\r\n if (typeof data === \"string\") return [data];\r\n return this.#inflateFrame(data);\r\n }\r\n\r\n async #inflateFrame(data: unknown): Promise<string[]> {\r\n const chunk = await toBytes(data);\r\n const inflate = (this.#inflate ??= this.#open());\r\n // A stream that has already failed cannot be trusted for any later\r\n // frame: its dictionary state is undefined from the error onwards.\r\n if (this.#failure) throw this.#failure;\r\n const complete =\r\n chunk.length >= 4 &&\r\n chunk[chunk.length - 4] === 0x00 &&\r\n chunk[chunk.length - 3] === 0x00 &&\r\n chunk[chunk.length - 2] === 0xff &&\r\n chunk[chunk.length - 1] === 0xff;\r\n\r\n await this.#awaiting((settle) =>\r\n inflate.write(chunk, (error) => (error ? settle(error) : settle())),\r\n );\r\n if (!complete) return [];\r\n\r\n await this.#awaiting((settle) =>\r\n inflate.flush(zlibConstants.Z_SYNC_FLUSH, () => settle()),\r\n );\r\n\r\n const parts = this.#chunks;\r\n this.#chunks = [];\r\n this.#size = 0;\r\n if (parts.length === 0) return [];\r\n const total = parts.reduce((size, part) => size + part.length, 0);\r\n const merged = new Uint8Array(total);\r\n let offset = 0;\r\n for (const part of parts) {\r\n merged.set(part, offset);\r\n offset += part.length;\r\n }\r\n return [new TextDecoder().decode(merged)];\r\n }\r\n\r\n public reset(): void {\r\n const inflate = this.#inflate;\r\n this.#inflate = undefined;\r\n this.#chunks = [];\r\n this.#size = 0;\r\n this.#failure = undefined;\r\n this.#pendingReject = undefined;\r\n if (!inflate) return;\r\n inflate.removeAllListeners();\r\n try {\r\n inflate.close();\r\n } catch {\r\n // Closing a stream that already failed is not itself a failure.\r\n }\r\n }\r\n\r\n /**\r\n * Runs one inflater operation, failing it if the stream errors meanwhile.\r\n */\r\n #awaiting(\r\n run: (settle: (error?: Error | null) => void) => void,\r\n ): Promise<void> {\r\n if (this.#failure) return Promise.reject(this.#failure);\r\n return new Promise<void>((resolve, reject) => {\r\n this.#pendingReject = reject;\r\n run((error) => {\r\n this.#pendingReject = undefined;\r\n if (error) reject(error);\r\n else if (this.#failure) reject(this.#failure);\r\n else resolve();\r\n });\r\n });\r\n }\r\n\r\n #open(): Inflate {\r\n const inflate = this.#create();\r\n inflate.on(\"data\", (chunk: Uint8Array) => {\r\n if (this.#failure) return;\r\n this.#size += chunk.length;\r\n if (this.#size > this.#maxFrameBytes) {\r\n // Same path as a corrupt stream: the waiter rejects and the\r\n // connection is reset, so nothing keeps accumulating.\r\n this.#chunks = [];\r\n inflate.emit(\r\n \"error\",\r\n new Error(\r\n `Gateway frame inflated past ${this.#maxFrameBytes} bytes.`,\r\n ),\r\n );\r\n return;\r\n }\r\n this.#chunks.push(chunk);\r\n });\r\n inflate.on(\"error\", (error: Error) => {\r\n this.#failure = error;\r\n // Settle whatever is waiting: zlib will not call its callback.\r\n const reject = this.#pendingReject;\r\n this.#pendingReject = undefined;\r\n reject?.(error);\r\n });\r\n return inflate;\r\n }\r\n}\r\n\r\n/** Creates the decoder a connection needs. */\r\nexport function createDecoder(compress: boolean | undefined): GatewayDecoder {\r\n return compress ? new ZlibStreamDecoder() : new PlainTextDecoder();\r\n}\r\n",
|
|
43
|
+
"/**\r\n * The WebSocket a Gateway connection runs on.\r\n *\r\n * Owns socket construction, listener wiring, sending, closing, and replacement.\r\n * It is infrastructure, not Discord semantics: it never inspects an opcode, a\r\n * session, or a heartbeat. Frames go out as text and come back as text.\r\n */\r\nimport { createDecoder, type GatewayDecoder } from \"./decoder.js\";\r\n\r\n/** Creates the underlying socket. Injected to support alternative runtimes. */\r\nexport type SocketFactory = (url: string) => WebSocket;\r\n\r\n/** Callbacks a transport reports to its owner. */\r\nexport interface TransportHandlers {\r\n /** The socket opened and is ready to send. */\r\n onOpen: () => void;\r\n /** A complete frame arrived, already decompressed. */\r\n onFrame: (raw: string) => void;\r\n /** The socket closed. */\r\n onClose: (code: number, reason: string) => void;\r\n /** A socket or decoding failure. Not a close on its own. */\r\n onError: (error: Error) => void;\r\n}\r\n\r\n/** Outcome of opening a connection. */\r\nexport type ConnectResult = { ok: true } | { ok: false; error: Error };\r\n\r\n/** Configuration for {@link WebSocketTransport}. */\r\nexport interface TransportOptions {\r\n /** Handlers for this transport's lifetime. */\r\n handlers: TransportHandlers;\r\n /** Frame decoder. Defaults to plain text, or zlib-stream when compressing. */\r\n decoder?: GatewayDecoder;\r\n /** Whether the connection negotiates `zlib-stream` compression. */\r\n compress?: boolean;\r\n /** Socket constructor. Defaults to the ambient `WebSocket`. */\r\n createSocket?: SocketFactory;\r\n}\r\n\r\n/** WebSocket states. Compared numerically so a stub needs no static constants. */\r\nconst OPEN = 1;\r\n\r\n/**\r\n * A replaceable WebSocket connection.\r\n *\r\n * **Generations.** Each {@link connect} takes a generation, and every event is\r\n * checked against the current one. A socket that has been replaced still holds\r\n * its listeners and can still fire — especially a frame that finishes\r\n * decompressing after the swap — and every such event is dropped. The owner\r\n * therefore never has to ask \"is this still my socket?\".\r\n */\r\nexport class WebSocketTransport {\r\n readonly #handlers: TransportHandlers;\r\n readonly #decoder: GatewayDecoder;\r\n readonly #createSocket: SocketFactory;\r\n readonly #compress: boolean;\r\n #socket?: WebSocket;\r\n #generation = 0;\r\n /** Serialises decoding so stateful decoders never see interleaved chunks. */\r\n #queue: Promise<void> = Promise.resolve();\r\n\r\n public constructor(options: TransportOptions) {\r\n this.#handlers = options.handlers;\r\n this.#compress = options.compress ?? false;\r\n this.#decoder = options.decoder ?? createDecoder(options.compress);\r\n this.#createSocket =\r\n options.createSocket ?? ((url: string) => new WebSocket(url));\r\n }\r\n\r\n /** Whether a socket is open and able to send. */\r\n public get connected(): boolean {\r\n return this.#socket?.readyState === OPEN;\r\n }\r\n\r\n /** Whether a socket is connecting or open, and therefore still in play. */\r\n public get live(): boolean {\r\n return this.#socket !== undefined && this.#socket.readyState <= OPEN;\r\n }\r\n\r\n /** Current connection generation; increments on every {@link connect}. */\r\n public get generation(): number {\r\n return this.#generation;\r\n }\r\n\r\n /**\r\n * Opens a connection, replacing any existing one.\r\n *\r\n * A construction failure is returned rather than reported through\r\n * `onError`: the caller is mid-`connect` and must decide what the failure\r\n * means for the attempt it is running.\r\n */\r\n public connect(url: string): ConnectResult {\r\n // Never leave a predecessor behind: an orphan keeps its listeners and\r\n // would go on feeding this transport's owner.\r\n this.#discard(1000, \"Superseded by a new connection\");\r\n const generation = ++this.#generation;\r\n // A replaced connection's decoder state is meaningless to the new one.\r\n this.#decoder.reset();\r\n this.#queue = Promise.resolve();\r\n\r\n let socket: WebSocket;\r\n try {\r\n socket = this.#createSocket(url);\r\n } catch (error) {\r\n return { ok: false, error: this.#asError(error) };\r\n }\r\n if (this.#compress) {\r\n try {\r\n (socket as { binaryType?: string }).binaryType = \"arraybuffer\";\r\n } catch {\r\n // Runtimes that pin binaryType are handled by the decoder.\r\n }\r\n }\r\n this.#socket = socket;\r\n\r\n socket.addEventListener(\"open\", () => {\r\n if (!this.#owns(generation)) return;\r\n this.#handlers.onOpen();\r\n });\r\n socket.addEventListener(\"message\", (event) => {\r\n if (!this.#owns(generation)) return;\r\n // A decoder that answers synchronously is delivered synchronously:\r\n // an uncompressed frame must not become a microtask, because\r\n // dispatch timing is observable to consumers.\r\n let decoded: string[] | Promise<string[]>;\r\n try {\r\n decoded = this.#decoder.push(event.data);\r\n } catch (error) {\r\n this.#handlers.onError(this.#asError(error));\r\n return;\r\n }\r\n if (!(decoded instanceof Promise)) {\r\n for (const frame of decoded) this.#handlers.onFrame(frame);\r\n return;\r\n }\r\n // A stateful decoder must never see interleaved chunks, and the\r\n // generation is re-checked once the chunk is actually decoded: the\r\n // socket may have been replaced while this frame was in flight.\r\n this.#queue = this.#queue\r\n .then(async () => {\r\n const frames = await decoded;\r\n if (!this.#owns(generation)) return;\r\n for (const frame of frames) this.#handlers.onFrame(frame);\r\n })\r\n .catch((error) => {\r\n if (!this.#owns(generation)) return;\r\n this.#handlers.onError(this.#asError(error));\r\n });\r\n });\r\n socket.addEventListener(\"close\", (event) => {\r\n if (!this.#owns(generation)) return;\r\n this.#socket = undefined;\r\n // A closed socket owns nothing further. Retiring its generation\r\n // here is what makes every later event from it — a late frame, a\r\n // second close, an error — stale by construction, including a\r\n // frame that was still decompressing when the socket went away.\r\n this.#generation++;\r\n this.#decoder.reset();\r\n this.#handlers.onClose(event.code, event.reason ?? \"\");\r\n });\r\n socket.addEventListener(\"error\", () => {\r\n if (!this.#owns(generation)) return;\r\n this.#handlers.onError(new Error(\"Gateway WebSocket error\"));\r\n });\r\n return { ok: true };\r\n }\r\n\r\n /**\r\n * Writes a frame.\r\n * @returns Whether it reached the socket.\r\n */\r\n public send(data: string): boolean {\r\n if (!this.connected) return false;\r\n try {\r\n this.#socket!.send(data);\r\n return true;\r\n } catch (error) {\r\n this.#handlers.onError(this.#asError(error));\r\n return false;\r\n }\r\n }\r\n\r\n /** Closes the current socket, if any. Its `close` event still fires. */\r\n public close(code = 1000, reason = \"\"): void {\r\n const socket = this.#socket;\r\n if (!socket) return;\r\n try {\r\n socket.close(code, reason);\r\n } catch (error) {\r\n this.#handlers.onError(this.#asError(error));\r\n }\r\n }\r\n\r\n /**\r\n * Abandons the current socket without reporting its close.\r\n *\r\n * Used for a deliberate shutdown, where the owner has already decided the\r\n * connection is over and must not be woken by the resulting close event.\r\n */\r\n public destroy(code = 1000, reason = \"\"): void {\r\n this.#discard(code, reason);\r\n this.#decoder.reset();\r\n }\r\n\r\n /** Whether `generation` still owns this transport. */\r\n #owns(generation: number): boolean {\r\n return generation === this.#generation;\r\n }\r\n\r\n /** Detaches and closes the current socket without emitting its close. */\r\n #discard(code: number, reason: string): void {\r\n const socket = this.#socket;\r\n if (!socket) return;\r\n // Bumping the generation first makes every event this socket may still\r\n // fire — including a close caused by the call below — a stale event.\r\n this.#generation++;\r\n this.#socket = undefined;\r\n try {\r\n socket.close(code, reason);\r\n } catch (error) {\r\n this.#handlers.onError(this.#asError(error));\r\n }\r\n }\r\n\r\n #asError(error: unknown): Error {\r\n return error instanceof Error ? error : new Error(String(error));\r\n }\r\n}\r\n",
|
|
44
|
+
"/** Discord Gateway opcodes. */\r\nexport const GatewayOpcodes = {\r\n Dispatch: 0,\r\n Heartbeat: 1,\r\n Identify: 2,\r\n PresenceUpdate: 3,\r\n VoiceStateUpdate: 4,\r\n Resume: 6,\r\n Reconnect: 7,\r\n RequestGuildMembers: 8,\r\n InvalidSession: 9,\r\n Hello: 10,\r\n HeartbeatAck: 11,\r\n} as const;\r\n",
|
|
45
|
+
"/**\r\n * Discord Gateway protocol: what a payload *means*.\r\n *\r\n * Pure translation from a received frame to an action, plus construction of\r\n * the payloads Lunibee sends. It performs nothing: no socket, no timers, no\r\n * session mutation, no event emission, no sending. The caller decides what to\r\n * do with an action, which is what lets the whole protocol be tested without a\r\n * connection.\r\n */\r\nimport type { GatewayPayload, GatewayPresence } from \"@lunibee/types\";\r\nimport { GatewayOpcodes } from \"./opcodes.js\";\r\nimport type { ResumeInfo } from \"./session.js\";\r\n\r\n/** Why a frame could not be understood. */\r\nexport type ProtocolViolation =\r\n /** The frame was not valid JSON. */\r\n | \"invalid-json\"\r\n /** The frame decoded to something other than a payload object. */\r\n | \"invalid-payload\"\r\n /** `HELLO` carried no usable heartbeat interval. */\r\n | \"invalid-hello\";\r\n\r\n/** What a received frame means. */\r\nexport type GatewayAction =\r\n /** `op 10`: begin heartbeating and hand shake. */\r\n | { type: \"hello\"; heartbeatInterval: number }\r\n /** `op 0`: an event. `event` is null only if Discord omitted `t`. */\r\n | { type: \"dispatch\"; event: string | null; data: unknown }\r\n /** `op 1`: Discord asks for a heartbeat now. */\r\n | { type: \"heartbeat\" }\r\n /** `op 11`: the last heartbeat was acknowledged. */\r\n | { type: \"heartbeat-ack\"; data: unknown }\r\n /** `op 7`: Discord asks the client to reconnect. */\r\n | { type: \"reconnect\" }\r\n /** `op 9`: the session is gone. `resumable` decides RESUME vs IDENTIFY. */\r\n | { type: \"invalid-session\"; resumable: boolean }\r\n /**\r\n * An opcode this version does not handle.\r\n *\r\n * Ignored rather than treated as an error: Discord adds opcodes, and a\r\n * client that fails on an unfamiliar one breaks itself on every addition.\r\n */\r\n | { type: \"unknown\"; opcode: number }\r\n /** The frame was malformed. Never silently swallowed. */\r\n | {\r\n type: \"invalid\";\r\n violation: ProtocolViolation;\r\n message: string;\r\n cause?: unknown;\r\n };\r\n\r\n/** A classified frame: its sequence, if any, and what it means. */\r\nexport interface ProtocolResult {\r\n /**\r\n * Sequence carried by the frame, or null when it carried none.\r\n *\r\n * Reported for every payload type, not just dispatches: recording it is\r\n * the caller's decision, and the caller records before acting so a RESUME\r\n * cannot be built from a sequence that was never seen.\r\n */\r\n sequence: number | null;\r\n /** What the frame means. */\r\n action: GatewayAction;\r\n}\r\n\r\n/**\r\n * Classifies one received frame.\r\n *\r\n * @param raw The frame text, already decompressed by the transport.\r\n */\r\nexport function classifyFrame(raw: string): ProtocolResult {\r\n let payload: GatewayPayload;\r\n try {\r\n payload = JSON.parse(raw) as GatewayPayload;\r\n } catch (error) {\r\n return {\r\n sequence: null,\r\n action: {\r\n type: \"invalid\",\r\n violation: \"invalid-json\",\r\n message: \"Gateway returned invalid JSON\",\r\n cause: error,\r\n },\r\n };\r\n }\r\n return classifyPayload(payload);\r\n}\r\n\r\n/** Classifies an already-parsed payload. */\r\nexport function classifyPayload(payload: unknown): ProtocolResult {\r\n if (\r\n payload === null ||\r\n typeof payload !== \"object\" ||\r\n typeof (payload as GatewayPayload).op !== \"number\"\r\n )\r\n return {\r\n sequence: null,\r\n action: {\r\n type: \"invalid\",\r\n violation: \"invalid-payload\",\r\n message: \"Gateway returned an invalid payload\",\r\n },\r\n };\r\n\r\n const frame = payload as GatewayPayload;\r\n const sequence = typeof frame.s === \"number\" ? frame.s : null;\r\n\r\n switch (frame.op) {\r\n case GatewayOpcodes.Dispatch:\r\n return {\r\n sequence,\r\n action: {\r\n type: \"dispatch\",\r\n event: typeof frame.t === \"string\" ? frame.t : null,\r\n data: frame.d,\r\n },\r\n };\r\n case GatewayOpcodes.Hello: {\r\n const interval = (frame.d as { heartbeat_interval?: unknown })\r\n ?.heartbeat_interval;\r\n if (\r\n typeof interval !== \"number\" ||\r\n !Number.isFinite(interval) ||\r\n interval <= 0\r\n )\r\n return {\r\n sequence,\r\n action: {\r\n type: \"invalid\",\r\n violation: \"invalid-hello\",\r\n message:\r\n \"Gateway HELLO payload contains an invalid heartbeat interval\",\r\n },\r\n };\r\n return {\r\n sequence,\r\n action: { type: \"hello\", heartbeatInterval: interval },\r\n };\r\n }\r\n case GatewayOpcodes.Heartbeat:\r\n return { sequence, action: { type: \"heartbeat\" } };\r\n case GatewayOpcodes.HeartbeatAck:\r\n return {\r\n sequence,\r\n action: { type: \"heartbeat-ack\", data: frame.d },\r\n };\r\n case GatewayOpcodes.Reconnect:\r\n return { sequence, action: { type: \"reconnect\" } };\r\n case GatewayOpcodes.InvalidSession:\r\n // `d` is a boolean: true means the session may still be resumed.\r\n // Anything else is treated as non-resumable, which is the safe\r\n // reading — a wrongly-attempted RESUME costs another round trip.\r\n return {\r\n sequence,\r\n action: {\r\n type: \"invalid-session\",\r\n resumable: frame.d === true,\r\n },\r\n };\r\n default:\r\n return { sequence, action: { type: \"unknown\", opcode: frame.op } };\r\n }\r\n}\r\n\r\n/** Identification properties sent with IDENTIFY. */\r\nexport interface IdentifyProperties {\r\n os?: string;\r\n browser?: string;\r\n device?: string;\r\n [key: string]: string | undefined;\r\n}\r\n\r\n/** Everything IDENTIFY needs. */\r\nexport interface IdentifyOptions {\r\n token: string;\r\n intents: number;\r\n shardId: number;\r\n shardCount: number;\r\n properties?: IdentifyProperties;\r\n presence?: GatewayPresence;\r\n}\r\n\r\n/** The `d` field of an IDENTIFY payload. */\r\nexport interface IdentifyData {\r\n token: string;\r\n intents: number;\r\n properties: IdentifyProperties;\r\n presence: Required<GatewayPresence>;\r\n shard: [shardId: number, shardCount: number];\r\n}\r\n\r\n/** Builds an IDENTIFY payload. */\r\nexport function identifyPayload(\r\n options: IdentifyOptions,\r\n): GatewayPayload<IdentifyData> {\r\n const props = options.properties ?? {};\r\n const os = props.os ?? process.platform;\r\n const browser = props.browser ?? \"Lunibee\";\r\n const device = props.device ?? \"Lunibee\";\r\n return {\r\n op: GatewayOpcodes.Identify,\r\n d: {\r\n token: options.token,\r\n intents: options.intents,\r\n properties: {\r\n os,\r\n browser,\r\n device,\r\n // Discord accepted `$`-prefixed property names historically and\r\n // still does; both spellings are sent so the payload works\r\n // against either expectation.\r\n $os: os,\r\n $browser: browser,\r\n $device: device,\r\n ...props,\r\n },\r\n presence: {\r\n since: options.presence?.since ?? null,\r\n activities: options.presence?.activities ?? [],\r\n status: options.presence?.status ?? \"online\",\r\n afk: Boolean(options.presence?.afk),\r\n },\r\n shard: [options.shardId, options.shardCount],\r\n },\r\n s: null,\r\n t: null,\r\n };\r\n}\r\n\r\n/** Builds a RESUME payload from the session's resume material. */\r\nexport function resumePayload(\r\n token: string,\r\n resume: ResumeInfo,\r\n): GatewayPayload {\r\n return {\r\n op: GatewayOpcodes.Resume,\r\n d: {\r\n token,\r\n session_id: resume.sessionId,\r\n seq: resume.sequence,\r\n },\r\n s: null,\r\n t: null,\r\n };\r\n}\r\n\r\n/** Builds a heartbeat payload carrying the last sequence seen. */\r\nexport function heartbeatPayload(sequence: number | null): GatewayPayload {\r\n return { op: GatewayOpcodes.Heartbeat, d: sequence, s: null, t: null };\r\n}\r\n",
|
|
46
|
+
"/** Gateway connection lifecycle states. */\r\nexport enum GatewayState {\r\n /** Initial connection state. */\r\n Connect = \"CONNECT\",\r\n /** Gateway HELLO received state. */\r\n Hello = \"HELLO\",\r\n /** IDENTIFY operation in progress. */\r\n Identify = \"IDENTIFY\",\r\n /** RESUME operation in progress. */\r\n Resume = \"RESUME\",\r\n /** Gateway READY state. */\r\n Ready = \"READY\",\r\n /** Gateway dispatch processing state. */\r\n Dispatch = \"DISPATCH\",\r\n /** Heartbeat processing state. */\r\n Heartbeat = \"HEARTBEAT\",\r\n /** Reconnect in progress. */\r\n Reconnect = \"RECONNECT\",\r\n /** Gateway is permanently closed. */\r\n Closed = \"CLOSED\",\r\n}\r\n/**\r\n * Discord.js-familiar alias for {@link GatewayState}.\r\n *\r\n * Discord.js exposes connection status via a `Status` enum. Lunibee's canonical\r\n * name is {@link GatewayState}; this is an additive alias so `discord.js` users\r\n * find the expected name. Note the *values* remain Lunibee's string states\r\n * (e.g. `\"READY\"`), not Discord.js's numeric `Status` members — an intentional\r\n * divergence documented in the compatibility matrix.\r\n */\r\nexport { GatewayState as Status };\r\n/** Gateway protocol error. */\r\nexport class GatewayError extends Error {\r\n /** Gateway close/error code. */\r\n public readonly code?: number;\r\n /** Creates a Gateway error. @param message Error message. @param code Optional Gateway code. @param options Optional error metadata. */\r\n public constructor(message: string, code?: number, options?: ErrorOptions) {\r\n super(message, options);\r\n this.name = \"GatewayError\";\r\n this.code = code;\r\n }\r\n}\r\n",
|
|
47
|
+
"/**\r\n * Sliding-window budget for outgoing Gateway payloads.\r\n *\r\n * Discord allows 120 sends per 60 seconds. Application traffic is capped at\r\n * 115 so the remaining headroom is reserved for privileged sends (heartbeats),\r\n * which are still recorded so the true total stays under Discord's limit.\r\n */\r\nexport class SendBudget {\r\n readonly #timestamps: number[] = [];\r\n readonly #limit: number;\r\n readonly #windowMs: number;\r\n\r\n public constructor(limit = 115, windowMs = 60_000) {\r\n this.#limit = limit;\r\n this.#windowMs = windowMs;\r\n }\r\n\r\n /** Sends recorded within the current window. */\r\n public get used(): number {\r\n return this.#timestamps.length;\r\n }\r\n\r\n /** Whether a send may go out now. Privileged sends always may. */\r\n public allows(privileged: boolean, now = Date.now()): boolean {\r\n while (\r\n this.#timestamps.length &&\r\n now - this.#timestamps[0]! >= this.#windowMs\r\n )\r\n this.#timestamps.shift();\r\n return privileged || this.#timestamps.length < this.#limit;\r\n }\r\n\r\n /** Records a send that went out. */\r\n public record(now = Date.now()): void {\r\n this.#timestamps.push(now);\r\n }\r\n}\r\n",
|
|
48
|
+
"import { GatewaySession } from \"./session.js\";\r\nimport { GatewayHeartbeat, type HeartbeatTimeout } from \"./heartbeat.js\";\r\nimport { GatewayCloseCodes } from \"./close-codes.js\";\r\nimport { GatewayReconnect, type CloseAction } from \"./reconnect.js\";\r\nimport { WebSocketTransport, type SocketFactory } from \"./transport.js\";\r\nimport { GatewayOpcodes } from \"./opcodes.js\";\r\nimport {\r\n classifyFrame,\r\n identifyPayload,\r\n resumePayload,\r\n heartbeatPayload,\r\n type GatewayAction,\r\n} from \"./protocol.js\";\r\nimport {\r\n resolveGatewayIntents,\r\n type GatewayPayload,\r\n type GatewayProperties,\r\n type GatewayPresence,\r\n type GatewayIntentResolvable,\r\n} from \"@lunibee/types\";\r\n\r\nexport {\r\n classifyFrame,\r\n classifyPayload,\r\n identifyPayload,\r\n resumePayload,\r\n heartbeatPayload,\r\n type GatewayAction,\r\n type ProtocolResult,\r\n type ProtocolViolation,\r\n type IdentifyOptions,\r\n type IdentifyProperties,\r\n type IdentifyData,\r\n} from \"./protocol.js\";\r\n\r\nexport {\r\n WebSocketTransport,\r\n type TransportHandlers,\r\n type TransportOptions,\r\n type SocketFactory,\r\n} from \"./transport.js\";\r\n\r\nexport {\r\n createDecoder,\r\n PlainTextDecoder,\r\n ZlibStreamDecoder,\r\n type GatewayDecoder,\r\n} from \"./decoder.js\";\r\n\r\nexport {\r\n GatewayReconnect,\r\n classifyCloseCode,\r\n FATAL_CLOSE_CODES,\r\n IDENTIFY_CLOSE_CODES,\r\n type CloseAction,\r\n type ReconnectOptions,\r\n type ScheduleResult,\r\n type ScheduleRefusal,\r\n} from \"./reconnect.js\";\r\n\r\nexport {\r\n GatewayHeartbeat,\r\n type HeartbeatOptions,\r\n type HeartbeatTimeout,\r\n} from \"./heartbeat.js\";\r\n\r\nexport {\r\n GatewaySession,\r\n type ResumeInfo,\r\n type HandshakeIntent,\r\n type InvalidationReason,\r\n} from \"./session.js\";\r\n\r\nexport { GatewayOpcodes } from \"./opcodes.js\";\r\n\r\nexport { GatewayCloseCodes } from \"./close-codes.js\";\r\n\r\nexport { GatewayState, Status, GatewayError } from \"./state.js\";\r\nimport { GatewayState, GatewayError } from \"./state.js\";\r\nimport { SendBudget } from \"./send-budget.js\";\r\n/** Gateway connection configuration. */\r\nexport interface GatewayOptions {\r\n /** Authentication token. */\r\n token: string;\r\n /** Gateway intent bitfield or resolvable. */\r\n intents: GatewayIntentResolvable;\r\n /** Shard identifier. */\r\n shardId?: number;\r\n /** Total shard count. */\r\n shardCount?: number;\r\n /** Whether automatic reconnect is enabled. */\r\n reconnect?: boolean;\r\n /** Maximum reconnect attempts. */\r\n maxReconnectAttempts?: number;\r\n /** Initial reconnect delay. */\r\n reconnectBaseDelay?: number;\r\n /** Maximum reconnect delay. */\r\n reconnectMaxDelay?: number;\r\n /** Heartbeat acknowledgement timeout. */\r\n heartbeatAckTimeout?: number;\r\n /** Zombie connection timeout. */\r\n zombieTimeout?: number;\r\n /** Identification properties. */\r\n properties?: GatewayProperties;\r\n /** Presence data. */\r\n presence?: GatewayPresence;\r\n /**\r\n * Whether to enable zlib-stream transport compression.\r\n * Decoded with a persistent `node:zlib` inflate stream, matching\r\n * Discord's zlib-wrapped stream framing (`Z_SYNC_FLUSH` boundaries).\r\n * When enabled, appends `&compress=zlib-stream` to the Gateway URL.\r\n */\r\n compress?: boolean;\r\n /**\r\n * Constructs the underlying socket. Defaults to the ambient `WebSocket`.\r\n * Injected to run the Gateway on an alternative transport, or on a stub.\r\n */\r\n createSocket?: SocketFactory;\r\n}\r\n/** Discord's main Gateway endpoint, used when no resume host is known. */\r\n/**\r\n * Close code for connections Lunibee means to RESUME. Discord invalidates the\r\n * session when a client closes with 1000 or 1001, so a reconnect that should\r\n * keep its session must close with anything else.\r\n */\r\nconst RESUMABLE_CLOSE_CODE = 4900;\r\nconst DEFAULT_GATEWAY_URL = \"wss://gateway.discord.gg/?v=10&encoding=json\";\r\n\r\n/** Gateway event listener. */\r\ntype GatewayListener = (data: unknown) => unknown;\r\n/** Manages a Discord Gateway connection. */\r\nexport class Gateway {\r\n /** Current Gateway lifecycle state. */\r\n public state: GatewayState = GatewayState.Connect;\r\n #options: Required<\r\n Omit<\r\n GatewayOptions,\r\n \"properties\" | \"presence\" | \"compress\" | \"createSocket\" | \"intents\"\r\n >\r\n > & {\r\n /** Resolved intent bitfield, never the resolvable form. */\r\n intents: number;\r\n properties?: GatewayProperties;\r\n presence?: GatewayPresence;\r\n compress?: boolean;\r\n };\r\n /**\r\n * The socket this connection runs on.\r\n *\r\n * The Gateway never touches a `WebSocket` directly: construction, listener\r\n * wiring, replacement and decoding all belong to the transport.\r\n */\r\n readonly #transport: WebSocketTransport;\r\n /**\r\n * Session identity and the IDENTIFY-vs-RESUME decision.\r\n *\r\n * The Gateway holds no session fields of its own: every read and write goes\r\n * through the session, which rejects mutations from a superseded socket.\r\n */\r\n readonly #session = new GatewaySession();\r\n /** Token of the socket this Gateway currently owns. */\r\n #token = 0;\r\n /**\r\n * Heartbeat, acknowledgement deadline and staleness watch.\r\n *\r\n * The Gateway holds no heartbeat timers of its own; it supplies the socket\r\n * and decides what to close when liveness fails.\r\n */\r\n readonly #heartbeat: GatewayHeartbeat;\r\n #closed = false;\r\n /**\r\n * Close classification, backoff, scheduling, and the coordination that\r\n * keeps at most one logical connection attempt in flight.\r\n */\r\n readonly #reconnect: GatewayReconnect;\r\n readonly #listeners = new Map<string, Set<GatewayListener>>();\r\n /** Application send budget under Discord's 120-per-60s limit. */\r\n readonly #sendBudget = new SendBudget();\r\n public ping: number = -1;\r\n /** Creates a Gateway connection manager. @param options Gateway configuration. @throws {TypeError|RangeError} If configuration is invalid. */\r\n public constructor(options: GatewayOptions) {\r\n if (!options.token?.trim())\r\n throw new TypeError(\"A Gateway token is required.\");\r\n const resolvedIntents = resolveGatewayIntents(options.intents);\r\n if (!Number.isInteger(resolvedIntents) || resolvedIntents < 0)\r\n throw new TypeError(\r\n \"Gateway intents must be a non-negative integer.\",\r\n );\r\n this.#options = {\r\n shardId: 0,\r\n shardCount: 1,\r\n reconnect: true,\r\n maxReconnectAttempts: Infinity,\r\n reconnectBaseDelay: 1000,\r\n reconnectMaxDelay: 30000,\r\n heartbeatAckTimeout: 10000,\r\n zombieTimeout: 30000,\r\n // Lunibee identifies as itself, not as an official Discord client.\r\n properties: {\r\n os: process.platform,\r\n browser: \"Lunibee\",\r\n device: \"Lunibee\",\r\n },\r\n presence: {\r\n status: \"online\",\r\n activities: [],\r\n afk: false,\r\n since: null,\r\n },\r\n ...options,\r\n // Store the *resolved* bitfield, not the resolvable the caller\r\n // passed. IDENTIFY must carry a number: sending the array or\r\n // string form verbatim makes Discord answer 4013 (invalid\r\n // intents), which is a fatal close — so the documented array form\r\n // would never connect.\r\n intents: resolvedIntents,\r\n };\r\n if (\r\n this.#options.shardId < 0 ||\r\n this.#options.shardId >= this.#options.shardCount\r\n )\r\n throw new RangeError(\r\n \"Gateway shardId must be within the configured shard count.\",\r\n );\r\n if (this.#options.zombieTimeout <= this.#options.heartbeatAckTimeout)\r\n throw new RangeError(\r\n \"Gateway zombieTimeout must be greater than heartbeatAckTimeout\",\r\n );\r\n this.#transport = new WebSocketTransport({\r\n compress: this.#options.compress,\r\n createSocket: options.createSocket,\r\n handlers: {\r\n onOpen: () => this.#onOpen(),\r\n onFrame: (raw) => this.#message(raw, this.#token),\r\n onClose: (code) => this.#close(code, this.#token),\r\n // Transport failures reach consumers as GatewayError, the\r\n // type every other Gateway error path already uses.\r\n onError: (error) =>\r\n this.#emitError(\r\n error instanceof GatewayError\r\n ? error\r\n : new GatewayError(error.message, undefined, {\r\n cause: error,\r\n }),\r\n ),\r\n },\r\n });\r\n this.#reconnect = new GatewayReconnect({\r\n enabled: this.#options.reconnect,\r\n maxAttempts: this.#options.maxReconnectAttempts,\r\n baseDelay: this.#options.reconnectBaseDelay,\r\n maxDelay: this.#options.reconnectMaxDelay,\r\n });\r\n this.#heartbeat = new GatewayHeartbeat({\r\n ackTimeout: this.#options.heartbeatAckTimeout,\r\n zombieTimeout: this.#options.zombieTimeout,\r\n // Heartbeats are privileged: application traffic must never starve\r\n // the one payload that keeps the connection alive.\r\n send: (sequence) =>\r\n this.#dispatch(heartbeatPayload(sequence), true),\r\n sequence: () => this.#session.sequence,\r\n isConnected: () => !this.#closed && this.#transport.connected,\r\n onTimeout: (timeout) => this.#onHeartbeatTimeout(timeout),\r\n onError: (error) => this.#emitError(error),\r\n });\r\n }\r\n\r\n /**\r\n * Closes a connection that failed a liveness check.\r\n *\r\n * The heartbeat decides *that* the connection is dead; the Gateway decides\r\n * what to do about it, because only the Gateway owns the socket.\r\n */\r\n #onHeartbeatTimeout(timeout: HeartbeatTimeout): void {\r\n if (timeout.type === \"zombie\") {\r\n this.#emit(\"zombie\", {\r\n silentFor: timeout.silentFor,\r\n timeout: timeout.deadline,\r\n });\r\n this.#emitError(\r\n new GatewayError(\r\n `Gateway connection appears stale after ${timeout.silentFor}ms without traffic.`,\r\n ),\r\n );\r\n } else {\r\n this.#emitError(\r\n new GatewayError(\r\n `Gateway heartbeat acknowledgement timed out after ${timeout.elapsedMs}ms.`,\r\n ),\r\n );\r\n }\r\n this.#transport.close(\r\n RESUMABLE_CLOSE_CODE,\r\n timeout.type === \"zombie\"\r\n ? \"Zombie Gateway connection\"\r\n : \"Heartbeat timeout\",\r\n );\r\n }\r\n\r\n /** Opens the Gateway connection. @param url Gateway WebSocket URL. @returns Promise fulfilled when the socket opens. @throws {GatewayError} If permanently closed or unable to connect. */\r\n public connect(url = DEFAULT_GATEWAY_URL): Promise<void> {\r\n if (this.state === GatewayState.Closed)\r\n throw new GatewayError(\"Gateway has been permanently closed.\");\r\n // At most one logical connection attempt is active: concurrent callers\r\n // join the in-flight attempt rather than opening competing sockets.\r\n const inFlight = this.#reconnect.attemptPromise;\r\n if (inFlight) return inFlight;\r\n // Connecting an already-live Gateway must be a no-op. Opening a second\r\n // socket leaves the first one unmanaged but still dispatching, which\r\n // interleaves two sequence streams (corrupting a later RESUME) and\r\n // sends a second IDENTIFY on the same session.\r\n if (this.#transport.live) return Promise.resolve();\r\n // A manual connect supersedes a scheduled reconnect; leaving the timer\r\n // armed would open a second socket once it fires.\r\n this.#reconnect.cancel();\r\n this.#closed = false;\r\n this.#setState(GatewayState.Connect);\r\n // Append compression parameter if enabled\r\n const connectURL = this.#options.compress\r\n ? url.includes(\"compress=\")\r\n ? url\r\n : `${url}&compress=zlib-stream`\r\n : url;\r\n return this.#reconnect.attempt(() => this.#open(connectURL));\r\n }\r\n /** Permanently closes the Gateway connection. */\r\n public close(): void {\r\n this.#closed = true;\r\n this.#clearTimers();\r\n this.#settleConnect(\r\n new GatewayError(\"Gateway connection closed before socket open.\"),\r\n );\r\n // Abandon rather than close-and-listen: the Gateway has already decided\r\n // the connection is over and must not be woken by its close event.\r\n this.#transport.destroy(1000, \"Client closed connection\");\r\n this.#setState(GatewayState.Closed);\r\n }\r\n /** Registers a Gateway event listener. @param event Event name. @param listener Event callback. @returns This Gateway. */\r\n /** Emits an event to all registered listeners. @param event Event name. @param data Event payload. */\r\n public emit(event: string, data?: unknown): void {\r\n this.#emit(event, data);\r\n }\r\n public on(event: string, listener: GatewayListener): this {\r\n if (!event || typeof listener !== \"function\")\r\n throw new TypeError(\"Gateway event and listener are required.\");\r\n let listeners = this.#listeners.get(event);\r\n if (!listeners) this.#listeners.set(event, (listeners = new Set()));\r\n listeners.add(listener);\r\n return this;\r\n }\r\n /** Removes a Gateway event listener. @param event Event name. @param listener Event callback. @returns This Gateway. */\r\n public off(event: string, listener: GatewayListener): this {\r\n this.#listeners.get(event)?.delete(listener);\r\n return this;\r\n }\r\n /** Sends a Gateway payload. @param payload Gateway payload. @returns Whether it was sent. */\r\n public send(payload: GatewayPayload): boolean {\r\n if (!payload || !Number.isInteger(payload.op))\r\n throw new TypeError(\r\n \"Gateway payload must contain an integer opcode.\",\r\n );\r\n return this.#dispatch(payload, false);\r\n }\r\n /**\r\n * Writes a payload to the socket. Heartbeats pass `privileged` so they are\r\n * never starved by application traffic: the 115 budget sits below\r\n * Discord's real 120/60s limit precisely to leave room for them, so\r\n * spending that headroom on heartbeats is what it is reserved for. They\r\n * are still recorded, keeping the true total under Discord's limit.\r\n */\r\n #dispatch(payload: GatewayPayload, privileged: boolean): boolean {\r\n if (!this.#transport.connected) return false;\r\n const now = Date.now();\r\n if (!this.#sendBudget.allows(privileged, now)) {\r\n this.#emitError(\r\n new GatewayError(\"Gateway send rate budget exhausted.\"),\r\n );\r\n return false;\r\n }\r\n if (!this.#transport.send(JSON.stringify(payload))) return false;\r\n this.#sendBudget.record(now);\r\n return true;\r\n }\r\n /** Sends a presence update. @param data Presence payload. @returns Whether it was sent. */\r\n public setPresence(data: GatewayPresence): boolean {\r\n this.#options.presence = { ...this.#options.presence, ...data };\r\n const payload = {\r\n since: this.#options.presence.since ?? null,\r\n activities: this.#options.presence.activities ?? [],\r\n status: this.#options.presence.status ?? \"online\",\r\n afk: Boolean(this.#options.presence.afk),\r\n };\r\n return this.send({\r\n op: GatewayOpcodes.PresenceUpdate,\r\n d: payload,\r\n s: null,\r\n t: null,\r\n });\r\n }\r\n /** Sends a voice state update. @param data Voice state payload. @returns Whether it was sent. */\r\n public setVoiceState(data: Record<string, unknown>): boolean {\r\n return this.send({\r\n op: GatewayOpcodes.VoiceStateUpdate,\r\n d: data,\r\n s: null,\r\n t: null,\r\n });\r\n }\r\n /** Requests guild members. @param data Guild member request payload. @returns Whether it was sent. */\r\n public requestGuildMembers(data: Record<string, unknown>): boolean {\r\n return this.send({\r\n op: GatewayOpcodes.RequestGuildMembers,\r\n d: data,\r\n s: null,\r\n t: null,\r\n });\r\n }\r\n /**\r\n * Starts one connection attempt.\r\n *\r\n * Ownership of the session moves to this attempt before the socket exists,\r\n * so a frame from the socket being replaced can never be mistaken for one\r\n * belonging to this connection.\r\n */\r\n #open(url: string): void {\r\n if (this.#closed) return;\r\n this.#token = this.#session.beginConnection();\r\n const result = this.#transport.connect(url);\r\n if (result.ok) return;\r\n // The socket could not be constructed. The caller's attempt fails with\r\n // the underlying reason, so a thrown GatewayError keeps its message.\r\n const failure = this.#normalizeError(result.error);\r\n this.#emitError(failure);\r\n if (this.#options.reconnect) {\r\n this.#setState(GatewayState.Reconnect);\r\n this.#scheduleReconnect();\r\n } else {\r\n this.#settleConnect(failure);\r\n }\r\n }\r\n #onOpen(): void {\r\n // Watch for silence from the moment the socket opens: a connection\r\n // that never reaches HELLO must still be detected as dead.\r\n this.#heartbeat.watch();\r\n this.#emit(\"open\", undefined);\r\n this.#settleConnect();\r\n }\r\n #message(raw: string, token: number): void {\r\n // The transport already drops frames from a replaced socket; this\r\n // second check keeps the session authoritative about who may mutate it.\r\n if (!this.#session.owns(token)) return;\r\n // Any frame from the current socket proves it is alive. Without this the\r\n // silence clock only moved on open, so every healthy connection was\r\n // declared a zombie once the staleness deadline passed.\r\n this.#heartbeat.receivedMessage();\r\n const { sequence, action } = classifyFrame(raw);\r\n // Record before acting: a RESUME must never be built from a sequence\r\n // the connection has not actually observed. The session ignores a\r\n // sequence from a superseded connection.\r\n if (sequence !== null) this.#session.recordSequence(sequence, token);\r\n this.#apply(action, token);\r\n }\r\n /**\r\n * Performs what the protocol says a frame meant.\r\n *\r\n * Every branch is an operation the protocol layer deliberately cannot do\r\n * for itself: closing a socket, mutating the session, running timers,\r\n * emitting events.\r\n */\r\n #apply(action: GatewayAction, token: number): void {\r\n switch (action.type) {\r\n case \"dispatch\":\r\n this.#setState(GatewayState.Dispatch);\r\n this.#handleDispatch(action.event, action.data, token);\r\n return;\r\n case \"hello\":\r\n this.#handleHello(action.heartbeatInterval);\r\n return;\r\n case \"heartbeat\":\r\n this.#setState(GatewayState.Heartbeat);\r\n this.#heartbeat.sendHeartbeat();\r\n return;\r\n case \"heartbeat-ack\":\r\n this.#heartbeat.acknowledge();\r\n this.ping = this.#heartbeat.latency;\r\n this.#emit(\"heartbeatAck\", action.data);\r\n return;\r\n case \"reconnect\":\r\n this.#transport.close(\r\n RESUMABLE_CLOSE_CODE,\r\n \"Server requested reconnect\",\r\n );\r\n return;\r\n case \"invalid-session\": {\r\n // A resumable invalidation keeps the session; a non-resumable\r\n // one destroys it, so the next connection must IDENTIFY.\r\n if (!action.resumable)\r\n this.#session.invalidate(token, \"invalid-session\");\r\n this.#emit(\"invalidSession\", action.resumable);\r\n this.#transport.close(\r\n action.resumable ? GatewayCloseCodes.UnknownError : 1000,\r\n action.resumable\r\n ? \"Invalid session (resumable)\"\r\n : \"Invalid session\",\r\n );\r\n return;\r\n }\r\n case \"invalid\":\r\n this.#emitError(\r\n new GatewayError(\r\n action.message,\r\n undefined,\r\n action.cause === undefined\r\n ? undefined\r\n : { cause: action.cause },\r\n ),\r\n );\r\n this.#transport.close(\r\n 1002,\r\n action.violation === \"invalid-json\"\r\n ? \"Invalid JSON\"\r\n : action.violation === \"invalid-hello\"\r\n ? \"Invalid heartbeat interval\"\r\n : \"Invalid payload\",\r\n );\r\n return;\r\n case \"unknown\":\r\n // Forward compatibility: Discord may add opcodes, and an\r\n // unfamiliar one is not a failure.\r\n return;\r\n }\r\n }\r\n #handleDispatch(event: string | null, data: unknown, token: number): void {\r\n if (event === \"READY\") {\r\n if (!this.#session.activate(data, token)) {\r\n // Either the payload lacked session information or this socket\r\n // no longer owns the session; only the former is an error.\r\n if (this.#session.owns(token))\r\n this.#emitError(\r\n new GatewayError(\r\n \"Gateway READY payload is missing session information\",\r\n ),\r\n );\r\n return;\r\n }\r\n this.#reconnect.reset();\r\n this.#setState(GatewayState.Ready);\r\n this.#emit(\"ready\", data);\r\n } else if (event === \"RESUMED\") {\r\n // A successful RESUME ends the reconnect cycle just like READY:\r\n // reset the backoff counter so a later disconnect starts from the\r\n // base delay, mark the connection READY, and surface a Discord.js-\r\n // familiar `resumed` event.\r\n this.#reconnect.reset();\r\n this.#setState(GatewayState.Ready);\r\n this.#emit(\"resumed\", data);\r\n }\r\n this.#emit(\"RAW\", { event: event ?? \"UNKNOWN\", data });\r\n if (this.#closed) return;\r\n this.#emit(event ?? \"dispatch\", data);\r\n }\r\n #handleHello(interval: number): void {\r\n this.#setState(\r\n this.#session.canResume ? GatewayState.Resume : GatewayState.Hello,\r\n );\r\n this.#heartbeat.start(interval);\r\n this.#identifyOrResume();\r\n }\r\n #identifyOrResume(): void {\r\n const intent = this.#session.handshake();\r\n // IDENTIFY/RESUME are privileged for the same reason heartbeats are:\r\n // dropping one leaves the shard connected but never READY, recoverable\r\n // only via the zombie timeout. Application traffic must never starve\r\n // the handshake out of the send budget.\r\n if (intent.type === \"resume\") {\r\n this.#setState(GatewayState.Resume);\r\n this.#dispatch(resumePayload(this.#options.token, intent), true);\r\n return;\r\n }\r\n this.#setState(GatewayState.Identify);\r\n this.#dispatch(\r\n identifyPayload({\r\n token: this.#options.token,\r\n intents: this.#options.intents,\r\n shardId: this.#options.shardId,\r\n shardCount: this.#options.shardCount,\r\n properties: this.#options.properties,\r\n presence: this.#options.presence,\r\n }),\r\n true,\r\n );\r\n }\r\n #close(code: number, token: number): void {\r\n this.#clearTimers();\r\n const action: CloseAction = this.#reconnect.classifyClose(\r\n code,\r\n this.#session.canResume,\r\n );\r\n this.#emit(\"close\", { code, action });\r\n if (this.#closed || !this.#reconnect.enabled || action === \"stop\") {\r\n // A fatal close is terminal: the condition behind 4004/4013/4014\r\n // cannot fix itself, so the Gateway settles as CLOSED rather than\r\n // sitting in CONNECT looking like it is about to try again (WS-003).\r\n if (action === \"stop\") this.#closed = true;\r\n this.#setState(\r\n this.#closed ? GatewayState.Closed : GatewayState.Connect,\r\n );\r\n if (this.#reconnect.connecting)\r\n this.#reconnect.settle(\r\n new GatewayError(\r\n `Gateway closed before READY (code ${code}).`,\r\n code,\r\n ),\r\n );\r\n return;\r\n }\r\n if (action === \"identify\")\r\n // Fresh IDENTIFY: drop the session AND its resume host so the\r\n // reconnect targets the main Gateway, not a stale resume URL.\r\n this.#session.invalidate(token, \"session-timeout\");\r\n this.#setState(GatewayState.Reconnect);\r\n this.#scheduleReconnect();\r\n }\r\n #scheduleReconnect(): void {\r\n if (this.#closed) return;\r\n const result = this.#reconnect.schedule(() =>\r\n this.#open(this.#session.connectURL(DEFAULT_GATEWAY_URL)),\r\n );\r\n if (result.scheduled || result.reason !== \"exhausted\") return;\r\n this.#reconnect.settle(\r\n new GatewayError(\"Gateway reconnect attempts exhausted.\"),\r\n );\r\n this.#setState(GatewayState.Connect);\r\n }\r\n #settleConnect(error?: GatewayError): void {\r\n this.#reconnect.settle(error);\r\n }\r\n #clearTimers(): void {\r\n this.#reconnect.cancel();\r\n this.#heartbeat.stop();\r\n }\r\n #normalizeError(error: unknown): GatewayError {\r\n return error instanceof GatewayError\r\n ? error\r\n : new GatewayError(\"Gateway connection failed.\", undefined, {\r\n cause: error,\r\n });\r\n }\r\n #emitError(error: unknown): void {\r\n this.#emit(\r\n \"error\",\r\n error instanceof Error ? error : new GatewayError(String(error)),\r\n );\r\n }\r\n #emit(event: string, data: unknown): void {\r\n for (const listener of this.#listeners.get(event) ?? []) {\r\n try {\r\n const result = listener(data);\r\n if (\r\n result &&\r\n typeof (result as PromiseLike<unknown>).then === \"function\"\r\n )\r\n void Promise.resolve(result).catch((error) => {\r\n if (event !== \"error\") this.#emitError(error);\r\n });\r\n } catch (error) {\r\n if (event !== \"error\") this.#emitError(error);\r\n }\r\n }\r\n }\r\n /** Changes the Gateway lifecycle state. @param next Next lifecycle state. */\r\n #setState(next: GatewayState): void {\r\n if (this.state === next) return;\r\n const previous = this.state;\r\n this.state = next;\r\n this.#emit(\"stateChange\", { previous, next });\r\n }\r\n}\r\n",
|
|
49
|
+
"export {\r\n Permission,\r\n Permissions,\r\n PermissionFlagsBits,\r\n PermissionSet,\r\n PermissionsBitField,\r\n PermissionOverwriteEnum,\r\n PermissionOverwriteType,\r\n computePermissions,\r\n type PermissionContext,\r\n type PermissionOverwrite,\r\n type PermissionRole,\r\n type PermissionName,\r\n} from \"./permissions.js\";\r\nexport {\r\n ClientEvent,\r\n /** Discord.js-familiar alias for {@link ClientEvent}. */\r\n ClientEvent as Events,\r\n type ClientEventName,\r\n type ClientEvents,\r\n type ClientListener,\r\n} from \"./events.js\";\r\nexport { Collector, type CollectorOptions } from \"./collector.js\";\r\nexport {\r\n GatewayIntentBits,\r\n IntentBits,\r\n Intents,\r\n IntentsBitField,\r\n resolveGatewayIntents,\r\n type GatewayIntentResolvable,\r\n} from \"@lunibee/types\";\r\n\r\nimport {\r\n ApplicationCommandManager,\r\n ChannelManager,\r\n GuildManager,\r\n MonetizationManager,\r\n StageInstanceManager,\r\n UserManager,\r\n toRequest,\r\n} from \"@lunibee/managers\";\r\nimport { REST, Routes } from \"@lunibee/rest\";\r\nimport {\r\n User,\r\n GuildMember,\r\n Role,\r\n Emoji,\r\n type Channel,\r\n createChannel,\r\n Message,\r\n createInteraction,\r\n type InteractionClient,\r\n type InteractionData,\r\n type ResourceContext,\r\n} from \"@lunibee/structures\";\r\nimport { Gateway } from \"@lunibee/ws\";\r\nimport type {\r\n APIEntitlement,\r\n APISoundboardSound,\r\n APIChannel,\r\n APIGuild,\r\n APIGuildMember,\r\n APIGuildRoleEvent,\r\n APIGuildRoleDeleteEvent,\r\n APIGuildBanEvent,\r\n APIGuildEmojisUpdateEvent,\r\n APIGuildStickersUpdateEvent,\r\n APIMessageDeleteBulkEvent,\r\n APIMessageDeleteEvent,\r\n APIMessageReactionEvent,\r\n APIMessageReactionRemoveEmojiEvent,\r\n APIReadyEvent,\r\n APIRole,\r\n APIThreadEvent,\r\n APIThreadListSync,\r\n APIThreadMembersUpdate,\r\n APIVoiceState,\r\n APIVoiceServerUpdate,\r\n APIPresenceUpdate,\r\n APITypingStart,\r\n APIInviteCreate,\r\n APIInviteDelete,\r\n APIWebhooksUpdate,\r\n APIAutoModerationRule,\r\n APIAutoModerationActionExecution,\r\n APIGuildScheduledEvent,\r\n APIGuildScheduledEventUserEvent,\r\n APIStageInstance,\r\n APIChannelPinsUpdate,\r\n APIGuildMembersChunk,\r\n APIMessagePollVoteEvent,\r\n ClientOptions,\r\n ClientUser,\r\n} from \"@lunibee/types\";\r\nimport { ClientEvent, type ClientEvents } from \"./events.js\";\r\nimport { Collector, type CollectorOptions } from \"./collector.js\";\r\nimport { computePermissions, PermissionSet } from \"./permissions.js\";\r\n\r\n/** Lifecycle state of a client. */\r\nexport type ClientState = \"idle\" | \"connecting\" | \"ready\" | \"destroyed\";\r\ntype Listener<T extends unknown[]> = (...args: T) => unknown;\r\ntype GuildMemberEvent = APIGuildMember & { guild_id: string };\r\n\r\n/** Minimal typed event emitter used by the client. */\r\nclass EventEmitter<Events extends { [K in keyof Events]: unknown[] }> {\r\n #listeners: { [K in keyof Events]?: Set<Listener<Events[K]>> } = {};\r\n /** Removes secrets from text this emitter prints; the client removes its token. */\r\n protected readonly redactSecrets = (text: string): string => text;\r\n public on<K extends keyof Events>(\r\n event: K,\r\n listener: Listener<Events[K]>,\r\n ): this {\r\n if (typeof listener !== \"function\")\r\n throw new TypeError(\"Event listener must be a function.\");\r\n (this.#listeners[event] ??= new Set()).add(listener);\r\n return this;\r\n }\r\n public once<K extends keyof Events>(\r\n event: K,\r\n listener: Listener<Events[K]>,\r\n ): this {\r\n const wrapped: Listener<Events[K]> = (...args) => {\r\n this.off(event, wrapped);\r\n return listener(...args);\r\n };\r\n return this.on(event, wrapped);\r\n }\r\n public off<K extends keyof Events>(\r\n event: K,\r\n listener: Listener<Events[K]>,\r\n ): this {\r\n this.#listeners[event]?.delete(listener);\r\n return this;\r\n }\r\n /** Alias of {@link off}, provided for Node.js/Discord.js familiarity. */\r\n public removeListener<K extends keyof Events>(\r\n event: K,\r\n listener: Listener<Events[K]>,\r\n ): this {\r\n return this.off(event, listener);\r\n }\r\n public removeAllListeners<K extends keyof Events>(event?: K): this {\r\n if (event === undefined) this.#listeners = {};\r\n else delete this.#listeners[event];\r\n return this;\r\n }\r\n protected emit<K extends keyof Events>(\r\n event: K,\r\n ...args: Events[K]\r\n ): boolean {\r\n const listeners = this.#listeners[event];\r\n if (!listeners?.size) return false;\r\n for (const listener of [...listeners]) {\r\n try {\r\n const result = listener(...args);\r\n if (\r\n result &&\r\n typeof (result as PromiseLike<unknown>).then === \"function\"\r\n )\r\n void Promise.resolve(result).catch((error) =>\r\n this.#handleError(event, error),\r\n );\r\n } catch (error) {\r\n this.#handleError(event, error);\r\n }\r\n }\r\n return true;\r\n }\r\n /** Sends a listener's error to the `error` listeners. When there are none, or\r\n * an `error` listener itself fails, it becomes a process warning instead of\r\n * disappearing (never a new `error` event, so it cannot loop). */\r\n #handleError(event: keyof Events, error: unknown): void {\r\n const normalized =\r\n error instanceof Error\r\n ? error\r\n : new Error(String(error), { cause: error });\r\n // Every emitter in this file declares `error: [Error]`.\r\n const errorListeners = this.#listeners[\r\n ClientEvent.Error as keyof Events\r\n ] as Set<Listener<[Error]>> | undefined;\r\n const listeners =\r\n event === ClientEvent.Error ? [] : [...(errorListeners ?? [])];\r\n if (listeners.length === 0)\r\n return warnListenerError(event, normalized, this.redactSecrets);\r\n for (const listener of listeners) {\r\n try {\r\n const result = listener(normalized);\r\n if (\r\n result &&\r\n typeof (result as PromiseLike<unknown>).then === \"function\"\r\n )\r\n void Promise.resolve(result).catch((failure) =>\r\n warnListenerError(\r\n ClientEvent.Error,\r\n failure,\r\n this.redactSecrets,\r\n ),\r\n );\r\n } catch (failure) {\r\n warnListenerError(\r\n ClientEvent.Error,\r\n failure,\r\n this.redactSecrets,\r\n );\r\n }\r\n }\r\n }\r\n}\r\n\r\n/** Reports an error no listener handled as a process warning (stderr by default), with secrets removed. */\r\nfunction warnListenerError(\r\n event: PropertyKey,\r\n error: unknown,\r\n redact: (text: string) => string = (text) => text,\r\n): void {\r\n const failure = error instanceof Error ? error : new Error(String(error));\r\n process.emitWarning(\r\n redact(\r\n `A \"${String(event)}\" listener threw and no error listener handled it: ${failure.message}`,\r\n ),\r\n {\r\n type: \"LunibeeWarning\",\r\n code: \"LUNIBEE_UNHANDLED_LISTENER_ERROR\",\r\n detail:\r\n failure.stack === undefined ? undefined : redact(failure.stack),\r\n },\r\n );\r\n}\r\n\r\n/** Main Lunibee Discord client. */\r\nexport class Client\r\n extends EventEmitter<ClientEvents>\r\n implements InteractionClient\r\n{\r\n public readonly rest: REST;\r\n public readonly users: UserManager;\r\n public readonly guilds: GuildManager;\r\n public readonly channels: ChannelManager;\r\n /** Stage instances, cached by stage channel ID. */\r\n public readonly stageInstances: StageInstanceManager;\r\n public readonly application: { commands: ApplicationCommandManager };\r\n /** SKUs, entitlements and subscriptions; available after READY (application ID known). */\r\n public monetization?: MonetizationManager;\r\n public get ws(): Gateway {\r\n return this.#gateway;\r\n }\r\n public get gateway(): Gateway {\r\n return this.#gateway;\r\n }\r\n public user?: ClientUser;\r\n public readyAt?: Date;\r\n public state: ClientState = \"idle\";\r\n /**\r\n * The bot token this client is authenticated with, or `null` once the\r\n * client has been destroyed. Mirrors `Client#token` in Discord.js.\r\n */\r\n /** Replaces the bot token in text Lunibee prints (listener warnings). */\r\n protected override readonly redactSecrets = (text: string): string => {\r\n const token = this.options.token;\r\n return token && token.length >= 8\r\n ? text.split(token).join(\"[token]\")\r\n : text;\r\n };\r\n public get token(): string | null {\r\n return this.state === \"destroyed\" ? null : (this.options.token ?? null);\r\n }\r\n public get uptime(): number | null {\r\n return this.readyAt ? Date.now() - this.readyAt.getTime() : null;\r\n }\r\n public get ping(): number {\r\n return this.#gateway.ping;\r\n }\r\n /** Whether the client is ready and connected. */\r\n public isReady(): boolean {\r\n return this.state === \"ready\";\r\n }\r\n /** Sets the bot's presence / status. @param data Presence payload. @returns Whether the payload was sent. */\r\n public setPresence(\r\n data: import(\"@lunibee/types\").GatewayPresence,\r\n ): boolean {\r\n return this.#gateway.setPresence(data);\r\n }\r\n /** Sends a voice state update. @param data Voice state payload. @returns Whether it was sent. */\r\n public setVoiceState(data: Record<string, unknown>): boolean {\r\n return this.#gateway.setVoiceState(data);\r\n }\r\n /** Requests guild members. @param data Guild member request payload. @returns Whether it was sent. */\r\n public requestGuildMembers(data: Record<string, unknown>): boolean {\r\n return this.#gateway.requestGuildMembers(data);\r\n }\r\n readonly #gateway: Gateway;\r\n /** Which resources Gateway events are allowed to cache. */\r\n readonly #cache: Required<NonNullable<ClientOptions[\"cache\"]>>;\r\n readonly #resourceContext: ResourceContext;\r\n\r\n public constructor(public readonly options: ClientOptions) {\r\n super();\r\n if (!options.token?.trim())\r\n throw new TypeError(\"Client token is required.\");\r\n this.rest = new REST({ token: options.token, ...options.rest });\r\n this.#cache = {\r\n users: true,\r\n members: true,\r\n roles: true,\r\n emojis: true,\r\n ...options.cache,\r\n };\r\n this.users = new UserManager(this.rest);\r\n this.guilds = new GuildManager(this.rest);\r\n this.channels = new ChannelManager(this.rest, {\r\n messageCache: options.messageCache,\r\n allowedMentions: options.allowedMentions,\r\n });\r\n this.stageInstances = new StageInstanceManager(this.rest);\r\n const placeholderAppCommands = new ApplicationCommandManager(\r\n this.rest,\r\n \"0\",\r\n );\r\n this.application = { commands: placeholderAppCommands };\r\n this.#resourceContext = this.#createResourceContext();\r\n this.guilds.attachContext(this.#resourceContext);\r\n this.#gateway = new Gateway({\r\n token: options.token,\r\n intents: options.intents,\r\n ...options.gateway,\r\n });\r\n\r\n this.#wireLifecycle();\r\n this.#wireMessages();\r\n this.#wireGuilds();\r\n this.#wireGuildFeatures();\r\n this.#wireChannels();\r\n this.#wireMisc();\r\n }\r\n\r\n /** Callbacks structures use to act through this client (send, edit, kick...). */\r\n #createResourceContext(): ResourceContext {\r\n return {\r\n sendMessage: (channelId, options) =>\r\n this.channels.send(channelId, options),\r\n editMessage: (channelId, messageId, options) =>\r\n this.channels.editMessage(channelId, messageId, options),\r\n deleteMessage: (channelId, messageId, reason) =>\r\n this.channels.deleteMessage(channelId, messageId, reason),\r\n crosspostMessage: (channelId, messageId) =>\r\n this.channels.crosspostMessage(channelId, messageId),\r\n editChannel: (channelId, options) =>\r\n this.channels.edit(channelId, options),\r\n deleteChannel: (channelId, reason) =>\r\n this.channels.remove(channelId, reason),\r\n addReaction: (channelId, messageId, emoji) =>\r\n this.channels.addReaction(channelId, messageId, emoji),\r\n removeOwnReaction: (channelId, messageId, emoji) =>\r\n this.channels.removeOwnReaction(channelId, messageId, emoji),\r\n removeReaction: (channelId, messageId, emoji, userId) =>\r\n this.channels.removeReaction(\r\n channelId,\r\n messageId,\r\n emoji,\r\n userId,\r\n ),\r\n removeAllReactions: (channelId, messageId) =>\r\n this.channels.removeAllReactions(channelId, messageId),\r\n pinMessage: (channelId, messageId, reason) =>\r\n this.channels.pinMessage(channelId, messageId, reason),\r\n unpinMessage: (channelId, messageId, reason) =>\r\n this.channels.unpinMessage(channelId, messageId, reason),\r\n collectInteractions: (options) =>\r\n this.createCollector(ClientEvent.InteractionCreate, options),\r\n memberPermissions: (\r\n guildId,\r\n memberId,\r\n roleIds,\r\n channelId,\r\n timedOutUntil,\r\n ) =>\r\n this.#memberPermissions(\r\n guildId,\r\n memberId,\r\n roleIds,\r\n channelId,\r\n timedOutUntil,\r\n ),\r\n kickMember: (guildId, userId, reason) =>\r\n this.guilds.members(guildId).kick(userId, reason),\r\n banMember: (guildId, userId, options) =>\r\n this.guilds.members(guildId).ban(userId, options),\r\n editMember: (guildId, userId, options, reason) =>\r\n this.guilds.members(guildId).edit(userId, options, reason),\r\n addMemberRole: (guildId, userId, roleId, reason) =>\r\n this.guilds.members(guildId).addRole(userId, roleId, reason),\r\n removeMemberRole: (guildId, userId, roleId, reason) =>\r\n this.guilds.members(guildId).removeRole(userId, roleId, reason),\r\n editPermissionOverwrite: async (\r\n channelId,\r\n targetId,\r\n changes,\r\n options,\r\n ) => {\r\n const bits = { allow: 0n, deny: 0n, inherit: 0n };\r\n for (const [name, value] of Object.entries(changes)) {\r\n // Names only: a number or bit string here is a mistake, not a permission.\r\n if (!/^[A-Za-z]+$/.test(name))\r\n throw new TypeError(`Unknown permission: ${name}`);\r\n let bit: bigint;\r\n try {\r\n bit = new PermissionSet(name).bitfield;\r\n } catch {\r\n throw new TypeError(`Unknown permission: ${name}`);\r\n }\r\n const key =\r\n value === true\r\n ? \"allow\"\r\n : value === false\r\n ? \"deny\"\r\n : \"inherit\";\r\n bits[key] |= bit;\r\n }\r\n return this.channels\r\n .permissionOverwrites(channelId)\r\n .update(targetId, bits, options);\r\n },\r\n };\r\n }\r\n\r\n /** Session lifecycle: ready, resume, open and close. */\r\n #wireLifecycle(): void {\r\n // ── Lifecycle ────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"READY\", (data) => {\r\n const ready = data as APIReadyEvent;\r\n this.user = ready.user;\r\n this.users.set(this.user.id, new User(this.user));\r\n this.readyAt = new Date();\r\n this.state = \"ready\";\r\n const appId = ready.application?.id ?? this.user.id;\r\n (\r\n this.application as { commands: ApplicationCommandManager }\r\n ).commands = new ApplicationCommandManager(this.rest, appId);\r\n if (this.monetization?.applicationId !== appId)\r\n this.monetization = new MonetizationManager(this.rest, appId);\r\n this.emit(ClientEvent.Ready, this.user);\r\n });\r\n this.#gateway.on(\"RESUMED\", () => {\r\n this.state = \"ready\";\r\n this.emit(ClientEvent.Resumed);\r\n });\r\n this.#gateway.on(\"invalidSession\", (isRecoverable) => {\r\n this.emit(ClientEvent.InvalidSession, isRecoverable as boolean);\r\n });\r\n this.#gateway.on(\"open\", () => this.emit(ClientEvent.Open));\r\n this.#gateway.on(\"close\", (data) => {\r\n if (this.state !== \"destroyed\") this.state = \"idle\";\r\n this.emit(\r\n ClientEvent.Close,\r\n data as { code: number; action: string },\r\n );\r\n });\r\n }\r\n\r\n /** Messages, reactions and polls. */\r\n #wireMessages(): void {\r\n // ── Messages ─────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"MESSAGE_CREATE\", (data) => {\r\n const payload = data as import(\"@lunibee/types\").APIMessage;\r\n const message = new Message(payload, this.#resourceContext);\r\n this.#observeMessage(message);\r\n // The author's member (roles, nickname) comes with every guild\r\n // message; keep the cached member current with it.\r\n if (\r\n payload.member &&\r\n payload.guild_id &&\r\n this.guilds.has(payload.guild_id)\r\n )\r\n this.#upsertMember(payload.guild_id, {\r\n ...payload.member,\r\n user: payload.member.user ?? payload.author,\r\n } as APIGuildMember);\r\n // With messageCache enabled, Gateway messages enter the bounded\r\n // cache so later edits and deletes can see the previous content;\r\n // listeners get the cached instance.\r\n const cached = this.options.messageCache\r\n ? this.channels\r\n .messages(message.channelId)\r\n .upsert(data as import(\"@lunibee/types\").APIMessage)\r\n : message;\r\n this.emit(ClientEvent.MessageCreate, cached);\r\n });\r\n this.#gateway.on(\"MESSAGE_UPDATE\", (data) => {\r\n const message = new Message(\r\n data as import(\"@lunibee/types\").APIMessage,\r\n this.#resourceContext,\r\n );\r\n this.#observeMessage(message);\r\n // The cached message is replaced, not merged, so listeners receive\r\n // the previous version intact alongside the new one.\r\n const messages = this.channels.cachedMessages(message.channelId);\r\n const previous = messages?.cache.peek(message.id);\r\n if (previous) messages!.cache.set(message.id, message);\r\n this.emit(ClientEvent.MessageUpdate, message, previous);\r\n });\r\n this.#gateway.on(\"MESSAGE_DELETE\", (data) => {\r\n const payload = data as APIMessageDeleteEvent;\r\n const messages = this.channels.cachedMessages(payload.channel_id);\r\n const removed = messages?.cache.peek(payload.id);\r\n messages?.delete(payload.id);\r\n this.emit(ClientEvent.MessageDelete, payload, removed);\r\n });\r\n this.#gateway.on(\"MESSAGE_DELETE_BULK\", (data) => {\r\n const payload = data as APIMessageDeleteBulkEvent;\r\n const messages = this.channels.cachedMessages(payload.channel_id);\r\n const removed: Message[] = [];\r\n if (messages)\r\n for (const id of payload.ids) {\r\n const message = messages.cache.peek(id);\r\n if (message) removed.push(message);\r\n messages.delete(id);\r\n }\r\n this.emit(ClientEvent.MessageDeleteBulk, payload, removed);\r\n });\r\n\r\n // ── Reactions ────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"MESSAGE_REACTION_ADD\", (data) =>\r\n this.emit(\r\n ClientEvent.MessageReactionAdd,\r\n data as APIMessageReactionEvent,\r\n ),\r\n );\r\n this.#gateway.on(\"MESSAGE_REACTION_REMOVE\", (data) =>\r\n this.emit(\r\n ClientEvent.MessageReactionRemove,\r\n data as APIMessageReactionEvent,\r\n ),\r\n );\r\n this.#gateway.on(\"MESSAGE_REACTION_REMOVE_ALL\", (data) =>\r\n this.emit(\r\n ClientEvent.MessageReactionRemoveAll,\r\n data as APIMessageDeleteEvent,\r\n ),\r\n );\r\n this.#gateway.on(\"MESSAGE_REACTION_REMOVE_EMOJI\", (data) =>\r\n this.emit(\r\n ClientEvent.MessageReactionRemoveEmoji,\r\n data as APIMessageReactionRemoveEmojiEvent,\r\n ),\r\n );\r\n\r\n // ── Polls ────────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"MESSAGE_POLL_VOTE_ADD\", (data) =>\r\n this.emit(\r\n ClientEvent.MessagePollVoteAdd,\r\n data as APIMessagePollVoteEvent,\r\n ),\r\n );\r\n this.#gateway.on(\"MESSAGE_POLL_VOTE_REMOVE\", (data) =>\r\n this.emit(\r\n ClientEvent.MessagePollVoteRemove,\r\n data as APIMessagePollVoteEvent,\r\n ),\r\n );\r\n }\r\n\r\n /** Guilds, members, bans and roles. */\r\n #wireGuilds(): void {\r\n // ── Guilds ───────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"GUILD_CREATE\", (data) => {\r\n const payload = data as APIGuild & {\r\n members?: APIGuildMember[];\r\n voice_states?: APIVoiceState[];\r\n channels?: APIChannel[];\r\n threads?: APIChannel[];\r\n unavailable?: boolean;\r\n };\r\n if (payload.unavailable) {\r\n this.emit(ClientEvent.GuildUnavailable, payload);\r\n return;\r\n }\r\n // A guild already in cache that arrives again (e.g. after an outage\r\n // or gateway resume) has become *available* rather than newly joined.\r\n // Mirrors Discord.js' guildAvailable vs. guildCreate distinction.\r\n const wasCached = this.guilds.has(payload.id);\r\n this.guilds.patch(payload);\r\n for (const role of payload.roles ?? [])\r\n this.#upsertRole(payload.id, role);\r\n if (this.#cache.emojis) {\r\n const emojis = this.guilds.emojis(payload.id);\r\n for (const emoji of payload.emojis ?? []) emojis.upsert(emoji);\r\n }\r\n for (const member of payload.members ?? [])\r\n this.#upsertMember(payload.id, member);\r\n for (const state of payload.voice_states ?? [])\r\n this.#storeVoiceState(payload.id, state);\r\n // Channels in GUILD_CREATE omit guild_id; restore it so the\r\n // channel can be cleaned up with its guild.\r\n for (const channelData of [\r\n ...(payload.channels ?? []),\r\n ...(payload.threads ?? []),\r\n ])\r\n this.channels.upsert({ ...channelData, guild_id: payload.id });\r\n this.emit(\r\n wasCached\r\n ? ClientEvent.GuildAvailable\r\n : ClientEvent.GuildCreate,\r\n payload,\r\n );\r\n });\r\n this.#gateway.on(\"GUILD_UPDATE\", (data) => {\r\n const payload = data as APIGuild;\r\n const cached = this.guilds.get(payload.id);\r\n const previous = cached ? this.#snapshot(cached) : null;\r\n this.guilds.patch(payload);\r\n this.emit(ClientEvent.GuildUpdate, payload, previous);\r\n });\r\n this.#gateway.on(\"GUILD_DELETE\", (data) => {\r\n const payload = data as { id: string; unavailable?: boolean };\r\n if (payload.unavailable) {\r\n this.emit(ClientEvent.GuildUnavailable, payload);\r\n return;\r\n }\r\n this.guilds.delete(payload.id);\r\n this.channels.deleteGuildChannels(payload.id);\r\n this.emit(ClientEvent.GuildDelete, payload);\r\n });\r\n\r\n // ── Guild Members ────────────────────────────────────────────────────────\r\n this.#gateway.on(\"GUILD_MEMBER_ADD\", (data) => {\r\n const member = data as GuildMemberEvent;\r\n this.#upsertMember(member.guild_id, member);\r\n this.emit(ClientEvent.GuildMemberAdd, member);\r\n });\r\n this.#gateway.on(\"GUILD_MEMBER_UPDATE\", (data) => {\r\n const member = data as GuildMemberEvent;\r\n const cached = this.#cache.members\r\n ? this.guilds.members(member.guild_id).get(member.user.id)\r\n : undefined;\r\n // A fresh instance keeps the client context (a private field).\r\n const previous = cached\r\n ? this.#snapshot(\r\n cached,\r\n new GuildMember(\r\n { user: member.user, guild_id: member.guild_id },\r\n this.#resourceContext,\r\n ),\r\n )\r\n : null;\r\n this.#upsertMember(member.guild_id, member);\r\n this.emit(ClientEvent.GuildMemberUpdate, member, previous);\r\n });\r\n this.#gateway.on(\"GUILD_MEMBER_REMOVE\", (data) => {\r\n const member = data as GuildMemberEvent;\r\n this.guilds.members(member.guild_id).delete(member.user.id);\r\n this.emit(ClientEvent.GuildMemberRemove, member);\r\n });\r\n this.#gateway.on(\"GUILD_MEMBERS_CHUNK\", (data) => {\r\n const chunk = data as APIGuildMembersChunk;\r\n for (const member of chunk.members)\r\n this.#upsertMember(chunk.guild_id, member);\r\n this.emit(ClientEvent.GuildMembersChunk, chunk);\r\n });\r\n\r\n // ── Guild Bans ───────────────────────────────────────────────────────────\r\n this.#gateway.on(\"GUILD_BAN_ADD\", (data) => {\r\n const ban = data as APIGuildBanEvent;\r\n const bans = this.guilds.bans(ban.guild_id);\r\n // Keep a reason already fetched over REST; the event carries none.\r\n bans.set(ban.user.id, {\r\n reason: bans.get(ban.user.id)?.reason ?? null,\r\n user: ban.user,\r\n });\r\n this.guilds.members(ban.guild_id).delete(ban.user.id);\r\n this.emit(ClientEvent.GuildBanAdd, ban);\r\n });\r\n this.#gateway.on(\"GUILD_BAN_REMOVE\", (data) => {\r\n const ban = data as APIGuildBanEvent;\r\n this.guilds.bans(ban.guild_id).delete(ban.user.id);\r\n this.emit(ClientEvent.GuildBanRemove, ban);\r\n });\r\n\r\n // ── Guild Roles ──────────────────────────────────────────────────────────\r\n this.#gateway.on(\"GUILD_ROLE_CREATE\", (data) => {\r\n const event = data as APIGuildRoleEvent;\r\n this.#upsertRole(event.guild_id, event.role);\r\n this.emit(ClientEvent.GuildRoleCreate, event);\r\n });\r\n this.#gateway.on(\"GUILD_ROLE_UPDATE\", (data) => {\r\n const event = data as APIGuildRoleEvent;\r\n const cached = this.#cache.roles\r\n ? this.guilds.roles(event.guild_id).get(event.role.id)\r\n : undefined;\r\n const previous = cached ? this.#snapshot(cached) : null;\r\n this.#upsertRole(event.guild_id, event.role);\r\n this.emit(ClientEvent.GuildRoleUpdate, event, previous);\r\n });\r\n this.#gateway.on(\"GUILD_ROLE_DELETE\", (data) => {\r\n const event = data as APIGuildRoleDeleteEvent;\r\n const roles = this.guilds.roles(event.guild_id);\r\n const removed = roles.get(event.role_id) ?? null;\r\n roles.delete(event.role_id);\r\n this.emit(ClientEvent.GuildRoleDelete, event, removed);\r\n });\r\n }\r\n\r\n /** Guild emojis, stickers, soundboard, monetization, integrations, scheduled events and AutoMod. */\r\n #wireGuildFeatures(): void {\r\n // ── Guild Emojis & Stickers ──────────────────────────────────────────────\r\n this.#gateway.on(\"GUILD_EMOJIS_UPDATE\", (data) => {\r\n const event = data as APIGuildEmojisUpdateEvent;\r\n let previous: Emoji[] | null = null;\r\n // The event carries the guild's full emoji list.\r\n if (this.#cache.emojis) {\r\n const emojis = this.guilds.emojis(event.guild_id);\r\n previous = [...emojis.cache.values()].map((emoji) =>\r\n this.#snapshot(emoji),\r\n );\r\n const current = new Set(event.emojis.map((emoji) => emoji.id));\r\n for (const id of [...emojis.cache.keys()])\r\n if (!current.has(id)) emojis.delete(id);\r\n for (const emoji of event.emojis) emojis.upsert(emoji);\r\n }\r\n this.emit(ClientEvent.GuildEmojisUpdate, event, previous);\r\n });\r\n this.#gateway.on(\"GUILD_STICKERS_UPDATE\", (data) => {\r\n const event = data as APIGuildStickersUpdateEvent;\r\n // The event carries the guild's full sticker list. `sync` replaces\r\n // the raw objects, so the previous list needs no copying.\r\n const stickers = this.guilds.stickers(event.guild_id);\r\n const previous = [...stickers.cache.values()];\r\n stickers.sync(event.stickers);\r\n this.emit(ClientEvent.GuildStickersUpdate, event, previous);\r\n });\r\n\r\n // ── Soundboard ───────────────────────────────────────────────────────────\r\n this.#gateway.on(\"GUILD_SOUNDBOARD_SOUND_CREATE\", (data) => {\r\n const sound = data as APISoundboardSound;\r\n if (sound.guild_id)\r\n this.guilds\r\n .soundboard(sound.guild_id)\r\n .set(sound.sound_id, sound);\r\n this.emit(ClientEvent.SoundboardSoundCreate, sound);\r\n });\r\n this.#gateway.on(\"GUILD_SOUNDBOARD_SOUND_UPDATE\", (data) => {\r\n const sound = data as APISoundboardSound;\r\n if (sound.guild_id)\r\n this.guilds\r\n .soundboard(sound.guild_id)\r\n .set(sound.sound_id, sound);\r\n this.emit(ClientEvent.SoundboardSoundUpdate, sound);\r\n });\r\n this.#gateway.on(\"GUILD_SOUNDBOARD_SOUND_DELETE\", (data) => {\r\n const event = data as { sound_id: string; guild_id: string };\r\n this.guilds.soundboard(event.guild_id).delete(event.sound_id);\r\n this.emit(ClientEvent.SoundboardSoundDelete, event);\r\n });\r\n this.#gateway.on(\"GUILD_SOUNDBOARD_SOUNDS_UPDATE\", (data) => {\r\n const event = data as {\r\n guild_id: string;\r\n soundboard_sounds: APISoundboardSound[];\r\n };\r\n const sounds = this.guilds.soundboard(event.guild_id);\r\n sounds.clear();\r\n for (const sound of event.soundboard_sounds)\r\n sounds.set(sound.sound_id, sound);\r\n this.emit(ClientEvent.SoundboardSoundsUpdate, event);\r\n });\r\n\r\n // ── Monetization ─────────────────────────────────────────────────────────\r\n this.#gateway.on(\"ENTITLEMENT_CREATE\", (data) => {\r\n const entitlement = data as APIEntitlement;\r\n this.monetization?.set(entitlement.id, entitlement);\r\n this.emit(ClientEvent.EntitlementCreate, entitlement);\r\n });\r\n this.#gateway.on(\"ENTITLEMENT_UPDATE\", (data) => {\r\n const entitlement = data as APIEntitlement;\r\n this.monetization?.set(entitlement.id, entitlement);\r\n this.emit(ClientEvent.EntitlementUpdate, entitlement);\r\n });\r\n this.#gateway.on(\"ENTITLEMENT_DELETE\", (data) => {\r\n const entitlement = data as APIEntitlement;\r\n this.monetization?.delete(entitlement.id);\r\n this.emit(ClientEvent.EntitlementDelete, entitlement);\r\n });\r\n\r\n // ── Guild Integrations ───────────────────────────────────────────────────\r\n this.#gateway.on(\"GUILD_INTEGRATIONS_UPDATE\", (data) =>\r\n this.emit(\r\n ClientEvent.GuildIntegrationsUpdate,\r\n data as { guild_id: string },\r\n ),\r\n );\r\n\r\n // ── Guild Scheduled Events ───────────────────────────────────────────────\r\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_CREATE\", (data) => {\r\n const event = data as APIGuildScheduledEvent;\r\n this.guilds.scheduledEvents(event.guild_id).set(event.id, event);\r\n this.emit(ClientEvent.GuildScheduledEventCreate, event);\r\n });\r\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_UPDATE\", (data) => {\r\n const event = data as APIGuildScheduledEvent;\r\n this.guilds.scheduledEvents(event.guild_id).set(event.id, event);\r\n this.emit(ClientEvent.GuildScheduledEventUpdate, event);\r\n });\r\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_DELETE\", (data) => {\r\n const event = data as APIGuildScheduledEvent;\r\n this.guilds.scheduledEvents(event.guild_id).delete(event.id);\r\n this.emit(ClientEvent.GuildScheduledEventDelete, event);\r\n });\r\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_USER_ADD\", (data) =>\r\n this.emit(\r\n ClientEvent.GuildScheduledEventUserAdd,\r\n data as APIGuildScheduledEventUserEvent,\r\n ),\r\n );\r\n this.#gateway.on(\"GUILD_SCHEDULED_EVENT_USER_REMOVE\", (data) =>\r\n this.emit(\r\n ClientEvent.GuildScheduledEventUserRemove,\r\n data as APIGuildScheduledEventUserEvent,\r\n ),\r\n );\r\n\r\n // ── AutoMod ──────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"AUTO_MODERATION_RULE_CREATE\", (data) => {\r\n const rule = data as APIAutoModerationRule;\r\n this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);\r\n this.emit(ClientEvent.AutoModerationRuleCreate, rule);\r\n });\r\n this.#gateway.on(\"AUTO_MODERATION_RULE_UPDATE\", (data) => {\r\n const rule = data as APIAutoModerationRule;\r\n this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);\r\n this.emit(ClientEvent.AutoModerationRuleUpdate, rule);\r\n });\r\n this.#gateway.on(\"AUTO_MODERATION_RULE_DELETE\", (data) => {\r\n const rule = data as APIAutoModerationRule;\r\n this.guilds.autoModerationRules(rule.guild_id).delete(rule.id);\r\n this.emit(ClientEvent.AutoModerationRuleDelete, rule);\r\n });\r\n this.#gateway.on(\"AUTO_MODERATION_ACTION_EXECUTION\", (data) =>\r\n this.emit(\r\n ClientEvent.AutoModerationActionExecution,\r\n data as APIAutoModerationActionExecution,\r\n ),\r\n );\r\n }\r\n\r\n /** Channels, threads, stage instances, invites and webhooks. */\r\n #wireChannels(): void {\r\n // ── Channels ─────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"CHANNEL_CREATE\", (data) => {\r\n const channel = this.channels.upsert(data as APIChannel);\r\n this.emit(ClientEvent.ChannelCreate, channel);\r\n });\r\n this.#gateway.on(\"CHANNEL_UPDATE\", (data) => {\r\n const previous = this.#previousChannel(data as APIChannel);\r\n const channel = this.channels.upsert(data as APIChannel);\r\n this.emit(ClientEvent.ChannelUpdate, channel, previous);\r\n });\r\n this.#gateway.on(\"CHANNEL_DELETE\", (data) => {\r\n const payload = data as APIChannel;\r\n const removed = this.channels.get(payload.id) ?? null;\r\n this.channels.delete(payload.id);\r\n this.emit(ClientEvent.ChannelDelete, payload, removed);\r\n });\r\n this.#gateway.on(\"CHANNEL_PINS_UPDATE\", (data) =>\r\n this.emit(\r\n ClientEvent.ChannelPinsUpdate,\r\n data as APIChannelPinsUpdate,\r\n ),\r\n );\r\n\r\n // ── Threads ──────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"THREAD_CREATE\", (data) => {\r\n const channel = this.channels.upsert(data as APIThreadEvent);\r\n this.emit(ClientEvent.ThreadCreate, channel);\r\n });\r\n this.#gateway.on(\"THREAD_UPDATE\", (data) => {\r\n const previous = this.#previousChannel(data as APIThreadEvent);\r\n const channel = this.channels.upsert(data as APIThreadEvent);\r\n this.emit(ClientEvent.ThreadUpdate, channel, previous);\r\n });\r\n this.#gateway.on(\"THREAD_DELETE\", (data) => {\r\n const payload = data as APIThreadEvent;\r\n const removed = this.channels.get(payload.id) ?? null;\r\n this.channels.delete(payload.id);\r\n this.emit(ClientEvent.ThreadDelete, payload, removed);\r\n });\r\n this.#gateway.on(\"THREAD_LIST_SYNC\", (data) => {\r\n const sync = data as APIThreadListSync;\r\n for (const thread of sync.threads)\r\n this.channels.upsert({ ...thread, guild_id: sync.guild_id });\r\n this.emit(ClientEvent.ThreadListSync, sync);\r\n });\r\n this.#gateway.on(\"THREAD_MEMBERS_UPDATE\", (data) =>\r\n this.emit(\r\n ClientEvent.ThreadMembersUpdate,\r\n data as APIThreadMembersUpdate,\r\n ),\r\n );\r\n this.#gateway.on(\"THREAD_MEMBER_UPDATE\", (data) =>\r\n this.emit(\r\n ClientEvent.ThreadMemberUpdate,\r\n data as import(\"@lunibee/types\").APIThreadMember,\r\n ),\r\n );\r\n\r\n // ── Stage Instances ──────────────────────────────────────────────────────\r\n this.#gateway.on(\"STAGE_INSTANCE_CREATE\", (data) => {\r\n const stage = data as APIStageInstance;\r\n this.stageInstances.set(stage.channel_id, stage);\r\n this.emit(ClientEvent.StageInstanceCreate, stage);\r\n });\r\n this.#gateway.on(\"STAGE_INSTANCE_UPDATE\", (data) => {\r\n const stage = data as APIStageInstance;\r\n this.stageInstances.set(stage.channel_id, stage);\r\n this.emit(ClientEvent.StageInstanceUpdate, stage);\r\n });\r\n this.#gateway.on(\"STAGE_INSTANCE_DELETE\", (data) => {\r\n const stage = data as APIStageInstance;\r\n this.stageInstances.delete(stage.channel_id);\r\n this.emit(ClientEvent.StageInstanceDelete, stage);\r\n });\r\n\r\n // ── Invites ──────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"INVITE_CREATE\", (data) => {\r\n const invite = data as APIInviteCreate;\r\n if (invite.guild_id)\r\n this.guilds.invites(invite.guild_id).set(invite.code, invite);\r\n this.emit(ClientEvent.InviteCreate, invite);\r\n });\r\n this.#gateway.on(\"INVITE_DELETE\", (data) => {\r\n const invite = data as APIInviteDelete;\r\n if (invite.guild_id)\r\n this.guilds.invites(invite.guild_id).delete(invite.code);\r\n this.emit(ClientEvent.InviteDelete, invite);\r\n });\r\n\r\n // ── Webhooks ─────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"WEBHOOKS_UPDATE\", (data) =>\r\n this.emit(ClientEvent.WebhooksUpdate, data as APIWebhooksUpdate),\r\n );\r\n }\r\n\r\n /** Voice, presence, typing, interactions, raw frames and errors. */\r\n #wireMisc(): void {\r\n // ── Voice ────────────────────────────────────────────────────────────────\r\n this.#gateway.on(\"VOICE_STATE_UPDATE\", (data) => {\r\n const state = data as APIVoiceState;\r\n if (state.guild_id) this.#storeVoiceState(state.guild_id, state);\r\n this.emit(ClientEvent.VoiceStateUpdate, state);\r\n });\r\n this.#gateway.on(\"VOICE_SERVER_UPDATE\", (data) =>\r\n this.emit(\r\n ClientEvent.VoiceServerUpdate,\r\n data as APIVoiceServerUpdate,\r\n ),\r\n );\r\n\r\n // ── Presence & Typing ────────────────────────────────────────────────────\r\n this.#gateway.on(\"PRESENCE_UPDATE\", (data) =>\r\n this.emit(ClientEvent.PresenceUpdate, data as APIPresenceUpdate),\r\n );\r\n this.#gateway.on(\"TYPING_START\", (data) =>\r\n this.emit(ClientEvent.TypingStart, data as APITypingStart),\r\n );\r\n\r\n // ── Interactions ─────────────────────────────────────────────────────────\r\n this.#gateway.on(\"INTERACTION_CREATE\", (data) =>\r\n this.emit(\r\n ClientEvent.InteractionCreate,\r\n createInteraction(this, data as InteractionData),\r\n ),\r\n );\r\n\r\n // ── Raw / Error ───────────────────────────────────────────────────────────\r\n this.#gateway.on(\"RAW\", (data) =>\r\n this.emit(\r\n ClientEvent.Raw,\r\n data as { event: string; data: unknown },\r\n ),\r\n );\r\n this.#gateway.on(\"error\", (error) =>\r\n this.emit(ClientEvent.Error, error as Error),\r\n );\r\n }\r\n\r\n /**\r\n * Convenience method to connect the bot to Discord.\r\n * Optionally overrides the configured token.\r\n * @param token Optional token override.\r\n * @returns The token used to log in.\r\n * @throws {TypeError} If the resulting token is empty.\r\n */\r\n /** Caches a message's author, and its channel only when none is cached: the\r\n * message carries a stub channel that must not overwrite a full one. */\r\n #observeMessage(message: Message): void {\r\n if (!this.channels.has(message.channelId))\r\n this.channels.set(message.channelId, message.channel);\r\n if (this.#cache.users)\r\n this.#merge(this.users, message.author.id, message.author);\r\n }\r\n\r\n #upsertMember(guildId: string, data: APIGuildMember): GuildMember {\r\n const member = new GuildMember(\r\n { ...data, guild_id: guildId },\r\n this.#resourceContext,\r\n );\r\n if (this.#cache.users)\r\n this.#merge(this.users, member.user.id, member.user);\r\n if (!this.#cache.members) return member;\r\n return this.#merge(\r\n this.guilds.members(guildId),\r\n member.user.id,\r\n member,\r\n );\r\n }\r\n\r\n /** A voice state without a channel means the user left voice. */\r\n #storeVoiceState(guildId: string, state: APIVoiceState): void {\r\n const states = this.guilds.voiceStates(guildId);\r\n if (state.channel_id) states.set(state.user_id, state);\r\n else states.delete(state.user_id);\r\n }\r\n\r\n #upsertRole(guildId: string, data: APIRole): Role {\r\n if (!this.#cache.roles) return new Role(data);\r\n return this.#merge(this.guilds.roles(guildId), data.id, new Role(data));\r\n }\r\n\r\n /**\r\n * Copies a cached structure's fields before an in-place merge changes them.\r\n * Pass `blank` (a fresh instance of the same class) when the class has\r\n * private fields, so the copy keeps them.\r\n */\r\n #snapshot<T extends object>(\r\n cached: T,\r\n blank: T = Object.create(Object.getPrototypeOf(cached)) as T,\r\n ): T {\r\n return Object.assign(blank, cached);\r\n }\r\n\r\n /** A copy of the cached channel an update is about to change, or null. */\r\n #previousChannel(data: APIChannel): Channel | null {\r\n const cached = this.channels.get(data.id);\r\n if (!cached) return null;\r\n // Channel keeps its client context in a private field; build the copy\r\n // through the same factory so it keeps the subclass and the context.\r\n return this.#snapshot(\r\n cached,\r\n createChannel(\r\n { id: cached.id, type: cached.type, guild_id: cached.guildId },\r\n this.#resourceContext,\r\n ),\r\n );\r\n }\r\n\r\n /** Merges `next` into the cached instance so references stay valid.\r\n * Fields a partial payload left undefined keep their cached value. */\r\n #merge<T extends object>(\r\n manager: {\r\n get(id: string): T | undefined;\r\n set(id: string, value: T): unknown;\r\n },\r\n id: string,\r\n next: T,\r\n ): T {\r\n const existing = manager.get(id);\r\n if (!existing) {\r\n manager.set(id, next);\r\n return next;\r\n }\r\n for (const [key, value] of Object.entries(next))\r\n if (value !== undefined)\r\n (existing as Record<string, unknown>)[key] = value;\r\n return existing;\r\n }\r\n\r\n /**\r\n * Collects the first argument of a client event until a limit, timeout,\r\n * idle timeout, abort or `stop()`. The collector unsubscribes itself when\r\n * it ends. Items are keyed by `options.key`, else their `id`, else order.\r\n */\r\n public createCollector<E extends keyof ClientEvents>(\r\n event: E,\r\n options: CollectorOptions<ClientEvents[E][0]> & {\r\n key?: (item: ClientEvents[E][0]) => string;\r\n } = {},\r\n ): Collector<string, ClientEvents[E][0]> {\r\n const collector = new Collector<string, ClientEvents[E][0]>(options);\r\n let order = 0;\r\n const listener = (...args: ClientEvents[E]): void => {\r\n const item = args[0];\r\n const id = (item as { id?: unknown } | null | undefined)?.id;\r\n const key =\r\n options.key?.(item) ??\r\n (typeof id === \"string\" ? id : String(order++));\r\n collector\r\n .handle(key, item)\r\n .catch((error: unknown) =>\r\n this.emit(\r\n ClientEvent.Error,\r\n error instanceof Error\r\n ? error\r\n : new Error(String(error)),\r\n ),\r\n );\r\n };\r\n this.on(event, listener);\r\n collector.onDispose(() => this.off(event, listener));\r\n return collector;\r\n }\r\n\r\n /** Structures built by this client (members from interactions...) act through this. */\r\n public get resourceContext(): ResourceContext {\r\n return this.#resourceContext;\r\n }\r\n\r\n /** Guild- or channel-level permissions from a member's role IDs and the cached roles and overwrites. */\r\n #memberPermissions(\r\n guildId: string,\r\n memberId: string,\r\n roleIds: readonly string[],\r\n channelId?: string,\r\n timedOutUntil?: Date | null,\r\n ): PermissionSet | null {\r\n const guild = this.guilds.get(guildId);\r\n if (!guild) return null;\r\n let channel = channelId ? this.channels.get(channelId) : undefined;\r\n if (channelId) {\r\n // Threads use their parent's overwrites; without it the answer is unknown.\r\n if (channel?.isThread())\r\n channel = channel.parentId\r\n ? this.channels.get(channel.parentId)\r\n : undefined;\r\n if (!channel || channel.guildId !== guildId) return null;\r\n }\r\n return computePermissions({\r\n guildId,\r\n ownerId: guild.ownerId,\r\n memberId,\r\n memberRoleIds: [...roleIds],\r\n roles: this.guilds.roles(guildId).values(),\r\n overwrites: channel?.permissionOverwrites,\r\n timedOutUntil,\r\n });\r\n }\r\n\r\n /**\r\n * Resolves a member's permissions from cached state: guild-level for a\r\n * guild ID, or channel-level (including overwrites) for a cached channel\r\n * ID. Returns null when the guild or member is not cached.\r\n */\r\n public permissionsFor(\r\n memberId: string,\r\n guildOrChannelId: string,\r\n ): PermissionSet | null {\r\n let channel = this.channels.get(guildOrChannelId);\r\n // Threads have no overwrites of their own: they use the parent's.\r\n // Without a cached parent the answer would be guild-level only, which\r\n // could wrongly grant access, so report it as unknown instead.\r\n if (channel?.isThread()) {\r\n channel = channel.parentId\r\n ? this.channels.get(channel.parentId)\r\n : undefined;\r\n if (!channel) return null;\r\n }\r\n const guildId = channel?.guildId ?? guildOrChannelId;\r\n const guild = this.guilds.get(guildId);\r\n const member = this.guilds.members(guildId).get(memberId);\r\n if (!guild || !member) return null;\r\n return computePermissions({\r\n guildId,\r\n ownerId: guild.ownerId,\r\n memberId,\r\n memberRoleIds: member.roleIds,\r\n roles: this.guilds.roles(guildId).values(),\r\n overwrites: channel?.permissionOverwrites,\r\n timedOutUntil: member.timedOutUntil,\r\n });\r\n }\r\n\r\n /** Fetches Discord's default soundboard sounds. */\r\n public fetchDefaultSoundboardSounds(): Promise<APISoundboardSound[]> {\r\n return this.rest.get<APISoundboardSound[]>(\r\n Routes.soundboardDefaultSounds(),\r\n );\r\n }\r\n\r\n /**\r\n * Connects to the Gateway. Resolves with the token used, like discord.js;\r\n * do not log the return value.\r\n */\r\n public async login(token?: string): Promise<string> {\r\n if (this.state === \"destroyed\")\r\n throw new Error(\"Cannot login a destroyed client.\");\r\n if (token?.trim()) {\r\n this.rest.setToken(token);\r\n this.options.token = token;\r\n }\r\n const usedToken = this.options.token;\r\n if (!usedToken?.trim())\r\n throw new TypeError(\"A bot token is required to log in.\");\r\n this.state = \"connecting\";\r\n await this.#gateway.connect();\r\n return usedToken;\r\n }\r\n\r\n /**\r\n * Destroys the client, permanently closing the Gateway connection.\r\n */\r\n public destroy(): void {\r\n this.state = \"destroyed\";\r\n this.#gateway.close();\r\n }\r\n\r\n // ── InteractionClient implementation ─────────────────────────────────────\r\n\r\n public postInteractionResponse(\r\n id: string,\r\n token: string,\r\n response: import(\"@lunibee/structures\").InteractionResponse,\r\n ): Promise<unknown> {\r\n const json = response.toJSON();\r\n // `?with_response=true` makes Discord return the created message.\r\n const callback = response.withResponse\r\n ? `${Routes.interactionCallback(id, token)}?with_response=true`\r\n : Routes.interactionCallback(id, token);\r\n // Only message responses (4 reply, 7 update) carry mentions; a modal or a deferral does not.\r\n const carriesMessage = json.type === 4 || json.type === 7;\r\n // Files in the reply turn the callback into an upload.\r\n const upload = json.data\r\n ? toRequest(\r\n json.data,\r\n carriesMessage ? this.options.allowedMentions : undefined,\r\n )\r\n : undefined;\r\n if (upload && typeof upload === \"object\" && \"files\" in upload) {\r\n const { body, files } = upload as { body: unknown; files: never[] };\r\n return this.rest.post(callback, {\r\n body: { ...json, data: body },\r\n files,\r\n });\r\n }\r\n return this.rest.post(\r\n callback,\r\n upload === undefined ? json : { ...json, data: upload },\r\n );\r\n }\r\n public editInteractionReply(\r\n token: string,\r\n data: Record<string, unknown>,\r\n ): Promise<unknown> {\r\n if (!this.user)\r\n return Promise.reject(new Error(\"Client is unauthenticated.\"));\r\n return this.rest.patch(\r\n Routes.interactionOriginalResponse(this.user.id, token),\r\n toRequest(data, this.options.allowedMentions),\r\n );\r\n }\r\n public deleteInteractionReply(token: string): Promise<void> {\r\n if (!this.user)\r\n return Promise.reject(new Error(\"Client is unauthenticated.\"));\r\n return this.rest.delete(\r\n Routes.interactionOriginalResponse(this.user.id, token),\r\n );\r\n }\r\n public async followUpInteraction(\r\n token: string,\r\n data: Record<string, unknown>,\r\n ): Promise<unknown> {\r\n if (!this.user)\r\n return Promise.reject(new Error(\"Client is unauthenticated.\"));\r\n return this.rest.post(\r\n Routes.webhook(this.user.id, token),\r\n toRequest(data, this.options.allowedMentions),\r\n );\r\n }\r\n public interactionWebhookMessage(\r\n method: \"GET\" | \"PATCH\" | \"DELETE\",\r\n applicationId: string,\r\n token: string,\r\n messageId: string,\r\n data?: Record<string, unknown>,\r\n ): Promise<unknown> {\r\n const path =\r\n messageId === \"@original\"\r\n ? Routes.interactionOriginalResponse(applicationId, token)\r\n : Routes.webhookMessage(applicationId, token, messageId);\r\n if (method === \"GET\") return this.rest.get(path);\r\n if (method === \"PATCH\")\r\n return this.rest.patch(\r\n path,\r\n data ? toRequest(data, this.options.allowedMentions) : data,\r\n );\r\n return this.rest.delete(path);\r\n }\r\n\r\n // ── Client Utilities ─────────────────────────────────────────────────────\r\n\r\n /** Fetches a webhook from Discord. */\r\n public async fetchWebhook(\r\n id: string,\r\n token?: string,\r\n ): Promise<Record<string, unknown>> {\r\n return this.rest.get(Routes.webhook(id, token)) as Promise<\r\n Record<string, unknown>\r\n >;\r\n }\r\n\r\n /** Fetches a guild preview from Discord. */\r\n public async fetchGuildPreview(\r\n guildId: string,\r\n ): Promise<Record<string, unknown>> {\r\n return this.rest.get(Routes.guildPreview(guildId)) as Promise<\r\n Record<string, unknown>\r\n >;\r\n }\r\n\r\n /** Fetches the voice regions from Discord. */\r\n public fetchVoiceRegions(): Promise<Record<string, unknown>[]> {\r\n return this.rest.get(\"/voice/regions\") as Promise<\r\n Record<string, unknown>[]\r\n >;\r\n }\r\n\r\n /** Fetches an invite from Discord. */\r\n public fetchInvite(\r\n code: string,\r\n options?: {\r\n withCounts?: boolean;\r\n /** @deprecated No effect: Discord always returns `expires_at` and deprecated `with_expiration`. Removed in 0.3.0. */\r\n withExpiration?: boolean;\r\n guildScheduledEventId?: string;\r\n },\r\n ): Promise<Record<string, unknown>> {\r\n const query = new URLSearchParams();\r\n if (options?.withCounts) query.set(\"with_counts\", \"true\");\r\n if (options?.guildScheduledEventId)\r\n query.set(\r\n \"guild_scheduled_event_id\",\r\n options.guildScheduledEventId,\r\n );\r\n const qs = query.toString();\r\n return this.rest.get(\r\n `/invites/${encodeURIComponent(code)}${qs ? `?${qs}` : \"\"}`,\r\n ) as Promise<Record<string, unknown>>;\r\n }\r\n\r\n /** Fetches a sticker from Discord. */\r\n public async fetchSticker(id: string): Promise<Record<string, unknown>> {\r\n return this.rest.get(Routes.sticker(id)) as Promise<\r\n Record<string, unknown>\r\n >;\r\n }\r\n\r\n /** Fetches premium sticker packs from Discord. */\r\n public fetchPremiumStickerPacks(): Promise<Record<string, unknown>> {\r\n return this.rest.get(`/sticker-packs`) as Promise<\r\n Record<string, unknown>\r\n >;\r\n }\r\n\r\n /** Fetches a guild template from Discord. */\r\n public fetchGuildTemplate(code: string): Promise<Record<string, unknown>> {\r\n return this.rest.get(\r\n `/guilds/templates/${encodeURIComponent(code)}`,\r\n ) as Promise<Record<string, unknown>>;\r\n }\r\n\r\n /** Generates an invite link for this client. */\r\n public generateInvite(options?: {\r\n scopes?: string[];\r\n permissions?: string | bigint;\r\n }): string {\r\n if (!this.user)\r\n throw new Error(\"Client must be ready to generate invite.\");\r\n const params = new URLSearchParams({\r\n client_id: this.user.id,\r\n scope: (options?.scopes ?? [\"bot\"]).join(\" \"),\r\n });\r\n if (options?.permissions) {\r\n params.set(\"permissions\", String(options.permissions));\r\n }\r\n return `https://discord.com/api/oauth2/authorize?${params.toString()}`;\r\n }\r\n}\r\n"
|
|
50
50
|
],
|
|
51
|
-
"mappings": "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",
|
|
52
|
-
"debugId": "
|
|
51
|
+
"mappings": "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",
|
|
52
|
+
"debugId": "9FDCE9C1C9B0DB0164756E2164756E21",
|
|
53
53
|
"names": []
|
|
54
54
|
}
|