From 8c035c1687607df7cb1b7dc530d7ed5bcd1470f3 Mon Sep 17 00:00:00 2001 From: Miodec Date: Tue, 2 Dec 2025 10:00:28 +0100 Subject: [PATCH 1/5] chore: remove duplicated debug log --- frontend/src/ts/input/handlers/keydown.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/frontend/src/ts/input/handlers/keydown.ts b/frontend/src/ts/input/handlers/keydown.ts index dc87f89f3459..4bbe80224e84 100644 --- a/frontend/src/ts/input/handlers/keydown.ts +++ b/frontend/src/ts/input/handlers/keydown.ts @@ -152,12 +152,6 @@ async function handleFunboxes( } export async function onKeydown(event: KeyboardEvent): Promise { - console.debug("wordsInput event keydown", { - event, - key: event.key, - code: event.code, - }); - const now = performance.now(); TestInput.recordKeydownTime(now, event); From ad3b7b37d154a8efe852c0b6b9cfb4e9e164dcea Mon Sep 17 00:00:00 2001 From: Miodec Date: Tue, 2 Dec 2025 10:26:46 +0100 Subject: [PATCH 2/5] fix: backspacing causing desync on some platforms --- frontend/src/ts/input/input-element.ts | 4 ++-- frontend/src/ts/input/listeners/misc.ts | 13 +++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/frontend/src/ts/input/input-element.ts b/frontend/src/ts/input/input-element.ts index 44b1de1edab0..6d8c0a946232 100644 --- a/frontend/src/ts/input/input-element.ts +++ b/frontend/src/ts/input/input-element.ts @@ -1,10 +1,10 @@ -const el = document.querySelector("#wordsInput") as HTMLInputElement; +const el = document.querySelector("#wordsInput") as HTMLTextAreaElement; if (el === null) { throw new Error("Words input element not found"); } -export function getInputElement(): HTMLInputElement { +export function getInputElement(): HTMLTextAreaElement { return el; } diff --git a/frontend/src/ts/input/listeners/misc.ts b/frontend/src/ts/input/listeners/misc.ts index 10e985070c4e..8c49762e0c44 100644 --- a/frontend/src/ts/input/listeners/misc.ts +++ b/frontend/src/ts/input/listeners/misc.ts @@ -20,20 +20,17 @@ inputEl.addEventListener("select selectstart", (event) => { inputEl.addEventListener("selectionchange", (event) => { const selection = window.getSelection(); + console.debug("wordsInput event selectionchange", { event, selection: selection?.toString(), isCollapsed: selection?.isCollapsed, - selectionStart: (event.target as HTMLInputElement).selectionStart, - selectionEnd: (event.target as HTMLInputElement).selectionEnd, + selectionStart: inputEl.selectionStart, + selectionEnd: inputEl.selectionEnd, }); - const el = event.target; - if (el === null || !(el instanceof HTMLInputElement)) { - return; - } - const hasSelectedText = el.selectionStart !== el.selectionEnd; - const isCursorAtEnd = el.selectionStart === el.value.length; + const hasSelectedText = inputEl.selectionStart !== inputEl.selectionEnd; + const isCursorAtEnd = inputEl.selectionStart === inputEl.value.length; if (hasSelectedText || !isCursorAtEnd) { moveInputElementCaretToTheEnd(); } From ad8e4f65b5bfe561ab6adf3abb269cd5048ca3c7 Mon Sep 17 00:00:00 2001 From: Miodec Date: Tue, 2 Dec 2025 15:54:48 +0100 Subject: [PATCH 3/5] chore: add disable slow timer button to dev options --- frontend/src/html/popups.html | 1 + frontend/src/ts/modals/dev-options.ts | 6 +++ frontend/src/ts/test/test-timer.ts | 53 +++++++++++++++------------ 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/frontend/src/html/popups.html b/frontend/src/html/popups.html index bbe596c993b9..686dd1306e99 100644 --- a/frontend/src/html/popups.html +++ b/frontend/src/html/popups.html @@ -68,6 +68,7 @@ + diff --git a/frontend/src/ts/modals/dev-options.ts b/frontend/src/ts/modals/dev-options.ts index 36c632e53dc4..9742c6e8832c 100644 --- a/frontend/src/ts/modals/dev-options.ts +++ b/frontend/src/ts/modals/dev-options.ts @@ -9,6 +9,7 @@ import { update } from "../elements/xp-bar"; import { toggleUserFakeChartData } from "../test/result"; import { toggleCaretDebug } from "../utils/caret"; import { getInputElement } from "../input/input-element"; +import { disableSlowTimerFail } from "../test/test-timer"; let mediaQueryDebugLevel = 0; @@ -94,6 +95,11 @@ async function setup(modalEl: HTMLElement): Promise { modalEl.querySelector(".toggleCaretDebug")?.addEventListener("click", () => { toggleCaretDebug(); }); + modalEl + .querySelector(".disableSlowTimerFail") + ?.addEventListener("click", () => { + disableSlowTimerFail(); + }); } const modal = new AnimatedModal({ diff --git a/frontend/src/ts/test/test-timer.ts b/frontend/src/ts/test/test-timer.ts index 3418ebc3dcb1..e0acebbd408b 100644 --- a/frontend/src/ts/test/test-timer.ts +++ b/frontend/src/ts/test/test-timer.ts @@ -32,6 +32,11 @@ let timer: NodeJS.Timeout | null = null; const interval = 1000; let expected = 0; +let slowTimerFailEnabled = true; +export function disableSlowTimerFail(): void { + slowTimerFailEnabled = false; +} + let timerDebug = false; export function enableTimerDebug(): void { timerDebug = true; @@ -234,30 +239,32 @@ export async function start(): Promise { expected: expected, nextDelay: delay, }); - if ( - (Config.mode === "time" && Config.time < 130 && Config.time > 0) || - (Config.mode === "words" && Config.words < 250 && Config.words > 0) - ) { - if (delay < interval / 2) { - //slow timer - SlowTimer.set(); - setLowFpsMode(); - } - if (delay < interval / 10) { - slowTimerCount++; - if (slowTimerCount > 5) { + if (slowTimerFailEnabled) { + if ( + (Config.mode === "time" && Config.time < 130 && Config.time > 0) || + (Config.mode === "words" && Config.words < 250 && Config.words > 0) + ) { + if (delay < interval / 2) { //slow timer - - Notifications.add( - 'This could be caused by "efficiency mode" on Microsoft Edge.', - ); - - Notifications.add( - "Stopping the test due to bad performance. This would cause test calculations to be incorrect. If this happens a lot, please report this.", - -1, - ); - - TimerEvent.dispatch("fail", "slow timer"); + SlowTimer.set(); + setLowFpsMode(); + } + if (delay < interval / 10) { + slowTimerCount++; + if (slowTimerCount > 5) { + //slow timer + + Notifications.add( + 'This could be caused by "efficiency mode" on Microsoft Edge.', + ); + + Notifications.add( + "Stopping the test due to bad performance. This would cause test calculations to be incorrect. If this happens a lot, please report this.", + -1, + ); + + TimerEvent.dispatch("fail", "slow timer"); + } } } } From b64db65e59cacfc725857bfe9121bd848c0ec194 Mon Sep 17 00:00:00 2001 From: Miodec Date: Tue, 2 Dec 2025 20:42:51 +0100 Subject: [PATCH 4/5] fix: weird input behavior on some android keyboards --- frontend/src/ts/input/handlers/insert-text.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/ts/input/handlers/insert-text.ts b/frontend/src/ts/input/handlers/insert-text.ts index b3c1f67ca22c..598336af93b1 100644 --- a/frontend/src/ts/input/handlers/insert-text.ts +++ b/frontend/src/ts/input/handlers/insert-text.ts @@ -69,6 +69,7 @@ export async function onInsertText(options: OnInsertTextParams): Promise { // make sure to not call TestInput.input.syncWithInputElement in here // it will be updated later in the body of onInsertText setInputElementValue(inputValue.slice(0, -options.data.length)); + TestInput.input.syncWithInputElement(); for (let i = 0; i < options.data.length; i++) { const char = options.data[i] as string; From 2fcc86dddf51bb1ace234c08b15dcf914348f74c Mon Sep 17 00:00:00 2001 From: Miodec Date: Tue, 2 Dec 2025 23:33:51 +0100 Subject: [PATCH 5/5] chore: make sure to use production env when building for production --- .gitignore | 1 + frontend/vite.config.js | 14 ++++++++++++-- packages/release/src/index.js | 6 +++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 788a04ad74ca..0b4945d42bb3 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ node_modules_bak/ # dotenv environment variables file .env +.env* #vs code .vscode/* diff --git a/frontend/vite.config.js b/frontend/vite.config.js index bf2572157c8f..dc08c12fdfbe 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -1,12 +1,17 @@ import { defineConfig, mergeConfig } from "vite"; import injectHTML from "vite-plugin-html-inject"; import autoprefixer from "autoprefixer"; -import "dotenv/config"; +import { config as dotenvConfig } from "dotenv"; import PROD_CONFIG from "./vite.config.prod"; import DEV_CONFIG from "./vite.config.dev"; import MagicString from "magic-string"; import { Fonts } from "./src/ts/constants/fonts"; +// Load environment variables based on NODE_ENV +const envFile = + process.env.NODE_ENV === "production" ? ".env.production" : ".env"; +dotenvConfig({ path: envFile }); + /** @type {import("vite").UserConfig} */ const BASE_CONFIG = { plugins: [ @@ -63,8 +68,13 @@ const BASE_CONFIG = { export default defineConfig(({ command }) => { if (command === "build") { + const envFileName = + process.env.NODE_ENV === "production" ? ".env.production" : ".env"; if (process.env.RECAPTCHA_SITE_KEY === undefined) { - throw new Error(".env: RECAPTCHA_SITE_KEY is not defined"); + throw new Error(`${envFileName}: RECAPTCHA_SITE_KEY is not defined`); + } + if (process.env.SENTRY && process.env.SENTRY_AUTH_TOKEN === undefined) { + throw new Error(`${envFileName}: SENTRY_AUTH_TOKEN is not defined`); } return mergeConfig(BASE_CONFIG, PROD_CONFIG); } else { diff --git a/packages/release/src/index.js b/packages/release/src/index.js index f48ed7071096..dfbca0a07e97 100755 --- a/packages/release/src/index.js +++ b/packages/release/src/index.js @@ -179,15 +179,15 @@ const buildProject = () => { if (isFrontend && !isBackend) { runProjectRootCommand( - "SENTRY=1 npx turbo lint test check-assets build --filter @monkeytype/frontend --force", + "NODE_ENV=production SENTRY=1 npx turbo lint test check-assets build --filter @monkeytype/frontend --force", ); } else if (isBackend && !isFrontend) { runProjectRootCommand( - "SENTRY=1 npx turbo lint test build --filter @monkeytype/backend --force", + "NODE_ENV=production SENTRY=1 npx turbo lint test build --filter @monkeytype/backend --force", ); } else { runProjectRootCommand( - "SENTRY=1 npx turbo lint test check-assets build --force", + "NODE_ENV=production SENTRY=1 npx turbo lint test check-assets build --force", ); } };