diff --git a/packages/discord-types/enums/channel.ts b/packages/discord-types/enums/channel.ts index 7aae546b..a068b101 100644 --- a/packages/discord-types/enums/channel.ts +++ b/packages/discord-types/enums/channel.ts @@ -12,4 +12,4 @@ export const enum ChannelType { GUILD_DIRECTORY = 14, GUILD_FORUM = 15, GUILD_MEDIA = 16 -} \ No newline at end of file +} diff --git a/packages/discord-types/enums/index.ts b/packages/discord-types/enums/index.ts index a25ff3b5..e776577f 100644 --- a/packages/discord-types/enums/index.ts +++ b/packages/discord-types/enums/index.ts @@ -3,3 +3,4 @@ export * from "./channel"; export * from "./commands"; export * from "./messages"; export * from "./misc"; +export * from "./user"; diff --git a/packages/discord-types/enums/misc.ts b/packages/discord-types/enums/misc.ts index d1419ba3..90b67d43 100644 --- a/packages/discord-types/enums/misc.ts +++ b/packages/discord-types/enums/misc.ts @@ -2,3 +2,102 @@ export const enum CloudUploadPlatform { REACT_NATIVE = 0, WEB = 1, } + +export const enum DraftType { + ChannelMessage = 0, + ThreadSettings = 1, + FirstThreadMessage = 2, + ApplicationLauncherCommand = 3, + Poll = 4, + SlashCommand = 5, + ForwardContextMessage = 6, +} + +export const enum GuildScheduledEventStatus { + SCHEDULED = 1, + ACTIVE = 2, + COMPLETED = 3, + CANCELED = 4, +} + +export const enum GuildScheduledEventEntityType { + STAGE_INSTANCE = 1, + VOICE = 2, + EXTERNAL = 3, +} + +export const enum GuildScheduledEventPrivacyLevel { + GUILD_ONLY = 2, +} + +export const enum ParticipantType { + STREAM = 0, + HIDDEN_STREAM = 1, + USER = 2, + ACTIVITY = 3, +} + +export const enum RTCPlatform { + DESKTOP = 0, + MOBILE = 1, + XBOX = 2, + PLAYSTATION = 3, +} + +export const enum VideoSourceType { + VIDEO = 0, + CAMERA_PREVIEW = 1, +} + +export const enum EmojiIntention { + REACTION = 0, + STATUS = 1, + COMMUNITY_CONTENT = 2, + CHAT = 3, + GUILD_STICKER_RELATED_EMOJI = 4, + GUILD_ROLE_BENEFIT_EMOJI = 5, + SOUNDBOARD = 6, + VOICE_CHANNEL_TOPIC = 7, + GIFT = 8, + AUTO_SUGGESTION = 9, + POLLS = 10, + PROFILE = 11, + MESSAGE_CONFETTI = 12, + GUILD_PROFILE = 13, + CHANNEL_NAME = 14, + DEFAULT_REACT_EMOJI = 15, +} + +export const enum LoadState { + NOT_LOADED = 0, + LOADING = 1, + LOADED = 2, + ERROR = 3, +} + +export const enum ConnectionStatsFlags { + TRANSPORT = 1, + OUTBOUND = 2, + INBOUND = 4, + ALL = 7, +} + +export const enum SpeakingFlags { + NONE = 0, + VOICE = 1, + SOUNDSHARE = 2, + PRIORITY = 4, + HIDDEN = 8, +} + +export const enum GoLiveQualityMode { + AUTO = 1, + FULL = 2, +} + +export const enum VoiceProcessingStateReason { + CPU_OVERUSE = 1, + FAILED = 2, + VAD_CPU_OVERUSE = 3, + INITIALIZED = 4, +} diff --git a/packages/discord-types/enums/user.ts b/packages/discord-types/enums/user.ts new file mode 100644 index 00000000..171fe5e8 --- /dev/null +++ b/packages/discord-types/enums/user.ts @@ -0,0 +1,22 @@ +export const enum RelationshipType { + NONE = 0, + FRIEND = 1, + BLOCKED = 2, + INCOMING_REQUEST = 3, + OUTGOING_REQUEST = 4, + IMPLICIT = 5, + SUGGESTION = 6 +} + +export enum GiftIntentType { + FRIEND_ANNIVERSARY = 0 +} + +export const enum ReadStateType { + CHANNEL = 0, + GUILD_EVENT = 1, + NOTIFICATION_CENTER = 2, + GUILD_HOME = 3, + GUILD_ONBOARDING_QUESTION = 4, + MESSAGE_REQUESTS = 5, +} diff --git a/packages/discord-types/src/common/Application.d.ts b/packages/discord-types/src/common/Application.d.ts index d2ec1e7e..e59925d9 100644 --- a/packages/discord-types/src/common/Application.d.ts +++ b/packages/discord-types/src/common/Application.d.ts @@ -1,23 +1,89 @@ +import { Guild } from "./Guild"; import { User } from "./User"; -export interface Application { +export interface ApplicationExecutable { + os: "win32" | "darwin" | "linux"; + name: string; + isLauncher: boolean; +} + +export interface ApplicationThirdPartySku { + id: string; + sku: string; + distributor: string; +} + +export interface ApplicationDeveloper { id: string; name: string; - description?: string | null; - type: number | null; - icon: string | null | undefined; - is_discoverable: boolean; - is_monetized: boolean; - is_verified: boolean; - bot?: User; - deeplink_uri?: string; - flags?: number; - privacy_policy_url?: string; - terms_of_service_url?: string; - install_params?: ApplicationInstallParams; } export interface ApplicationInstallParams { permissions: string | null; scopes: string[]; } + +export interface Application { + id: string; + name: string; + icon: string | null; + description: string; + type: number | null; + coverImage: string | null; + primarySkuId: string | undefined; + bot: User | null; + splash: string | undefined; + thirdPartySkus: ApplicationThirdPartySku[]; + isMonetized: boolean; + isVerified: boolean; + roleConnectionsVerificationUrl: string | undefined; + parentId: string | undefined; + connectionEntrypointUrl: string | undefined; + overlay: boolean; + overlayWarn: boolean; + overlayCompatibilityHook: boolean; + overlayMethods: number; + hook: boolean; + aliases: string[]; + publishers: ApplicationDeveloper[]; + developers: ApplicationDeveloper[]; + storeListingSkuId: string | undefined; + guildId: string | null; + guild: Guild | undefined; + executables: ApplicationExecutable[]; + hashes: string[]; + eulaId: string | undefined; + slug: string | undefined; + flags: number; + maxParticipants: number | undefined; + tags: string[]; + embeddedActivityConfig: Record | undefined; + team: ApplicationTeam | undefined; + integrationTypesConfig: Record>; + storefront_available: boolean; + termsOfServiceUrl: string | undefined; + privacyPolicyUrl: string | undefined; + isDiscoverable: boolean; + customInstallUrl: string | undefined; + installParams: ApplicationInstallParams | undefined; + directoryEntry: Record | undefined; + categories: string[] | undefined; + linkedGames: string[] | undefined; + deepLinkUri: string | undefined; +} + +export interface ApplicationTeam { + id: string; + name: string; + icon: string | null; + members: ApplicationTeamMember[]; + ownerUserId: string; +} + +export interface ApplicationTeamMember { + user: User; + teamId: string; + membershipState: number; + permissions: string[]; + role: string; +} diff --git a/packages/discord-types/src/common/messages/Emoji.d.ts b/packages/discord-types/src/common/messages/Emoji.d.ts index 793e90f8..98cfeae9 100644 --- a/packages/discord-types/src/common/messages/Emoji.d.ts +++ b/packages/discord-types/src/common/messages/Emoji.d.ts @@ -1,42 +1,114 @@ +/** Union type for both custom (guild) emojis and unicode emojis. */ export type Emoji = CustomEmoji | UnicodeEmoji; +/** + * Custom emoji uploaded to a guild. + */ export interface CustomEmoji { + /** Discriminator for custom emojis. */ type: 1; - allNamesString: string; + /** Whether the emoji is animated (GIF). */ animated: boolean; + /** Whether the emoji is available for use. */ available: boolean; + /** Guild id this emoji belongs to. */ guildId: string; + /** Unique emoji id (snowflake). */ id: string; + /** Whether the emoji is managed by an integration (e.g. Twitch). */ managed: boolean; + /** Emoji name without colons. */ name: string; + /** Original name before any modifications. */ originalName?: string; + /** Whether the emoji requires colons to use. */ require_colons: boolean; + /** Role ids that can use this emoji (empty array means everyone). */ roles: string[]; + /** Version number, incremented when emoji is updated. */ + version?: number; } +/** + * Built-in unicode emoji. + */ export interface UnicodeEmoji { + /** Discriminator for unicode emojis. */ type: 0; - diversityChildren: Record; - emojiObject: { - names: string[]; - surrogates: string; - unicodeVersion: number; - }; + /** Skin tone variant emojis keyed by diversity surrogate code (e.g. "1f3fb" for light skin). */ + diversityChildren: Record; + /** Raw emoji data from Discord's emoji dataset. */ + emojiObject: EmojiObject; + /** Index position in the emoji list. */ index: number; + /** Unicode surrogate pair(s) for this emoji. */ surrogates: string; + /** Unique name identifier for this emoji. */ uniqueName: string; + /** Whether to render using sprite sheet. */ useSpriteSheet: boolean; + /** Original name if renamed in context. */ + originalName?: string; + /** Emoji id when used in custom emoji context. */ + id?: string; + /** Guild id when used in guild context. */ + guildId?: string; + /** Formatted string of all emoji names. */ get allNamesString(): string; - get animated(): boolean; - get defaultDiversityChild(): any; + /** Always false for unicode emojis. */ + get animated(): false; + /** Default skin tone variant or undefined if no diversity. */ + get defaultDiversityChild(): UnicodeEmoji | undefined; + /** Whether this emoji supports skin tone modifiers. */ get hasDiversity(): boolean | undefined; + /** Whether this emoji is a skin tone variant of another. */ get hasDiversityParent(): boolean | undefined; + /** Whether this emoji supports multiple diversity modifiers (e.g. handshake with two skin tones). */ get hasMultiDiversity(): boolean | undefined; + /** Whether this emoji is a multi-diversity variant of another. */ get hasMultiDiversityParent(): boolean | undefined; - get managed(): boolean; + /** Always true for unicode emojis. */ + get managed(): true; + /** Primary emoji name. */ get name(): string; + /** All names/aliases for this emoji. */ get names(): string[]; + /** Surrogate sequence with optional diversity modifier. */ get optionallyDiverseSequence(): string | undefined; + /** Unicode version when this emoji was added. */ get unicodeVersion(): number; + /** CDN url for emoji image. */ get url(): string; + /** + * Iterates over all diversity variants of this emoji. + * @param callback Function called for each diversity variant. + */ + forEachDiversity(callback: (emoji: UnicodeEmoji) => void): void; + /** + * Iterates over all names/aliases of this emoji. + * @param callback Function called for each name. + */ + forEachName(callback: (name: string) => void): void; +} + +/** + * Raw emoji data from Discord's emoji dataset. + */ +export interface EmojiObject { + /** All names/aliases for this emoji. */ + names: string[]; + /** Unicode surrogate pair(s). */ + surrogates: string; + /** Unicode version when this emoji was added. */ + unicodeVersion: number; + /** Index in the sprite sheet for rendering. */ + spriteIndex?: number; + /** Whether this emoji supports multiple skin tone modifiers. */ + hasMultiDiversity?: boolean; + /** Whether this emoji is a diversity variant with a multi-diversity parent. */ + hasMultiDiversityParent?: boolean; + /** Skin tone modifier codes for this variant (e.g. ["1f3fb"] or ["1f3fb", "1f3fc"]). */ + diversity?: string[]; + /** Sprite indices of diversity children for parent emojis. */ + diversityChildren?: number[]; } diff --git a/packages/discord-types/src/stores/AccessibilityStore.d.ts b/packages/discord-types/src/stores/AccessibilityStore.d.ts new file mode 100644 index 00000000..86ad4c50 --- /dev/null +++ b/packages/discord-types/src/stores/AccessibilityStore.d.ts @@ -0,0 +1,73 @@ +import { FluxStore } from ".."; + +export type ReducedMotionPreference = "auto" | "reduce" | "no-preference"; +export type ForcedColorsPreference = "none" | "active"; +export type ContrastPreference = "no-preference" | "more" | "less" | "custom"; +export type RoleStyle = "username" | "dot" | "hidden"; + +export interface AccessibilityState { + fontSize: number; + zoom: number; + keyboardModeEnabled: boolean; + contrastMode: string; + colorblindMode: boolean; + lowContrastMode: boolean; + saturation: number; + contrast: number; + desaturateUserColors: boolean; + forcedColorsModalSeen: boolean; + keyboardNavigationExplainerModalSeen: boolean; + messageGroupSpacing: number | null; + systemPrefersReducedMotion: ReducedMotionPreference; + systemPrefersCrossfades: boolean; + prefersReducedMotion: ReducedMotionPreference; + systemForcedColors: ForcedColorsPreference; + syncForcedColors: boolean; + systemPrefersContrast: ContrastPreference; + alwaysShowLinkDecorations: boolean; + roleStyle: RoleStyle; + displayNameStylesEnabled: boolean; + submitButtonEnabled: boolean; + syncProfileThemeWithUserTheme: boolean; + enableCustomCursor: boolean; + switchIconsEnabled: boolean; +} + +export class AccessibilityStore extends FluxStore { + get fontScale(): number; + get fontSize(): number; + get isFontScaledUp(): boolean; + get isFontScaledDown(): boolean; + get fontScaleClass(): string; + get zoom(): number; + get isZoomedIn(): boolean; + get isZoomedOut(): boolean; + get keyboardModeEnabled(): boolean; + get colorblindMode(): boolean; + get lowContrastMode(): boolean; + get saturation(): number; + get contrast(): number; + get desaturateUserColors(): boolean; + get forcedColorsModalSeen(): boolean; + get keyboardNavigationExplainerModalSeen(): boolean; + get messageGroupSpacing(): number; + get isMessageGroupSpacingIncreased(): boolean; + get isMessageGroupSpacingDecreased(): boolean; + get isSubmitButtonEnabled(): boolean; + get syncProfileThemeWithUserTheme(): boolean; + get systemPrefersReducedMotion(): ReducedMotionPreference; + get rawPrefersReducedMotion(): ReducedMotionPreference; + get useReducedMotion(): boolean; + get systemForcedColors(): ForcedColorsPreference; + get syncForcedColors(): boolean; + get useForcedColors(): boolean; + get systemPrefersContrast(): ContrastPreference; + get systemPrefersCrossfades(): boolean; + get alwaysShowLinkDecorations(): boolean; + get enableCustomCursor(): boolean; + get roleStyle(): RoleStyle; + get displayNameStylesEnabled(): boolean; + get isHighContrastModeEnabled(): boolean; + get isSwitchIconsEnabled(): boolean; + getUserAgnosticState(): AccessibilityState; +} diff --git a/packages/discord-types/src/stores/ActiveJoinedThreadsStore.d.ts b/packages/discord-types/src/stores/ActiveJoinedThreadsStore.d.ts new file mode 100644 index 00000000..71138a68 --- /dev/null +++ b/packages/discord-types/src/stores/ActiveJoinedThreadsStore.d.ts @@ -0,0 +1,33 @@ +import { Channel, FluxStore } from ".."; + +export interface ThreadJoined { + channel: Channel; + joinTimestamp: number; +} + +export type ThreadsForParent = Record; +export type ThreadsForGuild = Record; +export type AllActiveJoinedThreads = Record; + +export interface NewThreadCounts { + [parentChannelId: string]: number; +} + +export class ActiveJoinedThreadsStore extends FluxStore { + computeAllActiveJoinedThreads(guildId?: string | null): Channel[]; + getActiveJoinedRelevantThreadsForGuild(guildId: string): ThreadsForGuild; + getActiveJoinedRelevantThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent; + getActiveJoinedThreadsForGuild(guildId: string): ThreadsForGuild; + getActiveJoinedThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent; + getActiveJoinedUnreadThreadsForGuild(guildId: string): ThreadsForGuild; + getActiveJoinedUnreadThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent; + getActiveThreadCount(guildId: string, parentChannelId: string): number; + getActiveUnjoinedThreadsForGuild(guildId: string): ThreadsForGuild; + getActiveUnjoinedThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent; + getActiveUnjoinedUnreadThreadsForGuild(guildId: string): ThreadsForGuild; + getActiveUnjoinedUnreadThreadsForParent(guildId: string, parentChannelId: string): ThreadsForParent; + getAllActiveJoinedThreads(): AllActiveJoinedThreads; + getNewThreadCount(guildId: string, parentChannelId: string): number; + getNewThreadCountsForGuild(guildId: string): NewThreadCounts; + hasActiveJoinedUnreadThreads(guildId: string, parentChannelId: string): boolean; +} diff --git a/packages/discord-types/src/stores/ApplicationStore.d.ts b/packages/discord-types/src/stores/ApplicationStore.d.ts new file mode 100644 index 00000000..6bfb5105 --- /dev/null +++ b/packages/discord-types/src/stores/ApplicationStore.d.ts @@ -0,0 +1,23 @@ +import { Application, FluxStore } from ".."; + +export interface ApplicationStoreState { + botUserIdToAppUsage: Record; +} + +export interface ApplicationUsage { + applicationId: string; + lastUsedMs: number; +} + +export class ApplicationStore extends FluxStore { + getState(): ApplicationStoreState; + getApplication(applicationId: string): Application; + getApplicationByName(name: string): Application | undefined; + getApplicationLastUpdated(applicationId: string): number | undefined; + getGuildApplication(guildId: string, type: number): Application | undefined; + getGuildApplicationIds(guildId: string): string[]; + getAppIdForBotUserId(botUserId: string): string | undefined; + getFetchingOrFailedFetchingIds(): string[]; + isFetchingApplication(applicationId: string): boolean; + didFetchingApplicationFail(applicationId: string): boolean; +} diff --git a/packages/discord-types/src/stores/CallStore.d.ts b/packages/discord-types/src/stores/CallStore.d.ts new file mode 100644 index 00000000..ea87ff70 --- /dev/null +++ b/packages/discord-types/src/stores/CallStore.d.ts @@ -0,0 +1,24 @@ +import { FluxStore } from ".."; + +export interface Call { + channelId: string; + messageId: string | null; + region: string | null; + ringing: string[]; + unavailable: boolean; + regionUpdated: boolean; +} + +export interface CallStoreState { + calls: Record; + enqueuedRings: Record; +} + +export class CallStore extends FluxStore { + getCall(channelId: string): Call; + getCalls(): Call[]; + getMessageId(channelId: string): string | null; + isCallActive(channelId: string, messageId?: string): boolean; + isCallUnavailable(channelId: string): boolean; + getInternalState(): CallStoreState; +} diff --git a/packages/discord-types/src/stores/ChannelRTCStore.d.ts b/packages/discord-types/src/stores/ChannelRTCStore.d.ts new file mode 100644 index 00000000..13fedf0f --- /dev/null +++ b/packages/discord-types/src/stores/ChannelRTCStore.d.ts @@ -0,0 +1,105 @@ +import { FluxStore, User, VoiceState } from ".."; +import { ParticipantType, RTCPlatform } from "../../enums"; + +export type RTCLayout = "normal" | "minimum" | "no-chat" | "full-screen" | "haven"; +export type RTCMode = "video" | "voice"; +export type RTCLayoutContext = "OVERLAY" | "APP" | "POPOUT" | "CALL_TILE_POPOUT"; +export type ParticipantFilterType = "VIDEO" | "STREAM" | "FILTERED" | "SPEAKING" | "ACTIVITY" | "NOT_POPPED_OUT"; + +export interface StreamResolution { + height: number; + width: number; +} + +export interface Stream { + channelId: string; + guildId: string | null; + ownerId: string; + streamType: string; +} + +export interface BaseParticipant { + id: string; + type: ParticipantType; + isPoppedOut?: boolean; +} + +export interface UserParticipant extends BaseParticipant { + type: ParticipantType.USER; + user: User; + voiceState: VoiceState | null; + voicePlatform: RTCPlatform | null; + speaking: boolean; + voiceDb: number; + latched: boolean; + lastSpoke: number; + soundsharing: boolean; + ringing: boolean; + userNick: string; + // TODO: type + userAvatarDecoration: any | null; + localVideoDisabled: boolean; + userVideo?: boolean; + streamId?: string; +} + +export interface StreamParticipant extends BaseParticipant { + type: ParticipantType.STREAM | ParticipantType.HIDDEN_STREAM; + user: User; + userNick: string; + userVideo: boolean; + stream: Stream; + maxResolution?: StreamResolution; + maxFrameRate?: number; + streamId?: string; +} + +export interface ActivityParticipant extends BaseParticipant { + type: ParticipantType.ACTIVITY; + applicationId: string; + activityType: number; + activityUrl: string; + participants: string[]; + guildId: string | null; + sortKey: string; +} + +export type Participant = UserParticipant | StreamParticipant | ActivityParticipant; + +export interface SelectedParticipantStats { + view_mode_grid_duration_ms?: number; + view_mode_focus_duration_ms?: number; + view_mode_toggle_count?: number; +} + +export interface ChannelRTCState { + voiceParticipantsHidden: Record; +} + +export class ChannelRTCStore extends FluxStore { + getActivityParticipants(channelId: string): ActivityParticipant[]; + getAllChatOpen(): Record; + getChatOpen(channelId: string): boolean; + getFilteredParticipants(channelId: string): Participant[]; + getGuildRingingUsers(channelId: string): Set; + getLayout(channelId: string, context?: RTCLayoutContext): RTCLayout; + getMode(channelId: string): RTCMode; + getParticipant(channelId: string, participantId: string): Participant | null; + getParticipants(channelId: string): Participant[]; + getParticipantsListOpen(channelId: string): boolean; + getParticipantsOpen(channelId: string): boolean; + getParticipantsVersion(channelId: string): number; + getSelectedParticipant(channelId: string): Participant | null; + getSelectedParticipantId(channelId: string): string | null; + getSelectedParticipantStats(channelId: string): SelectedParticipantStats; + getSpeakingParticipants(channelId: string): UserParticipant[]; + getStageStreamSize(channelId: string): StreamResolution | undefined; + getStageVideoLimitBoostUpsellDismissed(channelId: string): boolean | undefined; + getState(): ChannelRTCState; + getStreamParticipants(channelId: string): StreamParticipant[]; + getUserParticipantCount(channelId: string): number; + getVideoParticipants(channelId: string): UserParticipant[]; + getVoiceParticipantsHidden(channelId: string): boolean; + isFullscreenInContext(): boolean; + isParticipantPoppedOut(channelId: string, participantId: string): boolean; +} diff --git a/packages/discord-types/src/stores/ChannelStore.d.ts b/packages/discord-types/src/stores/ChannelStore.d.ts index 1507ba5e..81b006cd 100644 --- a/packages/discord-types/src/stores/ChannelStore.d.ts +++ b/packages/discord-types/src/stores/ChannelStore.d.ts @@ -10,6 +10,7 @@ export class ChannelStore extends FluxStore { getMutableGuildChannelsForGuild(guildId: string): Record; getAllThreadsForGuild(guildId: string): Channel[]; getAllThreadsForParent(channelId: string): Channel[]; + getSortedLinkedChannelsForGuild(guildId: string): Channel[]; getDMFromUserId(userId: string): string; getDMChannelFromUserId(userId: string): Channel | undefined; @@ -21,4 +22,10 @@ export class ChannelStore extends FluxStore { getGuildChannelsVersion(guildId: string): number; getPrivateChannelsVersion(): number; getInitialOverlayState(): Record; + + getDebugInfo(): { + loadedGuildIds: string[]; + pendingGuildLoads: string[]; + guildSizes: string[]; + }; } diff --git a/packages/discord-types/src/stores/DraftStore.d.ts b/packages/discord-types/src/stores/DraftStore.d.ts index 98b34cdf..89d50c43 100644 --- a/packages/discord-types/src/stores/DraftStore.d.ts +++ b/packages/discord-types/src/stores/DraftStore.d.ts @@ -1,14 +1,5 @@ import { FluxStore } from ".."; - -export enum DraftType { - ChannelMessage = 0, - ThreadSettings = 1, - FirstThreadMessage = 2, - ApplicationLauncherCommand = 3, - Poll = 4, - SlashCommand = 5, - ForwardContextMessage = 6 -} +import { DraftType } from "../../enums"; export interface Draft { timestamp: number; diff --git a/packages/discord-types/src/stores/EmojiStore.d.ts b/packages/discord-types/src/stores/EmojiStore.d.ts index 93161b2f..f22a70a1 100644 --- a/packages/discord-types/src/stores/EmojiStore.d.ts +++ b/packages/discord-types/src/stores/EmojiStore.d.ts @@ -1,57 +1,467 @@ import { Channel, CustomEmoji, Emoji, FluxStore } from ".."; +import { EmojiIntention, LoadState } from "../../enums"; -export class EmojiStore extends FluxStore { - getCustomEmojiById(id?: string | null): CustomEmoji | undefined; - getUsableCustomEmojiById(id?: string | null): CustomEmoji | undefined; - getGuilds(): Record; - getGuildEmoji(guildId?: string | null): CustomEmoji[]; - getNewlyAddedEmoji(guildId?: string | null): CustomEmoji[]; - getTopEmoji(guildId?: string | null): CustomEmoji[]; - getTopEmojisMetadata(guildId?: string | null): { - emojiIds: string[]; - topEmojisTTL: number; - }; - hasPendingUsage(): boolean; - hasUsableEmojiInAnyGuild(): boolean; - searchWithoutFetchingLatest(data: any): any; - getSearchResultsOrder(...args: any[]): any; - getState(): { - pendingUsages: { key: string, timestamp: number; }[]; - }; - searchWithoutFetchingLatest(data: { - channel: Channel; - query: string; - count?: number; - intention: number; - includeExternalGuilds?: boolean; - matchComparator?(name: string): boolean; - }): Record<"locked" | "unlocked", Emoji[]>; +/** Emoji picker category names. */ +export type EmojiCategory = + | "top guild emoji" + | "favorites" + | "recent" + | "custom" + | "people" + | "nature" + | "food" + | "activity" + | "travel" + | "objects" + | "symbols" + | "flags"; - getDisambiguatedEmojiContext(): { - backfillTopEmojis: Record; - customEmojis: Record; - emojisById: Record; - emojisByName: Record; - emoticonRegex: RegExp | null; - emoticonsByName: Record; - escapedEmoticonNames: string; - favoriteNamesAndIds?: any; - favorites?: any; - frequentlyUsed?: any; - groupedCustomEmojis: Record; - guildId?: string; - isFavoriteEmojiWithoutFetchingLatest(e: Emoji): boolean; - newlyAddedEmoji: Record; - topEmojis?: any; - unicodeAliases: Record; - get favoriteEmojisWithoutFetchingLatest(): Emoji[]; - }; +/** + * Tracks usage statistics for a single emoji to compute frecency scores. + */ +export interface EmojiUsageRecord { + /** Total number of times this emoji has been used. */ + totalUses: number; + /** Array of recent usage timestamps in milliseconds. */ + recentUses: number[]; + /** Computed frecency score combining frequency and recency, -1 when dirty. */ + frecency: number; + /** Raw score before frecency computation. */ + score: number; +} + +/** + * Options for tracking emoji usage. + */ +export interface TrackOptions { + /** Timestamp of the usage in milliseconds. */ + timestamp?: number; + /** Number of uses since last track call. */ + usesSinceLastTrack?: number; +} + +/** + * Frecency tracker for emoji usage, combines frequency and recency to rank emojis. + * Used by both regular emoji picker and reaction emoji picker. + */ +export interface EmojiFrecency { + /** True when data has been modified and needs recomputation. */ + dirty: boolean; + /** Cached array of frequently used emojis after computation. */ + _frequently: Emoji[]; + /** Maximum number of frequently used items to track (default 42). */ + numFrequentlyItems: number; + /** Maximum number of recent usage samples to keep per emoji (default 10). */ + maxSamples: number; + /** Computes bonus score for frecency calculation (returns 100). */ + computeBonus: () => number; + /** + * Computes weight multiplier based on recency index. + * Returns 100 for index <= 3, 70 for <= 15, 50 for <= 30, 30 for <= 45, 10 for <= 80. + */ + computeWeight: (index: number) => number; + /** + * Computes frecency score for an emoji. + * @param totalUses Total number of times emoji was used. + * @param score Raw score value. + * @param config Configuration for frecency calculation. + */ + computeFrecency: (totalUses: number, score: number, config: { + /** Number of recent uses to consider. */ + numOfRecentUses?: number; + /** Maximum total uses to cap at. */ + maxTotalUse?: number; + }) => number; + /** Whether to calculate max total use dynamically. */ + calculateMaxTotalUse: boolean; + /** + * Looks up an emoji by name or id. + * @param name Emoji name or id to look up. + * @returns The emoji if found. + */ + lookupKey: (name: string) => Emoji | undefined; + /** Usage history keyed by emoji name (for unicode) or id (for custom). */ + usageHistory: Record; + /** Callback invoked after frecency computation completes. */ + afterCompute: () => void; + + /** + * Overwrites the usage history with new data. + * @param history New usage history to set. + * @param pendingUsages Pending usages to track after overwriting. + */ + overwriteHistory(history: Record | null, pendingUsages?: PendingUsage[]): void; + /** Marks the frecency data as dirty, requiring recomputation. */ + markDirty(): void; + /** Returns whether the frecency data needs recomputation. */ + isDirty(): boolean; + /** + * Tracks usage of an emoji. + * @param key Emoji name or id. + * @param options Track options including timestamp. + */ + track(key: string, options?: TrackOptions): void; + /** + * Gets the usage record for an emoji, computing if dirty. + * @param key Emoji name or id. + * @returns The usage record or null if not found. + */ + getEntry(key: string): EmojiUsageRecord | null; + /** + * Gets the score for an emoji. + * @param key Emoji name or id. + * @returns The score or null if not found. + */ + getScore(key: string): number | null; + /** + * Gets the frecency for an emoji. + * @param key Emoji name or id. + * @returns The frecency or null if not found. + */ + getFrecency(key: string): number | null; + /** Recomputes frecency scores for all emojis. */ + compute(): void; + /** Gets the frequently used emojis, computing if necessary. */ + get frequently(): Emoji[]; +} + +/** + * Container for a guild's emoji collection with usability checks. + */ +export interface GuildEmojis { + /** Guild id this emoji collection belongs to. */ + id: string; + /** User id for permission checks. */ + _userId: string; + /** Internal emoji array. */ + _emojis: CustomEmoji[]; + /** Fast lookup map of emoji id to emoji. */ + _emojiMap: Record; + /** Internal emoticons array. */ + _emoticons: Emoticon[]; + /** Internal usable emojis cache. */ + _usableEmojis: CustomEmoji[]; + /** Whether user can see server subscription IAP. */ + _canSeeServerSubIAP: boolean; + /** All custom emojis in this guild. */ + get emojis(): CustomEmoji[]; + /** Custom emojis the current user can use in this guild. */ + get usableEmojis(): CustomEmoji[]; + /** Text emoticons configured for this guild. */ + get emoticons(): Emoticon[]; + /** + * Gets an emoji by id from this guild. + * @param id Emoji id to look up. + */ + getEmoji(id: string): CustomEmoji | undefined; + /** + * Gets a usable emoji by id from this guild. + * @param id Emoji id to look up. + */ + getUsableEmoji(id: string): CustomEmoji | undefined; + /** + * Checks if an emoji is usable by the current user. + * @param emoji Emoji to check. + */ + isUsable(emoji: CustomEmoji): boolean; + /** Returns array of all emoji ids in this guild. */ + emojiIds(): string[]; +} + +/** + * Text emoticon that can be converted to emoji. + */ +export interface Emoticon { + /** Names/aliases for this emoticon. */ + names: string[]; + /** The text representation (e.g. ":)" or ":D"). */ + surrogates: string; + /** Whether this emoticon should use sprite sheet rendering. */ + useSpriteSheet: boolean; +} + +/** + * Pending emoji usage waiting to be recorded. + */ +export interface PendingUsage { + /** Emoji key (name for unicode, id for custom). */ + key: string; + /** Timestamp in milliseconds when usage occurred. */ + timestamp: number; +} + +/** + * Serializable state for EmojiStore persistence. + */ +export interface EmojiStoreState { + /** Pending emoji usages not yet committed. */ + pendingUsages: PendingUsage[]; + /** Pending reaction emoji usages not yet committed. */ + emojiReactionPendingUsages: PendingUsage[]; + /** Guild ids with expanded emoji sections in picker. */ + expandedSectionsByGuildIds: Set; +} + +/** + * Context for emoji disambiguation, caching resolved emoji data for a guild context. + * Provides fast lookup of emojis without triggering data fetches. + */ +export interface DisambiguatedEmojiContext { + /** User's favorite emojis or null if not loaded. */ + favorites: Emoji[] | null; + /** Set of favorite emoji names and ids for fast lookup, or null if not loaded. */ + favoriteNamesAndIds: Set | null; + /** Top emojis for the current guild or null if not loaded. */ + topEmojis: Emoji[] | null; + /** Current guild id context or null for DMs. */ + guildId: string | null; + /** Regex-escaped emoticon names for matching. */ + escapedEmoticonNames: string; + /** All emojis with disambiguation applied (unique names). */ + disambiguatedEmoji: Emoji[]; + /** Compiled regex for matching emoticons or null if none. */ + emoticonRegex: RegExp | null; + /** Frequently used emojis or null if not loaded. */ + frequentlyUsed: Emoji[] | null; + /** Frequently used reaction emojis or null if not loaded. */ + frequentlyUsedReactionEmojis: Emoji[] | null; + /** Set of frequently used reaction emoji names and ids, or null if not loaded. */ + frequentlyUsedReactionNamesAndIds: Set | null; + /** Unicode emoji aliases keyed by alias name, maps to primary name. */ + unicodeAliases: Record; + /** Custom emojis keyed by emoji id. */ + customEmojis: Record; + /** Custom emojis grouped by guild id. */ + groupedCustomEmojis: Record; + /** Emoticons keyed by name for fast lookup. */ + emoticonsByName: Record; + /** All emojis keyed by name for fast lookup. */ + emojisByName: Record; + /** Custom emojis keyed by id for fast lookup. */ + emojisById: Record; + /** Newly added emojis grouped by guild id. */ + newlyAddedEmoji: Record; + /** + * Checks if an emoji is a favorite without triggering a fetch. + * @param emoji Emoji to check. + */ + isFavoriteEmojiWithoutFetchingLatest(emoji: Emoji): boolean; + + /** Gets favorite emojis without triggering a fetch. */ + get favoriteEmojisWithoutFetchingLatest(): Emoji[]; + /** Gets all disambiguated emojis. */ + getDisambiguatedEmoji(): Emoji[]; + /** Gets all custom emojis keyed by name. */ + getCustomEmoji(): Record; + /** Gets custom emojis grouped by guild id. */ + getGroupedCustomEmoji(): Record; + /** + * Gets an emoji by name. + * @param name Emoji name to look up. + */ + getByName(name: string): Emoji | undefined; + /** + * Gets an emoticon by name. + * @param name Emoticon name to look up. + */ + getEmoticonByName(name: string): Emoticon | undefined; + /** + * Gets an emoji by id. + * @param id Emoji id to look up. + */ + getById(id: string): Emoji | undefined; + /** + * Gets the regex for matching custom emoticons. + * @returns RegExp or null if no emoticons. + */ + getCustomEmoticonRegex(): RegExp | null; + /** Gets frequently used emojis without triggering a fetch. */ + getFrequentlyUsedEmojisWithoutFetchingLatest(): Emoji[]; + /** Rebuilds the frequently used reaction emojis cache and returns it. */ + rebuildFrequentlyUsedReactionsEmojisWithoutFetchingLatest(): { + frequentlyUsedReactionEmojis: Emoji[]; + frequentlyUsedReactionNamesAndIds: Set; + }; + /** Gets frequently used reaction emojis without triggering a fetch. */ + getFrequentlyUsedReactionEmojisWithoutFetchingLatest(): Emoji[]; + /** + * Checks if an emoji is frequently used for reactions. + * @param emoji Emoji to check. + */ + isFrequentlyUsedReactionEmojiWithoutFetchingLatest(emoji: Emoji): boolean; + /** Rebuilds the favorite emojis cache and returns it. */ + rebuildFavoriteEmojisWithoutFetchingLatest(): { + favorites: Emoji[]; + favoriteNamesAndIds: Set; + }; + /** + * Gets emojis in priority order (favorites, frequent, top) without fetching. + * @returns Array of emojis in priority order. + */ + getEmojiInPriorityOrderWithoutFetchingLatest(): Emoji[]; + /** + * Gets top emojis for a guild without triggering a fetch. + * @param guildId Guild id to get top emojis for. + */ + getTopEmojiWithoutFetchingLatest(guildId: string): Emoji[]; + /** + * Gets newly added emojis for a specific guild. + * @param guildId Guild id. + */ + getNewlyAddedEmojiForGuild(guildId: string): CustomEmoji[]; + /** Gets escaped custom emoticon names for regex matching. */ + getEscapedCustomEmoticonNames(): string; + /** + * Checks if a name matches an emoji name chain. + * @param name Name to match. + */ + nameMatchesChain(name: string): boolean; +} + +/** + * Search options for emoji search. + */ +export interface EmojiSearchOptions { + /** Channel context for permission checks. */ + channel: Channel; + /** Search query string. */ + query: string; + /** Maximum number of results to return. */ + count?: number; + /** Intention for using the emoji, affects availability filtering. */ + intention: EmojiIntention; + /** Whether to include emojis from guilds the user is not in. */ + includeExternalGuilds?: boolean; + /** Whether to only show unicode emojis in results. */ + showOnlyUnicode?: boolean; + /** + * Custom comparator for matching emoji names. + * @param name Emoji name to compare. + * @returns True if the name matches. + */ + matchComparator?(name: string): boolean; +} + +/** + * Search results split by availability. + */ +export interface EmojiSearchResults { + /** Emojis that are locked (require Nitro or permissions). */ + locked: Emoji[]; + /** Emojis that are available for use. */ + unlocked: Emoji[]; +} + +/** + * Metadata about top emojis for a guild. + */ +export interface TopEmojisMetadata { + /** Array of top emoji ids. */ + emojiIds: string[]; + /** Time-to-live for this data in milliseconds. */ + topEmojisTTL: number; +} + +/** + * Flux store managing all emoji data including custom guild emojis, + * unicode emojis, favorites, frecency, and search functionality. + */ +export class EmojiStore extends FluxStore { + /** Array of emoji category names for the picker. */ + get categories(): EmojiCategory[]; + /** + * Current skin tone modifier surrogate for emoji diversity. + * Empty string for default yellow, or skin tone modifier (🏻🏼🏽🏾🏿). + */ + get diversitySurrogate(): string; + /** Frecency tracker for emoji picker usage. */ + get emojiFrecencyWithoutFetchingLatest(): EmojiFrecency; + /** Frecency tracker for reaction emoji usage. */ + get emojiReactionFrecencyWithoutFetchingLatest(): EmojiFrecency; + /** Guild ids with expanded emoji sections in picker. */ + get expandedSectionsByGuildIds(): Set; + /** Current load state of the emoji store. */ + get loadState(): LoadState; + + /** + * Gets a custom emoji by its id. + * @param id Emoji id to look up. + * @returns The custom emoji if found. + */ + getCustomEmojiById(id?: string | null): CustomEmoji | undefined; + /** + * Gets a usable custom emoji by its id. + * @param id Emoji id to look up. + * @returns The custom emoji if found and usable by current user. + */ + getUsableCustomEmojiById(id?: string | null): CustomEmoji | undefined; + /** + * Gets all guild emoji collections keyed by guild id. + * @returns Record of guild id to GuildEmojis. + */ + getGuilds(): Record; + /** + * Gets all custom emojis for a guild. + * @param guildId Guild id to get emojis for, or null for all guilds. + * @returns Array of custom emojis. + */ + getGuildEmoji(guildId?: string | null): CustomEmoji[]; + /** + * Gets usable custom emojis for a guild. + * @param guildId Guild id to get emojis for. + * @returns Array of usable custom emojis. + */ + getUsableGuildEmoji(guildId?: string | null): CustomEmoji[]; + /** + * Gets newly added emojis for a guild. + * @param guildId Guild id to get emojis for. + * @returns Array of newly added custom emojis. + */ + getNewlyAddedEmoji(guildId?: string | null): CustomEmoji[]; + /** + * Gets top emojis for a guild based on usage. + * @param guildId Guild id to get emojis for. + * @returns Array of top custom emojis. + */ + getTopEmoji(guildId?: string | null): CustomEmoji[]; + /** + * Gets metadata about top emojis for a guild. + * @param guildId Guild id to get metadata for. + * @returns Metadata including emoji ids and TTL, or undefined if not cached. + */ + getTopEmojisMetadata(guildId?: string | null): TopEmojisMetadata | undefined; + /** + * Checks if user has any favorite emojis in a guild context. + * @param guildId Guild id to check. + * @returns True if user has favorites. + */ + hasFavoriteEmojis(guildId?: string | null): boolean; + /** + * Checks if there are pending emoji usages to be recorded. + * @returns True if there are pending usages. + */ + hasPendingUsage(): boolean; + /** + * Checks if user has any usable custom emojis in any guild. + * @returns True if user has usable emojis. + */ + hasUsableEmojiInAnyGuild(): boolean; + /** Internal method for ordering search results. */ + getSearchResultsOrder(...args: any[]): any; + /** + * Gets the serializable state for persistence. + * @returns Current store state. + */ + getState(): EmojiStoreState; + /** + * Searches for emojis without triggering data fetches. + * @param options Search options including query and filters. + * @returns Search results split by locked/unlocked. + */ + searchWithoutFetchingLatest(options: EmojiSearchOptions): EmojiSearchResults; + /** + * Gets the disambiguated emoji context for a guild. + * @param guildId Guild id to get context for, or null/undefined for global context. + */ + getDisambiguatedEmojiContext(guildId?: string | null): DisambiguatedEmojiContext; } diff --git a/packages/discord-types/src/stores/FluxStore.d.ts b/packages/discord-types/src/stores/FluxStore.d.ts index da55ac0b..61328f52 100644 --- a/packages/discord-types/src/stores/FluxStore.d.ts +++ b/packages/discord-types/src/stores/FluxStore.d.ts @@ -1,6 +1,7 @@ import { FluxDispatcher, FluxEvents } from ".."; type Callback = () => void; +type SyncCallback = () => boolean | void; /* For some reason, this causes type errors when you try to destructure it: @@ -14,31 +15,75 @@ type Callback = () => void; export type FluxEvent = any; export type ActionHandler = (event: FluxEvent) => void; +/** keyed by FluxEvents action type */ export type ActionHandlers = Partial>; +/** + * Base class for all Discord Flux stores. + * Provides change notification, action handling, and store synchronization. + */ export class FluxStore { - constructor(dispatcher: FluxDispatcher, actionHandlers?: ActionHandlers); + /** + * @param dispatcher the FluxDispatcher instance to register with + * @param actionHandlers handlers for Flux actions, keyed by action type + * @param band priority band for action handling (default 2), lower runs first + */ + constructor(dispatcher: FluxDispatcher, actionHandlers?: ActionHandlers, band?: number); + /** returns displayName if set, otherwise constructor.name */ getName(): string; + /** adds listener to _changeCallbacks, invoked before react listeners and triggers syncWith processing */ addChangeListener(callback: Callback): void; - /** Listener will be removed once the callback returns false. */ + /** + * adds a listener that auto-removes when callback returns false. + * @param callback returning false removes the listener + * @param preemptive if true (default), calls callback immediately and skips adding if it returns false + */ addConditionalChangeListener(callback: () => boolean, preemptive?: boolean): void; + /** adds listener to _reactChangeCallbacks, invoked after all regular change listeners complete */ addReactChangeListener(callback: Callback): void; removeChangeListener(callback: Callback): void; removeReactChangeListener(callback: Callback): void; + /** called by dispatcher after action handlers run, marks changed if listeners exist and may resume paused dispatch */ doEmitChanges(event: FluxEvent): void; + /** marks store as changed for batched listener notification */ emitChange(): void; + /** unique token identifying this store in the dispatcher */ getDispatchToken(): string; + /** override to set up initial state, called once by initializeIfNeeded */ initialize(): void; + /** calls initialize() if not already initialized, adds performance mark if init takes >5ms */ initializeIfNeeded(): void; - /** this is a setter */ - mustEmitChanges(actionHandler: ActionHandler | undefined): void; - registerActionHandlers(actionHandlers: ActionHandlers): void; - syncWith(stores: FluxStore[], callback: Callback, timeout?: number): void; + /** + * sets callback to determine if changes must emit during paused dispatch. + * @param callback if omitted, defaults to () => true (always emit) + */ + mustEmitChanges(callback?: ActionHandler): void; + /** + * registers additional action handlers after construction. + * @param actionHandlers handlers keyed by action type + * @param band priority band, lower runs first + */ + registerActionHandlers(actionHandlers: ActionHandlers, band?: number): void; + /** + * syncs this store with other stores, re-emitting when they change. + * without timeout: synchronous, callback runs during emitNonReactOnce. + * with timeout: debounced, adds regular change listener to each source store. + * @param stores stores to sync with + * @param callback returning false skips emitChange on this store + * @param timeout if provided, debounces the sync callback + */ + syncWith(stores: FluxStore[], callback: SyncCallback, timeout?: number): void; + /** adds dispatcher dependencies so this store's handlers run after the specified stores */ waitFor(...stores: FluxStore[]): void; + /** initializes all registered stores, called once at app startup */ + static initialize(): void; + /** clears all registered stores and destroys the change listener system */ + static destroy(): void; + /** returns all registered FluxStore instances */ static getAll(): FluxStore[]; } diff --git a/packages/discord-types/src/stores/FriendsStore.d.ts b/packages/discord-types/src/stores/FriendsStore.d.ts new file mode 100644 index 00000000..e0611bca --- /dev/null +++ b/packages/discord-types/src/stores/FriendsStore.d.ts @@ -0,0 +1,67 @@ +import { Activity, FluxStore, Guild, User } from ".."; +import { GiftIntentType, RelationshipType } from "../../enums"; + +export type FriendsSection = "ADD_FRIEND" | "ALL" | "ONLINE" | "PENDING" | "PENDING_IGNORED" | "SPAM" | "SUGGESTIONS"; + +export type StatusType = "online" | "offline" | "idle" | "dnd" | "invisible" | "streaming" | "unknown"; + +export interface ApplicationStream { + channelId: string; + guildId: string | null; + ownerId: string; + streamType: string; +} + +export interface FriendsRow { + key: string; + userId: string; + /** + * 99 means contact based friend suggestions from FriendSuggestionStore, + * shown in SUGGESTIONS tab. different from RelationshipType.SUGGESTION + * which is for implicit suggestions in RelationshipStore + */ + type: RelationshipType | 99; + status: StatusType; + isMobile: boolean; + activities: Activity[]; + applicationStream: ApplicationStream | null; + user: User | null; + usernameLower: string | null; + mutualGuildsLength: number; + mutualGuilds: Guild[]; + nickname: string | null; + spam: boolean; + giftIntentType: GiftIntentType | undefined; + ignoredUser: boolean; + applicationId: string | undefined; + isGameRelationship: boolean; + comparator: [RelationshipType | 99, string | null]; +} + +export interface RelationshipCounts { + [RelationshipType.FRIEND]: number; + [RelationshipType.INCOMING_REQUEST]: number; + [RelationshipType.OUTGOING_REQUEST]: number; + [RelationshipType.BLOCKED]: number; + /** contact based friend suggestions from FriendSuggestionStore */ + 99: number; +} + +export interface FriendsRows { + _rows: FriendsRow[]; + reset(): FriendsRows; + clone(): FriendsRows; + update(updater: (userId: string) => Partial): boolean; + filter(section: FriendsSection, searchQuery?: string | null): FriendsRow[]; + getRelationshipCounts(): RelationshipCounts; +} + +export interface FriendsState { + fetching: boolean; + section: FriendsSection; + rows: FriendsRows; +} + +export class FriendsStore extends FluxStore { + getState(): FriendsState; +} diff --git a/packages/discord-types/src/stores/GuildChannelStore.d.ts b/packages/discord-types/src/stores/GuildChannelStore.d.ts new file mode 100644 index 00000000..7dbd81f1 --- /dev/null +++ b/packages/discord-types/src/stores/GuildChannelStore.d.ts @@ -0,0 +1,46 @@ +import { Channel, FluxStore, ThreadJoined } from ".."; +import { ChannelType } from "../../enums"; + +export interface ChannelWithComparator { + channel: Channel; + comparator: number; +} + +export interface GuildChannels { + [ChannelType.GUILD_CATEGORY]: ChannelWithComparator[]; + id: string; + SELECTABLE: ChannelWithComparator[] | ThreadJoined[]; + VOCAL: ChannelWithComparator[]; + count: number; +} + +export interface ChannelNameDisambiguation { + id: string; + name: string; +} + +export class GuildChannelStore extends FluxStore { + getAllGuilds(): Record; + getChannels(guildId: string): GuildChannels; + getDefaultChannel(guildId: string): Channel | null; + getDirectoryChannelIds(guildId: string): string[]; + getFirstChannel( + guildId: string, + predicate: (item: ChannelWithComparator) => boolean, + includeVocal?: boolean + ): Channel | null; + getFirstChannelOfType( + guildId: string, + predicate: (item: ChannelWithComparator) => boolean, + type: "SELECTABLE" | "VOCAL" | ChannelType.GUILD_CATEGORY + ): Channel | null; + getSFWDefaultChannel(guildId: string): Channel | null; + getSelectableChannelIds(guildId: string): string[]; + getSelectableChannels(guildId: string): ChannelWithComparator[]; + getTextChannelNameDisambiguations(guildId: string): Record; + getVocalChannelIds(guildId: string): string[]; + hasCategories(guildId: string): boolean; + hasChannels(guildId: string): boolean; + hasElevatedPermissions(guildId: string): boolean; + hasSelectableChannel(guildId: string, channelId: string): boolean; +} diff --git a/packages/discord-types/src/stores/GuildMemberCountStore.d.ts b/packages/discord-types/src/stores/GuildMemberCountStore.d.ts new file mode 100644 index 00000000..14b24ccf --- /dev/null +++ b/packages/discord-types/src/stores/GuildMemberCountStore.d.ts @@ -0,0 +1,7 @@ +import { FluxStore } from ".."; + +export class GuildMemberCountStore extends FluxStore { + getMemberCounts(): Record; + getMemberCount(guildId: string): number; + getOnlineCount(guildId: string): number; +} diff --git a/packages/discord-types/src/stores/GuildMemberStore.d.ts b/packages/discord-types/src/stores/GuildMemberStore.d.ts index 9dec139a..38a9421d 100644 --- a/packages/discord-types/src/stores/GuildMemberStore.d.ts +++ b/packages/discord-types/src/stores/GuildMemberStore.d.ts @@ -1,5 +1,10 @@ import { FluxStore, GuildMember } from ".."; +export interface PendingRoleUpdates { + added: string[]; + removed: string[]; +} + export class GuildMemberStore extends FluxStore { /** @returns Format: [guildId-userId: Timestamp (string)] */ getCommunicationDisabledUserMap(): Record; @@ -11,6 +16,10 @@ export class GuildMemberStore extends FluxStore { getTrueMember(guildId: string, userId: string): GuildMember | null; getMemberIds(guildId: string): string[]; getMembers(guildId: string): GuildMember[]; + getMemberVersion(): number; + getMemberRoleWithPendingUpdates(guildId: string, userId: string): string[]; + getPendingRoleUpdates(guildId: string): PendingRoleUpdates; + memberOf(userId: string): string[]; getCachedSelfMember(guildId: string): GuildMember | null; getSelfMember(guildId: string): GuildMember | null; @@ -20,7 +29,6 @@ export class GuildMemberStore extends FluxStore { getNicknameGuildsMapping(userId: string): Record; getNicknames(userId: string): string[]; - isMember(guildId: string, userId: string): boolean; isMember(guildId: string, userId: string): boolean; isGuestOrLurker(guildId: string, userId: string): boolean; isCurrentUserGuest(guildId: string): boolean; diff --git a/packages/discord-types/src/stores/GuildRoleStore.d.ts b/packages/discord-types/src/stores/GuildRoleStore.d.ts index faf586a0..93d325b9 100644 --- a/packages/discord-types/src/stores/GuildRoleStore.d.ts +++ b/packages/discord-types/src/stores/GuildRoleStore.d.ts @@ -1,8 +1,13 @@ -import { FluxStore, Role } from ".."; +import { FluxStore, Guild, Role } from ".."; -// TODO: add the rest of the methods for GuildRoleStore export class GuildRoleStore extends FluxStore { - getRole(guildId: string, roleId: string): Role; - getSortedRoles(guildId: string): Role[]; getRolesSnapshot(guildId: string): Record; + getSortedRoles(guildId: string): Role[]; + + getEveryoneRole(guild: Guild): Role; + getManyRoles(guildId: string, roleIds: string[]): Role[]; + getNumRoles(guildId: string): number; + getRole(guildId: string, roleId: string): Role; + getUnsafeMutableRoles(guildId: string): Record; + serializeAllGuildRoles(): Array<{ partitionKey: string; values: Record; }>; } diff --git a/packages/discord-types/src/stores/GuildScheduledEventStore.d.ts b/packages/discord-types/src/stores/GuildScheduledEventStore.d.ts new file mode 100644 index 00000000..23e79774 --- /dev/null +++ b/packages/discord-types/src/stores/GuildScheduledEventStore.d.ts @@ -0,0 +1,67 @@ +import { FluxStore } from ".."; +import { GuildScheduledEventEntityType, GuildScheduledEventPrivacyLevel, GuildScheduledEventStatus } from "../../enums"; + +export interface GuildScheduledEventEntityMetadata { + location?: string; +} + +export interface GuildScheduledEventRecurrenceRule { + start: string; + end: string | null; + frequency: number; + interval: number; + byWeekday: number[] | null; + byNWeekday: { n: number; day: number; }[] | null; + byMonth: number[] | null; + byMonthDay: number[] | null; + byYearDay: number[] | null; + count: number | null; +} + +export interface GuildScheduledEvent { + id: string; + guild_id: string; + channel_id: string | null; + creator_id: string | null; + name: string; + description: string | null; + image: string | null; + scheduled_start_time: string; + scheduled_end_time: string | null; + privacy_level: GuildScheduledEventPrivacyLevel; + status: GuildScheduledEventStatus; + entity_type: GuildScheduledEventEntityType; + entity_id: string | null; + entity_metadata: GuildScheduledEventEntityMetadata | null; + sku_ids: string[]; + recurrence_rule: GuildScheduledEventRecurrenceRule | null; + // TODO: type + guild_scheduled_event_exceptions: any[]; + auto_start: boolean; +} + +export interface GuildScheduledEventRsvp { + guildScheduledEventId: string; + userId: string; + interested: boolean; +} + +export interface GuildScheduledEventUsers { + // TODO: finish typing + [userId: string]: any; +} + +export class GuildScheduledEventStore extends FluxStore { + getGuildScheduledEvent(eventId: string): GuildScheduledEvent | null; + getGuildScheduledEventsForGuild(guildId: string): GuildScheduledEvent[]; + getGuildScheduledEventsByIndex(status: GuildScheduledEventStatus): GuildScheduledEvent[]; + getGuildEventCountByIndex(status: GuildScheduledEventStatus): number; + getRsvpVersion(): number; + getRsvp(eventId: string, recurrenceId: string | null, userId: string | null): GuildScheduledEventRsvp | null; + isInterestedInEventRecurrence(eventId: string, recurrenceId: string | null): boolean; + getUserCount(eventId: string, recurrenceId: string | null): number; + hasUserCount(eventId: string, recurrenceId: string | null): boolean; + isActive(eventId: string): boolean; + getActiveEventByChannel(channelId: string): GuildScheduledEvent | null; + getUsersForGuildEvent(eventId: string, recurrenceId: string | null): GuildScheduledEventUsers; +} diff --git a/packages/discord-types/src/stores/GuildStore.d.ts b/packages/discord-types/src/stores/GuildStore.d.ts index d1a3b9b3..fd35053c 100644 --- a/packages/discord-types/src/stores/GuildStore.d.ts +++ b/packages/discord-types/src/stores/GuildStore.d.ts @@ -4,5 +4,6 @@ export class GuildStore extends FluxStore { getGuild(guildId: string): Guild; getGuildCount(): number; getGuilds(): Record; + getGuildsArray(): Guild[]; getGuildIds(): string[]; } diff --git a/packages/discord-types/src/stores/InstantInviteStore.d.ts b/packages/discord-types/src/stores/InstantInviteStore.d.ts new file mode 100644 index 00000000..bc4af185 --- /dev/null +++ b/packages/discord-types/src/stores/InstantInviteStore.d.ts @@ -0,0 +1,17 @@ +import { FluxStore } from ".."; +import { Invite } from "./InviteStore"; + +export interface FriendInvite extends Invite { + max_age: number; + max_uses: number; + uses: number; + created_at: string; + revoked?: boolean; +} + +export class InstantInviteStore extends FluxStore { + getInvite(channelId: string): Invite; + getFriendInvite(): FriendInvite | null; + getFriendInvitesFetching(): boolean; + canRevokeFriendInvite(): boolean; +} diff --git a/packages/discord-types/src/stores/InviteStore.d.ts b/packages/discord-types/src/stores/InviteStore.d.ts new file mode 100644 index 00000000..9ea8f2a2 --- /dev/null +++ b/packages/discord-types/src/stores/InviteStore.d.ts @@ -0,0 +1,27 @@ +import { Channel, FluxStore, Guild, User } from ".."; + +export interface Invite { + code: string; + guild: Guild | null; + channel: Channel | null; + inviter: User | null; + approximate_member_count?: number; + approximate_presence_count?: number; + expires_at?: string | null; + flags?: number; + target_type?: number; + target_user?: User; + // TODO: type these + target_application?: any; + stage_instance?: any; + guild_scheduled_event?: any; +} + +export class InviteStore extends FluxStore { + getInvite(code: string): Invite; + // TODO: finish typing + getInviteError(code: string): any | undefined; + getInvites(): Record; + getInviteKeyForGuildId(guildId: string): string | undefined; + getFriendMemberIds(code: string): string[] | undefined; +} diff --git a/packages/discord-types/src/stores/LocaleStore.d.ts b/packages/discord-types/src/stores/LocaleStore.d.ts new file mode 100644 index 00000000..ca5915de --- /dev/null +++ b/packages/discord-types/src/stores/LocaleStore.d.ts @@ -0,0 +1,6 @@ +import { FluxStore } from ".."; + +export class LocaleStore extends FluxStore { + get locale(): string; + get systemLocale(): string; +} diff --git a/packages/discord-types/src/stores/MediaEngineStore.d.ts b/packages/discord-types/src/stores/MediaEngineStore.d.ts new file mode 100644 index 00000000..f5861bc0 --- /dev/null +++ b/packages/discord-types/src/stores/MediaEngineStore.d.ts @@ -0,0 +1,2742 @@ +import { FluxStore } from ".."; + +/** Context for media engine settings. */ +export type MediaEngineContextType = "default" | "stream"; + +/** Audio/video device type identifiers. */ +export type DeviceType = "audioinput" | "audiooutput" | "videoinput"; + +/** Voice activation mode for microphone input. */ +export type VoiceMode = "PUSH_TO_TALK" | "VOICE_ACTIVITY"; + +/** WebRTC connection state. */ +export type ConnectionState = + | "DISCONNECTED" + | "CONNECTING" + | "CONNECTED" + | "NO_ROUTE" + | "ICE_CHECKING" + | "DTLS_CONNECTING"; + +/** Video toggle state indicating why video was enabled/disabled. */ +export type VideoToggleState = + | "NONE" + | "video_manual_disable" + | "video_manual_enable" + | "video_manual_reenable" + | "video_auto_disable" + | "video_auto_enable" + | "video_auto_downgrade" + | "video_auto_upgrade"; + +/** Quality override for video streams. */ +export type VideoQualityOverride = "no_override" | "high" | "low"; + +/** Audio processing subsystem. */ +export type AudioSubsystem = "legacy" | "standard" | "experimental" | "automatic"; + +/** Media stream types. */ +export type MediaType = "audio" | "video" | "screen" | "test"; + +/** Keyframe interval calculation mode. */ +export type KeyframeIntervalMode = "fixed" | "source"; + +/** Bandwidth estimation algorithm type. */ +export type BandwidthEstimationType = "remb"; + +/** Media engine implementation type. */ +export type MediaEngineType = "NATIVE" | "WEBRTC" | "DUMMY"; + +/** Desktop capture source types. */ +export type DesktopSourceType = "WINDOW" | "SCREEN"; + +/** HDR capture mode for screen sharing. */ +export type HdrCaptureMode = "never" | "always" | "auto"; + +/** Input profile type for voice settings. */ +export type InputProfile = "DEFAULT" | "CUSTOM"; + +/** Media engine feature flags for capability checking. */ +export type MediaEngineFeature = + | "AUTO_ENABLE" + | "ATTENUATION" + | "AUDIO_INPUT_DEVICE" + | "AUDIO_OUTPUT_DEVICE" + | "VOICE_PROCESSING" + | "QOS" + | "NATIVE_PING" + | "LEGACY_AUDIO_SUBSYSTEM" + | "EXPERIMENTAL_AUDIO_SUBSYSTEM" + | "AUTOMATIC_AUDIO_SUBSYSTEM" + | "AUDIO_SUBSYSTEM_DEFERRED_SWITCH" + | "AUDIO_BYPASS_SYSTEM_INPUT_PROCESSING" + | "DEBUG_LOGGING" + | "AUTOMATIC_VAD" + | "VOICE_PANNING" + | "DIAGNOSTICS" + | "VIDEO" + | "DESKTOP_CAPTURE" + | "DESKTOP_CAPTURE_FORMAT" + | "DESKTOP_CAPTURE_APPLICATIONS" + | "SOUNDSHARE" + | "LOOPBACK" + | "VIDEO_HOOK" + | "EXPERIMENTAL_SOUNDSHARE" + | "WUMPUS_VIDEO" + | "ELEVATED_HOOK" + | "HYBRID_VIDEO" + | "REMOTE_LOCUS_NETWORK_CONTROL" + | "SCREEN_PREVIEWS" + | "WINDOW_PREVIEWS" + | "AUDIO_DEBUG_STATE" + | "AEC_DUMP" + | "DISABLE_VIDEO" + | "CONNECTION_REPLAY" + | "SIMULCAST" + | "RTC_REGION_RANKING" + | "ELECTRON_VIDEO" + | "MEDIAPIPE" + | "FIXED_KEYFRAME_INTERVAL" + | "SAMPLE_PLAYBACK" + | "FIRST_FRAME_CALLBACK" + | "REMOTE_USER_MULTI_STREAM" + | "NOISE_SUPPRESSION" + | "NOISE_CANCELLATION" + | "VOICE_FILTERS" + | "AUTOMATIC_GAIN_CONTROL" + | "CLIPS" + | "SPEED_TEST" + | "IMAGE_QUALITY_MEASUREMENT" + | "GO_LIVE_HARDWARE" + | "SCREEN_CAPTURE_KIT" + | "SCREEN_SOUNDSHARE" + | "NATIVE_SCREENSHARE_PICKER" + | "MLS_PAIRWISE_FINGERPRINTS" + | "OFFLOAD_ADM_CONTROLS" + | "SIDECHAIN_COMPRESSION" + | "VAAPI" + | "GAMESCOPE_CAPTURE" + | "ASYNC_VIDEO_INPUT_DEVICE_INIT" + | "ASYNC_CLIPS_SOURCE_DEINIT" + | "PORT_AWARE_LATENCY_TESTING"; + +/** Events emitted by the media engine. */ +export type MediaEngineEvent = + | "Destroy" + | "Silence" + | "Connection" + | "DeviceChange" + | "VolumeChange" + | "VoiceActivity" + | "WatchdogTimeout" + | "AudioPermission" + | "VideoPermission" + | "DesktopSourceEnd" + | "ConnectionStats" + | "VideoInputInitialized" + | "AudioInputInitialized" + | "ClipsRecordingRestartNeeded" + | "ClipsInitFailure" + | "ClipsRecordingEnded" + | "NativeScreenSharePickerUpdate" + | "NativeScreenSharePickerCancel" + | "NativeScreenSharePickerError" + | "AudioDeviceModuleError" + | "VoiceFiltersFailed" + | "VideoCodecError" + | "VoiceQueueMetrics" + | "SystemMicrophoneModeChange" + | "SelectedDeviceChange"; + +/** + * Audio input or output device. + */ +export interface AudioDevice { + /** unique device identifier from the system. */ + id: string; + /** device index in enumeration, -1 for default device. */ + index: number; + /** human readable device name. */ + name: string; + /** whether the device is disabled in system settings. */ + disabled: boolean; + /** camera facing direction if applicable, undefined for audio devices. */ + facing?: string; + /** windows device GUID for identification. */ + guid: string; + /** hardware identifier for the device. */ + hardwareId: string; + /** container identifier grouping related devices. */ + containerId: string; + /** audio effects supported by device, undefined if none. */ + effects?: string[]; +} + +/** + * Video input device (webcam). + */ +export interface VideoDevice { + /** unique device identifier from the system. */ + id: string; + /** device index in enumeration. */ + index: number; + /** human readable device name. */ + name: string; + /** whether the device is disabled in system settings. */ + disabled: boolean; + /** camera facing direction, "front", "back", or "unknown". */ + facing?: string; + /** windows device GUID for identification. */ + guid: string; + /** hardware identifier for the device. */ + hardwareId?: string; + /** container identifier grouping related devices. */ + containerId?: string; + /** video effects supported by device, undefined if none. */ + effects?: string[]; +} + +/** + * Quality settings for clips recording. + */ +export interface ClipsQuality { + /** recording frame rate in fps. */ + frameRate: number; + /** recording resolution height in pixels. */ + resolution: number; +} + +/** + * Desktop capture configuration for clips. + */ +export interface DesktopDescription { + /** desktop source identifier. */ + id: string; + /** soundshare source identifier for audio capture. */ + soundshareId: number; + /** whether to use loopback audio capture. */ + useLoopback: boolean; + /** whether to use video hook for capture. */ + useVideoHook: boolean; + /** whether to use windows graphics capture API. */ + useGraphicsCapture: boolean; + /** whether to use macOS quartz capturer. */ + useQuartzCapturer: boolean; + /** whether to allow macOS screencapturekit. */ + allowScreenCaptureKit: boolean; + /** HDR capture behavior. */ + hdrCaptureMode: HdrCaptureMode; +} + +/** + * Source configuration for clips recording. + */ +export interface ClipsSource { + /** quality settings for the recording. */ + quality: ClipsQuality; + /** desktop capture configuration. */ + desktopDescription: DesktopDescription; +} + +/** + * Desktop source for screen sharing. + */ +export interface DesktopSource { + /** source identifier string. */ + id: string; + /** process id of the source application, null if not applicable. */ + sourcePid: number | null; + /** soundshare identifier for audio capture, null if not capturing audio. */ + soundshareId: string | null; + /** soundshare session identifier, null if not active. */ + soundshareSession: string | null; +} + +/** + * Quality settings for go live streaming. + */ +export interface GoLiveQuality { + /** stream resolution height in pixels. */ + resolution: number; + /** stream frame rate in fps. */ + frameRate: number; +} + +/** + * Source configuration for go live streaming. + */ +export interface GoLiveSource { + /** desktop source being streamed. */ + desktopSource: DesktopSource; + /** quality settings for the stream. */ + quality: GoLiveQuality; +} + +/** + * Video stream parameter for simulcast layers. + */ +export interface VideoStreamParameter { + /** simulcast layer id, e.g. "100" for full quality, "50" for half. */ + rid: string; + /** type of media stream. */ + type: MediaType; + /** quality percentage 0-100. */ + quality: number; +} + +/** + * Stereo panning for a user's audio. + */ +export interface LocalPan { + /** left channel volume multiplier 0-1, default 1. */ + left: number; + /** right channel volume multiplier 0-1, default 1. */ + right: number; +} + +/** + * Voice activity detection and push-to-talk options. + */ +export interface ModeOptions { + /** VAD threshold in dB, default -60. */ + threshold: number; + /** whether to auto-adjust threshold based on noise floor, default true. */ + autoThreshold: boolean; + /** whether to use krisp for VAD instead of webrtc, default true. */ + vadUseKrisp: boolean; + /** krisp activation threshold 0-1, default 0.8. */ + vadKrispActivationThreshold: number; + /** frames of audio to keep before speech is detected, default 5. */ + vadLeading: number; + /** frames to keep transmitting after speech ends, default 25. */ + vadTrailing: number; + /** PTT release delay in milliseconds, default 20. */ + delay: number; + /** keyboard shortcut keys for PTT, default empty array. */ + shortcut: string[]; + /** whether to run VAD before audio processing, default false. */ + vadDuringPreProcess?: boolean; +} + +/** + * Options for audio loopback testing. + */ +export interface LoopbackOptions { + /** whether echo cancellation is enabled. */ + echoCancellation: boolean; + /** whether noise suppression is enabled. */ + noiseSuppression: boolean; + /** whether automatic gain control is enabled. */ + automaticGainControl: boolean; + /** whether krisp noise cancellation is enabled. */ + noiseCancellation: boolean; +} + +/** + * Screen capture preview thumbnail. + */ +export interface ScreenPreview { + /** screen source identifier. */ + id: string; + /** data URL of thumbnail image. */ + url: string; + /** display name, e.g. "Screen 1". */ + name: string; +} + +/** + * Window capture preview thumbnail. + */ +export interface WindowPreview { + /** window source identifier. */ + id: string; + /** data URL of thumbnail image. */ + url: string; + /** window title. */ + name: string; +} + +/** + * Krisp noise cancellation statistics. + */ +export interface NoiseCancellationStats { + /** milliseconds of detected voice audio. */ + voiceMs: number; + /** milliseconds of detected music audio. */ + musicMs: number; + /** milliseconds of detected noise audio. */ + noiseMs: number; +} + +/** + * MLS signing key for end-to-end encryption. + */ +export interface MLSSigningKey { + /** raw key bytes. */ + key: Uint8Array; + /** key signature bytes. */ + signature: Uint8Array; +} + +/** + * Codec capability info for a single codec. + */ +export interface CodecInfo { + /** codec name (H264, VP8, VP9, AV1, H265). */ + name: string; + /** whether encoding is supported, false if no hardware/software encoder available. */ + encode: boolean; + /** whether decoding is supported, false if no hardware/software decoder available. */ + decode: boolean; +} + +/** + * Metadata for saved clips. + */ +export interface ClipMetadata { + /** custom name for the clip. */ + name?: string; + /** description text for the clip. */ + description?: string; +} + +/** + * Result of saving a clip. + */ +export interface SavedClip { + /** unique clip identifier. */ + id: string; + /** path where clip was saved. */ + filepath: string; +} + +/** + * Result of saving a screenshot. + */ +export interface Screenshot { + /** path where screenshot was saved. */ + filepath: string; +} + +/** + * Settings for video background filters. + */ +export interface MediaFilterSettings { + /** whether background replacement is enabled. */ + backgroundEnabled: boolean; + /** background blur intensity 0-100. */ + backgroundBlur: number; + /** custom background image id, null for blur only. */ + backgroundId: string | null; +} + +/** + * Options for local audio recording. + */ +export interface AudioRecordingOptions { + /** whether to apply echo cancellation. */ + echoCancellation: boolean; + /** whether to apply noise suppression. */ + noiseSuppression: boolean; +} + +/** + * Options for raw audio sample recording. + */ +export interface RawSamplesOptions { + /** number of audio channels. */ + channels: number; + /** sample rate in hz. */ + sampleRate: number; +} + +/** + * Options for creating a voice connection. + */ +export interface ConnectionOptions { + /** whether to start muted. */ + selfMute: boolean; + /** whether to start deafened. */ + selfDeaf: boolean; + /** whether to start with video enabled. */ + selfVideo: boolean; +} + +/** + * Options for creating a replay connection. + */ +export interface ReplayConnectionOptions { + /** path to the replay file. */ + filePath: string; +} + +/** + * Info emitted when video input initializes. + */ +export interface VideoInputInitializationInfo { + /** device that was initialized. */ + description: VideoDevice; + /** time in seconds until first frame. */ + timeToFirstFrame: number; + /** whether initialization timed out. */ + initializationTimerExpired: boolean; + /** entropy value for the video feed. */ + entropy: number; +} + +/** + * Info emitted when audio input initializes. + */ +export interface AudioInputInitializationInfo { + /** device that was initialized. */ + description: AudioDevice; + /** time in seconds until initialized. */ + timeToInitialized: number; +} + +/** + * Video codec error details. + */ +export interface VideoCodecErrorInfo { + /** whether error occurred during encode or decode. */ + mode: "encode" | "decode"; + /** codec standard name. */ + codecStandard: string; + /** error message text. */ + message: string; + /** implementation name that failed. */ + implName: string; +} + +/** + * Codec information for connection setup. + */ +export interface ConnectionCodec { + /** codec name. */ + name: string; + /** payload type number. */ + payloadType: number; + /** priority order. */ + priority: number; + /** rtx payload type if applicable. */ + rtxPayloadType?: number; +} + +/** + * Connection transport initialization options. + */ +export interface ConnectionTransportOptions { + /** server address. */ + address: string; + /** server port. */ + port: number; + /** audio ssrc. */ + ssrc: number; + /** available encryption modes. */ + modes: string[]; + /** stream count. */ + streamCount?: number; + /** audio codecs. */ + audioCodec?: ConnectionCodec; + /** video codecs. */ + videoCodec?: ConnectionCodec; + /** rtx codecs. */ + rtxCodec?: ConnectionCodec; + /** experiment flags. */ + experiments?: string[]; +} + +/** + * Input mode options for voice activity or push-to-talk. + */ +export interface InputModeOptions { + /** VAD threshold in dB. */ + vadThreshold?: number; + /** whether to auto-adjust threshold. */ + vadAutoThreshold?: boolean; + /** whether to use krisp for VAD. */ + vadUseKrisp?: boolean; + /** krisp activation threshold. */ + vadKrispActivationThreshold?: number; + /** frames before speech detection. */ + vadLeading?: number; + /** frames after speech ends. */ + vadTrailing?: number; + /** PTT release delay in ms. */ + pttReleaseDelay?: number; +} + +/** + * Go live source configuration for streaming. + */ +export interface GoLiveSourceOptions { + /** quality settings. */ + quality: GoLiveQuality; + /** desktop description if streaming desktop. */ + desktopDescription?: DesktopDescription; + /** camera description if streaming camera. */ + cameraDescription?: { deviceId: string; }; +} + +/** + * Video stream parameter for simulcast configuration. + */ +export interface StreamParameter { + /** simulcast rid. */ + rid: string; + /** max bitrate. */ + maxBitrate?: number; + /** max framerate. */ + maxFrameRate?: number; + /** max resolution. */ + maxResolution?: { width: number; height: number; }; + /** quality percentage. */ + quality?: number; +} + +/** + * Automatic gain control configuration. + */ +export interface AutomaticGainControlConfig { + /** whether AGC is enabled, default true. */ + enabled: boolean; + /** whether to use AGC2 algorithm, default true. */ + useAGC2: boolean; + /** whether analog gain control is enabled, default false. */ + enableAnalog: boolean; + /** whether digital gain control is enabled, default true. */ + enableDigital: boolean; + /** headroom in decibels, default 5. */ + headroom_db: number; + /** maximum gain in decibels, default 50. */ + max_gain_db: number; + /** initial gain in decibels, default 15. */ + initial_gain_db: number; + /** max gain change per second in decibels, default 6. */ + max_gain_change_db_per_second: number; + /** max output noise level in dbfs, default -50. */ + max_output_noise_level_dbfs: number; + /** fixed gain in decibels, default 0. */ + fixed_gain_db: number; +} + +/** + * Active voice/video connection to a channel. + */ +export interface MediaEngineConnection { + /** context this connection belongs to. */ + context: MediaEngineContextType; + /** unique identifier for this connection. */ + mediaEngineConnectionId: string; + /** user id who owns this connection. */ + userId: string; + /** user id for stream context, undefined in default context. */ + streamUserId: string | undefined; + /** current connection state. */ + connectionState: ConnectionState; + /** whether self is muted. */ + selfMute: boolean; + /** whether self is deafened. */ + selfDeaf: boolean; + /** whether self video is enabled. */ + selfVideo: boolean; + /** whether this connection has been destroyed. */ + destroyed: boolean; + /** audio ssrc for this connection. */ + audioSSRC: number; + /** video ssrc for this connection. */ + videoSSRC: number; + /** local mute states keyed by user id. */ + localMutes: { [userId: string]: boolean; }; + /** local volume levels keyed by user id. */ + localVolumes: { [userId: string]: number; }; + /** local pan settings keyed by user id. */ + localPans: { [userId: string]: LocalPan; }; + /** disabled local video states keyed by user id. */ + disabledLocalVideos: { [userId: string]: boolean; }; + /** current voice bitrate in bps, default 64000. */ + voiceBitrate: number; + /** whether video is supported. */ + videoSupported: boolean; + /** video stream parameters. */ + videoStreamParameters: StreamParameter[]; + /** soundshare source id. */ + soundshareId: number | null; + /** whether soundshare is active. */ + soundshareActive: boolean; + /** whether echo cancellation is enabled. */ + echoCancellation: boolean; + /** whether noise suppression is enabled. */ + noiseSuppression: boolean; + /** automatic gain control configuration. */ + automaticGainControl: AutomaticGainControlConfig; + /** whether noise cancellation is enabled. */ + noiseCancellation: boolean; + /** whether QoS is enabled. */ + qos: boolean; + /** current input mode. */ + inputMode: string; + /** VAD threshold in dB, default -60. */ + vadThreshold: number; + /** whether VAD auto threshold is enabled, default true. */ + vadAutoThreshold: boolean; + /** PTT release delay in ms, default 20. */ + pttReleaseDelay: number; + /** keyframe interval in ms, default 0. */ + keyframeInterval: number; + /** attenuation factor 0-1, default 1 (no attenuation). */ + attenuationFactor: number; + /** whether to attenuate while self speaking. */ + attenuateWhileSpeakingSelf: boolean; + /** whether to attenuate while others speaking. */ + attenuateWhileSpeakingOthers: boolean; + + /** + * Initializes the connection with transport options. + * @param options transport options. + */ + initialize(options: ConnectionTransportOptions): void; + /** destroys this connection and cleans up resources. */ + destroy(): void; + /** + * Sets codecs for the connection. + * @param audioCodec audio codec name. + * @param videoCodec video codec name. + * @param rtxCodec rtx codec name. + */ + setCodecs(audioCodec: string, videoCodec: string, rtxCodec: string): void; + /** + * Gets connection statistics. + * @returns promise resolving to stats or null. + */ + getStats(): Promise; + /** + * Creates a remote user in the connection. + * @param userId user id. + * @param audioSSRC audio ssrc. + * @param videoSSRC video ssrc. + */ + createUser(userId: string, audioSSRC: number, videoSSRC: number): void; + /** + * Destroys a remote user from the connection. + * @param userId user id. + */ + destroyUser(userId: string): void; + /** + * Sets self mute state. + * @param mute whether to mute. + */ + setSelfMute(mute: boolean): void; + /** + * Gets self mute state. + * @returns true if muted. + */ + getSelfMute(): boolean; + /** + * Gets self deaf state. + * @returns true if deafened. + */ + getSelfDeaf(): boolean; + /** + * Sets self deaf state. + * @param deaf whether to deafen. + */ + setSelfDeaf(deaf: boolean): void; + /** + * Sets soundshare source for this connection. + * @param soundshareId soundshare source id. + * @param active whether to enable. + */ + setSoundshareSource(soundshareId: number, active: boolean): void; + /** + * Sets local mute for a user. + * @param userId user to mute. + * @param muted whether to mute. + */ + setLocalMute(userId: string, muted: boolean): void; + /** performs a fast UDP reconnect. */ + fastUdpReconnect(): void; + /** + * Gets number of fast UDP reconnects. + * @returns reconnect count or null if unsupported. + */ + getNumFastUdpReconnects(): number | null; + /** checks if remote was disconnected. */ + wasRemoteDisconnected(): void; + /** + * Disables receiving video from a user. + * @param userId user to disable video for. + * @param disabled whether to disable. + */ + setLocalVideoDisabled(userId: string, disabled: boolean): void; + /** + * Sets minimum jitter buffer level. + * @param level jitter buffer level. + */ + setMinimumJitterBufferLevel(level: number): void; + /** + * Sets postpone decode level. + * @param level decode level. + */ + setPostponeDecodeLevel(level: number): void; + /** + * Sets clip recording for a user. + * @param userId user id. + * @param type clip type. + * @param enabled whether enabled. + */ + setClipRecordUser(userId: string, type: string, enabled: boolean): void; + /** + * Sets clips keyframe interval. + * @param interval interval in ms. + */ + setClipsKeyFrameInterval(interval: number): void; + /** + * Sets viewer side clip. + * @param enabled whether enabled. + */ + setViewerSideClip(enabled: boolean): void; + /** + * Sets remote audio history duration. + * @param durationMs duration in ms. + */ + setRemoteAudioHistory(durationMs: number): void; + /** + * Sets quality decoupling. + * @param enabled whether enabled. + */ + setQualityDecoupling(enabled: boolean): void; + /** + * Gets local volume for a user. + * @param userId user id. + * @returns volume level. + */ + getLocalVolume(userId: string): number; + /** + * Sets local volume for a user. + * @param userId user to adjust. + * @param volume volume level 0-200, 100 is normal. + */ + setLocalVolume(userId: string, volume: number): void; + /** + * Sets stereo pan for a user. + * @param userId user to adjust. + * @param left left channel 0-1. + * @param right right channel 0-1. + */ + setLocalPan(userId: string, left: number, right: number): void; + /** + * Checks if currently attenuating. + * @returns true if attenuating. + */ + isAttenuating(): boolean; + /** + * Sets attenuation settings. + * @param factor attenuation factor 0-100. + * @param whileSpeakingSelf attenuate while self speaking. + * @param whileSpeakingOthers attenuate while others speaking. + */ + setAttenuation(factor: number, whileSpeakingSelf: boolean, whileSpeakingOthers: boolean): void; + /** + * Sets whether user can have priority speaker. + * @param userId user id. + * @param canHavePriority whether can have priority. + */ + setCanHavePriority(userId: string, canHavePriority: boolean): void; + /** + * Sets voice bitrate. + * @param bitrate bitrate in bps. + */ + setBitRate(bitrate: number): void; + /** + * Sets voice bitrate. + * @param bitrate bitrate in bps. + */ + setVoiceBitRate(bitrate: number): void; + /** + * Sets camera bitrate. + * @param maxBitrate max bitrate. + * @param minBitrate min bitrate. + * @param targetBitrate target bitrate. + */ + setCameraBitRate(maxBitrate: number, minBitrate: number | null, targetBitrate: number | null): void; + /** + * Sets echo cancellation. + * @param enabled whether enabled. + */ + setEchoCancellation(enabled: boolean): void; + /** + * Sets noise suppression. + * @param enabled whether enabled. + */ + setNoiseSuppression(enabled: boolean): void; + /** + * Sets automatic gain control. + * @param config AGC configuration. + */ + setAutomaticGainControl(config: AutomaticGainControlConfig): void; + /** + * Sets noise cancellation. + * @param enabled whether enabled. + */ + setNoiseCancellation(enabled: boolean): void; + /** + * Sets noise cancellation during processing. + * @param enabled whether enabled. + */ + setNoiseCancellationDuringProcessing(enabled: boolean): void; + /** + * Sets noise cancellation after processing. + * @param enabled whether enabled. + */ + setNoiseCancellationAfterProcessing(enabled: boolean): void; + /** + * Sets VAD after WebRTC. + * @param enabled whether enabled. + */ + setVADAfterWebrtc(enabled: boolean): void; + /** + * Gets noise cancellation state. + * @returns true if enabled. + */ + getNoiseCancellation(): boolean; + /** + * Gets current voice filter id. + * @returns voice filter id or null. + */ + getVoiceFilterId(): string | null; + /** + * Sets voice filter id. + * @param filterId filter id or null. + */ + setVoiceFilterId(filterId: string | null): void; + /** + * Sets QoS enabled. + * @param enabled whether enabled. + */ + setQoS(enabled: boolean): void; + /** + * Sets soundshare discard rear channels. + * @param discard whether to discard. + */ + setSoundshareDiscardRearChannels(discard: boolean): void; + /** + * Sets input mode. + * @param mode input mode. + * @param options mode options. + */ + setInputMode(mode: string, options: InputModeOptions): void; + /** + * Sets silence threshold. + * @param threshold threshold value. + */ + setSilenceThreshold(threshold: number): void; + /** + * Sets force audio input. + * @param force whether to force. + * @param playTone whether to play tone. + * @param isSpeaking whether speaking. + */ + setForceAudioInput(force: boolean, playTone?: boolean, isSpeaking?: boolean): void; + /** + * Sets speaking flags for a user. + * @param userId user id. + * @param flags speaking flags. + */ + setSpeakingFlags(userId: string, flags: number): void; + /** clears all speaking states. */ + clearAllSpeaking(): void; + /** + * Sets encryption mode. + * @param mode encryption mode. + * @param secretKey secret key. + */ + setEncryption(mode: string, secretKey: Uint8Array): void; + /** + * Sets reconnect interval. + * @param interval interval in ms. + */ + setReconnectInterval(interval: number): void; + /** + * Sets keyframe interval. + * @param interval interval in ms. + */ + setKeyframeInterval(interval: number): void; + /** + * Sets video quality measurement. + * @param enabled whether enabled. + */ + setVideoQualityMeasurement(enabled: boolean): void; + /** + * Sets video encoder experiments. + * @param experiments experiment config. + */ + setVideoEncoderExperiments(experiments: object): void; + /** + * Sets video broadcast state. + * @param broadcast whether broadcasting. + */ + setVideoBroadcast(broadcast: boolean): void; + /** + * Sets go live source. + * @param source source options. + */ + setGoLiveSource(source: GoLiveSourceOptions): void; + /** clears go live devices. */ + clearGoLiveDevices(): void; + /** clears the desktop source from this connection. */ + clearDesktopSource(): void; + /** + * Sets desktop source status callback. + * @param callback callback function. + */ + setDesktopSourceStatusCallback(callback: (status: string) => void): void; + /** + * Checks if connection has a desktop source. + * @returns true if streaming desktop. + */ + hasDesktopSource(): boolean; + /** + * Sets desktop encoding options. + * @param width width. + * @param height height. + * @param framerate framerate. + */ + setDesktopEncodingOptions(width: number, height: number, framerate: number): void; + /** + * Sets SDP. + * @param sdp SDP string. + */ + setSDP(sdp: string): void; + /** + * Sets remote video sink wants. + * @param wants sink wants config. + */ + setRemoteVideoSinkWants(wants: object): void; + /** + * Sets local video sink wants. + * @param wants sink wants config. + */ + setLocalVideoSinkWants(wants: object): void; + /** + * Starts samples local playback. + * @param id playback id. + * @param buffer audio buffer. + * @param options playback options. + * @param callback completion callback. + */ + startSamplesLocalPlayback(id: string, buffer: AudioBuffer, options: object, callback: (error: number, message: string) => void): void; + /** stops all samples local playback. */ + stopAllSamplesLocalPlayback(): void; + /** + * Stops samples local playback. + * @param id playback id. + */ + stopSamplesLocalPlayback(id: string): void; + /** + * Sets bandwidth estimation experiments. + * @param experiments experiment config. + */ + setBandwidthEstimationExperiments(experiments: object): void; + /** + * Updates video quality core. + * @param options quality options. + * @param reason update reason. + */ + updateVideoQualityCore(options: object, reason: string): void; + /** + * Sets stream parameters. + * @param params stream parameters. + * @returns promise. + */ + setStreamParameters(params: StreamParameter[]): Promise; + /** applies video transport options. */ + applyVideoTransportOptions(): void; + /** + * Chooses encryption mode. + * @param preferred preferred modes. + * @param available available modes. + * @returns chosen mode. + */ + chooseEncryptionMode(preferred: string[], available: string[]): string; + /** + * Gets user options. + * @returns user options array. + */ + getUserOptions(): object[]; + /** + * Creates input mode options. + * @returns input mode options. + */ + createInputModeOptions(): InputModeOptions; + /** + * Gets attenuation options. + * @returns attenuation options. + */ + getAttenuationOptions(): object; + /** + * Gets codec params. + * @param codec codec name. + * @param isHardware whether hardware codec. + * @returns codec params. + */ + getCodecParams(codec: string, isHardware: boolean): object; + /** + * Gets codec options. + * @param audioCodec audio codec. + * @param videoCodec video codec. + * @param rtxCodec rtx codec. + * @returns codec options. + */ + getCodecOptions(audioCodec: string, videoCodec: string, rtxCodec: string): object; + /** + * Gets keyframe interval. + * @returns interval in ms. + */ + getKeyFrameInterval(): number; + /** + * Gets connection transport options. + * @returns transport options. + */ + getConnectionTransportOptions(): object; + /** + * Sets stream (not implemented). + * @param stream media stream. + */ + setStream(stream: MediaStream): void; + /** + * Gets user id by ssrc. + * @param ssrc ssrc value. + */ + getUserIdBySsrc(ssrc: number): void; + /** + * Prepares secure frames transition. + * @param transitionId transition id. + * @param epoch epoch number. + * @param callback callback function. + */ + prepareSecureFramesTransition(transitionId: number, epoch: number, callback: () => void): void; + /** + * Prepares secure frames epoch. + * @param epoch epoch number. + * @param data epoch data. + * @param callback callback function. + */ + prepareSecureFramesEpoch(epoch: number, data: Uint8Array, callback: () => void): void; + /** + * Executes secure frames transition. + * @param transitionId transition id. + */ + executeSecureFramesTransition(transitionId: number): void; + /** + * Gets MLS key package. + * @param callback callback receiving key package. + */ + getMLSKeyPackage(callback: (keyPackage: Uint8Array) => void): void; + /** + * Updates MLS external sender. + * @param sender external sender data. + */ + updateMLSExternalSender(sender: Uint8Array): void; + /** + * Processes MLS proposals. + * @param proposals proposals data. + * @param callback callback function. + */ + processMLSProposals(proposals: Uint8Array, callback: () => void): void; + /** + * Prepares MLS commit transition. + * @param transitionId transition id. + * @param commit commit data. + * @param callback callback function. + */ + prepareMLSCommitTransition(transitionId: number, commit: Uint8Array, callback: () => void): void; + /** + * Processes MLS welcome. + * @param transitionId transition id. + * @param welcome welcome data. + * @param callback callback function. + */ + processMLSWelcome(transitionId: number, welcome: Uint8Array, callback: () => void): void; + /** + * Gets MLS pairwise fingerprint. + * @param userId user id. + * @param version version. + * @param callback callback receiving fingerprint. + */ + getMLSPairwiseFingerprint(userId: string, version: number, callback: (fingerprint: Uint8Array) => void): void; + /** + * Presents desktop source picker. + * @param options picker options. + */ + presentDesktopSourcePicker(options: object): void; + /** + * Merges users. + * @param users user merge data. + */ + mergeUsers(users: object[]): void; + /** + * Gets whether there is an active video output sink. + * @param userId user id. + * @returns true if has active sink. + */ + getHasActiveVideoOutputSink(userId: string): boolean; + /** + * Sets whether there is an active video output sink. + * @param userId user id. + * @param hasActiveSink whether sink is active. + * @param reason reason for the change. + */ + setHasActiveVideoOutputSink(userId: string, hasActiveSink: boolean, reason: string): void; + /** + * Applies quality constraints to video. + * @param constraints quality constraints object. + * @param ssrc optional ssrc to apply to. + * @returns quality manager result. + */ + applyQualityConstraints(constraints?: object, ssrc?: number): object; + /** + * Applies video quality mode preset. + * @param mode quality mode to apply. + */ + applyVideoQualityMode(mode: number): void; + /** + * Configures go live simulcast settings. + * @param enabled whether simulcast is enabled. + * @param options simulcast options. + */ + configureGoLiveSimulcast(enabled: boolean, options: object): void; + /** + * Emits connection stats. + * @returns promise resolving to stats or null. + */ + emitStats(): Promise; + /** + * Gets whether active output sink tracking is enabled. + * @returns true if enabled. + */ + getActiveOutputSinkTrackingEnabled(): boolean; + /** + * Gets local mute state for a user. + * @param userId user id. + * @returns true if muted. + */ + getLocalMute(userId: string): boolean; + /** + * Gets local video disabled state for a user. + * @param userId user id. + * @returns true if disabled. + */ + getLocalVideoDisabled(userId: string): boolean; + /** + * Gets local video quality want for a ssrc. + * @param ssrc optional ssrc. + * @returns quality want object. + */ + getLocalWant(ssrc?: number): object; + /** + * Gets remote video sink pixel count for a user. + * @param userId user id. + * @returns pixel count. + */ + getRemoteVideoSinkPixelCount(userId: string): number; + /** + * Gets remote video sink wants for a user. + * @param userId user id. + * @returns sink wants object. + */ + getRemoteVideoSinkWants(userId: string): object; + /** + * Gets current stream parameters. + * @returns array of stream parameters. + */ + getStreamParameters(): StreamParameter[]; + /** + * Handles desktop source ended event. + * @param reason end reason. + * @param errorCode error code. + */ + handleDesktopSourceEnded(reason: string, errorCode: number): void; + /** + * Handles first frame received. + * @param userId user id. + * @param ssrc ssrc. + * @param stats stats object. + */ + handleFirstFrame(userId: string, ssrc: number, stats: object): void; + /** + * Handles first frame encrypted stats. + * @param stats stats object. + */ + handleFirstFrameEncryptedStats(stats: object): void; + /** + * Handles first frame stats. + * @param stats stats object. + */ + handleFirstFrameStats(stats: object): void; + /** + * Handles MLS failure. + * @param error error string. + * @param code error code. + */ + handleMLSFailure(error: string, code: number): void; + /** + * Handles native mute changed. + * @param muted new mute state. + */ + handleNativeMuteChanged(muted: boolean): void; + /** + * Handles native mute toggled from system. + */ + handleNativeMuteToggled(): void; + /** + * Handles new listener for native events. + * @param event event name. + */ + handleNewListenerNative(event: string): void; + /** + * Handles no input detected. + * @param hasInput whether input is detected. + */ + handleNoInput(hasInput: boolean): void; + /** + * Handles ping response. + * @param latency latency in ms. + * @param hostname hostname. + * @param port port number. + */ + handlePing(latency: number, hostname: string, port: number): void; + /** + * Handles ping timeout. + * @param hostname hostname. + * @param port port number. + * @param attempts attempt count. + * @param timeout timeout in ms. + */ + handlePingTimeout(hostname: string, port: number, attempts: number, timeout: number): void; + /** + * Handles RTCP message. + * @param type message type. + * @param data message data. + */ + handleRTCPMessage(type: string, data: string): void; + /** + * Handles soundshare attached. + * @param attached whether attached. + */ + handleSoundshare(attached: boolean): void; + /** + * Handles soundshare ended. + */ + handleSoundshareEnded(): void; + /** + * Handles soundshare failed. + * @param failureCode failure code. + * @param failureReason failure reason. + * @param willRetry whether it will retry. + */ + handleSoundshareFailed(failureCode: number, failureReason: string, willRetry: boolean): void; + /** + * Handles speaking flags change. + * @param userId user id. + * @param flags speaking flags. + * @param ssrc ssrc. + */ + handleSpeakingFlags(userId: string, flags: number, ssrc: number): void; + /** + * Handles native speaking event. + * @param userId user id. + * @param speaking speaking state or flags. + * @param ssrc ssrc. + */ + handleSpeakingNative(userId: string, speaking: boolean | number, ssrc: number): void; + /** + * Handles speaking while muted event. + */ + handleSpeakingWhileMuted(): void; + /** + * Handles stats received. + * @param stats stats object. + */ + handleStats(stats: object): void; + /** + * Handles video stream update. + * @param userId user id. + * @param ssrc ssrc. + * @param active whether active. + * @param streams stream array. + */ + handleVideo(userId: string, ssrc: number, active: boolean, streams: object[]): void; + /** + * Handles video encoder fallback. + * @param codecName codec that failed. + */ + handleVideoEncoderFallback(codecName: string): void; + /** + * Initializes stream parameters. + * @param parameters initial parameters. + */ + initializeStreamParameters(parameters: StreamParameter[]): void; + /** + * Callback when desktop encoding options are set. + * @param width width. + * @param height height. + * @param framerate framerate. + */ + onDesktopEncodingOptionsSet(width: number, height: number, framerate: number): void; + /** + * Overwrites quality for testing. + * @param quality quality value. + */ + overwriteQualityForTesting(quality: number): void; + /** + * Sets the connection state. + * @param state new connection state. + */ + setConnectionState(state: ConnectionState): void; + /** + * Sets an experiment flag. + * @param flag flag name. + * @param enabled whether enabled. + */ + setExperimentFlag(flag: string, enabled: boolean): void; + /** + * Sets whether to use electron video. + * @param use whether to use. + */ + setUseElectronVideo(use: boolean): void; + /** + * Updates video quality settings. + * @param ssrc optional ssrc to update. + */ + updateVideoQuality(ssrc?: number): void; +} + +/** + * Low-level media engine for audio/video processing. + * Handles device enumeration, encoding/decoding, and connections. + */ +export interface MediaEngine { + /** camera preview component. */ + Camera: React.ComponentType<{ disabled?: boolean; deviceId?: string; width?: number; height?: number; }>; + /** video display component. */ + Video: React.ComponentType & { onContainerResized: () => void; }; + /** set of active voice/video connections. */ + connections: Set; + + /** + * Registers a listener for device changes. + * @param event event name. + * @param listener callback receiving device lists. + */ + on(event: "DeviceChange", listener: (inputDevices: AudioDevice[], outputDevices: AudioDevice[], videoDevices: VideoDevice[]) => void): this; + /** + * Registers a listener for volume changes. + * @param event event name. + * @param listener callback receiving input and output volumes. + */ + on(event: "VolumeChange", listener: (inputVolume: number, outputVolume: number) => void): this; + /** + * Registers a listener for voice activity. + * @param event event name. + * @param listener callback receiving user id and activity level. + */ + on(event: "VoiceActivity", listener: (userId: string, voiceActivity: number) => void): this; + /** + * Registers a listener for desktop source end. + * @param event event name. + * @param listener callback receiving reason and error code. + */ + on(event: "DesktopSourceEnd", listener: (reason: string, errorCode: number) => void): this; + /** + * Registers a listener for audio permission changes. + * @param event event name. + * @param listener callback receiving granted state. + */ + on(event: "AudioPermission", listener: (granted: boolean) => void): this; + /** + * Registers a listener for video permission changes. + * @param event event name. + * @param listener callback receiving granted state. + */ + on(event: "VideoPermission", listener: (granted: boolean) => void): this; + /** + * Registers a listener for video input initialization. + * @param event event name. + * @param listener callback receiving initialization info. + */ + on(event: "VideoInputInitialized", listener: (info: VideoInputInitializationInfo) => void): this; + /** + * Registers a listener for audio input initialization. + * @param event event name. + * @param listener callback receiving initialization info. + */ + on(event: "AudioInputInitialized", listener: (info: AudioInputInitializationInfo) => void): this; + /** + * Registers a listener for clips init failure. + * @param event event name. + * @param listener callback receiving error message and app name. + */ + on(event: "ClipsInitFailure", listener: (errorMessage: string, applicationName: string) => void): this; + /** + * Registers a listener for clips recording ended. + * @param event event name. + * @param listener callback receiving source id and soundshare id. + */ + on(event: "ClipsRecordingEnded", listener: (sourceId: string, soundshareId: number) => void): this; + /** + * Registers a listener for native screen share picker update. + * @param event event name. + * @param listener callback receiving existing state and content. + */ + on(event: "NativeScreenSharePickerUpdate", listener: (existing: boolean, content: string) => void): this; + /** + * Registers a listener for native screen share picker cancel. + * @param event event name. + * @param listener callback receiving existing state. + */ + on(event: "NativeScreenSharePickerCancel", listener: (existing: boolean) => void): this; + /** + * Registers a listener for native screen share picker error. + * @param event event name. + * @param listener callback receiving error string. + */ + on(event: "NativeScreenSharePickerError", listener: (error: string) => void): this; + /** + * Registers a listener for audio device module error. + * @param event event name. + * @param listener callback receiving module, code and device name. + */ + on(event: "AudioDeviceModuleError", listener: (module: string, code: number, deviceName: string) => void): this; + /** + * Registers a listener for video codec error. + * @param event event name. + * @param listener callback receiving error info. + */ + on(event: "VideoCodecError", listener: (info: VideoCodecErrorInfo) => void): this; + /** + * Registers a listener for system microphone mode change. + * @param event event name. + * @param listener callback receiving new mode. + */ + on(event: "SystemMicrophoneModeChange", listener: (mode: string) => void): this; + /** + * Registers a listener for events without arguments. + * @param event event name. + * @param listener callback with no arguments. + */ + on(event: "Destroy" | "Silence" | "WatchdogTimeout" | "ClipsRecordingRestartNeeded" | "VoiceFiltersFailed", listener: () => void): this; + /** + * Registers a one-time listener for device changes. + * @param event event name. + * @param listener callback receiving device lists. + */ + once(event: "DeviceChange", listener: (inputDevices: AudioDevice[], outputDevices: AudioDevice[], videoDevices: VideoDevice[]) => void): this; + /** + * Registers a one-time listener for volume changes. + * @param event event name. + * @param listener callback receiving input and output volumes. + */ + once(event: "VolumeChange", listener: (inputVolume: number, outputVolume: number) => void): this; + /** + * Registers a one-time listener for events without arguments. + * @param event event name. + * @param listener callback with no arguments. + */ + once(event: "Destroy" | "Silence" | "WatchdogTimeout" | "ClipsRecordingRestartNeeded" | "VoiceFiltersFailed", listener: () => void): this; + /** + * Removes a listener for device changes. + * @param event event name. + * @param listener callback to remove. + */ + off(event: "DeviceChange", listener: (inputDevices: AudioDevice[], outputDevices: AudioDevice[], videoDevices: VideoDevice[]) => void): this; + /** + * Removes a listener for volume changes. + * @param event event name. + * @param listener callback to remove. + */ + off(event: "VolumeChange", listener: (inputVolume: number, outputVolume: number) => void): this; + /** + * Removes a listener for events without arguments. + * @param event event name. + * @param listener callback to remove. + */ + off(event: "Destroy" | "Silence" | "WatchdogTimeout" | "ClipsRecordingRestartNeeded" | "VoiceFiltersFailed", listener: () => void): this; + /** + * Removes all listeners for an event. + * @param event event name, or all if omitted. + */ + removeAllListeners(event?: MediaEngineEvent): this; + /** + * Gets the number of listeners for an event. + * @param event event name. + * @returns listener count. + */ + listenerCount(event: MediaEngineEvent): number; + + /** + * Applies video background filter settings. + * @param settings filter settings to apply. + */ + applyMediaFilterSettings(settings: MediaFilterSettings): Promise; + /** + * Creates a new voice connection. + * @param userId user id for the connection. + * @param channelId channel to connect to. + * @param options connection options. + * @returns the created connection. + */ + connect(userId: string, channelId: string, options: ConnectionOptions): MediaEngineConnection; + /** + * Checks if there are no active connections. + * @returns true if no connections exist. + */ + connectionsEmpty(): boolean; + /** + * Creates a replay connection from a file. + * @param userId user id for the connection. + * @param options replay options including file path. + * @returns the created connection or null if unsupported. + */ + createReplayConnection(userId: string, options: ReplayConnectionOptions): MediaEngineConnection | null; + /** destroys the media engine and all connections. */ + destroy(): void; + /** + * Iterates over all connections. + * @param callback called for each connection. + * @param context optional context filter, only iterates connections in this context. + */ + eachConnection(callback: (connection: MediaEngineConnection) => void, context?: MediaEngineContextType): void; + /** + * Enables the media engine. + * @returns promise that resolves when enabled. + */ + enable(): Promise; + /** + * Exports a clip as a blob. + * @param clipId clip identifier. + * @param userId user who owns the clip. + * @returns promise resolving to the clip blob. + */ + exportClip(clipId: string, userId: string): Promise; + /** + * Fetches async resources like DAVE keys. + * @param options fetch options. + */ + fetchAsyncResources(options: { fetchDave?: boolean; }): Promise; + + /** + * Gets available audio input devices. + * @returns promise resolving to device list. + */ + getAudioInputDevices(): Promise; + /** + * Gets the current audio layer name. + * @returns audio layer identifier. + */ + getAudioLayer(): string; + /** + * Gets available audio output devices. + * @returns promise resolving to device list. + */ + getAudioOutputDevices(): Promise; + /** + * Gets the current audio subsystem. + * @returns active audio subsystem. + */ + getAudioSubsystem(): AudioSubsystem; + /** + * Gets codec capabilities as JSON string. + * @param callback called with capabilities string. + */ + getCodecCapabilities(callback: (capabilities: string) => void): void; + /** + * Gets a survey of supported codecs. + * @returns promise resolving to codec info. + */ + getCodecSurvey(): Promise<{ codecs: CodecInfo[]; }>; + /** + * Gets whether debug logging is enabled. + * @returns true if enabled. + */ + getDebugLogging(): boolean; + /** + * Gets the current desktop source. + * @returns promise that rejects with NO_STREAM error if not streaming. + */ + getDesktopSource(): Promise; + /** + * Gets whether loopback is active. + * @returns always false for native engine. + */ + getLoopback(): boolean; + /** + * Gets MLS signing key for e2ee. + * @param userId user id. + * @param guildId guild id. + * @returns promise resolving to key and signature. + */ + getMLSSigningKey(userId: string, guildId: string): Promise; + /** + * Gets noise cancellation statistics. + * @returns promise resolving to stats or null if disabled. + */ + getNoiseCancellationStats(): Promise; + /** + * Gets screen preview thumbnails. + * @param width thumbnail width. + * @param height thumbnail height. + * @returns promise resolving to preview list. + */ + getScreenPreviews(width: number, height: number): Promise; + /** + * Gets supported bandwidth estimation experiments. + * @param callback called with experiment list. + */ + getSupportedBandwidthEstimationExperiments(callback: (experiments: string[]) => void): void; + /** + * Gets supported secure frames protocol version. + * @returns protocol version number. + */ + getSupportedSecureFramesProtocolVersion(): number; + /** + * Gets supported video codecs. + * @param callback called with codec name list. + */ + getSupportedVideoCodecs(callback: (codecs: string[]) => void): void; + /** + * Gets system microphone mode. + * @returns promise resolving to mode string. + */ + getSystemMicrophoneMode(): Promise; + /** + * Gets current video input device id. + * @returns device id or "disabled". + */ + getVideoInputDeviceId(): string; + /** + * Gets available video input devices. + * @returns promise resolving to device list. + */ + getVideoInputDevices(): Promise; + /** + * Gets window preview thumbnails. + * @param width thumbnail width. + * @param height thumbnail height. + * @returns promise resolving to preview list. + */ + getWindowPreviews(width: number, height: number): Promise; + + /** signals user interaction to enable autoplay. */ + interact(): void; + /** + * Shows native screen share picker. + * @param options picker options. + */ + presentNativeScreenSharePicker(options?: string): void; + /** + * Queues an audio subsystem switch. + * @param subsystem subsystem to switch to. + */ + queueAudioSubsystem(subsystem: AudioSubsystem): void; + /** + * Ranks RTC regions by latency. + * @param regions region ids to test. + * @returns promise resolving to sorted region ids. + */ + rankRtcRegions(regions: string[]): Promise; + /** releases native desktop video source picker stream. */ + releaseNativeDesktopVideoSourcePickerStream(): void; + + /** + * Saves a clip. + * @param clipId clip identifier. + * @param userId user who owns the clip. + * @returns promise resolving to saved clip info. + */ + saveClip(clipId: string, userId: string): Promise; + /** + * Saves a clip for another user. + * @param clipId clip identifier. + * @param userId user to save for. + * @param options clip metadata. + * @returns promise resolving to saved clip info. + */ + saveClipForUser(clipId: string, userId: string, options: ClipMetadata): Promise; + /** + * Saves a screenshot. + * @param channelId channel context. + * @param userId user context. + * @param width width or null for auto. + * @param height height or null for auto. + * @param options screenshot metadata. + * @returns promise resolving to screenshot info. + */ + saveScreenshot(channelId: string, userId: string, width: number | null, height: number | null, options: ClipMetadata): Promise; + + /** + * Enables or disables AEC dump. + * @param enabled whether to enable. + */ + setAecDump(enabled: boolean): void; + /** + * Sets callback for async clips source deinit. + * @param callback callback function. + */ + setAsyncClipsSourceDeinit(callback: () => void): void; + /** + * Sets callback for async video input device init. + * @param callback callback function. + */ + setAsyncVideoInputDeviceInit(callback: () => void): void; + /** + * Sets whether to bypass system audio input processing. + * @param bypass whether to bypass. + */ + setAudioInputBypassSystemProcessing(bypass: boolean): void; + /** + * Sets the audio input device. + * @param deviceId device identifier. + */ + setAudioInputDevice(deviceId: string): void; + /** + * Sets the audio output device. + * @param deviceId device identifier. + */ + setAudioOutputDevice(deviceId: string): void; + /** + * Sets the audio subsystem. + * @param subsystem subsystem to use. + */ + setAudioSubsystem(subsystem: AudioSubsystem): void; + /** + * Enables or disables AV1 codec. + * @param enabled whether to enable. + */ + setAv1Enabled(enabled: boolean): void; + /** + * Sets clip buffer length in seconds. + * @param seconds buffer duration. + */ + setClipBufferLength(seconds: number): void; + /** + * Enables or disables clips ML pipeline. + * @param enabled whether to enable. + */ + setClipsMLPipelineEnabled(enabled: boolean): void; + /** + * Enables or disables a clips ML pipeline type. + * @param type pipeline type. + * @param enabled whether to enable. + */ + setClipsMLPipelineTypeEnabled(type: string, enabled: boolean): void; + /** + * Sets clips quality settings. + * @param resolution resolution height. + * @param frameRate frame rate. + * @param hdr whether HDR is enabled. + * @returns true if settings were applied. + */ + setClipsQualitySettings(resolution: number, frameRate: number, hdr: boolean): boolean; + /** + * Sets or clears the clips source. + * @param source source config or null to clear. + */ + setClipsSource(source: ClipsSource | null): void; + /** + * Enables or disables debug logging. + * @param enabled whether to enable. + */ + setDebugLogging(enabled: boolean): void; + /** + * Sets or clears the go live source. + * @param source source config or null to clear. + * @param context context to apply to, defaults to "default". + */ + setGoLiveSource(source: GoLiveSource | null, context?: MediaEngineContextType): void; + /** + * Enables or disables H264 codec. + * @param enabled whether to enable. + */ + setH264Enabled(enabled: boolean): void; + /** + * Enables or disables H265 codec. + * @param enabled whether to enable. + */ + setH265Enabled(enabled: boolean): void; + /** + * Sets whether device has fullband performance. + * @param has whether it has fullband performance. + */ + setHasFullbandPerformance(has: boolean): void; + /** + * Sets input volume. + * @param volume volume 0-100. + */ + setInputVolume(volume: number): void; + /** + * Enables loopback for testing. + * @param reason reason for enabling loopback. + * @param options loopback audio options. + */ + setLoopback(reason: string, options: LoopbackOptions): void; + /** + * Sets max sync delay override. + * @param delay delay in milliseconds. + */ + setMaxSyncDelayOverride(delay: number): void; + /** + * Sets maybe preprocess mute state. + * @param mute whether to mute. + */ + setMaybePreprocessMute(mute: boolean): void; + /** + * Sets native desktop video source picker active state. + * @param active whether picker is active. + */ + setNativeDesktopVideoSourcePickerActive(active: boolean): void; + /** + * Enables or disables noise cancellation stats. + * @param enabled whether to enable. + */ + setNoiseCancellationEnableStats(enabled: boolean): void; + /** + * Sets whether to offload ADM controls. + * @param offload whether to offload. + */ + setOffloadAdmControls(offload: boolean): void; + /** + * Sets callback for video container resize. + * @param callback callback function. + */ + setOnVideoContainerResized(callback: () => void): void; + /** + * Sets output volume. + * @param volume volume 0-100. + */ + setOutputVolume(volume: number): void; + /** + * Enables or disables sidechain compression. + * @param enabled whether to enable. + */ + setSidechainCompression(enabled: boolean): void; + /** + * Sets sidechain compression strength. + * @param strength strength 0-100. + */ + setSidechainCompressionStrength(strength: number): void; + /** + * Sets soundshare source. + * @param soundshareId soundshare source id. + * @param active whether to enable. + * @param context context to apply to, defaults to "default". + */ + setSoundshareSource(soundshareId: number, active: boolean, context?: MediaEngineContextType): void; + /** + * Sets the video input device. + * @param deviceId device identifier. + */ + setVideoInputDevice(deviceId: string): Promise; + + /** + * Checks if a connection should broadcast video. + * @param connection connection to check. + * @returns true if should broadcast. + */ + shouldConnectionBroadcastVideo(connection: MediaEngineConnection): boolean; + /** + * Shows system capture configuration UI. + * @param options options including display id. + */ + showSystemCaptureConfigurationUI(options: { displayId?: string; }): void; + + /** starts AEC dump recording. */ + startAecDump(): void; + /** + * Starts local audio recording. + * @param options recording options. + */ + startLocalAudioRecording(options: AudioRecordingOptions): Promise; + /** + * Starts recording raw audio samples. + * @param options sample options. + */ + startRecordingRawSamples(options: RawSamplesOptions): void; + /** stops AEC dump recording. */ + stopAecDump(): void; + /** + * Stops local audio recording. + * @param callback called with success and filepath. + */ + stopLocalAudioRecording(callback: (success: boolean, filepath: string) => void): void; + /** stops recording raw audio samples. */ + stopRecordingRawSamples(): void; + + /** + * Checks if media engine is supported. + * @returns true if supported. + */ + supported(): boolean; + /** + * Checks if a feature is supported. + * @param feature feature to check. + * @returns true if supported. + */ + supports(feature: MediaEngineFeature): boolean; + /** + * Updates clip metadata. + * @param clipId clip identifier. + * @param metadata new metadata. + */ + updateClipMetadata(clipId: string, metadata: ClipMetadata): Promise; + /** ticks the watchdog timer. */ + watchdogTick(): void; + /** + * Writes audio debug state to file. + * @returns promise that resolves when written. + */ + writeAudioDebugState(): Promise; +} + +/** + * Persisted media engine settings for a context. + */ +export interface MediaEngineSettings { + /** current voice mode (PTT or VAD), default VOICE_ACTIVITY. */ + mode: VoiceMode; + /** voice mode configuration options. */ + modeOptions: ModeOptions; + /** settings version for vadUseKrisp migration. */ + vadUseKrispSettingVersion: number; + /** settings version for ncUseKrisp migration. */ + ncUseKrispSettingVersion: number; + /** settings version for ncUseKrispjs migration. */ + ncUseKrispjsSettingVersion: number; + /** whether self is muted, default false. */ + mute: boolean; + /** whether self is deafened, default false. */ + deaf: boolean; + /** whether echo cancellation is enabled, default false. */ + echoCancellation: boolean; + /** whether noise suppression is enabled, default false. */ + noiseSuppression: boolean; + /** whether automatic gain control is enabled, default true. */ + automaticGainControl: boolean; + /** whether krisp noise cancellation is enabled, default false. */ + noiseCancellation: boolean; + /** whether to bypass system audio input processing, default false. */ + bypassSystemInputProcessing: boolean; + /** most recently requested voice filter id, null if none. */ + mostRecentlyRequestedVoiceFilter: string | null; + /** whether voice filter playback is enabled, default false. */ + voiceFilterPlaybackEnabled: boolean; + /** version for hardware enabled migration. */ + hardwareEnabledVersion: number; + /** whether silence warning is enabled, default true. */ + silenceWarning: boolean; + /** attenuation level 0-100 for other users when speaking, default 0. */ + attenuation: number; + /** whether to attenuate others when self is speaking, default false. */ + attenuateWhileSpeakingSelf: boolean; + /** whether to attenuate others when others are speaking, default true. */ + attenuateWhileSpeakingOthers: boolean; + /** per-user local mute states, keyed by user id. */ + localMutes: { [userId: string]: boolean; }; + /** per-user disabled local video states, keyed by user id. */ + disabledLocalVideos: { [userId: string]: boolean; }; + /** per-user video toggle states, keyed by user id. */ + videoToggleStateMap: { [userId: string]: VideoToggleState; }; + /** per-user local volume levels 0-200, keyed by user id, default 100. */ + localVolumes: { [userId: string]: number; }; + /** per-user stereo pan settings, keyed by user id. */ + localPans: { [userId: string]: LocalPan; }; + /** microphone input volume 0-100, default 100. */ + inputVolume: number; + /** speaker output volume 0-100, default 100. */ + outputVolume: number; + /** selected audio input device id. */ + inputDeviceId: string; + /** selected audio output device id. */ + outputDeviceId: string; + /** selected video input device id. */ + videoDeviceId: string; + /** whether QoS packet priority is enabled. */ + qos: boolean; + /** whether QoS has been migrated. */ + qosMigrated: boolean; + /** whether video hook is enabled. */ + videoHook: boolean; + /** experimental soundshare setting, null if not set. */ + experimentalSoundshare2: boolean | null; + /** system screenshare picker setting, null if not set. */ + useSystemScreensharePicker: boolean | null; + /** whether H265 codec is enabled. */ + h265Enabled: boolean; + /** whether VAD threshold has been migrated. */ + vadThrehsoldMigrated: boolean; + /** whether AEC dump is enabled. */ + aecDumpEnabled: boolean; + /** whether sidechain compression is enabled. */ + sidechainCompression: boolean; + /** settings version for sidechain compression migration. */ + sidechainCompressionSettingVersion: number; + /** sidechain compression strength 0-100, default 50. */ + sidechainCompressionStrength: number; + /** whether automatic audio subsystem selection is enabled. */ + automaticAudioSubsystem: boolean; + /** active input profile or null. */ + activeInputProfile: InputProfile | null; +} + +/** + * Complete serializable state of MediaEngineStore. + */ +export interface MediaEngineState { + /** settings for each context type, keyed by context. */ + settingsByContext: { [context in MediaEngineContextType]: MediaEngineSettings; }; + /** available audio input devices, keyed by device id. */ + inputDevices: { [deviceId: string]: AudioDevice; }; + /** available audio output devices, keyed by device id. */ + outputDevices: { [deviceId: string]: AudioDevice; }; + /** supported features, keyed by feature name. */ + appSupported: { [feature in MediaEngineFeature]?: boolean; }; + /** whether krisp module is loaded. */ + krispModuleLoaded: boolean; + /** krisp module version or undefined. */ + krispVersion: string | undefined; + /** krisp suppression level or undefined. */ + krispSuppressionLevel: number | undefined; + /** current go live source or undefined. */ + goLiveSource: GoLiveSource | undefined; + /** context for go live. */ + goLiveContext: MediaEngineContextType; +} + +/** + * Keyboard shortcut binding. + */ +export interface Shortcut { + /** action the shortcut triggers. */ + action: string; + /** keys in the shortcut combination. */ + shortcut: string[]; +} + +/** + * Flux store managing audio/video settings, devices, and the media engine. + * Handles voice activity detection, noise cancellation, device selection, + * and go live streaming configuration. + */ +export class MediaEngineStore extends FluxStore { + /** fetches async resources like DAVE keys. */ + fetchAsyncResources(): void; + /** + * Gets the active input profile. + * @returns current input profile. + */ + getActiveInputProfile(): InputProfile; + /** + * Gets the active voice filter id. + * @returns voice filter id or null if none active. + */ + getActiveVoiceFilter(): string | null; + /** + * Gets when the active voice filter was applied. + * @returns application date or null if none active. + */ + getActiveVoiceFilterAppliedAt(): Date | null; + /** + * Gets whether AEC dump is enabled. + * @returns true if enabled. + */ + getAecDump(): boolean; + /** + * Gets whether to attenuate while others are speaking. + * @returns true if enabled. + */ + getAttenuateWhileSpeakingOthers(): boolean; + /** + * Gets whether to attenuate while self is speaking. + * @returns true if enabled. + */ + getAttenuateWhileSpeakingSelf(): boolean; + /** + * Gets the attenuation level. + * @returns attenuation 0-100, default 0. + */ + getAttenuation(): number; + /** + * Gets the current audio subsystem. + * @returns active audio subsystem. + */ + getAudioSubsystem(): AudioSubsystem; + /** + * Gets whether automatic gain control is enabled. + * @returns true if enabled. + */ + getAutomaticGainControl(): boolean; + /** + * Gets whether system audio input processing is bypassed. + * @returns true if bypassed. + */ + getBypassSystemInputProcessing(): boolean; + /** + * Gets the camera preview component. + * @returns react component for camera preview. + */ + getCameraComponent(): React.ComponentType; + /** + * Gets whether debug logging is enabled. + * @returns true if enabled. + */ + getDebugLogging(): boolean; + /** + * Gets whether echo cancellation is enabled. + * @returns true if enabled. + */ + getEchoCancellation(): boolean; + /** + * Gets whether silence warning is enabled. + * @returns true if enabled. + */ + getEnableSilenceWarning(): boolean; + /** + * Gets whether user has ever spoken while muted. + * @returns true if has spoken while muted. + */ + getEverSpeakingWhileMuted(): boolean; + /** + * Gets whether experimental soundshare is enabled. + * @returns true if enabled. + */ + getExperimentalSoundshare(): boolean; + /** + * Gets the go live context. + * @returns current go live context. + */ + getGoLiveContext(): MediaEngineContextType; + /** + * Gets the current go live source. + * @returns go live source or null if not streaming. + */ + getGoLiveSource(): GoLiveSource | null; + /** + * Gets the GPU brand name. + * @returns GPU brand string. + */ + getGpuBrand(): string; + /** + * Gets whether H265 is enabled. + * @returns true if enabled. + */ + getH265Enabled(): boolean; + /** + * Gets whether hardware encoding is enabled. + * @returns true if enabled. + */ + getHardwareEncoding(): boolean; + /** + * Gets whether audio input is detected. + * @returns true if detected, false if not, null if unknown. + */ + getInputDetected(): boolean | null; + /** + * Gets the selected audio input device id. + * @returns device id. + */ + getInputDeviceId(): string; + /** + * Gets available audio input devices. + * @returns devices keyed by device id. + */ + getInputDevices(): { [deviceId: string]: AudioDevice; }; + /** + * Gets the input volume. + * @returns volume 0-100, default 100. + */ + getInputVolume(): number; + /** + * Gets whether krisp stats are enabled. + * @returns true if enabled. + */ + getKrispEnableStats(): boolean; + /** + * Gets the krisp model override. + * @returns model name or undefined if not set. + */ + getKrispModelOverride(): string | undefined; + /** + * Gets available krisp models. + * @returns array of model names. + */ + getKrispModels(): string[]; + /** + * Gets the krisp suppression level. + * @returns suppression level 0-100, default 100. + */ + getKrispSuppressionLevel(): number; + /** + * Gets the krisp VAD activation threshold. + * @returns threshold 0-1, default 0.8. + */ + getKrispVadActivationThreshold(): number; + /** + * Gets the timestamp of the last audio input device change. + * @returns timestamp in milliseconds. + */ + getLastAudioInputDeviceChangeTimestamp(): number; + /** + * Gets the stereo pan for a user. + * @param userId user to get pan for. + * @param context settings context, defaults to "default". + * @returns pan with left/right 0-1, default {left: 1, right: 1}. + */ + getLocalPan(userId: string, context?: MediaEngineContextType): LocalPan; + /** + * Gets the volume for a user. + * @param userId user to get volume for. + * @param context settings context, defaults to "default". + * @returns volume 0-200, default 100. + */ + getLocalVolume(userId: string, context?: MediaEngineContextType): number; + /** + * Gets whether loopback is enabled. + * @returns true if enabled. + */ + getLoopback(): boolean; + /** + * Gets the reasons loopback is enabled. + * @returns set of reason strings. + */ + getLoopbackReasons(): Set; + /** + * Gets the media engine instance. + * @returns the media engine. + */ + getMediaEngine(): MediaEngine; + /** + * Gets MLS signing key for e2ee. + * @param userId user id. + * @param guildId guild id. + * @returns promise resolving to key and signature. + */ + getMLSSigningKey(userId: string, guildId: string): Promise; + /** + * Gets the current voice mode. + * @param context settings context, defaults to "default". + * @returns current voice mode. + */ + getMode(context?: MediaEngineContextType): VoiceMode; + /** + * Gets the mode options. + * @param context settings context, defaults to "default". + * @returns current mode options. + */ + getModeOptions(context?: MediaEngineContextType): ModeOptions; + /** + * Gets the most recently requested voice filter. + * @returns voice filter id or null if none. + */ + getMostRecentlyRequestedVoiceFilter(): string | null; + /** + * Gets whether no input detected notice is shown. + * @returns true if shown. + */ + getNoInputDetectedNotice(): boolean; + /** + * Gets whether noise cancellation is enabled. + * @returns true if enabled. + */ + getNoiseCancellation(): boolean; + /** + * Gets whether noise suppression is enabled. + * @returns true if enabled. + */ + getNoiseSuppression(): boolean; + /** + * Gets the selected audio output device id. + * @returns device id. + */ + getOutputDeviceId(): string; + /** + * Gets available audio output devices. + * @returns devices keyed by device id. + */ + getOutputDevices(): { [deviceId: string]: AudioDevice; }; + /** + * Gets the output volume. + * @returns volume 0-100, default 100. + */ + getOutputVolume(): number; + /** + * Gets the packet delay. + * @returns delay in milliseconds. + */ + getPacketDelay(): number; + /** + * Gets the previous voice filter. + * @returns voice filter id or null if none. + */ + getPreviousVoiceFilter(): string | null; + /** + * Gets when the previous voice filter was applied. + * @returns application date or null if none. + */ + getPreviousVoiceFilterAppliedAt(): Date | null; + /** + * Gets whether QoS is enabled. + * @returns true if enabled. + */ + getQoS(): boolean; + /** + * Gets the settings for a context. + * @param context settings context, defaults to "default". + * @returns current settings. + */ + getSettings(context?: MediaEngineContextType): MediaEngineSettings; + /** + * Gets registered shortcuts. + * @returns shortcuts keyed by action. + */ + getShortcuts(): { [action: string]: Shortcut; }; + /** + * Gets whether sidechain compression is enabled. + * @returns true if enabled. + */ + getSidechainCompression(): boolean; + /** + * Gets the sidechain compression strength. + * @returns strength 0-100, default 50. + */ + getSidechainCompressionStrength(): number; + /** + * Gets whether currently speaking while muted. + * @returns true if speaking while muted. + */ + getSpeakingWhileMuted(): boolean; + /** + * Gets the complete store state. + * @returns current state. + */ + getState(): MediaEngineState; + /** + * Gets supported secure frames protocol version. + * @returns protocol version number. + */ + getSupportedSecureFramesProtocolVersion(): number; + /** + * Gets the system microphone mode. + * @returns mode string or undefined if not available. + */ + getSystemMicrophoneMode(): string | undefined; + /** + * Gets whether gamescope capture is used. + * @returns true if used. + */ + getUseGamescopeCapture(): boolean; + /** + * Gets whether system screenshare picker is used. + * @returns true if used. + */ + getUseSystemScreensharePicker(): boolean; + /** + * Gets whether VA-API encoder is used. + * @returns true if used. + */ + getUseVaapiEncoder(): boolean; + /** + * Gets the video display component. + * @returns react component for video display. + */ + getVideoComponent(): React.ComponentType; + /** + * Gets the selected video device id. + * @returns device id. + */ + getVideoDeviceId(): string; + /** + * Gets available video devices. + * @returns devices keyed by device id. + */ + getVideoDevices(): { [deviceId: string]: VideoDevice; }; + /** + * Gets whether video hook is enabled. + * @returns true if enabled. + */ + getVideoHook(): boolean; + /** + * Gets video stream parameters. + * @param context settings context, defaults to "default". + * @returns array of stream parameters. + */ + getVideoStreamParameters(context?: MediaEngineContextType): VideoStreamParameter[]; + /** + * Gets the video toggle state for a user. + * @param userId user to check. + * @param context settings context, defaults to "default". + * @returns toggle state, NONE if not in map. + */ + getVideoToggleState(userId: string, context?: MediaEngineContextType): VideoToggleState; + /** + * Gets whether voice filter playback is enabled. + * @returns true if enabled. + */ + getVoiceFilterPlaybackEnabled(): boolean; + + /** + * Gets whether go live simulcast is enabled. + * @returns true if enabled. + */ + goLiveSimulcastEnabled(): boolean; + + /** + * Checks if there is an active CallKit call. + * @returns true if active. + */ + hasActiveCallKitCall(): boolean; + /** + * Checks if there is a clips source. + * @returns true if has source. + */ + hasClipsSource(): boolean; + /** + * Checks if a context exists. + * @param context context to check. + * @returns true if exists. + */ + hasContext(context: MediaEngineContextType): boolean; + /** + * Checks if H265 hardware decode is available. + * @returns true if available. + */ + hasH265HardwareDecode(): boolean; + + /** + * Checks if advanced voice activity is supported. + * @returns true if supported. + */ + isAdvancedVoiceActivitySupported(): boolean; + /** + * Checks if AEC dump is supported. + * @returns true if supported. + */ + isAecDumpSupported(): boolean; + /** + * Checks if any local video is auto disabled. + * @param context settings context, defaults to "default". + * @returns true if any auto disabled. + */ + isAnyLocalVideoAutoDisabled(context?: MediaEngineContextType): boolean; + /** + * Checks if automatic gain control is supported. + * @returns true if supported. + */ + isAutomaticGainControlSupported(): boolean; + /** + * Checks if self is deafened. + * @returns true if deafened. + */ + isDeaf(): boolean; + /** + * Checks if hardware mute notice is enabled. + * @returns true if enabled. + */ + isEnableHardwareMuteNotice(): boolean; + /** + * Checks if media engine is enabled. + * @returns true if enabled. + */ + isEnabled(): boolean; + /** + * Checks if hardware mute is active. + * @param context settings context, defaults to "default". + * @returns true if hardware muted. + */ + isHardwareMute(context?: MediaEngineContextType): boolean; + /** + * Checks if input profile is custom. + * @returns true if custom. + */ + isInputProfileCustom(): boolean; + /** + * Checks if user interaction is required. + * @returns true if required. + */ + isInteractionRequired(): boolean; + /** + * Checks if a user is locally muted. + * @param userId user to check. + * @param context settings context, defaults to "default". + * @returns true if muted. + */ + isLocalMute(userId: string, context?: MediaEngineContextType): boolean; + /** + * Checks if a user's video is auto disabled. + * @param userId user to check. + * @param context settings context, defaults to "default". + * @returns true if auto disabled. + */ + isLocalVideoAutoDisabled(userId: string, context?: MediaEngineContextType): boolean; + /** + * Checks if a user's video is disabled. + * @param userId user to check. + * @param context settings context, defaults to "default". + * @returns true if disabled. + */ + isLocalVideoDisabled(userId: string, context?: MediaEngineContextType): boolean; + /** + * Checks if media filter settings are loading. + * @returns true if loading. + */ + isMediaFilterSettingLoading(): boolean; + /** + * Checks if self is muted. + * @returns true if muted. + */ + isMute(): boolean; + /** + * Checks if native audio permission is ready. + * @returns true if ready. + */ + isNativeAudioPermissionReady(): boolean; + /** + * Checks if there was a noise cancellation error. + * @returns true if error occurred. + */ + isNoiseCancellationError(): boolean; + /** + * Checks if noise cancellation is supported. + * @returns true if supported. + */ + isNoiseCancellationSupported(): boolean; + /** + * Checks if noise suppression is supported. + * @returns true if supported. + */ + isNoiseSuppressionSupported(): boolean; + /** + * Checks if screen sharing is active. + * @param context settings context, defaults to "default". + * @returns true if sharing. + */ + isScreenSharing(context?: MediaEngineContextType): boolean; + /** + * Checks if self is deafened in context. + * @param context settings context, defaults to "default". + * @returns true if deafened. + */ + isSelfDeaf(context?: MediaEngineContextType): boolean; + /** + * Checks if self is muted in context. + * @param context settings context, defaults to "default". + * @returns true if muted. + */ + isSelfMute(context?: MediaEngineContextType): boolean; + /** + * Checks if self is temporarily muted. + * @param context settings context, defaults to "default". + * @returns true if temporarily muted. + */ + isSelfMutedTemporarily(context?: MediaEngineContextType): boolean; + /** + * Checks if simulcast is supported. + * @returns true if supported. + */ + isSimulcastSupported(): boolean; + /** + * Checks if sound sharing is active. + * @param context settings context, defaults to "default". + * @returns true if sharing. + */ + isSoundSharing(context?: MediaEngineContextType): boolean; + /** + * Checks if media engine is supported. + * @returns true if supported. + */ + isSupported(): boolean; + /** + * Checks if video is available. + * @returns true if available. + */ + isVideoAvailable(): boolean; + /** + * Checks if video is enabled. + * @returns true if enabled. + */ + isVideoEnabled(): boolean; + + /** notifies that mute/unmute sound was skipped. */ + notifyMuteUnmuteSoundWasSkipped(): void; + /** + * Sets whether a user can have priority speaker. + * @param userId user to set. + * @param canHavePriority whether can have priority. + */ + setCanHavePriority(userId: string, canHavePriority: boolean): void; + /** + * Sets whether there is an active CallKit call. + * @param active whether active. + */ + setHasActiveCallKitCall(active: boolean): void; + /** + * Checks if manual subsystem selection should be offered. + * @returns true if should offer. + */ + shouldOfferManualSubsystemSelection(): boolean; + /** + * Checks if mute/unmute sound should be skipped. + * @returns true if should skip. + */ + shouldSkipMuteUnmuteSound(): boolean; + /** + * Checks if bypass system input processing should be shown. + * @returns true if should show. + */ + showBypassSystemInputProcessing(): boolean; + + /** starts preloading DAVE encryption. */ + startDavePreload(): void; + + /** + * Checks if a feature is supported. + * @param feature feature to check. + * @returns true if supported. + */ + supports(feature: MediaEngineFeature): boolean; + /** + * Checks if disable local video is supported. + * @returns true if supported. + */ + supportsDisableLocalVideo(): boolean; + /** + * Checks if experimental soundshare is supported. + * @returns true if supported. + */ + supportsExperimentalSoundshare(): boolean; + /** + * Checks if hook soundshare is supported. + * @returns true if supported. + */ + supportsHookSoundshare(): boolean; + /** + * Checks if in-app capture is supported for an app. + * @param appName application name. + * @returns true if supported. + */ + supportsInApp(appName: string): boolean; + /** + * Checks if screen soundshare is supported. + * @returns true if supported. + */ + supportsScreenSoundshare(): boolean; + /** + * Checks if system screenshare picker is supported. + * @returns true if supported. + */ + supportsSystemScreensharePicker(): boolean; + /** + * Checks if video hook is supported. + * @returns true if supported. + */ + supportsVideoHook(): boolean; +} diff --git a/packages/discord-types/src/stores/MessageStore.d.ts b/packages/discord-types/src/stores/MessageStore.d.ts index d4823fc8..e8a095e7 100644 --- a/packages/discord-types/src/stores/MessageStore.d.ts +++ b/packages/discord-types/src/stores/MessageStore.d.ts @@ -1,13 +1,55 @@ -import { MessageJSON, FluxStore, Message } from ".."; +import { FluxStore, Message } from ".."; + +export type JumpType = "ANIMATED" | "INSTANT"; + +export interface MessageCache { + _messages: Message[]; + _map: Record; + _wasAtEdge: boolean; + _isCacheBefore: boolean; +} + +export interface ChannelMessages { + channelId: string; + ready: boolean; + cached: boolean; + jumpType: JumpType; + jumpTargetId: string | null; + jumpTargetOffset: number; + jumpSequenceId: number; + jumped: boolean; + jumpedToPresent: boolean; + jumpFlash: boolean; + jumpReturnTargetId: string | null; + focusTargetId: string | null; + focusSequenceId: number; + initialScrollSequenceId: number; + hasMoreBefore: boolean; + hasMoreAfter: boolean; + loadingMore: boolean; + revealedMessageId: string | null; + hasFetched: boolean; + error: boolean; + _array: Message[]; + _before: MessageCache; + _after: MessageCache; + _map: Record; +} export class MessageStore extends FluxStore { + focusedMessageId(channelId: string): string | undefined; + getLastChatCommandMessage(channelId: string): Message | undefined; + getLastEditableMessage(channelId: string): Message | undefined; + getLastMessage(channelId: string): Message | undefined; + getLastNonCurrentUserMessage(channelId: string): Message | undefined; getMessage(channelId: string, messageId: string): Message; - /** @returns This return object is fucking huge; I'll type it later. */ - getMessages(channelId: string): unknown; - getRawMessages(channelId: string): Record; + /** @see {@link ChannelMessages} */ + getMessages(channelId: string): ChannelMessages; hasCurrentUserSentMessage(channelId: string): boolean; + hasCurrentUserSentMessageSinceAppStart(channelId: string): boolean; hasPresent(channelId: string): boolean; isLoadingMessages(channelId: string): boolean; + isReady(channelId: string): boolean; jumpedMessageId(channelId: string): string | undefined; whenReady(channelId: string, callback: () => void): void; } diff --git a/packages/discord-types/src/stores/NotificationSettingsStore.d.ts b/packages/discord-types/src/stores/NotificationSettingsStore.d.ts new file mode 100644 index 00000000..e82596a7 --- /dev/null +++ b/packages/discord-types/src/stores/NotificationSettingsStore.d.ts @@ -0,0 +1,26 @@ +import { FluxStore } from ".."; + +export type DesktopNotificationType = "ALL" | "ONLY_MENTIONS" | "NEVER"; +export type TTSNotificationType = "ALL" | "ONLY_MENTIONS" | "NEVER"; + +export interface NotificationSettingsState { + desktopType: DesktopNotificationType; + disableAllSounds: boolean; + disabledSounds: string[]; + ttsType: TTSNotificationType; + disableUnreadBadge: boolean; + taskbarFlash: boolean; + notifyMessagesInSelectedChannel: boolean; +} + +export class NotificationSettingsStore extends FluxStore { + get taskbarFlash(): boolean; + getUserAgnosticState(): NotificationSettingsState; + getDesktopType(): DesktopNotificationType; + getTTSType(): TTSNotificationType; + getDisabledSounds(): string[]; + getDisableAllSounds(): boolean; + getDisableUnreadBadge(): boolean; + getNotifyMessagesInSelectedChannel(): boolean; + isSoundDisabled(sound: string): boolean; +} diff --git a/packages/discord-types/src/stores/OverridePremiumTypeStore.d.ts b/packages/discord-types/src/stores/OverridePremiumTypeStore.d.ts new file mode 100644 index 00000000..f14342d7 --- /dev/null +++ b/packages/discord-types/src/stores/OverridePremiumTypeStore.d.ts @@ -0,0 +1,15 @@ +import { FluxStore } from ".."; + +export interface OverridePremiumTypeState { + createdAtOverride: Date | undefined; + premiumTypeActual: number | null; + premiumTypeOverride: number | undefined; +} + +export class OverridePremiumTypeStore extends FluxStore { + getState(): OverridePremiumTypeState; + getCreatedAtOverride(): Date | undefined; + getPremiumTypeActual(): number | null; + getPremiumTypeOverride(): number | undefined; + get premiumType(): number | undefined; +} diff --git a/packages/discord-types/src/stores/PermissionStore.d.ts b/packages/discord-types/src/stores/PermissionStore.d.ts new file mode 100644 index 00000000..d338ae63 --- /dev/null +++ b/packages/discord-types/src/stores/PermissionStore.d.ts @@ -0,0 +1,57 @@ +import { Channel, Guild, Role, FluxStore } from ".."; + +export interface GuildPermissionProps { + canManageGuild: boolean; + canManageChannels: boolean; + canManageRoles: boolean; + canManageBans: boolean; + canManageNicknames: boolean; + canManageGuildExpressions: boolean; + canViewAuditLog: boolean; + canViewAuditLogV2: boolean; + canManageWebhooks: boolean; + canViewGuildAnalytics: boolean; + canAccessMembersPage: boolean; + isGuildAdmin: boolean; + isOwner: boolean; + isOwnerWithRequiredMfaLevel: boolean; + guild: Guild; +} + +export interface PartialChannelContext { + channelId: string; +} + +export interface PartialGuildContext { + guildId: string; +} + +export type PartialContext = PartialChannelContext | PartialGuildContext; + +type PartialChannel = Channel | { id: string; }; +type PartialGuild = Guild | { id: string; }; + +export class PermissionStore extends FluxStore { + // TODO: finish typing these + can(permission: bigint, channelOrGuild: PartialChannel | PartialGuild, guildId?: string, overwrites?: Record, userId?: string): boolean; + canBasicChannel(permission: bigint, channel: PartialChannel, guildId?: string, overwrites?: Record, userId?: string): boolean; + canWithPartialContext(permission: bigint, context: PartialContext): boolean; + canManageUser(permission: bigint, userOrUserId: string, guild: PartialGuild): boolean; + canAccessGuildSettings(guild: PartialGuild): boolean; + canAccessMemberSafetyPage(guild: PartialGuild): boolean; + canImpersonateRole(guild: PartialGuild, role: Role): boolean; + + // TODO: finish typing + computePermissions(channel: PartialChannel, guildId?: string, overwrites?: Record, userId?: string): bigint; + computeBasicPermissions(channel: PartialChannel): number; + + getChannelPermissions(channel: PartialChannel): bigint; + getGuildPermissions(guild: PartialGuild): bigint; + getGuildPermissionProps(guild: PartialGuild): GuildPermissionProps; + + getHighestRole(guild: PartialGuild): Role | null; + isRoleHigher(guild: PartialGuild, firstRole: Role | null, secondRole: Role | null): boolean; + + getGuildVersion(guildId: string): number; + getChannelsVersion(): number; +} diff --git a/packages/discord-types/src/stores/PresenceStore.d.ts b/packages/discord-types/src/stores/PresenceStore.d.ts index 3f245aca..c0462dce 100644 --- a/packages/discord-types/src/stores/PresenceStore.d.ts +++ b/packages/discord-types/src/stores/PresenceStore.d.ts @@ -8,17 +8,29 @@ export interface UserAndActivity { export type DiscordPlatform = "desktop" | "mobile" | "web" | "embedded"; +export interface PresenceStoreState { + presencesForGuilds: Record>; }>>; + statuses: Record; + activities: Record; + filteredActivities: Record; + hiddenActivities: Record; + // TODO: finish typing + activityMetadata: Record; + clientStatuses: Record>>; +} + export class PresenceStore extends FluxStore { findActivity(userId: string, predicate: (activity: Activity) => boolean, guildId?: string): Activity | undefined; getActivities(userId: string, guildId?: string): Activity[]; + // TODO: finish typing getActivityMetadata(userId: string): any; getAllApplicationActivities(applicationId: string): UserAndActivity[]; getApplicationActivity(userId: string, applicationId: string, guildId?: string): Activity | null; getClientStatus(userId: string): Record; - getHiddenActivities(): any; + getHiddenActivities(): Activity[]; /** literally just getActivities(...)[0] */ getPrimaryActivity(userId: string, guildId?: string): Activity | null; - getState(): any; + getState(): PresenceStoreState; getStatus(userId: string, guildId?: string | null, defaultStatus?: OnlineStatus): OnlineStatus; getUnfilteredActivities(userId: string, guildId?: string): Activity[]; getUserIds(): string[]; diff --git a/packages/discord-types/src/stores/RTCConnectionStore.d.ts b/packages/discord-types/src/stores/RTCConnectionStore.d.ts new file mode 100644 index 00000000..588defc8 --- /dev/null +++ b/packages/discord-types/src/stores/RTCConnectionStore.d.ts @@ -0,0 +1,82 @@ +import { FluxStore } from ".."; + +export type RTCConnectionState = + | "DISCONNECTED" + | "AWAITING_ENDPOINT" + | "AUTHENTICATING" + | "CONNECTING" + | "RTC_DISCONNECTED" + | "RTC_CONNECTING" + | "RTC_CONNECTED" + | "NO_ROUTE" + | "ICE_CHECKING" + | "DTLS_CONNECTING"; + +export type RTCConnectionQuality = "unknown" | "bad" | "average" | "fine"; + +export interface LastRTCConnectionState { + duration: number | null; + mediaSessionId: string | null; + rtcConnectionId: string | null; + wasEverMultiParticipant: boolean; + wasEverRtcConnected: boolean; + // TODO: type + voiceStateAnalytics: any; + channelId: string; +} + +export interface RTCConnectionPacketStats { + inbound: number; + outbound: number; + lost: number; +} + +export interface VoiceStateStats { + max_voice_state_count: number; +} + +export interface SecureFramesState { + state: string; +} + +export interface SecureFramesRosterMapEntry { + pendingVerifyState: number; + verifiedState: number; +} + +export class RTCConnectionStore extends FluxStore { + // TODO: type + getRTCConnection(): any | null; + getState(): RTCConnectionState; + isConnected(): boolean; + isDisconnected(): boolean; + getRemoteDisconnectVoiceChannelId(): string | null; + getLastSessionVoiceChannelId(): string | null; + setLastSessionVoiceChannelId(channelId: string | null): void; + getGuildId(): string | undefined; + getChannelId(): string | undefined; + getHostname(): string; + getQuality(): RTCConnectionQuality; + getPings(): number[]; + getAveragePing(): number; + getLastPing(): number | undefined; + getOutboundLossRate(): number | undefined; + getMediaSessionId(): string | undefined; + getRTCConnectionId(): string | undefined; + getDuration(): number | undefined; + getLastRTCConnectionState(): LastRTCConnectionState | null; + getVoiceFilterSpeakingDurationMs(): number | undefined; + getPacketStats(): RTCConnectionPacketStats | undefined; + getVoiceStateStats(): VoiceStateStats | undefined; + // TODO: finish typing + getUserVoiceSettingsStats(userId: string): any | undefined; + getWasEverMultiParticipant(): boolean; + getWasEverRtcConnected(): boolean; + getUserIds(): string[] | undefined; + getJoinVoiceId(): string | null; + isUserConnected(userId: string): boolean | undefined; + getSecureFramesState(): SecureFramesState | undefined; + getSecureFramesRosterMapEntry(oderId: string): SecureFramesRosterMapEntry | undefined; + getLastNonZeroRemoteVideoSinkWantsTime(): number | null; + getWasMoved(): boolean; +} diff --git a/packages/discord-types/src/stores/ReadStateStore.d.ts b/packages/discord-types/src/stores/ReadStateStore.d.ts new file mode 100644 index 00000000..6dcde5f1 --- /dev/null +++ b/packages/discord-types/src/stores/ReadStateStore.d.ts @@ -0,0 +1,70 @@ +import { Channel, FluxStore } from ".."; +import { ReadStateType } from "../../enums"; + +export interface GuildChannelUnreadState { + mentionCount: number; + unread: boolean; + isMentionLowImportance: boolean; +} + +export interface ReadStateSnapshot { + unread: boolean; + mentionCount: number; + guildUnread: boolean | null; + guildMentionCount: number | null; + takenAt: number; +} + +export interface SerializedReadState { + channelId: string; + type: ReadStateType; + _guildId: string; + _persisted: boolean; + _lastMessageId: string; + _lastMessageTimestamp: number; + _ackMessageId: string; + _ackMessageTimestamp: number; + ackPinTimestamp: number; + lastPinTimestamp: number; + _mentionCount: number; + flags: number; + lastViewed: number; +} + +export class ReadStateStore extends FluxStore { + ackMessageId(channelId: string, type?: ReadStateType): string | null; + getAllReadStates(includePrivate?: boolean): SerializedReadState[]; + getChannelIdsForWindowId(windowId: string): string[]; + getForDebugging(channelId: string): object | undefined; + getGuildChannelUnreadState( + channel: Channel, + isOptInEnabled: boolean, + guildHasActiveThreads: boolean, + isChannelMuted: boolean, + isGuildHome: boolean + ): GuildChannelUnreadState; + getGuildUnreadsSentinel(guildId: string): number; + getIsMentionLowImportance(channelId: string, type?: ReadStateType): boolean; + getMentionChannelIds(): string[]; + getMentionCount(channelId: string, type?: ReadStateType): number; + getNonChannelAckId(type: ReadStateType): string | null; + getNotifCenterReadState(channelId: string): object | undefined; + getOldestUnreadMessageId(channelId: string, type?: ReadStateType): string | null; + getOldestUnreadTimestamp(channelId: string, type?: ReadStateType): number; + getReadStatesByChannel(): Record; + getSnapshot(channelId: string, maxAge: number): ReadStateSnapshot; + getTrackedAckMessageId(channelId: string, type?: ReadStateType): string | null; + getUnreadCount(channelId: string, type?: ReadStateType): number; + hasOpenedThread(channelId: string): boolean; + hasRecentlyVisitedAndRead(channelId: string): boolean; + hasTrackedUnread(channelId: string): boolean; + hasUnread(channelId: string, type?: ReadStateType): boolean; + hasUnreadOrMentions(channelId: string, type?: ReadStateType): boolean; + hasUnreadPins(channelId: string): boolean; + isEstimated(channelId: string, type?: ReadStateType): boolean; + isForumPostUnread(channelId: string): boolean; + isNewForumThread(threadId: string, parentChannelId: string, guildId: string): boolean; + lastMessageId(channelId: string, type?: ReadStateType): string | null; + lastMessageTimestamp(channelId: string, type?: ReadStateType): number; + lastPinTimestamp(channelId: string): number; +} diff --git a/packages/discord-types/src/stores/RelationshipStore.d.ts b/packages/discord-types/src/stores/RelationshipStore.d.ts index 9aceac47..b1c24886 100644 --- a/packages/discord-types/src/stores/RelationshipStore.d.ts +++ b/packages/discord-types/src/stores/RelationshipStore.d.ts @@ -1,26 +1,42 @@ import { FluxStore } from ".."; +import { RelationshipType } from "../../enums"; export class RelationshipStore extends FluxStore { + getBlockedIDs(): string[]; + getBlockedOrIgnoredIDs(): string[]; + getFriendCount(): number; getFriendIDs(): string[]; getIgnoredIDs(): string[]; - getBlockedIDs(): string[]; + getMutableRelationships(): Map; + getNickname(userId: string): string; + getOriginApplicationId(userId: string): string | undefined; + getOutgoingCount(): number; getPendingCount(): number; + getPendingIgnoredCount(): number; getRelationshipCount(): number; - /** Related to friend nicknames. */ - getNickname(userId: string): string; /** @returns Enum value from constants.RelationshipTypes */ - getRelationshipType(userId: string): number; - isFriend(userId: string): boolean; + getRelationshipType(userId: string): RelationshipType; + getSince(userId: string): string; + getSinces(): Record; + getSpamCount(): number; + getVersion(): number; + isBlocked(userId: string): boolean; - isIgnored(userId: string): boolean; + isBlockedForMessage(userId: string): boolean; + /** * @see {@link isBlocked} * @see {@link isIgnored} */ isBlockedOrIgnored(userId: string): boolean; - getSince(userId: string): string; + isBlockedOrIgnoredForMessage(userId: string): boolean; - getMutableRelationships(): Map; + isFriend(userId: string): boolean; + isIgnored(userId: string): boolean; + isIgnoredForMessage(userId: string): boolean; + isSpam(userId: string): boolean; + isStranger(userId: string): boolean; + isUnfilteredPendingIncoming(userId: string): boolean; } diff --git a/packages/discord-types/src/stores/RunningGameStore.d.ts b/packages/discord-types/src/stores/RunningGameStore.d.ts new file mode 100644 index 00000000..34b6f496 --- /dev/null +++ b/packages/discord-types/src/stores/RunningGameStore.d.ts @@ -0,0 +1,60 @@ +import { FluxStore } from ".."; + +export interface RunningGame { + id?: string; + name: string; + exePath: string; + cmdLine: string; + distributor: string; + lastFocused: number; + lastLaunched: number; + nativeProcessObserverId: number; + pid?: number; + hidden?: boolean; + isLauncher?: boolean; + elevated?: boolean; + sandboxed?: boolean; +} + +export interface GameOverlayStatus { + enabledLegacy: boolean; + enabledOOP: boolean; +} + +export interface SystemServiceStatus { + state: string; +} + +export class RunningGameStore extends FluxStore { + canShowAdminWarning: boolean; + + addExecutableTrackedByAnalytics(exe: string): void; + getCandidateGames(): RunningGame[]; + getCurrentGameForAnalytics(): RunningGame | null; + getCurrentNonGameForAnalytics(): RunningGame | null; + getGameForName(name: string): RunningGame | null; + getGameForPID(pid: number): RunningGame | null; + getGameOrTransformedSubgameForPID(pid: number): RunningGame | null; + getGameOverlayStatus(game: RunningGame): GameOverlayStatus | null; + getGamesSeen(includeHidden?: boolean): RunningGame[]; + getLauncherForPID(pid: number): RunningGame | null; + getObservedAppNameForWindow(windowHandle: number): string | null; + getOverlayEnabledForGame(game: RunningGame): boolean; + getOverlayOptionsForPID(pid: number): object | null; + getOverrideForGame(game: RunningGame): object | null; + getOverrides(): object[]; + getRunningDiscordApplicationIds(): string[]; + getRunningGames(): RunningGame[]; + getRunningNonGames(): RunningGame[]; + getRunningVerifiedApplicationIds(): string[]; + getSeenGameByName(name: string): RunningGame | null; + getSystemServiceStatus(service: string): SystemServiceStatus; + getVisibleGame(): RunningGame | null; + getVisibleRunningGames(): RunningGame[]; + isDetectionEnabled(type?: string): boolean; + isGamesSeenLoaded(): boolean; + isObservedAppRunning(app: string): boolean; + isSystemServiceInitialized(service: string): boolean; + shouldContinueWithoutElevatedProcessForPID(pid: number): boolean; + shouldElevateProcessForPID(pid: number): boolean; +} diff --git a/packages/discord-types/src/stores/SelectedChannelStore.d.ts b/packages/discord-types/src/stores/SelectedChannelStore.d.ts index 13ac98ac..3237a3eb 100644 --- a/packages/discord-types/src/stores/SelectedChannelStore.d.ts +++ b/packages/discord-types/src/stores/SelectedChannelStore.d.ts @@ -1,14 +1,16 @@ import { FluxStore } from ".."; +export interface ChannelFollowingDestination { + guildId?: string; + channelId?: string; +} + export class SelectedChannelStore extends FluxStore { getChannelId(guildId?: string | null): string; getVoiceChannelId(): string | undefined; getCurrentlySelectedChannelId(guildId?: string): string | undefined; getMostRecentSelectedTextChannelId(guildId: string): string | undefined; getLastSelectedChannelId(guildId?: string): string; - // yes this returns a string getLastSelectedChannels(guildId?: string): string; - - /** If you follow an announcement channel, this will return whichever channel you chose as destination */ - getLastChannelFollowingDestination(): { guildId?: string; channelId?: string; } | undefined; + getLastChannelFollowingDestination(): ChannelFollowingDestination | undefined; } diff --git a/packages/discord-types/src/stores/SoundboardStore.d.ts b/packages/discord-types/src/stores/SoundboardStore.d.ts new file mode 100644 index 00000000..22065c72 --- /dev/null +++ b/packages/discord-types/src/stores/SoundboardStore.d.ts @@ -0,0 +1,47 @@ +import { FluxStore } from ".."; + +export interface SoundboardSound { + soundId: string; + name: string; + volume: number; + emojiId: string | null; + emojiName: string | null; + available: boolean; + guildId: string; + userId?: string; +} + +export interface TopSoundForGuild { + soundId: string; + rank: number; +} + +export interface SoundboardOverlayState { + soundboardSounds: Record; + favoritedSoundIds: string[]; + localSoundboardMutes: string[]; +} + +export class SoundboardStore extends FluxStore { + getOverlaySerializedState(): SoundboardOverlayState; + getSounds(): Map; + getSoundsForGuild(guildId: string): SoundboardSound[] | null; + getSound(guildId: string, soundId: string): SoundboardSound; + getSoundById(soundId: string): SoundboardSound; + isFetchingSounds(): boolean; + isFetchingDefaultSounds(): boolean; + isFetching(): boolean; + shouldFetchDefaultSounds(): boolean; + hasFetchedDefaultSounds(): boolean; + isUserPlayingSounds(userId: string): boolean; + isPlayingSound(soundId: string): boolean; + isFavoriteSound(soundId: string): boolean; + getFavorites(): Set; + getAllTopSoundsForGuilds(): Map; + isLocalSoundboardMuted(userId: string): boolean; + hasHadOtherUserPlaySoundInSession(): boolean; + shouldFetchTopSoundsForGuilds(): boolean; + hasFetchedTopSoundsForGuilds(): boolean; + hasFetchedAllSounds(): boolean; + isFetchingAnySounds(): boolean; +} diff --git a/packages/discord-types/src/stores/SpellCheckStore.d.ts b/packages/discord-types/src/stores/SpellCheckStore.d.ts new file mode 100644 index 00000000..ff8ecadd --- /dev/null +++ b/packages/discord-types/src/stores/SpellCheckStore.d.ts @@ -0,0 +1,6 @@ +import { FluxStore } from ".."; + +export class SpellCheckStore extends FluxStore { + hasLearnedWord(word: string): boolean; + isEnabled(): boolean; +} diff --git a/packages/discord-types/src/stores/SpotifyStore.d.ts b/packages/discord-types/src/stores/SpotifyStore.d.ts new file mode 100644 index 00000000..7a207f92 --- /dev/null +++ b/packages/discord-types/src/stores/SpotifyStore.d.ts @@ -0,0 +1,106 @@ +import { FluxStore } from ".."; + +export interface SpotifyDevice { + id: string; + is_active: boolean; + is_private_session: boolean; + is_restricted: boolean; + name: string; + supports_volume: boolean; + type: string; + volume_percent: number; +} + +export interface SpotifySocket { + accessToken: string; + accountId: string; + connectionId: string; + isPremium: boolean; + socket: WebSocket; +} + +export interface SpotifySocketAndDevice { + socket: SpotifySocket; + device: SpotifyDevice; +} + +export interface SpotifyArtist { + id: string; + name: string; +} + +export interface SpotifyImage { + url: string; + height: number; + width: number; +} + +export interface SpotifyAlbum { + id: string; + name: string; + type: string; + image: SpotifyImage | null; +} + +export interface SpotifyTrack { + id: string; + name: string; + duration: number; + isLocal: boolean; + type: string; + album: SpotifyAlbum; + artists: SpotifyArtist[]; +} + +export interface SpotifyPlayerState { + track: SpotifyTrack; + startTime: number; + context: { uri: string } | null; +} + +export interface SpotifyActivity { + name: string; + assets: { + large_image?: string; + large_text?: string; + }; + details: string; + state: string | undefined; + timestamps: { + start: number; + end: number; + }; + party: { + id: string; + }; + sync_id?: string; + flags?: number; + metadata?: { + context_uri: string | undefined; + album_id: string; + artist_ids: string[]; + type: string; + button_urls: string[]; + }; +} + +export interface SpotifySyncingWith { + oderId: string; + partyId: string; + sessionId: string; + userId: string; +} + +export class SpotifyStore extends FluxStore { + hasConnectedAccount(): boolean; + getActiveSocketAndDevice(): SpotifySocketAndDevice | null; + getPlayableComputerDevices(): SpotifySocketAndDevice[]; + canPlay(deviceId: string): boolean; + getSyncingWith(): SpotifySyncingWith | undefined; + wasAutoPaused(): boolean; + getLastPlayedTrackId(): string | undefined; + getTrack(): SpotifyTrack | null; + getPlayerState(accountId: string): SpotifyPlayerState | null; + shouldShowActivity(): boolean; + getActivity(): SpotifyActivity | null; +} diff --git a/packages/discord-types/src/stores/StickersStore.d.ts b/packages/discord-types/src/stores/StickersStore.d.ts index fdfb012c..5c0bb84c 100644 --- a/packages/discord-types/src/stores/StickersStore.d.ts +++ b/packages/discord-types/src/stores/StickersStore.d.ts @@ -1,15 +1,22 @@ import { FluxStore, GuildSticker, PremiumStickerPack, Sticker } from ".."; export type StickerGuildMap = Map; +export type StickerPackMap = Map; export class StickersStore extends FluxStore { - getAllGuildStickers(): StickerGuildMap; - getRawStickersByGuild(): StickerGuildMap; - getPremiumPacks(): PremiumStickerPack[]; + hasLoadedStickerPacks: boolean; + isFetchingStickerPacks: boolean; + isLoaded: boolean; + loadState: number; + getAllGuildStickers(): StickerGuildMap; + getAllPackStickers(): StickerPackMap; + getPremiumPacks(): PremiumStickerPack[]; + getRawStickersByGuild(): StickerGuildMap; getStickerById(id: string): Sticker | undefined; + // TODO: type + getStickerMetadataArrays(): any[]; getStickerPack(id: string): PremiumStickerPack | undefined; getStickersByGuildId(guildId: string): Sticker[] | undefined; - isPremiumPack(id: string): boolean; } diff --git a/packages/discord-types/src/stores/StreamerModeStore.d.ts b/packages/discord-types/src/stores/StreamerModeStore.d.ts index efa6cfc9..73e2eaea 100644 --- a/packages/discord-types/src/stores/StreamerModeStore.d.ts +++ b/packages/discord-types/src/stores/StreamerModeStore.d.ts @@ -1,4 +1,14 @@ -import { FluxStore } from "@vencord/discord-types"; +import { FluxStore } from ".."; + +export interface StreamerModeSettings { + enabled: boolean; + autoToggle: boolean; + hideInstantInvites: boolean; + hidePersonalInformation: boolean; + disableSounds: boolean; + disableNotifications: boolean; + enableContentProtection: boolean; +} export class StreamerModeStore extends FluxStore { get autoToggle(): boolean; @@ -8,4 +18,7 @@ export class StreamerModeStore extends FluxStore { get enabled(): boolean; get hideInstantInvites(): boolean; get hidePersonalInformation(): boolean; + + getSettings(): StreamerModeSettings; + getState(): Record; } diff --git a/packages/discord-types/src/stores/ThemeStore.d.ts b/packages/discord-types/src/stores/ThemeStore.d.ts index 2900f7f6..c0dbcf59 100644 --- a/packages/discord-types/src/stores/ThemeStore.d.ts +++ b/packages/discord-types/src/stores/ThemeStore.d.ts @@ -6,13 +6,14 @@ export type Theme = "light" | "dark" | "darker" | "midnight"; export interface ThemeState { theme: Theme; + /** 0 = not loaded, 1 = loaded */ status: 0 | 1; preferences: Record; } export class ThemeStore extends FluxStore { - get theme(): Theme; - get darkSidebar(): boolean; get systemTheme(): SystemTheme; - themePreferenceForSystemTheme(preference: ThemePreference): Theme; + get theme(): Theme; + getState(): ThemeState; + themePreferenceForSystemTheme(preference: ThemePreference): Theme; } diff --git a/packages/discord-types/src/stores/UploadAttachmentStore.d.ts b/packages/discord-types/src/stores/UploadAttachmentStore.d.ts new file mode 100644 index 00000000..c29e7c07 --- /dev/null +++ b/packages/discord-types/src/stores/UploadAttachmentStore.d.ts @@ -0,0 +1,11 @@ +import { CloudUpload, FluxStore } from ".."; +import { DraftType } from "../../enums"; + +export class UploadAttachmentStore extends FluxStore { + getFirstUpload(channelId: string, draftType: DraftType): CloudUpload | null; + hasAdditionalUploads(channelId: string, draftType: DraftType): boolean; + getUploads(channelId: string, draftType: DraftType): CloudUpload[]; + getUploadCount(channelId: string, draftType: DraftType): number; + getUpload(channelId: string, uploadId: string, draftType: DraftType): CloudUpload; + findUpload(channelId: string, draftType: DraftType, predicate: (upload: CloudUpload) => boolean): CloudUpload | undefined; +} diff --git a/packages/discord-types/src/stores/UserGuildSettingsStore.d.ts b/packages/discord-types/src/stores/UserGuildSettingsStore.d.ts new file mode 100644 index 00000000..e7f00592 --- /dev/null +++ b/packages/discord-types/src/stores/UserGuildSettingsStore.d.ts @@ -0,0 +1,91 @@ +import { Channel, FluxStore } from ".."; + +export interface MuteConfig { + selected_time_window: number; + end_time: string | null; +} + +export interface ChannelOverride { + muted: boolean; + mute_config: MuteConfig | null; + message_notifications: number; + flags: number; + collapsed: boolean; + channel_id: string; +} + +export interface GuildSettings { + suppress_everyone: boolean; + suppress_roles: boolean; + mute_scheduled_events: boolean; + mobile_push: boolean; + muted: boolean; + message_notifications: number; + flags: number; + channel_overrides: Record; + notify_highlights: number; + hide_muted_channels: boolean; + version: number; + mute_config: MuteConfig | null; + guild_id: string; +} + +export interface AccountNotificationSettings { + flags: number; +} + +export interface UserGuildSettingsState { + useNewNotifications: boolean; +} + +export class UserGuildSettingsStore extends FluxStore { + get accountNotificationSettings(): AccountNotificationSettings; + get mentionOnAllMessages(): boolean; + get useNewNotifications(): boolean; + + allowAllMessages(guildId: string): boolean; + allowNoMessages(guildId: string): boolean; + getAddedToMessages(): string[]; + // TODO: finish typing + getAllSettings(): { userGuildSettings: Record; }; + getChannelFlags(channel: Channel): number; + getChannelIdFlags(guildId: string, channelId: string): number; + getChannelMessageNotifications(guildId: string, channelId: string): number | null; + getChannelMuteConfig(guildId: string, channelId: string): MuteConfig | null; + getChannelOverrides(guildId: string): Record; + getChannelRecordUnreadSetting(channel: Channel): number; + getChannelUnreadSetting(guildId: string, channelId: string): number; + getGuildFavorites(guildId: string): string[]; + getGuildFlags(guildId: string): number; + getGuildUnreadSetting(guildId: string): number; + getMessageNotifications(guildId: string): number; + getMuteConfig(guildId: string): MuteConfig | null; + getMutedChannels(guildId: string): string[]; + getNewForumThreadsCreated(guildId: string): boolean; + getNotifyHighlights(guildId: string): number; + getOptedInChannels(guildId: string): string[]; + // TODO: finish typing these + getOptedInChannelsWithPendingUpdates(guildId: string): Record; + getPendingChannelUpdates(guildId: string): Record; + getState(): UserGuildSettingsState; + isAddedToMessages(channelId: string): boolean; + isCategoryMuted(guildId: string, channelId: string): boolean; + isChannelMuted(guildId: string, channelId: string): boolean; + isChannelOptedIn(guildId: string, channelId: string, usePending?: boolean): boolean; + isChannelOrParentOptedIn(guildId: string, channelId: string, usePending?: boolean): boolean; + isChannelRecordOrParentOptedIn(channel: Channel, usePending?: boolean): boolean; + isFavorite(guildId: string, channelId: string): boolean; + isGuildCollapsed(guildId: string): boolean; + isGuildOrCategoryOrChannelMuted(guildId: string, channelId: string): boolean; + isMessagesFavorite(guildId: string): boolean; + isMobilePushEnabled(guildId: string): boolean; + isMuteScheduledEventsEnabled(guildId: string): boolean; + isMuted(guildId: string): boolean; + isOptInEnabled(guildId: string): boolean; + isSuppressEveryoneEnabled(guildId: string): boolean; + isSuppressRolesEnabled(guildId: string): boolean; + isTemporarilyMuted(guildId: string): boolean; + resolveGuildUnreadSetting(guildId: string): number; + resolveUnreadSetting(channel: Channel): number; + resolvedMessageNotifications(guildId: string): number; +} diff --git a/packages/discord-types/src/stores/UserProfileStore.d.ts b/packages/discord-types/src/stores/UserProfileStore.d.ts index d9efc47b..cdbbe3d5 100644 --- a/packages/discord-types/src/stores/UserProfileStore.d.ts +++ b/packages/discord-types/src/stores/UserProfileStore.d.ts @@ -101,28 +101,21 @@ export interface UserProfile extends UserProfileBase, Pick premiumSince: Date | null; } -export class UserProfileStore extends FluxStore { - /** - * @param userId the user ID of the profile being fetched. - * @param guildId the guild ID to of the profile being fetched. - * defaults to the internal symbol `NO GUILD ID` if nullish - * - * @returns true if the profile is being fetched, false otherwise. - */ - isFetchingProfile(userId: string, guildId?: string): boolean; - /** - * Check if mutual friends for {@link userId} are currently being fetched. - * - * @param userId the user ID of the mutual friends being fetched. - * - * @returns true if mutual friends are being fetched, false otherwise. - */ - isFetchingFriends(userId: string): boolean; +export interface ApplicationWidgetConfig { + applicationId: string; + widgetType: number; +} +export interface WishlistSettings { + privacy: number; +} + +export class UserProfileStore extends FluxStore { + get applicationWidgetApplicationConfigs(): Record; get isSubmitting(): boolean; - getUserProfile(userId: string): UserProfile | undefined; - + getApplicationWidgetApplicationConfig(applicationId: string): ApplicationWidgetConfig | undefined; + getFirstWishlistId(userId: string): string | null; getGuildMemberProfile(userId: string, guildId: string | undefined): UserProfileBase | null; /** * Get the mutual friends of a user. @@ -148,4 +141,26 @@ export class UserProfileStore extends FluxStore { * @returns an array of mutual guilds, or undefined if the user has no mutual guilds */ getMutualGuilds(userId: string): MutualGuild[] | undefined; + getUserProfile(userId: string): UserProfile | undefined; + // TODO: finish typing + getWidgets(userId: string): any[] | undefined; + getWishlistIds(userId: string): string[]; + getWishlistSettings(userId: string): WishlistSettings | null; + /** + * Check if mutual friends for {@link userId} are currently being fetched. + * + * @param userId the user ID of the mutual friends being fetched. + * + * @returns true if mutual friends are being fetched, false otherwise. + */ + isFetchingFriends(userId: string): boolean; + /** + * @param userId the user ID of the profile being fetched. + * @param guildId the guild ID to of the profile being fetched. + * defaults to the internal symbol `NO GUILD ID` if nullish + * + * @returns true if the profile is being fetched, false otherwise. + */ + isFetchingProfile(userId: string, guildId?: string): boolean; + takeSnapshot(): Record; } diff --git a/packages/discord-types/src/stores/UserSettingsProtoStore.d.ts b/packages/discord-types/src/stores/UserSettingsProtoStore.d.ts new file mode 100644 index 00000000..9aaf8dd1 --- /dev/null +++ b/packages/discord-types/src/stores/UserSettingsProtoStore.d.ts @@ -0,0 +1,223 @@ +import { FluxStore } from ".."; + +export interface GuildFolder { + guildIds: string[]; + folderId?: number; + folderName?: string; + folderColor?: number; +} + +export interface GuildProto { + // TODO: finish typing + channels: Record; + hubProgress: number; + guildOnboardingProgress: number; + dismissedGuildContent: Record; + disableRaidAlertPush: boolean; + disableRaidAlertNag: boolean; + leaderboardsDisabled: boolean; + // TODO: finish typing + guildDismissibleContentStates: Record; +} + +export interface UserSettingsVersions { + clientVersion: number; + serverVersion: number; + dataVersion: number; +} + +export interface InboxSettings { + currentTab: number; + viewedTutorial: boolean; +} + +export interface GuildsSettings { + guilds: Record; +} + +export interface UserContentSettings { + dismissedContents: string; + lastReceivedChangelogId: string; + // TODO: finish typing + recurringDismissibleContentStates: Record; + // TODO: type + lastDismissedOutboundPromotionStartDate: any; + premiumTier0ModalDismissedAt: any; +} + +export interface VoiceAndVideoSettings { + // TODO: type + videoBackgroundFilterDesktop: any; + alwaysPreviewVideo: boolean; + afkTimeout: number; + streamNotificationsEnabled: boolean; + nativePhoneIntegrationEnabled: boolean; + disableStreamPreviews: boolean; + soundmojiVolume: number; +} + +export interface TextAndImagesSettings { + emojiPickerCollapsedSections: string[]; + stickerPickerCollapsedSections: string[]; + soundboardPickerCollapsedSections: string[]; + dmSpamFilterV2: number; + viewImageDescriptions: boolean; + inlineAttachmentMedia: boolean; + inlineEmbedMedia: boolean; + gifAutoPlay: boolean; + renderEmbeds: boolean; + renderReactions: boolean; + animateEmoji: boolean; + animateStickers: number; + enableTtsCommand: boolean; + messageDisplayCompact: boolean; + explicitContentFilter: number; + viewNsfwGuilds: boolean; + convertEmoticons: boolean; + viewNsfwCommands: boolean; + includeStickersInAutocomplete: boolean; + // TODO: type these + explicitContentSettings: any; + goreContentSettings: any; + showMentionSuggestions: boolean; +} + +export interface NotificationsSettings { + notificationCenterAckedBeforeId: string; + focusModeExpiresAtMs: string; + reactionNotifications: number; + gameActivityNotifications: boolean; + customStatusPushNotifications: boolean; + showInAppNotifications: boolean; + notifyFriendsOnGoLive: boolean; + enableVoiceActivityNotifications: boolean; + enableUserResurrectionNotifications: boolean; +} + +export interface PrivacySettings { + restrictedGuildIds: string[]; + defaultGuildsRestricted: boolean; + allowAccessibilityDetection: boolean; + activityRestrictedGuildIds: string[]; + defaultGuildsActivityRestricted: boolean; + activityJoiningRestrictedGuildIds: string[]; + messageRequestRestrictedGuildIds: string[]; + guildsLeaderboardOptOutDefault: boolean; + slayerSdkReceiveDmsInGame: boolean; + defaultGuildsActivityRestrictedV2: boolean; + detectPlatformAccounts: boolean; + passwordless: boolean; + contactSyncEnabled: boolean; + friendSourceFlags: number; + friendDiscoveryFlags: number; + dropsOptedOut: boolean; + hideLegacyUsername: boolean; + defaultGuildsRestrictedV2: boolean; + quests3PDataOptedOut: boolean; +} + +export interface GameLibrarySettings { + disableGamesTab: boolean; +} + +export interface StatusSettings { + statusExpiresAtMs: string; + status: { status: string; } | null; + showCurrentGame: boolean; + statusCreatedAtMs: string; +} + +export interface LocalizationSettings { + locale: { localeCode: string; } | null; + timezoneOffset: { offset: number; } | null; +} + +export interface AppearanceSettings { + theme: number; + developerMode: boolean; + mobileRedesignDisabled: boolean; + timestampHourCycle: number; + launchPadMode: number; + uiDensity: number; + swipeRightToLeftMode: number; + // TODO: type + clientThemeSettings: any; +} + +export interface GuildFoldersSettings { + folders: GuildFolder[]; + guildPositions: string[]; +} + +export interface AudioContextSettings { + // TODO: finish these + user: Record; + stream: Record; +} + +export interface ClipsSettings { + allowVoiceRecording: boolean; +} + +export interface InAppFeedbackSettings { + // TODO: finish typing + inAppFeedbackStates: Record; +} + +export interface UserSettings { + versions: UserSettingsVersions; + inbox: InboxSettings; + guilds: GuildsSettings; + userContent: UserContentSettings; + voiceAndVideo: VoiceAndVideoSettings; + textAndImages: TextAndImagesSettings; + notifications: NotificationsSettings; + privacy: PrivacySettings; + // TODO: finish typing + debug: Record; + gameLibrary: GameLibrarySettings; + status: StatusSettings; + localization: LocalizationSettings; + appearance: AppearanceSettings; + guildFolders: GuildFoldersSettings; + audioContextSettings: AudioContextSettings; + clips: ClipsSettings; + inAppFeedbackSettings: InAppFeedbackSettings; +} + +export interface FrecencySettings { + // TODO: type all of these + versions: any; + favoriteGifs: any; + favoriteStickers: any; + stickerFrecency: any; + favoriteEmojis: any; + emojiFrecency: any; + applicationCommandFrecency: any; + favoriteSoundboardSounds: any; + applicationFrecency: any; + playedSoundFrecency: any; + guildAndChannelFrecency: any; + emojiReactionFrecency: any; +} + +export interface ProtoState { + // TODO: type + proto: any; +} + +export class UserSettingsProtoStore extends FluxStore { + settings: UserSettings; + frecencyWithoutFetchingLatest: FrecencySettings; + wasMostRecentUpdateFromServer: boolean; + getState(): Record; + computeState(): Record; + getFullState(): Record; + hasLoaded(settingsType: number): boolean; + getGuildFolders(): GuildFolder[]; + getGuildRecentsDismissedAt(guildId: string): number; + getDismissedGuildContent(guildId: string): Record | null; + // TODO: finish typing + getGuildDismissedContentState(guildId: string): any; + getGuildsProto(): Record; +} diff --git a/packages/discord-types/src/stores/UserStore.d.ts b/packages/discord-types/src/stores/UserStore.d.ts index 323a1df0..0bb12cac 100644 --- a/packages/discord-types/src/stores/UserStore.d.ts +++ b/packages/discord-types/src/stores/UserStore.d.ts @@ -1,10 +1,34 @@ import { FluxStore, User } from ".."; +/** returned by takeSnapshot for persistence */ +export interface UserStoreSnapshot { + /** snapshot format version, currently 1 */ + version: number; + data: { + /** contains only the current user */ + users: User[]; + }; +} + export class UserStore extends FluxStore { - filter(filter: (user: User) => boolean, sort?: boolean): Record; - findByTag(username: string, discriminator: string): User; - forEach(action: (user: User) => void): void; + /** + * filters users and optionally sorts results. + * @param sort if true (default false), sorts alphabetically by username + */ + filter(filter: (user: User) => boolean, sort?: boolean): User[]; + /** + * finds user by username and discriminator. + * for new username system (unique usernames), pass null/undefined as discriminator. + */ + findByTag(username: string, discriminator?: string | null): User | undefined; + /** @param action return false to break iteration early */ + forEach(action: (user: User) => boolean | void): void; getCurrentUser(): User; getUser(userId: string): User; + /** keyed by user ID */ getUsers(): Record; + /** increments when users are added/updated/removed */ + getUserStoreVersion(): number; + /** only includes current user, used for persistence */ + takeSnapshot(): UserStoreSnapshot; } diff --git a/packages/discord-types/src/stores/VoiceStateStore.d.ts b/packages/discord-types/src/stores/VoiceStateStore.d.ts index 84540d99..51724cd2 100644 --- a/packages/discord-types/src/stores/VoiceStateStore.d.ts +++ b/packages/discord-types/src/stores/VoiceStateStore.d.ts @@ -24,19 +24,28 @@ export interface VoiceState extends DiscordRecord { export class VoiceStateStore extends FluxStore { getAllVoiceStates(): VoiceStates; + getVoiceStateVersion(): number; getVoiceStates(guildId?: string | null): UserVoiceStateRecords; getVoiceStatesForChannel(channelId: string): UserVoiceStateRecords; getVideoVoiceStatesForChannel(channelId: string): UserVoiceStateRecords; getVoiceState(guildId: string | null, userId: string): VoiceState | undefined; - getUserVoiceChannelId(guildId: string | null, userId: string): string | undefined; + getDiscoverableVoiceState(guildId: string | null, userId: string): VoiceState | null; getVoiceStateForChannel(channelId: string, userId?: string): VoiceState | undefined; getVoiceStateForUser(userId: string): VoiceState | undefined; + getDiscoverableVoiceStateForUser(userId: string): VoiceState | undefined; + getVoiceStateForSession(userId: string, sessionId?: string | null): VoiceState | null | undefined; + getUserVoiceChannelId(guildId: string | null, userId: string): string | undefined; getCurrentClientVoiceChannelId(guildId: string | null): string | undefined; - isCurrentClientInVoiceChannel(): boolean; + getUsersWithVideo(channelId: string): Set; + getVoicePlatformForChannel(channelId: string, guildId: string): string | undefined; + + isCurrentClientInVoiceChannel(): boolean; isInChannel(channelId: string, userId?: string): boolean; hasVideo(channelId: string): boolean; + + get userHasBeenMovedVersion(): number; } diff --git a/packages/discord-types/src/stores/WindowStore.d.ts b/packages/discord-types/src/stores/WindowStore.d.ts index 53a40e96..619db257 100644 --- a/packages/discord-types/src/stores/WindowStore.d.ts +++ b/packages/discord-types/src/stores/WindowStore.d.ts @@ -1,7 +1,22 @@ import { FluxStore } from ".."; -export class WindowStore extends FluxStore { - isElementFullScreen(): boolean; - isFocused(): boolean; - windowSize(): Record<"width" | "height", number>; +export interface WindowSize { + width: number; + height: number; +} + +export class WindowStore extends FluxStore { + /** returns focused window ID, or null if no window is focused */ + getFocusedWindowId(): string | null; + getLastFocusedWindowId(): string; + /** true if any window is focused (getFocusedWindowId() !== null) */ + isAppFocused(): boolean; + /** @param windowId defaults to current window */ + isElementFullScreen(windowId?: string): boolean; + /** @param windowId defaults to current window */ + isFocused(windowId?: string): boolean; + /** @param windowId defaults to current window */ + isVisible(windowId?: string): boolean; + /** @param windowId defaults to current window, returns {width: 0, height: 0} for invalid ID */ + windowSize(windowId?: string): WindowSize; } diff --git a/packages/discord-types/src/stores/index.d.ts b/packages/discord-types/src/stores/index.d.ts index 756021a5..f0b475de 100644 --- a/packages/discord-types/src/stores/index.d.ts +++ b/packages/discord-types/src/stores/index.d.ts @@ -1,22 +1,47 @@ // please keep in alphabetical order +export * from "./AccessibilityStore"; +export * from "./ActiveJoinedThreadsStore"; +export * from "./ApplicationStore"; export * from "./AuthenticationStore"; +export * from "./CallStore"; +export * from "./ChannelRTCStore"; export * from "./ChannelStore"; export * from "./DraftStore"; export * from "./EmojiStore"; export * from "./FluxStore"; +export * from "./FriendsStore"; +export * from "./GuildChannelStore"; +export * from "./GuildMemberCountStore"; export * from "./GuildMemberStore"; export * from "./GuildRoleStore"; +export * from "./GuildScheduledEventStore"; export * from "./GuildStore"; +export * from "./InstantInviteStore"; +export * from "./InviteStore"; +export * from "./LocaleStore"; +export * from "./MediaEngineStore"; export * from "./MessageStore"; +export * from "./NotificationSettingsStore"; +export * from "./OverridePremiumTypeStore"; +export * from "./PermissionStore"; export * from "./PresenceStore"; +export * from "./ReadStateStore"; export * from "./RelationshipStore"; +export * from "./RTCConnectionStore"; +export * from "./RunningGameStore"; export * from "./SelectedChannelStore"; export * from "./SelectedGuildStore"; +export * from "./SoundboardStore"; +export * from "./SpellCheckStore"; +export * from "./SpotifyStore"; export * from "./StickersStore"; export * from "./StreamerModeStore"; export * from "./ThemeStore"; export * from "./TypingStore"; +export * from "./UploadAttachmentStore"; +export * from "./UserGuildSettingsStore"; export * from "./UserProfileStore"; +export * from "./UserSettingsProtoStore"; export * from "./UserStore"; export * from "./VoiceStateStore"; export * from "./WindowStore"; diff --git a/src/plugins/betterFolders/FolderSideBar.tsx b/src/plugins/betterFolders/FolderSideBar.tsx index 0e643958..fb33d931 100644 --- a/src/plugins/betterFolders/FolderSideBar.tsx +++ b/src/plugins/betterFolders/FolderSideBar.tsx @@ -17,13 +17,12 @@ */ import ErrorBoundary from "@components/ErrorBoundary"; -import { findComponentByCodeLazy, findStoreLazy } from "@webpack"; -import { Animations, useStateFromStores } from "@webpack/common"; +import { findComponentByCodeLazy } from "@webpack"; +import { Animations, ChannelRTCStore, useStateFromStores } from "@webpack/common"; import type { CSSProperties } from "react"; import { ExpandedGuildFolderStore, settings, SortedGuildStore } from "."; -const ChannelRTCStore = findStoreLazy("ChannelRTCStore"); const GuildsBar = findComponentByCodeLazy('("guildsnav")'); function getExpandedFolderIds() { diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx index c80b5199..100b74d8 100644 --- a/src/plugins/fakeNitro/index.tsx +++ b/src/plugins/fakeNitro/index.tsx @@ -25,13 +25,11 @@ import { Logger } from "@utils/Logger"; import definePlugin, { OptionType, Patch } from "@utils/types"; import type { Emoji, Message, Sticker } from "@vencord/discord-types"; import { StickerFormatType } from "@vencord/discord-types/enums"; -import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack"; -import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, StickersStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common"; +import { findByCodeLazy, findByPropsLazy, proxyLazyWebpack } from "@webpack"; +import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, StickersStore, UploadHandler, UserSettingsActionCreators, UserSettingsProtoStore, UserStore } from "@webpack/common"; import { applyPalette, GIFEncoder, quantize } from "gifenc"; import type { ReactElement, ReactNode } from "react"; -const UserSettingsProtoStore = findStoreLazy("UserSettingsProtoStore"); - const BINARY_READ_OPTIONS = findByPropsLazy("readerFactory"); function searchProtoClassField(localName: string, protoClass: any) { diff --git a/src/plugins/ignoreActivities/index.tsx b/src/plugins/ignoreActivities/index.tsx index 14863ad6..73c2f01a 100644 --- a/src/plugins/ignoreActivities/index.tsx +++ b/src/plugins/ignoreActivities/index.tsx @@ -11,8 +11,7 @@ import { Flex } from "@components/Flex"; import { Devs } from "@utils/constants"; import { Margins } from "@utils/margins"; import definePlugin, { OptionType } from "@utils/types"; -import { findStoreLazy } from "@webpack"; -import { Button, Forms, showToast, TextInput, Toasts, Tooltip, useEffect, useState } from "@webpack/common"; +import { Button, Forms, RunningGameStore, showToast, TextInput, Toasts, Tooltip, useEffect, useState } from "@webpack/common"; const enum ActivitiesTypes { Game, @@ -30,8 +29,6 @@ const enum FilterMode { Blacklist } -const RunningGameStore = findStoreLazy("RunningGameStore"); - const ShowCurrentGame = getUserSettingLazy("status", "showCurrentGame")!; function ToggleIcon(activity: IgnoredActivity, tooltipText: string, path: string, fill: string) { diff --git a/src/plugins/memberCount/MemberCount.tsx b/src/plugins/memberCount/MemberCount.tsx index 6887af51..e20cc8e8 100644 --- a/src/plugins/memberCount/MemberCount.tsx +++ b/src/plugins/memberCount/MemberCount.tsx @@ -6,9 +6,9 @@ import { getCurrentChannel } from "@utils/discord"; import { isObjectEmpty } from "@utils/misc"; -import { ChannelStore, PermissionsBits, PermissionStore, SelectedChannelStore, Tooltip, useEffect, useStateFromStores, VoiceStateStore } from "@webpack/common"; +import { ChannelStore, GuildMemberCountStore, PermissionsBits, PermissionStore, SelectedChannelStore, Tooltip, useEffect, useStateFromStores, VoiceStateStore } from "@webpack/common"; -import { ChannelMemberStore, cl, GuildMemberCountStore, numberFormat, settings, ThreadMemberListStore } from "."; +import { ChannelMemberStore, cl, numberFormat, settings, ThreadMemberListStore } from "."; import { CircleIcon } from "./CircleIcon"; import { OnlineMemberCountStore } from "./OnlineMemberCountStore"; import { VoiceIcon } from "./VoiceIcon"; @@ -40,7 +40,7 @@ export function MemberCount({ isTooltip, tooltipGuildId }: { isTooltip?: true; t const totalCount = useStateFromStores( [GuildMemberCountStore], - () => GuildMemberCountStore.getMemberCount(guildId) + () => GuildMemberCountStore.getMemberCount(guildId!) ); let onlineCount = useStateFromStores( diff --git a/src/plugins/memberCount/OnlineMemberCountStore.ts b/src/plugins/memberCount/OnlineMemberCountStore.ts index 54cc4697..37dbc65a 100644 --- a/src/plugins/memberCount/OnlineMemberCountStore.ts +++ b/src/plugins/memberCount/OnlineMemberCountStore.ts @@ -22,7 +22,7 @@ export const OnlineMemberCountStore = proxyLazy(() => { async _ensureCount(guildId: string) { if (onlineMemberMap.has(guildId)) return; - await ChannelActionCreators.preload(guildId, GuildChannelStore.getDefaultChannel(guildId).id); + await ChannelActionCreators.preload(guildId, GuildChannelStore.getDefaultChannel(guildId)!.id); } ensureCount(guildId?: string) { diff --git a/src/plugins/memberCount/index.tsx b/src/plugins/memberCount/index.tsx index ae9c1793..66d9d44b 100644 --- a/src/plugins/memberCount/index.tsx +++ b/src/plugins/memberCount/index.tsx @@ -28,7 +28,6 @@ import { findStoreLazy } from "@webpack"; import { MemberCount } from "./MemberCount"; -export const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId?: string): number | null; }; export const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & { getProps(guildId?: string, channelId?: string): { groups: { count: number; id: string; }[]; }; }; diff --git a/src/plugins/petpet/index.ts b/src/plugins/petpet/index.ts index 40fd0af8..087bca1c 100644 --- a/src/plugins/petpet/index.ts +++ b/src/plugins/petpet/index.ts @@ -21,8 +21,7 @@ import { Devs } from "@utils/constants"; import { makeLazy } from "@utils/lazy"; import definePlugin from "@utils/types"; import { CommandArgument, CommandContext } from "@vencord/discord-types"; -import { findByPropsLazy } from "@webpack"; -import { DraftType, UploadHandler, UploadManager, UserUtils } from "@webpack/common"; +import { DraftType, UploadAttachmentStore, UploadHandler, UploadManager, UserUtils } from "@webpack/common"; import { applyPalette, GIFEncoder, quantize } from "gifenc"; const DEFAULT_DELAY = 20; @@ -36,8 +35,6 @@ const getFrames = makeLazy(() => Promise.all( )) ); -const UploadStore = findByPropsLazy("getUploads"); - function loadImage(source: File | string) { const isFile = source instanceof File; const url = isFile ? URL.createObjectURL(source) : source; @@ -59,7 +56,7 @@ async function resolveImage(options: CommandArgument[], ctx: CommandContext, noS for (const opt of options) { switch (opt.name) { case "image": - const upload = UploadStore.getUpload(ctx.channel.id, opt.name, DraftType.SlashCommand); + const upload = UploadAttachmentStore.getUpload(ctx.channel.id, opt.name, DraftType.SlashCommand); if (upload) { if (!upload.isImage) { UploadManager.clearAll(ctx.channel.id, DraftType.SlashCommand); diff --git a/src/plugins/previewMessage/index.tsx b/src/plugins/previewMessage/index.tsx index aa52a506..d2a6a12f 100644 --- a/src/plugins/previewMessage/index.tsx +++ b/src/plugins/previewMessage/index.tsx @@ -21,10 +21,7 @@ import { generateId, sendBotMessage } from "@api/Commands"; import { Devs } from "@utils/constants"; import definePlugin, { IconComponent, StartAt } from "@utils/types"; import { CloudUpload, MessageAttachment } from "@vencord/discord-types"; -import { findByPropsLazy } from "@webpack"; -import { DraftStore, DraftType, UserStore, useStateFromStores } from "@webpack/common"; - -const UploadStore = findByPropsLazy("getUploads"); +import { DraftStore, DraftType, UploadAttachmentStore, UserStore, useStateFromStores } from "@webpack/common"; const getDraft = (channelId: string) => DraftStore.getDraft(channelId, DraftType.ChannelMessage); @@ -44,7 +41,7 @@ const getImageBox = (url: string): Promise<{ width: number, height: number; } | const getAttachments = async (channelId: string) => await Promise.all( - UploadStore.getUploads(channelId, DraftType.ChannelMessage) + UploadAttachmentStore.getUploads(channelId, DraftType.ChannelMessage) .map(async (upload: CloudUpload) => { const { isImage, filename, spoiler, item: { file } } = upload; const url = URL.createObjectURL(file); @@ -94,7 +91,7 @@ const PreviewButton: ChatBarButtonFactory = ({ isAnyChat, isEmpty, type: { attac if (!isAnyChat) return null; - const hasAttachments = attachments && UploadStore.getUploads(channelId, DraftType.ChannelMessage).length > 0; + const hasAttachments = attachments && UploadAttachmentStore.getUploads(channelId, DraftType.ChannelMessage).length > 0; const hasContent = !isEmpty && draft?.length > 0; if (!hasContent && !hasAttachments) return null; diff --git a/src/plugins/readAllNotificationsButton/index.tsx b/src/plugins/readAllNotificationsButton/index.tsx index 6fc23061..8031a3b9 100644 --- a/src/plugins/readAllNotificationsButton/index.tsx +++ b/src/plugins/readAllNotificationsButton/index.tsx @@ -23,30 +23,14 @@ import { TextButton } from "@components/Button"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; -import { Channel } from "@vencord/discord-types"; -import { findStoreLazy } from "@webpack"; -import { FluxDispatcher, GuildChannelStore, GuildStore, React, ReadStateStore } from "@webpack/common"; - -interface ThreadJoined { - channel: Channel; - joinTimestamp: number; -} - -type ThreadsJoined = Record; -type ThreadsJoinedByParent = Record; - -interface ActiveJoinedThreadsStore { - getActiveJoinedThreadsForGuild(guildId: string): ThreadsJoinedByParent; -} - -const ActiveJoinedThreadsStore: ActiveJoinedThreadsStore = findStoreLazy("ActiveJoinedThreadsStore"); +import { ActiveJoinedThreadsStore, FluxDispatcher, GuildChannelStore, GuildStore, React, ReadStateStore } from "@webpack/common"; function onClick() { const channels: Array = []; Object.values(GuildStore.getGuilds()).forEach(guild => { - GuildChannelStore.getChannels(guild.id).SELECTABLE // Array<{ channel, comparator }> - .concat(GuildChannelStore.getChannels(guild.id).VOCAL) // Array<{ channel, comparator }> + GuildChannelStore.getChannels(guild.id).SELECTABLE + .concat(GuildChannelStore.getChannels(guild.id).VOCAL) .concat( Object.values(ActiveJoinedThreadsStore.getActiveJoinedThreadsForGuild(guild.id)) .flatMap(threadChannels => Object.values(threadChannels)) diff --git a/src/plugins/relationshipNotifier/functions.ts b/src/plugins/relationshipNotifier/functions.ts index 19f36086..da7838b9 100644 --- a/src/plugins/relationshipNotifier/functions.ts +++ b/src/plugins/relationshipNotifier/functions.ts @@ -17,11 +17,11 @@ */ import { getUniqueUsername, openUserProfile } from "@utils/discord"; -import { ChannelType } from "@vencord/discord-types/enums"; +import { ChannelType, RelationshipType } from "@vencord/discord-types/enums"; import { UserUtils } from "@webpack/common"; import settings from "./settings"; -import { ChannelDelete, GuildDelete, RelationshipRemove, RelationshipType } from "./types"; +import { ChannelDelete, GuildDelete, RelationshipRemove } from "./types"; import { deleteGroup, deleteGuild, getGroup, getGuild, GuildAvailabilityStore, notify } from "./utils"; let manuallyRemovedFriend: string | undefined; diff --git a/src/plugins/relationshipNotifier/types.ts b/src/plugins/relationshipNotifier/types.ts index 5d3d12d4..914f1a43 100644 --- a/src/plugins/relationshipNotifier/types.ts +++ b/src/plugins/relationshipNotifier/types.ts @@ -51,10 +51,3 @@ export interface SimpleGuild { name: string; iconURL?: string; } - -export const enum RelationshipType { - FRIEND = 1, - BLOCKED = 2, - INCOMING_REQUEST = 3, - OUTGOING_REQUEST = 4, -} diff --git a/src/plugins/relationshipNotifier/utils.ts b/src/plugins/relationshipNotifier/utils.ts index 206cb63c..24c7cdef 100644 --- a/src/plugins/relationshipNotifier/utils.ts +++ b/src/plugins/relationshipNotifier/utils.ts @@ -21,12 +21,12 @@ import { popNotice, showNotice } from "@api/Notices"; import { showNotification } from "@api/Notifications"; import { getUniqueUsername, openUserProfile } from "@utils/discord"; import { FluxStore } from "@vencord/discord-types"; -import { ChannelType } from "@vencord/discord-types/enums"; +import { ChannelType, RelationshipType } from "@vencord/discord-types/enums"; import { findStoreLazy } from "@webpack"; import { ChannelStore, GuildMemberStore, GuildStore, RelationshipStore, UserStore, UserUtils } from "@webpack/common"; import settings from "./settings"; -import { RelationshipType, SimpleGroupChannel, SimpleGuild } from "./types"; +import { SimpleGroupChannel, SimpleGuild } from "./types"; export const GuildAvailabilityStore = findStoreLazy("GuildAvailabilityStore") as FluxStore & { totalGuilds: number; diff --git a/src/plugins/typingIndicator/index.tsx b/src/plugins/typingIndicator/index.tsx index 4e369ee9..ecd8c44d 100644 --- a/src/plugins/typingIndicator/index.tsx +++ b/src/plugins/typingIndicator/index.tsx @@ -24,13 +24,11 @@ import { buildSeveralUsers } from "@plugins/typingTweaks"; import { Devs } from "@utils/constants"; import { getIntlMessage } from "@utils/discord"; import definePlugin, { OptionType } from "@utils/types"; -import { findComponentByCodeLazy, findStoreLazy } from "@webpack"; -import { GuildMemberStore, RelationshipStore, SelectedChannelStore, Tooltip, TypingStore, UserStore, UserSummaryItem, useStateFromStores } from "@webpack/common"; +import { findComponentByCodeLazy } from "@webpack"; +import { GuildMemberStore, RelationshipStore, SelectedChannelStore, Tooltip, TypingStore, UserGuildSettingsStore, UserStore, UserSummaryItem, useStateFromStores } from "@webpack/common"; const ThreeDots = findComponentByCodeLazy(".dots,", "dotRadius:"); -const UserGuildSettingsStore = findStoreLazy("UserGuildSettingsStore"); - const enum IndicatorMode { Dots = 1 << 0, Avatars = 1 << 1 diff --git a/src/plugins/voiceMessages/DesktopRecorder.tsx b/src/plugins/voiceMessages/DesktopRecorder.tsx index 18581ad1..8b6bc6d0 100644 --- a/src/plugins/voiceMessages/DesktopRecorder.tsx +++ b/src/plugins/voiceMessages/DesktopRecorder.tsx @@ -17,11 +17,10 @@ */ import { PluginNative } from "@utils/types"; -import { Button, showToast, Toasts, useState } from "@webpack/common"; +import { Button, MediaEngineStore, showToast, Toasts, useState } from "@webpack/common"; import type { VoiceRecorder } from "."; import { settings } from "./settings"; -import { MediaEngineStore } from "./utils"; const Native = VencordNative.pluginHelpers.VoiceMessages as PluginNative; diff --git a/src/plugins/voiceMessages/VoicePreview.tsx b/src/plugins/voiceMessages/VoicePreview.tsx index 9c77d832..05bf23d4 100644 --- a/src/plugins/voiceMessages/VoicePreview.tsx +++ b/src/plugins/voiceMessages/VoicePreview.tsx @@ -19,7 +19,7 @@ import { useTimer } from "@utils/react"; import { findComponentByCodeLazy } from "@webpack"; -import { cl } from "./utils"; +import { cl } from "."; interface VoiceMessageProps { src: string; diff --git a/src/plugins/voiceMessages/WebRecorder.tsx b/src/plugins/voiceMessages/WebRecorder.tsx index eb77b199..8bac28a2 100644 --- a/src/plugins/voiceMessages/WebRecorder.tsx +++ b/src/plugins/voiceMessages/WebRecorder.tsx @@ -16,11 +16,10 @@ * along with this program. If not, see . */ -import { Button, useState } from "@webpack/common"; +import { Button, MediaEngineStore, useState } from "@webpack/common"; import type { VoiceRecorder } from "."; import { settings } from "./settings"; -import { MediaEngineStore } from "./utils"; export const VoiceRecorderWeb: VoiceRecorder = ({ setAudioBlob, onRecordingChange }) => { const [recording, setRecording] = useState(false); diff --git a/src/plugins/voiceMessages/index.tsx b/src/plugins/voiceMessages/index.tsx index 4210d89c..3775114d 100644 --- a/src/plugins/voiceMessages/index.tsx +++ b/src/plugins/voiceMessages/index.tsx @@ -24,6 +24,7 @@ import { Microphone } from "@components/Icons"; import { Link } from "@components/Link"; import { Paragraph } from "@components/Paragraph"; import { Devs } from "@utils/constants"; +import { classNameFactory } from "@utils/css"; import { Margins } from "@utils/margins"; import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal"; import { useAwaiter } from "@utils/react"; @@ -37,7 +38,6 @@ import { ComponentType } from "react"; import { VoiceRecorderDesktop } from "./DesktopRecorder"; import { settings } from "./settings"; -import { cl } from "./utils"; import { VoicePreview } from "./VoicePreview"; import { VoiceRecorderWeb } from "./WebRecorder"; @@ -45,6 +45,7 @@ const CloudUpload: typeof TCloudUpload = findLazy(m => m.prototype?.trackUploadF const PendingReplyStore = findStoreLazy("PendingReplyStore"); const OptionClasses = findByPropsLazy("optionName", "optionIcon", "optionLabel"); +export const cl = classNameFactory("vc-vmsg-"); export type VoiceRecorder = ComponentType<{ setAudioBlob(blob: Blob): void; onRecordingChange?(recording: boolean): void; diff --git a/src/plugins/voiceMessages/utils.ts b/src/plugins/voiceMessages/utils.ts deleted file mode 100644 index 5a6bfa85..00000000 --- a/src/plugins/voiceMessages/utils.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2023 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . -*/ - -import { classNameFactory } from "@utils/css"; -import { findStoreLazy } from "@webpack"; - -export const MediaEngineStore = findStoreLazy("MediaEngineStore"); -export const cl = classNameFactory("vc-vmsg-"); diff --git a/src/webpack/common/stores.ts b/src/webpack/common/stores.ts index 1bad480b..f1ea29a9 100644 --- a/src/webpack/common/stores.ts +++ b/src/webpack/common/stores.ts @@ -31,16 +31,20 @@ export let MessageStore: Omit & GenericStore & { getMessages(chanId: string): any; }; -export let PermissionStore: GenericStore; -export let GuildChannelStore: GenericStore; -export let ReadStateStore: GenericStore; +export let PermissionStore: t.PermissionStore; +export let GuildChannelStore: t.GuildChannelStore; +export let ReadStateStore: t.ReadStateStore; export let PresenceStore: t.PresenceStore; +export let AccessibilityStore: t.AccessibilityStore; export let GuildStore: t.GuildStore; export let GuildRoleStore: t.GuildRoleStore; +export let GuildScheduledEventStore: t.GuildScheduledEventStore; +export let GuildMemberCountStore: t.GuildMemberCountStore; export let GuildMemberStore: t.GuildMemberStore; export let UserStore: t.UserStore; export let AuthenticationStore: t.AuthenticationStore; +export let ApplicationStore: t.ApplicationStore; export let UserProfileStore: t.UserProfileStore; export let SelectedChannelStore: t.SelectedChannelStore; export let SelectedGuildStore: t.SelectedGuildStore; @@ -55,12 +59,33 @@ export let ThemeStore: t.ThemeStore; export let WindowStore: t.WindowStore; export let DraftStore: t.DraftStore; export let StreamerModeStore: t.StreamerModeStore; +export let SpotifyStore: t.SpotifyStore; + +export let MediaEngineStore: t.MediaEngineStore; +export let NotificationSettingsStore: t.NotificationSettingsStore; +export let SpellCheckStore: t.SpellCheckStore; +export let UploadAttachmentStore: t.UploadAttachmentStore; +export let OverridePremiumTypeStore: t.OverridePremiumTypeStore; +export let RunningGameStore: t.RunningGameStore; +export let ActiveJoinedThreadsStore: t.ActiveJoinedThreadsStore; +export let UserGuildSettingsStore: t.UserGuildSettingsStore; +export let UserSettingsProtoStore: t.UserSettingsProtoStore; +export let CallStore: t.CallStore; +export let ChannelRTCStore: t.ChannelRTCStore; +export let FriendsStore: t.FriendsStore; +export let InstantInviteStore: t.InstantInviteStore; +export let InviteStore: t.InviteStore; +export let LocaleStore: t.LocaleStore; +export let RTCConnectionStore: t.RTCConnectionStore; +export let SoundboardStore: t.SoundboardStore; /** * @see jsdoc of {@link t.useStateFromStores} */ export const useStateFromStores: t.useStateFromStores = findByCodeLazy("useStateFromStores"); +waitForStore("AccessibilityStore", s => AccessibilityStore = s); +waitForStore("ApplicationStore", s => ApplicationStore = s); waitForStore("AuthenticationStore", s => AuthenticationStore = s); waitForStore("DraftStore", s => DraftStore = s); waitForStore("UserStore", s => UserStore = s); @@ -71,11 +96,16 @@ waitForStore("SelectedGuildStore", m => SelectedGuildStore = m); waitForStore("GuildStore", m => GuildStore = m); waitForStore("GuildMemberStore", m => GuildMemberStore = m); waitForStore("RelationshipStore", m => RelationshipStore = m); +waitForStore("MediaEngineStore", m => MediaEngineStore = m); +waitForStore("NotificationSettingsStore", m => NotificationSettingsStore = m); +waitForStore("SpellcheckStore", m => SpellCheckStore = m); waitForStore("PermissionStore", m => PermissionStore = m); waitForStore("PresenceStore", m => PresenceStore = m); waitForStore("ReadStateStore", m => ReadStateStore = m); waitForStore("GuildChannelStore", m => GuildChannelStore = m); waitForStore("GuildRoleStore", m => GuildRoleStore = m); +waitForStore("GuildScheduledEventStore", m => GuildScheduledEventStore = m); +waitForStore("GuildMemberCountStore", m => GuildMemberCountStore = m); waitForStore("MessageStore", m => MessageStore = m); waitForStore("WindowStore", m => WindowStore = m); waitForStore("EmojiStore", m => EmojiStore = m); @@ -83,6 +113,21 @@ waitForStore("StickersStore", m => StickersStore = m); waitForStore("TypingStore", m => TypingStore = m); waitForStore("VoiceStateStore", m => VoiceStateStore = m); waitForStore("StreamerModeStore", m => StreamerModeStore = m); +waitForStore("SpotifyStore", m => SpotifyStore = m); +waitForStore("OverridePremiumTypeStore", m => OverridePremiumTypeStore = m); +waitForStore("UploadAttachmentStore", m => UploadAttachmentStore = m); +waitForStore("RunningGameStore", m => RunningGameStore = m); +waitForStore("ActiveJoinedThreadsStore", m => ActiveJoinedThreadsStore = m); +waitForStore("UserGuildSettingsStore", m => UserGuildSettingsStore = m); +waitForStore("UserSettingsProtoStore", m => UserSettingsProtoStore = m); +waitForStore("CallStore", m => CallStore = m); +waitForStore("ChannelRTCStore", m => ChannelRTCStore = m); +waitForStore("FriendsStore", m => FriendsStore = m); +waitForStore("InstantInviteStore", m => InstantInviteStore = m); +waitForStore("InviteStore", m => InviteStore = m); +waitForStore("LocaleStore", m => LocaleStore = m); +waitForStore("RTCConnectionStore", m => RTCConnectionStore = m); +waitForStore("SoundboardStore", m => SoundboardStore = m); waitForStore("ThemeStore", m => { ThemeStore = m; // Importing this directly causes all webpack commons to be imported, which can easily cause circular dependencies.