Type more stores (#4627)

Co-authored-by: V <vendicated@riseup.net>
This commit is contained in:
thororen 2026-09-26 13:45:27 -04:00 • committed by GitHub
parent 7393fac768
commit 17907c8032
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
55 changed files with 893 additions and 206 deletions

View file

@ -12,6 +12,7 @@ export const enum DraftType {
SlashCommand = 5,
ForwardContextMessage = 6,
InteractionModal = 7,
ScheduledMessage = 8,
}
export const enum EmojiIntention {

View file

@ -5,6 +5,7 @@ export type ForcedColorsPreference = "none" | "active";
export type ContrastPreference = "no-preference" | "more" | "less" | "custom";
export type RoleStyle = "username" | "dot" | "hidden";
export type ContrastMode = "default" | "high";
export type YouBarAnimationPreference = "animate-never" | "animate-always" | "respect-motion-settings";
export interface AccessibilityState {
fontSize: number;
@ -32,6 +33,15 @@ export interface AccessibilityState {
syncProfileThemeWithUserTheme: boolean;
enableCustomCursor: boolean;
switchIconsEnabled: boolean;
officialMessageStyle: string;
expressionPickerFormat: string;
condensePickerWhenNarrow: boolean;
appsButtonEnabled: boolean;
emojiButtonEnabled: boolean;
gifButtonEnabled: boolean;
stickerButtonEnabled: boolean;
youBarNameplateAnimation: YouBarAnimationPreference;
youBarAvatarDecoAnimation: YouBarAnimationPreference;
}
export class AccessibilityStore extends FluxStore {
@ -55,6 +65,17 @@ export class AccessibilityStore extends FluxStore {
get isMessageGroupSpacingIncreased(): boolean;
get isMessageGroupSpacingDecreased(): boolean;
get isSubmitButtonEnabled(): boolean;
get isAppsButtonEnabled(): boolean;
get isEmojiButtonEnabled(): boolean;
get isGifButtonEnabled(): boolean;
get isStickerButtonEnabled(): boolean;
get officialMessageStyle(): string;
get expressionPickerFormat(): string;
get condensePickerWhenNarrow(): boolean;
get youBarNameplateAnimation(): YouBarAnimationPreference;
get youBarAvatarDecoAnimation(): YouBarAnimationPreference;
get animateYouBarNameplate(): boolean;
get animateYouBarAvatarDeco(): boolean;
get syncProfileThemeWithUserTheme(): boolean;
get systemPrefersReducedMotion(): ReducedMotionPreference;
get rawPrefersReducedMotion(): ReducedMotionPreference;

View file

@ -5,6 +5,11 @@ export interface ApplicationStoreState {
botUserIdToAppUsage: Record<string, ApplicationUsage>;
}
export interface GuildEmbeddedApplication {
applicationId: string;
status: unknown;
}
export interface ApplicationUsage {
applicationId: string;
lastUsedMs: number;
@ -13,13 +18,15 @@ export interface ApplicationUsage {
export class ApplicationStore extends FluxStore {
_getAllApplications(): Application[];
getState(): ApplicationStoreState;
getApplication(applicationId: string): Application;
getApplication(applicationId: string): Application | undefined;
getApplicationByName(name: string): Application | undefined;
getApplicationLastUpdated(applicationId: string): number | undefined;
getGuildApplication(guildId: string, type: ApplicationType): Application | undefined;
getGuildApplicationIds(guildId: string): string[];
getGuildEmbeddedApplications(guildId: string, surface: string): GuildEmbeddedApplication[] | undefined;
getAppIdForBotUserId(botUserId: string): string | undefined;
getFetchingOrFailedFetchingIds(): string[];
isFetchingApplication(applicationId: string): boolean;
isHydrated(applicationId: string): boolean;
didFetchingApplicationFail(applicationId: string): boolean;
}

View file

@ -2,6 +2,7 @@ import { FluxStore } from "..";
export interface ApplicationStreamPreviewStore extends FluxStore {
getIsPreviewLoading: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => boolean;
getPreviewURL: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => Promise<string | null>;
getPreviewURL: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => string | undefined;
getPreviewURLForStreamKey: (streamKey: string) => ReturnType<ApplicationStreamPreviewStore["getPreviewURL"]>;
shouldFetchPreview: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => boolean;
}

View file

@ -10,6 +10,9 @@ export interface StreamMetadata {
id: string | null,
pid: number | null,
sourceName: string | null;
previewDisabled?: boolean;
sourceIcon?: string | null;
sourceId?: string | null;
}
export interface StreamingStoreState {
@ -28,12 +31,18 @@ export interface ApplicationStreamingStore extends FluxStore {
getAllApplicationStreamsForChannel: (channelId: string | bigint) => ApplicationStream[];
getAllActiveStreamsForChannel: (channelId: string | bigint) => Stream[];
getAnyStreamForUser: (userId: string | bigint) => Stream | ApplicationStream | null;
getAnyDiscoverableStreamForUser: (userId: string | bigint) => ApplicationStream | null;
getStreamForUser: (userId: string | bigint, guildId?: string | bigint | null) => Stream | null;
getCurrentUserActiveStream: () => Stream | null;
getLastActiveStream: () => Stream | null;
getState: () => StreamingStoreState;
getRTCStream: (streamKey: string) => RTCStream | null;
getStreamerActiveStreamMetadata: () => StreamMetadata;
getViewerIds: (stream: ApplicationStream) => string[];
getStreamerActiveStreamMetadata: () => StreamMetadata | null;
getStreamerActiveStreamMetadataForStream: (streamKey: string) => StreamMetadata | null;
getIsActiveStreamPreviewDisabled: (streamKey: string) => boolean;
getCurrentAppIntent: () => unknown;
getStreamingState: () => Omit<StreamingStoreState, "activeStreams"> & { activeStreams: [string, Stream][]; };
isStreamMarkedFull: (streamKey: string) => boolean;
getViewerIds: (stream: ApplicationStream | string) => string[];
isSelfStreamHidden: (channelId: string | bigint | null) => boolean;
}

View file

@ -0,0 +1,18 @@
import { FluxStore } from "..";
export interface AuthorizedAppToken {
id: string;
application: { id: string; parent_id?: string | null;[key: string]: unknown; };
scopes: string[];
}
export type AuthorizedAppsFetchState = "NOT_FETCHED" | "FETCHING" | "FETCHED";
export class AuthorizedAppsStore extends FluxStore {
getNewestTokenForApplication(applicationId: string): AuthorizedAppToken | null;
getNewestTokens(): AuthorizedAppToken[];
getNewestTokensForNonChildrenApplications(): AuthorizedAppToken[];
getFetchState(): AuthorizedAppsFetchState;
getFetchStateForApplication(applicationId: string): AuthorizedAppsFetchState;
getApplicationFetchStateVersion(): number;
}

View file

@ -0,0 +1,18 @@
import { FluxStore } from "..";
export interface ChannelMemberGroup {
count: number;
id: string;
}
export interface ChannelMemberProps {
listId: string;
groups: ChannelMemberGroup[];
rows: unknown[];
version: number;
}
export class ChannelMemberStore extends FluxStore {
getProps(guildId?: string, channelId?: string): ChannelMemberProps;
getRows(guildId?: string, channelId?: string): ChannelMemberProps["rows"];
}

View file

@ -78,15 +78,14 @@ export interface ChannelRTCState {
export class ChannelRTCStore extends FluxStore {
getActivityParticipants(channelId: string): ActivityParticipant[];
getAllChatOpen(): Record<string, boolean>;
getChatOpen(channelId: string): boolean;
getFilteredParticipants(channelId: string): Participant[];
getGuildRingingUsers(channelId: string): Set<string>;
getLayout(channelId: string, context?: RTCLayoutContext): RTCLayout;
getMode(channelId: string): RTCMode;
getOpenChatChannelIds(): Set<string>;
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;

View file

@ -0,0 +1,13 @@
import { FluxStore } from "..";
export type ChannelSection = "SEARCH" | "SIDEBAR_CHAT" | "FRIENDS" | "PROFILE" | "SUMMARIES" | "MEMBERS" | "CONVERSATIONS" | "NONE";
export class ChannelSectionStore extends FluxStore {
getSection(channelId: string, isProfile?: boolean): ChannelSection;
isFriendsSidebarAvailable(): boolean;
getCurrentSidebarChannelId(channelId: string): string | null;
getCurrentSidebarMessageId(channelId: string): string | null | undefined;
getCurrentSearchContextId(): string | null;
getGuildSidebarState(guildId?: string): unknown;
getSidebarState(channelId?: string): unknown;
}

View file

@ -0,0 +1,14 @@
import { FluxStore } from "..";
export interface GradientPreset {
id: number;
[key: string]: unknown;
}
export class ClientThemesBackgroundStore extends FluxStore {
get gradientPreset(): GradientPreset | undefined;
get isPreview(): boolean;
get isCoachmark(): boolean;
get mobilePendingThemeIndex(): number | undefined;
getLinearGradient(): string | null;
}

View file

@ -0,0 +1,6 @@
import { FluxStore } from "..";
export class CollapsedVoiceChannelStore extends FluxStore {
getCollapsed(): Record<string, boolean>;
isCollapsed(channelId: string): boolean;
}

View file

@ -0,0 +1,15 @@
import { ConnectedAccount, FluxStore } from "..";
export class ConnectedAccountsStore extends FluxStore {
getAccounts(): ConnectedAccount[];
getLocalAccounts(): ConnectedAccount[];
getAccount(accountId: string | null | undefined, type: string): ConnectedAccount | undefined;
getLocalAccount(type: string): ConnectedAccount | undefined;
isFetching(): boolean;
isJoining(integrationId: string): boolean;
joinErrorMessage(integrationId: string): string | undefined;
isSuggestedAccountType(type: string): boolean;
addPendingAuthorizedState(state: string): void;
deletePendingAuthorizedState(state: string): void;
hasPendingAuthorizedState(state: string): boolean;
}

View file

@ -1,9 +1,10 @@
import { FluxStore } from "..";
import { Command, FluxStore } from "..";
import { DraftType } from "../../enums";
export interface Draft {
timestamp: number;
draft: string;
command?: Command;
}
export interface ThreadSettingsDraft {
@ -15,10 +16,16 @@ export interface ThreadSettingsDraft {
location?: string;
}
export interface ScheduledMessageDraft {
timestamp: number;
[key: string]: unknown;
}
export type ChannelDrafts = {
[DraftType.ThreadSettings]: ThreadSettingsDraft;
[DraftType.ScheduledMessage]: ScheduledMessageDraft;
} & {
[key in Exclude<DraftType, DraftType.ThreadSettings>]: Draft;
[key in Exclude<DraftType, DraftType.ThreadSettings | DraftType.ScheduledMessage>]: Draft;
};
export type UserDrafts = Partial<Record<string, ChannelDrafts>>;
@ -28,6 +35,8 @@ export class DraftStore extends FluxStore {
getState(): DraftState;
getRecentlyEditedDrafts(type: DraftType): Array<Draft & { channelId: string; }>;
getDraft(channelId: string, type: DraftType): string;
getDraftCommand(channelId: string, type: DraftType): Command | undefined;
getScheduledMessage(channelId: string): ScheduledMessageDraft | undefined;
getThreadSettings(channelId: string): ThreadSettingsDraft | null | undefined;
getThreadDraftWithParentMessageId(parentMessageId: string): ThreadSettingsDraft | null | undefined;

View file

@ -412,6 +412,11 @@ export class EmojiStore extends FluxStore {
* @returns Array of usable custom emojis.
*/
getUsableGuildEmoji(guildId?: string | null): CustomEmoji[];
/**
* Gets ids of custom emojis hidden in a guild.
* @param guildId Guild id to get hidden emoji ids for.
*/
getHiddenEmojiIds(guildId?: string | null): Set<string>;
/**
* Gets newly added emojis for a guild.
* @param guildId Guild id to get emojis for.
@ -446,8 +451,15 @@ export class EmojiStore extends FluxStore {
* @returns True if user has usable emojis.
*/
hasUsableEmojiInAnyGuild(): boolean;
/** Internal method for ordering search results. */
getSearchResultsOrder(...args: any[]): any;
/**
* Orders emoji search results by match quality and frecency.
* @param emojis Emojis to order.
* @param query Search query.
* @param count Max results, 0 for no limit.
* @param intention Where the emoji will be used, picks reaction or chat frecency.
* @returns Ordered emojis.
*/
getSearchResultsOrder<T extends Emoji>(emojis: T[], query: string, count: number, intention: EmojiIntention): T[];
/**
* Gets the serializable state for persistence.
* @returns Current store state.

View file

@ -63,6 +63,25 @@ interface TrackedExposures {
[key: GuildExposureKey]: ExperimentExposureEntry;
}
interface ExperimentExposureDescriptor {
type: "user" | "guild";
bucket: number;
revision: number;
guildId?: string;
triggerDebuggingEnabled?: boolean;
}
interface TrackExposureOptions {
experimentId: string;
descriptor: (UserExperimentAssignment | GuildExperimentAssignment) & ExperimentExposureDescriptor;
location?: string;
location_stack?: string[];
context?: { guildId?: string; };
fingerprint?: string;
excluded?: boolean;
exposureType?: string;
}
interface ExperimentState {
assignmentFingerprint: string | null;
assignmentSessionId: string;
@ -94,8 +113,9 @@ export class ExperimentStore extends FluxStore {
getUserExperimentDescriptor(experimentId: string): ExperimentAssignmentOverride;
hasRegisteredExperiment(experimentId: string): boolean;
// has two args
getRecentExposures(): unknown;
// has four args
hasExperimentTrackedExposure(): unknown;
trackExposure: (options: TrackExposureOptions) => false | void;
getRecentExposures(type: "user" | "guild", experimentId: string): [string, number][];
hasExperimentTrackedExposure(experimentId: string, descriptor: ExperimentExposureDescriptor, location?: string, triggerDebugging?: boolean): boolean;
loadCache(): void;
takeSnapshot(): { version: number; data: Record<string, unknown>; };
}

View file

@ -66,4 +66,5 @@ export interface FriendsState {
export class FriendsStore extends FluxStore {
getState(): FriendsState;
isInitialized(): boolean;
}

View file

@ -0,0 +1,32 @@
import { FluxStore } from "..";
export type GIFMediaFormat = 1 | 2;
export type GIFSelectedFormat = "webm" | "tinywebp";
export interface GIFResultItem {
id: string;
url: string;
src: string;
gifSrc: string;
width: number;
height: number;
format: GIFMediaFormat;
}
export interface GIFTrendingCategory {
type: "Trending" | "Category";
name: string;
src: string;
format: GIFMediaFormat;
}
export class GIFPickerViewStore extends FluxStore {
getAnalyticsID(): string | null;
getQuery(): string;
getResultItems(): GIFResultItem[];
getResultQuery(): string;
getSelectedFormat(): GIFSelectedFormat;
getSuggestions(): string[];
getTrendingCategories(): GIFTrendingCategory[];
getTrendingSearchTerms(): string[];
}

View file

@ -0,0 +1,36 @@
import { Channel, FluxStore } from "..";
import { ReadStateType } from "../../enums";
export interface GuildChannelMentionCount {
count: number;
isMentionLowImportance: boolean;
}
export interface GuildReadState {
unread: boolean;
unreadByType: Partial<Record<ReadStateType, boolean>>;
unreadChannelId: string | null;
lowImportanceMentionCount: number;
highImportanceMentionCount: number;
mentionCounts: Record<string, GuildChannelMentionCount>;
ncMentionCount: number;
sentinel: number;
}
export class GuildReadStateStore extends FluxStore {
getGuildChangeSentinel(guildId: string | null): number;
getGuildHasUnreadIgnoreMuted(guildId: string): boolean;
getHighImportanceMentionCountForChannel(guildId: string | null, channelId: string): number;
getIsMentionLowImportance(guildId: string | null): boolean;
getMentionCount(guildId: string | null): number;
getMentionCountForPrivateChannel(channelId: string): GuildChannelMentionCount | number;
getMutableGuildStates(): Record<string, GuildReadState>;
getMutableUnreadGuilds(): Set<string>;
getPrivateChannelMentionCount(): number;
getStoreChangeSentinel(): number;
getTotalMentionCount(excludePrivateChannels?: boolean): number;
getTotalNotificationsMentionCount(excludePrivateChannels?: boolean): number;
hasAnyUnread(): boolean;
hasUnread(guildId: string): boolean;
shouldCountChannelUnread(channel: Channel, mentionCount?: number): boolean;
}

View file

@ -9,9 +9,16 @@ export interface FriendInvite extends Invite {
revoked?: boolean;
}
export interface InstantInviteTarget {
targetType?: number;
targetUserId?: string;
targetApplicationId?: string;
}
export class InstantInviteStore extends FluxStore {
getInvite(channelId: string): Invite;
getInvite(channelId: string, target?: InstantInviteTarget): Invite | undefined;
getFriendInvite(): FriendInvite | null;
getFriendInvitesFetching(): boolean;
canRevokeFriendInvite(): boolean;
getReceivedInstallationIdForInviteCode(inviteCode: string): string | undefined;
}

View file

@ -0,0 +1,20 @@
import { FluxStore, MuteConfig } from "..";
export interface JoinedThread {
threadId: string;
guildId: string;
flags: number;
muted: boolean;
muteConfig: MuteConfig | null;
joinTimestamp: Date;
}
export class JoinedThreadsStore extends FluxStore {
hasJoined(channelId: string): boolean;
joinTimestamp(channelId: string): Date | undefined;
flags(channelId: string): number | undefined;
getInitialOverlayState(): JoinedThread[];
getMuteConfig(channelId: string): MuteConfig | null | undefined;
getMutedThreads(): Set<string>;
isMuted(channelId: string): boolean;
}

View file

@ -404,10 +404,46 @@ export interface ClipMetadata {
* Result of saving a clip.
*/
export interface SavedClip {
/** unique clip identifier. */
id: string;
/** path where clip was saved. */
/** clip duration in milliseconds. */
duration: number;
/** parsed clip encoder stats. */
clipStats: Record<string, unknown>;
/** thumbnail data, if generated. */
thumbnail?: string;
/** serialized clip metadata, if any. */
metadata?: string;
}
/**
* Options for saving a clip from the recording buffer.
*/
export interface SaveClipOptions {
/** path to write the clip to. */
filepath: string;
/** serialized clip metadata. */
metadata: string;
/** timestamp to take the thumbnail from. */
thumbnailMs: number;
/** buffer start timestamp. */
startMs: number;
/** buffer end timestamp. */
endMs: number;
/** trim start timestamp. */
trimStartMs: number;
/** trim end timestamp. */
trimEndMs: number;
/** current user id when streaming. */
userId?: string;
}
/**
* Result of exporting a clip to a file.
*/
export interface ExportedClip {
/** path of the exported file. */
filepath: string;
/** whether the file is already formatted for upload. */
formattedForUpload: boolean;
}
/**
@ -1423,6 +1459,18 @@ export interface MediaEngine {
Video: React.ComponentType & { onContainerResized: () => void; };
/** set of active voice/video connections. */
connections: Set<MediaEngineConnection>;
/** current audio input device id. */
audioInputDeviceId: string;
/** current audio output device id. */
audioOutputDeviceId: string;
/** current video input device id, or "disabled". */
videoInputDeviceId: string;
/** active audio layer name. */
audioLayer: string;
/** active audio subsystem. */
audioSubsystem: AudioSubsystem;
/** cached codec survey JSON, set after the first getCodecSurvey call. */
codecSurvey?: string;
/**
* Registers a listener for device changes.
@ -1579,6 +1627,8 @@ export interface MediaEngine {
* @param settings filter settings to apply.
*/
applyMediaFilterSettings(settings: MediaFilterSettings): Promise<void>;
/** cancels an in-progress batch audio processing run. */
cancelBatchAudioProcessing(): void;
/**
* Creates a new voice connection.
* @param userId user id for the connection.
@ -1613,12 +1663,13 @@ export interface MediaEngine {
*/
enable(): Promise<void>;
/**
* Exports a clip as a blob.
* @param clipId clip identifier.
* @param userId user who owns the clip.
* @returns promise resolving to the clip blob.
* Exports a clip to a file, applying edits.
* @param sourcePath path of the source clip.
* @param outputPath path to write the exported clip to.
* @param editMetadata trim, crop and track settings.
* @returns promise resolving to the exported file info, rejects with "unsupported" if unavailable.
*/
exportClip(clipId: string, userId: string): Promise<Blob>;
exportClipToFile(sourcePath: string, outputPath: string, editMetadata: Record<string, unknown>): Promise<ExportedClip>;
/**
* Fetches async resources like DAVE keys.
* @param options fetch options.
@ -1651,10 +1702,10 @@ export interface MediaEngine {
*/
getCodecCapabilities(callback: (capabilities: string) => void): void;
/**
* Gets a survey of supported codecs.
* @returns promise resolving to codec info.
* Gets a survey of available video encoders and decoders.
* @returns promise resolving to JSON with available_video_encoders and available_video_decoders.
*/
getCodecSurvey(): Promise<{ codecs: CodecInfo[]; }>;
getCodecSurvey(): Promise<string>;
/**
* Gets whether debug logging is enabled.
* @returns true if enabled.
@ -1665,6 +1716,24 @@ export interface MediaEngine {
* @returns promise that rejects with NO_STREAM error if not streaming.
*/
getDesktopSource(): Promise<DesktopSource>;
/**
* Gets audio effects applied by the OS to a device, Windows only.
* @param deviceId device identifier.
* @returns promise resolving to effect info, rejects if unsupported.
*/
getDeviceAudioEffects(deviceId: string): Promise<Record<string, unknown>>;
/**
* Gets whether a device is muted at the OS level.
* @param deviceId device identifier.
* @returns promise resolving to muted state, undefined if unsupported.
*/
getDeviceOSMuted(deviceId: string): Promise<boolean | undefined>;
/**
* Gets a device's OS volume.
* @param deviceId device identifier.
* @returns promise resolving to volume, undefined if unsupported.
*/
getDeviceOSVolume(deviceId: string): Promise<number | undefined>;
/**
* Gets whether loopback is active.
* @returns always false for native engine.
@ -1686,9 +1755,19 @@ export interface MediaEngine {
* Gets screen preview thumbnails.
* @param width thumbnail width.
* @param height thumbnail height.
* @param useWgc whether to capture previews with Windows Graphics Capture.
* @returns promise resolving to preview list.
*/
getScreenPreviews(width: number, height: number): Promise<ScreenPreview[]>;
getScreenPreviews(width: number, height: number, useWgc?: boolean): Promise<ScreenPreview[]>;
/**
* Gets a preview thumbnail for a single window.
* @param windowId window source identifier.
* @param width thumbnail width.
* @param height thumbnail height.
* @param useWgc whether to capture previews with Windows Graphics Capture.
* @returns promise resolving to the preview, or null if unavailable.
*/
getSingleWindowPreview(windowId: string, width: number, height: number, useWgc?: boolean): Promise<WindowPreview | null>;
/**
* Gets supported bandwidth estimation experiments.
* @param callback called with experiment list.
@ -1699,16 +1778,16 @@ export interface MediaEngine {
* @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<string>;
/**
* Gets the native steady clock time.
* @returns time in milliseconds, or null if unsupported.
*/
getSystemSteadyClockNowMs(): number | null;
/**
* Gets current video input device id.
* @returns device id or "disabled".
@ -1723,10 +1802,16 @@ export interface MediaEngine {
* Gets window preview thumbnails.
* @param width thumbnail width.
* @param height thumbnail height.
* @param useWgc whether to capture previews with Windows Graphics Capture.
* @returns promise resolving to preview list.
*/
getWindowPreviews(width: number, height: number): Promise<WindowPreview[]>;
getWindowPreviews(width: number, height: number, useWgc?: boolean): Promise<WindowPreview[]>;
/**
* Checks if the native module supports clips v3.
* @returns true if supported.
*/
hasClipsV3Support(): boolean;
/** signals user interaction to enable autoplay. */
interact(): void;
/**
@ -1734,6 +1819,19 @@ export interface MediaEngine {
* @param options picker options.
*/
presentNativeScreenSharePicker(options?: string): void;
/**
* Runs audio processing over every file in a directory.
* @param inputDir directory to read audio files from.
* @param outputDir directory to write processed files to.
* @param onProgress called after each file.
* @param onComplete called when finished or cancelled.
*/
processBatchAudioFiles(
inputDir: string,
outputDir: string,
onProgress: (filename: string, current: number, total: number, success: boolean) => void,
onComplete: (processed: number, failed: number) => void
): void;
/**
* Queues an audio subsystem switch.
* @param subsystem subsystem to switch to.
@ -1745,24 +1843,17 @@ export interface MediaEngine {
* @returns promise resolving to sorted region ids.
*/
rankRtcRegions(regions: string[]): Promise<string[]>;
/** registers the native clips recording event handler, once. */
registerClipsRecordingEventHandler(): void;
/** releases native desktop video source picker stream. */
releaseNativeDesktopVideoSourcePickerStream(): void;
/**
* Saves a clip.
* @param clipId clip identifier.
* @param userId user who owns the clip.
* Saves a clip from the recording buffer.
* @param options clip save options.
* @returns promise resolving to saved clip info.
*/
saveClip(clipId: string, userId: string): Promise<SavedClip>;
/**
* 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<SavedClip>;
saveClipEx(options: SaveClipOptions): Promise<SavedClip>;
/**
* Saves a screenshot.
* @param channelId channel context.
@ -1780,15 +1871,10 @@ export interface MediaEngine {
*/
setAecDump(enabled: boolean): void;
/**
* Sets callback for async clips source deinit.
* @param callback callback function.
* Sets whether video input devices initialize asynchronously.
* @param enabled whether to enable.
*/
setAsyncClipsSourceDeinit(callback: () => void): void;
/**
* Sets callback for async video input device init.
* @param callback callback function.
*/
setAsyncVideoInputDeviceInit(callback: () => void): void;
setAsyncVideoInputDeviceInit(enabled: boolean): void;
/**
* Sets whether to bypass system audio input processing.
* @param bypass whether to bypass.
@ -1799,6 +1885,11 @@ export interface MediaEngine {
* @param deviceId device identifier.
*/
setAudioInputDevice(deviceId: string): void;
/**
* Sets spatial audio mixer options.
* @param options mixer options.
*/
setAudioMixerOptions(options: Record<string, unknown>): void;
/**
* Sets the audio output device.
* @param deviceId device identifier.
@ -1809,40 +1900,67 @@ export interface MediaEngine {
* @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.
* Overrides the clips audio model.
* @param model model identifier.
*/
setClipsMLPipelineEnabled(enabled: boolean): void;
setClipsAudioModelOverride(model: string): void;
/**
* Enables or disables a clips ML pipeline type.
* @param type pipeline type.
* @param enabled whether to enable.
* Sets the clips data directory.
* @param path directory path.
*/
setClipsMLPipelineTypeEnabled(type: string, enabled: boolean): void;
setClipsDataPath(path: string): void;
/**
* Sets the clips native module path and registers the recording event handler.
* @param path module path.
*/
setClipsModulePath(path: string): void;
/**
* Configures clips performance monitoring.
* @returns promise resolving to monitoring state, rejects with "unsupported" if unavailable.
*/
setClipsPerfMonitoring(...args: unknown[]): Promise<{ enabled: boolean; }>;
/**
* Sets clips quality settings.
* @param resolution resolution height.
* @param width resolution width.
* @param height resolution height.
* @param frameRate frame rate.
* @param hdr whether HDR is enabled.
* @param bitratePercent bitrate percentage.
* @returns true if settings were applied.
*/
setClipsQualitySettings(resolution: number, frameRate: number, hdr: boolean): boolean;
setClipsQualitySettings(width: number, height: number, frameRate: number, bitratePercent: number): boolean;
/**
* Enables or disables clips recording.
* @param enabled whether to enable.
*/
setClipsRecordingEnabled(enabled: boolean): void;
/**
* Configures Sentry for the clips module.
* @param release release identifier.
* @param dir Sentry data directory.
* @param environment release channel.
*/
setClipsSentryConfig(release: string, dir: string, environment: string): void;
/**
* Sets or clears the clips source.
* @param source source config or null to clear.
*/
setClipsSource(source: ClipsSource | null): void;
/**
* Sets whether the clips UI is active.
* @param active whether active.
*/
setClipsUIActive(active: boolean): void;
/**
* Enables or disables the clips v3 ML pipeline.
* @param enabled whether to enable.
*/
setClipsV3MLEnabled(enabled: boolean): void;
/**
* Enables or disables debug logging.
* @param enabled whether to enable.
@ -1854,16 +1972,6 @@ export interface MediaEngine {
* @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.
@ -1885,16 +1993,16 @@ export interface MediaEngine {
* @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;
/**
* Sets noise cancellation models.
* @param models model config.
*/
setNcModels(models: unknown): void;
/**
* Enables or disables noise cancellation stats.
* @param enabled whether to enable.
@ -1937,6 +2045,16 @@ export interface MediaEngine {
* @param deviceId device identifier.
*/
setVideoInputDevice(deviceId: string): Promise<void>;
/**
* Caps the voice channel count.
* @param count max channel count, 0 for no cap.
*/
setVoiceChannelCountCap(count: number): void;
/**
* Caps the voice sample rate.
* @param rate max sample rate in Hz, 0 for no cap.
*/
setVoiceSampleRateCap(rate: number): void;
/**
* Checks if a connection should broadcast video.
@ -1989,6 +2107,17 @@ export interface MediaEngine {
* @param metadata new metadata.
*/
updateClipMetadata(clipId: string, metadata: ClipMetadata): Promise<void>;
/**
* Updates a WebRTC field trial.
* @param name field trial name.
* @param value field trial value.
*/
updateFieldTrial(name: string, value: string): void;
/**
* Starts watching a device for hardware mute changes.
* @param deviceId device identifier.
*/
watchDeviceHardwareMutedChange(deviceId: string): void;
/** ticks the watchdog timer. */
watchdogTick(): void;
/**
@ -2122,6 +2251,28 @@ export interface Shortcut {
shortcut: string[];
}
/**
* Spatial audio mixer settings.
*/
export interface AudioMixerSettings {
enabled: boolean;
spatialBlend: number;
reflectionsEnabled: boolean;
roomSize: number;
distanceAttenuationEnabled: boolean;
mode: string;
spread: number;
arcAngle: number;
gridColumns: number;
gridSpacing: number;
buckets: number;
listenerHeight: number;
distance: number;
}
/** 0 unknown, 1 active, 2 mono output, 3 init failed, 4 HRTF failed. */
export type SpatialAudioStatus = 0 | 1 | 2 | 3 | 4;
/**
* Flux store managing audio/video settings, devices, and the media engine.
* Handles voice activity detection, noise cancellation, device selection,
@ -2135,16 +2286,6 @@ export class MediaEngineStore extends FluxStore {
* @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.
@ -2165,6 +2306,11 @@ export class MediaEngineStore extends FluxStore {
* @returns attenuation 0-100, default 0.
*/
getAttenuation(): number;
/**
* Gets spatial audio mixer settings.
* @returns mixer settings.
*/
getAudioMixerSettings(): AudioMixerSettings;
/**
* Gets the current audio subsystem.
* @returns active audio subsystem.
@ -2200,11 +2346,6 @@ export class MediaEngineStore extends FluxStore {
* @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.
@ -2240,11 +2381,31 @@ export class MediaEngineStore extends FluxStore {
* @returns true if detected, false if not, null if unknown.
*/
getInputDetected(): boolean | null;
/**
* Gets whether input was detected during the current connection.
* @returns true if detected.
*/
getInputDetectedThisConnection(): boolean;
/**
* Gets whether the input device is muted in hardware.
* @returns true if muted, undefined if unknown.
*/
getInputDeviceHardwareMuted(): boolean | undefined;
/**
* Gets the selected audio input device id.
* @returns device id.
*/
getInputDeviceId(): string;
/**
* Gets whether the input device is muted by the OS.
* @returns true if muted, undefined if unknown.
*/
getInputDeviceOSMuted(): boolean | undefined;
/**
* Gets the OS volume of the input device.
* @returns volume, undefined if unknown.
*/
getInputDeviceOSVolume(): number | undefined;
/**
* Gets available audio input devices.
* @returns devices keyed by device id.
@ -2285,6 +2446,11 @@ export class MediaEngineStore extends FluxStore {
* @returns timestamp in milliseconds.
*/
getLastAudioInputDeviceChangeTimestamp(): number;
/**
* Gets when input detection state last changed.
* @returns timestamp in milliseconds.
*/
getLastInputDetectedUpdateTime(): number;
/**
* Gets the stereo pan for a user.
* @param userId user to get pan for.
@ -2333,11 +2499,6 @@ export class MediaEngineStore extends FluxStore {
* @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.
@ -2353,6 +2514,11 @@ export class MediaEngineStore extends FluxStore {
* @returns true if enabled.
*/
getNoiseSuppression(): boolean;
/**
* Gets whether OpenH264 is enabled, only on Linux.
* @returns true if enabled.
*/
getOpenH264Enabled(): boolean;
/**
* Gets the selected audio output device id.
* @returns device id.
@ -2373,16 +2539,6 @@ export class MediaEngineStore extends FluxStore {
* @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.
@ -2409,6 +2565,11 @@ export class MediaEngineStore extends FluxStore {
* @returns strength 0-100, default 50.
*/
getSidechainCompressionStrength(): number;
/**
* Gets the spatial audio status reported by the engine.
* @returns spatial audio status.
*/
getSpatialAudioStatus(): SpatialAudioStatus;
/**
* Gets whether currently speaking while muted.
* @returns true if speaking while muted.
@ -2459,6 +2620,13 @@ export class MediaEngineStore extends FluxStore {
* @returns devices keyed by device id.
*/
getVideoDevices(): { [deviceId: string]: VideoDevice; };
/**
* Builds the video encoder experiment flags.
* @param context media engine context.
* @param role "streamer" when encoding own stream.
* @returns comma separated experiment flags.
*/
getVideoEncoderExperiments(context: MediaEngineContextType, role?: string): string;
/**
* Gets whether video hook is enabled.
* @returns true if enabled.
@ -2477,18 +2645,6 @@ export class MediaEngineStore extends FluxStore {
* @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.
@ -2510,7 +2666,11 @@ export class MediaEngineStore extends FluxStore {
* @returns true if available.
*/
hasH265HardwareDecode(): boolean;
/**
* Checks if any video input device is available.
* @returns true if available.
*/
hasVideoDevice(): boolean;
/**
* Checks if advanced voice activity is supported.
* @returns true if supported.
@ -2532,27 +2692,42 @@ export class MediaEngineStore extends FluxStore {
* @returns true if supported.
*/
isAutomaticGainControlSupported(): boolean;
/**
* Checks if clips recording is ready.
* @returns true if ready.
*/
isClipsRecordingReady(): boolean;
/**
* Checks if the engine emits clips recording ready events.
* @returns true if supported.
*/
isClipsRecordingReadySignalSupported(): 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 Media Foundation H264 decoding is available.
* @returns true if available.
*/
isH264MfDecodeAvailable(): 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 hardware mute notice is enabled.
* @returns true if enabled.
*/
isHardwareMuteNoticeEnabled(): boolean;
/**
* Checks if input profile is custom.
* @returns true if custom.
@ -2638,6 +2813,16 @@ export class MediaEngineStore extends FluxStore {
* @returns true if temporarily muted.
*/
isSelfMutedTemporarily(context?: MediaEngineContextType): boolean;
/**
* Checks if self is server deafened.
* @returns true if server deafened.
*/
isServerDeaf(): boolean;
/**
* Checks if self is server muted.
* @returns true if server muted.
*/
isServerMute(): boolean;
/**
* Checks if simulcast is supported.
* @returns true if supported.
@ -2649,6 +2834,16 @@ export class MediaEngineStore extends FluxStore {
* @returns true if sharing.
*/
isSoundSharing(context?: MediaEngineContextType): boolean;
/**
* Checks if spatial audio is enabled in mixer settings.
* @returns true if enabled.
*/
isSpatialAudioEnabled(): boolean;
/**
* Checks if spatial audio was requested.
* @returns true if requested.
*/
isSpatialAudioRequested(): boolean;
/**
* Checks if media engine is supported.
* @returns true if supported.
@ -2664,7 +2859,6 @@ export class MediaEngineStore extends FluxStore {
* @returns true if enabled.
*/
isVideoEnabled(): boolean;
/** notifies that mute/unmute sound was skipped. */
notifyMuteUnmuteSoundWasSkipped(): void;
/**
@ -2693,10 +2887,8 @@ export class MediaEngineStore extends FluxStore {
* @returns true if should show.
*/
showBypassSystemInputProcessing(): boolean;
/** starts preloading DAVE encryption. */
startDavePreload(): void;
/**
* Checks if a feature is supported.
* @param feature feature to check.

View file

@ -0,0 +1,9 @@
import { FluxStore } from "..";
export class MessageRequestStore extends FluxStore {
getMessageRequestChannelIds(): Set<string>;
getMessageRequestsCount(): number;
isAcceptedOptimistic(channelId: string): boolean;
isMessageRequest(channelId: string): boolean;
isReady(): boolean;
}

View file

@ -52,6 +52,8 @@ export class MessageStore extends FluxStore {
getMessages(channelId: string): ChannelMessages;
hasCurrentUserSentMessage(channelId: string): boolean;
hasCurrentUserSentMessageSinceAppStart(channelId: string): boolean;
hasCurrentUserSentWaveBlockingMessage(channelId: string): boolean;
getAutomodRemovalNotice(messageId: string): unknown;
hasPresent(channelId: string): boolean;
isLoadingMessages(channelId: string): boolean;
isReady(channelId: string): boolean;

View file

@ -15,6 +15,7 @@ export interface NotificationSettingsState {
export class NotificationSettingsStore extends FluxStore {
get taskbarFlash(): boolean;
get screenDowntimeReminder(): boolean;
getUserAgnosticState(): NotificationSettingsState;
getDesktopType(): DesktopNotificationType;
getTTSType(): TTSNotificationType;

View file

@ -5,6 +5,7 @@ export interface OverridePremiumTypeState {
createdAtOverride: Date | undefined;
premiumTypeActual: PremiumType | null;
premiumTypeOverride: PremiumType | undefined;
perksActual: Record<string, unknown> | null;
}
export class OverridePremiumTypeStore extends FluxStore {
@ -12,5 +13,6 @@ export class OverridePremiumTypeStore extends FluxStore {
getCreatedAtOverride(): Date | undefined;
getPremiumTypeActual(): PremiumType | null;
getPremiumTypeOverride(): PremiumType | undefined;
getPerksActual(): Record<string, unknown> | null;
get premiumType(): PremiumType | undefined;
}

View file

@ -29,7 +29,7 @@ export class PresenceStore extends FluxStore {
getAllApplicationActivities(applicationId: string): UserAndActivity[];
getApplicationActivity(userId: string, applicationId: string, guildId?: string): Activity | null;
getClientStatus(userId: string): ClientStatusMap;
getHiddenActivities(): Activity[];
getHiddenActivities(userId: string, guildId?: string | null): Activity[];
/** literally just getActivities(...)[0] */
getPrimaryActivity(userId: string, guildId?: string): Activity | null;
getState(): PresenceStoreState;
@ -37,4 +37,6 @@ export class PresenceStore extends FluxStore {
getUnfilteredActivities(userId: string, guildId?: string): Activity[];
getUserIds(): string[];
isMobileOnline(userId: string): boolean;
isVROnline(userId: string): boolean;
setCurrentUserOnConnectionOpen(status: OnlineStatus, activities: Activity[]): void;
}

View file

@ -0,0 +1,14 @@
import { FluxStore } from "..";
export interface PrivateChannelSortEntry {
channelId: string;
lastMessageId: string;
isFavorite: boolean;
isRequest: boolean;
}
export class PrivateChannelSortStore extends FluxStore {
getPrivateChannelIds(): string[];
getSortedChannels(): [PrivateChannelSortEntry[], PrivateChannelSortEntry[]];
serializeForOverlay(): Record<string, string>;
}

View file

@ -66,7 +66,6 @@ export class RTCConnectionStore extends FluxStore {
getRTCConnectionId(): string | undefined;
getDuration(): number | undefined;
getLastRTCConnectionState(): LastRTCConnectionState | null;
getVoiceFilterSpeakingDurationMs(): number | undefined;
getPacketStats(): RTCConnectionPacketStats | undefined;
getVoiceStateStats(): VoiceStateStats | undefined;
// TODO: finish typing

View file

@ -59,6 +59,8 @@ export class ReadStateStore extends FluxStore {
hasRecentlyVisitedAndRead(channelId: string): boolean;
hasTrackedUnread(channelId: string): boolean;
hasUnread(channelId: string, type?: ReadStateType): boolean;
hasLastMessage(channelId: string, type?: ReadStateType): boolean;
canBeUnread(channelId: string, type?: ReadStateType): boolean;
hasUnreadOrMentions(channelId: string, type?: ReadStateType): boolean;
hasUnreadPins(channelId: string): boolean;
isEstimated(channelId: string, type?: ReadStateType): boolean;

View file

@ -0,0 +1,12 @@
import { FluxStore, Message } from "..";
export interface ReferencedMessage {
state: number;
message?: Message;
}
export class ReferencedMessageStore extends FluxStore {
getMessageByReference(reference: Message["messageReference"]): { message: Message; } | undefined;
getMessage(channelId: string, messageId: string): ReferencedMessage;
getReplyIdsForChannel(channelId: string | null | undefined): Set<string>;
}

View file

@ -4,13 +4,14 @@ import { RelationshipType } from "../../enums";
export class RelationshipStore extends FluxStore {
getBlockedIDs(): string[];
getBlockedOrIgnoredIDs(): string[];
getBlockedOrIgnoredIDs(): Set<string>;
getFriendCount(): number;
getFriendIDs(): string[];
getIgnoredIDs(): string[];
getMutableRelationships(): Map<string, RelationshipType>;
getNickname(userId: string): string;
getNickname(userId: string): string | undefined;
getNote(userId: string): string | undefined;
getOriginApplicationId(userId: string): string | undefined;
getOutgoingCount(): number;
getPendingCount(): number;
@ -38,6 +39,6 @@ export class RelationshipStore extends FluxStore {
isIgnored(userId: string): boolean;
isIgnoredForMessage(message: Message | MessageJSON): boolean;
isSpam(userId: string): boolean;
isStranger(userId: string): boolean;
isStranger(userId: string): boolean | undefined;
isUnfilteredPendingIncoming(userId: string): boolean;
}

View file

@ -34,6 +34,9 @@ export class RunningGameStore extends FluxStore {
getCandidateGames(): RunningGame[];
getCurrentGameForAnalytics(): RunningGame | null;
getCurrentNonGameForAnalytics(): RunningGame | null;
getDebugRunningGame(): RunningGame | null;
getDetectionDebug(): { timestamp: number; totalFromNative: number; entries: { game: RunningGame; outcome: { kind: string; }; }[]; } | null;
canCollectExecutableFingerprintsForRunningGames(): boolean;
getGameForName(name: string): RunningGame | null;
getGameForPID(pid: number): RunningGame | null;
getGameOrTransformedSubgameForPID(pid: number): RunningGame | null;
@ -55,6 +58,7 @@ export class RunningGameStore extends FluxStore {
getVisibleRunningGames(): RunningGame[];
isDetectionEnabled(game: RunningGame): boolean;
isGamesSeenLoaded(): boolean;
isGameSeen(gameId: string): boolean;
isObservedAppRunning(app: string): boolean;
isSystemServiceInitialized(service: string): boolean;
shouldContinueWithoutElevatedProcessForPID(pid: number): boolean;

View file

@ -0,0 +1,46 @@
import { FluxStore } from "..";
import { StandingState } from "../../enums";
export interface AccountStanding {
state: StandingState;
}
export interface SafetyHubClassification {
id: string;
[key: string]: unknown;
}
export type ClassificationRequestState = 0 | 1 | 2;
export type AgeCheckStatus = "loading" | "error" | "success" | "failure" | "none" | "verified" | "verified_other_violations_remain" | "underage" | "underage_manual_review";
export class SafetyHubStore extends FluxStore {
getAccountStanding(): AccountStanding;
isInitialized(): boolean;
isFetching(): boolean;
getFetchError(): unknown;
getClassifications(): SafetyHubClassification[];
getClassification(classificationId: string): SafetyHubClassification | undefined;
getClassificationRequestState(classificationId: string): ClassificationRequestState | undefined;
getAppealClassificationId(): string | null;
getIsDsaEligible(): boolean;
getIsAppealEligible(): boolean;
getAppealEligibility(): unknown[];
getAppealSignal(): number;
getFreeTextAppealReason(): string;
getIsSubmitting(): boolean;
getSubmitError(): unknown;
getIsExpressiveModalV2Enabled(): boolean;
getShowExpressiveModalSubtitleAlt(): boolean;
getIsManualReviewFallbackEnabled(): boolean;
getIsManualReviewDecidedUnderage(): boolean;
getUsername(): string;
getAgeVerificationWebviewUrl(): string;
getAgeVerificationError(): unknown;
getIsLoadingAgeVerification(): boolean;
getAgeCheckStatus(): AgeCheckStatus;
getAgeCheckError(): unknown;
getAgeCheckAttempts(): number;
}

View file

@ -0,0 +1,19 @@
import { Activity, FluxStore, OnlineStatus } from "..";
export interface LocalPresence {
status: OnlineStatus;
since: number;
activities: Activity[];
afk: boolean;
}
export class SelfPresenceStore extends FluxStore {
findActivity(predicate: (activity: Activity) => boolean, filtered?: boolean): Activity | undefined;
getActivities(filtered?: boolean): Activity[];
getApplicationActivity(applicationId: string, filtered?: boolean): Activity | undefined;
getHiddenActivities(): Activity[];
getLocalPresence(): LocalPresence;
getPrimaryActivity(filtered?: boolean): Activity | undefined;
getStatus(): OnlineStatus;
getUnfilteredActivities(filtered?: boolean): Activity[];
}

View file

@ -0,0 +1,24 @@
import { Activity, FluxStore } from "..";
export interface Session {
sessionId: string;
status: string;
active: boolean;
activities: Activity[];
hiddenActivities?: Activity[];
clientInfo: {
version: number;
os: string;
client: string;
};
}
export class SessionsStore extends FluxStore {
getSessions(): Record<string, Session>;
getSession(): Session | null | undefined;
getSessionById(sessionId: string): Session | undefined;
getActiveSession(): Session | undefined;
getRemoteActivities(): Activity[];
getHiddenActivities(): Activity[];
getRemoteApplicationActivity(applicationId: string | null | undefined): Activity | null | undefined;
}

View file

@ -0,0 +1,29 @@
import { FluxStore, GuildFolder } from "..";
export interface GuildsTreeNode {
type: string;
id: string | number;
children: GuildsTreeNode[];
name?: string;
color?: number;
expanded?: boolean;
}
export interface GuildsTree {
root: GuildsTreeNode;
version: number;
getRoots(): GuildsTreeNode[];
getNode(id: string | number): GuildsTreeNode | undefined;
allNodes(): GuildsTreeNode[];
sortedGuildNodes(): GuildsTreeNode[];
}
export class SortedGuildStore extends FluxStore {
getGuildsTree(): GuildsTree;
getFlattenedGuildFolderList(): GuildsTreeNode[];
getCompatibleGuildFolders(): GuildFolder[];
getFastListGuildFolders(): GuildsTreeNode[];
getFlattenedGuildIds(): string[];
getGuildFolderById(folderId: number): GuildFolder;
getGuildFolders(): GuildFolder[];
}

View file

@ -11,14 +11,15 @@ export interface SoundboardSound {
userId?: string;
}
export interface TopSoundForGuild {
soundId: string;
rank: number;
export interface TopSoundboardSoundsMetadata {
soundIds: string[];
topSoundsTTL: number;
}
export interface SoundboardOverlayState {
soundboardSounds: Record<string, SoundboardSound[]>;
favoritedSoundIds: string[];
orderedFavoritedSoundIds: string[];
localSoundboardMutes: string[];
}
@ -37,11 +38,14 @@ export class SoundboardStore extends FluxStore {
isPlayingSound(soundId: string): boolean;
isFavoriteSound(soundId: string): boolean;
getFavorites(): Set<string>;
getAllTopSoundsForGuilds(): Map<string, TopSoundForGuild[]>;
getFrequentlyUsedSoundIds(): string[];
getTopSoundboardSoundsMetadata(guildId: string): TopSoundboardSoundsMetadata | undefined;
getTopSoundboardSoundIds(guildId: string | null | undefined): string[];
hasPendingUsage(): boolean;
get playedSoundFrecencyWithoutFetchingLatest(): { frequently: string[]; };
isLocalSoundboardMuted(userId: string): boolean;
isSoundboardVolumeMuted(): boolean;
hasHadOtherUserPlaySoundInSession(): boolean;
shouldFetchTopSoundsForGuilds(): boolean;
hasFetchedTopSoundsForGuilds(): boolean;
hasFetchedAllSounds(): boolean;
isFetchingAnySounds(): boolean;
}

View file

@ -2,5 +2,6 @@ import { FluxStore } from "..";
export class SpellCheckStore extends FluxStore {
hasLearnedWord(word: string): boolean;
findLearnedWordIn(text: string): string | null;
isEnabled(): boolean;
}

View file

@ -32,6 +32,7 @@ export interface SpotifySocketAndDevice {
export interface SpotifyArtist {
id: string;
name: string;
external_urls: { spotify: string; };
}
export interface SpotifyImage {

View file

@ -8,6 +8,7 @@ export interface StreamerModeSettings {
disableSounds: boolean;
disableNotifications: boolean;
enableContentProtection: boolean;
disabledOverlayWidgets?: string[];
}
export class StreamerModeStore extends FluxStore {
@ -21,4 +22,5 @@ export class StreamerModeStore extends FluxStore {
getSettings(): StreamerModeSettings;
getState(): Record<string, StreamerModeSettings>;
isOverlayWidgetDisabled(widget: string): boolean;
}

View file

@ -9,6 +9,13 @@ export interface ThemeState {
/** 0 = not loaded, 1 = loaded */
status: 0 | 1;
preferences: Record<ThemePreference, Theme>;
syncedClientThemes: Partial<Record<SystemTheme, SyncedClientTheme>>;
syncedThemesEnabled: boolean;
}
export interface SyncedClientTheme {
backgroundGradientPresetId?: number;
[key: string]: unknown;
}
export class ThemeStore extends FluxStore {
get systemTheme(): SystemTheme;
@ -16,4 +23,6 @@ export class ThemeStore extends FluxStore {
getState(): ThemeState;
themePreferenceForSystemTheme(preference: ThemePreference): Theme;
getSyncedClientTheme(systemTheme: SystemTheme): SyncedClientTheme | undefined;
isSameAsDeviceThemeEnabled(): boolean;
}

View file

@ -0,0 +1,12 @@
import { FluxStore } from "..";
export interface ThreadMemberListSection {
sectionId: string;
userIds: string[];
}
export class ThreadMemberListStore extends FluxStore {
getMemberListSections(channelId?: string): Record<string, ThreadMemberListSection>;
getMemberListVersion(channelId: string): number | undefined;
canUserViewChannel(channelId: string, sectionId: string, userId: string): boolean;
}

View file

@ -5,5 +5,10 @@ export class TypingStore extends FluxStore {
* returns a map of user ids to timeout ids
*/
getTypingUsers(channelId: string): Record<string, number>;
/**
* returns a map of channel ids to maps of user ids to timeout ids
*/
getTypingUsersByGuild(guildId: string): Record<string, Record<string, number>>;
isTyping(channelId: string, userId: string): boolean;
getCustomTypingIndicatorConfig(userId: string): unknown;
}

View file

@ -26,7 +26,7 @@ export class UserAffinitiesStore extends FluxStore {
getState(): UserAffinitiesResponse;
getUserAffinities(): UserAffinity[];
getUserAffinitiesMap(): Map<string, UserAffinity>;
getUserAffinity(userId: string): UserAffinity;
getUserAffinity(userId: string): UserAffinity | undefined;
isFetching(): boolean;
isHighlyAffinedVCUser(userId: string): boolean;
shouldFetch(): boolean;

View file

@ -0,0 +1,14 @@
import { FluxStore, Guild } from "..";
export interface UserGuildJoinRequest {
guildId: string;
[key: string]: unknown;
}
export class UserGuildJoinRequestStore extends FluxStore {
get hasFetchedRequestToJoinGuilds(): boolean;
computeGuildIds(): string[];
getRequest(guildId: string): UserGuildJoinRequest | undefined;
getJoinRequestGuild(guildId: string): Guild | null;
hasJoinRequestCoackmark(): boolean;
}

View file

@ -46,7 +46,6 @@ export class UserGuildSettingsStore extends FluxStore {
allowAllMessages(channel: Channel): boolean;
allowNoMessages(channel: Channel): boolean;
getAddedToMessages(): string[];
// TODO: finish typing
getAllSettings(): { userGuildSettings: Record<string, GuildSettings>; };
getChannelFlags(channel: Channel): ChannelOverrideFlags;
@ -69,9 +68,8 @@ export class UserGuildSettingsStore extends FluxStore {
getOptedInChannelsWithPendingUpdates(guildId: string): Record<string, any>;
getPendingChannelUpdates(guildId: string): Record<string, any>;
getState(): UserGuildSettingsState;
isAddedToMessages(channelId: string): boolean;
isCategoryMuted(guildId: string, channelId: string): boolean;
isChannelMuted(guildId: string, channelId: string): boolean;
isChannelMuted(guildId: string | null, 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;

View file

@ -0,0 +1,13 @@
import { FluxStore } from "..";
export class UserProfileSettingsStore extends FluxStore {
get selectedGuildId(): string | undefined;
getPendingChanges(guildId?: string): Record<string, any>;
getFormState(): unknown;
getErrors(guildId?: string): Record<string, unknown>;
getTryItOutChanges(): Record<string, unknown>;
hasTryItOutChanges(): boolean;
hasUnsavedChanges(): boolean;
showNotice(): boolean;
canSubmit(): boolean;
}

View file

@ -103,20 +103,13 @@ export interface UserProfile extends UserProfileBase, Pick<User, "premiumType">
premiumSince: Date | null;
}
export interface ApplicationWidgetConfig {
applicationId: string;
widgetType: number;
}
export interface WishlistSettings {
privacy: number;
}
export class UserProfileStore extends FluxStore {
get applicationWidgetApplicationConfigs(): Record<string, ApplicationWidgetConfig>;
get isSubmitting(): boolean;
getApplicationWidgetApplicationConfig(applicationId: string): ApplicationWidgetConfig | undefined;
getFirstWishlistId(userId: string): string | null;
getGuildMemberProfile(userId: string, guildId: string | undefined): UserProfileBase | null;
/**
@ -147,7 +140,7 @@ export class UserProfileStore extends FluxStore {
// TODO: finish typing
getWidgets(userId: string): any[] | undefined;
getWishlistIds(userId: string): string[];
getWishlistSettings(userId: string): WishlistSettings | null;
getWishlistSettings(userId: string, wishlistId: string): WishlistSettings | null;
/**
* Check if mutual friends for {@link userId} are currently being fetched.
*

View file

@ -223,4 +223,7 @@ export class UserSettingsProtoStore extends FluxStore {
// TODO: finish typing
getGuildDismissedContentState(guildId: string): any;
getGuildsProto(): Record<string, GuildProto>;
getDefaultGuildThemePreference(): number;
getGuildThemeSourcePreferenceOverride(guildId: string | null | undefined): number;
resolveGuildThemeSourcePreference(guildId: string | null | undefined): number;
}

View file

@ -6,25 +6,35 @@ export * from "./ApplicationStore";
export * from "./ApplicationStreamingStore";
export * from "./ApplicationStreamPreviewStore";
export * from "./AuthenticationStore";
export * from "./AuthorizedAppsStore";
export * from "./CallStore";
export * from "./ChannelMemberStore";
export * from "./ChannelRTCStore";
export * from "./ChannelSectionStore";
export * from "./ChannelStore";
export * from "./ClientThemesBackgroundStore";
export * from "./CollapsedVoiceChannelStore";
export * from "./ConnectedAccountsStore";
export * from "./DraftStore";
export * from "./EditMessageStore";
export * from "./EmojiStore";
export * from "./ExperimentStore";
export * from "./FluxStore";
export * from "./FriendsStore";
export * from "./GIFPickerViewStore";
export * from "./GuildChannelStore";
export * from "./GuildMemberCountStore";
export * from "./GuildMemberStore";
export * from "./GuildReadStateStore";
export * from "./GuildRoleStore";
export * from "./GuildScheduledEventStore";
export * from "./GuildStore";
export * from "./InstantInviteStore";
export * from "./InviteStore";
export * from "./JoinedThreadsStore";
export * from "./LocaleStore";
export * from "./MediaEngineStore";
export * from "./MessageRequestStore";
export * from "./MessageStore";
export * from "./NotificationSettingsStore";
export * from "./OverridePremiumTypeStore";
@ -32,22 +42,31 @@ export * from "./PendingReplyStore";
export * from "./PermissionStore";
export * from "./PopoutWindowStore";
export * from "./PresenceStore";
export * from "./PrivateChannelSortStore";
export * from "./ReadStateStore";
export * from "./ReferencedMessageStore";
export * from "./RelationshipStore";
export * from "./RTCConnectionStore";
export * from "./RunningGameStore";
export * from "./SafetyHubStore";
export * from "./SelectedChannelStore";
export * from "./SelectedGuildStore";
export * from "./SelfPresenceStore";
export * from "./SessionsStore";
export * from "./SortedGuildStore";
export * from "./SoundboardStore";
export * from "./SpellCheckStore";
export * from "./SpotifyStore";
export * from "./StickersStore";
export * from "./StreamerModeStore";
export * from "./ThemeStore";
export * from "./ThreadMemberListStore";
export * from "./TypingStore";
export * from "./UploadAttachmentStore";
export * from "./UserAffinitiesStore";
export * from "./UserGuildJoinRequestStore";
export * from "./UserGuildSettingsStore";
export * from "./UserProfileSettingsStore";
export * from "./UserProfileStore";
export * from "./UserSettingsProtoStore";
export * from "./UserStore";

View file

@ -19,9 +19,7 @@
import { definePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
const MessageRequestStore = findByPropsLazy("getMessageRequestsCount");
import { MessageRequestStore } from "@webpack/common";
const settings = definePluginSettings({
hideFriendRequestsCount: {

View file

@ -20,50 +20,17 @@ import { ApplicationCommandInputType, findOption, OptionalMessageOption, sendBot
import { Devs } from "@utils/constants";
import { sendMessage } from "@utils/discord";
import definePlugin from "@utils/types";
import { Command } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { FluxDispatcher, MessageActions, PendingReplyStore } from "@webpack/common";
import { Command, SpotifyTrack } from "@vencord/discord-types";
import { FluxDispatcher, MessageActions, PendingReplyStore, SpotifyStore } from "@webpack/common";
interface Album {
id: string;
image: {
height: number;
width: number;
url: string;
};
name: string;
}
interface Artist {
external_urls: {
spotify: string;
};
href: string;
id: string;
name: string;
type: "artist" | string;
uri: string;
}
interface Track {
id: string | null;
album: Album;
artists: Artist[];
duration: number;
isLocal: boolean;
name: string;
}
const Spotify = findByPropsLazy("getPlayerState");
function makeCommand(name: string, formatUrl: (track: Track) => string): Command {
function makeCommand(name: string, formatUrl: (track: SpotifyTrack) => string): Command {
return {
name,
description: `Share your current Spotify ${name} in chat`,
inputType: ApplicationCommandInputType.BUILT_IN,
options: [OptionalMessageOption],
execute(options, { channel }) {
const track: Track | null = Spotify.getTrack();
const track = SpotifyStore.getTrack();
if (!track) {
return sendBotMessage(channel.id, {
content: "You're not listening to any music."

View file

@ -7,14 +7,11 @@
import { Devs } from "@utils/constants";
import { isNonNullish } from "@utils/guards";
import definePlugin from "@utils/types";
import { findStoreLazy } from "@webpack";
import { FluxDispatcher, LocaleStore } from "@webpack/common";
import { FluxDispatcher, GIFPickerViewStore, LocaleStore } from "@webpack/common";
// API key is taken from the GBoard app on iOS
const TENOR_KEY = "3Z0688EVWYKH";
const GIFPickerViewStore = findStoreLazy("GIFPickerViewStore");
let cachedCategories: TrendingCategories | null = null;
interface TenorMedia {

View file

@ -8,14 +8,10 @@ import { addThemeChangeListener, removeThemeChangeListener } from "@api/Themes";
import { Devs } from "@utils/constants";
import { sleep } from "@utils/misc";
import definePlugin from "@utils/types";
import { FluxStore } from "@vencord/discord-types";
import { findStoreLazy } from "@webpack";
import { NotificationSettingsStore, RelationshipStore, ThemeStore } from "@webpack/common";
import { GuildReadStateStore, NotificationSettingsStore, RelationshipStore, ThemeStore } from "@webpack/common";
import managedStyle from "./styles.css?managed";
const GuildReadStateStore: FluxStore & { getTotalMentionCount: () => number; hasAnyUnread: () => boolean; } = findStoreLazy("GuildReadStateStore");
let _keybinds: Record<string, { onTrigger: () => any; }>;
function colorToHex(color: string) {

View file

@ -86,6 +86,25 @@ export let ExperimentStore: t.ExperimentStore;
export let UserAffinitiesStore: t.UserAffinitiesStore;
export let ApplicationStreamingStore: t.ApplicationStreamingStore;
export let ApplicationStreamPreviewStore: t.ApplicationStreamPreviewStore;
export let SortedGuildStore: t.SortedGuildStore;
export let JoinedThreadsStore: t.JoinedThreadsStore;
export let SafetyHubStore: t.SafetyHubStore;
export let PrivateChannelSortStore: t.PrivateChannelSortStore;
export let UserProfileSettingsStore: t.UserProfileSettingsStore;
export let AuthorizedAppsStore: t.AuthorizedAppsStore;
export let ChannelSectionStore: t.ChannelSectionStore;
export let ClientThemesBackgroundStore: t.ClientThemesBackgroundStore;
export let ConnectedAccountsStore: t.ConnectedAccountsStore;
export let ChannelMemberStore: t.ChannelMemberStore;
export let ThreadMemberListStore: t.ThreadMemberListStore;
export let CollapsedVoiceChannelStore: t.CollapsedVoiceChannelStore;
export let ReferencedMessageStore: t.ReferencedMessageStore;
export let SessionsStore: t.SessionsStore;
export let UserGuildJoinRequestStore: t.UserGuildJoinRequestStore;
export let SelfPresenceStore: t.SelfPresenceStore;
export let MessageRequestStore: t.MessageRequestStore;
export let GIFPickerViewStore: t.GIFPickerViewStore;
export let GuildReadStateStore: t.GuildReadStateStore;
/**
* @see jsdoc of {@link t.useStateFromStores}
@ -144,6 +163,25 @@ waitForStore("ExperimentStore", m => ExperimentStore = m);
waitForStore("UserAffinitiesV2Store", m => UserAffinitiesStore = m);
waitForStore("ApplicationStreamingStore", m => ApplicationStreamingStore = m);
waitForStore("ApplicationStreamPreviewStore", m => ApplicationStreamPreviewStore = m);
waitForStore("SortedGuildStore", m => SortedGuildStore = m);
waitForStore("JoinedThreadsStore", m => JoinedThreadsStore = m);
waitForStore("SafetyHubStore", m => SafetyHubStore = m);
waitForStore("PrivateChannelSortStore", m => PrivateChannelSortStore = m);
waitForStore("UserProfileSettingsStore", m => UserProfileSettingsStore = m);
waitForStore("AuthorizedAppsStore", m => AuthorizedAppsStore = m);
waitForStore("ChannelSectionStore", m => ChannelSectionStore = m);
waitForStore("ClientThemesBackgroundStore", m => ClientThemesBackgroundStore = m);
waitForStore("ConnectedAccountsStore", m => ConnectedAccountsStore = m);
waitForStore("ChannelMemberStore", m => ChannelMemberStore = m);
waitForStore("ThreadMemberListStore", m => ThreadMemberListStore = m);
waitForStore("CollapsedVoiceChannelStore", m => CollapsedVoiceChannelStore = m);
waitForStore("ReferencedMessageStore", m => ReferencedMessageStore = m);
waitForStore("SessionsStore", m => SessionsStore = m);
waitForStore("UserGuildJoinRequestStore", m => UserGuildJoinRequestStore = m);
waitForStore("SelfPresenceStore", m => SelfPresenceStore = m);
waitForStore("MessageRequestStore", m => MessageRequestStore = m);
waitForStore("GIFPickerViewStore", m => GIFPickerViewStore = m);
waitForStore("GuildReadStateStore", m => GuildReadStateStore = m);
waitForStore("ThemeStore", m => {
ThemeStore = m;
// Importing this directly causes all webpack commons to be imported, which can easily cause circular dependencies.