commit 4fbd3635e411d0d0a85a754ba688138f03121da8 parent f936b3e62ff5b34a7e044ff67c7d6c6f80196835 Author: Florian Dold <dold@taler.net> Date: Sun, 9 Aug 2026 22:57:12 +0200 web-util: remove deprecated request handler Diffstat:
17 files changed, 279 insertions(+), 544 deletions(-)
diff --git a/packages/taler-auditor-webui/src/Application.tsx b/packages/taler-auditor-webui/src/Application.tsx @@ -22,7 +22,6 @@ import { HttpStatusCode, LibtoolVersion } from "@gnu-taler/taler-util"; import { - ErrorType, TranslationProvider, useTranslationContext, } from "@gnu-taler/web-util/browser"; @@ -38,6 +37,7 @@ import { BackendContextProvider } from "./context/backend.js"; import { ConfigContextProvider } from "./context/config.js"; import { useBackendConfig } from "./hooks/backend.js"; import { strings } from "./i18n/strings.js"; +import { ErrorType } from "./utils/http.js"; export function Application(): VNode { return ( diff --git a/packages/taler-auditor-webui/src/hooks/backend.ts b/packages/taler-auditor-webui/src/hooks/backend.ts @@ -23,18 +23,17 @@ /** * Imports. */ +import { useCallback, useEffect, useRef, useState } from "preact/hooks"; +import { useSWRConfig } from "swr"; +import { useBackendContext } from "../context/backend.js"; +import { AuditorBackend } from "../declaration.js"; import { HttpResponse, HttpResponseOk, RequestError, RequestOptions, - useApiContext, -} from "@gnu-taler/web-util/browser"; -import { useCallback, useEffect, useState } from "preact/hooks"; -import { useSWRConfig } from "swr"; -import { useBackendContext } from "../context/backend.js"; -import { AuditorBackend } from "../declaration.js"; -import { useRef } from "preact/hooks"; + request as requestHandler, +} from "../utils/http.js"; export function useMatchMutate(): ( re?: RegExp, @@ -194,7 +193,6 @@ interface useBackendBaseRequestType { //TODO: Add token export function useBackendBaseRequest(): useBackendBaseRequestType { const { url: backend } = useBackendContext(); - const { request: requestHandler } = useApiContext(); const request = useCallback( function requestImpl<T>( @@ -218,7 +216,6 @@ export function useBackendBaseRequest(): useBackendBaseRequestType { export function useBackendRequest(): useBackendInstanceRequestType { const { url: baseUrl } = useBackendContext(); - const { request: requestHandler } = useApiContext(); const request = useCallback( function requestImpl<T>( diff --git a/packages/taler-auditor-webui/src/hooks/critical.ts b/packages/taler-auditor-webui/src/hooks/critical.ts @@ -13,12 +13,8 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { - HttpResponse, - HttpResponseOk, - RequestError, -} from "@gnu-taler/web-util/browser"; import { AuditorBackend } from "../declaration.js"; +import { HttpResponse, HttpResponseOk, RequestError } from "../utils/http.js"; import { useBackendRequest } from "./backend.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 diff --git a/packages/taler-auditor-webui/src/hooks/entity.ts b/packages/taler-auditor-webui/src/hooks/entity.ts @@ -17,12 +17,8 @@ /** * Imports. */ -import { - HttpResponse, - HttpResponseOk, - RequestError, -} from "@gnu-taler/web-util/browser"; import { AuditorBackend } from "../declaration.js"; +import { HttpResponse, HttpResponseOk, RequestError } from "../utils/http.js"; import { useBackendRequest, useMatchMutate } from "./backend.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 diff --git a/packages/taler-auditor-webui/src/hooks/finance.ts b/packages/taler-auditor-webui/src/hooks/finance.ts @@ -17,12 +17,8 @@ /** * Imports. */ -import { - HttpResponse, - HttpResponseOk, - RequestError, -} from "@gnu-taler/web-util/browser"; import { AuditorBackend } from "../declaration.js"; +import { HttpResponse, HttpResponseOk, RequestError } from "../utils/http.js"; import { useBackendRequest } from "./backend.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 diff --git a/packages/taler-auditor-webui/src/hooks/operational.ts b/packages/taler-auditor-webui/src/hooks/operational.ts @@ -13,12 +13,8 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { - HttpResponse, - HttpResponseOk, - RequestError, -} from "@gnu-taler/web-util/browser"; import { AuditorBackend } from "../declaration.js"; +import { HttpResponse, HttpResponseOk, RequestError } from "../utils/http.js"; import { useBackendRequest } from "./backend.js"; // FIX default import https://github.com/microsoft/TypeScript/issues/49189 diff --git a/packages/taler-auditor-webui/src/paths/default/index.tsx b/packages/taler-auditor-webui/src/paths/default/index.tsx @@ -20,11 +20,7 @@ */ import { HttpStatusCode } from "@gnu-taler/taler-util"; -import { - ErrorType, - HttpError, - useTranslationContext, -} from "@gnu-taler/web-util/browser"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h, VNode } from "preact"; import { route } from "preact-router"; import { useMemo, useState } from "preact/hooks"; @@ -39,6 +35,7 @@ import { AuditorBackend, WithId } from "../../declaration.js"; import { getEntityList, useEntityAPI } from "../../hooks/entity.js"; import { Paths } from "../../InstanceRoutes.js"; import { Notification } from "../../utils/types.js"; +import { ErrorType, HttpError } from "../../utils/http.js"; import { CardTable } from "./Table.js"; interface Props { @@ -58,7 +55,7 @@ export default function DefaultList({ onLoadError, onNotFound }: Props): VNode { let data = result.loading || !result.ok ? undefined : result.data; const value = useMemo(() => ({ data }), [data]); - + if (result.loading) return <Loading />; if (!result.ok) { if ( @@ -69,7 +66,6 @@ export default function DefaultList({ onLoadError, onNotFound }: Props): VNode { return onLoadError(result); } - function onReturn(): void { route(Paths.detail_view); } diff --git a/packages/taler-auditor-webui/src/paths/finance/index.tsx b/packages/taler-auditor-webui/src/paths/finance/index.tsx @@ -21,13 +21,14 @@ */ import { HttpStatusCode } from "@gnu-taler/taler-util"; -import { ErrorType, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../components/exception/loading.js"; import { NotificationCard } from "../../components/menu/index.js"; import { getKeyFiguresData } from "../../hooks/finance.js"; import { Notification } from "../../utils/types.js"; +import { ErrorType } from "../../utils/http.js"; import { ListPage } from "./ListPage.js"; interface Props { diff --git a/packages/taler-auditor-webui/src/paths/operations/index.tsx b/packages/taler-auditor-webui/src/paths/operations/index.tsx @@ -21,13 +21,14 @@ */ import { HttpStatusCode } from "@gnu-taler/taler-util"; -import { ErrorType, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../components/exception/loading.js"; import { NotificationCard } from "../../components/menu/index.js"; import { getOperationData } from "../../hooks/operational.js"; import { Notification } from "../../utils/types.js"; +import { ErrorType } from "../../utils/http.js"; import { ListPage } from "./ListPage.js"; interface Props { diff --git a/packages/taler-auditor-webui/src/paths/security/index.tsx b/packages/taler-auditor-webui/src/paths/security/index.tsx @@ -24,13 +24,14 @@ * Imports. */ import { HttpStatusCode } from "@gnu-taler/taler-util"; -import { ErrorType, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../components/exception/loading.js"; import { NotificationCard } from "../../components/menu/index.js"; import { getCriticalData } from "../../hooks/critical.js"; import { Notification } from "../../utils/types.js"; +import { ErrorType } from "../../utils/http.js"; import { ListPage } from "./ListPage.js"; interface Props { diff --git a/packages/taler-auditor-webui/src/utils/http.ts b/packages/taler-auditor-webui/src/utils/http.ts @@ -0,0 +1,238 @@ +/* + This file is part of GNU Taler + (C) 2026 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { + Duration, + HttpStatusCode, + TalerError, + TalerErrorCode, +} from "@gnu-taler/taler-util"; +import { BrowserFetchHttpLib } from "@gnu-taler/web-util/browser"; + +export enum ErrorType { + CLIENT, + SERVER, + UNREADABLE, + TIMEOUT, + UNEXPECTED, +} + +export interface RequestOptions { + method?: "GET" | "POST" | "PATCH" | "DELETE" | "PUT"; + data?: string | Uint8Array | object; + params?: Record<string, unknown>; + timeout?: number; +} + +interface RequestInfo { + url: string; + payload: unknown; + status: number; + options: RequestOptions; +} + +interface HttpResponseLoading<T> { + ok?: false; + loading: true; + data?: T; +} + +export interface HttpResponseOk<T> { + ok: true; + loading?: false; + data: T; + info?: RequestInfo; +} + +interface HttpRequestTimeoutError { + ok?: false; + loading?: false; + type: ErrorType.TIMEOUT; + info: RequestInfo; + message: string; +} + +interface HttpResponseError<ErrorDetail> { + ok?: false; + loading?: false; + type: ErrorType.CLIENT | ErrorType.SERVER; + payload: ErrorDetail; + status: HttpStatusCode; + message: string; + info: RequestInfo; +} + +interface HttpResponseUnreadableError { + ok?: false; + loading: false; + type: ErrorType.UNREADABLE; + info: RequestInfo; + status: HttpStatusCode; + exception: unknown; + body: string; + message: string; +} + +interface HttpResponseUnexpectedError { + ok?: false; + loading: false; + type: ErrorType.UNEXPECTED; + info: RequestInfo; + status?: HttpStatusCode; + exception: unknown; + message: string; +} + +export type HttpError<ErrorDetail> = + | HttpRequestTimeoutError + | HttpResponseError<ErrorDetail> + | HttpResponseUnreadableError + | HttpResponseUnexpectedError; + +export type HttpResponse<T, ErrorDetail> = + | HttpResponseOk<T> + | HttpResponseLoading<T> + | HttpError<ErrorDetail>; + +export class RequestError<ErrorDetail> extends Error { + declare cause: HttpError<ErrorDetail>; + + constructor(error: HttpError<ErrorDetail>) { + super(error.message, { cause: error }); + this.cause = error; + } +} + +const httpClient = new BrowserFetchHttpLib({ + enableThrottling: false, + requireTls: false, +}); + +export async function request<T>( + baseUrl: string, + endpoint: string, + options: RequestOptions = {}, +): Promise<HttpResponseOk<T>> { + let url: URL; + try { + url = new URL(`${baseUrl}${endpoint}`); + } catch (exception) { + const info: RequestInfo = { + url: `${baseUrl}${endpoint}`, + payload: options.data, + status: 0, + options, + }; + throw new RequestError({ + type: ErrorType.UNEXPECTED, + exception, + loading: false, + info, + message: `invalid URL: "${info.url}"`, + }); + } + + for (const [key, value] of Object.entries(options.params ?? {})) { + url.searchParams.set(key, String(value)); + } + + const method = options.method ?? "GET"; + const info: RequestInfo = { + url: url.href, + payload: options.data, + status: 0, + options, + }; + + let response; + try { + response = await httpClient.fetch(url.href, { + method, + body: options.data, + timeout: Duration.fromMilliseconds(options.timeout ?? 5_000), + }); + } catch (exception) { + if ( + exception instanceof TalerError && + exception.hasErrorCode(TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT) + ) { + throw new RequestError({ + type: ErrorType.TIMEOUT, + info, + message: "request timeout", + }); + } + throw new RequestError({ + type: ErrorType.UNEXPECTED, + exception, + loading: false, + info, + message: + exception instanceof Error ? exception.message : String(exception), + }); + } + + info.status = response.status; + const body = await response.text(); + let data: T | undefined; + try { + data = body ? JSON.parse(body) : undefined; + } catch (exception) { + throw new RequestError({ + type: ErrorType.UNREADABLE, + exception, + loading: false, + body, + info, + status: response.status, + message: "Could not parse body as json", + }); + } + + if (response.status >= 200 && response.status < 300) { + return { ok: true, data: data as T, info }; + } + + const errorType = + response.status >= 400 && response.status < 500 + ? ErrorType.CLIENT + : response.status >= 500 && response.status < 600 + ? ErrorType.SERVER + : undefined; + if (errorType !== undefined) { + const detail = data as any; + const code = detail?.code ? ` (code: ${detail.code})` : ""; + const message = detail?.hint + ? `${detail.hint}${code}` + : `HTTP error (${response.status})`; + throw new RequestError({ + type: errorType, + status: response.status, + info, + message, + payload: data, + }); + } + + throw new RequestError({ + type: ErrorType.UNEXPECTED, + status: response.status, + exception: undefined, + loading: false, + info, + message: `http status code not handled: ${response.status}`, + }); +} diff --git a/packages/taler-merchant-webui/src/hooks/testing.tsx b/packages/taler-merchant-webui/src/hooks/testing.tsx @@ -198,7 +198,6 @@ export class ApiMockEnvironment extends MockEnvironment { // > <ApiContextProvider value={{ - request: undefined as any, bankCore, bankIntegration, bankRevenue, diff --git a/packages/taler-wallet-webextension/src/test-utils.ts b/packages/taler-wallet-webextension/src/test-utils.ts @@ -31,7 +31,6 @@ import { import { ApiContextProvider, TranslationProvider, - defaultRequestHandler, } from "@gnu-taler/web-util/browser"; import { ComponentChildren, @@ -191,7 +190,6 @@ export function createWalletApiMock(): { let children = _cs; children = create(AlertProvider, { children }, children); const value = { - request: defaultRequestHandler, bankCore: new TalerCoreBankHttpClient("/"), bankIntegration: new TalerBankIntegrationHttpClient("/"), bankWire: new TalerWireGatewayHttpClient("/"), diff --git a/packages/web-util/src/context/api.ts b/packages/web-util/src/context/api.ts @@ -27,20 +27,15 @@ import { } from "@gnu-taler/taler-util"; import { ComponentChildren, createContext, h, VNode } from "preact"; import { useContext } from "preact/hooks"; -import { defaultRequestHandler } from "../utils/request.js"; interface Type { - /** - * @deprecated this show not be used - */ - request: typeof defaultRequestHandler; bankCore: TalerCoreBankHttpClient; bankIntegration: TalerBankIntegrationHttpClient; bankWire: TalerWireGatewayHttpClient; bankRevenue: TalerRevenueHttpClient; } -const Context = createContext<Type>({ request: defaultRequestHandler } as any); +const Context = createContext<Type>(undefined as any); export const useApiContext = (): Type => useContext(Context); export const ApiContextProvider = ({ diff --git a/packages/web-util/src/tests/swr.ts b/packages/web-util/src/tests/swr.ts @@ -18,10 +18,7 @@ import { ComponentChildren, FunctionalComponent, h, VNode } from "preact"; import { MockEnvironment } from "./mock.js"; import { SWRConfig } from "swr"; import * as swr__internal from "swr/_internal"; -import { Logger } from "@gnu-taler/taler-util"; -import { RequestError, buildRequestFailed } from "../utils/request.js"; - -const logger = new Logger("tests/swr.ts"); +import { TalerError, TalerErrorCode } from "@gnu-taler/taler-util"; /** * Helper for hook that use SWR inside. @@ -54,18 +51,28 @@ export class SwrMockEnvironment extends MockEnvironment { //unexpected query if (!mocked.expectedQuery) return undefined; const status = mocked.expectedQuery.query.code ?? 200; - const requestPayload = mocked.expectedQuery.params?.request; const responsePayload = mocked.expectedQuery.params?.response; //simulated error if (status >= 400) { - const error = buildRequestFailed( - url, - JSON.stringify(responsePayload), - status, - requestPayload, - ); - //example error handling from https://swr.vercel.app/docs/error-handling - throw new RequestError(error); + if ( + responsePayload && + typeof responsePayload === "object" && + "code" in responsePayload && + typeof responsePayload.code === "number" + ) { + throw TalerError.fromUncheckedDetail({ + ...responsePayload, + code: responsePayload.code as TalerErrorCode, + }); + } + throw TalerError.fromUncheckedDetail({ + code: TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR, + hint: `Mock request failed with HTTP status ${status}`, + requestUrl: url, + requestMethod: "GET", + httpStatusCode: status, + errorResponse: responsePayload, + }); } return responsePayload; } diff --git a/packages/web-util/src/utils/index.ts b/packages/web-util/src/utils/index.ts @@ -1,7 +1,6 @@ export * from "./http-impl.browser.js"; export * from "./http-impl.sw.js"; export * from "./observable.js"; -export * from "./request.js"; export * from "./route.js"; export * from "./select-ui-lists.js"; export * from "./buildPaginatedResult.js"; diff --git a/packages/web-util/src/utils/request.ts b/packages/web-util/src/utils/request.ts @@ -1,481 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2025 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -import { HttpStatusCode } from "@gnu-taler/taler-util"; -import { base64encode } from "./base64.js"; - -/** - * @deprecated do not use it, it will be removed - */ -export enum ErrorType { - CLIENT, - SERVER, - UNREADABLE, - TIMEOUT, - UNEXPECTED, -} - -/** - * - * @param baseUrl URL where the service is located - * @param endpoint endpoint of the service to be called - * @param options auth, method and params - * @deprecated do not use it, it will be removed - * @returns - */ -export async function defaultRequestHandler<T>( - baseUrl: string, - endpoint: string, - options: RequestOptions = {}, -): Promise<HttpResponseOk<T>> { - const requestHeaders: Record<string, string> = {}; - if (options.token) { - requestHeaders.Authorization = `Bearer secret-token:${options.token}`; - } else if (options.basicAuth) { - requestHeaders.Authorization = `Basic ${base64encode( - `${options.basicAuth.username}:${options.basicAuth.password}`, - )}`; - } - - requestHeaders["Content-Type"] = - !options.contentType || options.contentType === "json" - ? "application/json" - : "text/plain"; - - if (options.talerAmlOfficerSignature) { - requestHeaders["Taler-AML-Officer-Signature"] = - options.talerAmlOfficerSignature; - } - - const requestMethod = options?.method ?? "GET"; - const requestBody = options?.data; - const requestTimeout = options?.timeout ?? 5 * 1000; - const requestParams = options.params ?? {}; - const requestPreventCache = options.preventCache ?? false; - const requestPreventCors = options.preventCors ?? false; - - const validURL = validateURL(baseUrl, endpoint); - - if (!validURL) { - const error: HttpResponseUnexpectedError = { - info: { - url: `${baseUrl}${endpoint}`, - payload: {}, - hasToken: !!options.token, - status: 0, - options, - }, - type: ErrorType.UNEXPECTED, - exception: undefined, - loading: false, - message: `invalid URL: "${baseUrl}${endpoint}"`, - }; - throw new RequestError(error); - } - - Object.entries(requestParams).forEach(([key, value]) => { - validURL.searchParams.set(key, String(value)); - }); - - let payload: BodyInit | undefined = undefined; - if (requestBody != null) { - if (typeof requestBody === "string") { - payload = requestBody; - } else if (requestBody instanceof ArrayBuffer) { - payload = requestBody; - } else if (ArrayBuffer.isView(requestBody)) { - payload = new Uint8Array( - requestBody.buffer, - requestBody.byteOffset, - requestBody.byteLength, - ) as Uint8Array<ArrayBuffer>; - } else if (typeof requestBody === "object") { - payload = JSON.stringify(requestBody); - } else { - const error: HttpResponseUnexpectedError = { - info: { - url: validURL.href, - payload: {}, - hasToken: !!options.token, - status: 0, - options, - }, - type: ErrorType.UNEXPECTED, - exception: undefined, - loading: false, - message: `unsupported request body type: "${typeof requestBody}"`, - }; - throw new RequestError(error); - } - } - - const controller = new AbortController(); - const timeoutId = setTimeout(() => { - controller.abort("HTTP_REQUEST_TIMEOUT"); - }, requestTimeout); - - let response; - try { - response = await fetch(validURL.href, { - headers: requestHeaders, - method: requestMethod, - credentials: "omit", - mode: requestPreventCors ? "no-cors" : "cors", - cache: requestPreventCache ? "no-cache" : "default", - body: payload, - signal: controller.signal, - }); - } catch (ex) { - const info: RequestInfo = { - payload, - url: validURL.href, - hasToken: !!options.token, - status: 0, - options, - }; - - if (ex instanceof Error) { - if (ex.message === "HTTP_REQUEST_TIMEOUT") { - const error: HttpRequestTimeoutError = { - info, - type: ErrorType.TIMEOUT, - message: "request timeout", - }; - throw new RequestError(error); - } - } - - const error: HttpResponseUnexpectedError = { - info, - type: ErrorType.UNEXPECTED, - exception: ex, - loading: false, - message: ex instanceof Error ? ex.message : "", - }; - throw new RequestError(error); - } - - if (timeoutId) { - clearTimeout(timeoutId); - } - const headerMap = new Headers(); - response.headers.forEach((value, key) => { - headerMap.set(key, value); - }); - - if (response.ok) { - const result = await buildRequestOk<T>( - response, - validURL.href, - payload, - !!options.token, - options, - ); - return result; - } else { - const dataTxt = await response.text(); - const error = buildRequestFailed( - validURL.href, - dataTxt, - response.status, - payload, - options, - ); - throw new RequestError(error); - } -} - -/** - * @deprecated do not use it, it will be removed - */ -export type HttpResponse<T, ErrorDetail> = - | HttpResponseOk<T> - | HttpResponseLoading<T> - | HttpError<ErrorDetail>; - -/** - * @deprecated do not use it, it will be removed - */ -export type HttpResponsePaginated<T, ErrorDetail> = - | HttpResponseOkPaginated<T> - | HttpResponseLoading<T> - | HttpError<ErrorDetail>; - -/** - * @deprecated do not use it, it will be removed - */ -export interface RequestInfo { - url: string; - hasToken: boolean; - payload: any; - status: number; - options: RequestOptions; -} - -interface HttpResponseLoading<T> { - ok?: false; - loading: true; - clientError?: false; - serverError?: false; - - data?: T; -} -/** - * @deprecated do not use it, it will be removed - */ -export interface HttpResponseOk<T> { - ok: true; - loading?: false; - clientError?: false; - serverError?: false; - - data: T; - info?: RequestInfo; -} - -/** - * @deprecated do not use it, it will be removed - */ -export type HttpResponseOkPaginated<T> = HttpResponseOk<T> & WithPagination; - -/** - * @deprecated do not use it, it will be removed - */ -export interface WithPagination { - loadMore: () => void; - loadMorePrev: () => void; - isReachingEnd?: boolean; - isReachingStart?: boolean; -} - -/** - * @deprecated do not use it, it will be removed - */ -export type HttpError<ErrorDetail> = - | HttpRequestTimeoutError - | HttpResponseClientError<ErrorDetail> - | HttpResponseServerError<ErrorDetail> - | HttpResponseUnreadableError - | HttpResponseUnexpectedError; - -/** - * @deprecated do not use it, it will be removed - */ -export interface HttpResponseServerError<ErrorDetail> { - ok?: false; - loading?: false; - type: ErrorType.SERVER; - payload: ErrorDetail; - status: HttpStatusCode; - message: string; - info: RequestInfo; -} -interface HttpRequestTimeoutError { - ok?: false; - loading?: false; - type: ErrorType.TIMEOUT; - - info: RequestInfo; - - message: string; -} -interface HttpResponseClientError<ErrorDetail> { - ok?: false; - loading?: false; - type: ErrorType.CLIENT; - - info: RequestInfo; - status: HttpStatusCode; - payload: ErrorDetail; - message: string; -} - -interface HttpResponseUnexpectedError { - ok?: false; - loading: false; - type: ErrorType.UNEXPECTED; - - info: RequestInfo; - status?: HttpStatusCode; - exception: unknown; - message: string; -} - -interface HttpResponseUnreadableError { - ok?: false; - loading: false; - type: ErrorType.UNREADABLE; - - info: RequestInfo; - status: HttpStatusCode; - exception: unknown; - body: string; - message: string; -} -/** - * @deprecated do not use it, it will be removed - */ -export class RequestError<ErrorDetail> extends Error { - /** - * @deprecated use cause - */ - info: HttpError<ErrorDetail>; - cause: HttpError<ErrorDetail>; - constructor(d: HttpError<ErrorDetail>) { - super(d.message); - this.info = d; - this.cause = d; - } -} - -type Methods = "GET" | "POST" | "PATCH" | "DELETE" | "PUT"; - -/** - * @deprecated do not use it, it will be removed - */ -export interface RequestOptions { - method?: Methods; - token?: string; - basicAuth?: { - username: string; - password: string; - }; - preventCache?: boolean; - preventCors?: boolean; - data?: any; - params?: unknown; - timeout?: number; - contentType?: "text" | "json"; - talerAmlOfficerSignature?: string; -} - -/** - * @deprecated do not use it, it will be removed - */ -async function buildRequestOk<T>( - response: Response, - url: string, - payload: any, - hasToken: boolean, - options: RequestOptions, -): Promise<HttpResponseOk<T>> { - const dataTxt = await response.text(); - const data = dataTxt ? JSON.parse(dataTxt) : undefined; - return { - ok: true, - data, - info: { - payload, - url, - hasToken, - options, - status: response.status, - }, - }; -} - -/** - * @deprecated do not use it, it will be removed - */ -export function buildRequestFailed<ErrorDetail>( - url: string, - dataTxt: string, - status: number, - payload: any, - maybeOptions?: RequestOptions, -): - | HttpResponseClientError<ErrorDetail> - | HttpResponseServerError<ErrorDetail> - | HttpResponseUnreadableError - | HttpResponseUnexpectedError { - const options = maybeOptions ?? {}; - const info: RequestInfo = { - payload, - url, - hasToken: !!options.token, - options, - status: status || 0, - }; - - // const dataTxt = await response.text(); - try { - const data = dataTxt ? JSON.parse(dataTxt) : undefined; - const errorCode = !data || !data.code ? "" : `(code: ${data.code})`; - const errorHint = - !data || !data.hint ? "Not hint." : `${data.hint} ${errorCode}`; - - if (status && status >= 400 && status < 500) { - const message = - data === undefined - ? `Client error (${status}) without data.` - : errorHint; - - const error: HttpResponseClientError<ErrorDetail> = { - type: ErrorType.CLIENT, - status, - info, - message, - payload: data, - }; - return error; - } - if (status && status >= 500 && status < 600) { - const message = - data === undefined - ? `Server error (${status}) without data.` - : errorHint; - const error: HttpResponseServerError<ErrorDetail> = { - type: ErrorType.SERVER, - status, - info, - message, - payload: data, - }; - return error; - } - return { - info, - loading: false, - type: ErrorType.UNEXPECTED, - status, - exception: undefined, - message: `http status code not handled: ${status}`, - }; - } catch (ex) { - const error: HttpResponseUnreadableError = { - info, - loading: false, - status, - type: ErrorType.UNREADABLE, - exception: ex, - body: dataTxt, - message: "Could not parse body as json", - }; - - return error; - } -} - -/** - * @deprecated do not use it, it will be removed - */ -function validateURL(baseUrl: string, endpoint: string): URL | undefined { - try { - return new URL(`${baseUrl}${endpoint}`); - } catch (ex) { - return undefined; - } -}