This commit is contained in:
Miodec 2022-06-03 15:47:31 +02:00
commit 3726ec08e3
13 changed files with 308 additions and 459 deletions

View file

@ -0,0 +1,107 @@
import { Auth } from "../../firebase";
import { getIdToken } from "firebase/auth";
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
type AxiosClientMethod = (
endpoint: string,
config: AxiosRequestConfig
) => Promise<AxiosResponse>;
type AxiosClientDataMethod = (
endpoint: string,
data: any,
config: AxiosRequestConfig
) => Promise<AxiosResponse>;
type AxiosClientMethods = AxiosClientMethod & AxiosClientDataMethod;
async function adaptRequestOptions(
options: Ape.RequestOptions
): Promise<AxiosRequestConfig> {
const currentUser = Auth.currentUser;
const idToken = currentUser && (await getIdToken(currentUser));
return {
params: options.searchQuery,
data: options.payload,
headers: {
...options.headers,
Accept: "application/json",
"Content-Type": "application/json",
...(idToken && { Authorization: `Bearer ${idToken}` }),
},
};
}
function apeifyClientMethod(
clientMethod: AxiosClientMethods,
methodType: Ape.HttpMethodTypes
): Ape.HttpClientMethod {
return async (
endpoint: string,
options: Ape.RequestOptions = {}
): Ape.EndpointData => {
let errorMessage = "";
try {
const requestOptions: AxiosRequestConfig = await adaptRequestOptions(
options
);
let response;
if (methodType === "get" || methodType === "delete") {
response = await clientMethod(endpoint, requestOptions);
} else {
response = await clientMethod(
endpoint,
requestOptions.data,
requestOptions
);
}
const { message, data } = response.data as Ape.ApiResponse;
return {
status: response.status,
message,
data,
};
} catch (error) {
console.error(error);
const typedError = error as Error;
errorMessage = typedError.message;
if (axios.isAxiosError(typedError)) {
return {
status: typedError.response?.status ?? 500,
message: typedError.message,
...typedError.response?.data,
};
}
}
return {
status: 500,
message: errorMessage,
};
};
}
export function buildHttpClient(
baseURL: string,
timeout: number
): Ape.HttpClient {
const axiosClient = axios.create({
baseURL,
timeout,
});
return {
get: apeifyClientMethod(axiosClient.get, "get"),
post: apeifyClientMethod(axiosClient.post, "post"),
put: apeifyClientMethod(axiosClient.put, "put"),
patch: apeifyClientMethod(axiosClient.patch, "patch"),
delete: apeifyClientMethod(axiosClient.delete, "delete"),
};
}

View file

