mirror of
				https://github.com/monkeytypegame/monkeytype.git
				synced 2025-10-25 07:17:23 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			601 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			601 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| // Shared types between server/client.
 | |
| declare namespace SharedTypes {
 | |
|   interface ValidModeRule {
 | |
|     language: string;
 | |
|     mode: string;
 | |
|     mode2: string;
 | |
|   }
 | |
|   interface RewardBracket {
 | |
|     minRank: number;
 | |
|     maxRank: number;
 | |
|     minReward: number;
 | |
|     maxReward: number;
 | |
|   }
 | |
| 
 | |
|   interface Configuration {
 | |
|     maintenance: boolean;
 | |
|     quotes: {
 | |
|       reporting: {
 | |
|         enabled: boolean;
 | |
|         maxReports: number;
 | |
|         contentReportLimit: number;
 | |
|       };
 | |
|       submissionsEnabled: boolean;
 | |
|       maxFavorites: number;
 | |
|     };
 | |
|     results: {
 | |
|       savingEnabled: boolean;
 | |
|       objectHashCheckEnabled: boolean;
 | |
|       filterPresets: {
 | |
|         enabled: boolean;
 | |
|         maxPresetsPerUser: number;
 | |
|       };
 | |
|       limits: {
 | |
|         regularUser: number;
 | |
|         premiumUser: number;
 | |
|       };
 | |
|       maxBatchSize: number;
 | |
|     };
 | |
|     users: {
 | |
|       signUp: boolean;
 | |
|       lastHashesCheck: {
 | |
|         enabled: boolean;
 | |
|         maxHashes: number;
 | |
|       };
 | |
|       autoBan: {
 | |
|         enabled: boolean;
 | |
|         maxCount: number;
 | |
|         maxHours: number;
 | |
|       };
 | |
|       profiles: {
 | |
|         enabled: boolean;
 | |
|       };
 | |
|       discordIntegration: {
 | |
|         enabled: boolean;
 | |
|       };
 | |
|       xp: {
 | |
|         enabled: boolean;
 | |
|         funboxBonus: number;
 | |
|         gainMultiplier: number;
 | |
|         maxDailyBonus: number;
 | |
|         minDailyBonus: number;
 | |
|         streak: {
 | |
|           enabled: boolean;
 | |
|           maxStreakDays: number;
 | |
|           maxStreakMultiplier: number;
 | |
|         };
 | |
|       };
 | |
|       inbox: {
 | |
|         enabled: boolean;
 | |
|         maxMail: number;
 | |
|       };
 | |
|       premium: {
 | |
|         enabled: boolean;
 | |
|       };
 | |
|     };
 | |
|     admin: {
 | |
|       endpointsEnabled: boolean;
 | |
|     };
 | |
|     apeKeys: {
 | |
|       endpointsEnabled: boolean;
 | |
|       acceptKeys: boolean;
 | |
|       maxKeysPerUser: number;
 | |
|       apeKeyBytes: number;
 | |
|       apeKeySaltRounds: number;
 | |
|     };
 | |
|     rateLimiting: {
 | |
|       badAuthentication: {
 | |
|         enabled: boolean;
 | |
|         penalty: number;
 | |
|         flaggedStatusCodes: number[];
 | |
|       };
 | |
|     };
 | |
|     dailyLeaderboards: {
 | |
|       enabled: boolean;
 | |
|       leaderboardExpirationTimeInDays: number;
 | |
|       maxResults: number;
 | |
|       validModeRules: ValidModeRule[];
 | |
|       scheduleRewardsModeRules: ValidModeRule[];
 | |
|       topResultsToAnnounce: number;
 | |
|       xpRewardBrackets: RewardBracket[];
 | |
|     };
 | |
|     leaderboards: {
 | |
|       weeklyXp: {
 | |
|         enabled: boolean;
 | |
|         expirationTimeInDays: number;
 | |
|         xpRewardBrackets: RewardBracket[];
 | |
|       };
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   type StringNumber = `${number}`;
 | |
| 
 | |
|   interface PersonalBest {
 | |
|     acc: number;
 | |
|     consistency?: number;
 | |
|     difficulty: SharedTypes.Config.Difficulty;
 | |
|     lazyMode?: boolean;
 | |
|     language: string;
 | |
|     punctuation?: boolean;
 | |
|     numbers?: boolean;
 | |
|     raw: number;
 | |
|     wpm: number;
 | |
|     timestamp: number;
 | |
|   }
 | |
| 
 | |
|   interface PersonalBests {
 | |
|     time: Record<StringNumber, PersonalBest[]>;
 | |
|     words: Record<StringNumber, PersonalBest[]>;
 | |
|     quote: Record<StringNumber, PersonalBest[]>;
 | |
|     custom: Partial<Record<"custom", PersonalBest[]>>;
 | |
|     zen: Partial<Record<"zen", PersonalBest[]>>;
 | |
|   }
 | |
| 
 | |
|   interface IncompleteTest {
 | |
|     acc: number;
 | |
|     seconds: number;
 | |
|   }
 | |
| 
 | |
|   interface ChartData {
 | |
|     wpm: number[];
 | |
|     raw: number[];
 | |
|     err: number[];
 | |
|   }
 | |
| 
 | |
|   interface KeyStats {
 | |
|     average: number;
 | |
|     sd: number;
 | |
|   }
 | |
| 
 | |
|   interface Result<M extends SharedTypes.Config.Mode> {
 | |
|     _id: string;
 | |
|     wpm: number;
 | |
|     rawWpm: number;
 | |
|     charStats: [number, number, number, number];
 | |
|     acc: number;
 | |
|     mode: M;
 | |
|     mode2: SharedTypes.Config.Mode2<M>;
 | |
|     quoteLength?: number;
 | |
|     timestamp: number;
 | |
|     restartCount: number;
 | |
|     incompleteTestSeconds: number;
 | |
|     incompleteTests: IncompleteTest[];
 | |
|     testDuration: number;
 | |
|     afkDuration: number;
 | |
|     tags: string[];
 | |
|     consistency: number;
 | |
|     keyConsistency: number;
 | |
|     chartData: ChartData | "toolong";
 | |
|     uid: string;
 | |
|     keySpacingStats?: KeyStats;
 | |
|     keyDurationStats?: KeyStats;
 | |
|     isPb: boolean;
 | |
|     bailedOut: boolean;
 | |
|     blindMode: boolean;
 | |
|     lazyMode: boolean;
 | |
|     difficulty: SharedTypes.Config.Difficulty;
 | |
|     funbox: string;
 | |
|     language: string;
 | |
|     numbers: boolean;
 | |
|     punctuation: boolean;
 | |
|   }
 | |
| 
 | |
|   interface CustomText {
 | |
|     text: string[];
 | |
|     isWordRandom: boolean;
 | |
|     isTimeRandom: boolean;
 | |
|     word: number;
 | |
|     time: number;
 | |
|     delimiter: string;
 | |
|     textLen?: number;
 | |
|   }
 | |
| 
 | |
|   type DBResult<T extends SharedTypes.Config.Mode> = Omit<
 | |
|     SharedTypes.Result<T>,
 | |
|     | "bailedOut"
 | |
|     | "blindMode"
 | |
|     | "lazyMode"
 | |
|     | "difficulty"
 | |
|     | "funbox"
 | |
|     | "language"
 | |
|     | "numbers"
 | |
|     | "punctuation"
 | |
|     | "restartCount"
 | |
|     | "incompleteTestSeconds"
 | |
|     | "afkDuration"
 | |
|     | "tags"
 | |
|     | "incompleteTests"
 | |
|     | "customText"
 | |
|     | "quoteLength"
 | |
|     | "isPb"
 | |
|   > & {
 | |
|     correctChars?: number; // --------------
 | |
|     incorrectChars?: number; // legacy results
 | |
|     // --------------
 | |
|     name: string;
 | |
|     // -------------- fields that might be removed to save space
 | |
|     bailedOut?: boolean;
 | |
|     blindMode?: boolean;
 | |
|     lazyMode?: boolean;
 | |
|     difficulty?: SharedTypes.Config.Difficulty;
 | |
|     funbox?: string;
 | |
|     language?: string;
 | |
|     numbers?: boolean;
 | |
|     punctuation?: boolean;
 | |
|     restartCount?: number;
 | |
|     incompleteTestSeconds?: number;
 | |
|     afkDuration?: number;
 | |
|     tags?: string[];
 | |
|     customText?: CustomText;
 | |
|     quoteLength?: number;
 | |
|     isPb?: boolean;
 | |
|   };
 | |
| 
 | |
|   interface CompletedEvent extends Result<SharedTypes.Config.Mode> {
 | |
|     keySpacing: number[] | "toolong";
 | |
|     keyDuration: number[] | "toolong";
 | |
|     customText?: CustomText;
 | |
|     wpmConsistency: number;
 | |
|     challenge?: string | null;
 | |
|     keyOverlap: number;
 | |
|     lastKeyToEnd: number;
 | |
|     startToFirstKey: number;
 | |
|     charTotal: number;
 | |
|     stringified?: string;
 | |
|     hash?: string;
 | |
|   }
 | |
| 
 | |
|   interface ResultFilters {
 | |
|     _id: string;
 | |
|     name: string;
 | |
|     pb: {
 | |
|       no: boolean;
 | |
|       yes: boolean;
 | |
|     };
 | |
|     difficulty: {
 | |
|       normal: boolean;
 | |
|       expert: boolean;
 | |
|       master: boolean;
 | |
|     };
 | |
|     mode: {
 | |
|       words: boolean;
 | |
|       time: boolean;
 | |
|       quote: boolean;
 | |
|       zen: boolean;
 | |
|       custom: boolean;
 | |
|     };
 | |
|     words: {
 | |
|       "10": boolean;
 | |
|       "25": boolean;
 | |
|       "50": boolean;
 | |
|       "100": boolean;
 | |
|       custom: boolean;
 | |
|     };
 | |
|     time: {
 | |
|       "15": boolean;
 | |
|       "30": boolean;
 | |
|       "60": boolean;
 | |
|       "120": boolean;
 | |
|       custom: boolean;
 | |
|     };
 | |
|     quoteLength: {
 | |
|       short: boolean;
 | |
|       medium: boolean;
 | |
|       long: boolean;
 | |
|       thicc: boolean;
 | |
|     };
 | |
|     punctuation: {
 | |
|       on: boolean;
 | |
|       off: boolean;
 | |
|     };
 | |
|     numbers: {
 | |
|       on: boolean;
 | |
|       off: boolean;
 | |
|     };
 | |
|     date: {
 | |
|       last_day: boolean;
 | |
|       last_week: boolean;
 | |
|       last_month: boolean;
 | |
|       last_3months: boolean;
 | |
|       all: boolean;
 | |
|     };
 | |
|     tags: Record<string, boolean>;
 | |
|     language: Record<string, boolean>;
 | |
|     funbox: {
 | |
|       none?: boolean;
 | |
|     } & Record<string, boolean>;
 | |
|   }
 | |
| 
 | |
|   interface PSA {
 | |
|     _id: string;
 | |
|     message: string;
 | |
|     sticky?: boolean;
 | |
|     level?: number;
 | |
|     date?: number;
 | |
|   }
 | |
| 
 | |
|   interface SpeedHistogram {
 | |
|     [key: string]: number;
 | |
|   }
 | |
| 
 | |
|   interface PublicTypingStats {
 | |
|     type: string;
 | |
|     timeTyping: number;
 | |
|     testsCompleted: number;
 | |
|     testsStarted: number;
 | |
|   }
 | |
| 
 | |
|   interface ApeKey {
 | |
|     name: string;
 | |
|     enabled: boolean;
 | |
|     createdOn: number;
 | |
|     modifiedOn: number;
 | |
|     lastUsedOn: number;
 | |
|   }
 | |
| 
 | |
|   interface Config {
 | |
|     theme: string;
 | |
|     themeLight: string;
 | |
|     themeDark: string;
 | |
|     autoSwitchTheme: boolean;
 | |
|     customTheme: boolean;
 | |
|     customThemeColors: string[];
 | |
|     favThemes: string[];
 | |
|     showKeyTips: boolean;
 | |
|     showLiveWpm: boolean;
 | |
|     showTimerProgress: boolean;
 | |
|     smoothCaret: SharedTypes.Config.SmoothCaret;
 | |
|     quickRestart: SharedTypes.Config.QuickRestart;
 | |
|     punctuation: boolean;
 | |
|     numbers: boolean;
 | |
|     words: number;
 | |
|     time: number;
 | |
|     mode: SharedTypes.Config.Mode;
 | |
|     quoteLength: SharedTypes.Config.QuoteLength[];
 | |
|     language: string;
 | |
|     fontSize: number;
 | |
|     freedomMode: boolean;
 | |
|     difficulty: SharedTypes.Config.Difficulty;
 | |
|     blindMode: boolean;
 | |
|     quickEnd: boolean;
 | |
|     caretStyle: SharedTypes.Config.CaretStyle;
 | |
|     paceCaretStyle: SharedTypes.Config.CaretStyle;
 | |
|     flipTestColors: boolean;
 | |
|     layout: string;
 | |
|     funbox: string;
 | |
|     confidenceMode: SharedTypes.Config.ConfidenceMode;
 | |
|     indicateTypos: SharedTypes.Config.IndicateTypos;
 | |
|     timerStyle: SharedTypes.Config.TimerStyle;
 | |
|     colorfulMode: boolean;
 | |
|     randomTheme: SharedTypes.Config.RandomTheme;
 | |
|     timerColor: SharedTypes.Config.TimerColor;
 | |
|     timerOpacity: SharedTypes.Config.TimerOpacity;
 | |
|     stopOnError: SharedTypes.Config.StopOnError;
 | |
|     showAllLines: boolean;
 | |
|     keymapMode: SharedTypes.Config.KeymapMode;
 | |
|     keymapStyle: SharedTypes.Config.KeymapStyle;
 | |
|     keymapLegendStyle: SharedTypes.Config.KeymapLegendStyle;
 | |
|     keymapLayout: string;
 | |
|     keymapShowTopRow: SharedTypes.Config.KeymapShowTopRow;
 | |
|     fontFamily: string;
 | |
|     smoothLineScroll: boolean;
 | |
|     alwaysShowDecimalPlaces: boolean;
 | |
|     alwaysShowWordsHistory: boolean;
 | |
|     singleListCommandLine: SharedTypes.Config.SingleListCommandLine;
 | |
|     capsLockWarning: boolean;
 | |
|     playSoundOnError: SharedTypes.Config.PlaySoundOnError;
 | |
|     playSoundOnClick: SharedTypes.Config.PlaySoundOnClick;
 | |
|     soundVolume: SharedTypes.Config.SoundVolume;
 | |
|     startGraphsAtZero: boolean;
 | |
|     showOutOfFocusWarning: boolean;
 | |
|     paceCaret: SharedTypes.Config.PaceCaret;
 | |
|     paceCaretCustomSpeed: number;
 | |
|     repeatedPace: boolean;
 | |
|     pageWidth: SharedTypes.Config.PageWidth;
 | |
|     accountChart: SharedTypes.Config.AccountChart;
 | |
|     minWpm: SharedTypes.Config.MinimumWordsPerMinute;
 | |
|     minWpmCustomSpeed: number;
 | |
|     highlightMode: SharedTypes.Config.HighlightMode;
 | |
|     typingSpeedUnit: SharedTypes.Config.TypingSpeedUnit;
 | |
|     ads: SharedTypes.Config.Ads;
 | |
|     hideExtraLetters: boolean;
 | |
|     strictSpace: boolean;
 | |
|     minAcc: SharedTypes.Config.MinimumAccuracy;
 | |
|     minAccCustom: number;
 | |
|     showLiveAcc: boolean;
 | |
|     showLiveBurst: boolean;
 | |
|     monkey: boolean;
 | |
|     repeatQuotes: SharedTypes.Config.RepeatQuotes;
 | |
|     oppositeShiftMode: SharedTypes.Config.OppositeShiftMode;
 | |
|     customBackground: string;
 | |
|     customBackgroundSize: SharedTypes.Config.CustomBackgroundSize;
 | |
|     customBackgroundFilter: SharedTypes.Config.CustomBackgroundFilter;
 | |
|     customLayoutfluid: SharedTypes.Config.CustomLayoutFluid;
 | |
|     monkeyPowerLevel: SharedTypes.Config.MonkeyPowerLevel;
 | |
|     minBurst: SharedTypes.Config.MinimumBurst;
 | |
|     minBurstCustomSpeed: number;
 | |
|     burstHeatmap: boolean;
 | |
|     britishEnglish: boolean;
 | |
|     lazyMode: boolean;
 | |
|     showAverage: SharedTypes.Config.ShowAverage;
 | |
|     tapeMode: SharedTypes.Config.TapeMode;
 | |
|   }
 | |
| 
 | |
|   type ConfigValue = Config[keyof Config];
 | |
| 
 | |
|   type ConfigPreset = Partial<Config> & {
 | |
|     tags?: string[];
 | |
|   };
 | |
| 
 | |
|   interface DBConfigPreset {
 | |
|     _id: string;
 | |
|     uid: string;
 | |
|     name: string;
 | |
|     config: SharedTypes.ConfigPreset;
 | |
|   }
 | |
| 
 | |
|   interface LeaderboardEntry {
 | |
|     _id: string;
 | |
|     wpm: number;
 | |
|     acc: number;
 | |
|     timestamp: number;
 | |
|     raw: number;
 | |
|     consistency?: number;
 | |
|     uid: string;
 | |
|     name: string;
 | |
|     discordId?: string;
 | |
|     discordAvatar?: string;
 | |
|     rank: number;
 | |
|     badgeId: number | null;
 | |
|   }
 | |
| 
 | |
|   type PostResultResponse = {
 | |
|     isPb: boolean;
 | |
|     tagPbs: string[];
 | |
|     insertedId: string;
 | |
|     dailyLeaderboardRank?: number;
 | |
|     weeklyXpLeaderboardRank?: number;
 | |
|     xp: number;
 | |
|     dailyXpBonus: boolean;
 | |
|     xpBreakdown: Record<string, number>;
 | |
|     streak: number;
 | |
|   };
 | |
| 
 | |
|   type UserStreak = {
 | |
|     lastResultTimestamp: number;
 | |
|     length: number;
 | |
|     maxLength: number;
 | |
|     hourOffset?: number;
 | |
|   };
 | |
| 
 | |
|   type UserTag = {
 | |
|     _id: string;
 | |
|     name: string;
 | |
|     personalBests: PersonalBests;
 | |
|   };
 | |
| 
 | |
|   type UserProfileDetails = {
 | |
|     bio?: string;
 | |
|     keyboard?: string;
 | |
|     socialProfiles: {
 | |
|       twitter?: string;
 | |
|       github?: string;
 | |
|       website?: string;
 | |
|     };
 | |
|   };
 | |
| 
 | |
|   type CustomTheme = {
 | |
|     _id: string;
 | |
|     name: string;
 | |
|     colors: string[];
 | |
|   };
 | |
| 
 | |
|   type PremiumInfo = {
 | |
|     startTimestamp: number;
 | |
|     expirationTimestamp: number;
 | |
|   };
 | |
| 
 | |
|   type UserQuoteRatings = Record<string, Record<string, number>>;
 | |
| 
 | |
|   type UserLbMemory = Record<string, Record<string, Record<string, number>>>;
 | |
| 
 | |
|   type UserInventory = {
 | |
|     badges: Badge[];
 | |
|   };
 | |
| 
 | |
|   type Badge = {
 | |
|     id: number;
 | |
|     selected?: boolean;
 | |
|   };
 | |
| 
 | |
|   type User = {
 | |
|     name: string;
 | |
|     email: string;
 | |
|     uid: string;
 | |
|     addedAt: number;
 | |
|     personalBests: PersonalBests;
 | |
|     lastReultHashes?: string[]; //todo: fix typo (its in the db too)
 | |
|     completedTests?: number;
 | |
|     startedTests?: number;
 | |
|     timeTyping?: number;
 | |
|     streak?: UserStreak;
 | |
|     xp?: number;
 | |
|     discordId?: string;
 | |
|     discordAvatar?: string;
 | |
|     tags?: UserTag[];
 | |
|     profileDetails?: UserProfileDetails;
 | |
|     customThemes?: CustomTheme[];
 | |
|     premium?: PremiumInfo;
 | |
|     quoteRatings?: UserQuoteRatings;
 | |
|     favoriteQuotes?: Record<string, string[]>;
 | |
|     lbMemory?: UserLbMemory;
 | |
|     inventory?: UserInventory;
 | |
|     banned?: boolean;
 | |
|     lbOptOut?: boolean;
 | |
|     verified?: boolean;
 | |
|     needsToChangeName?: boolean;
 | |
|     quoteMod?: boolean | string;
 | |
|     resultFilterPresets?: ResultFilters[];
 | |
|   };
 | |
| 
 | |
|   type Reward<T> = {
 | |
|     type: string;
 | |
|     item: T;
 | |
|   };
 | |
| 
 | |
|   type XpReward = {
 | |
|     type: "xp";
 | |
|     item: number;
 | |
|   } & Reward<number>;
 | |
| 
 | |
|   type BadgeReward = {
 | |
|     type: "badge";
 | |
|     item: SharedTypes.Badge;
 | |
|   } & Reward<SharedTypes.Badge>;
 | |
| 
 | |
|   type AllRewards = XpReward | BadgeReward;
 | |
| 
 | |
|   type MonkeyMail = {
 | |
|     id: string;
 | |
|     subject: string;
 | |
|     body: string;
 | |
|     timestamp: number;
 | |
|     read: boolean;
 | |
|     rewards: AllRewards[];
 | |
|   };
 | |
| 
 | |
|   type UserProfile = Pick<
 | |
|     User,
 | |
|     | "name"
 | |
|     | "banned"
 | |
|     | "addedAt"
 | |
|     | "discordId"
 | |
|     | "discordAvatar"
 | |
|     | "xp"
 | |
|     | "lbOptOut"
 | |
|     | "inventory"
 | |
|     | "uid"
 | |
|   > & {
 | |
|     typingStats: {
 | |
|       completedTests: User["completedTests"];
 | |
|       startedTests: User["startedTests"];
 | |
|       timeTyping: User["timeTyping"];
 | |
|     };
 | |
|     streak: UserStreak["length"];
 | |
|     maxStreak: UserStreak["maxLength"];
 | |
|     details: UserProfileDetails;
 | |
|     allTimeLbs: {
 | |
|       time: Record<string, Record<string, number | null>>;
 | |
|     };
 | |
|     personalBests: {
 | |
|       time: Pick<
 | |
|         Record<`${number}`, SharedTypes.PersonalBest[]>,
 | |
|         "15" | "30" | "60" | "120"
 | |
|       >;
 | |
|       words: Pick<
 | |
|         Record<`${number}`, SharedTypes.PersonalBest[]>,
 | |
|         "10" | "25" | "50" | "100"
 | |
|       >;
 | |
|     };
 | |
|   };
 | |
| }
 |