aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJack <[email protected]>2024-09-23 15:34:16 +0200
committerGitHub <[email protected]>2024-09-23 15:34:16 +0200
commitb6bd5ba2b4d2d441c4e09ceec2ad42b24e10d097 (patch)
tree8b889f95b55682df6ca78b6a7abaf76120e87a51
parentd9788a15e7a63060bcb6e9fb5e860da771730b58 (diff)
downloadmonkeytype-b6bd5ba2b4d2d441c4e09ceec2ad42b24e10d097.tar.gz
monkeytype-b6bd5ba2b4d2d441c4e09ceec2ad42b24e10d097.zip
refactor: remove global type namespaces (@miodec) (#5907)
Remove global types, move types to where they originate from, import them when needed.
-rw-r--r--backend/__migration__/testActivity.ts6
-rw-r--r--backend/__tests__/__migration__/testActivity.spec.ts3
-rw-r--r--backend/__tests__/__testData__/auth.ts2
-rw-r--r--backend/__tests__/__testData__/users.ts8
-rw-r--r--backend/__tests__/api/controllers/admin.spec.ts8
-rw-r--r--backend/__tests__/api/controllers/ape-key.spec.ts11
-rw-r--r--backend/__tests__/api/controllers/result.spec.ts6
-rw-r--r--backend/__tests__/api/controllers/user.spec.ts28
-rw-r--r--backend/__tests__/dal/leaderboards.spec.ts18
-rw-r--r--backend/__tests__/dal/result.spec.ts5
-rw-r--r--backend/__tests__/dal/user.spec.ts8
-rw-r--r--backend/__tests__/middlewares/auth.spec.ts5
-rw-r--r--backend/__tests__/middlewares/configuration.spec.ts1
-rw-r--r--backend/__tests__/middlewares/permission.spec.ts4
-rw-r--r--backend/__tests__/tsconfig.json2
-rw-r--r--backend/__tests__/utils/daily-leaderboards.spec.ts3
-rw-r--r--backend/__tests__/utils/pb.spec.ts4
-rw-r--r--backend/src/api/controllers/admin.ts11
-rw-r--r--backend/src/api/controllers/ape-key.ts13
-rw-r--r--backend/src/api/controllers/config.ts7
-rw-r--r--backend/src/api/controllers/configuration.ts7
-rw-r--r--backend/src/api/controllers/dev.ts17
-rw-r--r--backend/src/api/controllers/leaderboard.ts13
-rw-r--r--backend/src/api/controllers/preset.ts9
-rw-r--r--backend/src/api/controllers/psa.ts5
-rw-r--r--backend/src/api/controllers/public.ts5
-rw-r--r--backend/src/api/controllers/quote.ts19
-rw-r--r--backend/src/api/controllers/result.ts21
-rw-r--r--backend/src/api/controllers/user.ts111
-rw-r--r--backend/src/api/controllers/webhooks.ts3
-rw-r--r--backend/src/api/routes/index.ts3
-rw-r--r--backend/src/api/ts-rest-adapter.ts19
-rw-r--r--backend/src/api/types.ts27
-rw-r--r--backend/src/constants/funbox-list.ts11
-rw-r--r--backend/src/dal/ape-keys.ts28
-rw-r--r--backend/src/dal/blocklist.ts18
-rw-r--r--backend/src/dal/config.ts2
-rw-r--r--backend/src/dal/leaderboards.ts151
-rw-r--r--backend/src/dal/new-quotes.ts3
-rw-r--r--backend/src/dal/preset.ts3
-rw-r--r--backend/src/dal/psa.ts3
-rw-r--r--backend/src/dal/quote-ratings.ts3
-rw-r--r--backend/src/dal/report.ts31
-rw-r--r--backend/src/dal/result.ts24
-rw-r--r--backend/src/dal/user.ts97
-rw-r--r--backend/src/middlewares/auth.ts27
-rw-r--r--backend/src/middlewares/configuration.ts6
-rw-r--r--backend/src/middlewares/context.ts18
-rw-r--r--backend/src/middlewares/error.ts3
-rw-r--r--backend/src/middlewares/permission.ts25
-rw-r--r--backend/src/middlewares/rate-limit.ts17
-rw-r--r--backend/src/middlewares/utility.ts16
-rw-r--r--backend/src/types/types.d.ts131
-rw-r--r--backend/src/utils/misc.ts15
-rw-r--r--backend/src/utils/pb.ts12
-rw-r--r--backend/src/utils/result.ts18
-rw-r--r--frontend/src/ts/commandline/commandline.ts15
-rw-r--r--frontend/src/ts/commandline/lists.ts29
-rw-r--r--frontend/src/ts/commandline/lists/add-or-remove-theme-to-favorites.ts3
-rw-r--r--frontend/src/ts/commandline/lists/always-show-decimal.ts5
-rw-r--r--frontend/src/ts/commandline/lists/background-filter.ts5
-rw-r--r--frontend/src/ts/commandline/lists/background-size.ts5
-rw-r--r--frontend/src/ts/commandline/lists/bail-out.ts5
-rw-r--r--frontend/src/ts/commandline/lists/blind-mode.ts5
-rw-r--r--frontend/src/ts/commandline/lists/british-english.ts5
-rw-r--r--frontend/src/ts/commandline/lists/caps-lock-warning.ts5
-rw-r--r--frontend/src/ts/commandline/lists/caret-style.ts5
-rw-r--r--frontend/src/ts/commandline/lists/colorful-mode.ts5
-rw-r--r--frontend/src/ts/commandline/lists/confidence-mode.ts3
-rw-r--r--frontend/src/ts/commandline/lists/custom-theme.ts5
-rw-r--r--frontend/src/ts/commandline/lists/custom-themes-list.ts5
-rw-r--r--frontend/src/ts/commandline/lists/difficulty.ts5
-rw-r--r--frontend/src/ts/commandline/lists/enable-ads.ts5
-rw-r--r--frontend/src/ts/commandline/lists/flip-test-colors.ts5
-rw-r--r--frontend/src/ts/commandline/lists/font-family.ts8
-rw-r--r--frontend/src/ts/commandline/lists/font-size.ts3
-rw-r--r--frontend/src/ts/commandline/lists/freedom-mode.ts5
-rw-r--r--frontend/src/ts/commandline/lists/funbox.ts8
-rw-r--r--frontend/src/ts/commandline/lists/hide-extra-letters.ts5
-rw-r--r--frontend/src/ts/commandline/lists/highlight-mode.ts5
-rw-r--r--frontend/src/ts/commandline/lists/indicate-typos.ts5
-rw-r--r--frontend/src/ts/commandline/lists/key-tips.ts5
-rw-r--r--frontend/src/ts/commandline/lists/keymap-layouts.ts8
-rw-r--r--frontend/src/ts/commandline/lists/keymap-legend-style.ts5
-rw-r--r--frontend/src/ts/commandline/lists/keymap-mode.ts5
-rw-r--r--frontend/src/ts/commandline/lists/keymap-show-top-row.ts5
-rw-r--r--frontend/src/ts/commandline/lists/keymap-size.ts3
-rw-r--r--frontend/src/ts/commandline/lists/keymap-style.ts5
-rw-r--r--frontend/src/ts/commandline/lists/languages.ts5
-rw-r--r--frontend/src/ts/commandline/lists/layouts.ts8
-rw-r--r--frontend/src/ts/commandline/lists/lazy-mode.ts5
-rw-r--r--frontend/src/ts/commandline/lists/live-acc-style.ts5
-rw-r--r--frontend/src/ts/commandline/lists/live-burst-style.ts5
-rw-r--r--frontend/src/ts/commandline/lists/live-speed-style.ts5
-rw-r--r--frontend/src/ts/commandline/lists/load-challenge.ts8
-rw-r--r--frontend/src/ts/commandline/lists/max-line-width.ts3
-rw-r--r--frontend/src/ts/commandline/lists/min-acc.ts5
-rw-r--r--frontend/src/ts/commandline/lists/min-burst.ts5
-rw-r--r--frontend/src/ts/commandline/lists/min-wpm.ts5
-rw-r--r--frontend/src/ts/commandline/lists/mode.ts3
-rw-r--r--frontend/src/ts/commandline/lists/monkey-power-level.ts5
-rw-r--r--frontend/src/ts/commandline/lists/navigation.ts3
-rw-r--r--frontend/src/ts/commandline/lists/numbers.ts5
-rw-r--r--frontend/src/ts/commandline/lists/opposite-shift-mode.ts5
-rw-r--r--frontend/src/ts/commandline/lists/out-of-focus-warning.ts5
-rw-r--r--frontend/src/ts/commandline/lists/pace-caret-style.ts5
-rw-r--r--frontend/src/ts/commandline/lists/pace-caret.ts5
-rw-r--r--frontend/src/ts/commandline/lists/presets.ts7
-rw-r--r--frontend/src/ts/commandline/lists/punctuation.ts3
-rw-r--r--frontend/src/ts/commandline/lists/quick-end.ts5
-rw-r--r--frontend/src/ts/commandline/lists/quick-restart.ts5
-rw-r--r--frontend/src/ts/commandline/lists/quote-favorites.ts9
-rw-r--r--frontend/src/ts/commandline/lists/quote-length.ts3
-rw-r--r--frontend/src/ts/commandline/lists/random-theme.ts5
-rw-r--r--frontend/src/ts/commandline/lists/repeat-quotes.ts5
-rw-r--r--frontend/src/ts/commandline/lists/repeated-pace.ts5
-rw-r--r--frontend/src/ts/commandline/lists/result-saving.ts5
-rw-r--r--frontend/src/ts/commandline/lists/result-screen.ts5
-rw-r--r--frontend/src/ts/commandline/lists/show-all-lines.ts5
-rw-r--r--frontend/src/ts/commandline/lists/show-average.ts5
-rw-r--r--frontend/src/ts/commandline/lists/show-words-history.ts5
-rw-r--r--frontend/src/ts/commandline/lists/single-list-commandline.ts5
-rw-r--r--frontend/src/ts/commandline/lists/smooth-caret.ts5
-rw-r--r--frontend/src/ts/commandline/lists/smooth-line-scroll.ts5
-rw-r--r--frontend/src/ts/commandline/lists/sound-on-click.ts5
-rw-r--r--frontend/src/ts/commandline/lists/sound-on-error.ts5
-rw-r--r--frontend/src/ts/commandline/lists/sound-volume.ts5
-rw-r--r--frontend/src/ts/commandline/lists/start-graphs-at-zero.ts5
-rw-r--r--frontend/src/ts/commandline/lists/stop-on-error.ts3
-rw-r--r--frontend/src/ts/commandline/lists/strict-space.ts5
-rw-r--r--frontend/src/ts/commandline/lists/tags.ts5
-rw-r--r--frontend/src/ts/commandline/lists/tape-mode.ts5
-rw-r--r--frontend/src/ts/commandline/lists/themes.ts10
-rw-r--r--frontend/src/ts/commandline/lists/time.ts3
-rw-r--r--frontend/src/ts/commandline/lists/timer-color.ts5
-rw-r--r--frontend/src/ts/commandline/lists/timer-opacity.ts5
-rw-r--r--frontend/src/ts/commandline/lists/timer-style.ts5
-rw-r--r--frontend/src/ts/commandline/lists/typing-speed-unit.ts5
-rw-r--r--frontend/src/ts/commandline/lists/words.ts3
-rw-r--r--frontend/src/ts/commandline/types.ts42
-rw-r--r--frontend/src/ts/config.ts8
-rw-r--r--frontend/src/ts/constants/default-snapshot.ts5
-rw-r--r--frontend/src/ts/controllers/account-controller.ts2
-rw-r--r--frontend/src/ts/controllers/badge-controller.ts16
-rw-r--r--frontend/src/ts/controllers/chart-controller.ts56
-rw-r--r--frontend/src/ts/controllers/page-controller.ts3
-rw-r--r--frontend/src/ts/controllers/preset-controller.ts2
-rw-r--r--frontend/src/ts/controllers/quotes-controller.ts50
-rw-r--r--frontend/src/ts/db.ts190
-rw-r--r--frontend/src/ts/elements/account-button.ts6
-rw-r--r--frontend/src/ts/elements/account/result-filters.ts6
-rw-r--r--frontend/src/ts/elements/alerts.ts3
-rw-r--r--frontend/src/ts/elements/keymap.ts4
-rw-r--r--frontend/src/ts/elements/notifications.ts11
-rw-r--r--frontend/src/ts/elements/profile.ts4
-rw-r--r--frontend/src/ts/elements/test-activity-calendar.ts24
-rw-r--r--frontend/src/ts/elements/test-activity.ts10
-rw-r--r--frontend/src/ts/modals/edit-preset.ts32
-rw-r--r--frontend/src/ts/modals/edit-result-tags.ts4
-rw-r--r--frontend/src/ts/modals/quote-rate.ts10
-rw-r--r--frontend/src/ts/modals/quote-report.ts4
-rw-r--r--frontend/src/ts/modals/quote-search.ts18
-rw-r--r--frontend/src/ts/modals/share-test-settings.ts2
-rw-r--r--frontend/src/ts/modals/streak-hour-offset.ts4
-rw-r--r--frontend/src/ts/modals/version-history.ts2
-rw-r--r--frontend/src/ts/modals/word-filter.ts4
-rw-r--r--frontend/src/ts/pages/account.ts32
-rw-r--r--frontend/src/ts/pages/page.ts16
-rw-r--r--frontend/src/ts/pages/settings.ts11
-rw-r--r--frontend/src/ts/states/active-page.ts8
-rw-r--r--frontend/src/ts/test/custom-text.ts13
-rw-r--r--frontend/src/ts/test/funbox/funbox-list.ts15
-rw-r--r--frontend/src/ts/test/funbox/funbox-validation.ts5
-rw-r--r--frontend/src/ts/test/funbox/funbox.ts8
-rw-r--r--frontend/src/ts/test/lazy-mode.ts8
-rw-r--r--frontend/src/ts/test/poetry.ts2
-rw-r--r--frontend/src/ts/test/practise-words.ts2
-rw-r--r--frontend/src/ts/test/result.ts14
-rw-r--r--frontend/src/ts/test/shift-tracker.ts2
-rw-r--r--frontend/src/ts/test/test-logic.ts9
-rw-r--r--frontend/src/ts/test/test-state.ts6
-rw-r--r--frontend/src/ts/test/test-stats.ts7
-rw-r--r--frontend/src/ts/test/test-timer.ts20
-rw-r--r--frontend/src/ts/test/test-ui.ts2
-rw-r--r--frontend/src/ts/test/test-words.ts8
-rw-r--r--frontend/src/ts/test/wikipedia.ts9
-rw-r--r--frontend/src/ts/test/words-generator.ts57
-rw-r--r--frontend/src/ts/test/wordset.ts18
-rw-r--r--frontend/src/ts/types/types.d.ts510
-rw-r--r--frontend/src/ts/utils/json-data.ts273
-rw-r--r--frontend/src/ts/utils/misc.ts37
-rw-r--r--frontend/src/ts/utils/results.ts11
-rw-r--r--frontend/src/ts/utils/simple-modal.ts2
-rw-r--r--frontend/src/ts/utils/typing-speed-units.ts14
-rw-r--r--frontend/src/ts/utils/url-handler.ts2
-rw-r--r--frontend/tsconfig.json6
-rw-r--r--packages/contracts/src/schemas/shared.ts29
-rw-r--r--packages/contracts/src/schemas/users.ts47
198 files changed, 1608 insertions, 1642 deletions
diff --git a/backend/__migration__/testActivity.ts b/backend/__migration__/testActivity.ts
index 655611f62..211d64d63 100644
--- a/backend/__migration__/testActivity.ts
+++ b/backend/__migration__/testActivity.ts
@@ -3,13 +3,15 @@ import * as DB from "../src/init/db";
import { Collection, Db } from "mongodb";
import readlineSync from "readline-sync";
+import { DBUser } from "../src/dal/user";
+import { DBResult } from "../src/utils/result";
const batchSize = 50;
let appRunning = true;
let db: Db | undefined;
-let userCollection: Collection<MonkeyTypes.DBUser>;
-let resultCollection: Collection<MonkeyTypes.DBResult>;
+let userCollection: Collection<DBUser>;
+let resultCollection: Collection<DBResult>;
const filter = { testActivity: { $exists: false } };
diff --git a/backend/__tests__/__migration__/testActivity.spec.ts b/backend/__tests__/__migration__/testActivity.spec.ts
index badc6f7f0..2b65382fb 100644
--- a/backend/__tests__/__migration__/testActivity.spec.ts
+++ b/backend/__tests__/__migration__/testActivity.spec.ts
@@ -2,6 +2,7 @@ import * as Migration from "../../__migration__/testActivity";
import * as UserTestData from "../__testData__/users";
import * as UserDal from "../../src/dal/user";
import * as ResultDal from "../../src/dal/result";
+import { DBResult } from "../../src/utils/result";
describe("testActivity migration", () => {
it("migrates users without results", async () => {
@@ -69,5 +70,5 @@ async function createResult(uid: string, timestamp: number): Promise<void> {
keyConsistency: 0,
chartData: "toolong",
name: "",
- } as unknown as ResultDal.DBResult);
+ } as unknown as DBResult);
}
diff --git a/backend/__tests__/__testData__/auth.ts b/backend/__tests__/__testData__/auth.ts
index a1c0f94de..bd836d580 100644
--- a/backend/__tests__/__testData__/auth.ts
+++ b/backend/__tests__/__testData__/auth.ts
@@ -16,7 +16,7 @@ export async function mockAuthenticateWithApeKey(
const apiKey = randomBytes(apeKeyBytes).toString("base64url");
const saltyHash = await hash(apiKey, apeKeySaltRounds);
- const apeKey: MonkeyTypes.ApeKeyDB = {
+ const apeKey: ApeKeyDal.DBApeKey = {
_id: new ObjectId(),
name: "bob",
enabled: true,
diff --git a/backend/__tests__/__testData__/users.ts b/backend/__tests__/__testData__/users.ts
index 21156d902..26c27b5b6 100644
--- a/backend/__tests__/__testData__/users.ts
+++ b/backend/__tests__/__testData__/users.ts
@@ -3,8 +3,8 @@ import * as UserDAL from "../../src/dal/user";
import { ObjectId } from "mongodb";
export async function createUser(
- user?: Partial<MonkeyTypes.DBUser>
-): Promise<MonkeyTypes.DBUser> {
+ user?: Partial<UserDAL.DBUser>
+): Promise<UserDAL.DBUser> {
const uid = new ObjectId().toHexString();
await UserDAL.addUser("user" + uid, uid + "@example.com", uid);
await DB.collection("users").updateOne({ uid }, { $set: { ...user } });
@@ -12,8 +12,8 @@ export async function createUser(
}
export async function createUserWithoutMigration(
- user?: Partial<MonkeyTypes.DBUser>
-): Promise<MonkeyTypes.DBUser> {
+ user?: Partial<UserDAL.DBUser>
+): Promise<UserDAL.DBUser> {
const uid = new ObjectId().toHexString();
await UserDAL.addUser("user" + uid, uid + "@example.com", uid);
await DB.collection("users").updateOne({ uid }, { $set: { ...user } });
diff --git a/backend/__tests__/api/controllers/admin.spec.ts b/backend/__tests__/api/controllers/admin.spec.ts
index 7c362506f..dfe81861e 100644
--- a/backend/__tests__/api/controllers/admin.spec.ts
+++ b/backend/__tests__/api/controllers/admin.spec.ts
@@ -207,11 +207,11 @@ describe("AdminController", () => {
const reportOne = {
id: "1",
reason: "one",
- } as any as MonkeyTypes.Report;
+ } as any as ReportDal.DBReport;
const reportTwo = {
id: "2",
reason: "two",
- } as any as MonkeyTypes.Report;
+ } as any as ReportDal.DBReport;
getReportsMock.mockResolvedValue([reportOne, reportTwo]);
//WHEN
@@ -321,11 +321,11 @@ describe("AdminController", () => {
const reportOne = {
id: "1",
reason: "one",
- } as any as MonkeyTypes.Report;
+ } as any as ReportDal.DBReport;
const reportTwo = {
id: "2",
reason: "two",
- } as any as MonkeyTypes.Report;
+ } as any as ReportDal.DBReport;
getReportsMock.mockResolvedValue([reportOne, reportTwo]);
//WHEN
diff --git a/backend/__tests__/api/controllers/ape-key.spec.ts b/backend/__tests__/api/controllers/ape-key.spec.ts
index 6061a4e99..7c05fbf2b 100644
--- a/backend/__tests__/api/controllers/ape-key.spec.ts
+++ b/backend/__tests__/api/controllers/ape-key.spec.ts
@@ -337,8 +337,8 @@ describe("ApeKeyController", () => {
function apeKeyDb(
uid: string,
- data?: Partial<MonkeyTypes.ApeKeyDB>
-): MonkeyTypes.ApeKeyDB {
+ data?: Partial<ApeKeyDal.DBApeKey>
+): ApeKeyDal.DBApeKey {
return {
_id: new ObjectId(),
uid,
@@ -363,12 +363,9 @@ async function enableApeKeysEndpoints(enabled: boolean): Promise<void> {
);
}
-function user(
- uid: string,
- data: Partial<MonkeyTypes.DBUser>
-): MonkeyTypes.DBUser {
+function user(uid: string, data: Partial<UserDal.DBUser>): UserDal.DBUser {
return {
uid,
...data,
- } as MonkeyTypes.DBUser;
+ } as UserDal.DBUser;
}
diff --git a/backend/__tests__/api/controllers/result.spec.ts b/backend/__tests__/api/controllers/result.spec.ts
index 07981f614..bffa1e538 100644
--- a/backend/__tests__/api/controllers/result.spec.ts
+++ b/backend/__tests__/api/controllers/result.spec.ts
@@ -10,6 +10,7 @@ import { DecodedIdToken } from "firebase-admin/lib/auth/token-verifier";
import { ObjectId } from "mongodb";
import { mockAuthenticateWithApeKey } from "../../__testData__/auth";
import { enableRateLimitExpects } from "../../__testData__/rate-limit";
+import { DBResult } from "../../../src/utils/result";
const uid = "123456";
const mockDecodedToken: DecodedIdToken = {
@@ -830,10 +831,7 @@ async function enablePremiumFeatures(premium: boolean): Promise<void> {
mockConfig
);
}
-function givenDbResult(
- uid: string,
- customize?: Partial<MonkeyTypes.DBResult>
-): MonkeyTypes.DBResult {
+function givenDbResult(uid: string, customize?: Partial<DBResult>): DBResult {
return {
_id: new ObjectId(),
wpm: Math.random() * 100,
diff --git a/backend/__tests__/api/controllers/user.spec.ts b/backend/__tests__/api/controllers/user.spec.ts
index 4e9cc9730..746d8696f 100644
--- a/backend/__tests__/api/controllers/user.spec.ts
+++ b/backend/__tests__/api/controllers/user.spec.ts
@@ -484,7 +484,7 @@ describe("user controller test", () => {
//given
getUserMock.mockResolvedValue({
testActivity: { "2023": [1, 2, 3], "2024": [4, 5, 6] },
- } as Partial<MonkeyTypes.DBUser> as MonkeyTypes.DBUser);
+ } as Partial<UserDal.DBUser> as UserDal.DBUser);
//when
await mockApp
@@ -497,7 +497,7 @@ describe("user controller test", () => {
//given
getUserMock.mockResolvedValue({
testActivity: { "2023": [1, 2, 3], "2024": [4, 5, 6] },
- } as Partial<MonkeyTypes.DBUser> as MonkeyTypes.DBUser);
+ } as Partial<UserDal.DBUser> as UserDal.DBUser);
vi.spyOn(UserDal, "checkIfUserIsPremium").mockResolvedValue(true);
await enablePremiumFeatures(true);
@@ -633,7 +633,7 @@ describe("user controller test", () => {
email: "email",
discordId: "discordId",
banned: true,
- } as Partial<MonkeyTypes.DBUser> as MonkeyTypes.DBUser;
+ } as Partial<UserDal.DBUser> as UserDal.DBUser;
await getUserMock.mockResolvedValue(user);
//WHEN
@@ -664,7 +664,7 @@ describe("user controller test", () => {
name: "name",
email: "email",
discordId: "discordId",
- } as Partial<MonkeyTypes.DBUser> as MonkeyTypes.DBUser;
+ } as Partial<UserDal.DBUser> as UserDal.DBUser;
getUserMock.mockResolvedValue(user);
//WHEN
@@ -1555,7 +1555,7 @@ describe("user controller test", () => {
uid,
name: "name",
email: "email",
- } as Partial<MonkeyTypes.DBUser> as MonkeyTypes.DBUser;
+ } as Partial<UserDal.DBUser> as UserDal.DBUser;
getUserMock.mockResolvedValue(user);
blocklistContainsMock.mockResolvedValue(true);
@@ -2061,12 +2061,12 @@ describe("user controller test", () => {
it("should get tags", async () => {
//GIVEN
- const tagOne: MonkeyTypes.DBUserTag = {
+ const tagOne: UserDal.DBUserTag = {
_id: new ObjectId(),
name: "tagOne",
personalBests: {} as any,
};
- const tagTwo: MonkeyTypes.DBUserTag = {
+ const tagTwo: UserDal.DBUserTag = {
_id: new ObjectId(),
name: "tagOne",
personalBests: {} as any,
@@ -2171,12 +2171,12 @@ describe("user controller test", () => {
});
it("should get custom themes", async () => {
//GIVEN
- const themeOne: MonkeyTypes.DBCustomTheme = {
+ const themeOne: UserDal.DBCustomTheme = {
_id: new ObjectId(),
name: "themeOne",
colors: new Array(10).fill("#000000") as any,
};
- const themeTwo: MonkeyTypes.DBCustomTheme = {
+ const themeTwo: UserDal.DBCustomTheme = {
_id: new ObjectId(),
name: "themeTwo",
colors: new Array(10).fill("#FFFFFF") as any,
@@ -2207,7 +2207,7 @@ describe("user controller test", () => {
it("should add ", async () => {
//GIVEN
- const addedTheme: MonkeyTypes.DBCustomTheme = {
+ const addedTheme: UserDal.DBCustomTheme = {
_id: new ObjectId(),
name: "custom",
colors: new Array(10).fill("#000000") as any,
@@ -2501,7 +2501,7 @@ describe("user controller test", () => {
it("should get stats", async () => {
//GIVEN
const stats: Pick<
- MonkeyTypes.DBUser,
+ UserDal.DBUser,
"startedTests" | "completedTests" | "timeTyping"
> = {
startedTests: 5,
@@ -2672,7 +2672,7 @@ describe("user controller test", () => {
const checkIfUserIsPremiumMock = vi.spyOn(UserDal, "checkIfUserIsPremium");
const leaderboardGetRankMock = vi.spyOn(LeaderboardDal, "getRank");
- const foundUser: Partial<MonkeyTypes.DBUser> = {
+ const foundUser: Partial<UserDal.DBUser> = {
_id: new ObjectId(),
uid: new ObjectId().toHexString(),
name: "bob",
@@ -3548,7 +3548,7 @@ describe("user controller test", () => {
testActivity: {
"2024": fillYearWithDay(94),
},
- } as Partial<MonkeyTypes.DBUser> as MonkeyTypes.DBUser;
+ } as Partial<UserDal.DBUser> as UserDal.DBUser;
getUserMock.mockResolvedValue(user);
//WHEN
@@ -3584,7 +3584,7 @@ describe("user controller test", () => {
maxLength: 1024,
hourOffset: 2,
},
- } as Partial<MonkeyTypes.DBUser> as MonkeyTypes.DBUser;
+ } as Partial<UserDal.DBUser> as UserDal.DBUser;
getUserMock.mockResolvedValue(user);
//WHEN
diff --git a/backend/__tests__/dal/leaderboards.spec.ts b/backend/__tests__/dal/leaderboards.spec.ts
index 1c3925b3a..160625049 100644
--- a/backend/__tests__/dal/leaderboards.spec.ts
+++ b/backend/__tests__/dal/leaderboards.spec.ts
@@ -9,6 +9,7 @@ import type { PersonalBest } from "@monkeytype/contracts/schemas/shared";
const configuration = Configuration.getCachedConfiguration();
import * as DB from "../../src/init/db";
+import { LbPersonalBests } from "../../src/utils/pb";
describe("LeaderboardsDal", () => {
describe("update", () => {
@@ -289,14 +290,14 @@ function expectedLbEntry(
}
async function createUser(
- lbPersonalBests?: MonkeyTypes.LbPersonalBests,
- userProperties?: Partial<MonkeyTypes.DBUser>
-): Promise<MonkeyTypes.DBUser> {
+ lbPersonalBests?: LbPersonalBests,
+ userProperties?: Partial<UserDal.DBUser>
+): Promise<UserDal.DBUser> {
const uid = new ObjectId().toHexString();
await UserDal.addUser("User " + uid, uid + "@example.com", uid);
await DB.getDb()
- ?.collection<MonkeyTypes.DBUser>("users")
+ ?.collection<UserDal.DBUser>("users")
.updateOne(
{ uid },
{
@@ -313,11 +314,8 @@ async function createUser(
return await UserDal.getUser(uid, "test");
}
-function lbBests(
- pb15?: PersonalBest,
- pb60?: PersonalBest
-): MonkeyTypes.LbPersonalBests {
- const result: MonkeyTypes.LbPersonalBests = { time: {} };
+function lbBests(pb15?: PersonalBest, pb60?: PersonalBest): LbPersonalBests {
+ const result: LbPersonalBests = { time: {} };
if (pb15) result.time["15"] = { english: pb15 };
if (pb60) result.time["60"] = { english: pb60 };
return result;
@@ -355,7 +353,7 @@ function premium(expirationDeltaSeconds: number) {
interface ExpectedLbEntry {
rank: number;
- user: MonkeyTypes.DBUser;
+ user: UserDal.DBUser;
badgeId?: number;
isPremium?: boolean;
}
diff --git a/backend/__tests__/dal/result.spec.ts b/backend/__tests__/dal/result.spec.ts
index e37d16f43..a16eab6f4 100644
--- a/backend/__tests__/dal/result.spec.ts
+++ b/backend/__tests__/dal/result.spec.ts
@@ -1,6 +1,7 @@
import * as ResultDal from "../../src/dal/result";
import { ObjectId } from "mongodb";
import * as UserDal from "../../src/dal/user";
+import { DBResult } from "../../src/utils/result";
let uid: string = "";
const timestamp = Date.now() - 60000;
@@ -11,7 +12,7 @@ async function createDummyData(
timestamp: number,
tag?: string
): Promise<void> {
- const dummyUser: MonkeyTypes.DBUser = {
+ const dummyUser: UserDal.DBUser = {
_id: new ObjectId(),
uid,
addedAt: 0,
@@ -56,7 +57,7 @@ async function createDummyData(
language: "english",
isPb: false,
name: "Test",
- } as MonkeyTypes.DBResult);
+ } as DBResult);
}
}
describe("ResultDal", () => {
diff --git a/backend/__tests__/dal/user.spec.ts b/backend/__tests__/dal/user.spec.ts
index e8feb2de1..6df733608 100644
--- a/backend/__tests__/dal/user.spec.ts
+++ b/backend/__tests__/dal/user.spec.ts
@@ -493,7 +493,7 @@ describe("UserDal", () => {
it("should fail if tag not found", async () => {
// given
- const tagOne: MonkeyTypes.DBUserTag = {
+ const tagOne: UserDAL.DBUserTag = {
_id: new ObjectId(),
name: "one",
personalBests: {} as any,
@@ -510,7 +510,7 @@ describe("UserDal", () => {
it("editTag success", async () => {
// given
- const tagOne: MonkeyTypes.DBUserTag = {
+ const tagOne: UserDAL.DBUserTag = {
_id: new ObjectId(),
name: "one",
personalBests: {} as any,
@@ -540,7 +540,7 @@ describe("UserDal", () => {
it("should return error if tag is unknown", async () => {
// given
- const tagOne: MonkeyTypes.DBUserTag = {
+ const tagOne: UserDAL.DBUserTag = {
_id: new ObjectId(),
name: "one",
personalBests: {} as any,
@@ -594,7 +594,7 @@ describe("UserDal", () => {
it("should return error if tag is unknown", async () => {
// given
- const tagOne: MonkeyTypes.DBUserTag = {
+ const tagOne: UserDAL.DBUserTag = {
_id: new ObjectId(),
name: "one",
personalBests: {} as any,
diff --git a/backend/__tests__/middlewares/auth.spec.ts b/backend/__tests__/middlewares/auth.spec.ts
index 5c52f41f5..654f7bba5 100644
--- a/backend/__tests__/middlewares/auth.spec.ts
+++ b/backend/__tests__/middlewares/auth.spec.ts
@@ -14,6 +14,7 @@ import {
RequestAuthenticationOptions,
} from "@monkeytype/contracts/schemas/api";
import * as Prometheus from "../../src/utils/prometheus";
+import { TsRestRequestWithContext } from "../../src/api/types";
const mockDecodedToken: DecodedIdToken = {
uid: "123456789",
@@ -37,7 +38,7 @@ const mockApeKey = {
vi.spyOn(ApeKeys, "getApeKey").mockResolvedValue(mockApeKey);
vi.spyOn(ApeKeys, "updateLastUsedOn").mockResolvedValue();
const isDevModeMock = vi.spyOn(Misc, "isDevEnvironment");
-let mockRequest: Partial<Auth.TsRestRequestWithCtx>;
+let mockRequest: Partial<TsRestRequestWithContext>;
let mockResponse: Partial<Response>;
let nextFunction: NextFunction;
@@ -553,7 +554,7 @@ describe("middlewares/auth", () => {
async function authenticate(
request: Partial<Request>,
authenticationOptions?: RequestAuthenticationOptions
-): Promise<{ decodedToken: MonkeyTypes.DecodedToken }> {
+): Promise<{ decodedToken: Auth.DecodedToken }> {
const mergedRequest = {
...mockRequest,
...request,
diff --git a/backend/__tests__/middlewares/configuration.spec.ts b/backend/__tests__/middlewares/configuration.spec.ts
index 733235a51..8a63c601b 100644
--- a/backend/__tests__/middlewares/configuration.spec.ts
+++ b/backend/__tests__/middlewares/configuration.spec.ts
@@ -3,6 +3,7 @@ import { verifyRequiredConfiguration } from "../../src/middlewares/configuration
import { Configuration } from "@monkeytype/contracts/schemas/configuration";
import { Response } from "express";
import MonkeyError from "../../src/utils/error";
+import { TsRestRequest } from "../../src/api/types";
describe("configuration middleware", () => {
const handler = verifyRequiredConfiguration();
diff --git a/backend/__tests__/middlewares/permission.spec.ts b/backend/__tests__/middlewares/permission.spec.ts
index 19146ba2d..b87c14f13 100644
--- a/backend/__tests__/middlewares/permission.spec.ts
+++ b/backend/__tests__/middlewares/permission.spec.ts
@@ -5,6 +5,8 @@ import * as Misc from "../../src/utils/misc";
import * as AdminUids from "../../src/dal/admin-uids";
import * as UserDal from "../../src/dal/user";
import MonkeyError from "../../src/utils/error";
+import { DecodedToken } from "../../src/middlewares/auth";
+import { TsRestRequest } from "../../src/api/types";
const uid = "123456789";
@@ -311,7 +313,7 @@ describe("permission middleware", () => {
function givenRequest(
metadata: EndpointMetadata,
- decodedToken?: Partial<MonkeyTypes.DecodedToken>
+ decodedToken?: Partial<DecodedToken>
): TsRestRequest {
return { tsRestRoute: { metadata }, ctx: { decodedToken } } as any;
}
diff --git a/backend/__tests__/tsconfig.json b/backend/__tests__/tsconfig.json
index 001f654f4..44bc60c8f 100644
--- a/backend/__tests__/tsconfig.json
+++ b/backend/__tests__/tsconfig.json
@@ -7,6 +7,6 @@
"ts-node": {
"files": true
},
- "files": ["../src/types/types.d.ts", "vitest.d.ts"],
+ "files": ["vitest.d.ts"],
"include": ["./**/*.ts", "./**/*.spec.ts", "./setup-tests.ts"]
}
diff --git a/backend/__tests__/utils/daily-leaderboards.spec.ts b/backend/__tests__/utils/daily-leaderboards.spec.ts
index ad65e6b9c..041ef06af 100644
--- a/backend/__tests__/utils/daily-leaderboards.spec.ts
+++ b/backend/__tests__/utils/daily-leaderboards.spec.ts
@@ -1,3 +1,4 @@
+import { Mode } from "@monkeytype/contracts/schemas/shared";
import { getDailyLeaderboard } from "../../src/utils/daily-leaderboards";
const dailyLeaderboardsConfig = {
@@ -77,7 +78,7 @@ describe("Daily Leaderboards", () => {
modeCases.forEach(({ case: { language, mode, mode2 }, expected }) => {
const result = getDailyLeaderboard(
language,
- mode,
+ mode as Mode,
mode2,
dailyLeaderboardsConfig
);
diff --git a/backend/__tests__/utils/pb.spec.ts b/backend/__tests__/utils/pb.spec.ts
index 79c80693d..5fe1366f8 100644
--- a/backend/__tests__/utils/pb.spec.ts
+++ b/backend/__tests__/utils/pb.spec.ts
@@ -59,7 +59,7 @@ describe("Pb Utils", () => {
const run = pb.checkAndUpdatePb(
userPbs,
- {} as MonkeyTypes.LbPersonalBests,
+ {} as pb.LbPersonalBests,
result
);
@@ -168,7 +168,7 @@ describe("Pb Utils", () => {
for (const lbPb of lbpbstartingvalues) {
const lbPbPb = pb.updateLeaderboardPersonalBests(
userPbs,
- _.cloneDeep(lbPb) as MonkeyTypes.LbPersonalBests,
+ _.cloneDeep(lbPb) as pb.LbPersonalBests,
result15
);
diff --git a/backend/src/api/controllers/admin.ts b/backend/src/api/controllers/admin.ts
index 518c50e05..1ae73486a 100644
--- a/backend/src/api/controllers/admin.ts
+++ b/backend/src/api/controllers/admin.ts
@@ -14,13 +14,14 @@ import {
import MonkeyError, { getErrorMessage } from "../../utils/error";
import { Configuration } from "@monkeytype/contracts/schemas/configuration";
import { addImportantLog } from "../../dal/logs";
+import { MonkeyRequest } from "../types";
-export async function test(_req: MonkeyTypes.Request): Promise<MonkeyResponse> {
+export async function test(_req: MonkeyRequest): Promise<MonkeyResponse> {
return new MonkeyResponse("OK", null);
}
export async function toggleBan(
- req: MonkeyTypes.Request<undefined, ToggleBanRequest>
+ req: MonkeyRequest<undefined, ToggleBanRequest>
): Promise<ToggleBanResponse> {
const { uid } = req.body;
@@ -42,7 +43,7 @@ export async function toggleBan(
}
export async function acceptReports(
- req: MonkeyTypes.Request<undefined, AcceptReportsRequest>
+ req: MonkeyRequest<undefined, AcceptReportsRequest>
): Promise<MonkeyResponse> {
await handleReports(
req.body.reports.map((it) => ({ ...it })),
@@ -53,7 +54,7 @@ export async function acceptReports(
}
export async function rejectReports(
- req: MonkeyTypes.Request<undefined, RejectReportsRequest>
+ req: MonkeyRequest<undefined, RejectReportsRequest>
): Promise<MonkeyResponse> {
await handleReports(
req.body.reports.map((it) => ({ ...it })),
@@ -127,7 +128,7 @@ export async function handleReports(
}
export async function sendForgotPasswordEmail(
- req: MonkeyTypes.Request<undefined, SendForgotPasswordEmailRequest>
+ req: MonkeyRequest<undefined, SendForgotPasswordEmailRequest>
): Promise<MonkeyResponse> {
const { email } = req.body;
await authSendForgotPasswordEmail(email);
diff --git a/backend/src/api/controllers/ape-key.ts b/backend/src/api/controllers/ape-key.ts
index 755088df0..5ff616f34 100644
--- a/backend/src/api/controllers/ape-key.ts
+++ b/backend/src/api/controllers/ape-key.ts
@@ -15,13 +15,14 @@ import {
GetApeKeyResponse,
} from "@monkeytype/contracts/ape-keys";
import { ApeKey } from "@monkeytype/contracts/schemas/ape-keys";
+import { MonkeyRequest } from "../types";
-function cleanApeKey(apeKey: MonkeyTypes.ApeKeyDB): ApeKey {
+function cleanApeKey(apeKey: ApeKeysDAL.DBApeKey): ApeKey {
return _.omit(apeKey, "hash", "_id", "uid", "useCount");
}
export async function getApeKeys(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetApeKeyResponse> {
const { uid } = req.ctx.decodedToken;
@@ -32,7 +33,7 @@ export async function getApeKeys(
}
export async function generateApeKey(
- req: MonkeyTypes.Request<undefined, AddApeKeyRequest>
+ req: MonkeyRequest<undefined, AddApeKeyRequest>
): Promise<AddApeKeyResponse> {
const { name, enabled } = req.body;
const { uid } = req.ctx.decodedToken;
@@ -48,7 +49,7 @@ export async function generateApeKey(
const apiKey = randomBytes(apeKeyBytes).toString("base64url");
const saltyHash = await hash(apiKey, apeKeySaltRounds);
- const apeKey: MonkeyTypes.ApeKeyDB = {
+ const apeKey: ApeKeysDAL.DBApeKey = {
_id: new ObjectId(),
name,
enabled,
@@ -70,7 +71,7 @@ export async function generateApeKey(
}
export async function editApeKey(
- req: MonkeyTypes.Request<undefined, EditApeKeyRequest, ApeKeyParams>
+ req: MonkeyRequest<undefined, EditApeKeyRequest, ApeKeyParams>
): Promise<MonkeyResponse> {
const { apeKeyId } = req.params;
const { name, enabled } = req.body;
@@ -82,7 +83,7 @@ export async function editApeKey(
}
export async function deleteApeKey(
- req: MonkeyTypes.Request<undefined, undefined, ApeKeyParams>
+ req: MonkeyRequest<undefined, undefined, ApeKeyParams>
): Promise<MonkeyResponse> {
const { apeKeyId } = req.params;
const { uid } = req.ctx.decodedToken;
diff --git a/backend/src/api/controllers/config.ts b/backend/src/api/controllers/config.ts
index 39569ebd0..afd68c875 100644
--- a/backend/src/api/controllers/config.ts
+++ b/backend/src/api/controllers/config.ts
@@ -2,9 +2,10 @@ import { PartialConfig } from "@monkeytype/contracts/schemas/configs";
import * as ConfigDAL from "../../dal/config";
import { MonkeyResponse } from "../../utils/monkey-response";
import { GetConfigResponse } from "@monkeytype/contracts/configs";
+import { MonkeyRequest } from "../types";
export async function getConfig(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetConfigResponse> {
const { uid } = req.ctx.decodedToken;
const data = (await ConfigDAL.getConfig(uid))?.config ?? null;
@@ -13,7 +14,7 @@ export async function getConfig(
}
export async function saveConfig(
- req: MonkeyTypes.Request<undefined, PartialConfig>
+ req: MonkeyRequest<undefined, PartialConfig>
): Promise<MonkeyResponse> {
const config = req.body;
const { uid } = req.ctx.decodedToken;
@@ -24,7 +25,7 @@ export async function saveConfig(
}
export async function deleteConfig(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
diff --git a/backend/src/api/controllers/configuration.ts b/backend/src/api/controllers/configuration.ts
index 35d172897..46978d597 100644
--- a/backend/src/api/controllers/configuration.ts
+++ b/backend/src/api/controllers/configuration.ts
@@ -7,16 +7,17 @@ import {
PatchConfigurationRequest,
} from "@monkeytype/contracts/configuration";
import MonkeyError from "../../utils/error";
+import { MonkeyRequest } from "../types";
export async function getConfiguration(
- _req: MonkeyTypes.Request
+ _req: MonkeyRequest
): Promise<GetConfigurationResponse> {
const currentConfiguration = await Configuration.getLiveConfiguration();
return new MonkeyResponse("Configuration retrieved", currentConfiguration);
}
export async function getSchema(
- _req: MonkeyTypes.Request
+ _req: MonkeyRequest
): Promise<ConfigurationSchemaResponse> {
return new MonkeyResponse(
"Configuration schema retrieved",
@@ -25,7 +26,7 @@ export async function getSchema(
}
export async function updateConfiguration(
- req: MonkeyTypes.Request<undefined, PatchConfigurationRequest>
+ req: MonkeyRequest<undefined, PatchConfigurationRequest>
): Promise<MonkeyResponse> {
const { configuration } = req.body;
const success = await Configuration.patchConfiguration(configuration);
diff --git a/backend/src/api/controllers/dev.ts b/backend/src/api/controllers/dev.ts
index 2b4eff576..26aa7d6b9 100644
--- a/backend/src/api/controllers/dev.ts
+++ b/backend/src/api/controllers/dev.ts
@@ -19,6 +19,9 @@ import {
GenerateDataResponse,
} from "@monkeytype/contracts/dev";
import { roundTo2 } from "@monkeytype/util/numbers";
+import { MonkeyRequest } from "../types";
+import { DBResult } from "../../utils/result";
+import { LbPersonalBests } from "../../utils/pb";
const CREATE_RESULT_DEFAULT_OPTIONS = {
firstTestTimestamp: DateUtils.startOfDay(new UTCDate(Date.now())).valueOf(),
@@ -28,7 +31,7 @@ const CREATE_RESULT_DEFAULT_OPTIONS = {
};
export async function createTestData(
- req: MonkeyTypes.Request<undefined, GenerateDataRequest>
+ req: MonkeyRequest<undefined, GenerateDataRequest>
): Promise<GenerateDataResponse> {
const { username, createUser } = req.body;
const user = await getOrCreateUser(username, "password", createUser);
@@ -46,7 +49,7 @@ async function getOrCreateUser(
username: string,
password: string,
createUser = false
-): Promise<MonkeyTypes.DBUser> {
+): Promise<UserDal.DBUser> {
const existingUser = await UserDal.findByName(username);
if (existingUser !== undefined && existingUser !== null) {
@@ -69,7 +72,7 @@ async function getOrCreateUser(
}
async function createTestResults(
- user: MonkeyTypes.DBUser,
+ user: UserDal.DBUser,
configOptions: GenerateDataRequest
): Promise<void> {
const config = {
@@ -110,9 +113,9 @@ function random(min: number, max: number): number {
}
function createResult(
- user: MonkeyTypes.DBUser,
+ user: UserDal.DBUser,
timestamp: Date //evil, we modify this value
-): MonkeyTypes.DBResult {
+): DBResult {
const mode: Mode = randomValue(["time", "words"]);
const mode2: number =
mode === "time"
@@ -187,7 +190,7 @@ async function updateUser(uid: string): Promise<void> {
);
//update PBs
- const lbPersonalBests: MonkeyTypes.LbPersonalBests = {
+ const lbPersonalBests: LbPersonalBests = {
time: {
15: {},
60: {},
@@ -222,7 +225,7 @@ async function updateUser(uid: string): Promise<void> {
.sort({ wpm: -1, timestamp: 1 })
.limit(1)
.toArray()
- )[0] as MonkeyTypes.DBResult;
+ )[0] as DBResult;
if (personalBests[mode.mode] === undefined) personalBests[mode.mode] = {};
if (personalBests[mode.mode][mode.mode2] === undefined)
diff --git a/backend/src/api/controllers/leaderboard.ts b/backend/src/api/controllers/leaderboard.ts
index 720af4784..129004ed8 100644
--- a/backend/src/api/controllers/leaderboard.ts
+++ b/backend/src/api/controllers/leaderboard.ts
@@ -22,9 +22,10 @@ import {
getCurrentWeekTimestamp,
MILLISECONDS_IN_DAY,
} from "@monkeytype/util/date-and-time";
+import { MonkeyRequest } from "../types";
export async function getLeaderboard(
- req: MonkeyTypes.Request<GetLeaderboardQuery>
+ req: MonkeyRequest<GetLeaderboardQuery>
): Promise<GetLeaderboardResponse> {
const { language, mode, mode2, skip = 0, limit = 50 } = req.query;
@@ -49,7 +50,7 @@ export async function getLeaderboard(
}
export async function getRankFromLeaderboard(
- req: MonkeyTypes.Request<LanguageAndModeQuery>
+ req: MonkeyRequest<LanguageAndModeQuery>
): Promise<GetLeaderboardRankResponse> {
const { language, mode, mode2 } = req.query;
const { uid } = req.ctx.decodedToken;
@@ -89,7 +90,7 @@ function getDailyLeaderboardWithError(
}
export async function getDailyLeaderboard(
- req: MonkeyTypes.Request<GetDailyLeaderboardQuery>
+ req: MonkeyRequest<GetDailyLeaderboardQuery>
): Promise<GetLeaderboardResponse> {
const { skip = 0, limit = 50 } = req.query;
@@ -112,7 +113,7 @@ export async function getDailyLeaderboard(
}
export async function getDailyLeaderboardRank(
- req: MonkeyTypes.Request<GetDailyLeaderboardRankQuery>
+ req: MonkeyRequest<GetDailyLeaderboardRankQuery>
): Promise<GetLeaderboardDailyRankResponse> {
const { uid } = req.ctx.decodedToken;
@@ -147,7 +148,7 @@ function getWeeklyXpLeaderboardWithError(
}
export async function getWeeklyXpLeaderboardResults(
- req: MonkeyTypes.Request<GetWeeklyXpLeaderboardQuery>
+ req: MonkeyRequest<GetWeeklyXpLeaderboardQuery>
): Promise<GetWeeklyXpLeaderboardResponse> {
const { skip = 0, limit = 50 } = req.query;
@@ -168,7 +169,7 @@ export async function getWeeklyXpLeaderboardResults(
}
export async function getWeeklyXpLeaderboardRank(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetWeeklyXpLeaderboardRankResponse> {
const { uid } = req.ctx.decodedToken;
diff --git a/backend/src/api/controllers/preset.ts b/backend/src/api/controllers/preset.ts
index 2cf15715a..361acdd7c 100644
--- a/backend/src/api/controllers/preset.ts
+++ b/backend/src/api/controllers/preset.ts
@@ -8,9 +8,10 @@ import * as PresetDAL from "../../dal/preset";
import { MonkeyResponse } from "../../utils/monkey-response";
import { replaceObjectId } from "../../utils/misc";
import { EditPresetRequest } from "@monkeytype/contracts/schemas/presets";
+import { MonkeyRequest } from "../types";
export async function getPresets(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetPresetResponse> {
const { uid } = req.ctx.decodedToken;
@@ -25,7 +26,7 @@ export async function getPresets(
}
export async function addPreset(
- req: MonkeyTypes.Request<undefined, AddPresetRequest>
+ req: MonkeyRequest<undefined, AddPresetRequest>
): Promise<AddPresetResponse> {
const { uid } = req.ctx.decodedToken;
@@ -35,7 +36,7 @@ export async function addPreset(
}
export async function editPreset(
- req: MonkeyTypes.Request<undefined, EditPresetRequest>
+ req: MonkeyRequest<undefined, EditPresetRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
@@ -45,7 +46,7 @@ export async function editPreset(
}
export async function removePreset(
- req: MonkeyTypes.Request<undefined, undefined, DeletePresetsParams>
+ req: MonkeyRequest<undefined, undefined, DeletePresetsParams>
): Promise<MonkeyResponse> {
const { presetId } = req.params;
const { uid } = req.ctx.decodedToken;
diff --git a/backend/src/api/controllers/psa.ts b/backend/src/api/controllers/psa.ts
index e70abb428..c5f561807 100644
--- a/backend/src/api/controllers/psa.ts
+++ b/backend/src/api/controllers/psa.ts
@@ -2,10 +2,9 @@ import { GetPsaResponse } from "@monkeytype/contracts/psas";
import * as PsaDAL from "../../dal/psa";
import { MonkeyResponse } from "../../utils/monkey-response";
import { replaceObjectIds } from "../../utils/misc";
+import { MonkeyRequest } from "../types";
-export async function getPsas(
- _req: MonkeyTypes.Request
-): Promise<GetPsaResponse> {
+export async function getPsas(_req: MonkeyRequest): Promise<GetPsaResponse> {
const data = await PsaDAL.get();
return new MonkeyResponse("PSAs retrieved", replaceObjectIds(data));
}
diff --git a/backend/src/api/controllers/public.ts b/backend/src/api/controllers/public.ts
index 64ae2d384..093cffb6d 100644
--- a/backend/src/api/controllers/public.ts
+++ b/backend/src/api/controllers/public.ts
@@ -5,9 +5,10 @@ import {
} from "@monkeytype/contracts/public";
import * as PublicDAL from "../../dal/public";
import { MonkeyResponse } from "../../utils/monkey-response";
+import { MonkeyRequest } from "../types";
export async function getSpeedHistogram(
- req: MonkeyTypes.Request<GetSpeedHistogramQuery>
+ req: MonkeyRequest<GetSpeedHistogramQuery>
): Promise<GetSpeedHistogramResponse> {
const { language, mode, mode2 } = req.query;
const data = await PublicDAL.getSpeedHistogram(language, mode, mode2);
@@ -15,7 +16,7 @@ export async function getSpeedHistogram(
}
export async function getTypingStats(
- _req: MonkeyTypes.Request
+ _req: MonkeyRequest
): Promise<GetTypingStatsResponse> {
const data = await PublicDAL.getTypingStats();
return new MonkeyResponse("Public typing stats retrieved", data);
diff --git a/backend/src/api/controllers/quote.ts b/backend/src/api/controllers/quote.ts
index 103b8f6fe..ae8981a97 100644
--- a/backend/src/api/controllers/quote.ts
+++ b/backend/src/api/controllers/quote.ts
@@ -22,6 +22,7 @@ import {
ReportQuoteRequest,
} from "@monkeytype/contracts/quotes";
import { replaceObjectId, replaceObjectIds } from "../../utils/misc";
+import { MonkeyRequest } from "../types";
async function verifyCaptcha(captcha: string): Promise<void> {
if (!(await verify(captcha))) {
@@ -30,7 +31,7 @@ async function verifyCaptcha(captcha: string): Promise<void> {
}
export async function getQuotes(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetQuotesResponse> {
const { uid } = req.ctx.decodedToken;
const quoteMod = (await getPartialUser(uid, "get quotes", ["quoteMod"]))
@@ -45,7 +46,7 @@ export async function getQuotes(
}
export async function isSubmissionEnabled(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<IsSubmissionEnabledResponse> {
const { submissionsEnabled } = req.ctx.configuration.quotes;
return new MonkeyResponse(
@@ -55,7 +56,7 @@ export async function isSubmissionEnabled(
}
export async function addQuote(
- req: MonkeyTypes.Request<undefined, AddQuoteRequest>
+ req: MonkeyRequest<undefined, AddQuoteRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { text, source, language, captcha } = req.body;
@@ -67,7 +68,7 @@ export async function addQuote(
}
export async function approveQuote(
- req: MonkeyTypes.Request<undefined, ApproveQuoteRequest>
+ req: MonkeyRequest<undefined, ApproveQuoteRequest>
): Promise<ApproveQuoteResponse> {
const { uid } = req.ctx.decodedToken;
const { quoteId, editText, editSource } = req.body;
@@ -85,7 +86,7 @@ export async function approveQuote(
}
export async function refuseQuote(
- req: MonkeyTypes.Request<undefined, RejectQuoteRequest>
+ req: MonkeyRequest<undefined, RejectQuoteRequest>
): Promise<MonkeyResponse> {
const { quoteId } = req.body;
@@ -94,7 +95,7 @@ export async function refuseQuote(
}
export async function getRating(
- req: MonkeyTypes.Request<GetQuoteRatingQuery>
+ req: MonkeyRequest<GetQuoteRatingQuery>
): Promise<GetQuoteRatingResponse> {
const { quoteId, language } = req.query;
@@ -104,7 +105,7 @@ export async function getRating(
}
export async function submitRating(
- req: MonkeyTypes.Request<undefined, AddQuoteRatingRequest>
+ req: MonkeyRequest<undefined, AddQuoteRatingRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { quoteId, rating, language } = req.body;
@@ -135,7 +136,7 @@ export async function submitRating(
}
export async function reportQuote(
- req: MonkeyTypes.Request<undefined, ReportQuoteRequest>
+ req: MonkeyRequest<undefined, ReportQuoteRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const {
@@ -146,7 +147,7 @@ export async function reportQuote(
await verifyCaptcha(captcha);
- const newReport: MonkeyTypes.Report = {
+ const newReport: ReportDAL.DBReport = {
_id: new ObjectId(),
id: uuidv4(),
type: "quote",
diff --git a/backend/src/api/controllers/result.ts b/backend/src/api/controllers/result.ts
index 27ef99465..0dc5d5ec0 100644
--- a/backend/src/api/controllers/result.ts
+++ b/backend/src/api/controllers/result.ts
@@ -27,7 +27,11 @@ import _, { omit } from "lodash";
import * as WeeklyXpLeaderboard from "../../services/weekly-xp-leaderboard";
import { UAParser } from "ua-parser-js";
import { canFunboxGetPb } from "../../utils/pb";
-import { buildDbResult, replaceLegacyValues } from "../../utils/result";
+import {
+ buildDbResult,
+ DBResult,
+ replaceLegacyValues,
+} from "../../utils/result";
import { Configuration } from "@monkeytype/contracts/schemas/configuration";
import { addLog } from "../../dal/logs";
import {
@@ -52,6 +56,7 @@ import {
getCurrentDayTimestamp,
getStartOfDayTimestamp,
} from "@monkeytype/util/date-and-time";
+import { MonkeyRequest } from "../types";
try {
if (!anticheatImplemented()) throw new Error("undefined");
@@ -70,7 +75,7 @@ try {
}
export async function getResults(
- req: MonkeyTypes.Request<GetResultsQuery>
+ req: MonkeyRequest<GetResultsQuery>
): Promise<GetResultsResponse> {
const { uid } = req.ctx.decodedToken;
const premiumFeaturesEnabled = req.ctx.configuration.users.premium.enabled;
@@ -123,16 +128,14 @@ export async function getResults(
}
export async function getLastResult(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetLastResultResponse> {
const { uid } = req.ctx.decodedToken;
const results = await ResultDAL.getLastResult(uid);
return new MonkeyResponse("Result retrieved", convertResult(results));
}
-export async function deleteAll(
- req: MonkeyTypes.Request
-): Promise<MonkeyResponse> {
+export async function deleteAll(req: MonkeyRequest): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
await ResultDAL.deleteAll(uid);
@@ -141,7 +144,7 @@ export async function deleteAll(
}
export async function updateTags(
- req: MonkeyTypes.Request<undefined, UpdateResultTagsRequest>
+ req: MonkeyRequest<undefined, UpdateResultTagsRequest>
): Promise<UpdateResultTagsResponse> {
const { uid } = req.ctx.decodedToken;
const { tagIds, resultId } = req.body;
@@ -176,7 +179,7 @@ export async function updateTags(
}
export async function addResult(
- req: MonkeyTypes.Request<undefined, AddResultRequest>
+ req: MonkeyRequest<undefined, AddResultRequest>
): Promise<AddResultResponse> {
const { uid } = req.ctx.decodedToken;
@@ -799,6 +802,6 @@ async function calculateXp(
};
}
-function convertResult(db: MonkeyTypes.DBResult): Result<Mode> {
+function convertResult(db: DBResult): Result<Mode> {
return replaceObjectId(replaceLegacyValues(db));
}
diff --git a/backend/src/api/controllers/user.ts b/backend/src/api/controllers/user.ts
index 2b7c78517..755ec52fe 100644
--- a/backend/src/api/controllers/user.ts
+++ b/backend/src/api/controllers/user.ts
@@ -86,6 +86,7 @@ import {
UpdateUserProfileResponse,
} from "@monkeytype/contracts/users";
import { MILLISECONDS_IN_DAY } from "@monkeytype/util/date-and-time";
+import { MonkeyRequest } from "../types";
async function verifyCaptcha(captcha: string): Promise<void> {
let verified = false;
@@ -104,7 +105,7 @@ async function verifyCaptcha(captcha: string): Promise<void> {
}
export async function createNewUser(
- req: MonkeyTypes.Request<undefined, CreateUserRequest>
+ req: MonkeyRequest<undefined, CreateUserRequest>
): Promise<MonkeyResponse> {
const { name, captcha } = req.body;
const { email, uid } = req.ctx.decodedToken;
@@ -138,7 +139,7 @@ export async function createNewUser(
}
export async function sendVerificationEmail(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<MonkeyResponse> {
const { email, uid } = req.ctx.decodedToken;
const isVerified = (
@@ -235,7 +236,7 @@ export async function sendVerificationEmail(
}
export async function sendForgotPasswordEmail(
- req: MonkeyTypes.Request<undefined, ForgotPasswordEmailRequest>
+ req: MonkeyRequest<undefined, ForgotPasswordEmailRequest>
): Promise<MonkeyResponse> {
const { email } = req.body;
await authSendForgotPasswordEmail(email);
@@ -245,9 +246,7 @@ export async function sendForgotPasswordEmail(
);
}
-export async function deleteUser(
- req: MonkeyTypes.Request
-): Promise<MonkeyResponse> {
+export async function deleteUser(req: MonkeyRequest): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const userInfo = await UserDAL.getPartialUser(uid, "delete user", [
@@ -287,9 +286,7 @@ export async function deleteUser(
return new MonkeyResponse("User deleted", null);
}
-export async function resetUser(
- req: MonkeyTypes.Request
-): Promise<MonkeyResponse> {
+export async function resetUser(req: MonkeyRequest): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const userInfo = await UserDAL.getPartialUser(uid, "reset user", [
@@ -324,7 +321,7 @@ export async function resetUser(
}
export async function updateName(
- req: MonkeyTypes.Request<undefined, UpdateUserNameRequest>
+ req: MonkeyRequest<undefined, UpdateUserNameRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { name } = req.body;
@@ -357,9 +354,7 @@ export async function updateName(
return new MonkeyResponse("User's name updated", null);
}
-export async function clearPb(
- req: MonkeyTypes.Request
-): Promise<MonkeyResponse> {
+export async function clearPb(req: MonkeyRequest): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
await UserDAL.clearPb(uid);
@@ -373,7 +368,7 @@ export async function clearPb(
}
export async function optOutOfLeaderboards(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
@@ -388,7 +383,7 @@ export async function optOutOfLeaderboards(
}
export async function checkName(
- req: MonkeyTypes.Request<undefined, undefined, CheckNamePathParameters>
+ req: MonkeyRequest<undefined, undefined, CheckNamePathParameters>
): Promise<MonkeyResponse> {
const { name } = req.params;
const { uid } = req.ctx.decodedToken;
@@ -402,7 +397,7 @@ export async function checkName(
}
export async function updateEmail(
- req: MonkeyTypes.Request<undefined, UpdateEmailRequestSchema>
+ req: MonkeyRequest<undefined, UpdateEmailRequestSchema>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
let { newEmail } = req.body;
@@ -448,7 +443,7 @@ export async function updateEmail(
}
export async function updatePassword(
- req: MonkeyTypes.Request<undefined, UpdatePasswordRequest>
+ req: MonkeyRequest<undefined, UpdatePasswordRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { newPassword } = req.body;
@@ -459,7 +454,7 @@ export async function updatePassword(
}
type RelevantUserInfo = Omit<
- MonkeyTypes.DBUser,
+ UserDAL.DBUser,
| "bananas"
| "lbPersonalBests"
| "inbox"
@@ -472,7 +467,7 @@ type RelevantUserInfo = Omit<
| "testActivity"
>;
-function getRelevantUserInfo(user: MonkeyTypes.DBUser): RelevantUserInfo {
+function getRelevantUserInfo(user: UserDAL.DBUser): RelevantUserInfo {
return _.omit(user, [
"bananas",
"lbPersonalBests",
@@ -487,12 +482,10 @@ function getRelevantUserInfo(user: MonkeyTypes.DBUser): RelevantUserInfo {
]) as RelevantUserInfo;
}
-export async function getUser(
- req: MonkeyTypes.Request
-): Promise<GetUserResponse> {
+export async function getUser(req: MonkeyRequest): Promise<GetUserResponse> {
const { uid } = req.ctx.decodedToken;
- let userInfo: MonkeyTypes.DBUser;
+ let userInfo: UserDAL.DBUser;
try {
userInfo = await UserDAL.getUser(uid, "get user");
} catch (e) {
@@ -535,7 +528,7 @@ export async function getUser(
custom: {},
};
- const agentLog = buildAgentLog(req.raw);
+ const agentLog = buildAgentLog(req);
void addLog("user_data_requested", agentLog, uid);
void UserDAL.logIpAddress(uid, agentLog.ip, userInfo);
@@ -585,7 +578,7 @@ export async function getUser(
}
export async function getOauthLink(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetDiscordOauthLinkResponse> {
const { uid } = req.ctx.decodedToken;
@@ -599,7 +592,7 @@ export async function getOauthLink(
}
export async function linkDiscord(
- req: MonkeyTypes.Request<undefined, LinkDiscordRequest>
+ req: MonkeyRequest<undefined, LinkDiscordRequest>
): Promise<LinkDiscordResponse> {
const { uid } = req.ctx.decodedToken;
const { tokenType, accessToken, state } = req.body;
@@ -659,7 +652,7 @@ export async function linkDiscord(
}
export async function unlinkDiscord(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
@@ -685,7 +678,7 @@ export async function unlinkDiscord(
}
export async function addResultFilterPreset(
- req: MonkeyTypes.Request<undefined, AddResultFilterPresetRequest>
+ req: MonkeyRequest<undefined, AddResultFilterPresetRequest>
): Promise<AddResultFilterPresetResponse> {
const { uid } = req.ctx.decodedToken;
const filter = req.body;
@@ -703,11 +696,7 @@ export async function addResultFilterPreset(
}
export async function removeResultFilterPreset(
- req: MonkeyTypes.Request<
- undefined,
- undefined,
- RemoveResultFilterPresetPathParams
- >
+ req: MonkeyRequest<undefined, undefined, RemoveResultFilterPresetPathParams>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { presetId } = req.params;
@@ -717,7 +706,7 @@ export async function removeResultFilterPreset(
}
export async function addTag(
- req: MonkeyTypes.Request<undefined, AddTagRequest>
+ req: MonkeyRequest<undefined, AddTagRequest>
): Promise<AddTagResponse> {
const { uid } = req.ctx.decodedToken;
const { tagName } = req.body;
@@ -727,7 +716,7 @@ export async function addTag(
}
export async function clearTagPb(
- req: MonkeyTypes.Request<undefined, undefined, TagIdPathParams>
+ req: MonkeyRequest<undefined, undefined, TagIdPathParams>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { tagId } = req.params;
@@ -737,7 +726,7 @@ export async function clearTagPb(
}
export async function editTag(
- req: MonkeyTypes.Request<undefined, EditTagRequest>
+ req: MonkeyRequest<undefined, EditTagRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { tagId, newName } = req.body;
@@ -747,7 +736,7 @@ export async function editTag(
}
export async function removeTag(
- req: MonkeyTypes.Request<undefined, undefined, TagIdPathParams>
+ req: MonkeyRequest<undefined, undefined, TagIdPathParams>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { tagId } = req.params;
@@ -756,9 +745,7 @@ export async function removeTag(
return new MonkeyResponse("Tag deleted", null);
}
-export async function getTags(
- req: MonkeyTypes.Request
-): Promise<GetTagsResponse> {
+export async function getTags(req: MonkeyRequest): Promise<GetTagsResponse> {
const { uid } = req.ctx.decodedToken;
const tags = await UserDAL.getTags(uid);
@@ -766,7 +753,7 @@ export async function getTags(
}
export async function updateLbMemory(
- req: MonkeyTypes.Request<undefined, UpdateLeaderboardMemoryRequest>
+ req: MonkeyRequest<undefined, UpdateLeaderboardMemoryRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { mode, language, rank } = req.body;
@@ -777,7 +764,7 @@ export async function updateLbMemory(
}
export async function getCustomThemes(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetCustomThemesResponse> {
const { uid } = req.ctx.decodedToken;
const customThemes = await UserDAL.getThemes(uid);
@@ -788,7 +775,7 @@ export async function getCustomThemes(
}
export async function addCustomTheme(
- req: MonkeyTypes.Request<undefined, AddCustomThemeRequest>
+ req: MonkeyRequest<undefined, AddCustomThemeRequest>
): Promise<AddCustomThemeResponse> {
const { uid } = req.ctx.decodedToken;
const { name, colors } = req.body;
@@ -798,7 +785,7 @@ export async function addCustomTheme(
}
export async function removeCustomTheme(
- req: MonkeyTypes.Request<undefined, DeleteCustomThemeRequest>
+ req: MonkeyRequest<undefined, DeleteCustomThemeRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { themeId } = req.body;
@@ -807,7 +794,7 @@ export async function removeCustomTheme(
}
export async function editCustomTheme(
- req: MonkeyTypes.Request<undefined, EditCustomThemeRequst>
+ req: MonkeyRequest<undefined, EditCustomThemeRequst>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { themeId, theme } = req.body;
@@ -817,7 +804,7 @@ export async function editCustomTheme(
}
export async function getPersonalBests(
- req: MonkeyTypes.Request<GetPersonalBestsQuery>
+ req: MonkeyRequest<GetPersonalBestsQuery>
): Promise<GetPersonalBestsResponse> {
const { uid } = req.ctx.decodedToken;
const { mode, mode2 } = req.query;
@@ -826,9 +813,7 @@ export async function getPersonalBests(
return new MonkeyResponse("Personal bests retrieved", data);
}
-export async function getStats(
- req: MonkeyTypes.Request
-): Promise<GetStatsResponse> {
+export async function getStats(req: MonkeyRequest): Promise<GetStatsResponse> {
const { uid } = req.ctx.decodedToken;
const data = (await UserDAL.getStats(uid)) ?? null;
@@ -836,7 +821,7 @@ export async function getStats(
}
export async function getFavoriteQuotes(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetFavoriteQuotesResponse> {
const { uid } = req.ctx.decodedToken;
@@ -846,7 +831,7 @@ export async function getFavoriteQuotes(
}
export async function addFavoriteQuote(
- req: MonkeyTypes.Request<undefined, AddFavoriteQuoteRequest>
+ req: MonkeyRequest<undefined, AddFavoriteQuoteRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
@@ -863,7 +848,7 @@ export async function addFavoriteQuote(
}
export async function removeFavoriteQuote(
- req: MonkeyTypes.Request<undefined, RemoveFavoriteQuoteRequest>
+ req: MonkeyRequest<undefined, RemoveFavoriteQuoteRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
@@ -874,7 +859,7 @@ export async function removeFavoriteQuote(
}
export async function getProfile(
- req: MonkeyTypes.Request<GetProfileQuery, undefined, GetProfilePathParams>
+ req: MonkeyRequest<GetProfileQuery, undefined, GetProfilePathParams>
): Promise<GetProfileResponse> {
const { uidOrName } = req.params;
@@ -946,7 +931,7 @@ export async function getProfile(
}
export async function updateProfile(
- req: MonkeyTypes.Request<undefined, UpdateUserProfileRequest>
+ req: MonkeyRequest<undefined, UpdateUserProfileRequest>
): Promise<UpdateUserProfileResponse> {
const { uid } = req.ctx.decodedToken;
const { bio, keyboard, socialProfiles, selectedBadgeId } = req.body;
@@ -983,7 +968,7 @@ export async function updateProfile(
}
export async function getInbox(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetUserInboxResponse> {
const { uid } = req.ctx.decodedToken;
@@ -996,7 +981,7 @@ export async function getInbox(
}
export async function updateInbox(
- req: MonkeyTypes.Request<undefined, UpdateUserInboxRequest>
+ req: MonkeyRequest<undefined, UpdateUserInboxRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { mailIdsToMarkRead, mailIdsToDelete } = req.body;
@@ -1011,7 +996,7 @@ export async function updateInbox(
}
export async function reportUser(
- req: MonkeyTypes.Request<undefined, ReportUserRequest>
+ req: MonkeyRequest<undefined, ReportUserRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const {
@@ -1022,7 +1007,7 @@ export async function reportUser(
await verifyCaptcha(captcha);
- const newReport: MonkeyTypes.Report = {
+ const newReport: ReportDAL.DBReport = {
_id: new ObjectId(),
id: uuidv4(),
type: "user",
@@ -1039,7 +1024,7 @@ export async function reportUser(
}
export async function setStreakHourOffset(
- req: MonkeyTypes.Request<undefined, SetStreakHourOffsetRequest>
+ req: MonkeyRequest<undefined, SetStreakHourOffsetRequest>
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
const { hourOffset } = req.body;
@@ -1063,7 +1048,7 @@ export async function setStreakHourOffset(
}
export async function revokeAllTokens(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<MonkeyResponse> {
const { uid } = req.ctx.decodedToken;
await AuthUtil.revokeTokensByUid(uid);
@@ -1151,7 +1136,7 @@ export function generateCurrentTestActivity(
}
export async function getTestActivity(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetTestActivityResponse> {
const { uid } = req.ctx.decodedToken;
const premiumFeaturesEnabled = req.ctx.configuration.users.premium.enabled;
@@ -1184,7 +1169,7 @@ async function firebaseDeleteUserIgnoreError(uid: string): Promise<void> {
}
export async function getCurrentTestActivity(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetCurrentTestActivityResponse> {
const { uid } = req.ctx.decodedToken;
@@ -1199,7 +1184,7 @@ export async function getCurrentTestActivity(
}
export async function getStreak(
- req: MonkeyTypes.Request
+ req: MonkeyRequest
): Promise<GetStreakResponseSchema> {
const { uid } = req.ctx.decodedToken;
diff --git a/backend/src/api/controllers/webhooks.ts b/backend/src/api/controllers/webhooks.ts
index f6f7525b4..702ff2621 100644
--- a/backend/src/api/controllers/webhooks.ts
+++ b/backend/src/api/controllers/webhooks.ts
@@ -2,9 +2,10 @@ import { PostGithubReleaseRequest } from "@monkeytype/contracts/webhooks";
import GeorgeQueue from "../../queues/george-queue";
import { MonkeyResponse } from "../../utils/monkey-response";
import MonkeyError from "../../utils/error";
+import { MonkeyRequest } from "../types";
export async function githubRelease(
- req: MonkeyTypes.Request<undefined, PostGithubReleaseRequest>
+ req: MonkeyRequest<undefined, PostGithubReleaseRequest>
): Promise<MonkeyResponse> {
const action = req.body.action;
diff --git a/backend/src/api/routes/index.ts b/backend/src/api/routes/index.ts
index a11d9b092..91d061fd8 100644
--- a/backend/src/api/routes/index.ts
+++ b/backend/src/api/routes/index.ts
@@ -36,6 +36,7 @@ import { authenticateTsRestRequest } from "../../middlewares/auth";
import { rateLimitRequest } from "../../middlewares/rate-limit";
import { verifyPermissions } from "../../middlewares/permission";
import { verifyRequiredConfiguration } from "../../middlewares/configuration";
+import { ExpressRequestWithContext } from "../types";
const pathOverride = process.env["API_PATH_OVERRIDE"];
const BASE_ROUTE = pathOverride !== undefined ? `/${pathOverride}` : "";
@@ -156,7 +157,7 @@ function applyApiRoutes(app: Application): void {
app.use(
(
- req: MonkeyTypes.ExpressRequestWithContext,
+ req: ExpressRequestWithContext,
res: Response,
next: NextFunction
): void => {
diff --git a/backend/src/api/ts-rest-adapter.ts b/backend/src/api/ts-rest-adapter.ts
index a48313473..587fad99c 100644
--- a/backend/src/api/ts-rest-adapter.ts
+++ b/backend/src/api/ts-rest-adapter.ts
@@ -1,6 +1,9 @@
import { AppRoute, AppRouter } from "@ts-rest/core";
import { TsRestRequest } from "@ts-rest/express";
import { MonkeyResponse } from "../utils/monkey-response";
+import { Context } from "../middlewares/context";
+import { MonkeyRequest } from "./types";
+
export function callController<
TRoute extends AppRoute | AppRouter,
TQuery,
@@ -11,18 +14,18 @@ export function callController<
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
TStatus = 200
>(
- handler: Handler<TQuery, TBody, TParams, TResponse>
-): (all: RequestType2<TRoute, TQuery, TBody, TParams>) => Promise<{
+ handler: MonkeyHandler<TQuery, TBody, TParams, TResponse>
+): (all: TypeSafeTsRestRequest<TRoute, TQuery, TBody, TParams>) => Promise<{
status: TStatus;
- body: { message: string; data: TResponse };
+ body: MonkeyResponse<TResponse>;
}> {
return async (all) => {
- const req: MonkeyTypes.Request<TQuery, TBody, TParams> = {
+ const req: MonkeyRequest<TQuery, TBody, TParams> = {
body: all.body as TBody,
query: all.query as TQuery,
params: all.params as TParams,
raw: all.req,
- ctx: all.req["ctx"] as MonkeyTypes.Context,
+ ctx: all.req["ctx"] as Context,
};
const result = await handler(req);
@@ -59,11 +62,11 @@ type WithoutParams = {
params?: never;
};
-type Handler<TQuery, TBody, TParams, TResponse> = (
- req: MonkeyTypes.Request<TQuery, TBody, TParams>
+type MonkeyHandler<TQuery, TBody, TParams, TResponse> = (
+ req: MonkeyRequest<TQuery, TBody, TParams>
) => Promise<MonkeyResponse<TResponse>>;
-type RequestType2<
+type TypeSafeTsRestRequest<
TRoute extends AppRoute | AppRouter,
TQuery,
TBody,
diff --git a/backend/src/api/types.ts b/backend/src/api/types.ts
new file mode 100644
index 000000000..ec84f5950
--- /dev/null
+++ b/backend/src/api/types.ts
@@ -0,0 +1,27 @@
+import { TsRestRequest as TsRestRequestGeneric } from "@ts-rest/express";
+import { Request as ExpressRequest } from "express";
+import { Context } from "../middlewares/context";
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type TsRestRequest = TsRestRequestGeneric<any>;
+
+export type ExpressRequestWithContext = {
+ ctx: Readonly<Context>;
+} & ExpressRequest;
+
+export type TsRestRequestWithContext = {
+ ctx: Readonly<Context>;
+} & TsRestRequest &
+ ExpressRequest;
+
+export type MonkeyRequest<
+ TQuery = undefined,
+ TBody = undefined,
+ TParams = undefined
+> = {
+ query: Readonly<TQuery>;
+ body: Readonly<TBody>;
+ params: Readonly<TParams>;
+ ctx: Readonly<Context>;
+ raw: Readonly<TsRestRequest>;
+};
diff --git a/backend/src/constants/funbox-list.ts b/backend/src/constants/funbox-list.ts
index 07b003b5a..61b88a139 100644
--- a/backend/src/constants/funbox-list.ts
+++ b/backend/src/constants/funbox-list.ts
@@ -1,4 +1,13 @@
-const FunboxList: MonkeyTypes.FunboxMetadata[] = [
+export type FunboxMetadata = {
+ name: string;
+ canGetPb: boolean;
+ difficultyLevel: number;
+ properties?: string[];
+ frontendForcedConfig?: Record<string, string[] | boolean[]>;
+ frontendFunctions?: string[];
+};
+
+const FunboxList: FunboxMetadata[] = [
{
canGetPb: false,
difficultyLevel: 1,
diff --git a/backend/src/dal/ape-keys.ts b/backend/src/dal/ape-keys.ts
index 16a03a60a..2cf9ce8a3 100644
--- a/backend/src/dal/ape-keys.ts
+++ b/backend/src/dal/ape-keys.ts
@@ -8,28 +8,30 @@ import {
Collection,
} from "mongodb";
import MonkeyError from "../utils/error";
+import { ApeKey } from "@monkeytype/contracts/schemas/ape-keys";
-export const getApeKeysCollection = (): Collection<
- WithId<MonkeyTypes.ApeKeyDB>
-> => db.collection<MonkeyTypes.ApeKeyDB>("ape-keys");
+export type DBApeKey = ApeKey & {
+ _id: ObjectId;
+ uid: string;
+ hash: string;
+ useCount: number;
+};
-function getApeKeyFilter(
- uid: string,
- keyId: string
-): Filter<MonkeyTypes.ApeKeyDB> {
+export const getApeKeysCollection = (): Collection<WithId<DBApeKey>> =>
+ db.collection<DBApeKey>("ape-keys");
+
+function getApeKeyFilter(uid: string, keyId: string): Filter<DBApeKey> {
return {
_id: new ObjectId(keyId),
uid,
};
}
-export async function getApeKeys(uid: string): Promise<MonkeyTypes.ApeKeyDB[]> {
+export async function getApeKeys(uid: string): Promise<DBApeKey[]> {
return await getApeKeysCollection().find({ uid }).toArray();
}
-export async function getApeKey(
- keyId: string
-): Promise<MonkeyTypes.ApeKeyDB | null> {
+export async function getApeKey(keyId: string): Promise<DBApeKey | null> {
return await getApeKeysCollection().findOne({ _id: new ObjectId(keyId) });
}
@@ -37,7 +39,7 @@ export async function countApeKeysForUser(uid: string): Promise<number> {
return getApeKeysCollection().countDocuments({ uid });
}
-export async function addApeKey(apeKey: MonkeyTypes.ApeKeyDB): Promise<string> {
+export async function addApeKey(apeKey: DBApeKey): Promise<string> {
const insertionResult = await getApeKeysCollection().insertOne(apeKey);
return insertionResult.insertedId.toHexString();
}
@@ -45,7 +47,7 @@ export async function addApeKey(apeKey: MonkeyTypes.ApeKeyDB): Promise<string> {
async function updateApeKey(
uid: string,
keyId: string,
- updates: MatchKeysAndValues<MonkeyTypes.ApeKeyDB>
+ updates: MatchKeysAndValues<DBApeKey>
): Promise<void> {
const updateResult = await getApeKeysCollection().updateOne(
getApeKeyFilter(uid, keyId),
diff --git a/backend/src/dal/blocklist.ts b/backend/src/dal/blocklist.ts
index c6992fe27..5c0cf9c0d 100644
--- a/backend/src/dal/blocklist.ts
+++ b/backend/src/dal/blocklist.ts
@@ -2,10 +2,22 @@ import { Collection } from "mongodb";
import * as db from "../init/db";
import { createHash } from "crypto";
import { User } from "@monkeytype/contracts/schemas/users";
+import { WithObjectId } from "../utils/misc";
type BlocklistEntryProperties = Pick<User, "name" | "email" | "discordId">;
+
+type BlocklistEntry = {
+ _id: string;
+ usernameHash?: string;
+ emailHash?: string;
+ discordIdHash?: string;
+ timestamp: number;
+};
+
+type DBBlocklistEntry = WithObjectId<BlocklistEntry>;
+
// Export for use in tests
-export const getCollection = (): Collection<MonkeyTypes.DBBlocklistEntry> =>
+export const getCollection = (): Collection<DBBlocklistEntry> =>
db.collection("blocklist");
export async function add(user: BlocklistEntryProperties): Promise<void> {
@@ -75,8 +87,8 @@ export function hash(value: string): string {
function getFilter(
user: Partial<BlocklistEntryProperties>
-): Partial<MonkeyTypes.DBBlocklistEntry>[] {
- const filter: Partial<MonkeyTypes.DBBlocklistEntry>[] = [];
+): Partial<DBBlocklistEntry>[] {
+ const filter: Partial<DBBlocklistEntry>[] = [];
if (user.email !== undefined) {
filter.push({ emailHash: hash(user.email) });
}
diff --git a/backend/src/dal/config.ts b/backend/src/dal/config.ts
index 67cd2abc4..a11b32fe5 100644
--- a/backend/src/dal/config.ts
+++ b/backend/src/dal/config.ts
@@ -1,4 +1,4 @@
-import { Collection, UpdateResult } from "mongodb";
+import { Collection, ObjectId, UpdateResult } from "mongodb";
import * as db from "../init/db";
import _ from "lodash";
import { Config, PartialConfig } from "@monkeytype/contracts/schemas/configs";
diff --git a/backend/src/dal/leaderboards.ts b/backend/src/dal/leaderboards.ts
index 9f833ca38..6d1f98118 100644
--- a/backend/src/dal/leaderboards.ts
+++ b/backend/src/dal/leaderboards.ts
@@ -6,12 +6,13 @@ import { isDevEnvironment } from "../utils/misc";
import { getCachedConfiguration } from "../init/configuration";
import { addLog } from "./logs";
-import { Collection } from "mongodb";
+import { Collection, ObjectId } from "mongodb";
import {
LeaderboardEntry,
LeaderboardRank,
} from "@monkeytype/contracts/schemas/leaderboards";
import { omit } from "lodash";
+import { DBUser } from "./user";
export type DBLeaderboardEntry = LeaderboardEntry & {
_id: ObjectId;
@@ -104,77 +105,75 @@ export async function update(
}> {
const key = `lbPersonalBests.${mode}.${mode2}.${language}`;
const lbCollectionName = `leaderboards.${language}.${mode}.${mode2}`;
- const lb = db
- .collection<MonkeyTypes.DBUser>("users")
- .aggregate<LeaderboardEntry>(
- [
- {
- $match: {
- [`${key}.wpm`]: {
- $gt: 0,
- },
- [`${key}.acc`]: {
- $gt: 0,
- },
- [`${key}.timestamp`]: {
- $gt: 0,
- },
- banned: {
- $ne: true,
- },
- lbOptOut: {
- $ne: true,
- },
- needsToChangeName: {
- $ne: true,
- },
- timeTyping: {
- $gt: isDevEnvironment() ? 0 : 7200,
- },
+ const lb = db.collection<DBUser>("users").aggregate<LeaderboardEntry>(
+ [
+ {
+ $match: {
+ [`${key}.wpm`]: {
+ $gt: 0,
},
- },
- {
- $sort: {
- [`${key}.wpm`]: -1,
- [`${key}.acc`]: -1,
- [`${key}.timestamp`]: -1,
+ [`${key}.acc`]: {
+ $gt: 0,
},
- },
- {
- $project: {
- _id: 0,
- [`${key}.wpm`]: 1,
- [`${key}.acc`]: 1,
- [`${key}.raw`]: 1,
- [`${key}.consistency`]: 1,
- [`${key}.timestamp`]: 1,
- uid: 1,
- name: 1,
- discordId: 1,
- discordAvatar: 1,
- inventory: 1,
- premium: 1,
+ [`${key}.timestamp`]: {
+ $gt: 0,
+ },
+ banned: {
+ $ne: true,
},
+ lbOptOut: {
+ $ne: true,
+ },
+ needsToChangeName: {
+ $ne: true,
+ },
+ timeTyping: {
+ $gt: isDevEnvironment() ? 0 : 7200,
+ },
+ },
+ },
+ {
+ $sort: {
+ [`${key}.wpm`]: -1,
+ [`${key}.acc`]: -1,
+ [`${key}.timestamp`]: -1,
+ },
+ },
+ {
+ $project: {
+ _id: 0,
+ [`${key}.wpm`]: 1,
+ [`${key}.acc`]: 1,
+ [`${key}.raw`]: 1,
+ [`${key}.consistency`]: 1,
+ [`${key}.timestamp`]: 1,
+ uid: 1,
+ name: 1,
+ discordId: 1,
+ discordAvatar: 1,
+ inventory: 1,
+ premium: 1,
},
+ },
- {
- $addFields: {
- "user.uid": "$uid",
- "user.name": "$name",
- "user.discordId": { $ifNull: ["$discordId", "$$REMOVE"] },
- "user.discordAvatar": { $ifNull: ["$discordAvatar", "$$REMOVE"] },
- [`${key}.consistency`]: {
- $ifNull: [`$${key}.consistency`, "$$REMOVE"],
- },
- calculated: {
- $function: {
- lang: "js",
- args: [
- "$premium.expirationTimestamp",
- "$$NOW",
- "$inventory.badges",
- ],
- body: `function(expiration, currentTime, badges) {
+ {
+ $addFields: {
+ "user.uid": "$uid",
+ "user.name": "$name",
+ "user.discordId": { $ifNull: ["$discordId", "$$REMOVE"] },
+ "user.discordAvatar": { $ifNull: ["$discordAvatar", "$$REMOVE"] },
+ [`${key}.consistency`]: {
+ $ifNull: [`$${key}.consistency`, "$$REMOVE"],
+ },
+ calculated: {
+ $function: {
+ lang: "js",
+ args: [
+ "$premium.expirationTimestamp",
+ "$$NOW",
+ "$inventory.badges",
+ ],
+ body: `function(expiration, currentTime, badges) {
try {row_number+= 1;} catch (e) {row_number= 1;}
var badgeId = undefined;
if(badges)for(let i=0; i<badges.length; i++){
@@ -183,19 +182,19 @@ export async function update(
var isPremium = expiration !== undefined && (expiration === -1 || new Date(expiration)>currentTime) || undefined;
return {rank:row_number,badgeId, isPremium};
}`,
- },
},
},
},
- {
- $replaceWith: {
- $mergeObjects: [`$${key}`, "$user", "$calculated"],
- },
+ },
+ {
+ $replaceWith: {
+ $mergeObjects: [`$${key}`, "$user", "$calculated"],
},
- { $out: lbCollectionName },
- ],
- { allowDiskUse: true }
- );
+ },
+ { $out: lbCollectionName },
+ ],
+ { allowDiskUse: true }
+ );
const start1 = performance.now();
await lb.toArray();
diff --git a/backend/src/dal/new-quotes.ts b/backend/src/dal/new-quotes.ts
index 54e5f1117..9e4752ba2 100644
--- a/backend/src/dal/new-quotes.ts
+++ b/backend/src/dal/new-quotes.ts
@@ -7,6 +7,7 @@ import * as db from "../init/db";
import MonkeyError from "../utils/error";
import { compareTwoStrings } from "string-similarity";
import { ApproveQuote, Quote } from "@monkeytype/contracts/schemas/quotes";
+import { WithObjectId } from "../utils/misc";
type JsonQuote = {
text: string;
@@ -38,7 +39,7 @@ type AddQuoteReturn = {
similarityScore?: number;
};
-export type DBNewQuote = MonkeyTypes.WithObjectId<Quote>;
+export type DBNewQuote = WithObjectId<Quote>;
// Export for use in tests
export const getNewQuoteCollection = (): Collection<DBNewQuote> =>
diff --git a/backend/src/dal/preset.ts b/backend/src/dal/preset.ts
index 0a7d5a0ca..0ffb3075e 100644
--- a/backend/src/dal/preset.ts
+++ b/backend/src/dal/preset.ts
@@ -6,10 +6,11 @@ import {
Preset,
} from "@monkeytype/contracts/schemas/presets";
import { omit } from "lodash";
+import { WithObjectId } from "../utils/misc";
const MAX_PRESETS = 10;
-type DBConfigPreset = MonkeyTypes.WithObjectId<
+type DBConfigPreset = WithObjectId<
Preset & {
uid: string;
}
diff --git a/backend/src/dal/psa.ts b/backend/src/dal/psa.ts
index 904c30b8a..2f57bb2b0 100644
--- a/backend/src/dal/psa.ts
+++ b/backend/src/dal/psa.ts
@@ -1,7 +1,8 @@
import { PSA } from "@monkeytype/contracts/schemas/psas";
import * as db from "../init/db";
+import { WithObjectId } from "../utils/misc";
-export type DBPSA = MonkeyTypes.WithObjectId<PSA>;
+export type DBPSA = WithObjectId<PSA>;
export async function get(): Promise<DBPSA[]> {
return await db.collection<DBPSA>("psa").find().toArray();
diff --git a/backend/src/dal/quote-ratings.ts b/backend/src/dal/quote-ratings.ts
index 031582420..6046b5183 100644
--- a/backend/src/dal/quote-ratings.ts
+++ b/backend/src/dal/quote-ratings.ts
@@ -1,8 +1,9 @@
import { QuoteRating } from "@monkeytype/contracts/schemas/quotes";
import * as db from "../init/db";
import { Collection } from "mongodb";
+import { WithObjectId } from "../utils/misc";
-type DBQuoteRating = MonkeyTypes.WithObjectId<QuoteRating>;
+type DBQuoteRating = WithObjectId<QuoteRating>;
// Export for use in tests
export const getQuoteRatingCollection = (): Collection<DBQuoteRating> =>
diff --git a/backend/src/dal/report.ts b/backend/src/dal/report.ts
index 7f746019c..9f3b98332 100644
--- a/backend/src/dal/report.ts
+++ b/backend/src/dal/report.ts
@@ -1,16 +1,25 @@
import MonkeyError from "../utils/error";
import * as db from "../init/db";
+import { ObjectId } from "mongodb";
+
+type ReportTypes = "quote" | "user";
+
+export type DBReport = {
+ _id: ObjectId;
+ id: string;
+ type: ReportTypes;
+ timestamp: number;
+ uid: string;
+ contentId: string;
+ reason: string;
+ comment: string;
+};
const COLLECTION_NAME = "reports";
-export async function getReports(
- reportIds: string[]
-): Promise<MonkeyTypes.Report[]> {
+export async function getReports(reportIds: string[]): Promise<DBReport[]> {
const query = { id: { $in: reportIds } };
- return await db
- .collection<MonkeyTypes.Report>(COLLECTION_NAME)
- .find(query)
- .toArray();
+ return await db.collection<DBReport>(COLLECTION_NAME).find(query).toArray();
}
export async function deleteReports(reportIds: string[]): Promise<void> {
@@ -19,7 +28,7 @@ export async function deleteReports(reportIds: string[]): Promise<void> {
}
export async function createReport(
- report: MonkeyTypes.Report,
+ report: DBReport,
maxReports: number,
contentReportLimit: number
): Promise<void> {
@@ -28,7 +37,7 @@ export async function createReport(
}
const reportsCount = await db
- .collection<MonkeyTypes.Report>(COLLECTION_NAME)
+ .collection<DBReport>(COLLECTION_NAME)
.estimatedDocumentCount();
if (reportsCount >= maxReports) {
@@ -39,7 +48,7 @@ export async function createReport(
}
const sameReports = await db
- .collection<MonkeyTypes.Report>(COLLECTION_NAME)
+ .collection<DBReport>(COLLECTION_NAME)
.find({ contentId: report.contentId })
.toArray();
@@ -58,5 +67,5 @@ export async function createReport(
throw new MonkeyError(409, "You have already reported this content.");
}
- await db.collection<MonkeyTypes.Report>(COLLECTION_NAME).insertOne(report);
+ await db.collection<DBReport>(COLLECTION_NAME).insertOne(report);
}
diff --git a/backend/src/dal/result.ts b/backend/src/dal/result.ts
index dd1d80364..797829e38 100644
--- a/backend/src/dal/result.ts
+++ b/backend/src/dal/result.ts
@@ -8,16 +8,17 @@ import {
import MonkeyError from "../utils/error";
import * as db from "../init/db";
-import { getUser, getTags } from "./user";
+import { getUser, getTags, DBUser } from "./user";
+import { DBResult } from "../utils/result";
-export const getResultCollection = (): Collection<MonkeyTypes.DBResult> =>
- db.collection<MonkeyTypes.DBResult>("results");
+export const getResultCollection = (): Collection<DBResult> =>
+ db.collection<DBResult>("results");
export async function addResult(
uid: string,
- result: MonkeyTypes.DBResult
+ result: DBResult
): Promise<{ insertedId: ObjectId }> {
- let user: MonkeyTypes.DBUser | null = null;
+ let user: DBUser | null = null;
try {
user = await getUser(uid, "add result");
} catch (e) {
@@ -61,10 +62,7 @@ export async function updateTags(
);
}
-export async function getResult(
- uid: string,
- id: string
-): Promise<MonkeyTypes.DBResult> {
+export async function getResult(uid: string, id: string): Promise<DBResult> {
const result = await getResultCollection().findOne({
_id: new ObjectId(id),
uid,
@@ -73,9 +71,7 @@ export async function getResult(
return result;
}
-export async function getLastResult(
- uid: string
-): Promise<MonkeyTypes.DBResult> {
+export async function getLastResult(uid: string): Promise<DBResult> {
const [lastResult] = await getResultCollection()
.find({ uid })
.sort({ timestamp: -1 })
@@ -88,7 +84,7 @@ export async function getLastResult(
export async function getResultByTimestamp(
uid: string,
timestamp: number
-): Promise<MonkeyTypes.DBResult | null> {
+): Promise<DBResult | null> {
return await getResultCollection().findOne({ uid, timestamp });
}
@@ -101,7 +97,7 @@ type GetResultsOpts = {
export async function getResults(
uid: string,
opts?: GetResultsOpts
-): Promise<MonkeyTypes.DBResult[]> {
+): Promise<DBResult[]> {
const { onOrAfterTimestamp, offset, limit } = opts ?? {};
let query = getResultCollection()
.find({
diff --git a/backend/src/dal/user.ts b/backend/src/dal/user.ts
index da652c2cc..07f016355 100644
--- a/backend/src/dal/user.ts
+++ b/backend/src/dal/user.ts
@@ -1,5 +1,5 @@
import _ from "lodash";
-import { canFunboxGetPb, checkAndUpdatePb } from "../utils/pb";
+import { canFunboxGetPb, checkAndUpdatePb, LbPersonalBests } from "../utils/pb";
import * as db from "../init/db";
import MonkeyError from "../utils/error";
import {
@@ -9,7 +9,7 @@ import {
type UpdateFilter,
type Filter,
} from "mongodb";
-import { flattenObjectDeep } from "../utils/misc";
+import { flattenObjectDeep, WithObjectId } from "../utils/misc";
import { getCachedConfiguration } from "../init/configuration";
import { getDayOfYear } from "date-fns";
import { UTCDate } from "@date-fns/utc";
@@ -23,6 +23,9 @@ import {
UserQuoteRatings,
UserStreak,
ResultFilters,
+ UserTag,
+ User,
+ CountByYearAndDay,
} from "@monkeytype/contracts/schemas/users";
import {
Mode,
@@ -34,20 +37,46 @@ import { Result as ResultType } from "@monkeytype/contracts/schemas/results";
import { Configuration } from "@monkeytype/contracts/schemas/configuration";
import { isToday, isYesterday } from "@monkeytype/util/date-and-time";
+export type DBUserTag = WithObjectId<UserTag>;
+
+export type DBUser = Omit<
+ User,
+ | "resultFilterPresets"
+ | "tags"
+ | "customThemes"
+ | "isPremium"
+ | "allTimeLbs"
+ | "testActivity"
+> & {
+ _id: ObjectId;
+ resultFilterPresets?: WithObjectId<ResultFilters>[];
+ tags?: DBUserTag[];
+ lbPersonalBests?: LbPersonalBests;
+ customThemes?: WithObjectId<CustomTheme>[];
+ autoBanTimestamps?: number[];
+ inbox?: MonkeyMail[];
+ ips?: string[];
+ canReport?: boolean;
+ lastNameChange?: number;
+ canManageApeKeys?: boolean;
+ bananas?: number;
+ testActivity?: CountByYearAndDay;
+};
+
const SECONDS_PER_HOUR = 3600;
type Result = Omit<ResultType<Mode>, "_id" | "name">;
// Export for use in tests
-export const getUsersCollection = (): Collection<MonkeyTypes.DBUser> =>
- db.collection<MonkeyTypes.DBUser>("users");
+export const getUsersCollection = (): Collection<DBUser> =>
+ db.collection<DBUser>("users");
export async function addUser(
name: string,
email: string,
uid: string
): Promise<void> {
- const newUserDocument: Partial<MonkeyTypes.DBUser> = {
+ const newUserDocument: Partial<DBUser> = {
name,
email,
uid,
@@ -211,10 +240,7 @@ export async function updateEmail(
return true;
}
-export async function getUser(
- uid: string,
- stack: string
-): Promise<MonkeyTypes.DBUser> {
+export async function getUser(uid: string, stack: string): Promise<DBUser> {
const user = await getUsersCollection().findOne({ uid });
if (!user) throw new MonkeyError(404, "User not found", stack);
return user;
@@ -228,11 +254,11 @@ export async function getUser(
* @returns partial DBUser only containing requested fields
* @throws MonkeyError if user does not exist
*/
-export async function getPartialUser<K extends keyof MonkeyTypes.DBUser>(
+export async function getPartialUser<K extends keyof DBUser>(
uid: string,
stack: string,
fields: K[]
-): Promise<Pick<MonkeyTypes.DBUser, K>> {
+): Promise<Pick<DBUser, K>> {
const projection = new Map(fields.map((it) => [it, 1]));
const results = await getUsersCollection().findOne({ uid }, { projection });
if (results === null) throw new MonkeyError(404, "User not found", stack);
@@ -240,9 +266,7 @@ export async function getPartialUser<K extends keyof MonkeyTypes.DBUser>(
return results;
}
-export async function findByName(
- name: string
-): Promise<MonkeyTypes.DBUser | undefined> {
+export async function findByName(name: string): Promise<DBUser | undefined> {
return (
await getUsersCollection()
.find({ name })
@@ -265,7 +289,7 @@ export async function isNameAvailable(
export async function getUserByName(
name: string,
stack: string
-): Promise<MonkeyTypes.DBUser> {
+): Promise<DBUser> {
const user = await findByName(name);
if (!user) throw new MonkeyError(404, "User not found", stack);
return user;
@@ -328,10 +352,7 @@ export async function removeResultFilterPreset(
);
}
-export async function addTag(
- uid: string,
- name: string
-): Promise<MonkeyTypes.DBUserTag> {
+export async function addTag(uid: string, name: string): Promise<DBUserTag> {
const toPush = {
_id: new ObjectId(),
name,
@@ -357,7 +378,7 @@ export async function addTag(
return toPush;
}
-export async function getTags(uid: string): Promise<MonkeyTypes.DBUserTag[]> {
+export async function getTags(uid: string): Promise<DBUserTag[]> {
const user = await getPartialUser(uid, "get tags", ["tags"]);
return user.tags ?? [];
@@ -426,7 +447,7 @@ export async function updateLbMemory(
export async function checkIfPb(
uid: string,
- user: Pick<MonkeyTypes.DBUser, "personalBests" | "lbPersonalBests">,
+ user: Pick<DBUser, "personalBests" | "lbPersonalBests">,
result: Result
): Promise<boolean> {
const { mode } = result;
@@ -469,7 +490,7 @@ export async function checkIfPb(
export async function checkIfTagPb(
uid: string,
- user: Pick<MonkeyTypes.DBUser, "tags">,
+ user: Pick<DBUser, "tags">,
result: Result
): Promise<string[]> {
if (user.tags === undefined || user.tags.length === 0) {
@@ -484,7 +505,7 @@ export async function checkIfTagPb(
return [];
}
- const tagsToCheck: MonkeyTypes.DBUserTag[] = [];
+ const tagsToCheck: DBUserTag[] = [];
user.tags.forEach((userTag) => {
for (const resultTag of resultTags ?? []) {
if (resultTag === userTag._id.toHexString()) {
@@ -571,7 +592,7 @@ export async function linkDiscord(
discordId: string,
discordAvatar?: string
): Promise<void> {
- const updates: Partial<MonkeyTypes.DBUser> = _.pickBy(
+ const updates: Partial<DBUser> = _.pickBy(
{ discordId, discordAvatar },
_.identity
);
@@ -632,7 +653,7 @@ export async function incrementXp(uid: string, xp: number): Promise<void> {
}
export async function incrementTestActivity(
- user: MonkeyTypes.DBUser,
+ user: DBUser,
timestamp: number
): Promise<void> {
if (user.testActivity === undefined) {
@@ -719,9 +740,9 @@ export async function editTheme(
);
}
-export async function getThemes(
- uid: string
-): Promise<MonkeyTypes.DBCustomTheme[]> {
+export type DBCustomTheme = WithObjectId<CustomTheme>;
+
+export async function getThemes(uid: string): Promise<DBCustomTheme[]> {
const user = await getPartialUser(uid, "get themes", ["customThemes"]);
return user.customThemes ?? [];
}
@@ -745,9 +766,7 @@ export async function getPersonalBests(
export async function getStats(
uid: string
-): Promise<
- Pick<MonkeyTypes.DBUser, "startedTests" | "completedTests" | "timeTyping">
-> {
+): Promise<Pick<DBUser, "startedTests" | "completedTests" | "timeTyping">> {
const user = await getPartialUser(uid, "get stats", [
"startedTests",
"completedTests",
@@ -759,7 +778,7 @@ export async function getStats(
export async function getFavoriteQuotes(
uid: string
-): Promise<NonNullable<MonkeyTypes.DBUser["favoriteQuotes"]>> {
+): Promise<NonNullable<DBUser["favoriteQuotes"]>> {
const user = await getPartialUser(uid, "get favorite quotes", [
"favoriteQuotes",
]);
@@ -843,7 +862,7 @@ export async function recordAutoBanEvent(
recentAutoBanTimestamps.push(now);
//update user, ban if needed
- const updateObj: Partial<MonkeyTypes.DBUser> = {
+ const updateObj: Partial<DBUser> = {
autoBanTimestamps: recentAutoBanTimestamps,
};
let banningUser = false;
@@ -891,7 +910,7 @@ export async function updateProfile(
export async function getInbox(
uid: string
-): Promise<NonNullable<MonkeyTypes.DBUser["inbox"]>> {
+): Promise<NonNullable<DBUser["inbox"]>> {
const user = await getPartialUser(uid, "get inbox", ["inbox"]);
return user.inbox ?? [];
}
@@ -981,7 +1000,7 @@ export async function updateInbox(
inventory: UserInventory,
deletedIds: string[],
readIds: string[]
- ): Pick<MonkeyTypes.DBUser, "xp" | "inventory" | "inbox"> {
+ ): Pick<DBUser, "xp" | "inventory" | "inbox"> {
const toBeDeleted = inbox.filter((it) =>
deletedIds.includes(it.id)
);
@@ -1121,7 +1140,7 @@ export async function setBanned(uid: string, banned: boolean): Promise<void> {
export async function checkIfUserIsPremium(
uid: string,
- userInfoOverride?: Pick<MonkeyTypes.DBUser, "premium">
+ userInfoOverride?: Pick<DBUser, "premium">
): Promise<boolean> {
const premiumFeaturesEnabled = (await getCachedConfiguration(true)).users
.premium.enabled;
@@ -1141,7 +1160,7 @@ export async function checkIfUserIsPremium(
export async function logIpAddress(
uid: string,
ip: string,
- userInfoOverride?: Pick<MonkeyTypes.DBUser, "ips">
+ userInfoOverride?: Pick<DBUser, "ips">
): Promise<void> {
const user =
userInfoOverride ?? (await getPartialUser(uid, "logIpAddress", ["ips"]));
@@ -1165,8 +1184,8 @@ export async function logIpAddress(
* @throws MonkeyError if user does not exist
*/
async function updateUser(
- filter: Filter<MonkeyTypes.DBUser>,
- update: UpdateFilter<MonkeyTypes.DBUser>,
+ filter: Filter<DBUser>,
+ update: UpdateFilter<DBUser>,
error: { stack: string; statusCode?: number; message?: string }
): Promise<void> {
const result = await getUsersCollection().updateOne(filter, update);
diff --git a/backend/src/middlewares/auth.ts b/backend/src/middlewares/auth.ts
index f42aa1bf9..0bd0028ee 100644
--- a/backend/src/middlewares/auth.ts
+++ b/backend/src/middlewares/auth.ts
@@ -19,7 +19,14 @@ import {
RequestAuthenticationOptions,
} from "@monkeytype/contracts/schemas/api";
import { Configuration } from "@monkeytype/contracts/schemas/configuration";
-import { getMetadata, TsRestRequestWithCtx } from "./utility";
+import { getMetadata } from "./utility";
+import { TsRestRequestWithContext } from "../api/types";
+
+export type DecodedToken = {
+ type: "Bearer" | "ApeKey" | "None" | "GithubWebhook";
+ uid: string;
+ email: string;
+};
const DEFAULT_OPTIONS: RequestAuthenticationOptions = {
isGithubWebhook: false,
@@ -38,7 +45,7 @@ export function authenticateTsRestRequest<
T extends AppRouter | AppRoute
>(): TsRestRequestHandler<T> {
return async (
- req: TsRestRequestWithCtx,
+ req: TsRestRequestWithContext,
_res: Response,
next: NextFunction
): Promise<void> => {
@@ -49,7 +56,7 @@ export function authenticateTsRestRequest<
};
const startTime = performance.now();
- let token: MonkeyTypes.DecodedToken;
+ let token: DecodedToken;
let authType = "None";
const isPublic =
@@ -126,7 +133,7 @@ async function authenticateWithAuthHeader(
authHeader: string,
configuration: Configuration,
options: RequestAuthenticationOptions
-): Promise<MonkeyTypes.DecodedToken> {
+): Promise<DecodedToken> {
const [authScheme, token] = authHeader.split(" ");
if (token === undefined) {
@@ -158,7 +165,7 @@ async function authenticateWithAuthHeader(
async function authenticateWithBearerToken(
token: string,
options: RequestAuthenticationOptions
-): Promise<MonkeyTypes.DecodedToken> {
+): Promise<DecodedToken> {
try {
const decodedToken = await verifyIdToken(
token,
@@ -221,7 +228,7 @@ async function authenticateWithApeKey(
key: string,
configuration: Configuration,
options: RequestAuthenticationOptions
-): Promise<MonkeyTypes.DecodedToken> {
+): Promise<DecodedToken> {
const isPublic =
options.isPublic || (options.isPublicOnDev && isDevEnvironment());
@@ -281,9 +288,7 @@ async function authenticateWithApeKey(
}
}
-async function authenticateWithUid(
- token: string
-): Promise<MonkeyTypes.DecodedToken> {
+async function authenticateWithUid(token: string): Promise<DecodedToken> {
if (!isDevEnvironment()) {
throw new MonkeyError(401, "Baerer type uid is not supported");
}
@@ -301,9 +306,9 @@ async function authenticateWithUid(
}
export function authenticateGithubWebhook(
- req: TsRestRequest,
+ req: TsRestRequestWithContext,
authHeader: string | string[] | undefined
-): MonkeyTypes.DecodedToken {
+): DecodedToken {
try {
const webhookSecret = process.env["GITHUB_WEBHOOK_SECRET"];
diff --git a/backend/src/middlewares/configuration.ts b/backend/src/middlewares/configuration.ts
index c1990cb46..02b04ecf5 100644
--- a/backend/src/middlewares/configuration.ts
+++ b/backend/src/middlewares/configuration.ts
@@ -7,13 +7,15 @@ import {
ConfigurationPath,
RequireConfiguration,
} from "@monkeytype/contracts/require-configuration/index";
-import { getMetadata, TsRestRequestWithCtx } from "./utility";
+import { getMetadata } from "./utility";
+import { TsRestRequestWithContext } from "../api/types";
+import { AppRoute, AppRouter } from "@ts-rest/core";
export function verifyRequiredConfiguration<
T extends AppRouter | AppRoute
>(): TsRestRequestHandler<T> {
return async (
- req: TsRestRequestWithCtx,
+ req: TsRestRequestWithContext,
_res: Response,
next: NextFunction
): Promise<void> => {
diff --git a/backend/src/middlewares/context.ts b/backend/src/middlewares/context.ts
index 3a681d0ae..ae76941a1 100644
--- a/backend/src/middlewares/context.ts
+++ b/backend/src/middlewares/context.ts
@@ -1,5 +1,17 @@
import { getCachedConfiguration } from "../init/configuration";
-import type { Response, NextFunction } from "express";
+import type {
+ Response,
+ NextFunction,
+ Request as ExpressRequest,
+} from "express";
+import { DecodedToken } from "./auth";
+import { Configuration } from "@monkeytype/contracts/schemas/configuration";
+import { ExpressRequestWithContext } from "../api/types";
+
+export type Context = {
+ configuration: Configuration;
+ decodedToken: DecodedToken;
+};
/**
* Add the context to the request
@@ -8,13 +20,13 @@ import type { Response, NextFunction } from "express";
* @param next
*/
async function contextMiddleware(
- req: MonkeyTypes.ExpressRequestWithContext,
+ req: ExpressRequest,
_res: Response,
next: NextFunction
): Promise<void> {
const configuration = await getCachedConfiguration(true);
- req.ctx = {
+ (req as ExpressRequestWithContext).ctx = {
configuration,
decodedToken: {
type: "None",
diff --git a/backend/src/middlewares/error.ts b/backend/src/middlewares/error.ts
index 3d45a853c..0d66de7e0 100644
--- a/backend/src/middlewares/error.ts
+++ b/backend/src/middlewares/error.ts
@@ -14,6 +14,7 @@ import { isDevEnvironment } from "../utils/misc";
import { ObjectId } from "mongodb";
import { version } from "../version";
import { addLog } from "../dal/logs";
+import { ExpressRequestWithContext } from "../api/types";
type DBError = {
_id: ObjectId;
@@ -34,7 +35,7 @@ type ErrorData = {
async function errorHandlingMiddleware(
error: Error,
- req: MonkeyTypes.ExpressRequestWithContext,
+ req: ExpressRequestWithContext,
res: Response,
_next: NextFunction
): Promise<void> {
diff --git a/backend/src/middlewares/permission.ts b/backend/src/middlewares/permission.ts
index 60b4621aa..77053c100 100644
--- a/backend/src/middlewares/permission.ts
+++ b/backend/src/middlewares/permission.ts
@@ -1,7 +1,7 @@
import _ from "lodash";
import MonkeyError from "../utils/error";
import type { Response, NextFunction } from "express";
-import { getPartialUser } from "../dal/user";
+import { DBUser, getPartialUser } from "../dal/user";
import { isAdmin } from "../dal/admin-uids";
import { TsRestRequestHandler } from "@ts-rest/express";
import {
@@ -10,12 +10,15 @@ import {
PermissionId,
} from "@monkeytype/contracts/schemas/api";
import { isDevEnvironment } from "../utils/misc";
-import { getMetadata, TsRestRequestWithCtx } from "./utility";
+import { getMetadata } from "./utility";
+import { TsRestRequestWithContext } from "../api/types";
+import { DecodedToken } from "./auth";
+import { AppRoute, AppRouter } from "@ts-rest/core";
type RequestPermissionCheck = {
type: "request";
criteria: (
- req: TsRestRequestWithCtx,
+ req: TsRestRequestWithContext,
metadata: EndpointMetadata | undefined
) => Promise<boolean>;
invalidMessage?: string;
@@ -23,16 +26,16 @@ type RequestPermissionCheck = {
type UserPermissionCheck = {
type: "user";
- fields: (keyof MonkeyTypes.DBUser)[];
- criteria: (user: MonkeyTypes.DBUser) => boolean;
+ fields: (keyof DBUser)[];
+ criteria: (user: DBUser) => boolean;
invalidMessage?: string;
};
type PermissionCheck = UserPermissionCheck | RequestPermissionCheck;
-function buildUserPermission<K extends keyof MonkeyTypes.DBUser>(
+function buildUserPermission<K extends keyof DBUser>(
fields: K[],
- criteria: (user: Pick<MonkeyTypes.DBUser, K>) => boolean,
+ criteria: (user: Pick<DBUser, K>) => boolean,
invalidMessage?: string
): UserPermissionCheck {
return {
@@ -73,7 +76,7 @@ export function verifyPermissions<
T extends AppRouter | AppRoute
>(): TsRestRequestHandler<T> {
return async (
- req: TsRestRequestWithCtx,
+ req: TsRestRequestWithContext,
_res: Response,
next: NextFunction
): Promise<void> => {
@@ -143,7 +146,7 @@ function getRequiredPermissionIds(
}
async function checkIfUserIsAdmin(
- decodedToken: MonkeyTypes.DecodedToken | undefined,
+ decodedToken: DecodedToken | undefined,
options: RequestAuthenticationOptions | undefined
): Promise<boolean> {
if (decodedToken === undefined) return false;
@@ -162,7 +165,7 @@ type CheckResult =
};
async function checkUserPermissions(
- decodedToken: MonkeyTypes.DecodedToken | undefined,
+ decodedToken: DecodedToken | undefined,
checks: UserPermissionCheck[]
): Promise<CheckResult> {
if (checks === undefined || checks.length === 0) {
@@ -181,7 +184,7 @@ async function checkUserPermissions(
decodedToken.uid,
"check user permissions",
checks.flatMap((it) => it.fields)
- )) as MonkeyTypes.DBUser;
+ )) as DBUser;
for (const check of checks) {
if (!check.criteria(user))
diff --git a/backend/src/middlewares/rate-limit.ts b/backend/src/middlewares/rate-limit.ts
index cb158e596..fc5b85b59 100644
--- a/backend/src/middlewares/rate-limit.ts
+++ b/backend/src/middlewares/rate-limit.ts
@@ -16,12 +16,17 @@ import {
Window,
} from "@monkeytype/contracts/rate-limit/index";
import statuses from "../constants/monkey-status-codes";
-import { getMetadata, TsRestRequestWithCtx } from "./utility";
+import { getMetadata } from "./utility";
+import {
+ ExpressRequestWithContext,
+ TsRestRequestWithContext,
+} from "../api/types";
+import { AppRoute, AppRouter } from "@ts-rest/core";
export const REQUEST_MULTIPLIER = isDevEnvironment() ? 100 : 1;
export const customHandler = (
- req: MonkeyTypes.ExpressRequestWithContext,
+ req: ExpressRequestWithContext,
_res: Response,
_next: NextFunction,
_options: Options
@@ -45,7 +50,7 @@ const getKey = (req: Request, _res: Response): string => {
};
const getKeyWithUid = (
- req: MonkeyTypes.ExpressRequestWithContext,
+ req: ExpressRequestWithContext,
_res: Response
): string => {
const uid = req?.ctx?.decodedToken?.uid;
@@ -94,7 +99,7 @@ export function rateLimitRequest<
T extends AppRouter | AppRoute
>(): TsRestRequestHandler<T> {
return async (
- req: TsRestRequestWithCtx,
+ req: TsRestRequestWithContext,
res: Response,
next: NextFunction
): Promise<void> => {
@@ -149,7 +154,7 @@ const badAuthRateLimiter = new RateLimiterMemory({
});
export async function badAuthRateLimiterHandler(
- req: MonkeyTypes.ExpressRequestWithContext,
+ req: ExpressRequestWithContext,
res: Response,
next: NextFunction
): Promise<void> {
@@ -179,7 +184,7 @@ export async function badAuthRateLimiterHandler(
}
export async function incrementBadAuth(
- req: MonkeyTypes.ExpressRequestWithContext,
+ req: ExpressRequestWithContext,
res: Response,
status: number
): Promise<void> {
diff --git a/backend/src/middlewares/utility.ts b/backend/src/middlewares/utility.ts
index 2d29f0180..8f3cbce12 100644
--- a/backend/src/middlewares/utility.ts
+++ b/backend/src/middlewares/utility.ts
@@ -4,11 +4,7 @@ import { recordClientVersion as prometheusRecordClientVersion } from "../utils/p
import { isDevEnvironment } from "../utils/misc";
import MonkeyError from "../utils/error";
import { EndpointMetadata } from "@monkeytype/contracts/schemas/api";
-
-export type TsRestRequestWithCtx = {
- ctx: Readonly<MonkeyTypes.Context>;
-} & TsRestRequest &
- ExpressRequest;
+import { TsRestRequestWithContext } from "../api/types";
/**
* record the client version from the `x-client-version` or ` client-version` header to prometheus
@@ -26,8 +22,12 @@ export function recordClientVersion(): RequestHandler {
}
/** Endpoint is only available in dev environment, else return 503. */
-export function onlyAvailableOnDev(): MonkeyTypes.RequestHandler {
- return (_req: TsRestRequestWithCtx, _res: Response, next: NextFunction) => {
+export function onlyAvailableOnDev(): RequestHandler {
+ return (
+ _req: TsRestRequestWithContext,
+ _res: Response,
+ next: NextFunction
+ ) => {
if (!isDevEnvironment()) {
next(
new MonkeyError(
@@ -41,7 +41,7 @@ export function onlyAvailableOnDev(): MonkeyTypes.RequestHandler {
};
}
-export function getMetadata(req: TsRestRequestWithCtx): EndpointMetadata {
+export function getMetadata(req: TsRestRequestWithContext): EndpointMetadata {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return (req.tsRestRoute["metadata"] ?? {}) as EndpointMetadata;
}
diff --git a/backend/src/types/types.d.ts b/backend/src/types/types.d.ts
deleted file mode 100644
index d662b0733..000000000
--- a/backend/src/types/types.d.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-type ObjectId = import("mongodb").ObjectId;
-
-type ExpressRequest = import("express").Request;
-type AppRoute = import("@ts-rest/core").AppRoute;
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-type TsRestRequest = import("@ts-rest/express").TsRestRequest<any>;
-type AppRouter = import("@ts-rest/core").AppRouter;
-declare namespace MonkeyTypes {
- export type DecodedToken = {
- type: "Bearer" | "ApeKey" | "None" | "GithubWebhook";
- uid: string;
- email: string;
- };
-
- export type Context = {
- configuration: import("@monkeytype/contracts/schemas/configuration").Configuration;
- decodedToken: DecodedToken;
- };
-
- type ExpressRequestWithContext = {
- ctx: Readonly<Context>;
- } & ExpressRequest;
-
- type Request<TQuery = undefined, TBody = undefined, TParams = undefined> = {
- query: Readonly<TQuery>;
- body: Readonly<TBody>;
- params: Readonly<TParams>;
- ctx: Readonly<Context>;
- raw: Readonly<TsRestRequest>;
- };
-
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
- type RequestHandler = import("@ts-rest/core").TsRestRequestHandler<any>;
-
- type DBUser = Omit<
- import("@monkeytype/contracts/schemas/users").User,
- | "resultFilterPresets"
- | "tags"
- | "customThemes"
- | "isPremium"
- | "allTimeLbs"
- | "testActivity"
- > & {
- _id: ObjectId;
- resultFilterPresets?: WithObjectId<
- import("@monkeytype/contracts/schemas/users").ResultFilters
- >[];
- tags?: DBUserTag[];
- lbPersonalBests?: LbPersonalBests;
- customThemes?: DBCustomTheme[];
- autoBanTimestamps?: number[];
- inbox?: import("@monkeytype/contracts/schemas/users").MonkeyMail[];
- ips?: string[];
- canReport?: boolean;
- lastNameChange?: number;
- canManageApeKeys?: boolean;
- bananas?: number;
- testActivity?: import("@monkeytype/contracts/schemas/users").CountByYearAndDay;
- };
-
- type DBCustomTheme = WithObjectId<
- import("@monkeytype/contracts/schemas/users").CustomTheme
- >;
-
- type DBUserTag = WithObjectId<
- import("@monkeytype/contracts/schemas/users").UserTag
- >;
-
- type LbPersonalBests = {
- time: Record<
- number,
- Record<
- string,
- import("@monkeytype/contracts/schemas/shared").PersonalBest
- >
- >;
- };
-
- type WithObjectId<T extends { _id: string }> = Omit<T, "_id"> & {
- _id: ObjectId;
- };
-
- type ApeKeyDB = import("@monkeytype/contracts/schemas/ape-keys").ApeKey & {
- _id: ObjectId;
- uid: string;
- hash: string;
- useCount: number;
- };
-
- type ReportTypes = "quote" | "user";
-
- type Report = {
- _id: ObjectId;
- id: string;
- type: ReportTypes;
- timestamp: number;
- uid: string;
- contentId: string;
- reason: string;
- comment: string;
- };
-
- type FunboxMetadata = {
- name: string;
- canGetPb: boolean;
- difficultyLevel: number;
- properties?: string[];
- frontendForcedConfig?: Record<string, string[] | boolean[]>;
- frontendFunctions?: string[];
- };
-
- type DBResult = MonkeyTypes.WithObjectId<
- import("@monkeytype/contracts/schemas/results").Result<
- import("@monkeytype/contracts/schemas/shared").Mode
- >
- > & {
- //legacy values
- correctChars?: number;
- incorrectChars?: number;
- };
-
- type BlocklistEntry = {
- _id: string;
- usernameHash?: string;
- emailHash?: string;
- discordIdHash?: string;
- timestamp: number;
- };
-
- type DBBlocklistEntry = WithObjectId<MonkeyTypes.BlocklistEntry>;
-}
diff --git a/backend/src/utils/misc.ts b/backend/src/utils/misc.ts
index e69c47083..d035c9cc6 100644
--- a/backend/src/utils/misc.ts
+++ b/backend/src/utils/misc.ts
@@ -2,6 +2,8 @@ import { MILLISECONDS_IN_DAY } from "@monkeytype/util/date-and-time";
import { roundTo2 } from "@monkeytype/util/numbers";
import _, { omit } from "lodash";
import uaparser from "ua-parser-js";
+import { MonkeyRequest } from "../api/types";
+import { ObjectId } from "mongodb";
//todo split this file into smaller util files (grouped by functionality)
@@ -26,14 +28,14 @@ type AgentLog = {
device?: string;
};
-export function buildAgentLog(req: TsRestRequest): AgentLog {
- const agent = uaparser(req.headers["user-agent"]);
+export function buildAgentLog(req: MonkeyRequest): AgentLog {
+ const agent = uaparser(req.raw.headers["user-agent"]);
const agentLog: AgentLog = {
ip:
- (req.headers["cf-connecting-ip"] as string) ||
- (req.headers["x-forwarded-for"] as string) ||
- (req.ip as string) ||
+ (req.raw.headers["cf-connecting-ip"] as string) ||
+ (req.raw.headers["x-forwarded-for"] as string) ||
+ (req.raw.ip as string) ||
"255.255.255.255",
agent: `${agent.os.name} ${agent.os.version} ${agent.browser.name} ${agent.browser.version}`,
};
@@ -224,3 +226,6 @@ export function replaceObjectIds<T extends { _id: ObjectId }>(
if (data === undefined) return data;
return data.map((it) => replaceObjectId(it));
}
+export type WithObjectId<T extends { _id: string }> = Omit<T, "_id"> & {
+ _id: ObjectId;
+};
diff --git a/backend/src/utils/pb.ts b/backend/src/utils/pb.ts
index b20f801cb..e733e25c7 100644
--- a/backend/src/utils/pb.ts
+++ b/backend/src/utils/pb.ts
@@ -8,10 +8,14 @@ import {
} from "@monkeytype/contracts/schemas/shared";
import { Result as ResultType } from "@monkeytype/contracts/schemas/results";
+export type LbPersonalBests = {
+ time: Record<number, Record<string, PersonalBest>>;
+};
+
type CheckAndUpdatePbResult = {
isPb: boolean;
personalBests: PersonalBests;
- lbPersonalBests?: MonkeyTypes.LbPersonalBests;
+ lbPersonalBests?: LbPersonalBests;
};
type Result = Omit<ResultType<Mode>, "_id" | "name">;
@@ -35,7 +39,7 @@ export function canFunboxGetPb(result: Result): boolean {
export function checkAndUpdatePb(
userPersonalBests: PersonalBests,
- lbPersonalBests: MonkeyTypes.LbPersonalBests | undefined,
+ lbPersonalBests: LbPersonalBests | undefined,
result: Result
): CheckAndUpdatePbResult {
const mode = result.mode;
@@ -174,9 +178,9 @@ function buildPersonalBest(result: Result): PersonalBest {
export function updateLeaderboardPersonalBests(
userPersonalBests: PersonalBests,
- lbPersonalBests: MonkeyTypes.LbPersonalBests,
+ lbPersonalBests: LbPersonalBests,
result: Result
-): MonkeyTypes.LbPersonalBests | null {
+): LbPersonalBests | null {
if (!shouldUpdateLeaderboardPersonalBests(result)) {
return null;
}
diff --git a/backend/src/utils/result.ts b/backend/src/utils/result.ts
index 65abc1c73..53df3dc25 100644
--- a/backend/src/utils/result.ts
+++ b/backend/src/utils/result.ts
@@ -1,13 +1,21 @@
-import { CompletedEvent } from "@monkeytype/contracts/schemas/results";
+import { CompletedEvent, Result } from "@monkeytype/contracts/schemas/results";
+import { Mode } from "@monkeytype/contracts/schemas/shared";
import { ObjectId } from "mongodb";
+import { WithObjectId } from "./misc";
+
+export type DBResult = WithObjectId<Result<Mode>> & {
+ //legacy values
+ correctChars?: number;
+ incorrectChars?: number;
+};
export function buildDbResult(
completedEvent: CompletedEvent,
userName: string,
isPb: boolean
-): MonkeyTypes.DBResult {
+): DBResult {
const ce = completedEvent;
- const res: MonkeyTypes.DBResult = {
+ const res: DBResult = {
_id: new ObjectId(),
uid: ce.uid,
wpm: ce.wpm,
@@ -63,9 +71,7 @@ export function buildDbResult(
* @param result
* @returns
*/
-export function replaceLegacyValues(
- result: MonkeyTypes.DBResult
-): MonkeyTypes.DBResult {
+export function replaceLegacyValues(result: DBResult): DBResult {
//convert legacy values
if (
result.correctChars !== undefined &&
diff --git a/frontend/src/ts/commandline/commandline.ts b/frontend/src/ts/commandline/commandline.ts
index 190f77c4a..69c24623b 100644
--- a/frontend/src/ts/commandline/commandline.ts
+++ b/frontend/src/ts/commandline/commandline.ts
@@ -10,10 +10,11 @@ import * as OutOfFocus from "../test/out-of-focus";
import * as ActivePage from "../states/active-page";
import { focusWords } from "../test/test-ui";
import * as Loader from "../elements/loader";
+import { Command, CommandsSubgroup } from "./types";
type CommandlineMode = "search" | "input";
type InputModeParams = {
- command: MonkeyTypes.Command | null;
+ command: Command | null;
placeholder: string | null;
value: string | null;
icon: string | null;
@@ -22,7 +23,7 @@ type InputModeParams = {
let activeIndex = 0;
let usingSingleList = false;
let inputValue = "";
-let activeCommand: MonkeyTypes.Command | null = null;
+let activeCommand: Command | null = null;
let mouseMode = false;
let mode: CommandlineMode = "search";
let inputModeParams: InputModeParams = {
@@ -31,7 +32,7 @@ let inputModeParams: InputModeParams = {
value: "",
icon: "",
};
-let subgroupOverride: MonkeyTypes.CommandsSubgroup | null = null;
+let subgroupOverride: CommandsSubgroup | null = null;
function removeCommandlineBackground(): void {
$("#commandLine").addClass("noBackground");
@@ -49,7 +50,7 @@ function addCommandlineBackground(): void {
}
type ShowSettings = {
- subgroupOverride?: MonkeyTypes.CommandsSubgroup | string;
+ subgroupOverride?: CommandsSubgroup | string;
singleListOverride?: boolean;
};
@@ -284,9 +285,9 @@ function hideCommands(): void {
element.innerHTML = "";
}
-let cachedSingleSubgroup: MonkeyTypes.CommandsSubgroup | null = null;
+let cachedSingleSubgroup: CommandsSubgroup | null = null;
-async function getSubgroup(): Promise<MonkeyTypes.CommandsSubgroup> {
+async function getSubgroup(): Promise<CommandsSubgroup> {
if (subgroupOverride !== null) {
return subgroupOverride;
}
@@ -302,7 +303,7 @@ async function getSubgroup(): Promise<MonkeyTypes.CommandsSubgroup> {
return CommandlineLists.getTopOfStack();
}
-async function getList(): Promise<MonkeyTypes.Command[]> {
+async function getList(): Promise<Command[]> {
return (await getSubgroup()).list;
}
diff --git a/frontend/src/ts/commandline/lists.ts b/frontend/src/ts/commandline/lists.ts
index 011236898..8344bc3b3 100644
--- a/frontend/src/ts/commandline/lists.ts
+++ b/frontend/src/ts/commandline/lists.ts
@@ -105,6 +105,7 @@ import * as QuoteSearchModal from "../modals/quote-search";
import * as FPSCounter from "../elements/fps-counter";
import { migrateConfig } from "../utils/config";
import { PartialConfigSchema } from "@monkeytype/contracts/schemas/configs";
+import { Command, CommandsSubgroup } from "./types";
const layoutsPromise = JSONData.getLayoutsList();
layoutsPromise
@@ -178,7 +179,7 @@ challengesPromise
);
});
-export const commands: MonkeyTypes.CommandsSubgroup = {
+export const commands: CommandsSubgroup = {
title: "",
list: [
//result
@@ -510,7 +511,7 @@ export function doesListExist(listName: string): boolean {
export async function getList(
listName: ListsObjectKeys
-): Promise<MonkeyTypes.CommandsSubgroup> {
+): Promise<CommandsSubgroup> {
await Promise.allSettled([
layoutsPromise,
languagesPromise,
@@ -527,7 +528,7 @@ export async function getList(
return list;
}
-let stack: MonkeyTypes.CommandsSubgroup[] = [];
+let stack: CommandsSubgroup[] = [];
stack = [commands];
@@ -541,11 +542,11 @@ export function setStackToDefault(): void {
setStack([commands]);
}
-export function setStack(val: MonkeyTypes.CommandsSubgroup[]): void {
+export function setStack(val: CommandsSubgroup[]): void {
stack = val;
}
-export function pushToStack(val: MonkeyTypes.CommandsSubgroup): void {
+export function pushToStack(val: CommandsSubgroup): void {
stack.push(val);
}
@@ -553,12 +554,12 @@ export function popFromStack(): void {
stack.pop();
}
-export function getTopOfStack(): MonkeyTypes.CommandsSubgroup {
- return stack[stack.length - 1] as MonkeyTypes.CommandsSubgroup;
+export function getTopOfStack(): CommandsSubgroup {
+ return stack[stack.length - 1] as CommandsSubgroup;
}
-let singleList: MonkeyTypes.CommandsSubgroup | undefined;
-export async function getSingleSubgroup(): Promise<MonkeyTypes.CommandsSubgroup> {
+let singleList: CommandsSubgroup | undefined;
+export async function getSingleSubgroup(): Promise<CommandsSubgroup> {
await Promise.allSettled([
layoutsPromise,
languagesPromise,
@@ -568,7 +569,7 @@ export async function getSingleSubgroup(): Promise<MonkeyTypes.CommandsSubgroup>
challengesPromise,
]);
- const singleCommands: MonkeyTypes.Command[] = [];
+ const singleCommands: Command[] = [];
for (const command of commands.list) {
const ret = buildSingleListCommands(command);
singleCommands.push(...ret);
@@ -582,10 +583,10 @@ export async function getSingleSubgroup(): Promise<MonkeyTypes.CommandsSubgroup>
}
function buildSingleListCommands(
- command: MonkeyTypes.Command,
- parentCommand?: MonkeyTypes.Command
-): MonkeyTypes.Command[] {
- const commands: MonkeyTypes.Command[] = [];
+ command: Command,
+ parentCommand?: Command
+): Command[] {
+ const commands: Command[] = [];
if (command.subgroup) {
if (command.subgroup.beforeList) {
command.subgroup.beforeList();
diff --git a/frontend/src/ts/commandline/lists/add-or-remove-theme-to-favorites.ts b/frontend/src/ts/commandline/lists/add-or-remove-theme-to-favorites.ts
index 0cda2388b..13b5567db 100644
--- a/frontend/src/ts/commandline/lists/add-or-remove-theme-to-favorites.ts
+++ b/frontend/src/ts/commandline/lists/add-or-remove-theme-to-favorites.ts
@@ -1,7 +1,8 @@
import Config, * as UpdateConfig from "../../config";
import { randomTheme } from "../../controllers/theme-controller";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "addThemeToFavorite",
display: "Add current theme to favorite",
diff --git a/frontend/src/ts/commandline/lists/always-show-decimal.ts b/frontend/src/ts/commandline/lists/always-show-decimal.ts
index 20dce01cc..50c138c02 100644
--- a/frontend/src/ts/commandline/lists/always-show-decimal.ts
+++ b/frontend/src/ts/commandline/lists/always-show-decimal.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Always show decimal places...",
configKey: "alwaysShowDecimalPlaces",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeAlwaysShowDecimal",
display: "Always show decimal places...",
diff --git a/frontend/src/ts/commandline/lists/background-filter.ts b/frontend/src/ts/commandline/lists/background-filter.ts
index 3e7fc3961..31b9ccab8 100644
--- a/frontend/src/ts/commandline/lists/background-filter.ts
+++ b/frontend/src/ts/commandline/lists/background-filter.ts
@@ -1,6 +1,7 @@
import Config, * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Custom background filter...",
configKey: "customBackgroundFilter",
list: [
@@ -67,7 +68,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "setCustomBackgroundFilter",
display: "Custom background filter...",
diff --git a/frontend/src/ts/commandline/lists/background-size.ts b/frontend/src/ts/commandline/lists/background-size.ts
index a3fb5ec3d..d8e29a17d 100644
--- a/frontend/src/ts/commandline/lists/background-size.ts
+++ b/frontend/src/ts/commandline/lists/background-size.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Custom background size...",
configKey: "customBackgroundSize",
list: [
@@ -34,7 +35,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "setCustomBackgroundSize",
display: "Custom background size...",
diff --git a/frontend/src/ts/commandline/lists/bail-out.ts b/frontend/src/ts/commandline/lists/bail-out.ts
index a478d4281..d73fbdae9 100644
--- a/frontend/src/ts/commandline/lists/bail-out.ts
+++ b/frontend/src/ts/commandline/lists/bail-out.ts
@@ -3,6 +3,7 @@ import * as CustomText from "../../test/custom-text";
import * as TestLogic from "../../test/test-logic";
import * as TestState from "../../test/test-state";
import * as CustomTextState from "../../states/custom-text-name";
+import { Command, CommandsSubgroup } from "../types";
function canBailOut(): boolean {
return (
@@ -23,7 +24,7 @@ function canBailOut(): boolean {
);
}
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Are you sure...",
list: [
{
@@ -47,7 +48,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "bailOut",
display: "Bail out...",
diff --git a/frontend/src/ts/commandline/lists/blind-mode.ts b/frontend/src/ts/commandline/lists/blind-mode.ts
index 720fa8389..34febb6c5 100644
--- a/frontend/src/ts/commandline/lists/blind-mode.ts
+++ b/frontend/src/ts/commandline/lists/blind-mode.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Blind mode...",
configKey: "blindMode",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeBlindMode",
display: "Blind mode...",
diff --git a/frontend/src/ts/commandline/lists/british-english.ts b/frontend/src/ts/commandline/lists/british-english.ts
index ea7433aba..2e7a5119f 100644
--- a/frontend/src/ts/commandline/lists/british-english.ts
+++ b/frontend/src/ts/commandline/lists/british-english.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "British english...",
configKey: "britishEnglish",
list: [
@@ -26,7 +27,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeBritishEnglish",
display: "British english...",
diff --git a/frontend/src/ts/commandline/lists/caps-lock-warning.ts b/frontend/src/ts/commandline/lists/caps-lock-warning.ts
index 370fe49c2..092cf858c 100644
--- a/frontend/src/ts/commandline/lists/caps-lock-warning.ts
+++ b/frontend/src/ts/commandline/lists/caps-lock-warning.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Caps lock warning...",
configKey: "capsLockWarning",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "capsLockWarning",
display: "Caps lock warning...",
diff --git a/frontend/src/ts/commandline/lists/caret-style.ts b/frontend/src/ts/commandline/lists/caret-style.ts
index 4eef78a25..dff3d53f7 100644
--- a/frontend/src/ts/commandline/lists/caret-style.ts
+++ b/frontend/src/ts/commandline/lists/caret-style.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Caret style...",
configKey: "caretStyle",
list: [
@@ -65,7 +66,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeCaretStyle",
display: "Caret style...",
diff --git a/frontend/src/ts/commandline/lists/colorful-mode.ts b/frontend/src/ts/commandline/lists/colorful-mode.ts
index d5a197529..6523212ee 100644
--- a/frontend/src/ts/commandline/lists/colorful-mode.ts
+++ b/frontend/src/ts/commandline/lists/colorful-mode.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Colorful mode...",
configKey: "colorfulMode",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeColorfulMode",
display: "Colorful mode...",
diff --git a/frontend/src/ts/commandline/lists/confidence-mode.ts b/frontend/src/ts/commandline/lists/confidence-mode.ts
index a163378c5..c1cd11186 100644
--- a/frontend/src/ts/commandline/lists/confidence-mode.ts
+++ b/frontend/src/ts/commandline/lists/confidence-mode.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeConfidenceMode",
display: "Confidence mode...",
diff --git a/frontend/src/ts/commandline/lists/custom-theme.ts b/frontend/src/ts/commandline/lists/custom-theme.ts
index 34a47b2ae..897151c66 100644
--- a/frontend/src/ts/commandline/lists/custom-theme.ts
+++ b/frontend/src/ts/commandline/lists/custom-theme.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Custom theme",
configKey: "customTheme",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "setCustomTheme",
display: "Custom theme...",
diff --git a/frontend/src/ts/commandline/lists/custom-themes-list.ts b/frontend/src/ts/commandline/lists/custom-themes-list.ts
index 89bb2dc07..ca6aae004 100644
--- a/frontend/src/ts/commandline/lists/custom-themes-list.ts
+++ b/frontend/src/ts/commandline/lists/custom-themes-list.ts
@@ -2,15 +2,16 @@ import * as UpdateConfig from "../../config";
import { isAuthenticated } from "../../firebase";
import * as DB from "../../db";
import * as ThemeController from "../../controllers/theme-controller";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Custom themes list...",
// configKey: "customThemeId",
beforeList: (): void => update(),
list: [],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "setCustomThemeId",
display: "Custom themes...",
diff --git a/frontend/src/ts/commandline/lists/difficulty.ts b/frontend/src/ts/commandline/lists/difficulty.ts
index b0a16756c..a454e8a69 100644
--- a/frontend/src/ts/commandline/lists/difficulty.ts
+++ b/frontend/src/ts/commandline/lists/difficulty.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Difficulty...",
configKey: "difficulty",
list: [
@@ -31,7 +32,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeDifficulty",
display: "Difficulty...",
diff --git a/frontend/src/ts/commandline/lists/enable-ads.ts b/frontend/src/ts/commandline/lists/enable-ads.ts
index f7bc8fdd1..50cbdc556 100644
--- a/frontend/src/ts/commandline/lists/enable-ads.ts
+++ b/frontend/src/ts/commandline/lists/enable-ads.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Set enable ads...",
configKey: "ads",
list: [
@@ -39,7 +40,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "setEnableAds",
display: "Enable ads...",
diff --git a/frontend/src/ts/commandline/lists/flip-test-colors.ts b/frontend/src/ts/commandline/lists/flip-test-colors.ts
index 58ca1c0a4..ad719155f 100644
--- a/frontend/src/ts/commandline/lists/flip-test-colors.ts
+++ b/frontend/src/ts/commandline/lists/flip-test-colors.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Flip test colors...",
configKey: "flipTestColors",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeFlipTestColors",
display: "Flip test colors...",
diff --git a/frontend/src/ts/commandline/lists/font-family.ts b/frontend/src/ts/commandline/lists/font-family.ts
index e6f500b20..4131b7068 100644
--- a/frontend/src/ts/commandline/lists/font-family.ts
+++ b/frontend/src/ts/commandline/lists/font-family.ts
@@ -1,13 +1,15 @@
import * as UpdateConfig from "../../config";
import * as UI from "../../ui";
+import { FontObject } from "../../utils/json-data";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Font family...",
configKey: "fontFamily",
list: [],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeFontFamily",
display: "Font family...",
@@ -16,7 +18,7 @@ const commands: MonkeyTypes.Command[] = [
},
];
-function update(fonts: MonkeyTypes.FontObject[]): void {
+function update(fonts: FontObject[]): void {
fonts.forEach((font) => {
const configVal = font.name.replace(/ /g, "_");
diff --git a/frontend/src/ts/commandline/lists/font-size.ts b/frontend/src/ts/commandline/lists/font-size.ts
index c4706d626..b55b277f7 100644
--- a/frontend/src/ts/commandline/lists/font-size.ts
+++ b/frontend/src/ts/commandline/lists/font-size.ts
@@ -1,6 +1,7 @@
import Config, * as UpdateConfig from "../../config";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeFontSize",
display: "Font size...",
diff --git a/frontend/src/ts/commandline/lists/freedom-mode.ts b/frontend/src/ts/commandline/lists/freedom-mode.ts
index 3f634319e..6563c57ab 100644
--- a/frontend/src/ts/commandline/lists/freedom-mode.ts
+++ b/frontend/src/ts/commandline/lists/freedom-mode.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Freedom mode...",
configKey: "freedomMode",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeFreedomMode",
display: "Freedom mode...",
diff --git a/frontend/src/ts/commandline/lists/funbox.ts b/frontend/src/ts/commandline/lists/funbox.ts
index d63b62800..704d0d4d3 100644
--- a/frontend/src/ts/commandline/lists/funbox.ts
+++ b/frontend/src/ts/commandline/lists/funbox.ts
@@ -3,8 +3,10 @@ import * as TestLogic from "../../test/test-logic";
import * as ManualRestart from "../../test/manual-restart-tracker";
import Config from "../../config";
import { areFunboxesCompatible } from "../../test/funbox/funbox-validation";
+import { FunboxMetadata } from "../../utils/json-data";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Funbox...",
configKey: "funbox",
list: [
@@ -22,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeFunbox",
display: "Funbox...",
@@ -32,7 +34,7 @@ const commands: MonkeyTypes.Command[] = [
},
];
-function update(funboxes: MonkeyTypes.FunboxMetadata[]): void {
+function update(funboxes: FunboxMetadata[]): void {
subgroup.list = [];
subgroup.list.push({
id: "changeFunboxNone",
diff --git a/frontend/src/ts/commandline/lists/hide-extra-letters.ts b/frontend/src/ts/commandline/lists/hide-extra-letters.ts
index da423ac39..f0a0274e3 100644
--- a/frontend/src/ts/commandline/lists/hide-extra-letters.ts
+++ b/frontend/src/ts/commandline/lists/hide-extra-letters.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Hide extra letters...",
configKey: "hideExtraLetters",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeHideExtraLetters",
display: "Hide extra letters...",
diff --git a/frontend/src/ts/commandline/lists/highlight-mode.ts b/frontend/src/ts/commandline/lists/highlight-mode.ts
index 0626fa506..568b9acdc 100644
--- a/frontend/src/ts/commandline/lists/highlight-mode.ts
+++ b/frontend/src/ts/commandline/lists/highlight-mode.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Highlight mode...",
configKey: "highlightMode",
list: [
@@ -55,7 +56,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeHighlightMode",
display: "Highlight mode...",
diff --git a/frontend/src/ts/commandline/lists/indicate-typos.ts b/frontend/src/ts/commandline/lists/indicate-typos.ts
index e0c3f3665..f103a414a 100644
--- a/frontend/src/ts/commandline/lists/indicate-typos.ts
+++ b/frontend/src/ts/commandline/lists/indicate-typos.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Indicate typos...",
configKey: "indicateTypos",
list: [
@@ -31,7 +32,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeIndicateTypos",
display: "Indicate typos...",
diff --git a/frontend/src/ts/commandline/lists/key-tips.ts b/frontend/src/ts/commandline/lists/key-tips.ts
index 2e752c84f..a2c09e29d 100644
--- a/frontend/src/ts/commandline/lists/key-tips.ts
+++ b/frontend/src/ts/commandline/lists/key-tips.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Key tips...",
configKey: "showKeyTips",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeKeyTips",
display: "Key tips...",
diff --git a/frontend/src/ts/commandline/lists/keymap-layouts.ts b/frontend/src/ts/commandline/lists/keymap-layouts.ts
index 17118501e..69bb4dd60 100644
--- a/frontend/src/ts/commandline/lists/keymap-layouts.ts
+++ b/frontend/src/ts/commandline/lists/keymap-layouts.ts
@@ -1,8 +1,10 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
+import { LayoutsList } from "../../utils/json-data";
import { capitalizeFirstLetterOfEachWord } from "../../utils/strings";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Change keymap layout...",
configKey: "keymapLayout",
list: [
@@ -13,7 +15,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeKeymapLayout",
display: "Keymap layout...",
@@ -23,7 +25,7 @@ const commands: MonkeyTypes.Command[] = [
},
];
-function update(layouts: MonkeyTypes.Layouts): void {
+function update(layouts: LayoutsList): void {
subgroup.list = [];
subgroup.list.push({
id: "changeKeymapLayoutOverrideSync",
diff --git a/frontend/src/ts/commandline/lists/keymap-legend-style.ts b/frontend/src/ts/commandline/lists/keymap-legend-style.ts
index a050e0859..d609b593e 100644
--- a/frontend/src/ts/commandline/lists/keymap-legend-style.ts
+++ b/frontend/src/ts/commandline/lists/keymap-legend-style.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Keymap legend style...",
configKey: "keymapLegendStyle",
list: [
@@ -39,7 +40,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeKeymapLegendStyle",
display: "Keymap legend style...",
diff --git a/frontend/src/ts/commandline/lists/keymap-mode.ts b/frontend/src/ts/commandline/lists/keymap-mode.ts
index d92bbbcde..62fcc0b55 100644
--- a/frontend/src/ts/commandline/lists/keymap-mode.ts
+++ b/frontend/src/ts/commandline/lists/keymap-mode.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Keymap mode...",
configKey: "keymapMode",
list: [
@@ -40,7 +41,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "toggleKeymap",
display: "Keymap mode...",
diff --git a/frontend/src/ts/commandline/lists/keymap-show-top-row.ts b/frontend/src/ts/commandline/lists/keymap-show-top-row.ts
index 0e8c06833..65559dc65 100644
--- a/frontend/src/ts/commandline/lists/keymap-show-top-row.ts
+++ b/frontend/src/ts/commandline/lists/keymap-show-top-row.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Keymap show top row...",
configKey: "keymapShowTopRow",
list: [
@@ -31,7 +32,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeKeymapShowTopRow",
display: "Keymap show top row...",
diff --git a/frontend/src/ts/commandline/lists/keymap-size.ts b/frontend/src/ts/commandline/lists/keymap-size.ts
index eb0f4e0ca..fd67a1e74 100644
--- a/frontend/src/ts/commandline/lists/keymap-size.ts
+++ b/frontend/src/ts/commandline/lists/keymap-size.ts
@@ -1,6 +1,7 @@
import Config, * as UpdateConfig from "../../config";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeKeymapSize",
display: "Keymap size...",
diff --git a/frontend/src/ts/commandline/lists/keymap-style.ts b/frontend/src/ts/commandline/lists/keymap-style.ts
index 61768a7bd..9b01e9018 100644
--- a/frontend/src/ts/commandline/lists/keymap-style.ts
+++ b/frontend/src/ts/commandline/lists/keymap-style.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Keymap style...",
configKey: "keymapStyle",
list: [
@@ -63,7 +64,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeKeymapStyle",
display: "Keymap style...",
diff --git a/frontend/src/ts/commandline/lists/languages.ts b/frontend/src/ts/commandline/lists/languages.ts
index 01b95dab2..c1a3a9d54 100644
--- a/frontend/src/ts/commandline/lists/languages.ts
+++ b/frontend/src/ts/commandline/lists/languages.ts
@@ -3,8 +3,9 @@ import {
capitalizeFirstLetterOfEachWord,
getLanguageDisplayString,
} from "../../utils/strings";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Language...",
configKey: "language",
list: [
@@ -15,7 +16,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeLanguage",
display: "Language...",
diff --git a/frontend/src/ts/commandline/lists/layouts.ts b/frontend/src/ts/commandline/lists/layouts.ts
index df1c83dc0..5f9b01595 100644
--- a/frontend/src/ts/commandline/lists/layouts.ts
+++ b/frontend/src/ts/commandline/lists/layouts.ts
@@ -1,8 +1,10 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
+import { LayoutsList } from "../../utils/json-data";
import { capitalizeFirstLetterOfEachWord } from "../../utils/strings";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Layout emulator...",
configKey: "layout",
list: [
@@ -13,7 +15,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeLayout",
display: "Layout emulator...",
@@ -22,7 +24,7 @@ const commands: MonkeyTypes.Command[] = [
},
];
-function update(layouts: MonkeyTypes.Layouts): void {
+function update(layouts: LayoutsList): void {
subgroup.list = [];
subgroup.list.push({
id: "changeLayoutDefault",
diff --git a/frontend/src/ts/commandline/lists/lazy-mode.ts b/frontend/src/ts/commandline/lists/lazy-mode.ts
index 9d1694a52..d886aae0e 100644
--- a/frontend/src/ts/commandline/lists/lazy-mode.ts
+++ b/frontend/src/ts/commandline/lists/lazy-mode.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Lazy mode...",
configKey: "lazyMode",
list: [
@@ -26,7 +27,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeLazyMode",
display: "Lazy mode...",
diff --git a/frontend/src/ts/commandline/lists/live-acc-style.ts b/frontend/src/ts/commandline/lists/live-acc-style.ts
index 30e3d4f14..a82db9c75 100644
--- a/frontend/src/ts/commandline/lists/live-acc-style.ts
+++ b/frontend/src/ts/commandline/lists/live-acc-style.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Live acc style...",
configKey: "liveAccStyle",
list: [
@@ -31,7 +32,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeLiveAccStyle",
display: "Live acc style...",
diff --git a/frontend/src/ts/commandline/lists/live-burst-style.ts b/frontend/src/ts/commandline/lists/live-burst-style.ts
index 9af83a78a..a56d122a6 100644
--- a/frontend/src/ts/commandline/lists/live-burst-style.ts
+++ b/frontend/src/ts/commandline/lists/live-burst-style.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Live burst style...",
configKey: "liveBurstStyle",
list: [
@@ -31,7 +32,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeLiveBurstStyle",
display: "Live burst style...",
diff --git a/frontend/src/ts/commandline/lists/live-speed-style.ts b/frontend/src/ts/commandline/lists/live-speed-style.ts
index b3a5914de..bb42153cf 100644
--- a/frontend/src/ts/commandline/lists/live-speed-style.ts
+++ b/frontend/src/ts/commandline/lists/live-speed-style.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Live speed style...",
configKey: "liveSpeedStyle",
list: [
@@ -31,7 +32,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeLiveSpeedStyle",
display: "Live speed style...",
diff --git a/frontend/src/ts/commandline/lists/load-challenge.ts b/frontend/src/ts/commandline/lists/load-challenge.ts
index e260ff2db..c9ad3a7dc 100644
--- a/frontend/src/ts/commandline/lists/load-challenge.ts
+++ b/frontend/src/ts/commandline/lists/load-challenge.ts
@@ -2,13 +2,15 @@ import { navigate } from "../../controllers/route-controller";
import * as ChallengeController from "../../controllers/challenge-controller";
import * as TestLogic from "../../test/test-logic";
import { capitalizeFirstLetterOfEachWord } from "../../utils/strings";
+import { Command, CommandsSubgroup } from "../types";
+import { Challenge } from "../../utils/json-data";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Load challenge...",
list: [],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "loadChallenge",
display: "Load challenge...",
@@ -17,7 +19,7 @@ const commands: MonkeyTypes.Command[] = [
},
];
-function update(challenges: MonkeyTypes.Challenge[]): void {
+function update(challenges: Challenge[]): void {
challenges.forEach((challenge) => {
subgroup.list.push({
id: "loadChallenge" + capitalizeFirstLetterOfEachWord(challenge.name),
diff --git a/frontend/src/ts/commandline/lists/max-line-width.ts b/frontend/src/ts/commandline/lists/max-line-width.ts
index ad97d6335..63ab65adb 100644
--- a/frontend/src/ts/commandline/lists/max-line-width.ts
+++ b/frontend/src/ts/commandline/lists/max-line-width.ts
@@ -1,6 +1,7 @@
import Config, * as UpdateConfig from "../../config";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeMaxLineWidth",
display: "Max line width...",
diff --git a/frontend/src/ts/commandline/lists/min-acc.ts b/frontend/src/ts/commandline/lists/min-acc.ts
index 84466ef8e..0b831d99e 100644
--- a/frontend/src/ts/commandline/lists/min-acc.ts
+++ b/frontend/src/ts/commandline/lists/min-acc.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Change min accuracy mode...",
configKey: "minAcc",
list: [
@@ -26,7 +27,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeMinAcc",
display: "Minimum accuracy...",
diff --git a/frontend/src/ts/commandline/lists/min-burst.ts b/frontend/src/ts/commandline/lists/min-burst.ts
index 0ecd089ba..626d0a734 100644
--- a/frontend/src/ts/commandline/lists/min-burst.ts
+++ b/frontend/src/ts/commandline/lists/min-burst.ts
@@ -1,7 +1,8 @@
import Config, * as UpdateConfig from "../../config";
import { get as getTypingSpeedUnit } from "../../utils/typing-speed-units";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Change min burst mode...",
configKey: "minBurst",
list: [
@@ -44,7 +45,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeMinBurst",
display: "Minimum burst...",
diff --git a/frontend/src/ts/commandline/lists/min-wpm.ts b/frontend/src/ts/commandline/lists/min-wpm.ts
index 67a03f0e1..5322ff28c 100644
--- a/frontend/src/ts/commandline/lists/min-wpm.ts
+++ b/frontend/src/ts/commandline/lists/min-wpm.ts
@@ -1,7 +1,8 @@
import Config, * as UpdateConfig from "../../config";
import { get as getTypingSpeedUnit } from "../../utils/typing-speed-units";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Change min speed mode...",
configKey: "minWpm",
list: [
@@ -30,7 +31,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeMinWpm",
display: "Minimum speed...",
diff --git a/frontend/src/ts/commandline/lists/mode.ts b/frontend/src/ts/commandline/lists/mode.ts
index 78a8fd8d9..844aff159 100644
--- a/frontend/src/ts/commandline/lists/mode.ts
+++ b/frontend/src/ts/commandline/lists/mode.ts
@@ -1,8 +1,9 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
import * as ManualRestart from "../../test/manual-restart-tracker";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeMode",
display: "Mode...",
diff --git a/frontend/src/ts/commandline/lists/monkey-power-level.ts b/frontend/src/ts/commandline/lists/monkey-power-level.ts
index da530873e..4bf907e95 100644
--- a/frontend/src/ts/commandline/lists/monkey-power-level.ts
+++ b/frontend/src/ts/commandline/lists/monkey-power-level.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Power mode...",
configKey: "monkeyPowerLevel",
list: [
@@ -37,7 +38,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "monkeyPower",
display: "Power mode...",
diff --git a/frontend/src/ts/commandline/lists/navigation.ts b/frontend/src/ts/commandline/lists/navigation.ts
index d9d7e1460..9750419dd 100644
--- a/frontend/src/ts/commandline/lists/navigation.ts
+++ b/frontend/src/ts/commandline/lists/navigation.ts
@@ -1,8 +1,9 @@
import { navigate } from "../../controllers/route-controller";
import { isAuthenticated } from "../../firebase";
import { toggleFullscreen } from "../../utils/misc";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "viewTypingPage",
display: "View Typing Page",
diff --git a/frontend/src/ts/commandline/lists/numbers.ts b/frontend/src/ts/commandline/lists/numbers.ts
index 26cee7546..77bb86262 100644
--- a/frontend/src/ts/commandline/lists/numbers.ts
+++ b/frontend/src/ts/commandline/lists/numbers.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Numbers...",
configKey: "numbers",
list: [
@@ -26,7 +27,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeNumbers",
display: "Numbers...",
diff --git a/frontend/src/ts/commandline/lists/opposite-shift-mode.ts b/frontend/src/ts/commandline/lists/opposite-shift-mode.ts
index 507ec9627..215923a81 100644
--- a/frontend/src/ts/commandline/lists/opposite-shift-mode.ts
+++ b/frontend/src/ts/commandline/lists/opposite-shift-mode.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as ModesNotice from "./../../elements/modes-notice";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Change opposite shift mode...",
configKey: "oppositeShiftMode",
list: [
@@ -35,7 +36,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeOppositeShiftMode",
display: "Change opposite shift mode...",
diff --git a/frontend/src/ts/commandline/lists/out-of-focus-warning.ts b/frontend/src/ts/commandline/lists/out-of-focus-warning.ts
index 36c3e0fa7..14a1d491d 100644
--- a/frontend/src/ts/commandline/lists/out-of-focus-warning.ts
+++ b/frontend/src/ts/commandline/lists/out-of-focus-warning.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Colorful mode...",
configKey: "showOutOfFocusWarning",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeOutOfFocusWarning",
display: "Out of focus warning...",
diff --git a/frontend/src/ts/commandline/lists/pace-caret-style.ts b/frontend/src/ts/commandline/lists/pace-caret-style.ts
index f7db6e19a..92e70d497 100644
--- a/frontend/src/ts/commandline/lists/pace-caret-style.ts
+++ b/frontend/src/ts/commandline/lists/pace-caret-style.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Change pace caret style...",
configKey: "paceCaretStyle",
list: [
@@ -65,7 +66,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changePaceCaretStyle",
display: "Pace caret style...",
diff --git a/frontend/src/ts/commandline/lists/pace-caret.ts b/frontend/src/ts/commandline/lists/pace-caret.ts
index 98be56512..c7b2d9b66 100644
--- a/frontend/src/ts/commandline/lists/pace-caret.ts
+++ b/frontend/src/ts/commandline/lists/pace-caret.ts
@@ -1,8 +1,9 @@
import Config, * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
import { get as getTypingSpeedUnit } from "../../utils/typing-speed-units";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Pace caret mode...",
configKey: "paceCaret",
list: [
@@ -78,7 +79,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changePaceCaret",
display: "Pace caret mode...",
diff --git a/frontend/src/ts/commandline/lists/presets.ts b/frontend/src/ts/commandline/lists/presets.ts
index 0f2b8843c..552440a6f 100644
--- a/frontend/src/ts/commandline/lists/presets.ts
+++ b/frontend/src/ts/commandline/lists/presets.ts
@@ -4,8 +4,9 @@ import * as Settings from "../../pages/settings";
import * as PresetController from "../../controllers/preset-controller";
import * as EditPresetPopup from "../../modals/edit-preset";
import { isAuthenticated } from "../../firebase";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Presets...",
list: [],
beforeList: (): void => {
@@ -13,7 +14,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
},
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
visible: false,
id: "applyPreset",
@@ -30,7 +31,7 @@ function update(): void {
const snapshot = DB.getSnapshot();
subgroup.list = [];
if (!snapshot?.presets || snapshot.presets.length === 0) return;
- snapshot.presets.forEach((preset: MonkeyTypes.SnapshotPreset) => {
+ snapshot.presets.forEach((preset) => {
const dis = preset.display;
subgroup.list.push({
diff --git a/frontend/src/ts/commandline/lists/punctuation.ts b/frontend/src/ts/commandline/lists/punctuation.ts
index 4bef072ca..d99fc528f 100644
--- a/frontend/src/ts/commandline/lists/punctuation.ts
+++ b/frontend/src/ts/commandline/lists/punctuation.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changePunctuation",
display: "Punctuation...",
diff --git a/frontend/src/ts/commandline/lists/quick-end.ts b/frontend/src/ts/commandline/lists/quick-end.ts
index 4ff21385f..409d5b37a 100644
--- a/frontend/src/ts/commandline/lists/quick-end.ts
+++ b/frontend/src/ts/commandline/lists/quick-end.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Quick end...",
configKey: "quickEnd",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeQuickEnd",
display: "Quick end...",
diff --git a/frontend/src/ts/commandline/lists/quick-restart.ts b/frontend/src/ts/commandline/lists/quick-restart.ts
index 803a16fbf..7cab7f657 100644
--- a/frontend/src/ts/commandline/lists/quick-restart.ts
+++ b/frontend/src/ts/commandline/lists/quick-restart.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Quick restart...",
configKey: "quickRestart",
list: [
@@ -39,7 +40,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeQuickRestart",
display: "Quick restart...",
diff --git a/frontend/src/ts/commandline/lists/quote-favorites.ts b/frontend/src/ts/commandline/lists/quote-favorites.ts
index 5a859a0bb..38149266b 100644
--- a/frontend/src/ts/commandline/lists/quote-favorites.ts
+++ b/frontend/src/ts/commandline/lists/quote-favorites.ts
@@ -1,12 +1,13 @@
import Config from "../../config";
-import QuotesController from "../../controllers/quotes-controller";
+import QuotesController, { Quote } from "../../controllers/quotes-controller";
import * as Notifications from "../../elements/notifications";
import { isAuthenticated } from "../../firebase";
import { createErrorMessage } from "../../utils/misc";
import * as Loader from "../../elements/loader";
import * as TestWords from "../../test/test-words";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "addQuoteToFavorite",
display: "Add current quote to favorite",
@@ -24,7 +25,7 @@ const commands: MonkeyTypes.Command[] = [
try {
Loader.show();
await QuotesController.setQuoteFavorite(
- TestWords.currentQuote as MonkeyTypes.QuoteWithTextSplit,
+ TestWords.currentQuote as Quote,
true
);
Loader.hide();
@@ -56,7 +57,7 @@ const commands: MonkeyTypes.Command[] = [
try {
Loader.show();
await QuotesController.setQuoteFavorite(
- TestWords.currentQuote as MonkeyTypes.QuoteWithTextSplit,
+ TestWords.currentQuote as Quote,
false
);
Loader.hide();
diff --git a/frontend/src/ts/commandline/lists/quote-length.ts b/frontend/src/ts/commandline/lists/quote-length.ts
index 7b1f5fdde..49b2b7c03 100644
--- a/frontend/src/ts/commandline/lists/quote-length.ts
+++ b/frontend/src/ts/commandline/lists/quote-length.ts
@@ -1,8 +1,9 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
import { isAuthenticated } from "../../firebase";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeQuoteLength",
display: "Quote length...",
diff --git a/frontend/src/ts/commandline/lists/random-theme.ts b/frontend/src/ts/commandline/lists/random-theme.ts
index c2b29cae7..2fba39b80 100644
--- a/frontend/src/ts/commandline/lists/random-theme.ts
+++ b/frontend/src/ts/commandline/lists/random-theme.ts
@@ -1,8 +1,9 @@
import * as UpdateConfig from "../../config";
import { isAuthenticated } from "../../firebase";
import * as Notifications from "../../elements/notifications";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Random theme...",
configKey: "randomTheme",
list: [
@@ -64,7 +65,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeRandomTheme",
display: "Random theme...",
diff --git a/frontend/src/ts/commandline/lists/repeat-quotes.ts b/frontend/src/ts/commandline/lists/repeat-quotes.ts
index 3265f9e44..fc788350f 100644
--- a/frontend/src/ts/commandline/lists/repeat-quotes.ts
+++ b/frontend/src/ts/commandline/lists/repeat-quotes.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Repeat quotes...",
configKey: "repeatQuotes",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeRepeatQuotes",
display: "Repeat quotes...",
diff --git a/frontend/src/ts/commandline/lists/repeated-pace.ts b/frontend/src/ts/commandline/lists/repeated-pace.ts
index d4eab1042..b1b44ce91 100644
--- a/frontend/src/ts/commandline/lists/repeated-pace.ts
+++ b/frontend/src/ts/commandline/lists/repeated-pace.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Repeated pace...",
configKey: "repeatedPace",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeRepeatedPace",
display: "Repeated pace...",
diff --git a/frontend/src/ts/commandline/lists/result-saving.ts b/frontend/src/ts/commandline/lists/result-saving.ts
index 9ff3913e9..acf1d9600 100644
--- a/frontend/src/ts/commandline/lists/result-saving.ts
+++ b/frontend/src/ts/commandline/lists/result-saving.ts
@@ -1,7 +1,8 @@
import * as TestState from "../../test/test-state";
import * as ModesNotice from "../../elements/modes-notice";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Result saving...",
list: [
{
@@ -25,7 +26,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "setResultSaving",
display: "Result saving...",
diff --git a/frontend/src/ts/commandline/lists/result-screen.ts b/frontend/src/ts/commandline/lists/result-screen.ts
index 9c5cc6a02..2c9e3ae66 100644
--- a/frontend/src/ts/commandline/lists/result-screen.ts
+++ b/frontend/src/ts/commandline/lists/result-screen.ts
@@ -6,8 +6,9 @@ import * as TestInput from "../../test/test-input";
import * as TestWords from "../../test/test-words";
import Config from "../../config";
import * as PractiseWords from "../../test/practise-words";
+import { Command, CommandsSubgroup } from "../types";
-const practiceSubgroup: MonkeyTypes.CommandsSubgroup = {
+const practiceSubgroup: CommandsSubgroup = {
title: "Practice words...",
list: [
{
@@ -43,7 +44,7 @@ const practiceSubgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "nextTest",
display: "Next test",
diff --git a/frontend/src/ts/commandline/lists/show-all-lines.ts b/frontend/src/ts/commandline/lists/show-all-lines.ts
index e631fc47d..7b463bca9 100644
--- a/frontend/src/ts/commandline/lists/show-all-lines.ts
+++ b/frontend/src/ts/commandline/lists/show-all-lines.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Show all lines...",
configKey: "showAllLines",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeShowAllLines",
display: "Show all lines...",
diff --git a/frontend/src/ts/commandline/lists/show-average.ts b/frontend/src/ts/commandline/lists/show-average.ts
index f2738d3b9..5d89a09cd 100644
--- a/frontend/src/ts/commandline/lists/show-average.ts
+++ b/frontend/src/ts/commandline/lists/show-average.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Show average...",
configKey: "showAverage",
list: [
@@ -39,7 +40,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeShowAverage",
display: "Show average...",
diff --git a/frontend/src/ts/commandline/lists/show-words-history.ts b/frontend/src/ts/commandline/lists/show-words-history.ts
index 0fa479ae3..59e4a7046 100644
--- a/frontend/src/ts/commandline/lists/show-words-history.ts
+++ b/frontend/src/ts/commandline/lists/show-words-history.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Always show words history...",
configKey: "alwaysShowWordsHistory",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeShowWordsHistory",
display: "Always show words history...",
diff --git a/frontend/src/ts/commandline/lists/single-list-commandline.ts b/frontend/src/ts/commandline/lists/single-list-commandline.ts
index 6f4723ea5..cfaa97905 100644
--- a/frontend/src/ts/commandline/lists/single-list-commandline.ts
+++ b/frontend/src/ts/commandline/lists/single-list-commandline.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Single list command line...",
configKey: "singleListCommandLine",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "singleListCommandLine",
display: "Single list command line...",
diff --git a/frontend/src/ts/commandline/lists/smooth-caret.ts b/frontend/src/ts/commandline/lists/smooth-caret.ts
index 437ad7191..d3cea716d 100644
--- a/frontend/src/ts/commandline/lists/smooth-caret.ts
+++ b/frontend/src/ts/commandline/lists/smooth-caret.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Smooth caret...",
configKey: "smoothCaret",
list: [
@@ -39,7 +40,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeSmoothCaret",
display: "Smooth caret...",
diff --git a/frontend/src/ts/commandline/lists/smooth-line-scroll.ts b/frontend/src/ts/commandline/lists/smooth-line-scroll.ts
index 6f167f147..feed43c45 100644
--- a/frontend/src/ts/commandline/lists/smooth-line-scroll.ts
+++ b/frontend/src/ts/commandline/lists/smooth-line-scroll.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Smooth line scroll...",
configKey: "smoothLineScroll",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeSmoothLineScroll",
display: "Smooth line scroll...",
diff --git a/frontend/src/ts/commandline/lists/sound-on-click.ts b/frontend/src/ts/commandline/lists/sound-on-click.ts
index fb85cf7ee..187299ce5 100644
--- a/frontend/src/ts/commandline/lists/sound-on-click.ts
+++ b/frontend/src/ts/commandline/lists/sound-on-click.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as SoundController from "../../controllers/sound-controller";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Sound on click...",
configKey: "playSoundOnClick",
list: [
@@ -196,7 +197,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeSoundOnClick",
display: "Sound on click...",
diff --git a/frontend/src/ts/commandline/lists/sound-on-error.ts b/frontend/src/ts/commandline/lists/sound-on-error.ts
index c04f017fb..c6c6e53ed 100644
--- a/frontend/src/ts/commandline/lists/sound-on-error.ts
+++ b/frontend/src/ts/commandline/lists/sound-on-error.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as SoundController from "../../controllers/sound-controller";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Sound on error...",
configKey: "playSoundOnError",
list: [
@@ -64,7 +65,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeSoundOnError",
display: "Sound on error...",
diff --git a/frontend/src/ts/commandline/lists/sound-volume.ts b/frontend/src/ts/commandline/lists/sound-volume.ts
index 2cac406b8..7009ec34c 100644
--- a/frontend/src/ts/commandline/lists/sound-volume.ts
+++ b/frontend/src/ts/commandline/lists/sound-volume.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as SoundController from "../../controllers/sound-controller";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Sound volume...",
configKey: "soundVolume",
list: [
@@ -45,7 +46,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeSoundVolume",
display: "Sound volume...",
diff --git a/frontend/src/ts/commandline/lists/start-graphs-at-zero.ts b/frontend/src/ts/commandline/lists/start-graphs-at-zero.ts
index 9ecd2d3c4..780bc42e1 100644
--- a/frontend/src/ts/commandline/lists/start-graphs-at-zero.ts
+++ b/frontend/src/ts/commandline/lists/start-graphs-at-zero.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Start graphs at zero...",
configKey: "startGraphsAtZero",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeStartGraphsAtZero",
display: "Start graphs at zero...",
diff --git a/frontend/src/ts/commandline/lists/stop-on-error.ts b/frontend/src/ts/commandline/lists/stop-on-error.ts
index d0f8cf5df..e979f5cf6 100644
--- a/frontend/src/ts/commandline/lists/stop-on-error.ts
+++ b/frontend/src/ts/commandline/lists/stop-on-error.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeStopOnError",
display: "Stop on error...",
diff --git a/frontend/src/ts/commandline/lists/strict-space.ts b/frontend/src/ts/commandline/lists/strict-space.ts
index 36d1f1d03..2dd822eb5 100644
--- a/frontend/src/ts/commandline/lists/strict-space.ts
+++ b/frontend/src/ts/commandline/lists/strict-space.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Strict space...",
configKey: "strictSpace",
list: [
@@ -23,7 +24,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeStrictSpace",
display: "Strict space...",
diff --git a/frontend/src/ts/commandline/lists/tags.ts b/frontend/src/ts/commandline/lists/tags.ts
index 377f2fc86..52d789987 100644
--- a/frontend/src/ts/commandline/lists/tags.ts
+++ b/frontend/src/ts/commandline/lists/tags.ts
@@ -5,8 +5,9 @@ import * as TagController from "../../controllers/tag-controller";
import Config from "../../config";
import * as PaceCaret from "../../test/pace-caret";
import { isAuthenticated } from "../../firebase";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Change tags...",
list: [],
beforeList: (): void => {
@@ -14,7 +15,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
},
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeTags",
display: "Tags...",
diff --git a/frontend/src/ts/commandline/lists/tape-mode.ts b/frontend/src/ts/commandline/lists/tape-mode.ts
index 26577f0d6..7b7f09d08 100644
--- a/frontend/src/ts/commandline/lists/tape-mode.ts
+++ b/frontend/src/ts/commandline/lists/tape-mode.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Tape mode...",
configKey: "tapeMode",
list: [
@@ -31,7 +32,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeTapeMode",
display: "Tape mode...",
diff --git a/frontend/src/ts/commandline/lists/themes.ts b/frontend/src/ts/commandline/lists/themes.ts
index 58bc1de05..ad3a05532 100644
--- a/frontend/src/ts/commandline/lists/themes.ts
+++ b/frontend/src/ts/commandline/lists/themes.ts
@@ -1,14 +1,16 @@
import Config, * as UpdateConfig from "../../config";
import { capitalizeFirstLetterOfEachWord } from "../../utils/strings";
import * as ThemeController from "../../controllers/theme-controller";
+import { Command, CommandsSubgroup } from "../types";
+import { Theme } from "../../utils/json-data";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Theme...",
configKey: "theme",
list: [],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeTheme",
display: "Theme...",
@@ -17,9 +19,9 @@ const commands: MonkeyTypes.Command[] = [
},
];
-function update(themes: MonkeyTypes.Theme[]): void {
+function update(themes: Theme[]): void {
subgroup.list = [];
- const favs: MonkeyTypes.Command[] = [];
+ const favs: Command[] = [];
themes.forEach((theme) => {
if (Config.favThemes.includes(theme.name)) {
favs.push({
diff --git a/frontend/src/ts/commandline/lists/time.ts b/frontend/src/ts/commandline/lists/time.ts
index 34416071e..f96b5d88f 100644
--- a/frontend/src/ts/commandline/lists/time.ts
+++ b/frontend/src/ts/commandline/lists/time.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeTimeConfig",
display: "Time...",
diff --git a/frontend/src/ts/commandline/lists/timer-color.ts b/frontend/src/ts/commandline/lists/timer-color.ts
index ee272a3d2..cdeb6ac50 100644
--- a/frontend/src/ts/commandline/lists/timer-color.ts
+++ b/frontend/src/ts/commandline/lists/timer-color.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Live stats color...",
configKey: "timerColor",
list: [
@@ -43,7 +44,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeTimerColor",
display: "Live stats color...",
diff --git a/frontend/src/ts/commandline/lists/timer-opacity.ts b/frontend/src/ts/commandline/lists/timer-opacity.ts
index 38897fdce..365cd0272 100644
--- a/frontend/src/ts/commandline/lists/timer-opacity.ts
+++ b/frontend/src/ts/commandline/lists/timer-opacity.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Live stats opacity...",
configKey: "timerOpacity",
list: [
@@ -43,7 +44,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeTimerOpacity",
display: "Live stats opacity...",
diff --git a/frontend/src/ts/commandline/lists/timer-style.ts b/frontend/src/ts/commandline/lists/timer-style.ts
index b79c6ee02..0c3c33b45 100644
--- a/frontend/src/ts/commandline/lists/timer-style.ts
+++ b/frontend/src/ts/commandline/lists/timer-style.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Live progress style...",
configKey: "timerStyle",
list: [
@@ -39,7 +40,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeTimerStyle",
display: "Live progress style...",
diff --git a/frontend/src/ts/commandline/lists/typing-speed-unit.ts b/frontend/src/ts/commandline/lists/typing-speed-unit.ts
index d2884e058..abcd68c33 100644
--- a/frontend/src/ts/commandline/lists/typing-speed-unit.ts
+++ b/frontend/src/ts/commandline/lists/typing-speed-unit.ts
@@ -1,6 +1,7 @@
import * as UpdateConfig from "../../config";
+import { Command, CommandsSubgroup } from "../types";
-const subgroup: MonkeyTypes.CommandsSubgroup = {
+const subgroup: CommandsSubgroup = {
title: "Typing speed unit...",
configKey: "typingSpeedUnit",
list: [
@@ -48,7 +49,7 @@ const subgroup: MonkeyTypes.CommandsSubgroup = {
],
};
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeTypingSpeedUnit",
display: "Typing speed unit...",
diff --git a/frontend/src/ts/commandline/lists/words.ts b/frontend/src/ts/commandline/lists/words.ts
index b780f722e..154f10b09 100644
--- a/frontend/src/ts/commandline/lists/words.ts
+++ b/frontend/src/ts/commandline/lists/words.ts
@@ -1,7 +1,8 @@
import * as UpdateConfig from "../../config";
import * as TestLogic from "../../test/test-logic";
+import { Command } from "../types";
-const commands: MonkeyTypes.Command[] = [
+const commands: Command[] = [
{
id: "changeWordCount",
display: "Words...",
diff --git a/frontend/src/ts/commandline/types.ts b/frontend/src/ts/commandline/types.ts
new file mode 100644
index 000000000..4932b274d
--- /dev/null
+++ b/frontend/src/ts/commandline/types.ts
@@ -0,0 +1,42 @@
+import { Config } from "@monkeytype/contracts/schemas/configs";
+import AnimatedModal from "../utils/animated-modal";
+
+// this file is needed becauase otherwise it would produce a circular dependency
+
+export type CommandExecOptions = {
+ input?: string;
+ commandlineModal: AnimatedModal;
+};
+
+export type Command = {
+ id: string;
+ display: string;
+ singleListDisplay?: string;
+ singleListDisplayNoIcon?: string;
+ subgroup?: CommandsSubgroup;
+ found?: boolean;
+ icon?: string;
+ sticky?: boolean;
+ alias?: string;
+ input?: boolean;
+ visible?: boolean;
+ customStyle?: string;
+ opensModal?: boolean;
+ defaultValue?: () => string;
+ configKey?: keyof Config;
+ configValue?: string | number | boolean | number[];
+ configValueMode?: "include";
+ exec?: (options: CommandExecOptions) => void;
+ hover?: () => void;
+ available?: () => boolean;
+ active?: () => boolean;
+ shouldFocusTestUI?: boolean;
+ customData?: Record<string, string | boolean>;
+};
+
+export type CommandsSubgroup = {
+ title: string;
+ configKey?: keyof Config;
+ list: Command[];
+ beforeList?: () => void;
+};
diff --git a/frontend/src/ts/config.ts b/frontend/src/ts/config.ts
index 381b1c7a9..441f7078e 100644
--- a/frontend/src/ts/config.ts
+++ b/frontend/src/ts/config.ts
@@ -1831,7 +1831,7 @@ export function setCustomBackground(
}
export async function setCustomLayoutfluid(
- value: MonkeyTypes.CustomLayoutFluidSpaces,
+ value: ConfigSchemas.CustomLayoutFluid,
nosave?: boolean
): Promise<boolean> {
const trimmed = value.trim();
@@ -1932,7 +1932,7 @@ export function setBurstHeatmap(value: boolean, nosave?: boolean): boolean {
}
export async function apply(
- configToApply: Config | MonkeyTypes.ConfigChanges
+ configToApply: Config | Partial<Config>
): Promise<void> {
if (configToApply === undefined) return;
@@ -2064,8 +2064,8 @@ export async function loadFromLocalStorage(): Promise<void> {
loadDone();
}
-export function getConfigChanges(): MonkeyTypes.ConfigChanges {
- const configChanges: MonkeyTypes.ConfigChanges = {};
+export function getConfigChanges(): Partial<Config> {
+ const configChanges: Partial<Config> = {};
typedKeys(config)
.filter((key) => {
return config[key] !== DefaultConfig[key];
diff --git a/frontend/src/ts/constants/default-snapshot.ts b/frontend/src/ts/constants/default-snapshot.ts
index 28737c9c1..0f26c07db 100644
--- a/frontend/src/ts/constants/default-snapshot.ts
+++ b/frontend/src/ts/constants/default-snapshot.ts
@@ -1,6 +1,7 @@
+import { deepClone } from "../utils/misc";
import defaultConfig from "./default-config";
-export const defaultSnap: MonkeyTypes.Snapshot = {
+const defaultSnap = {
results: undefined,
personalBests: {
time: {},
@@ -42,3 +43,5 @@ export const defaultSnap: MonkeyTypes.Snapshot = {
},
},
};
+
+export default deepClone(defaultSnap);
diff --git a/frontend/src/ts/controllers/account-controller.ts b/frontend/src/ts/controllers/account-controller.ts
index cbcee49f3..78291adf4 100644
--- a/frontend/src/ts/controllers/account-controller.ts
+++ b/frontend/src/ts/controllers/account-controller.ts
@@ -122,7 +122,7 @@ async function getDataAndInit(): Promise<boolean> {
LoadingPage.updateBar(45);
}
LoadingPage.updateText("Applying settings...");
- const snapshot = DB.getSnapshot() as MonkeyTypes.Snapshot;
+ const snapshot = DB.getSnapshot() as DB.Snapshot;
AccountButton.update(snapshot);
Alerts.setNotificationBubbleVisible(snapshot.inboxUnreadSize > 0);
showFavoriteQuoteLength();
diff --git a/frontend/src/ts/controllers/badge-controller.ts b/frontend/src/ts/controllers/badge-controller.ts
index 1bea8ad6d..79b137d36 100644
--- a/frontend/src/ts/controllers/badge-controller.ts
+++ b/frontend/src/ts/controllers/badge-controller.ts
@@ -1,4 +1,14 @@
-const badges: Record<number, MonkeyTypes.UserBadge> = {
+type UserBadge = {
+ id: number;
+ name: string;
+ description: string;
+ icon?: string;
+ background?: string;
+ color?: string;
+ customStyle?: string;
+};
+
+const badges: Record<number, UserBadge> = {
1: {
id: 1,
name: "Developer",
@@ -119,7 +129,7 @@ export function getHTMLById(
noBalloon = false,
showUnknown = false
): string {
- const badge = badges[id] as MonkeyTypes.UserBadge | undefined;
+ const badge = badges[id] as UserBadge | undefined;
if (!badge && !showUnknown) {
return "";
@@ -160,6 +170,6 @@ export function getHTMLById(
}</div>`;
}
-export function getById(id: number): MonkeyTypes.UserBadge | undefined {
+export function getById(id: number): UserBadge | undefined {
return badges[id];
}
diff --git a/frontend/src/ts/controllers/chart-controller.ts b/frontend/src/ts/controllers/chart-controller.ts
index c64826130..87acaa697 100644
--- a/frontend/src/ts/controllers/chart-controller.ts
+++ b/frontend/src/ts/controllers/chart-controller.ts
@@ -269,11 +269,41 @@ export const result = new ChartWithUpdateColors<
export let accountHistoryActiveIndex: number;
+export type HistoryChartData = {
+ x: number;
+ y: number;
+ wpm: number;
+ acc: number;
+ mode: string;
+ mode2: string;
+ punctuation: boolean;
+ language: string;
+ timestamp: number;
+ difficulty: string;
+ raw: number;
+ isPb: boolean;
+};
+
+export type AccChartData = {
+ x: number;
+ y: number;
+ errorRate: number;
+};
+
+export type OtherChartData = {
+ x: number;
+ y: number;
+};
+
+export type ActivityChartDataPoint = {
+ x: number;
+ y: number;
+ amount?: number;
+};
+
export const accountHistory = new ChartWithUpdateColors<
"line",
- | MonkeyTypes.HistoryChartData[]
- | MonkeyTypes.AccChartData[]
- | MonkeyTypes.OtherChartData[],
+ HistoryChartData[] | AccChartData[] | OtherChartData[],
string,
| "wpm"
| "pb"
@@ -500,14 +530,14 @@ export const accountHistory = new ChartWithUpdateColors<
if (tooltipItem.datasetIndex !== 0) {
const resultData = tooltipItem.dataset.data[
tooltipItem.dataIndex
- ] as MonkeyTypes.AccChartData;
+ ] as AccChartData;
return `error rate: ${Numbers.roundTo2(
resultData.errorRate
)}%\nacc: ${Numbers.roundTo2(100 - resultData.errorRate)}%`;
}
const resultData = tooltipItem.dataset.data[
tooltipItem.dataIndex
- ] as MonkeyTypes.HistoryChartData;
+ ] as HistoryChartData;
let label =
`${Config.typingSpeedUnit}: ${resultData.wpm}` +
"\n" +
@@ -559,7 +589,7 @@ export const accountHistory = new ChartWithUpdateColors<
export const accountActivity = new ChartWithUpdateColors<
"bar" | "line",
- MonkeyTypes.ActivityChartDataPoint[],
+ ActivityChartDataPoint[],
string,
"count" | "avgWpm"
>(
@@ -670,13 +700,13 @@ export const accountActivity = new ChartWithUpdateColors<
const firstItem = tooltipItem[0] as TooltipItem<"bar" | "line">;
const resultData = firstItem.dataset.data[
firstItem.dataIndex
- ] as MonkeyTypes.ActivityChartDataPoint;
+ ] as ActivityChartDataPoint;
return format(new Date(resultData.x), "dd MMM yyyy");
},
beforeLabel: function (tooltipItem): string {
const resultData = tooltipItem.dataset.data[
tooltipItem.dataIndex
- ] as MonkeyTypes.ActivityChartDataPoint;
+ ] as ActivityChartDataPoint;
switch (tooltipItem.datasetIndex) {
case 0:
return `Time Typing: ${DateTime.secondsToString(
@@ -704,7 +734,7 @@ export const accountActivity = new ChartWithUpdateColors<
export const accountHistogram = new ChartWithUpdateColors<
"bar",
- MonkeyTypes.ActivityChartDataPoint[],
+ ActivityChartDataPoint[],
string,
"count"
>(
@@ -807,7 +837,7 @@ export const accountHistogram = new ChartWithUpdateColors<
export const globalSpeedHistogram = new ChartWithUpdateColors<
"bar",
- MonkeyTypes.ActivityChartDataPoint[],
+ ActivityChartDataPoint[],
string,
"count"
>(
@@ -1102,9 +1132,9 @@ function updateAverage100(updateChart = true): void {
async function updateColors<
TType extends ChartType = "bar" | "line" | "scatter",
TData =
- | MonkeyTypes.HistoryChartData[]
- | MonkeyTypes.AccChartData[]
- | MonkeyTypes.ActivityChartDataPoint[]
+ | HistoryChartData[]
+ | AccChartData[]
+ | ActivityChartDataPoint[]
| number[],
TLabel = string
>(chart: ChartWithUpdateColors<TType, TData, TLabel>): Promise<void> {
diff --git a/frontend/src/ts/controllers/page-controller.ts b/frontend/src/ts/controllers/page-controller.ts
index e38309051..1e90ccd11 100644
--- a/frontend/src/ts/controllers/page-controller.ts
+++ b/frontend/src/ts/controllers/page-controller.ts
@@ -14,6 +14,7 @@ import * as PageAccountSettings from "../pages/account-settings";
import * as PageTransition from "../states/page-transition";
import * as AdController from "../controllers/ad-controller";
import * as Focus from "../test/focus";
+import { PageName } from "../pages/page";
type ChangeOptions = {
force?: boolean;
@@ -22,7 +23,7 @@ type ChangeOptions = {
};
export async function change(
- pageName: MonkeyTypes.PageName,
+ pageName: PageName,
options = {} as ChangeOptions
): Promise<boolean> {
const defaultOptions = {
diff --git a/frontend/src/ts/controllers/preset-controller.ts b/frontend/src/ts/controllers/preset-controller.ts
index 1198ec40c..b8afa1cfd 100644
--- a/frontend/src/ts/controllers/preset-controller.ts
+++ b/frontend/src/ts/controllers/preset-controller.ts
@@ -41,7 +41,7 @@ export async function apply(_id: string): Promise<void> {
});
UpdateConfig.saveFullConfigToLocalStorage();
}
-function isPartialPreset(preset: MonkeyTypes.SnapshotPreset): boolean {
+function isPartialPreset(preset: DB.SnapshotPreset): boolean {
return preset.settingGroups !== undefined && preset.settingGroups !== null;
}
diff --git a/frontend/src/ts/controllers/quotes-controller.ts b/frontend/src/ts/controllers/quotes-controller.ts
index 71bc025b9..a0cbacdc0 100644
--- a/frontend/src/ts/controllers/quotes-controller.ts
+++ b/frontend/src/ts/controllers/quotes-controller.ts
@@ -5,25 +5,38 @@ import { subscribe } from "../observables/config-event";
import * as DB from "../db";
import Ape from "../ape";
-type JsonQuote = {
+export type Quote = {
text: string;
britishText?: string;
source: string;
length: number;
id: number;
+ group: number;
+ language: string;
+ textSplit?: string[];
+};
+
+export type QuoteWithTextSplit = Quote & {
+ textSplit: string[];
};
type QuoteData = {
language: string;
- quotes: JsonQuote[];
+ quotes: {
+ text: string;
+ britishText?: string;
+ source: string;
+ length: number;
+ id: number;
+ }[];
groups: [number, number][];
};
type QuoteCollection = {
- quotes: MonkeyTypes.Quote[];
+ quotes: Quote[];
length: number;
language: string | null;
- groups: MonkeyTypes.Quote[][];
+ groups: Quote[][];
};
const defaultQuoteCollection: QuoteCollection = {
@@ -36,7 +49,7 @@ const defaultQuoteCollection: QuoteCollection = {
class QuotesController {
private quoteCollection: QuoteCollection = defaultQuoteCollection;
- private quoteQueue: MonkeyTypes.Quote[] = [];
+ private quoteQueue: Quote[] = [];
private queueIndex = 0;
async getQuotes(
@@ -71,8 +84,8 @@ class QuotesController {
};
// Transform JSON Quote schema to MonkeyTypes Quote schema
- data.quotes.forEach((quote: JsonQuote) => {
- const monkeyTypeQuote: MonkeyTypes.Quote = {
+ data.quotes.forEach((quote) => {
+ const monkeyTypeQuote: Quote = {
text: quote.text,
britishText: quote.britishText,
source: quote.source,
@@ -107,12 +120,10 @@ class QuotesController {
return this.quoteCollection;
}
- getQuoteById(id: number): MonkeyTypes.Quote | undefined {
- const targetQuote = this.quoteCollection.quotes.find(
- (quote: MonkeyTypes.Quote) => {
- return quote.id === id;
- }
- );
+ getQuoteById(id: number): Quote | undefined {
+ const targetQuote = this.quoteCollection.quotes.find((quote: Quote) => {
+ return quote.id === id;
+ });
return targetQuote;
}
@@ -133,7 +144,7 @@ class QuotesController {
this.queueIndex = 0;
}
- getRandomQuote(): MonkeyTypes.Quote | null {
+ getRandomQuote(): Quote | null {
if (this.quoteQueue.length === 0) {
return null;
}
@@ -143,14 +154,14 @@ class QuotesController {
shuffle(this.quoteQueue);
}
- const randomQuote = this.quoteQueue[this.queueIndex] as MonkeyTypes.Quote;
+ const randomQuote = this.quoteQueue[this.queueIndex] as Quote;
this.queueIndex += 1;
return randomQuote;
}
- getRandomFavoriteQuote(language: string): MonkeyTypes.Quote | null {
+ getRandomFavoriteQuote(language: string): Quote | null {
const snapshot = DB.getSnapshot();
if (!snapshot) {
return null;
@@ -182,7 +193,7 @@ class QuotesController {
return randomQuote ?? null;
}
- isQuoteFavorite({ language: quoteLanguage, id }: MonkeyTypes.Quote): boolean {
+ isQuoteFavorite({ language: quoteLanguage, id }: Quote): boolean {
const snapshot = DB.getSnapshot();
if (!snapshot) {
return false;
@@ -206,10 +217,7 @@ class QuotesController {
return matchedLanguage !== undefined;
}
- async setQuoteFavorite(
- quote: MonkeyTypes.Quote,
- isFavorite: boolean
- ): Promise<void> {
+ async setQuoteFavorite(quote: Quote, isFavorite: boolean): Promise<void> {
const snapshot = DB.getSnapshot();
if (!snapshot) {
throw new Error("Snapshot is not available");
diff --git a/frontend/src/ts/db.ts b/frontend/src/ts/db.ts
index b1618839a..18f9dabd2 100644
--- a/frontend/src/ts/db.ts
+++ b/frontend/src/ts/db.ts
@@ -3,7 +3,6 @@ import * as Notifications from "./elements/notifications";
import * as LoadingPage from "./pages/loading";
import DefaultConfig from "./constants/default-config";
import { isAuthenticated } from "./firebase";
-import { defaultSnap } from "./constants/default-snapshot";
import * as ConnectionState from "./states/connection";
import { lastElementFromArray } from "./utils/arrays";
import { getFunboxList } from "./utils/json-data";
@@ -15,7 +14,14 @@ import {
} from "./elements/test-activity-calendar";
import * as Loader from "./elements/loader";
-import { Badge } from "@monkeytype/contracts/schemas/users";
+import {
+ Badge,
+ CustomTheme,
+ ResultFilters,
+ User,
+ UserProfileDetails,
+ UserTag,
+} from "@monkeytype/contracts/schemas/users";
import { Config, Difficulty } from "@monkeytype/contracts/schemas/configs";
import {
Mode,
@@ -23,8 +29,86 @@ import {
PersonalBest,
PersonalBests,
} from "@monkeytype/contracts/schemas/shared";
-
-let dbSnapshot: MonkeyTypes.Snapshot | undefined;
+import { Preset } from "@monkeytype/contracts/schemas/presets";
+import defaultSnapshot from "./constants/default-snapshot";
+import { Result } from "@monkeytype/contracts/schemas/results";
+
+export type SnapshotUserTag = UserTag & {
+ active?: boolean;
+ display: string;
+};
+
+export type SnapshotResult<M extends Mode> = Omit<
+ Result<M>,
+ | "_id"
+ | "bailedOut"
+ | "blindMode"
+ | "lazyMode"
+ | "difficulty"
+ | "funbox"
+ | "language"
+ | "numbers"
+ | "punctuation"
+ | "quoteLength"
+ | "restartCount"
+ | "incompleteTestSeconds"
+ | "afkDuration"
+ | "tags"
+> & {
+ _id: string;
+ bailedOut: boolean;
+ blindMode: boolean;
+ lazyMode: boolean;
+ difficulty: string;
+ funbox: string;
+ language: string;
+ numbers: boolean;
+ punctuation: boolean;
+ quoteLength: number;
+ restartCount: number;
+ incompleteTestSeconds: number;
+ afkDuration: number;
+ tags: string[];
+};
+
+export type Snapshot = Omit<
+ User,
+ | "timeTyping"
+ | "startedTests"
+ | "completedTests"
+ | "profileDetails"
+ | "streak"
+ | "resultFilterPresets"
+ | "tags"
+ | "xp"
+ | "testActivity"
+> & {
+ typingStats: {
+ timeTyping: number;
+ startedTests: number;
+ completedTests: number;
+ };
+ details?: UserProfileDetails;
+ inboxUnreadSize: number;
+ streak: number;
+ maxStreak: number;
+ filterPresets: ResultFilters[];
+ isPremium: boolean;
+ streakHourOffset?: number;
+ config: Config;
+ tags: SnapshotUserTag[];
+ presets: SnapshotPreset[];
+ results?: SnapshotResult<Mode>[];
+ xp: number;
+ testActivity?: ModifiableTestActivityCalendar;
+ testActivityByYear?: { [key: string]: TestActivityCalendar };
+};
+
+export type SnapshotPreset = Preset & {
+ display: string;
+};
+
+let dbSnapshot: Snapshot | undefined;
export class SnapshotInitError extends Error {
constructor(message: string, public responseCode: number) {
@@ -34,13 +118,11 @@ export class SnapshotInitError extends Error {
}
}
-export function getSnapshot(): MonkeyTypes.Snapshot | undefined {
+export function getSnapshot(): Snapshot | undefined {
return dbSnapshot;
}
-export function setSnapshot(
- newSnapshot: MonkeyTypes.Snapshot | undefined
-): void {
+export function setSnapshot(newSnapshot: Snapshot | undefined): void {
const originalBanned = dbSnapshot?.banned;
const originalVerified = dbSnapshot?.verified;
const lbOptOut = dbSnapshot?.lbOptOut;
@@ -63,11 +145,9 @@ export function setSnapshot(
}
}
-export async function initSnapshot(): Promise<
- MonkeyTypes.Snapshot | number | boolean
-> {
+export async function initSnapshot(): Promise<Snapshot | number | boolean> {
//send api request with token that returns tags, presets, and data needed for snap
- const snap = { ...defaultSnap };
+ const snap = defaultSnapshot as Snapshot;
try {
if (!isAuthenticated()) return false;
// if (ActivePage.get() === "loading") {
@@ -241,24 +321,26 @@ export async function initSnapshot(): Promise<
...preset,
display: preset.name.replace(/_/gi, " "),
};
- }) as MonkeyTypes.SnapshotPreset[];
+ }) as SnapshotPreset[];
snap.presets = presetsWithDisplay;
- snap.presets = snap.presets?.sort((a, b) => {
- if (a.name > b.name) {
- return 1;
- } else if (a.name < b.name) {
- return -1;
- } else {
- return 0;
+ snap.presets = snap.presets?.sort(
+ (a: SnapshotPreset, b: SnapshotPreset) => {
+ if (a.name > b.name) {
+ return 1;
+ } else if (a.name < b.name) {
+ return -1;
+ } else {
+ return 0;
+ }
}
- });
+ );
}
dbSnapshot = snap;
return dbSnapshot;
} catch (e) {
- dbSnapshot = defaultSnap;
+ dbSnapshot = defaultSnapshot;
throw e;
}
}
@@ -290,29 +372,27 @@ export async function getUserResults(offset?: number): Promise<boolean> {
return false;
}
- const results: MonkeyTypes.FullResult<Mode>[] = response.body.data.map(
- (result) => {
- if (result.bailedOut === undefined) result.bailedOut = false;
- if (result.blindMode === undefined) result.blindMode = false;
- if (result.lazyMode === undefined) result.lazyMode = false;
- if (result.difficulty === undefined) result.difficulty = "normal";
- if (result.funbox === undefined) result.funbox = "none";
- if (result.language === undefined || result.language === null) {
- result.language = "english";
- }
- if (result.numbers === undefined) result.numbers = false;
- if (result.punctuation === undefined) result.punctuation = false;
- if (result.numbers === undefined) result.numbers = false;
- if (result.quoteLength === undefined) result.quoteLength = -1;
- if (result.restartCount === undefined) result.restartCount = 0;
- if (result.incompleteTestSeconds === undefined) {
- result.incompleteTestSeconds = 0;
- }
- if (result.afkDuration === undefined) result.afkDuration = 0;
- if (result.tags === undefined) result.tags = [];
- return result as MonkeyTypes.FullResult<Mode>;
+ const results: SnapshotResult<Mode>[] = response.body.data.map((result) => {
+ if (result.bailedOut === undefined) result.bailedOut = false;
+ if (result.blindMode === undefined) result.blindMode = false;
+ if (result.lazyMode === undefined) result.lazyMode = false;
+ if (result.difficulty === undefined) result.difficulty = "normal";
+ if (result.funbox === undefined) result.funbox = "none";
+ if (result.language === undefined || result.language === null) {
+ result.language = "english";
}
- );
+ if (result.numbers === undefined) result.numbers = false;
+ if (result.punctuation === undefined) result.punctuation = false;
+ if (result.numbers === undefined) result.numbers = false;
+ if (result.quoteLength === undefined) result.quoteLength = -1;
+ if (result.restartCount === undefined) result.restartCount = 0;
+ if (result.incompleteTestSeconds === undefined) {
+ result.incompleteTestSeconds = 0;
+ }
+ if (result.afkDuration === undefined) result.afkDuration = 0;
+ if (result.tags === undefined) result.tags = [];
+ return result as SnapshotResult<Mode>;
+ });
results?.sort((a, b) => b.timestamp - a.timestamp);
if (dbSnapshot.results !== undefined && dbSnapshot.results.length > 0) {
@@ -329,14 +409,12 @@ export async function getUserResults(offset?: number): Promise<boolean> {
return true;
}
-function _getCustomThemeById(
- themeID: string
-): MonkeyTypes.CustomTheme | undefined {
+function _getCustomThemeById(themeID: string): CustomTheme | undefined {
return dbSnapshot?.customThemes?.find((t) => t._id === themeID);
}
export async function addCustomTheme(
- theme: MonkeyTypes.RawCustomTheme
+ theme: Omit<CustomTheme, "_id">
): Promise<boolean> {
if (!dbSnapshot) return false;
@@ -363,7 +441,7 @@ export async function addCustomTheme(
return false;
}
- const newCustomTheme: MonkeyTypes.CustomTheme = {
+ const newCustomTheme: CustomTheme = {
...theme,
_id: response.body.data._id,
};
@@ -374,7 +452,7 @@ export async function addCustomTheme(
export async function editCustomTheme(
themeId: string,
- newTheme: MonkeyTypes.RawCustomTheme
+ newTheme: Omit<CustomTheme, "_id">
): Promise<boolean> {
if (!isAuthenticated()) return false;
if (!dbSnapshot) return false;
@@ -403,7 +481,7 @@ export async function editCustomTheme(
return false;
}
- const newCustomTheme: MonkeyTypes.CustomTheme = {
+ const newCustomTheme: CustomTheme = {
...newTheme,
_id: themeId,
};
@@ -476,7 +554,7 @@ export async function getUserAverage10<M extends Mode>(
(result.lazyMode === lazyMode ||
(result.lazyMode === undefined && !lazyMode)) &&
(activeTagIds.length === 0 ||
- activeTagIds.some((tagId) => result.tags.includes(tagId)))
+ activeTagIds.some((tagId) => result.tags?.includes(tagId)))
) {
// Continue if the mode2 doesn't match and it's not a quote
if (
@@ -556,7 +634,7 @@ export async function getUserDailyBest<M extends Mode>(
(result.lazyMode === lazyMode ||
(result.lazyMode === undefined && !lazyMode)) &&
(activeTagIds.length === 0 ||
- activeTagIds.some((tagId) => result.tags.includes(tagId)))
+ activeTagIds.some((tagId) => result.tags?.includes(tagId)))
) {
if (result.timestamp < Date.now() - 86400000) {
continue;
@@ -797,7 +875,7 @@ export async function saveLocalTagPB<M extends Mode>(
function cont(): void {
const filteredtag = dbSnapshot?.tags?.filter(
(t) => t._id === tagId
- )[0] as MonkeyTypes.UserTag;
+ )[0] as SnapshotUserTag;
filteredtag.personalBests ??= {
time: {},
@@ -945,7 +1023,7 @@ export async function resetConfig(): Promise<void> {
}
}
-export function saveLocalResult(result: MonkeyTypes.FullResult<Mode>): void {
+export function saveLocalResult(result: SnapshotResult<Mode>): void {
const snapshot = getSnapshot();
if (!snapshot) return;
@@ -1018,7 +1096,7 @@ export function setStreak(streak: number): void {
export async function getTestActivityCalendar(
yearString: string
-): Promise<MonkeyTypes.TestActivityCalendar | undefined> {
+): Promise<TestActivityCalendar | undefined> {
if (!isAuthenticated() || dbSnapshot === undefined) return undefined;
if (yearString === "current") return dbSnapshot.testActivity;
diff --git a/frontend/src/ts/elements/account-button.ts b/frontend/src/ts/elements/account-button.ts
index be7085f19..80e2fe6f4 100644
--- a/frontend/src/ts/elements/account-button.ts
+++ b/frontend/src/ts/elements/account-button.ts
@@ -9,6 +9,7 @@ import {
} from "../controllers/user-flag-controller";
import { isAuthenticated } from "../firebase";
import { mapRange } from "@monkeytype/util/numbers";
+import { Snapshot } from "../db";
let usingAvatar = false;
@@ -154,11 +155,10 @@ export function updateAvatar(
}
}
-export function update(snapshot: MonkeyTypes.Snapshot | undefined): void {
+export function update(snapshot: Snapshot | undefined): void {
if (isAuthenticated()) {
// this function is called after the snapshot is loaded (awaited), so it should be fine
- const { xp, discordId, discordAvatar, name } =
- snapshot as MonkeyTypes.Snapshot;
+ const { xp, discordId, discordAvatar, name } = snapshot as Snapshot;
updateName(name);
updateFlags(snapshot ?? {});
diff --git a/frontend/src/ts/elements/account/result-filters.ts b/frontend/src/ts/elements/account/result-filters.ts
index 0c647bb41..d29c61a93 100644
--- a/frontend/src/ts/elements/account/result-filters.ts
+++ b/frontend/src/ts/elements/account/result-filters.ts
@@ -269,7 +269,7 @@ function setAllFilters(group: ResultFiltersGroup, value: boolean): void {
});
}
-export function loadTags(tags: MonkeyTypes.UserTag[]): void {
+export function loadTags(tags: DB.SnapshotUserTag[]): void {
tags.forEach((tag) => {
defaultResultFilters.tags[tag._id] = true;
});
@@ -601,14 +601,14 @@ $(".pageAccount .topFilters button.currentConfigFilter").on("click", () => {
filters.mode[Config.mode] = true;
if (Config.mode === "time") {
if ([15, 30, 60, 120].includes(Config.time)) {
- const configTime = Config.time as MonkeyTypes.DefaultTimeModes;
+ const configTime = `${Config.time}` as keyof typeof filters.time;
filters.time[configTime] = true;
} else {
filters.time.custom = true;
}
} else if (Config.mode === "words") {
if ([10, 25, 50, 100, 200].includes(Config.words)) {
- const configWords = Config.words as MonkeyTypes.DefaultWordsModes;
+ const configWords = `${Config.words}` as keyof typeof filters.words;
filters.words[configWords] = true;
} else {
filters.words.custom = true;
diff --git a/frontend/src/ts/elements/alerts.ts b/frontend/src/ts/elements/alerts.ts
index f48a2cfcf..beeac7356 100644
--- a/frontend/src/ts/elements/alerts.ts
+++ b/frontend/src/ts/elements/alerts.ts
@@ -10,8 +10,9 @@ import * as ConnectionState from "../states/connection";
import { escapeHTML } from "../utils/misc";
import AnimatedModal from "../utils/animated-modal";
import { updateXp as accountPageUpdateProfile } from "./profile";
+import { MonkeyMail } from "@monkeytype/contracts/schemas/users";
-let accountAlerts: MonkeyTypes.MonkeyMail[] = [];
+let accountAlerts: MonkeyMail[] = [];
let maxMail = 0;
let mailToMarkRead: string[] = [];
let mailToDelete: string[] = [];
diff --git a/frontend/src/ts/elements/keymap.ts b/frontend/src/ts/elements/keymap.ts
index c1259efca..e40bb536c 100644
--- a/frontend/src/ts/elements/keymap.ts
+++ b/frontend/src/ts/elements/keymap.ts
@@ -10,7 +10,7 @@ import * as Notifications from "../elements/notifications";
import * as ActivePage from "../states/active-page";
import * as TestWords from "../test/test-words";
-const stenoKeys: MonkeyTypes.Layout = {
+const stenoKeys: JSONData.Layout = {
keymapShowTopRow: true,
type: "matrix",
keys: {
@@ -171,7 +171,7 @@ export async function refresh(
const rowIds = Object.keys(lts.keys);
for (let index = 0; index < rowIds.length; index++) {
- const row = rowIds[index] as keyof MonkeyTypes.Keys;
+ const row = rowIds[index] as keyof JSONData.Keys;
let rowKeys = lts.keys[row];
if (row === "row1" && (isMatrix || Config.keymapStyle === "staggered")) {
rowKeys = rowKeys.slice(1);
diff --git a/frontend/src/ts/elements/notifications.ts b/frontend/src/ts/elements/notifications.ts
index e8e876d8b..66e221198 100644
--- a/frontend/src/ts/elements/notifications.ts
+++ b/frontend/src/ts/elements/notifications.ts
@@ -266,10 +266,19 @@ function updateClearAllButton(): void {
}
}
+export type AddNotificationOptions = {
+ important?: boolean;
+ duration?: number;
+ customTitle?: string;
+ customIcon?: string;
+ closeCallback?: () => void;
+ allowHTML?: boolean;
+};
+
export function add(
message: string,
level = 0,
- options: MonkeyTypes.AddNotificationOptions = {}
+ options: AddNotificationOptions = {}
): void {
NotificationEvent.dispatch(message, level, options.customTitle);
diff --git a/frontend/src/ts/elements/profile.ts b/frontend/src/ts/elements/profile.ts
index 199fe0372..7cb650581 100644
--- a/frontend/src/ts/elements/profile.ts
+++ b/frontend/src/ts/elements/profile.ts
@@ -16,7 +16,7 @@ import { abbreviateNumber, convertRemToPixels } from "../utils/numbers";
import { secondsToString } from "../utils/date-and-time";
type ProfileViewPaths = "profile" | "account";
-type UserProfileOrSnapshot = UserProfile | MonkeyTypes.Snapshot;
+type UserProfileOrSnapshot = UserProfile | DB.Snapshot;
//this is probably the dirtiest code ive ever written
@@ -129,7 +129,7 @@ export async function update(
const results = DB.getSnapshot()?.results;
const lastResult = results?.[0];
- const streakOffset = (profile as MonkeyTypes.Snapshot).streakHourOffset;
+ const streakOffset = (profile as DB.Snapshot).streakHourOffset;
const dayInMilis = 1000 * 60 * 60 * 24;
diff --git a/frontend/src/ts/elements/test-activity-calendar.ts b/frontend/src/ts/elements/test-activity-calendar.ts
index a2209ddf0..6eb9886f4 100644
--- a/frontend/src/ts/elements/test-activity-calendar.ts
+++ b/frontend/src/ts/elements/test-activity-calendar.ts
@@ -20,7 +20,17 @@ import {
Interval,
} from "date-fns";
-export class TestActivityCalendar implements MonkeyTypes.TestActivityCalendar {
+type TestActivityDay = {
+ level: string;
+ label?: string;
+};
+
+export type TestActivityMonth = {
+ text: string;
+ weeks: number;
+};
+
+export class TestActivityCalendar implements TestActivityCalendar {
protected data: (number | null | undefined)[];
protected startDay: Date;
protected endDay: Date;
@@ -69,12 +79,12 @@ export class TestActivityCalendar implements MonkeyTypes.TestActivityCalendar {
return values.slice(offset);
}
- getMonths(): MonkeyTypes.TestActivityMonth[] {
+ getMonths(): TestActivityMonth[] {
const months: Date[] = eachMonthOfInterval({
start: this.startDay,
end: this.endDay,
});
- const results: MonkeyTypes.TestActivityMonth[] = [];
+ const results: TestActivityMonth[] = [];
for (let i = 0; i < months.length; i++) {
const month: Date = months[i] as Date;
@@ -101,8 +111,8 @@ export class TestActivityCalendar implements MonkeyTypes.TestActivityCalendar {
return results;
}
- getDays(): MonkeyTypes.TestActivityDay[] {
- const result: MonkeyTypes.TestActivityDay[] = [];
+ getDays(): TestActivityDay[] {
+ const result: TestActivityDay[] = [];
const buckets = this.getBuckets();
const getValue = (v: number | null | undefined): string => {
if (v === undefined) return "0";
@@ -172,7 +182,7 @@ export class TestActivityCalendar implements MonkeyTypes.TestActivityCalendar {
export class ModifiableTestActivityCalendar
extends TestActivityCalendar
- implements MonkeyTypes.ModifiableTestActivityCalendar
+ implements ModifiableTestActivityCalendar
{
private lastDay: Date;
@@ -205,7 +215,7 @@ export class ModifiableTestActivityCalendar
this.data = this.buildData(this.data, this.lastDay);
}
- getFullYearCalendar(): MonkeyTypes.TestActivityCalendar {
+ getFullYearCalendar(): TestActivityCalendar {
const today = new Date();
if (this.lastDay.getFullYear() !== new UTCDateMini(today).getFullYear()) {
return new TestActivityCalendar([], today, true);
diff --git a/frontend/src/ts/elements/test-activity.ts b/frontend/src/ts/elements/test-activity.ts
index 51e328c7f..5dfa46418 100644
--- a/frontend/src/ts/elements/test-activity.ts
+++ b/frontend/src/ts/elements/test-activity.ts
@@ -3,11 +3,15 @@ import { DataObjectPartial } from "slim-select/store";
import { getTestActivityCalendar } from "../db";
import * as ServerConfiguration from "../ape/server-configuration";
import * as DB from "../db";
+import {
+ TestActivityCalendar,
+ TestActivityMonth,
+} from "./test-activity-calendar";
let yearSelector: SlimSelect | undefined = undefined;
export function init(
- calendar?: MonkeyTypes.TestActivityCalendar,
+ calendar?: TestActivityCalendar,
userSignUpDate?: Date
): void {
if (calendar === undefined) {
@@ -21,7 +25,7 @@ export function init(
update(calendar);
}
-function update(calendar?: MonkeyTypes.TestActivityCalendar): void {
+function update(calendar?: TestActivityCalendar): void {
const container = document.querySelector("#testActivity .activity");
if (container === null) {
@@ -89,7 +93,7 @@ export function initYearSelector(
years.length > 1 ? yearSelect.enable() : yearSelect.disable();
}
-function updateMonths(months: MonkeyTypes.TestActivityMonth[]): void {
+function updateMonths(months: TestActivityMonth[]): void {
const element = document.querySelector("#testActivity .months") as Element;
element.innerHTML = months
diff --git a/frontend/src/ts/modals/edit-preset.ts b/frontend/src/ts/modals/edit-preset.ts
index b0124e80a..a2f1d9bb3 100644
--- a/frontend/src/ts/modals/edit-preset.ts
+++ b/frontend/src/ts/modals/edit-preset.ts
@@ -16,6 +16,7 @@ import {
} from "@monkeytype/contracts/schemas/presets";
import { getPreset } from "../controllers/preset-controller";
import defaultConfig from "../constants/default-config";
+import { Config as ConfigType } from "@monkeytype/contracts/schemas/configs";
const state = {
presetType: "full" as PresetType,
@@ -279,12 +280,12 @@ async function apply(): Promise<void> {
}),
display: propPresetName,
_id: response.body.data.presetId,
- } as MonkeyTypes.SnapshotPreset);
+ } as DB.SnapshotPreset);
}
} else if (action === "edit") {
const preset = snapshotPresets.filter(
- (preset: MonkeyTypes.SnapshotPreset) => preset._id === presetId
- )[0] as MonkeyTypes.SnapshotPreset;
+ (preset: DB.SnapshotPreset) => preset._id === presetId
+ )[0] as DB.SnapshotPreset;
if (preset === undefined) {
Notifications.add("Preset not found", -1);
return;
@@ -329,13 +330,11 @@ async function apply(): Promise<void> {
);
} else {
Notifications.add("Preset removed", 1);
- snapshotPresets.forEach(
- (preset: MonkeyTypes.SnapshotPreset, index: number) => {
- if (preset._id === presetId) {
- snapshotPresets.splice(index, 1);
- }
+ snapshotPresets.forEach((preset: DB.SnapshotPreset, index: number) => {
+ if (preset._id === presetId) {
+ snapshotPresets.splice(index, 1);
}
- );
+ });
}
}
@@ -467,16 +466,16 @@ function getSettingGroup(configFieldName: string): PresetSettingGroup {
}
function getPartialConfigChanges(
- configChanges: MonkeyTypes.ConfigChanges
-): MonkeyTypes.ConfigChanges {
- const activeConfigChanges: MonkeyTypes.ConfigChanges = {};
+ configChanges: Partial<ConfigType>
+): Partial<ConfigType> {
+ const activeConfigChanges: Partial<ConfigType> = {};
Object.keys(defaultConfig)
.filter(
(settingName) =>
state.checkboxes.get(getSettingGroup(settingName)) === true
)
.forEach((settingName) => {
- const safeSettingName = settingName as keyof MonkeyTypes.ConfigChanges;
+ const safeSettingName = settingName as keyof Partial<ConfigType>;
const newValue =
configChanges[safeSettingName] !== undefined
? configChanges[safeSettingName]
@@ -493,7 +492,7 @@ function getActiveSettingGroupsFromState(): ActiveSettingGroups {
.map(([key]) => key)
);
}
-function getConfigChanges(): MonkeyTypes.ConfigChanges {
+function getConfigChanges(): Partial<ConfigType> {
const activeConfigChanges =
state.presetType === "partial"
? getPartialConfigChanges(Config.getConfigChanges())
@@ -501,9 +500,8 @@ function getConfigChanges(): MonkeyTypes.ConfigChanges {
const tags = DB.getSnapshot()?.tags ?? [];
const activeTagIds: string[] = tags
- .filter((tag: MonkeyTypes.UserTag) => tag.active)
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
- .map((tag: MonkeyTypes.UserTag) => tag._id);
+ .filter((tag) => tag.active)
+ .map((tag) => tag._id);
const setTags: boolean =
state.presetType === "full" || state.checkboxes.get("behavior") === true;
diff --git a/frontend/src/ts/modals/edit-result-tags.ts b/frontend/src/ts/modals/edit-result-tags.ts
index 332e5eb9f..f6d2ee932 100644
--- a/frontend/src/ts/modals/edit-result-tags.ts
+++ b/frontend/src/ts/modals/edit-result-tags.ts
@@ -7,8 +7,6 @@ import * as ConnectionState from "../states/connection";
import { areUnsortedArraysEqual } from "../utils/arrays";
import * as TestResult from "../test/result";
import AnimatedModal from "../utils/animated-modal";
-import { Mode } from "@monkeytype/contracts/schemas/shared";
-import { Result } from "@monkeytype/contracts/schemas/results";
type State = {
resultId: string;
@@ -137,7 +135,7 @@ async function save(): Promise<void> {
duration: 2,
});
- DB.getSnapshot()?.results?.forEach((result: Result<Mode>) => {
+ DB.getSnapshot()?.results?.forEach((result) => {
if (result._id === state.resultId) {
result.tags = state.tags;
}
diff --git a/frontend/src/ts/modals/quote-rate.ts b/frontend/src/ts/modals/quote-rate.ts
index 07193efb9..918946644 100644
--- a/frontend/src/ts/modals/quote-rate.ts
+++ b/frontend/src/ts/modals/quote-rate.ts
@@ -1,4 +1,5 @@
import Ape from "../ape";
+import { Quote } from "../controllers/quotes-controller";
import * as DB from "../db";
import * as Loader from "../elements/loader";
import * as Notifications from "../elements/notifications";
@@ -15,7 +16,7 @@ type QuoteStats = {
};
let quoteStats: QuoteStats | null | Record<string, never> = null;
-let currentQuote: MonkeyTypes.Quote | null = null;
+let currentQuote: Quote | null = null;
export function clearQuoteStats(): void {
quoteStats = null;
@@ -39,7 +40,7 @@ function getRatingAverage(quoteStats: QuoteStats): number {
}
export async function getQuoteStats(
- quote?: MonkeyTypes.Quote
+ quote?: Quote
): Promise<QuoteStats | undefined> {
if (!quote) {
return;
@@ -106,10 +107,7 @@ function updateData(): void {
void updateRatingStats();
}
-export function show(
- quote: MonkeyTypes.Quote,
- showOptions?: ShowOptions
-): void {
+export function show(quote: Quote, showOptions?: ShowOptions): void {
void modal.show({
...showOptions,
beforeAnimation: async () => {
diff --git a/frontend/src/ts/modals/quote-report.ts b/frontend/src/ts/modals/quote-report.ts
index fc3a5f573..425ae56b5 100644
--- a/frontend/src/ts/modals/quote-report.ts
+++ b/frontend/src/ts/modals/quote-report.ts
@@ -2,7 +2,7 @@ import Ape from "../ape";
import Config from "../config";
import * as Loader from "../elements/loader";
import * as Notifications from "../elements/notifications";
-import QuotesController from "../controllers/quotes-controller";
+import QuotesController, { Quote } from "../controllers/quotes-controller";
import * as CaptchaController from "../controllers/captcha-controller";
import { removeLanguageSize } from "../utils/strings";
import SlimSelect from "slim-select";
@@ -11,7 +11,7 @@ import { CharacterCounter } from "../elements/character-counter";
import { QuoteReportReason } from "@monkeytype/contracts/schemas/quotes";
type State = {
- quoteToReport?: MonkeyTypes.Quote;
+ quoteToReport?: Quote;
reasonSelect?: SlimSelect | undefined;
};
diff --git a/frontend/src/ts/modals/quote-search.ts b/frontend/src/ts/modals/quote-search.ts
index 9192853d8..ffc0be97b 100644
--- a/frontend/src/ts/modals/quote-search.ts
+++ b/frontend/src/ts/modals/quote-search.ts
@@ -11,7 +11,7 @@ import {
TextExtractor,
} from "../utils/search-service";
import { splitByAndKeep } from "../utils/strings";
-import QuotesController from "../controllers/quotes-controller";
+import QuotesController, { Quote } from "../controllers/quotes-controller";
import { isAuthenticated } from "../firebase";
import { debounce } from "throttle-debounce";
import Ape from "../ape";
@@ -23,7 +23,7 @@ import * as TestLogic from "../test/test-logic";
import { createErrorMessage } from "../utils/misc";
import { QuoteLength } from "@monkeytype/contracts/schemas/configs";
-const searchServiceCache: Record<string, SearchService<MonkeyTypes.Quote>> = {};
+const searchServiceCache: Record<string, SearchService<Quote>> = {};
const pageSize = 100;
let currentPageNumber = 1;
@@ -61,9 +61,7 @@ function highlightMatches(text: string, matchedText: string[]): string {
return normalizedWords.join("");
}
-function applyQuoteLengthFilter(
- quotes: MonkeyTypes.Quote[]
-): MonkeyTypes.Quote[] {
+function applyQuoteLengthFilter(quotes: Quote[]): Quote[] {
const quoteLengthFilterValue = $(
"#quoteSearchModal .quoteLengthFilter"
).val() as string[];
@@ -81,7 +79,7 @@ function applyQuoteLengthFilter(
return filteredQuotes;
}
-function applyQuoteFavFilter(quotes: MonkeyTypes.Quote[]): MonkeyTypes.Quote[] {
+function applyQuoteFavFilter(quotes: Quote[]): Quote[] {
const showFavOnly = (
document.querySelector(".toggleFavorites") as HTMLDivElement
).classList.contains("active");
@@ -98,7 +96,7 @@ function applyQuoteFavFilter(quotes: MonkeyTypes.Quote[]): MonkeyTypes.Quote[] {
}
function buildQuoteSearchResult(
- quote: MonkeyTypes.Quote,
+ quote: Quote,
matchedSearchTerms: string[]
): string {
let lengthDesc;
@@ -158,10 +156,10 @@ function buildQuoteSearchResult(
async function updateResults(searchText: string): Promise<void> {
const { quotes } = await QuotesController.getQuotes(Config.language);
- const quoteSearchService = getSearchService<MonkeyTypes.Quote>(
+ const quoteSearchService = getSearchService<Quote>(
Config.language,
quotes,
- (quote: MonkeyTypes.Quote) => {
+ (quote: Quote) => {
return `${quote.text} ${quote.id} ${quote.source}`;
}
);
@@ -357,7 +355,7 @@ async function toggleFavoriteForQuote(quoteId: string): Promise<void> {
const quote = {
language: quoteLang,
id: parseInt(quoteId, 10),
- } as MonkeyTypes.Quote;
+ } as Quote;
const alreadyFavorited = QuotesController.isQuoteFavorite(quote);
diff --git a/frontend/src/ts/modals/share-test-settings.ts b/frontend/src/ts/modals/share-test-settings.ts
index 8a0cf4ba5..54ba7d185 100644
--- a/frontend/src/ts/modals/share-test-settings.ts
+++ b/frontend/src/ts/modals/share-test-settings.ts
@@ -16,7 +16,7 @@ function getCheckboxValue(checkbox: string): boolean {
type SharedTestSettings = [
Mode | null,
Mode2<Mode> | null,
- MonkeyTypes.CustomTextData | null,
+ CustomText.CustomTextData | null,
boolean | null,
boolean | null,
string | null,
diff --git a/frontend/src/ts/modals/streak-hour-offset.ts b/frontend/src/ts/modals/streak-hour-offset.ts
index 1b6e0089e..0c11bf068 100644
--- a/frontend/src/ts/modals/streak-hour-offset.ts
+++ b/frontend/src/ts/modals/streak-hour-offset.ts
@@ -4,7 +4,7 @@ import * as Notifications from "../elements/notifications";
import * as Loader from "../elements/loader";
// import * as Settings from "../pages/settings";
import * as ConnectionState from "../states/connection";
-import { getSnapshot, setSnapshot } from "../db";
+import { getSnapshot, setSnapshot, Snapshot } from "../db";
import AnimatedModal from "../utils/animated-modal";
export function show(): void {
@@ -93,7 +93,7 @@ async function apply(): Promise<void> {
);
} else {
Notifications.add("Streak hour offset set", 1);
- const snap = getSnapshot() as MonkeyTypes.Snapshot;
+ const snap = getSnapshot() as Snapshot;
snap.streakHourOffset = value;
setSnapshot(snap);
hide();
diff --git a/frontend/src/ts/modals/version-history.ts b/frontend/src/ts/modals/version-history.ts
index 3df9b29fc..b57c738a0 100644
--- a/frontend/src/ts/modals/version-history.ts
+++ b/frontend/src/ts/modals/version-history.ts
@@ -14,7 +14,7 @@ export function show(): void {
getReleasesFromGitHub()
.then((releases) => {
$("#versionHistoryModal .modal").html(`<div class="releases"></div`);
- releases.forEach((release: MonkeyTypes.GithubRelease) => {
+ releases.forEach((release) => {
if (!release.draft && !release.prerelease) {
let body = release.body;
diff --git a/frontend/src/ts/modals/word-filter.ts b/frontend/src/ts/modals/word-filter.ts
index 1ff21624e..6bc20fe2c 100644
--- a/frontend/src/ts/modals/word-filter.ts
+++ b/frontend/src/ts/modals/word-filter.ts
@@ -10,8 +10,8 @@ import AnimatedModal, {
type FilterPreset = {
display: string;
- getIncludeString: (layout: MonkeyTypes.Layout) => string[];
- getExcludeString: (layout: MonkeyTypes.Layout) => string[];
+ getIncludeString: (layout: JSONData.Layout) => string[];
+ getExcludeString: (layout: JSONData.Layout) => string[];
};
const presets: Record<string, FilterPreset> = {
diff --git a/frontend/src/ts/pages/account.ts b/frontend/src/ts/pages/account.ts
index d4470095d..de8c5954d 100644
--- a/frontend/src/ts/pages/account.ts
+++ b/frontend/src/ts/pages/account.ts
@@ -28,9 +28,15 @@ import * as ResultBatches from "../elements/result-batches";
import Format from "../utils/format";
import * as TestActivity from "../elements/test-activity";
import { ChartData } from "@monkeytype/contracts/schemas/results";
-import { Mode, Mode2, Mode2Custom } from "@monkeytype/contracts/schemas/shared";
+import {
+ Difficulty,
+ Mode,
+ Mode2,
+ Mode2Custom,
+} from "@monkeytype/contracts/schemas/shared";
import { ResultFiltersGroupItem } from "@monkeytype/contracts/schemas/users";
import { findLineByLeastSquares } from "../utils/numbers";
+import defaultResultFilters from "../constants/default-result-filters";
let filterDebug = false;
//toggle filterdebug
@@ -41,7 +47,7 @@ export function toggleFilterDebug(): void {
}
}
-let filteredResults: MonkeyTypes.FullResult<Mode>[] = [];
+let filteredResults: DB.SnapshotResult<Mode>[] = [];
let visibleTableLines = 0;
function loadMoreLines(lineIndex?: number): void {
@@ -202,8 +208,8 @@ function reset(): void {
}
let totalSecondsFiltered = 0;
-let chartData: MonkeyTypes.HistoryChartData[] = [];
-let accChartData: MonkeyTypes.AccChartData[] = [];
+let chartData: ChartController.HistoryChartData[] = [];
+let accChartData: ChartController.AccChartData[] = [];
async function fillContent(): Promise<void> {
LoadingPage.updateText("Displaying stats...");
@@ -288,7 +294,7 @@ async function fillContent(): Promise<void> {
if (resdiff === undefined) {
resdiff = "normal";
}
- if (!ResultFilters.getFilter("difficulty", resdiff)) {
+ if (!ResultFilters.getFilter("difficulty", resdiff as Difficulty)) {
if (filterDebug) {
console.log(`skipping result due to difficulty filter`, result);
}
@@ -344,7 +350,8 @@ async function fillContent(): Promise<void> {
}
if (result.quoteLength !== null) {
- let filter: MonkeyTypes.QuoteModes | undefined = undefined;
+ let filter: keyof typeof defaultResultFilters.quoteLength | undefined =
+ undefined;
if (result.quoteLength === 0) {
filter = "short";
} else if (result.quoteLength === 1) {
@@ -519,7 +526,7 @@ async function fillContent(): Promise<void> {
dataForTimestamp.amount++;
dataForTimestamp.time +=
result.testDuration +
- result.incompleteTestSeconds -
+ (result.incompleteTestSeconds ?? 0) -
(result.afkDuration ?? 0);
dataForTimestamp.totalWpm += result.wpm;
} else {
@@ -527,7 +534,7 @@ async function fillContent(): Promise<void> {
amount: 1,
time:
result.testDuration +
- result.incompleteTestSeconds -
+ (result.incompleteTestSeconds ?? 0) -
(result.afkDuration ?? 0),
totalWpm: result.wpm,
};
@@ -660,9 +667,9 @@ async function fillContent(): Promise<void> {
loadMoreLines();
////////
- const activityChartData_timeAndAmount: MonkeyTypes.ActivityChartDataPoint[] =
+ const activityChartData_timeAndAmount: ChartController.ActivityChartDataPoint[] =
[];
- const activityChartData_avgWpm: MonkeyTypes.ActivityChartDataPoint[] = [];
+ const activityChartData_avgWpm: ChartController.ActivityChartDataPoint[] = [];
const wpmStepSize = typingSpeedUnit.historyStepSize;
// let lastTimestamp = 0;
@@ -736,7 +743,7 @@ async function fillContent(): Promise<void> {
const pb: { x: number; y: number }[] = [];
for (let i = chartData.length - 1; i >= 0; i--) {
- const a = chartData[i] as MonkeyTypes.HistoryChartData;
+ const a = chartData[i] as ChartController.HistoryChartData;
if (a.y > currentPb) {
currentPb = a.y;
pb.push(a);
@@ -1065,7 +1072,7 @@ function sortAndRefreshHistory(
$(headerClass).append('<i class="fas fa-sort-up", aria-hidden="true"></i>');
}
- const temp: MonkeyTypes.FullResult<Mode>[] = [];
+ const temp: DB.SnapshotResult<Mode>[] = [];
const parsedIndexes: number[] = [];
while (temp.length < filteredResults.length) {
@@ -1224,6 +1231,7 @@ $(".pageAccount .group.presetFilterButtons").on(
);
$(".pageAccount .content .group.aboveHistory .exportCSV").on("click", () => {
+ //@ts-expect-error
void Misc.downloadResultsCSV(filteredResults);
});
diff --git a/frontend/src/ts/pages/page.ts b/frontend/src/ts/pages/page.ts
index f08595d14..397f39088 100644
--- a/frontend/src/ts/pages/page.ts
+++ b/frontend/src/ts/pages/page.ts
@@ -1,10 +1,22 @@
+export type PageName =
+ | "loading"
+ | "test"
+ | "settings"
+ | "about"
+ | "account"
+ | "login"
+ | "profile"
+ | "profileSearch"
+ | "404"
+ | "accountSettings";
+
type Options<T> = {
params?: Record<string, string>;
data?: T;
};
type PageProperties<T> = {
- name: MonkeyTypes.PageName;
+ name: PageName;
element: JQuery;
path: string;
beforeHide?: () => Promise<void>;
@@ -17,7 +29,7 @@ async function empty(): Promise<void> {
return;
}
export default class Page<T> {
- public name: MonkeyTypes.PageName;
+ public name: PageName;
public element: JQuery;
public pathname: string;
public beforeHide: () => Promise<void>;
diff --git a/frontend/src/ts/pages/settings.ts b/frontend/src/ts/pages/settings.ts
index 8a6325dcd..3fe334dae 100644
--- a/frontend/src/ts/pages/settings.ts
+++ b/frontend/src/ts/pages/settings.ts
@@ -21,7 +21,10 @@ import SlimSelect from "slim-select";
import * as Skeleton from "../utils/skeleton";
import * as CustomBackgroundFilter from "../elements/custom-background-filter";
-import { ConfigValue } from "@monkeytype/contracts/schemas/configs";
+import {
+ ConfigValue,
+ CustomLayoutFluid,
+} from "@monkeytype/contracts/schemas/configs";
type SettingsGroups<T extends ConfigValue> = Record<string, SettingsGroup<T>>;
@@ -787,7 +790,7 @@ function refreshTagsSettingsSection(): void {
function refreshPresetsSettingsSection(): void {
if (isAuthenticated() && DB.getSnapshot()) {
const presetsEl = $(".pageSettings .section.presets .presetsList").empty();
- DB.getSnapshot()?.presets?.forEach((preset: MonkeyTypes.SnapshotPreset) => {
+ DB.getSnapshot()?.presets?.forEach((preset: DB.SnapshotPreset) => {
presetsEl.append(`
<div class="buttons preset" data-id="${preset._id}" data-name="${preset.name}" data-display="${preset.display}">
<button class="presetButton">${preset.display}</button>
@@ -1274,7 +1277,7 @@ $(
void UpdateConfig.setCustomLayoutfluid(
$(
".pageSettings .section[data-config-name='customLayoutfluid'] .inputAndButton input"
- ).val() as MonkeyTypes.CustomLayoutFluidSpaces
+ ).val() as CustomLayoutFluid
).then((bool) => {
if (bool) {
Notifications.add("Custom layoutfluid saved", 1);
@@ -1289,7 +1292,7 @@ $(
void UpdateConfig.setCustomLayoutfluid(
$(
".pageSettings .section[data-config-name='customLayoutfluid'] .inputAndButton input"
- ).val() as MonkeyTypes.CustomLayoutFluidSpaces
+ ).val() as CustomLayoutFluid
).then((bool) => {
if (bool) {
Notifications.add("Custom layoutfluid saved", 1);
diff --git a/frontend/src/ts/states/active-page.ts b/frontend/src/ts/states/active-page.ts
index 5977afbcb..fa8f96f8f 100644
--- a/frontend/src/ts/states/active-page.ts
+++ b/frontend/src/ts/states/active-page.ts
@@ -1,9 +1,11 @@
-let activePage: MonkeyTypes.PageName = "loading";
+import { PageName } from "../pages/page";
-export function get(): MonkeyTypes.PageName {
+let activePage: PageName = "loading";
+
+export function get(): PageName {
return activePage;
}
-export function set(active: MonkeyTypes.PageName): void {
+export function set(active: PageName): void {
activePage = active;
}
diff --git a/frontend/src/ts/test/custom-text.ts b/frontend/src/ts/test/custom-text.ts
index 3614196fd..a0d59cb2f 100644
--- a/frontend/src/ts/test/custom-text.ts
+++ b/frontend/src/ts/test/custom-text.ts
@@ -6,6 +6,7 @@ import {
} from "@monkeytype/contracts/schemas/util";
import { LocalStorageWithSchema } from "../utils/local-storage-with-schema";
import { z } from "zod";
+import { CustomTextDataWithTextLen } from "@monkeytype/contracts/schemas/results";
const CustomTextObjectSchema = z.record(z.string(), z.string());
type CustomTextObject = z.infer<typeof CustomTextObjectSchema>;
@@ -37,6 +38,8 @@ const CustomTextSettingsSchema = z.object({
type CustomTextSettings = z.infer<typeof CustomTextSettingsSchema>;
+type CustomTextLimit = z.infer<typeof CustomTextSettingsSchema>["limit"];
+
const defaultCustomTextSettings: CustomTextSettings = {
text: ["The", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"],
mode: "repeat",
@@ -93,8 +96,8 @@ export function setMode(val: CustomTextMode): void {
});
}
-export function getLimit(): MonkeyTypes.CustomTextLimit {
- return customTextSettings.get().limit as MonkeyTypes.CustomTextLimit;
+export function getLimit(): CustomTextLimit {
+ return customTextSettings.get().limit as CustomTextLimit;
}
export function getLimitValue(): number {
@@ -133,7 +136,11 @@ export function setPipeDelimiter(val: boolean): void {
});
}
-export function getData(): MonkeyTypes.CustomTextData {
+export type CustomTextData = Omit<CustomTextDataWithTextLen, "textLen"> & {
+ text: string[];
+};
+
+export function getData(): CustomTextData {
return {
text: getText(),
mode: getMode(),
diff --git a/frontend/src/ts/test/funbox/funbox-list.ts b/frontend/src/ts/test/funbox/funbox-list.ts
index ede52df88..9090c7a74 100644
--- a/frontend/src/ts/test/funbox/funbox-list.ts
+++ b/frontend/src/ts/test/funbox/funbox-list.ts
@@ -1,4 +1,6 @@
-const list: MonkeyTypes.FunboxMetadata[] = [
+import { FunboxFunctions, FunboxMetadata } from "../../utils/json-data";
+
+const list: FunboxMetadata[] = [
{
name: "nausea",
info: "I think I'm gonna be sick.",
@@ -280,12 +282,12 @@ const list: MonkeyTypes.FunboxMetadata[] = [
},
];
-export function getAll(): MonkeyTypes.FunboxMetadata[] {
+export function getAll(): FunboxMetadata[] {
return list;
}
-export function get(config: string): MonkeyTypes.FunboxMetadata[] {
- const funboxes: MonkeyTypes.FunboxMetadata[] = [];
+export function get(config: string): FunboxMetadata[] {
+ const funboxes: FunboxMetadata[] = [];
for (const i of config.split("#")) {
const f = list.find((f) => f.name === i);
if (f) funboxes.push(f);
@@ -293,10 +295,7 @@ export function get(config: string): MonkeyTypes.FunboxMetadata[] {
return funboxes;
}
-export function setFunboxFunctions(
- name: string,
- obj: MonkeyTypes.FunboxFunctions
-): void {
+export function setFunboxFunctions(name: string, obj: FunboxFunctions): void {
const fb = list.find((f) => f.name === name);
if (!fb) throw new Error(`Funbox ${name} not found.`);
fb.functions = obj;
diff --git a/frontend/src/ts/test/funbox/funbox-validation.ts b/frontend/src/ts/test/funbox/funbox-validation.ts
index 9a9f37033..31b132b9d 100644
--- a/frontend/src/ts/test/funbox/funbox-validation.ts
+++ b/frontend/src/ts/test/funbox/funbox-validation.ts
@@ -3,6 +3,7 @@ import * as Notifications from "../../elements/notifications";
import * as Strings from "../../utils/strings";
import { Config, ConfigValue } from "@monkeytype/contracts/schemas/configs";
import { intersect } from "@monkeytype/util/arrays";
+import { FunboxForcedConfig, FunboxMetadata } from "../../utils/json-data";
export function checkFunboxForcedConfigs(
key: string,
@@ -79,7 +80,7 @@ export function canSetConfigWithCurrentFunboxes(
): boolean {
let errorCount = 0;
if (key === "mode") {
- let fb: MonkeyTypes.FunboxMetadata[] = [];
+ let fb: FunboxMetadata[] = [];
fb = fb.concat(
FunboxList.get(funbox).filter(
(f) =>
@@ -295,7 +296,7 @@ export function areFunboxesCompatible(
funboxesToCheck.filter((f) => f.functions?.isCharCorrect).length <= 1;
const oneCharReplacerMax =
funboxesToCheck.filter((f) => f.functions?.getWordHtml).length <= 1;
- const allowedConfig = {} as MonkeyTypes.FunboxForcedConfig;
+ const allowedConfig = {} as FunboxForcedConfig;
let noConfigConflicts = true;
for (const f of funboxesToCheck) {
if (!f.forcedConfig) continue;
diff --git a/frontend/src/ts/test/funbox/funbox.ts b/frontend/src/ts/test/funbox/funbox.ts
index b020cb2df..fff8f111b 100644
--- a/frontend/src/ts/test/funbox/funbox.ts
+++ b/frontend/src/ts/test/funbox/funbox.ts
@@ -22,7 +22,7 @@ import {
areFunboxesCompatible,
checkFunboxForcedConfigs,
} from "./funbox-validation";
-import { Wordset } from "../wordset";
+import { FunboxWordsFrequency, Wordset } from "../wordset";
import * as LayoutfluidFunboxTimer from "./layoutfluid-funbox-timer";
import * as DDR from "../../utils/ddr";
import { HighlightMode } from "@monkeytype/contracts/schemas/configs";
@@ -432,13 +432,13 @@ FunboxList.setFunboxFunctions("nospace", {
});
FunboxList.setFunboxFunctions("poetry", {
- async pullSection(): Promise<Misc.Section | false> {
+ async pullSection(): Promise<JSONData.Section | false> {
return getPoem();
},
});
FunboxList.setFunboxFunctions("wikipedia", {
- async pullSection(lang?: string): Promise<Misc.Section | false> {
+ async pullSection(lang?: string): Promise<JSONData.Section | false> {
return getSection((lang ?? "") || "english");
},
});
@@ -512,7 +512,7 @@ FunboxList.setFunboxFunctions("hexadecimal", {
});
FunboxList.setFunboxFunctions("zipf", {
- getWordsFrequencyMode(): MonkeyTypes.FunboxWordsFrequency {
+ getWordsFrequencyMode(): FunboxWordsFrequency {
return "zipf";
},
});
diff --git a/frontend/src/ts/test/lazy-mode.ts b/frontend/src/ts/test/lazy-mode.ts
index 3f8a73b37..153dac2c4 100644
--- a/frontend/src/ts/test/lazy-mode.ts
+++ b/frontend/src/ts/test/lazy-mode.ts
@@ -1,4 +1,4 @@
-const accents: [string, string][] = [
+const accents: Accents = [
["áàâäåãąą́āą̄ă", "a"],
["éèêëẽęę́ēę̄ėě", "e"],
["íìîïĩįį́īį̄ı", "i"],
@@ -46,9 +46,11 @@ const accentsMap = new Map<string, string>(
accents.flatMap((rule) => [...rule[0]].map((accent) => [accent, rule[1]]))
);
+export type Accents = [string, string][];
+
function findAccent(
char: string,
- additionalAccents?: MonkeyTypes.Accents
+ additionalAccents?: Accents
): string | undefined {
const lookup = char.toLowerCase();
@@ -59,7 +61,7 @@ function findAccent(
export function replaceAccents(
word: string,
- additionalAccents?: MonkeyTypes.Accents
+ additionalAccents?: Accents
): string {
if (!word) return word;
const uppercased = word.toUpperCase();
diff --git a/frontend/src/ts/test/poetry.ts b/frontend/src/ts/test/poetry.ts
index ab104ac10..c127a1602 100644
--- a/frontend/src/ts/test/poetry.ts
+++ b/frontend/src/ts/test/poetry.ts
@@ -1,4 +1,4 @@
-import { Section } from "../utils/misc";
+import { Section } from "../utils/json-data";
const bannedChars = ["—", "_", " "];
const maxWords = 100;
diff --git a/frontend/src/ts/test/practise-words.ts b/frontend/src/ts/test/practise-words.ts
index 4a9e08634..7e7cbb0e4 100644
--- a/frontend/src/ts/test/practise-words.ts
+++ b/frontend/src/ts/test/practise-words.ts
@@ -11,7 +11,7 @@ type Before = {
mode: Mode | null;
punctuation: boolean | null;
numbers: boolean | null;
- customText: MonkeyTypes.CustomTextData | null;
+ customText: CustomText.CustomTextData | null;
};
export const before: Before = {
diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts
index 5f8feabc7..5166315f9 100644
--- a/frontend/src/ts/test/result.ts
+++ b/frontend/src/ts/test/result.ts
@@ -3,7 +3,7 @@ import { Chart, type PluginChartOptions } from "chart.js";
import Config from "../config";
import * as AdController from "../controllers/ad-controller";
import * as ChartController from "../controllers/chart-controller";
-import QuotesController from "../controllers/quotes-controller";
+import QuotesController, { Quote } from "../controllers/quotes-controller";
import * as DB from "../db";
import * as Loader from "../elements/loader";
import * as Notifications from "../elements/notifications";
@@ -538,7 +538,7 @@ export function showConfetti(): void {
}
async function updateTags(dontSave: boolean): Promise<void> {
- const activeTags: MonkeyTypes.UserTag[] = [];
+ const activeTags: DB.SnapshotUserTag[] = [];
const userTagsCount = DB.getSnapshot()?.tags?.length ?? 0;
try {
DB.getSnapshot()?.tags?.forEach((tag) => {
@@ -654,7 +654,7 @@ async function updateTags(dontSave: boolean): Promise<void> {
});
}
-function updateTestType(randomQuote: MonkeyTypes.Quote | null): void {
+function updateTestType(randomQuote: Quote | null): void {
let testType = "";
testType += Config.mode;
@@ -761,7 +761,7 @@ function updateOther(
}
}
-export function updateRateQuote(randomQuote: MonkeyTypes.Quote | null): void {
+export function updateRateQuote(randomQuote: Quote | null): void {
if (Config.mode === "quote") {
if (randomQuote === null) {
console.error(
@@ -794,7 +794,7 @@ export function updateRateQuote(randomQuote: MonkeyTypes.Quote | null): void {
}
}
-function updateQuoteFavorite(randomQuote: MonkeyTypes.Quote | null): void {
+function updateQuoteFavorite(randomQuote: Quote | null): void {
const icon = $(".pageTest #result #favoriteQuoteButton .icon");
if (Config.mode !== "quote" || !isAuthenticated()) {
@@ -817,7 +817,7 @@ function updateQuoteFavorite(randomQuote: MonkeyTypes.Quote | null): void {
icon.parent().removeClass("hidden");
}
-function updateQuoteSource(randomQuote: MonkeyTypes.Quote | null): void {
+function updateQuoteSource(randomQuote: Quote | null): void {
if (Config.mode === "quote") {
$("#result .stats .source").removeClass("hidden");
$("#result .stats .source .bottom").html(
@@ -835,7 +835,7 @@ export async function update(
afkDetected: boolean,
isRepeated: boolean,
tooShort: boolean,
- randomQuote: MonkeyTypes.Quote | null,
+ randomQuote: Quote | null,
dontSave: boolean
): Promise<void> {
resultAnnotation = [];
diff --git a/frontend/src/ts/test/shift-tracker.ts b/frontend/src/ts/test/shift-tracker.ts
index 627e5679e..802100a6a 100644
--- a/frontend/src/ts/test/shift-tracker.ts
+++ b/frontend/src/ts/test/shift-tracker.ts
@@ -283,7 +283,7 @@ export function isUsingOppositeShift(keycode: string): boolean {
export function layoutKeyToKeycode(
key: string,
- layout: MonkeyTypes.Layout
+ layout: JSONData.Layout
): string | undefined {
const rows: string[][] = Object.values(layout.keys);
diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts
index 2a2932404..7bc8e5bac 100644
--- a/frontend/src/ts/test/test-logic.ts
+++ b/frontend/src/ts/test/test-logic.ts
@@ -1181,9 +1181,12 @@ async function saveResult(
}
if (data.insertedId !== undefined) {
- const result = JSON.parse(
- JSON.stringify(completedEvent)
- ) as MonkeyTypes.FullResult<Mode>;
+ //TODO - this type cast was not needed before because we were using JSON cloning
+ // but now with the stronger types it shows that we are forcing completed event
+ // into a snapshot result - might not cuase issues but worth investigating
+ const result = Misc.deepClone(
+ completedEvent
+ ) as unknown as DB.SnapshotResult<Mode>;
result._id = data.insertedId;
if (data.isPb !== undefined && data.isPb) {
result.isPb = true;
diff --git a/frontend/src/ts/test/test-state.ts b/frontend/src/ts/test/test-state.ts
index e996aec00..85a23ec7a 100644
--- a/frontend/src/ts/test/test-state.ts
+++ b/frontend/src/ts/test/test-state.ts
@@ -1,7 +1,9 @@
+import { Challenge } from "../utils/json-data";
+
export let isRepeated = false;
export let isPaceRepeat = false;
export let isActive = false;
-export let activeChallenge: null | MonkeyTypes.Challenge = null;
+export let activeChallenge: null | Challenge = null;
export let savingEnabled = true;
export let bailedOut = false;
export let selectedQuoteId = 1;
@@ -18,7 +20,7 @@ export function setActive(tf: boolean): void {
isActive = tf;
}
-export function setActiveChallenge(val: null | MonkeyTypes.Challenge): void {
+export function setActiveChallenge(val: null | Challenge): void {
activeChallenge = val;
}
diff --git a/frontend/src/ts/test/test-stats.ts b/frontend/src/ts/test/test-stats.ts
index 33b52db43..44fb8dcbd 100644
--- a/frontend/src/ts/test/test-stats.ts
+++ b/frontend/src/ts/test/test-stats.ts
@@ -142,9 +142,10 @@ export function calculateTestSeconds(now?: number): number {
}
}
-export function calculateWpmAndRaw(
- withDecimalPoints?: true
-): MonkeyTypes.WpmAndRaw {
+export function calculateWpmAndRaw(withDecimalPoints?: true): {
+ wpm: number;
+ raw: number;
+} {
const testSeconds = calculateTestSeconds(
TestState.isActive ? performance.now() : end
);
diff --git a/frontend/src/ts/test/test-timer.ts b/frontend/src/ts/test/test-timer.ts
index 0303089bb..1cbf5e19f 100644
--- a/frontend/src/ts/test/test-timer.ts
+++ b/frontend/src/ts/test/test-timer.ts
@@ -18,6 +18,13 @@ import * as Time from "../states/time";
import * as TimerEvent from "../observables/timer-event";
import * as LayoutfluidFunboxTimer from "../test/funbox/layoutfluid-funbox-timer";
+type TimerStats = {
+ dateNow: number;
+ now: number;
+ expected: number;
+ nextDelay: number;
+};
+
let slowTimerCount = 0;
let timer: NodeJS.Timeout | null = null;
const interval = 1000;
@@ -54,7 +61,7 @@ function updateTimer(): void {
if (timerDebug) console.timeEnd("timer progress update");
}
-function calculateWpmRaw(): MonkeyTypes.WpmAndRaw {
+function calculateWpmRaw(): { wpm: number; raw: number } {
if (timerDebug) console.time("calculate wpm and raw");
const wpmAndRaw = TestStats.calculateWpmAndRaw();
if (timerDebug) console.timeEnd("calculate wpm and raw");
@@ -68,7 +75,7 @@ function calculateWpmRaw(): MonkeyTypes.WpmAndRaw {
return wpmAndRaw;
}
-function monkey(wpmAndRaw: MonkeyTypes.WpmAndRaw): void {
+function monkey(wpmAndRaw: { wpm: number; raw: number }): void {
if (timerDebug) console.time("update monkey");
const num = Config.blindMode ? wpmAndRaw.raw : wpmAndRaw.wpm;
Monkey.updateFastOpacity(num);
@@ -119,7 +126,10 @@ function layoutfluid(): void {
if (timerDebug) console.timeEnd("layoutfluid");
}
-function checkIfFailed(wpmAndRaw: MonkeyTypes.WpmAndRaw, acc: number): void {
+function checkIfFailed(
+ wpmAndRaw: { wpm: number; raw: number },
+ acc: number
+): void {
if (timerDebug) console.time("fail conditions");
TestInput.pushKeypressesToHistory();
TestInput.pushErrorToHistory();
@@ -175,9 +185,9 @@ function checkIfTimeIsUp(): void {
// ---------------------------------------
-let timerStats: MonkeyTypes.TimerStats[] = [];
+let timerStats: TimerStats[] = [];
-export function getTimerStats(): MonkeyTypes.TimerStats[] {
+export function getTimerStats(): TimerStats[] {
return timerStats;
}
diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts
index 4385ae7df..5a0b825ff 100644
--- a/frontend/src/ts/test/test-ui.ts
+++ b/frontend/src/ts/test/test-ui.ts
@@ -113,7 +113,7 @@ async function joinOverlappingHints(
}
const debouncedZipfCheck = debounce(250, async () => {
- const supports = await Misc.checkIfLanguageSupportsZipf(Config.language);
+ const supports = await JSONData.checkIfLanguageSupportsZipf(Config.language);
if (supports === "no") {
Notifications.add(
`${Strings.capitalizeFirstLetter(
diff --git a/frontend/src/ts/test/test-words.ts b/frontend/src/ts/test/test-words.ts
index db0e79a37..d2ee8a778 100644
--- a/frontend/src/ts/test/test-words.ts
+++ b/frontend/src/ts/test/test-words.ts
@@ -1,3 +1,5 @@
+import { QuoteWithTextSplit } from "../controllers/quotes-controller";
+
class Words {
public list: string[];
public sectionIndexList: number[];
@@ -69,11 +71,9 @@ export const words = new Words();
export let hasTab = false;
export let hasNewline = false;
export let hasNumbers = false;
-export let currentQuote = null as MonkeyTypes.QuoteWithTextSplit | null;
+export let currentQuote = null as QuoteWithTextSplit | null;
-export function setCurrentQuote(
- rq: MonkeyTypes.QuoteWithTextSplit | null
-): void {
+export function setCurrentQuote(rq: QuoteWithTextSplit | null): void {
currentQuote = rq;
}
diff --git a/frontend/src/ts/test/wikipedia.ts b/frontend/src/ts/test/wikipedia.ts
index 5f2cf36df..5bed9a7c6 100644
--- a/frontend/src/ts/test/wikipedia.ts
+++ b/frontend/src/ts/test/wikipedia.ts
@@ -2,10 +2,9 @@ import * as Loader from "../elements/loader";
import * as Misc from "../utils/misc";
import * as Strings from "../utils/strings";
import * as JSONData from "../utils/json-data";
-import { Section } from "../utils/misc";
export async function getTLD(
- languageGroup: MonkeyTypes.LanguageGroup
+ languageGroup: JSONData.LanguageGroup
): Promise<
| "en"
| "es"
@@ -242,14 +241,14 @@ type SectionObject = {
author: string;
};
-export async function getSection(language: string): Promise<Section> {
+export async function getSection(language: string): Promise<JSONData.Section> {
// console.log("Getting section");
Loader.show();
// get TLD for wikipedia according to language group
let urlTLD = "en";
- let currentLanguageGroup: MonkeyTypes.LanguageGroup | undefined;
+ let currentLanguageGroup: JSONData.LanguageGroup | undefined;
try {
currentLanguageGroup = await JSONData.getCurrentGroup(language);
} catch (e) {
@@ -319,7 +318,7 @@ export async function getSection(language: string): Promise<Section> {
const words = sectionText.split(" ");
- const section = new Section(
+ const section = new JSONData.Section(
sectionObj.title,
sectionObj.author,
words
diff --git a/frontend/src/ts/test/words-generator.ts b/frontend/src/ts/test/words-generator.ts
index 822f7e693..00e31ebe2 100644
--- a/frontend/src/ts/test/words-generator.ts
+++ b/frontend/src/ts/test/words-generator.ts
@@ -2,7 +2,10 @@ import Config, * as UpdateConfig from "../config";
import * as FunboxList from "./funbox/funbox-list";
import * as CustomText from "./custom-text";
import * as Wordset from "./wordset";
-import QuotesController from "../controllers/quotes-controller";
+import QuotesController, {
+ Quote,
+ QuoteWithTextSplit,
+} from "../controllers/quotes-controller";
import * as TestWords from "./test-words";
import * as BritishEnglish from "./british-english";
import * as LazyMode from "./lazy-mode";
@@ -13,6 +16,7 @@ import * as Strings from "../utils/strings";
import * as Arrays from "../utils/arrays";
import * as TestState from "../test/test-state";
import * as GetText from "../utils/generate";
+import { FunboxWordOrder, LanguageObject } from "../utils/json-data";
function shouldCapitalize(lastChar: string): boolean {
return /[?!.؟]/.test(lastChar);
@@ -297,9 +301,7 @@ async function applyEnglishPunctuationToWord(word: string): Promise<string> {
return EnglishPunctuation.replace(word);
}
-function getFunboxWordsFrequency():
- | MonkeyTypes.FunboxWordsFrequency
- | undefined {
+function getFunboxWordsFrequency(): Wordset.FunboxWordsFrequency | undefined {
const wordFunbox = FunboxList.get(Config.funbox).find(
(f) => f.functions?.getWordsFrequencyMode
);
@@ -372,10 +374,7 @@ async function applyBritishEnglishToWord(
return await BritishEnglish.replace(word, previousWord);
}
-function applyLazyModeToWord(
- word: string,
- language: MonkeyTypes.LanguageObject
-): string {
+function applyLazyModeToWord(word: string, language: LanguageObject): string {
const allowLazyMode = !language.noLazyMode || Config.mode === "custom";
if (Config.lazyMode && allowLazyMode) {
word = LazyMode.replaceAccents(word, language.additionalAccents);
@@ -383,7 +382,7 @@ function applyLazyModeToWord(
return word;
}
-export function getWordOrder(): MonkeyTypes.FunboxWordOrder {
+export function getWordOrder(): FunboxWordOrder {
const wordOrder =
FunboxList.get(Config.funbox)
.find((f) => f.properties?.find((fp) => fp.startsWith("wordOrder")))
@@ -392,7 +391,7 @@ export function getWordOrder(): MonkeyTypes.FunboxWordOrder {
if (!wordOrder) {
return "normal";
} else {
- return wordOrder.split(":")[1] as MonkeyTypes.FunboxWordOrder;
+ return wordOrder.split(":")[1] as FunboxWordOrder;
}
}
@@ -422,7 +421,7 @@ export function getWordsLimit(): number {
limit = Config.words;
}
if (Config.mode === "quote") {
- limit = (currentQuote as MonkeyTypes.QuoteWithTextSplit).textSplit.length;
+ limit = (currentQuote as QuoteWithTextSplit).textSplit.length;
}
}
@@ -456,9 +455,9 @@ export function getWordsLimit(): number {
if (
Config.mode === "quote" &&
- (currentQuote as MonkeyTypes.QuoteWithTextSplit).textSplit.length < limit
+ (currentQuote as QuoteWithTextSplit).textSplit.length < limit
) {
- limit = (currentQuote as MonkeyTypes.QuoteWithTextSplit).textSplit.length;
+ limit = (currentQuote as QuoteWithTextSplit).textSplit.length;
}
if (
@@ -481,8 +480,8 @@ export class WordGenError extends Error {
}
async function getQuoteWordList(
- language: MonkeyTypes.LanguageObject,
- wordOrder?: MonkeyTypes.FunboxWordOrder
+ language: LanguageObject,
+ wordOrder?: FunboxWordOrder
): Promise<string[]> {
if (TestState.isRepeated) {
if (currentWordset === null) {
@@ -517,7 +516,7 @@ async function getQuoteWordList(
);
}
- let rq: MonkeyTypes.Quote;
+ let rq: Quote;
if (Config.quoteLength.includes(-2) && Config.quoteLength.length === 1) {
const targetQuote = QuotesController.getQuoteById(
TestState.selectedQuoteId
@@ -563,7 +562,7 @@ async function getQuoteWordList(
rq.textSplit = rq.text.split(" ");
}
- TestWords.setCurrentQuote(rq as MonkeyTypes.QuoteWithTextSplit);
+ TestWords.setCurrentQuote(rq as QuoteWithTextSplit);
if (TestWords.currentQuote === null) {
throw new WordGenError("Random quote is null");
@@ -577,7 +576,7 @@ async function getQuoteWordList(
}
let currentWordset: Wordset.Wordset | null = null;
-let currentLanguage: MonkeyTypes.LanguageObject | null = null;
+let currentLanguage: LanguageObject | null = null;
let isCurrentlyUsingFunboxSection = false;
type GenerateWordsReturn = {
@@ -587,10 +586,10 @@ type GenerateWordsReturn = {
hasNewline: boolean;
};
-let previousRandomQuote: MonkeyTypes.QuoteWithTextSplit | null = null;
+let previousRandomQuote: QuoteWithTextSplit | null = null;
export async function generateWords(
- language: MonkeyTypes.LanguageObject
+ language: LanguageObject
): Promise<GenerateWordsReturn> {
if (!TestState.isRepeated) {
previousGetNextWordReturns = [];
@@ -633,7 +632,15 @@ export async function generateWords(
wordList = wordList.reverse();
}
- currentWordset = await Wordset.withWords(wordList);
+ const wordFunbox = FunboxList.get(Config.funbox).find(
+ (f) => f.functions?.withWords
+ );
+ if (wordFunbox?.functions?.withWords) {
+ currentWordset = await wordFunbox.functions.withWords(wordList);
+ } else {
+ currentWordset = await Wordset.withWords(wordList);
+ }
+
console.debug("Wordset", currentWordset);
if (limit === 0) {
@@ -675,16 +682,12 @@ export async function generateWords(
ret.words.some((w) => w.includes("\t")) ||
currentWordset.words.some((w) => w.includes("\t")) ||
(Config.mode === "quote" &&
- (quote as MonkeyTypes.QuoteWithTextSplit).textSplit.some((w) =>
- w.includes("\t")
- ));
+ (quote as QuoteWithTextSplit).textSplit.some((w) => w.includes("\t")));
ret.hasNewline =
ret.words.some((w) => w.includes("\n")) ||
currentWordset.words.some((w) => w.includes("\n")) ||
(Config.mode === "quote" &&
- (quote as MonkeyTypes.QuoteWithTextSplit).textSplit.some((w) =>
- w.includes("\n")
- ));
+ (quote as QuoteWithTextSplit).textSplit.some((w) => w.includes("\n")));
sectionHistory = []; //free up a bit of memory? is that even a thing?
return ret;
diff --git a/frontend/src/ts/test/wordset.ts b/frontend/src/ts/test/wordset.ts
index 377f919df..4bab3c826 100644
--- a/frontend/src/ts/test/wordset.ts
+++ b/frontend/src/ts/test/wordset.ts
@@ -1,11 +1,11 @@
-import * as FunboxList from "./funbox/funbox-list";
import { zipfyRandomArrayIndex } from "../utils/misc";
import { randomElementFromArray, shuffle } from "../utils/arrays";
-import Config from "../config";
-let currentWordset: MonkeyTypes.Wordset | null = null;
+export type FunboxWordsFrequency = "normal" | "zipf";
-export class Wordset implements MonkeyTypes.Wordset {
+let currentWordset: Wordset | null = null;
+
+export class Wordset {
words: string[];
length: number;
orderedIndex: number;
@@ -23,7 +23,7 @@ export class Wordset implements MonkeyTypes.Wordset {
this.shuffledIndexes = [];
}
- randomWord(mode: MonkeyTypes.FunboxWordsFrequency): string {
+ randomWord(mode: FunboxWordsFrequency): string {
if (mode === "zipf") {
return this.words[zipfyRandomArrayIndex(this.words.length)] as string;
} else {
@@ -54,13 +54,7 @@ export class Wordset implements MonkeyTypes.Wordset {
}
}
-export async function withWords(words: string[]): Promise<MonkeyTypes.Wordset> {
- const wordFunbox = FunboxList.get(Config.funbox).find(
- (f) => f.functions?.withWords
- );
- if (wordFunbox?.functions?.withWords) {
- return wordFunbox.functions.withWords(words);
- }
+export async function withWords(words: string[]): Promise<Wordset> {
if (currentWordset === null || words !== currentWordset.words) {
currentWordset = new Wordset(words);
}
diff --git a/frontend/src/ts/types/types.d.ts b/frontend/src/ts/types/types.d.ts
deleted file mode 100644
index 54f008bd3..000000000
--- a/frontend/src/ts/types/types.d.ts
+++ /dev/null
@@ -1,510 +0,0 @@
-type Mode = import("@monkeytype/contracts/schemas/shared").Mode;
-type Result<M extends Mode> =
- import("@monkeytype/contracts/schemas/results").Result<M>;
-type IncompleteTest =
- import("@monkeytype/contracts/schemas/results").IncompleteTest;
-
-declare namespace MonkeyTypes {
- type PageName =
- | "loading"
- | "test"
- | "settings"
- | "about"
- | "account"
- | "login"
- | "profile"
- | "profileSearch"
- | "404"
- | "accountSettings";
-
- type LanguageGroup = {
- name: string;
- languages: string[];
- };
-
- type AddNotificationOptions = {
- important?: boolean;
- duration?: number;
- customTitle?: string;
- customIcon?: string;
- closeCallback?: () => void;
- allowHTML?: boolean;
- };
-
- type Accents = [string, string][];
-
- type LanguageObject = {
- name: string;
- rightToLeft: boolean;
- noLazyMode?: boolean;
- ligatures?: boolean;
- orderedByFrequency?: boolean;
- words: string[];
- additionalAccents: Accents;
- bcp47?: string;
- originalPunctuation?: boolean;
- };
-
- type DefaultWordsModes = 10 | 25 | 50 | 100;
-
- type DefaultTimeModes = 15 | 30 | 60 | 120;
-
- type QuoteModes = "short" | "medium" | "long" | "thicc";
-
- type CustomLayoutFluidSpaces =
- | import("@monkeytype/contracts/schemas/configs").CustomLayoutFluid
- | `${string} ${string} ${string}`;
-
- type HistoryChartData = {
- x: number;
- y: number;
- wpm: number;
- acc: number;
- mode: string;
- mode2: string;
- punctuation: boolean;
- language: string;
- timestamp: number;
- difficulty: string;
- raw: number;
- isPb: boolean;
- };
-
- type AccChartData = {
- x: number;
- y: number;
- errorRate: number;
- };
-
- type OtherChartData = {
- x: number;
- y: number;
- };
-
- type ActivityChartDataPoint = {
- x: number;
- y: number;
- amount?: number;
- };
-
- type FontObject = {
- name: string;
- display?: string;
- systemFont?: string;
- };
-
- type FunboxWordsFrequency = "normal" | "zipf";
-
- type FunboxWordOrder = "normal" | "reverse";
-
- type FunboxProperty =
- | "symmetricChars"
- | "conflictsWithSymmetricChars"
- | "changesWordsVisibility"
- | "speaks"
- | "unspeakable"
- | "changesLayout"
- | "ignoresLayout"
- | "usesLayout"
- | "ignoresLanguage"
- | "noLigatures"
- | "noLetters"
- | "changesCapitalisation"
- | "nospace"
- | `toPush:${number}`
- | "noInfiniteDuration"
- | "changesWordsFrequency"
- | `wordOrder:${FunboxWordOrder}`;
-
- class Wordset {
- words: string[];
- length: number;
- orderedIndex: number;
- shuffledIndexes: number[];
- constructor(words: string[]);
- resetIndexes(): void;
- randomWord(mode: MonkeyTypes.FunboxWordsFrequency): string;
- shuffledWord(): string;
- generateShuffledIndexes(): void;
- nextWord(): string;
- }
-
- class Section {
- public title: string;
- public author: string;
- public words: string[];
- constructor(title: string, author: string, words: string[]);
- }
-
- type FunboxFunctions = {
- getWord?: (wordset?: Wordset, wordIndex?: number) => string;
- punctuateWord?: (word: string) => string;
- withWords?: (words?: string[]) => Promise<Wordset>;
- alterText?: (word: string) => string;
- applyConfig?: () => void;
- applyGlobalCSS?: () => void;
- clearGlobal?: () => void;
- rememberSettings?: () => void;
- toggleScript?: (params: string[]) => void;
- pullSection?: (language?: string) => Promise<Section | false>;
- handleSpace?: () => void;
- handleChar?: (char: string) => string;
- isCharCorrect?: (char: string, originalChar: string) => boolean;
- preventDefaultEvent?: (
- event: JQuery.KeyDownEvent<Document, null, Document, Document>
- ) => Promise<boolean>;
- handleKeydown?: (
- event: JQuery.KeyDownEvent<Document, null, Document, Document>
- ) => Promise<void>;
- getResultContent?: () => string;
- start?: () => void;
- restart?: () => void;
- getWordHtml?: (char: string, letterTag?: boolean) => string;
- getWordsFrequencyMode?: () => FunboxWordsFrequency;
- };
-
- type FunboxForcedConfig = Record<
- string,
- import("@monkeytype/contracts/schemas/configs").ConfigValue[]
- >;
-
- type FunboxMetadata = {
- name: string;
- info: string;
- canGetPb?: boolean;
- alias?: string;
- forcedConfig?: MonkeyTypes.FunboxForcedConfig;
- properties?: FunboxProperty[];
- functions?: FunboxFunctions;
- hasCSS?: boolean;
- };
-
- type SnapshotPreset =
- import("@monkeytype/contracts/schemas/presets").Preset & {
- display: string;
- };
-
- type RawCustomTheme = {
- name: string;
- colors: import("@monkeytype/contracts/schemas/configs").CustomThemeColors;
- };
-
- type CustomTheme = {
- _id: string;
- } & RawCustomTheme;
-
- type ConfigChanges = Partial<
- import("@monkeytype/contracts/schemas/configs").Config
- >;
-
- type LeaderboardMemory = {
- time: {
- [_key in "15" | "60"]: Record<string, number>;
- };
- };
-
- type QuoteRatings = Record<string, Record<number, number>>;
-
- type UserTag = import("@monkeytype/contracts/schemas/users").UserTag & {
- active?: boolean;
- display: string;
- };
-
- type Snapshot = Omit<
- import("@monkeytype/contracts/schemas/users").User,
- | "timeTyping"
- | "startedTests"
- | "completedTests"
- | "profileDetails"
- | "streak"
- | "resultFilterPresets"
- | "tags"
- | "xp"
- | "testActivity"
- > & {
- typingStats: {
- timeTyping: number;
- startedTests: number;
- completedTests: number;
- };
- details?: import("@monkeytype/contracts/schemas/users").UserProfileDetails;
- inboxUnreadSize: number;
- streak: number;
- maxStreak: number;
- filterPresets: import("@monkeytype/contracts/schemas/users").ResultFilters[];
- isPremium: boolean;
- streakHourOffset?: number;
- config: import("@monkeytype/contracts/schemas/configs").Config;
- tags: UserTag[];
- presets: SnapshotPreset[];
- results?: MonkeyTypes.FullResult<Mode>[];
- xp: number;
- testActivity?: ModifiableTestActivityCalendar;
- testActivityByYear?: { [key: string]: TestActivityCalendar };
- };
-
- type TimerStats = {
- dateNow: number;
- now: number;
- expected: number;
- nextDelay: number;
- };
-
- type GithubRelease = {
- url: string;
- assets_url: string;
- upload_url: string;
- html_url: string;
- id: number;
- author: {
- login: string;
- id: number;
- node_id: string;
- avatar_url: string;
- gravatar_id: string;
- url: string;
- html_url: string;
- followers_url: string;
- following_url: string;
- gists_url: string;
- starred_url: string;
- subscriptions_url: string;
- organizations_url: string;
- repos_url: string;
- events_url: string;
- received_events_url: string;
- type: string;
- site_admin: boolean;
- };
- node_id: string;
- tag_name: string;
- target_commitish: string;
- name: string;
- draft: boolean;
- prerelease: boolean;
- created_at: string;
- published_at: string;
- assets: unknown[];
- tarball_url: string;
- zipball_url: string;
- body: string;
- reactions: {
- url: string;
- total_count: number;
- [reaction: string]: number | string;
- };
- };
-
- type CommandExecOptions = {
- input?: string;
- commandlineModal: import("../utils/animated-modal").default;
- };
-
- type Command = {
- id: string;
- display: string;
- singleListDisplay?: string;
- singleListDisplayNoIcon?: string;
- subgroup?: CommandsSubgroup;
- found?: boolean;
- icon?: string;
- sticky?: boolean;
- alias?: string;
- input?: boolean;
- visible?: boolean;
- customStyle?: string;
- opensModal?: boolean;
- defaultValue?: () => string;
- configKey?: keyof import("@monkeytype/contracts/schemas/configs").Config;
- configValue?: string | number | boolean | number[];
- configValueMode?: "include";
- exec?: (options: CommandExecOptions) => void;
- hover?: () => void;
- available?: () => boolean;
- active?: () => boolean;
- shouldFocusTestUI?: boolean;
- customData?: Record<string, string | boolean>;
- };
-
- type CommandsSubgroup = {
- title: string;
- configKey?: keyof import("@monkeytype/contracts/schemas/configs").Config;
- list: Command[];
- beforeList?: () => void;
- };
-
- type Theme = {
- name: string;
- bgColor: string;
- mainColor: string;
- subColor: string;
- textColor: string;
- };
-
- type Quote = {
- text: string;
- britishText?: string;
- source: string;
- length: number;
- id: number;
- group: number;
- language: string;
- textSplit?: string[];
- };
-
- type QuoteWithTextSplit = Quote & {
- textSplit: string[];
- };
-
- type ThemeColors = {
- bg: string;
- main: string;
- caret: string;
- sub: string;
- subAlt: string;
- text: string;
- error: string;
- errorExtra: string;
- colorfulError: string;
- colorfulErrorExtra: string;
- };
-
- type Layout = {
- keymapShowTopRow: boolean;
- matrixShowRightColumn?: boolean;
- type: "iso" | "ansi" | "ortho" | "matrix";
- keys: Keys;
- };
-
- type Layouts = Record<string, Layout>;
- type Keys = {
- row1: string[];
- row2: string[];
- row3: string[];
- row4: string[];
- row5: string[];
- };
-
- type WpmAndRaw = {
- wpm: number;
- raw: number;
- };
-
- type Challenge = {
- name: string;
- display: string;
- autoRole: boolean;
- type: string;
- parameters: (string | number | boolean)[];
- message: string;
- requirements: Record<string, Record<string, string | number | boolean>>;
- };
-
- type UserBadge = {
- id: number;
- name: string;
- description: string;
- icon?: string;
- background?: string;
- color?: string;
- customStyle?: string;
- };
-
- type MonkeyMail = {
- id: string;
- subject: string;
- body: string;
- timestamp: number;
- read: boolean;
- rewards: AllRewards[];
- };
-
- type Reward<T> = {
- type: string;
- item: T;
- };
-
- type XpReward = {
- type: "xp";
- item: number;
- } & Reward<number>;
-
- type BadgeReward = {
- type: "badge";
- item: import("@monkeytype/contracts/schemas/users").Badge;
- } & Reward<import("@monkeytype/contracts/schemas/users").Badge>;
-
- type AllRewards = XpReward | BadgeReward;
-
- type TypingSpeedUnitSettings = {
- fromWpm: (number: number) => number;
- toWpm: (number: number) => number;
- fullUnitString: string;
- histogramDataBucketSize: number;
- historyStepSize: number;
- };
-
- type TestActivityCalendar = {
- getMonths: () => TestActivityMonth[];
- getDays: () => TestActivityDay[];
- getTotalTests: () => number;
- };
-
- type ModifiableTestActivityCalendar = TestActivityCalendar & {
- increment: (date: Date) => void;
- getFullYearCalendar: () => TestActivityCalendar;
- };
-
- type TestActivityDay = {
- level: string;
- label?: string;
- };
-
- type TestActivityMonth = {
- text: string;
- weeks: number;
- };
-
- /**
- * Result from the rest api but all omittable default values are set (and non optional)
- */
- type FullResult<M extends Mode> = Omit<
- Result<M>,
- | "restartCount"
- | "incompleteTestSeconds"
- | "afkDuration"
- | "tags"
- | "bailedOut"
- | "blindMode"
- | "lazyMode"
- | "funbox"
- | "language"
- | "difficulty"
- | "numbers"
- | "punctuation"
- > & {
- restartCount: number;
- incompleteTestSeconds: number;
- afkDuration: number;
- tags: string[];
- bailedOut: boolean;
- blindMode: boolean;
- lazyMode: boolean;
- funbox: string;
- language: string;
- difficulty: import("@monkeytype/contracts/schemas/shared").Difficulty;
- numbers: boolean;
- punctuation: boolean;
- };
- type CustomTextLimit = {
- value: number;
- mode: import("@monkeytype/contracts/schemas/util").CustomTextLimitMode;
- };
-
- type CustomTextData = Omit<
- import("@monkeytype/contracts/schemas/results").CustomTextDataWithTextLen,
- "textLen"
- > & {
- text: string[];
- };
-}
diff --git a/frontend/src/ts/utils/json-data.ts b/frontend/src/ts/utils/json-data.ts
index e2898e5d2..79909d5c4 100644
--- a/frontend/src/ts/utils/json-data.ts
+++ b/frontend/src/ts/utils/json-data.ts
@@ -1,4 +1,7 @@
+import { ConfigValue } from "@monkeytype/contracts/schemas/configs";
+import { Accents } from "../test/lazy-mode";
import { hexToHSL } from "./colors";
+import { FunboxWordsFrequency, Wordset } from "../test/wordset";
/**
* Fetches JSON data from the specified URL using the fetch API.
@@ -62,13 +65,30 @@ export const cachedFetchJson = memoizeAsync<string, typeof fetchJson>(
fetchJson
);
+export type Keys = {
+ row1: string[];
+ row2: string[];
+ row3: string[];
+ row4: string[];
+ row5: string[];
+};
+
+export type Layout = {
+ keymapShowTopRow: boolean;
+ matrixShowRightColumn?: boolean;
+ type: "iso" | "ansi" | "ortho" | "matrix";
+ keys: Keys;
+};
+
+export type LayoutsList = Record<string, Layout>;
+
/**
* Fetches the layouts list from the server.
* @returns A promise that resolves to the layouts list.
*/
-export async function getLayoutsList(): Promise<MonkeyTypes.Layouts> {
+export async function getLayoutsList(): Promise<LayoutsList> {
try {
- const layoutsList = await cachedFetchJson<MonkeyTypes.Layouts>(
+ const layoutsList = await cachedFetchJson<LayoutsList>(
"/layouts/_list.json"
);
return layoutsList;
@@ -83,9 +103,7 @@ export async function getLayoutsList(): Promise<MonkeyTypes.Layouts> {
* @returns A promise that resolves to the layout object.
* @throws {Error} If the layout list or layout doesn't exist.
*/
-export async function getLayout(
- layoutName: string
-): Promise<MonkeyTypes.Layout> {
+export async function getLayout(layoutName: string): Promise<Layout> {
const layouts = await getLayoutsList();
const layout = layouts[layoutName];
if (layout === undefined) {
@@ -94,20 +112,26 @@ export async function getLayout(
return layout;
}
-let themesList: MonkeyTypes.Theme[] | undefined;
+export type Theme = {
+ name: string;
+ bgColor: string;
+ mainColor: string;
+ subColor: string;
+ textColor: string;
+};
+
+let themesList: Theme[] | undefined;
/**
* Fetches the list of themes from the server, sorting them alphabetically by name.
* If the list has already been fetched, returns the cached list.
* @returns A promise that resolves to the sorted list of themes.
*/
-export async function getThemesList(): Promise<MonkeyTypes.Theme[]> {
+export async function getThemesList(): Promise<Theme[]> {
if (!themesList) {
- let themes = await cachedFetchJson<MonkeyTypes.Theme[]>(
- "/themes/_list.json"
- );
+ let themes = await cachedFetchJson<Theme[]>("/themes/_list.json");
- themes = themes.sort(function (a: MonkeyTypes.Theme, b: MonkeyTypes.Theme) {
+ themes = themes.sort((a, b) => {
const nameA = a.name.toLowerCase();
const nameB = b.name.toLowerCase();
if (nameA < nameB) return -1;
@@ -121,13 +145,13 @@ export async function getThemesList(): Promise<MonkeyTypes.Theme[]> {
}
}
-let sortedThemesList: MonkeyTypes.Theme[] | undefined;
+let sortedThemesList: Theme[] | undefined;
/**
* Fetches the sorted list of themes from the server.
* @returns A promise that resolves to the sorted list of themes.
*/
-export async function getSortedThemesList(): Promise<MonkeyTypes.Theme[]> {
+export async function getSortedThemesList(): Promise<Theme[]> {
if (!sortedThemesList) {
if (!themesList) {
await getThemesList();
@@ -163,42 +187,64 @@ export async function getLanguageList(): Promise<string[]> {
}
}
+export type LanguageGroup = {
+ name: string;
+ languages: string[];
+};
+
/**
* Fetches the list of language groups from the server.
* @returns A promise that resolves to the list of language groups.
*/
-export async function getLanguageGroups(): Promise<
- MonkeyTypes.LanguageGroup[]
-> {
+export async function getLanguageGroups(): Promise<LanguageGroup[]> {
try {
- const languageGroupList = await cachedFetchJson<
- MonkeyTypes.LanguageGroup[]
- >("/languages/_groups.json");
+ const languageGroupList = await cachedFetchJson<LanguageGroup[]>(
+ "/languages/_groups.json"
+ );
return languageGroupList;
} catch (e) {
throw new Error("Language groups JSON fetch failed");
}
}
-let currentLanguage: MonkeyTypes.LanguageObject;
+export type LanguageObject = {
+ name: string;
+ rightToLeft: boolean;
+ noLazyMode?: boolean;
+ ligatures?: boolean;
+ orderedByFrequency?: boolean;
+ words: string[];
+ additionalAccents: Accents;
+ bcp47?: string;
+ originalPunctuation?: boolean;
+};
+
+let currentLanguage: LanguageObject;
/**
* Fetches the language object for a given language from the server.
* @param lang The language code.
* @returns A promise that resolves to the language object.
*/
-export async function getLanguage(
- lang: string
-): Promise<MonkeyTypes.LanguageObject> {
+export async function getLanguage(lang: string): Promise<LanguageObject> {
// try {
if (currentLanguage === undefined || currentLanguage.name !== lang) {
- currentLanguage = await cachedFetchJson<MonkeyTypes.LanguageObject>(
+ currentLanguage = await cachedFetchJson<LanguageObject>(
`/languages/${lang}.json`
);
}
return currentLanguage;
}
+export async function checkIfLanguageSupportsZipf(
+ language: string
+): Promise<"yes" | "no" | "unknown"> {
+ const lang = await getLanguage(language);
+ if (lang.orderedByFrequency === true) return "yes";
+ if (lang.orderedByFrequency === false) return "no";
+ return "unknown";
+}
+
/**
* Fetches the current language object.
* @param languageName The name of the language.
@@ -206,7 +252,7 @@ export async function getLanguage(
*/
export async function getCurrentLanguage(
languageName: string
-): Promise<MonkeyTypes.LanguageObject> {
+): Promise<LanguageObject> {
return await getLanguage(languageName);
}
@@ -217,8 +263,8 @@ export async function getCurrentLanguage(
*/
export async function getCurrentGroup(
language: string
-): Promise<MonkeyTypes.LanguageGroup | undefined> {
- let retgroup: MonkeyTypes.LanguageGroup | undefined;
+): Promise<LanguageGroup | undefined> {
+ let retgroup: LanguageGroup | undefined;
const groups = await getLanguageGroups();
groups.forEach((group) => {
if (retgroup === undefined) {
@@ -230,21 +276,16 @@ export async function getCurrentGroup(
return retgroup;
}
-let funboxList: MonkeyTypes.FunboxMetadata[] | undefined;
+let funboxList: FunboxMetadata[] | undefined;
/**
* Fetches the list of funbox metadata from the server.
* @returns A promise that resolves to the list of funbox metadata.
*/
-export async function getFunboxList(): Promise<MonkeyTypes.FunboxMetadata[]> {
+export async function getFunboxList(): Promise<FunboxMetadata[]> {
if (!funboxList) {
- let list = await cachedFetchJson<MonkeyTypes.FunboxMetadata[]>(
- "/funbox/_list.json"
- );
- list = list.sort(function (
- a: MonkeyTypes.FunboxMetadata,
- b: MonkeyTypes.FunboxMetadata
- ) {
+ let list = await cachedFetchJson<FunboxMetadata[]>("/funbox/_list.json");
+ list = list.sort((a, b) => {
const nameA = a.name.toLowerCase();
const nameB = b.name.toLowerCase();
if (nameA < nameB) return -1;
@@ -258,6 +299,78 @@ export async function getFunboxList(): Promise<MonkeyTypes.FunboxMetadata[]> {
}
}
+export class Section {
+ public title: string;
+ public author: string;
+ public words: string[];
+ constructor(title: string, author: string, words: string[]) {
+ this.title = title;
+ this.author = author;
+ this.words = words;
+ }
+}
+
+export type FunboxMetadata = {
+ name: string;
+ info: string;
+ canGetPb?: boolean;
+ alias?: string;
+ forcedConfig?: FunboxForcedConfig;
+ properties?: FunboxProperty[];
+ functions?: FunboxFunctions;
+ hasCSS?: boolean;
+};
+
+export type FunboxWordOrder = "normal" | "reverse";
+
+type FunboxProperty =
+ | "symmetricChars"
+ | "conflictsWithSymmetricChars"
+ | "changesWordsVisibility"
+ | "speaks"
+ | "unspeakable"
+ | "changesLayout"
+ | "ignoresLayout"
+ | "usesLayout"
+ | "ignoresLanguage"
+ | "noLigatures"
+ | "noLetters"
+ | "changesCapitalisation"
+ | "nospace"
+ | `toPush:${number}`
+ | "noInfiniteDuration"
+ | "changesWordsFrequency"
+ | `wordOrder:${FunboxWordOrder}`;
+
+export type FunboxForcedConfig = Record<string, ConfigValue[]>;
+
+export type FunboxFunctions = {
+ getWord?: (wordset?: Wordset, wordIndex?: number) => string;
+ punctuateWord?: (word: string) => string;
+ withWords?: (words?: string[]) => Promise<Wordset>;
+ alterText?: (word: string) => string;
+ applyConfig?: () => void;
+ applyGlobalCSS?: () => void;
+ clearGlobal?: () => void;
+ rememberSettings?: () => void;
+ toggleScript?: (params: string[]) => void;
+ pullSection?: (language?: string) => Promise<Section | false>;
+ handleSpace?: () => void;
+ handleChar?: (char: string) => string;
+ isCharCorrect?: (char: string, originalChar: string) => boolean;
+ preventDefaultEvent?: (
+ event: JQuery.KeyDownEvent<Document, null, Document, Document>
+ ) => Promise<boolean>;
+ handleKeydown?: (
+ event: JQuery.KeyDownEvent<Document, null, Document, Document>
+ ) => Promise<void>;
+ getResultContent?: () => string;
+ start?: () => void;
+ restart?: () => void;
+ getWordHtml?: (char: string, letterTag?: boolean) => string;
+ getWordsFrequencyMode?: () => FunboxWordsFrequency;
+};
+
/**
* Fetches the funbox metadata for a given funbox from the server.
* @param funbox The name of the funbox.
@@ -265,28 +378,29 @@ export async function getFunboxList(): Promise<MonkeyTypes.FunboxMetadata[]> {
*/
export async function getFunbox(
funbox: string
-): Promise<MonkeyTypes.FunboxMetadata | undefined> {
- const list: MonkeyTypes.FunboxMetadata[] = await getFunboxList();
+): Promise<FunboxMetadata | undefined> {
+ const list: FunboxMetadata[] = await getFunboxList();
return list.find(function (element) {
return element.name === funbox;
});
}
-let fontsList: MonkeyTypes.FontObject[] | undefined;
+export type FontObject = {
+ name: string;
+ display?: string;
+ systemFont?: string;
+};
+
+let fontsList: FontObject[] | undefined;
/**
* Fetches the list of font objects from the server.
* @returns A promise that resolves to the list of font objects.
*/
-export async function getFontsList(): Promise<MonkeyTypes.FontObject[]> {
+export async function getFontsList(): Promise<FontObject[]> {
if (!fontsList) {
- let list = await cachedFetchJson<MonkeyTypes.FontObject[]>(
- "/fonts/_list.json"
- );
- list = list.sort(function (
- a: MonkeyTypes.FontObject,
- b: MonkeyTypes.FontObject
- ) {
+ let list = await cachedFetchJson<FontObject[]>("/fonts/_list.json");
+ list = list.sort((a, b) => {
const nameA = a.name.toLowerCase();
const nameB = b.name.toLowerCase();
if (nameA < nameB) return -1;
@@ -300,15 +414,23 @@ export async function getFontsList(): Promise<MonkeyTypes.FontObject[]> {
}
}
+export type Challenge = {
+ name: string;
+ display: string;
+ autoRole: boolean;
+ type: string;
+ parameters: (string | number | boolean)[];
+ message: string;
+ requirements: Record<string, Record<string, string | number | boolean>>;
+};
+
/**
* Fetches the list of challenges from the server.
* @returns A promise that resolves to the list of challenges.
*/
-export async function getChallengeList(): Promise<MonkeyTypes.Challenge[]> {
+export async function getChallengeList(): Promise<Challenge[]> {
try {
- const data = await cachedFetchJson<MonkeyTypes.Challenge[]>(
- "/challenges/_list.json"
- );
+ const data = await cachedFetchJson<Challenge[]>("/challenges/_list.json");
return data;
} catch (e) {
throw new Error("Challenge list JSON fetch failed");
@@ -341,6 +463,51 @@ export async function getContributorsList(): Promise<string[]> {
}
}
+type GithubRelease = {
+ url: string;
+ assets_url: string;
+ upload_url: string;
+ html_url: string;
+ id: number;
+ author: {
+ login: string;
+ id: number;
+ node_id: string;
+ avatar_url: string;
+ gravatar_id: string;
+ url: string;
+ html_url: string;
+ followers_url: string;
+ following_url: string;
+ gists_url: string;
+ starred_url: string;
+ subscriptions_url: string;
+ organizations_url: string;
+ repos_url: string;
+ events_url: string;
+ received_events_url: string;
+ type: string;
+ site_admin: boolean;
+ };
+ node_id: string;
+ tag_name: string;
+ target_commitish: string;
+ name: string;
+ draft: boolean;
+ prerelease: boolean;
+ created_at: string;
+ published_at: string;
+ assets: unknown[];
+ tarball_url: string;
+ zipball_url: string;
+ body: string;
+ reactions: {
+ url: string;
+ total_count: number;
+ [reaction: string]: number | string;
+ };
+};
+
/**
* Fetches the latest release name from GitHub.
* @returns A promise that resolves to the latest release name.
@@ -360,9 +527,7 @@ export async function getLatestReleaseFromGitHub(): Promise<string> {
* Fetches the list of releases from GitHub.
* @returns A promise that resolves to the list of releases.
*/
-export async function getReleasesFromGitHub(): Promise<
- MonkeyTypes.GithubRelease[]
-> {
+export async function getReleasesFromGitHub(): Promise<GithubRelease[]> {
return cachedFetchJson(
"https://api.github.com/repos/monkeytypegame/monkeytype/releases?per_page=5"
);
diff --git a/frontend/src/ts/utils/misc.ts b/frontend/src/ts/utils/misc.ts
index bc785a172..82651157c 100644
--- a/frontend/src/ts/utils/misc.ts
+++ b/frontend/src/ts/utils/misc.ts
@@ -1,7 +1,6 @@
import * as Loader from "../elements/loader";
import { envConfig } from "../constants/env-config";
import { lastElementFromArray } from "./arrays";
-import * as JSONData from "./json-data";
import { Config } from "@monkeytype/contracts/schemas/configs";
import {
Mode,
@@ -9,6 +8,10 @@ import {
PersonalBests,
} from "@monkeytype/contracts/schemas/shared";
import { ZodError, ZodSchema } from "zod";
+import {
+ CustomTextDataWithTextLen,
+ Result,
+} from "@monkeytype/contracts/schemas/results";
export function whorf(speed: number, wordlen: number): number {
return Math.min(
@@ -196,7 +199,7 @@ export function canQuickRestart(
mode: string,
words: number,
time: number,
- CustomText: MonkeyTypes.CustomTextData,
+ CustomText: Omit<CustomTextDataWithTextLen, "textLen">,
customTextIsLong: boolean
): boolean {
const wordsLong = mode === "words" && (words >= 1000 || words === 0);
@@ -357,7 +360,7 @@ export async function swapElements(
export function getMode2<M extends keyof PersonalBests>(
config: Config,
- randomQuote: MonkeyTypes.Quote | null
+ randomQuote: { id: number } | null
): Mode2<M> {
const mode = config.mode;
let retVal: string;
@@ -379,9 +382,7 @@ export function getMode2<M extends keyof PersonalBests>(
return retVal as Mode2<M>;
}
-export async function downloadResultsCSV(
- array: MonkeyTypes.FullResult<Mode>[]
-): Promise<void> {
+export async function downloadResultsCSV(array: Result<Mode>[]): Promise<void> {
Loader.show();
const csvString = [
[
@@ -410,7 +411,7 @@ export async function downloadResultsCSV(
"tags",
"timestamp",
],
- ...array.map((item: MonkeyTypes.FullResult<Mode>) => [
+ ...array.map((item) => [
item._id,
item.isPb,
item.wpm,
@@ -433,7 +434,7 @@ export async function downloadResultsCSV(
item.lazyMode,
item.blindMode,
item.bailedOut,
- item.tags.join(";"),
+ item.tags?.join(";"),
item.timestamp,
]),
]
@@ -532,17 +533,6 @@ export async function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
-export class Section {
- public title: string;
- public author: string;
- public words: string[];
- constructor(title: string, author: string, words: string[]) {
- this.title = title;
- this.author = author;
- this.words = words;
- }
-}
-
export function isPasswordStrong(password: string): boolean {
const hasCapital = !!password.match(/[A-Z]/);
const hasNumber = !!password.match(/[\d]/);
@@ -597,15 +587,6 @@ export function zipfyRandomArrayIndex(dictLength: number): number {
return Math.floor(inverseCDF);
}
-export async function checkIfLanguageSupportsZipf(
- language: string
-): Promise<"yes" | "no" | "unknown"> {
- const lang = await JSONData.getLanguage(language);
- if (lang.orderedByFrequency === true) return "yes";
- if (lang.orderedByFrequency === false) return "no";
- return "unknown";
-}
-
// Function to get the bounding rectangle of a collection of elements
export function getBoundingRectOfElements(elements: HTMLElement[]): DOMRect {
let minX = Infinity,
diff --git a/frontend/src/ts/utils/results.ts b/frontend/src/ts/utils/results.ts
index ab04f2e58..cb065eec6 100644
--- a/frontend/src/ts/utils/results.ts
+++ b/frontend/src/ts/utils/results.ts
@@ -2,6 +2,8 @@ import Ape from "../ape";
import * as Notifications from "../elements/notifications";
import * as DB from "../db";
import * as TestLogic from "../test/test-logic";
+import { deepClone } from "./misc";
+import { Mode } from "@monkeytype/contracts/schemas/shared";
export async function syncNotSignedInLastResult(uid: string): Promise<void> {
const notSignedInLastResult = TestLogic.notSignedInLastResult;
@@ -19,9 +21,12 @@ export async function syncNotSignedInLastResult(uid: string): Promise<void> {
return;
}
- const result = JSON.parse(
- JSON.stringify(notSignedInLastResult)
- ) as MonkeyTypes.FullResult<Mode>;
+ //TODO - this type cast was not needed before because we were using JSON cloning
+ // but now with the stronger types it shows that we are forcing completed event
+ // into a snapshot result - might not cuase issues but worth investigating
+ const result = deepClone(
+ notSignedInLastResult
+ ) as unknown as DB.SnapshotResult<Mode>;
result._id = response.body.data.insertedId;
if (response.body.data.isPb) {
result.isPb = true;
diff --git a/frontend/src/ts/utils/simple-modal.ts b/frontend/src/ts/utils/simple-modal.ts
index e9927a7e3..6763627fa 100644
--- a/frontend/src/ts/utils/simple-modal.ts
+++ b/frontend/src/ts/utils/simple-modal.ts
@@ -62,7 +62,7 @@ export type ExecReturn = {
status: 1 | 0 | -1;
message: string;
showNotification?: false;
- notificationOptions?: MonkeyTypes.AddNotificationOptions;
+ notificationOptions?: Notifications.AddNotificationOptions;
hideOptions?: HideOptions;
afterHide?: () => void;
};
diff --git a/frontend/src/ts/utils/typing-speed-units.ts b/frontend/src/ts/utils/typing-speed-units.ts
index 9d0f8bb4e..214b5a5ea 100644
--- a/frontend/src/ts/utils/typing-speed-units.ts
+++ b/frontend/src/ts/utils/typing-speed-units.ts
@@ -1,6 +1,14 @@
import { TypingSpeedUnit } from "@monkeytype/contracts/schemas/configs";
-class Unit implements MonkeyTypes.TypingSpeedUnitSettings {
+type TypingSpeedUnitSettings = {
+ fromWpm: (number: number) => number;
+ toWpm: (number: number) => number;
+ fullUnitString: string;
+ histogramDataBucketSize: number;
+ historyStepSize: number;
+};
+
+class Unit implements TypingSpeedUnitSettings {
unit: TypingSpeedUnit;
convertFactor: number;
fullUnitString: string;
@@ -38,8 +46,6 @@ const typingSpeedUnits: Record<TypingSpeedUnit, Unit> = {
wph: new Unit("wph", 60, "Words per Hour", 250, 1000),
};
-export function get(
- unit: TypingSpeedUnit
-): MonkeyTypes.TypingSpeedUnitSettings {
+export function get(unit: TypingSpeedUnit): TypingSpeedUnitSettings {
return typingSpeedUnits[unit];
}
diff --git a/frontend/src/ts/utils/url-handler.ts b/frontend/src/ts/utils/url-handler.ts
index dc05b8c63..7ba713e49 100644
--- a/frontend/src/ts/utils/url-handler.ts
+++ b/frontend/src/ts/utils/url-handler.ts
@@ -134,7 +134,7 @@ export function loadCustomThemeFromUrl(getOverride?: string): void {
type SharedTestSettings = [
Mode | null,
Mode2<Mode> | null,
- MonkeyTypes.CustomTextData | null,
+ CustomText.CustomTextData | null,
boolean | null,
boolean | null,
string | null,
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index a74452381..d4de7464f 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -9,10 +9,6 @@
"target": "ES6",
"noEmit": true
},
- "include": [
- "./src/**/*.ts",
- "./scripts/**/*.ts",
- "./src/ts/ape/types/*.d.ts"
- ],
+ "include": ["./src/**/*.ts", "./scripts/**/*.ts"],
"exclude": ["node_modules", "build", "setup-tests.ts", "**/*.spec.ts"]
}
diff --git a/packages/contracts/src/schemas/shared.ts b/packages/contracts/src/schemas/shared.ts
index e80e9a2d8..df10f0363 100644
--- a/packages/contracts/src/schemas/shared.ts
+++ b/packages/contracts/src/schemas/shared.ts
@@ -39,7 +39,34 @@ export const PersonalBestsSchema = z.object({
});
export type PersonalBests = z.infer<typeof PersonalBestsSchema>;
-//used by user, config, public
+export const DefaultWordsModeSchema = z.union([
+ z.literal("10"),
+ z.literal("25"),
+ z.literal("50"),
+ z.literal("100"),
+]);
+
+export const DefaultTimeModeSchema = z.union([
+ z.literal("15"),
+ z.literal("30"),
+ z.literal("60"),
+ z.literal("120"),
+]);
+
+export const QuoteLengthSchema = z.union([
+ z.literal("short"),
+ z.literal("medium"),
+ z.literal("long"),
+ z.literal("thicc"),
+]);
+
+// // Step 1: Define the schema for specific string values "10" and "25"
+// const SpecificKeySchema = z.union([z.literal("10"), z.literal("25")]);
+
+// // Step 2: Use this schema as the key schema for another object
+// export const ExampleSchema = z.record(SpecificKeySchema, z.string());
+
+// //used by user, config, public
export const ModeSchema = PersonalBestsSchema.keyof();
export type Mode = z.infer<typeof ModeSchema>;
diff --git a/packages/contracts/src/schemas/users.ts b/packages/contracts/src/schemas/users.ts
index 9bcf3c417..d1f986fd4 100644
--- a/packages/contracts/src/schemas/users.ts
+++ b/packages/contracts/src/schemas/users.ts
@@ -1,6 +1,14 @@
import { z, ZodEffects, ZodOptional, ZodString } from "zod";
import { IdSchema, LanguageSchema, StringNumberSchema } from "./util";
-import { ModeSchema, Mode2Schema, PersonalBestsSchema } from "./shared";
+import {
+ ModeSchema,
+ Mode2Schema,
+ PersonalBestsSchema,
+ DefaultWordsModeSchema,
+ DefaultTimeModeSchema,
+ QuoteLengthSchema,
+ DifficultySchema,
+} from "./shared";
import { CustomThemeColorsSchema } from "./configs";
import { doesNotContainProfanity } from "../validation/validation";
@@ -16,40 +24,11 @@ export const ResultFiltersSchema = z.object({
yes: z.boolean(),
})
.strict(),
- difficulty: z
- .object({
- normal: z.boolean(),
- expert: z.boolean(),
- master: z.boolean(),
- })
- .strict(),
+ difficulty: z.record(DifficultySchema, z.boolean()),
mode: z.record(ModeSchema, z.boolean()),
- words: z
- .object({
- "10": z.boolean(),
- "25": z.boolean(),
- "50": z.boolean(),
- "100": z.boolean(),
- custom: z.boolean(),
- })
- .strict(),
- time: z
- .object({
- "15": z.boolean(),
- "30": z.boolean(),
- "60": z.boolean(),
- "120": z.boolean(),
- custom: z.boolean(),
- })
- .strict(),
- quoteLength: z
- .object({
- short: z.boolean(),
- medium: z.boolean(),
- long: z.boolean(),
- thicc: z.boolean(),
- })
- .strict(),
+ words: z.record(DefaultWordsModeSchema.or(z.literal("custom")), z.boolean()),
+ time: z.record(DefaultTimeModeSchema.or(z.literal("custom")), z.boolean()),
+ quoteLength: z.record(QuoteLengthSchema, z.boolean()),
punctuation: z
.object({
on: z.boolean(),