@ -1,33 +1,28 @@
const BASE_PATH = "/ape-keys";
export default function getApeKeysEndpoints(
apeClient: Ape.Client
): Ape.Endpoints["apeKeys"] {
async function get(): Ape.EndpointData {
return await apeClient.get(BASE_PATH);
export default class ApeKeys {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async function generate(name: string, enabled: boolean): Ape.EndpointData {
async get(): Ape.EndpointData {
return await this.httpClient.get(BASE_PATH);
}
async generate(name: string, enabled: boolean): Ape.EndpointData {
const payload = { name, enabled };
return await apeClient.post(BASE_PATH, { payload });
return await this.httpClient.post(BASE_PATH, { payload });
}
async function update(
async update(
apeKeyId: string,
updates: { name?: string; enabled?: boolean }
): Ape.EndpointData {
const payload = { ...updates };
return await apeClient.patch(`${BASE_PATH}/${apeKeyId}`, { payload });
return await this.httpClient.patch(`${BASE_PATH}/${apeKeyId}`, { payload });
}
async function _delete(apeKeyId: string): Ape.EndpointData {
return await apeClient.delete(`${BASE_PATH}/${apeKeyId}`);
async delete(apeKeyId: string): Ape.EndpointData {
return await this.httpClient.delete(`${BASE_PATH}/${apeKeyId}`);
}
return {
get,
generate,
update,
delete: _delete,
};
}

View file

@ -1,18 +1,15 @@
const BASE_PATH = "/configs";
export default function getConfigsEndpoints(
apeClient: Ape.Client
): Ape.Endpoints["configs"] {
async function get(): Ape.EndpointData {
return await apeClient.get(BASE_PATH);
export default class Configs {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async function save(config: MonkeyTypes.Config): Ape.EndpointData {
return await apeClient.patch(BASE_PATH, { payload: { config } });
async get(): Ape.EndpointData {
return await this.httpClient.get(BASE_PATH);
}
return {
get,
save,
};
async save(config: MonkeyTypes.Config): Ape.EndpointData {
return await this.httpClient.patch(BASE_PATH, { payload: { config } });
}
}

View file

@ -1,19 +1,19 @@
import getConfigsEndpoints from "./configs";
import getLeaderboardsEndpoints from "./leaderboards";
import getPresetsEndpoints from "./presets";
import getPsasEndpoints from "./psas";
import getQuotesEndpoints from "./quotes";
import getResultsEndpoints from "./results";
import getUsersEndpoints from "./users";
import getApeKeysEndpoints from "./ape-keys";
import Configs from "./configs";
import Leaderboards from "./leaderboards";
import Presets from "./presets";
import Psas from "./psas";
import Quotes from "./quotes";
import Results from "./results";
import Users from "./users";
import ApeKeys from "./ape-keys";
export default {
getConfigsEndpoints,
getLeaderboardsEndpoints,
getPresetsEndpoints,
getPsasEndpoints,
getQuotesEndpoints,
getResultsEndpoints,
getUsersEndpoints,
getApeKeysEndpoints,
Configs,
Leaderboards,
Presets,
Psas,
Quotes,
Results,
Users,
ApeKeys,
};

View file

@ -1,11 +1,23 @@
const BASE_PATH = "/leaderboards";
export default function getLeaderboardsEndpoints(
apeClient: Ape.Client
): Ape.Endpoints["leaderboards"] {
async function get(
query: Ape.EndpointTypes.LeadeboardQueryWithPagination
): Ape.EndpointData {
interface LeaderboardQuery {
language: string;
mode: MonkeyTypes.Mode;
mode2: string | number;
isDaily?: boolean;
}
interface LeadeboardQueryWithPagination extends LeaderboardQuery {
skip?: number;
limit?: number;
}
export default class Leaderboards {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async get(query: LeadeboardQueryWithPagination): Ape.EndpointData {
const { language, mode, mode2, isDaily, skip = 0, limit = 50 } = query;
const searchQuery = {
@ -18,12 +30,10 @@ export default function getLeaderboardsEndpoints(
const endpointPath = `${BASE_PATH}/${isDaily ? "daily" : ""}`;
return await apeClient.get(endpointPath, { searchQuery });
return await this.httpClient.get(endpointPath, { searchQuery });
}
async function getRank(
query: Ape.EndpointTypes.LeaderboardQuery
): Ape.EndpointData {
async getRank(query: LeaderboardQuery): Ape.EndpointData {
const { language, mode, mode2, isDaily } = query;
const searchQuery = {
@ -34,8 +44,6 @@ export default function getLeaderboardsEndpoints(
const endpointPath = `${BASE_PATH}${isDaily ? "/daily" : ""}/rank`;
return await apeClient.get(endpointPath, { searchQuery });
return await this.httpClient.get(endpointPath, { searchQuery });
}
return { get, getRank };
}

View file

@ -1,13 +1,15 @@
const BASE_PATH = "/presets";
export default function getPresetsEndpoints(
apeClient: Ape.Client
): Ape.Endpoints["presets"] {
async function get(): Ape.EndpointData {
return await apeClient.get(BASE_PATH);
export default class Presets {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async function add(
async get(): Ape.EndpointData {
return await this.httpClient.get(BASE_PATH);
}
async add(
presetName: string,
configChanges: MonkeyTypes.ConfigChanges
): Ape.EndpointData {
@ -16,10 +18,10 @@ export default function getPresetsEndpoints(
config: configChanges,
};
return await apeClient.post(BASE_PATH, { payload });
return await this.httpClient.post(BASE_PATH, { payload });
}
async function edit(
async edit(
presetId: string,
presetName: string,
configChanges: MonkeyTypes.ConfigChanges
@ -30,12 +32,10 @@ export default function getPresetsEndpoints(
config: configChanges,
};
return await apeClient.patch(BASE_PATH, { payload });
return await this.httpClient.patch(BASE_PATH, { payload });
}
async function _delete(presetId: string): Ape.EndpointData {
return await apeClient.delete(`${BASE_PATH}/${presetId}`);
async delete(presetId: string): Ape.EndpointData {
return await this.httpClient.delete(`${BASE_PATH}/${presetId}`);
}
return { get, add, edit, delete: _delete };
}

View file

@ -2,16 +2,16 @@ import { CLIENT_VERSION } from "../../version";
const BASE_PATH = "/psas";
export default function getPsasEndpoints(
apeClient: Ape.Client
): Ape.Endpoints["psas"] {
async function get(): Ape.EndpointData {
return await apeClient.get(BASE_PATH, {
export default class Psas {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async get(): Ape.EndpointData {
return await this.httpClient.get(BASE_PATH, {
headers: {
"Client-Version": CLIENT_VERSION,
},
});
}
return { get };
}

View file

@ -1,13 +1,15 @@
const BASE_PATH = "/quotes";
export default function getQuotesEndpoints(
apeClient: Ape.Client
): Ape.Endpoints["quotes"] {
async function get(): Ape.EndpointData {
return await apeClient.get(BASE_PATH);
export default class Quotes {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async function submit(
async get(): Ape.EndpointData {
return await this.httpClient.get(BASE_PATH);
}
async submit(
text: string,
source: string,
language: string,
@ -20,10 +22,10 @@ export default function getQuotesEndpoints(
captcha,
};
return await apeClient.post(BASE_PATH, { payload });
return await this.httpClient.post(BASE_PATH, { payload });
}
async function approveSubmission(
async approveSubmission(
quoteSubmissionId: string,
editText?: string,
editSource?: string
@ -34,38 +36,35 @@ export default function getQuotesEndpoints(
editSource,
};
return await apeClient.post(`${BASE_PATH}/approve`, { payload });
return await this.httpClient.post(`${BASE_PATH}/approve`, { payload });
}
async function rejectSubmission(quoteSubmissionId: string): Ape.EndpointData {
return await apeClient.post(`${BASE_PATH}/reject`, {
async rejectSubmission(quoteSubmissionId: string): Ape.EndpointData {
return await this.httpClient.post(`${BASE_PATH}/reject`, {
payload: { quoteId: quoteSubmissionId },
});
}
async function getRating(quote: MonkeyTypes.Quote): Ape.EndpointData {
async getRating(quote: MonkeyTypes.Quote): Ape.EndpointData {
const searchQuery = {
quoteId: quote.id,
language: quote.language,
};
return await apeClient.get(`${BASE_PATH}/rating`, { searchQuery });
return await this.httpClient.get(`${BASE_PATH}/rating`, { searchQuery });
}
async function addRating(
quote: MonkeyTypes.Quote,
rating: number
): Ape.EndpointData {
async addRating(quote: MonkeyTypes.Quote, rating: number): Ape.EndpointData {
const payload = {
quoteId: quote.id,
rating,
language: quote.language,
};
return await apeClient.post(`${BASE_PATH}/rating`, { payload });
return await this.httpClient.post(`${BASE_PATH}/rating`, { payload });
}
async function report(
async report(
quoteId: string,
quoteLanguage: string,
reason: string,
@ -80,16 +79,6 @@ export default function getQuotesEndpoints(
captcha,
};
return await apeClient.post(`${BASE_PATH}/report`, { payload });
return await this.httpClient.post(`${BASE_PATH}/report`, { payload });
}
return {
get,
submit,
approveSubmission,
rejectSubmission,
getRating,
addRating,
report,
};
}

View file

@ -2,34 +2,29 @@ import { CLIENT_VERSION } from "../../version";
const BASE_PATH = "/results";
export default function getResultsEndpoints(
apeClient: Ape.Client
): Ape.Endpoints["results"] {
async function get(): Ape.EndpointData {
return await apeClient.get(BASE_PATH);
export default class Results {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async function save(
result: MonkeyTypes.Result<MonkeyTypes.Mode>
): Ape.EndpointData {
return await apeClient.post(BASE_PATH, {
async get(): Ape.EndpointData {
return await this.httpClient.get(BASE_PATH);
}
async save(result: MonkeyTypes.Result<MonkeyTypes.Mode>): Ape.EndpointData {
return await this.httpClient.post(BASE_PATH, {
payload: { result },
headers: { "Client-Version": CLIENT_VERSION },
});
}
async function updateTags(
resultId: string,
tagIds: string[]
): Ape.EndpointData {
return await apeClient.patch(`${BASE_PATH}/tags`, {
async updateTags(resultId: string, tagIds: string[]): Ape.EndpointData {
return await this.httpClient.patch(`${BASE_PATH}/tags`, {
payload: { resultId, tagIds },
});
}
async function deleteAll(): Ape.EndpointData {
return await apeClient.delete(BASE_PATH);
async deleteAll(): Ape.EndpointData {
return await this.httpClient.delete(BASE_PATH);
}
return { get, save, updateTags, deleteAll };
}

View file

@ -1,39 +1,39 @@
const BASE_PATH = "/users";
export default function getUsersEndpoints(
apeClient: Ape.Client
): Ape.Endpoints["users"] {
async function getData(): Ape.EndpointData {
return await apeClient.get(BASE_PATH);
export default class Users {
constructor(private httpClient: Ape.HttpClient) {
this.httpClient = httpClient;
}
async function create(
name: string,
email?: string,
uid?: string
): Ape.EndpointData {
async getData(): Ape.EndpointData {
return await this.httpClient.get(BASE_PATH);
}
async create(name: string, email?: string, uid?: string): Ape.EndpointData {
const payload = {
email,
name,
uid,
};
return await apeClient.post(`${BASE_PATH}/signup`, { payload });
return await this.httpClient.post(`${BASE_PATH}/signup`, { payload });
}
async function getNameAvailability(name: string): Ape.EndpointData {
return await apeClient.get(`${BASE_PATH}/checkName/${name}`);
async getNameAvailability(name: string): Ape.EndpointData {
return await this.httpClient.get(`${BASE_PATH}/checkName/${name}`);
}
async function _delete(): Ape.EndpointData {
return await apeClient.delete(BASE_PATH);
async delete(): Ape.EndpointData {
return await this.httpClient.delete(BASE_PATH);
}
async function updateName(name: string): Ape.EndpointData {
return await apeClient.patch(`${BASE_PATH}/name`, { payload: { name } });
async updateName(name: string): Ape.EndpointData {
return await this.httpClient.patch(`${BASE_PATH}/name`, {
payload: { name },
});
}
async function updateLeaderboardMemory<M extends MonkeyTypes.Mode>(
async updateLeaderboardMemory<M extends MonkeyTypes.Mode>(
mode: string,
mode2: MonkeyTypes.Mode2<M>,
language: string,
@ -46,55 +46,58 @@ export default function getUsersEndpoints(
rank,
};
return await apeClient.patch(`${BASE_PATH}/leaderboardMemory`, { payload });
return await this.httpClient.patch(`${BASE_PATH}/leaderboardMemory`, {
payload,
});
}
async function updateEmail(
newEmail: string,
previousEmail: string
): Ape.EndpointData {
async updateEmail(newEmail: string, previousEmail: string): Ape.EndpointData {
const payload = {
newEmail,
previousEmail,
};
return await apeClient.patch(`${BASE_PATH}/email`, { payload });
return await this.httpClient.patch(`${BASE_PATH}/email`, { payload });
}
async function deletePersonalBests(): Ape.EndpointData {
return await apeClient.delete(`${BASE_PATH}/personalBests`);
async deletePersonalBests(): Ape.EndpointData {
return await this.httpClient.delete(`${BASE_PATH}/personalBests`);
}
async function getTags(): Ape.EndpointData {
return await apeClient.get(`${BASE_PATH}/tags`);
async getTags(): Ape.EndpointData {
return await this.httpClient.get(`${BASE_PATH}/tags`);
}
async function createTag(tagName: string): Ape.EndpointData {
return await apeClient.post(`${BASE_PATH}/tags`, { payload: { tagName } });
async createTag(tagName: string): Ape.EndpointData {
return await this.httpClient.post(`${BASE_PATH}/tags`, {
payload: { tagName },
});
}
async function editTag(tagId: string, newName: string): Ape.EndpointData {
async editTag(tagId: string, newName: string): Ape.EndpointData {
const payload = {
tagId,
newName,
};
return await apeClient.patch(`${BASE_PATH}/tags`, { payload });
return await this.httpClient.patch(`${BASE_PATH}/tags`, { payload });
}
async function deleteTag(tagId: string): Ape.EndpointData {
return await apeClient.delete(`${BASE_PATH}/tags/${tagId}`);
async deleteTag(tagId: string): Ape.EndpointData {
return await this.httpClient.delete(`${BASE_PATH}/tags/${tagId}`);
}
async function deleteTagPersonalBest(tagId: string): Ape.EndpointData {
return await apeClient.delete(`${BASE_PATH}/tags/${tagId}/personalBest`);
async deleteTagPersonalBest(tagId: string): Ape.EndpointData {
return await this.httpClient.delete(
`${BASE_PATH}/tags/${tagId}/personalBest`
);
}
async function getCustomThemes(): Ape.EndpointData {
return await apeClient.get(`${BASE_PATH}/customThemes`);
async getCustomThemes(): Ape.EndpointData {
return await this.httpClient.get(`${BASE_PATH}/customThemes`);
}
async function editCustomTheme(
async editCustomTheme(
themeId: string,
newTheme: Partial<MonkeyTypes.CustomTheme>
): Ape.EndpointData {
@ -105,74 +108,58 @@ export default function getUsersEndpoints(
colors: newTheme.colors,
},
};
return await apeClient.patch(`${BASE_PATH}/customThemes`, { payload });
return await this.httpClient.patch(`${BASE_PATH}/customThemes`, {
payload,
});
}
async function deleteCustomTheme(themeId: string): Ape.EndpointData {
async deleteCustomTheme(themeId: string): Ape.EndpointData {
const payload = {
themeId: themeId,
};
return await apeClient.delete(`${BASE_PATH}/customThemes`, { payload });
return await this.httpClient.delete(`${BASE_PATH}/customThemes`, {
payload,
});
}
async function addCustomTheme(
async addCustomTheme(
newTheme: Partial<MonkeyTypes.CustomTheme>
): Ape.EndpointData {
const payload = { name: newTheme.name, colors: newTheme.colors };
return await apeClient.post(`${BASE_PATH}/customThemes`, { payload });
return await this.httpClient.post(`${BASE_PATH}/customThemes`, { payload });
}
async function linkDiscord(data: {
async linkDiscord(data: {
tokenType: string;
accessToken: string;
uid?: string;
}): Ape.EndpointData {
return await apeClient.post(`${BASE_PATH}/discord/link`, {
return await this.httpClient.post(`${BASE_PATH}/discord/link`, {
payload: { data },
});
}
async function unlinkDiscord(): Ape.EndpointData {
return await apeClient.post(`${BASE_PATH}/discord/unlink`);
async unlinkDiscord(): Ape.EndpointData {
return await this.httpClient.post(`${BASE_PATH}/discord/unlink`);
}
async function addQuoteToFavorites(
async addQuoteToFavorites(
language: string,
quoteId: string
): Ape.EndpointData {
const payload = { language, quoteId };
return await apeClient.post(`${BASE_PATH}/favoriteQuotes`, { payload });
return await this.httpClient.post(`${BASE_PATH}/favoriteQuotes`, {
payload,
});
}
async function removeQuoteFromFavorites(
async removeQuoteFromFavorites(
language: string,
quoteId: string
): Ape.EndpointData {
const payload = { language, quoteId };
return await apeClient.delete(`${BASE_PATH}/favoriteQuotes`, { payload });
return await this.httpClient.delete(`${BASE_PATH}/favoriteQuotes`, {
payload,
});
}
return {
getData,
create,
getNameAvailability,
delete: _delete,
updateName,
updateLeaderboardMemory,
updateEmail,
deletePersonalBests,
getTags,
createTag,
editTag,
deleteTag,
deleteTagPersonalBest,
linkDiscord,
unlinkDiscord,
getCustomThemes,
addCustomTheme,
editCustomTheme,
deleteCustomTheme,
addQuoteToFavorites,
removeQuoteFromFavorites,
};
}

View file

@ -1,7 +1,5 @@
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import endpoints from "./endpoints";
import { Auth } from "../firebase";
import { getIdToken } from "firebase/auth";
import { buildHttpClient } from "./adapters/axios-adapter";
const DEV_SERVER_HOST = "http://localhost:5005";
const PROD_SERVER_HOST = "https://api.monkeytype.com";
@ -11,117 +9,18 @@ const BASE_URL =
window.location.hostname === "localhost" ? DEV_SERVER_HOST : PROD_SERVER_HOST;
const API_URL = `${BASE_URL}${API_PATH}`;
// Adapts the ape client's view of request options to the underlying HTTP client.
async function adaptRequestOptions(
options: Ape.RequestOptions
): Promise<AxiosRequestConfig> {
const currentUser = Auth.currentUser;
const idToken = currentUser && (await getIdToken(currentUser));
return {
params: options.searchQuery,
data: options.payload,
headers: {
...options.headers,
Accept: "application/json",
"Content-Type": "application/json",
...(idToken && { Authorization: `Bearer ${idToken}` }),
},
};
}
type AxiosClientMethod = (
endpoint: string,
config: AxiosRequestConfig
) => Promise<AxiosResponse>;
type AxiosClientDataMethod = (
endpoint: string,
data: any,
config: AxiosRequestConfig
) => Promise<AxiosResponse>;
type AxiosClientMethods = AxiosClientMethod & AxiosClientDataMethod;
// Wrap the underlying HTTP client's method with our own.
function apeifyClientMethod(
clientMethod: AxiosClientMethods,
methodType: Ape.MethodTypes
): Ape.ClientMethod {
return async (
endpoint: string,
options: Ape.RequestOptions = {}
): Ape.EndpointData => {
let errorMessage = "";
try {
const requestOptions: AxiosRequestConfig = await adaptRequestOptions(
options
);
let response;
if (methodType === "get" || methodType === "delete") {
response = await clientMethod(endpoint, requestOptions);
} else {
response = await clientMethod(
endpoint,
requestOptions.data,
requestOptions
);
}
const { message, data } = response.data as Ape.ApiResponse;
return {
status: response.status,
message,
data,
};
} catch (error) {
console.error(error);
const typedError = error as Error;
errorMessage = typedError.message;
if (axios.isAxiosError(typedError)) {
return {
status: typedError.response?.status ?? 500,
message: typedError.message,
...typedError.response?.data,
};
}
}
return {
status: 500,
message: errorMessage,
};
};
}
const axiosClient = axios.create({
baseURL: API_URL,
timeout: 10000,
});
const apeClient: Ape.Client = {
get: apeifyClientMethod(axiosClient.get, "get"),
post: apeifyClientMethod(axiosClient.post, "post"),
put: apeifyClientMethod(axiosClient.put, "put"),
patch: apeifyClientMethod(axiosClient.patch, "patch"),
delete: apeifyClientMethod(axiosClient.delete, "delete"),
};
const httpClient = buildHttpClient(API_URL, 10000);
// API Endpoints
const Ape: Ape.Endpoints = {
users: endpoints.getUsersEndpoints(apeClient),
configs: endpoints.getConfigsEndpoints(apeClient),
results: endpoints.getResultsEndpoints(apeClient),
psas: endpoints.getPsasEndpoints(apeClient),
quotes: endpoints.getQuotesEndpoints(apeClient),
leaderboards: endpoints.getLeaderboardsEndpoints(apeClient),
presets: endpoints.getPresetsEndpoints(apeClient),
apeKeys: endpoints.getApeKeysEndpoints(apeClient),
const Ape = {
users: new endpoints.Users(httpClient),
configs: new endpoints.Configs(httpClient),
results: new endpoints.Results(httpClient),
psas: new endpoints.Psas(httpClient),
quotes: new endpoints.Quotes(httpClient),
leaderboards: new endpoints.Leaderboards(httpClient),
presets: new endpoints.Presets(httpClient),
apeKeys: new endpoints.ApeKeys(httpClient),
};
export default Ape;

View file

@ -1,163 +1,35 @@
declare namespace Ape {
type ClientMethod = (
endpoint: string,
config?: RequestOptions
) => Promise<Response>;
interface ApiResponse {
message: string;
data: any | null;
}
interface Client {
get: ClientMethod;
post: ClientMethod;
put: ClientMethod;
patch: ClientMethod;
delete: ClientMethod;
}
type MethodTypes = keyof Client;
interface RequestOptions {
headers?: Record<string, string>;
searchQuery?: Record<string, any>;
payload?: any;
}
interface Response {
interface HttpClientResponse {
status: number;
message: string;
data?: any;
}
type EndpointData = Promise<Response>;
type Endpoint = () => EndpointData;
type EndpointData = Promise<HttpClientResponse>;
declare namespace EndpointTypes {
interface LeaderboardQuery {
language: string;
mode: MonkeyTypes.Mode;
mode2: string | number;
isDaily?: boolean;
}
type HttpClientMethod = (
endpoint: string,
config?: RequestOptions
) => Promise<HttpClientResponse>;
interface LeadeboardQueryWithPagination extends LeaderboardQuery {
skip?: number;
limit?: number;
}
interface HttpClient {
get: HttpClientMethod;
post: HttpClientMethod;
put: HttpClientMethod;
patch: HttpClientMethod;
delete: HttpClientMethod;
}
interface Endpoints {
configs: {
get: Endpoint;
save: (config: MonkeyTypes.Config) => EndpointData;
};
type HttpMethodTypes = keyof HttpClient;
leaderboards: {
get: (query: EndpointTypes.LeadeboardQueryWithPagination) => EndpointData;
getRank: (query: EndpointTypes.LeaderboardQuery) => EndpointData;
};
presets: {
get: Endpoint;
add: (
presetName: string,
configChanges: MonkeyTypes.ConfigChanges
) => EndpointData;
edit: (
presetId: string,
presetName: string,
configChanges: MonkeyTypes.ConfigChanges
) => EndpointData;
delete: (presetId: string) => EndpointData;
};
psas: {
get: Endpoint;
};
quotes: {
get: Endpoint;
submit: (
text: string,
source: string,
language: string,
captcha: string
) => EndpointData;
approveSubmission: (
quoteSubmissionId: string,
editText?: string,
editSource?: string
) => EndpointData;
rejectSubmission: (quoteSubmissionId: string) => EndpointData;
getRating: (quote: MonkeyTypes.Quote) => EndpointData;
addRating: (quote: MonkeyTypes.Quote, rating: number) => EndpointData;
report: (
quoteId: string,
quoteLanguage: string,
reason: string,
comment: string,
captcha: string
) => EndpointData;
};
users: {
getData: Endpoint;
create: (name: string, email?: string, uid?: string) => EndpointData;
getNameAvailability: (name: string) => EndpointData;
delete: Endpoint;
updateName: (name: string) => EndpointData;
updateLeaderboardMemory: <M extends MonkeyTypes.Mode>(
mode: string,
mode2: MonkeyTypes.Mode2<M>,
language: string,
rank: number
) => EndpointData;
updateEmail: (newEmail: string, previousEmail: string) => EndpointData;
deletePersonalBests: Endpoint;
getCustomThemes: () => EndpointData;
addCustomTheme: (
newTheme: Partial<MonkeyTypes.CustomTheme>
) => EndpointData;
editCustomTheme: (
themeId: string,
newTheme: Partial<MonkeyTypes.CustomTheme>
) => EndpointData;
deleteCustomTheme: (themeId: string) => EndpointData;
getTags: Endpoint;
createTag: (tagName: string) => EndpointData;
editTag: (tagId: string, newName: string) => EndpointData;
deleteTag: (tagId: string) => EndpointData;
deleteTagPersonalBest: (tagId: string) => EndpointData;
linkDiscord: (data: {
tokenType: string;
accessToken: string;
uid?: string;
}) => EndpointData;
unlinkDiscord: Endpoint;
addQuoteToFavorites: (language: string, quoteId: string) => EndpointData;
removeQuoteFromFavorites: (
language: string,
quoteId: string
) => EndpointData;
};
results: {
get: Endpoint;
save: (result: MonkeyTypes.Result<MonkeyTypes.Mode>) => EndpointData;
updateTags: (resultId: string, tagIds: string[]) => EndpointData;
deleteAll: Endpoint;
};
apeKeys: {
get: Endpoint;
generate: (name: string, enabled: boolean) => EndpointData;
update: (
apeKeyId: string,
updates: { name?: string; enabled?: boolean }
) => EndpointData;
delete: (apeKeyId: string) => EndpointData;
};
interface ApiResponse {
message: string;
data: any | null;
}
}

View file

@ -73,7 +73,7 @@ export async function initSnapshot(): Promise<
configResponse,
tagsResponse,
presetsResponse,
].map((response: Ape.Response) => response.data);
].map((response: Ape.HttpClientResponse) => response.data);
snap.name = userData.name;
snap.personalBests = userData.personalBests;