1 import { LemmyHttp } from "lemmy-js-client";
2 import { getHttpBase } from "../../shared/env";
3 import { toast } from "../../shared/toast";
4 import { I18NextService } from "./I18NextService";
6 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) {
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",
64 console.error(`API error: ${error}`);
65 toast(I18NextService.i18n.t(error), "danger");
77 export function wrapClient(client: LemmyHttp) {
78 return new WrappedLemmyHttpClient(client) as unknown as WrappedLemmyHttp; // unfortunately, this verbose cast is necessary
81 export class HttpService {
82 static #_instance: HttpService;
83 #client: WrappedLemmyHttp;
85 private constructor() {
86 this.#client = wrapClient(new LemmyHttp(getHttpBase()));
89 static get #Instance() {
90 return this.#_instance ?? (this.#_instance = new this());
93 public static get client() {
94 return this.#Instance.#client;