1 import { getHttpBase } from "@utils/env";
2 import { LemmyHttp } from "lemmy-js-client";
3 import { toast } from "../toast";
4 import { I18NextService } from "./I18NextService";
6 export type EmptyRequestState = {
10 type LoadingRequestState = {
14 export type FailedRequestState = {
19 type SuccessRequestState<T> = {
25 * Shows the state of an API request.
27 * Can be empty, loading, failed, or success
29 export type RequestState<T> =
33 | SuccessRequestState<T>;
35 export type WrappedLemmyHttp = {
36 [K in keyof LemmyHttp]: LemmyHttp[K] extends (...args: any[]) => any
37 ? ReturnType<LemmyHttp[K]> extends Promise<infer U>
38 ? (...args: Parameters<LemmyHttp[K]>) => Promise<RequestState<U>>
40 ...args: Parameters<LemmyHttp[K]>
41 ) => Promise<RequestState<LemmyHttp[K]>>
45 class WrappedLemmyHttpClient {
48 constructor(client: LemmyHttp, silent = false) {
49 this.#client = client;
51 for (const key of Object.getOwnPropertyNames(
52 Object.getPrototypeOf(this.#client),
54 if (key !== "constructor") {
55 WrappedLemmyHttpClient.prototype[key] = async (...args) => {
57 const res = await this.#client[key](...args);
61 state: !(res === undefined || res === null) ? "success" : "empty",
65 console.error(`API error: ${error}`);
66 toast(I18NextService.i18n.t(error), "danger");
79 export function wrapClient(client: LemmyHttp, silent = false) {
80 // unfortunately, this verbose cast is necessary
81 return new WrappedLemmyHttpClient(
84 ) as unknown as WrappedLemmyHttp;
87 export class HttpService {
88 static #_instance: HttpService;
89 #silent_client: WrappedLemmyHttp;
90 #client: WrappedLemmyHttp;
92 private constructor() {
93 const lemmyHttp = new LemmyHttp(getHttpBase());
94 this.#client = wrapClient(lemmyHttp);
95 this.#silent_client = wrapClient(lemmyHttp, true);
98 static get #Instance() {
99 return this.#_instance ?? (this.#_instance = new this());
102 public static get client() {
103 return this.#Instance.#client;
106 public static get silent_client() {
107 return this.#Instance.#silent_client;