gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 04/06: moving testing sdk to web-utils


From: gnunet
Subject: [taler-wallet-core] 04/06: moving testing sdk to web-utils
Date: Wed, 14 Dec 2022 19:35:49 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

commit e97c808b412167d334353c7f6370e6d8b70bc0ae
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Dec 14 15:17:15 2022 -0300

    moving testing sdk to web-utils
---
 packages/web-util/build.mjs                    |   4 +-
 packages/web-util/package.json                 |   6 +-
 packages/web-util/src/components/index.ts      |   1 -
 packages/web-util/src/context/index.ts         |   7 +-
 packages/web-util/src/context/translation.ts   |   6 +-
 packages/web-util/src/hooks/index.ts           |  13 +-
 packages/web-util/src/hooks/useLocalStorage.ts |  36 +-
 packages/web-util/src/index.browser.ts         |   2 +-
 packages/web-util/src/live-reload.ts           |  24 +-
 packages/web-util/src/serve.ts                 |  25 +-
 packages/web-util/src/test/index.ts            | 224 ------
 packages/web-util/src/tests/axios.ts           | 136 ++++
 packages/web-util/src/tests/hook.ts            | 310 +++++++++
 packages/web-util/src/tests/index.ts           |   2 +
 packages/web-util/src/tests/mock.ts            | 458 ++++++++++++
 packages/web-util/src/tests/swr.ts             |  82 +++
 packages/web-util/src/utils/axios.ts           |  79 +++
 packages/web-util/src/utils/index.ts           |   1 +
 pnpm-lock.yaml                                 | 924 ++++---------------------
 19 files changed, 1263 insertions(+), 1077 deletions(-)

diff --git a/packages/web-util/build.mjs b/packages/web-util/build.mjs
index ba277b666..e7aede81c 100755
--- a/packages/web-util/build.mjs
+++ b/packages/web-util/build.mjs
@@ -78,13 +78,13 @@ const buildConfigNode = {
 
 const buildConfigBrowser = {
   ...buildConfigBase,
-  entryPoints: ["src/index.browser.ts", "src/live-reload.ts", 
'src/stories.tsx'],
+  entryPoints: ["src/tests/axios.ts", "src/tests/swr.ts", 
"src/index.browser.ts", "src/live-reload.ts", 'src/stories.tsx'],
   outExtension: {
     '.js': '.mjs'
   },
   format: 'esm',
   platform: 'browser',
-  external: ["preact", "@gnu-taler/taler-util", "jed"],
+  external: ["preact", "@gnu-taler/taler-util", "jed","swr","axios"],
   jsxFactory: 'h',
   jsxFragment: 'Fragment',
 };
diff --git a/packages/web-util/package.json b/packages/web-util/package.json
index 1add56d87..ad87304fe 100644
--- a/packages/web-util/package.json
+++ b/packages/web-util/package.json
@@ -12,6 +12,8 @@
   "license": "AGPL-3.0-or-later",
   "private": false,
   "exports": {
+    "./lib/tests/swr": "./lib/tests/swr.mjs",
+    "./lib/tests/axios": "./lib/tests/axios.mjs",
     "./lib/index.browser": "./lib/index.browser.mjs",
     "./lib/index.node": "./lib/index.node.cjs"
   },
@@ -27,6 +29,7 @@
     "@types/node": "^18.11.9",
     "@types/web": "^0.0.82",
     "@types/ws": "^8.5.3",
+    "axios": "^1.2.1",
     "chokidar": "^3.5.3",
     "esbuild": "^0.14.21",
     "express": "^4.18.2",
@@ -34,8 +37,9 @@
     "preact-render-to-string": "^5.2.6",
     "prettier": "^2.5.1",
     "rimraf": "^3.0.2",
+    "swr": "1.3.0",
     "tslib": "^2.4.0",
     "typescript": "^4.8.4",
     "ws": "7.4.5"
   }
-}
+}
\ No newline at end of file
diff --git a/packages/web-util/src/components/index.ts 
b/packages/web-util/src/components/index.ts
index dc7c86d7d..9441e971d 100644
--- a/packages/web-util/src/components/index.ts
+++ b/packages/web-util/src/components/index.ts
@@ -1,2 +1 @@
-
 export * as utils from "./utils.js";
diff --git a/packages/web-util/src/context/index.ts 
b/packages/web-util/src/context/index.ts
index 0ac2c752a..4bc1b22f2 100644
--- a/packages/web-util/src/context/index.ts
+++ b/packages/web-util/src/context/index.ts
@@ -1,2 +1,5 @@
-
-export { InternationalizationAPI, TranslationProvider, useTranslationContext } 
from "./translation.js";
+export {
+  InternationalizationAPI,
+  TranslationProvider,
+  useTranslationContext,
+} from "./translation.js";
diff --git a/packages/web-util/src/context/translation.ts 
b/packages/web-util/src/context/translation.ts
index ce140ec42..3b79e31d3 100644
--- a/packages/web-util/src/context/translation.ts
+++ b/packages/web-util/src/context/translation.ts
@@ -19,7 +19,7 @@ import { ComponentChildren, createContext, h, VNode } from 
"preact";
 import { useContext, useEffect } from "preact/hooks";
 import { useLang } from "../hooks/index.js";
 
-export type InternationalizationAPI = typeof i18n
+export type InternationalizationAPI = typeof i18n;
 
 interface Type {
   lang: string;
@@ -54,7 +54,7 @@ interface Props {
   initial?: string;
   children: ComponentChildren;
   forceLang?: string;
-  source: Record<string, any>
+  source: Record<string, any>;
 }
 
 // Outmost UI wrapper.
@@ -62,7 +62,7 @@ export const TranslationProvider = ({
   initial,
   children,
   forceLang,
-  source
+  source,
 }: Props): VNode => {
   const [lang, changeLanguage, isSaved] = useLang(initial);
   useEffect(() => {
diff --git a/packages/web-util/src/hooks/index.ts 
b/packages/web-util/src/hooks/index.ts
index 9ac56c4ac..393a6fcbb 100644
--- a/packages/web-util/src/hooks/index.ts
+++ b/packages/web-util/src/hooks/index.ts
@@ -1,4 +1,11 @@
-
 export { useLang } from "./useLang.js";
-export { useLocalStorage, useNotNullLocalStorage } from "./useLocalStorage.js"
-export { useAsyncAsHook, HookError, HookOk, HookResponse, 
HookResponseWithRetry, HookGenericError, HookOperationalError } from 
"./useAsyncAsHook.js"
\ No newline at end of file
+export { useLocalStorage, useNotNullLocalStorage } from "./useLocalStorage.js";
+export {
+  useAsyncAsHook,
+  HookError,
+  HookOk,
+  HookResponse,
+  HookResponseWithRetry,
+  HookGenericError,
+  HookOperationalError,
+} from "./useAsyncAsHook.js";
diff --git a/packages/web-util/src/hooks/useLocalStorage.ts 
b/packages/web-util/src/hooks/useLocalStorage.ts
index f518405b6..ab786db13 100644
--- a/packages/web-util/src/hooks/useLocalStorage.ts
+++ b/packages/web-util/src/hooks/useLocalStorage.ts
@@ -35,13 +35,13 @@ export function useLocalStorage(
 
   useEffect(() => {
     const listener = buildListenerForKey(key, (newValue) => {
-      setStoredValue(newValue ?? initialValue)
-    })
-    window.addEventListener('storage', listener)
+      setStoredValue(newValue ?? initialValue);
+    });
+    window.addEventListener("storage", listener);
     return () => {
-      window.removeEventListener('storage', listener)
-    }
-  }, [])
+      window.removeEventListener("storage", listener);
+    };
+  }, []);
 
   const setValue = (
     value?: string | ((val?: string) => string | undefined),
@@ -62,11 +62,14 @@ export function useLocalStorage(
   return [storedValue, setValue];
 }
 
-function buildListenerForKey(key: string, onUpdate: (newValue: string | 
undefined) => void): () => void {
+function buildListenerForKey(
+  key: string,
+  onUpdate: (newValue: string | undefined) => void,
+): () => void {
   return function listenKeyChange() {
-    const value = window.localStorage.getItem(key)
-    onUpdate(value ?? undefined)
-  }
+    const value = window.localStorage.getItem(key);
+    onUpdate(value ?? undefined);
+  };
 }
 
 //TODO: merge with the above function
@@ -80,16 +83,15 @@ export function useNotNullLocalStorage(
       : initialValue;
   });
 
-
   useEffect(() => {
     const listener = buildListenerForKey(key, (newValue) => {
-      setStoredValue(newValue ?? initialValue)
-    })
-    window.addEventListener('storage', listener)
+      setStoredValue(newValue ?? initialValue);
+    });
+    window.addEventListener("storage", listener);
     return () => {
-      window.removeEventListener('storage', listener)
-    }
-  })
+      window.removeEventListener("storage", listener);
+    };
+  });
 
   const setValue = (value: string | ((val: string) => string)): void => {
     const valueToStore = value instanceof Function ? value(storedValue) : 
value;
diff --git a/packages/web-util/src/index.browser.ts 
b/packages/web-util/src/index.browser.ts
index 734a2f426..d3aeae168 100644
--- a/packages/web-util/src/index.browser.ts
+++ b/packages/web-util/src/index.browser.ts
@@ -1,5 +1,5 @@
 export * from "./hooks/index.js";
 export * from "./context/index.js";
 export * from "./components/index.js";
-export * as test from "./test/index.js";
+export * as tests from "./tests/index.js";
 export { renderStories, parseGroupImport } from "./stories.js";
diff --git a/packages/web-util/src/live-reload.ts 
b/packages/web-util/src/live-reload.ts
index 901127f83..74d542956 100644
--- a/packages/web-util/src/live-reload.ts
+++ b/packages/web-util/src/live-reload.ts
@@ -15,24 +15,24 @@ function setupLiveReload(): void {
         return;
       }
       if (event.type === "file-updated-failed") {
-        const h1 = document.getElementById("overlay-text")
+        const h1 = document.getElementById("overlay-text");
         if (h1) {
-          h1.innerHTML = "compilation failed"
-          h1.style.color = 'red'
-          h1.style.margin = ''
+          h1.innerHTML = "compilation failed";
+          h1.style.color = "red";
+          h1.style.margin = "";
         }
-        const div = document.getElementById("overlay")
+        const div = document.getElementById("overlay");
         if (div) {
-          const content = JSON.stringify(event.data, undefined, 2)
+          const content = JSON.stringify(event.data, undefined, 2);
           const pre = document.createElement("pre");
-          pre.id = "error-text"
+          pre.id = "error-text";
           pre.style.margin = "";
           pre.textContent = content;
           div.style.backgroundColor = "rgba(0,0,0,0.8)";
-          div.style.flexDirection = 'column'
+          div.style.flexDirection = "column";
           div.appendChild(pre);
         }
-        console.error(event.data.error)
+        console.error(event.data.error);
         return;
       }
       if (event.type === "file-updated") {
@@ -56,17 +56,17 @@ setupLiveReload();
 
 function showReloadOverlay(): void {
   const d = document.createElement("div");
-  d.id = "overlay"
+  d.id = "overlay";
   d.style.position = "absolute";
   d.style.width = "100%";
   d.style.height = "100%";
   d.style.color = "white";
   d.style.backgroundColor = "rgba(0,0,0,0.5)";
   d.style.display = "flex";
-  d.style.zIndex = String(Number.MAX_SAFE_INTEGER)
+  d.style.zIndex = String(Number.MAX_SAFE_INTEGER);
   d.style.justifyContent = "center";
   const h = document.createElement("h1");
-  h.id = "overlay-text"
+  h.id = "overlay-text";
   h.style.margin = "auto";
   h.innerHTML = "reloading...";
   d.appendChild(h);
diff --git a/packages/web-util/src/serve.ts b/packages/web-util/src/serve.ts
index 3248bbeb8..f3a97e2e2 100644
--- a/packages/web-util/src/serve.ts
+++ b/packages/web-util/src/serve.ts
@@ -77,23 +77,26 @@ export async function serve(opts: {
 
       if (opts.onUpdate) {
         sendToAllClients({ type: "file-updated-start", data: { path } });
-        opts.onUpdate().then((result) => {
-          sendToAllClients({
-            type: "file-updated-done",
-            data: { path, result },
+        opts
+          .onUpdate()
+          .then((result) => {
+            sendToAllClients({
+              type: "file-updated-done",
+              data: { path, result },
+            });
+          })
+          .catch((error) => {
+            sendToAllClients({
+              type: "file-updated-failed",
+              data: { path, error },
+            });
           });
-        }).catch((error) => {
-          sendToAllClients({
-            type: "file-updated-failed",
-            data: { path, error },
-          });
-        });
       } else {
         sendToAllClients({ type: "file-change", data: { path } });
       }
     });
 
-    if (opts.onUpdate) opts.onUpdate()
+    if (opts.onUpdate) opts.onUpdate();
 
     app.get(PATHS.EXAMPLE, function (req: any, res: any) {
       res.set("Content-Type", "text/html");
diff --git a/packages/web-util/src/test/index.ts 
b/packages/web-util/src/test/index.ts
deleted file mode 100644
index 623115e79..000000000
--- a/packages/web-util/src/test/index.ts
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { NotificationType } from "@gnu-taler/taler-util";
-//  import {
-//    WalletCoreApiClient,
-//    WalletCoreOpKeys,
-//    WalletCoreRequestType,
-//    WalletCoreResponseType,
-//  } from "@gnu-taler/taler-wallet-core";
-import {
-  ComponentChildren,
-  Fragment,
-  FunctionalComponent,
-  h as create,
-  options,
-  render as renderIntoDom,
-  VNode,
-} from "preact";
-import { render as renderToString } from "preact-render-to-string";
-// import { BackgroundApiClient, wxApi } from "./wxApi.js";
-
-// When doing tests we want the requestAnimationFrame to be as fast as 
possible.
-// without this option the RAF will timeout after 100ms making the tests slower
-options.requestAnimationFrame = (fn: () => void) => {
-  return fn();
-};
-
-export function createExample<Props>(
-  Component: FunctionalComponent<Props>,
-  props: Partial<Props> | (() => Partial<Props>),
-): ComponentChildren {
-  const evaluatedProps = typeof props === "function" ? props() : props;
-  const Render = (args: any): VNode => create(Component, args);
-
-  return {
-    component: Render,
-    props: evaluatedProps
-  };
-}
-
-export function createExampleWithCustomContext<Props, ContextProps>(
-  Component: FunctionalComponent<Props>,
-  props: Partial<Props> | (() => Partial<Props>),
-  ContextProvider: FunctionalComponent<ContextProps>,
-  contextProps: Partial<ContextProps>,
-): ComponentChildren {
-  /**
-   * FIXME:
-   * This may not be useful since the example can be created with context
-   * already
-   */
-  const evaluatedProps = typeof props === "function" ? props() : props;
-  const Render = (args: any): VNode => create(Component, args);
-  const WithContext = (args: any): VNode =>
-    create(ContextProvider, {
-      ...contextProps,
-      children: [Render(args)],
-    } as any);
-
-  return {
-    component: WithContext,
-    props: evaluatedProps
-  };
-}
-
-const isNode = typeof window === "undefined";
-
-/**
- * To be used on automated unit test.
- * So test will run under node or browser
- * @param Component 
- * @param args 
- */
-export function renderNodeOrBrowser(Component: any, args: any): void {
-  const vdom = create(Component, args);
-  if (isNode) {
-    renderToString(vdom);
-  } else {
-    const div = document.createElement("div");
-    document.body.appendChild(div);
-    renderIntoDom(vdom, div);
-    renderIntoDom(null, div);
-    document.body.removeChild(div);
-  }
-}
-type RecursiveState<S> = S | (() => RecursiveState<S>);
-
-interface Mounted<T> {
-  unmount: () => void;
-  pullLastResultOrThrow: () => Exclude<T, VoidFunction>;
-  assertNoPendingUpdate: () => void;
-  // waitNextUpdate: (s?: string) => Promise<void>;
-  waitForStateUpdate: () => Promise<boolean>;
-}
-
-/**
- * Main test API, mount the hook and return testing API
- * @param callback 
- * @param Context 
- * @returns 
- */
-export function mountHook<T extends object>(
-  callback: () => RecursiveState<T>,
-  Context?: ({ children }: { children: any }) => VNode,
-): Mounted<T> {
-  let lastResult: Exclude<T, VoidFunction> | Error | null = null;
-
-  const listener: Array<() => void> = [];
-
-  // component that's going to hold the hook
-  function Component(): VNode {
-    try {
-      let componentOrResult = callback();
-      while (typeof componentOrResult === "function") {
-        componentOrResult = componentOrResult();
-      }
-      //typecheck fails here
-      const l: Exclude<T, () => void> = componentOrResult as any;
-      lastResult = l;
-    } catch (e) {
-      if (e instanceof Error) {
-        lastResult = e;
-      } else {
-        lastResult = new Error(`mounting the hook throw an exception: ${e}`);
-      }
-    }
-
-    // notify to everyone waiting for an update and clean the queue
-    listener.splice(0, listener.length).forEach((cb) => cb());
-    return create(Fragment, {});
-  }
-
-  // create the vdom with context if required
-  const vdom = !Context
-    ? create(Component, {})
-    : create(Context, { children: [create(Component, {})] });
-
-  const customElement = {} as Element;
-  const parentElement = isNode ? customElement : document.createElement("div");
-  if (!isNode) {
-    document.body.appendChild(parentElement);
-  }
-
-  renderIntoDom(vdom, parentElement);
-
-  // clean up callback
-  function unmount(): void {
-    if (!isNode) {
-      document.body.removeChild(parentElement);
-    }
-  }
-
-  function pullLastResult(): Exclude<T | Error | null, VoidFunction> {
-    const copy: Exclude<T | Error | null, VoidFunction> = lastResult;
-    lastResult = null;
-    return copy;
-  }
-
-  function pullLastResultOrThrow(): Exclude<T, VoidFunction> {
-    const r = pullLastResult();
-    if (r instanceof Error) throw r;
-    if (!r) throw Error("there was no last result");
-    return r;
-  }
-
-  async function assertNoPendingUpdate(): Promise<void> {
-    await new Promise((res, rej) => {
-      const tid = setTimeout(() => {
-        res(undefined);
-      }, 10);
-
-      listener.push(() => {
-        clearTimeout(tid);
-        rej(
-          Error(`Expecting no pending result but the hook got updated. 
-         If the update was not intended you need to check the hook 
dependencies 
-         (or dependencies of the internal state) but otherwise make 
-         sure to consume the result before ending the test.`),
-        );
-      });
-    });
-
-    const r = pullLastResult();
-    if (r)
-      throw Error(`There are still pending results.
-     This may happen because the hook did a new update but the test didn't 
consume the result using pullLastResult`);
-  }
-  async function waitForStateUpdate(): Promise<boolean> {
-    return await new Promise((res, rej) => {
-      const tid = setTimeout(() => {
-        res(false);
-      }, 10);
-
-      listener.push(() => {
-        clearTimeout(tid);
-        res(true);
-      });
-    });
-  }
-
-  return {
-    unmount,
-    pullLastResultOrThrow,
-    waitForStateUpdate,
-    assertNoPendingUpdate,
-  };
-}
-
-export const nullFunction = (): void => { null }
-export const nullAsyncFunction = (): Promise<void> => { return 
Promise.resolve() }
\ No newline at end of file
diff --git a/packages/web-util/src/tests/axios.ts 
b/packages/web-util/src/tests/axios.ts
new file mode 100644
index 000000000..38f8a9899
--- /dev/null
+++ b/packages/web-util/src/tests/axios.ts
@@ -0,0 +1,136 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 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 axios, { AxiosPromise, AxiosRequestConfig } from "axios";
+import * as axios from "axios";
+import {
+  setAxiosRequestAsTestingEnvironment,
+  mockAxiosOnce,
+} from "../utils/axios.js";
+
+const TESTING_DEBUG_LOG = process.env["TESTING_DEBUG_LOG"] !== undefined;
+
+const defaultCallback = (
+  actualQuery?: axios.AxiosRequestConfig,
+): axios.AxiosPromise<any> => {
+  if (TESTING_DEBUG_LOG) {
+    console.log("UNEXPECTED QUERY", actualQuery);
+  }
+  throw Error(
+    "Default Axios mock callback is called, this mean that the test did a 
tried to use axios but there was no expectation in place, try using 
JEST_DEBUG_LOG env",
+  );
+};
+
+setAxiosRequestAsTestingEnvironment(defaultCallback);
+
+export type Query<Req, Res> = {
+  method: axios.Method;
+  url: string;
+  code?: number;
+};
+
+type ExpectationValues = {
+  query: Query<any, any>;
+  params?: {
+    auth?: string;
+    request?: object;
+    qparam?: Record<string, string>;
+    response?: object;
+  };
+};
+
+type TestValues = [
+  axios.AxiosRequestConfig | undefined,
+  ExpectationValues | undefined,
+];
+
+export class AxiosMockEnvironment {
+  expectations: Array<
+    | {
+        query: Query<any, any>;
+        auth?: string;
+        params?: {
+          request?: object;
+          qparam?: Record<string, string>;
+          response?: object;
+        };
+        result: { args: axios.AxiosRequestConfig | undefined };
+      }
+    | undefined
+  > = [];
+  // axiosMock: jest.MockedFunction<axios.AxiosStatic>
+
+  addRequestExpectation<
+    RequestType extends object,
+    ResponseType extends object,
+  >(
+    expectedQuery: Query<RequestType, ResponseType>,
+    params: {
+      auth?: string;
+      request?: RequestType;
+      qparam?: any;
+      response?: ResponseType;
+    },
+  ): void {
+    const result = mockAxiosOnce(function (
+      actualQuery?: axios.AxiosRequestConfig,
+    ): axios.AxiosPromise {
+      if (TESTING_DEBUG_LOG) {
+        console.log("query to the backend is made", actualQuery);
+      }
+      if (!expectedQuery) {
+        return Promise.reject("a query was made but it was not expected");
+      }
+      if (TESTING_DEBUG_LOG) {
+        console.log("expected query:", params?.request);
+        console.log("expected qparams:", params?.qparam);
+        console.log("sending response:", params?.response);
+      }
+
+      const responseCode = expectedQuery.code || 200;
+
+      //This response is what buildRequestOk is expecting in file 
hook/backend.ts
+      if (responseCode >= 200 && responseCode < 300) {
+        return Promise.resolve({
+          data: params?.response,
+          config: {
+            data: params?.response,
+            params: actualQuery?.params || {},
+          },
+          request: { params: actualQuery?.params || {} },
+        } as any);
+      }
+      //This response is what buildRequestFailed is expecting in file 
hook/backend.ts
+      return Promise.reject({
+        response: {
+          status: responseCode,
+        },
+        request: {
+          data: params?.response,
+          params: actualQuery?.params || {},
+        },
+      });
+    } as any);
+
+    this.expectations.push({ query: expectedQuery, params, result });
+  }
+
+  getLastTestValues(): TestValues {
+    const expectedQuery = this.expectations.shift();
+
+    return [expectedQuery?.result.args, expectedQuery];
+  }
+}
diff --git a/packages/web-util/src/tests/hook.ts 
b/packages/web-util/src/tests/hook.ts
new file mode 100644
index 000000000..f5bebbd6d
--- /dev/null
+++ b/packages/web-util/src/tests/hook.ts
@@ -0,0 +1,310 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 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 {
+  ComponentChildren,
+  Fragment,
+  FunctionalComponent,
+  h as create,
+  options,
+  render as renderIntoDom,
+  VNode
+} from "preact";
+
+// This library is expected to be included in testing environment only
+// When doing tests we want the requestAnimationFrame to be as fast as 
possible.
+// without this option the RAF will timeout after 100ms making the tests slower
+options.requestAnimationFrame = (fn: () => void) => {
+  return fn();
+};
+
+export function createExample<Props>(
+  Component: FunctionalComponent<Props>,
+  props: Partial<Props> | (() => Partial<Props>),
+): ComponentChildren {
+  const evaluatedProps = typeof props === "function" ? props() : props;
+  const Render = (args: any): VNode => create(Component, args);
+
+  return {
+    component: Render,
+    props: evaluatedProps,
+  };
+}
+
+// export function createExampleWithCustomContext<Props, ContextProps>(
+//   Component: FunctionalComponent<Props>,
+//   props: Partial<Props> | (() => Partial<Props>),
+//   ContextProvider: FunctionalComponent<ContextProps>,
+//   contextProps: Partial<ContextProps>,
+// ): ComponentChildren {
+//   /**
+//    * FIXME:
+//    * This may not be useful since the example can be created with context
+//    * already
+//    */
+//   const evaluatedProps = typeof props === "function" ? props() : props;
+//   const Render = (args: any): VNode => create(Component, args);
+//   const WithContext = (args: any): VNode =>
+//     create(ContextProvider, {
+//       ...contextProps,
+//       children: [Render(args)],
+//     } as any);
+
+//   return {
+//     component: WithContext,
+//     props: evaluatedProps,
+//   };
+// }
+
+const isNode = typeof window === "undefined";
+
+/**
+ * To be used on automated unit test.
+ * So test will run under node or browser
+ * @param Component
+ * @param args
+ */
+export function renderNodeOrBrowser(
+  Component: any,
+  args: any,
+  Context: any,
+): void {
+  const vdom = !Context
+    ? create(Component, args)
+    : create(Context, { children: [create(Component, args)] });
+
+  const customElement = {} as Element;
+  const parentElement = isNode ? customElement : document.createElement("div");
+  if (!isNode) {
+    document.body.appendChild(parentElement);
+  }
+
+  // renderIntoDom works also in nodejs
+  // if the VirtualDOM is composed only by functional components
+  // then no called is going to be made to the DOM api.
+  // vdom should not have any 'div' or other html component
+  renderIntoDom(vdom, parentElement);
+
+  if (!isNode) {
+    document.body.removeChild(parentElement);
+  }
+}
+type RecursiveState<S> = S | (() => RecursiveState<S>);
+
+interface Mounted<T> {
+  // unmount: () => void;
+  pullLastResultOrThrow: () => Exclude<T, VoidFunction>;
+  assertNoPendingUpdate: () => Promise<boolean>;
+  // waitNextUpdate: (s?: string) => Promise<void>;
+  waitForStateUpdate: () => Promise<boolean>;
+}
+
+/**
+ * Manual API mount the hook and return testing API
+ * Consider using hookBehaveLikeThis() function
+ * 
+ * @param hookToBeTested
+ * @param Context
+ * 
+ * @returns testing API
+ */
+export function mountHook<T extends object>(
+  hookToBeTested: () => RecursiveState<T>,
+  Context?: ({ children }: { children: any }) => VNode | null,
+): Mounted<T> {
+  let lastResult: Exclude<T, VoidFunction> | Error | null = null;
+
+  const listener: Array<() => void> = [];
+
+  // component that's going to hold the hook
+  function Component(): VNode {
+    try {
+      let componentOrResult = hookToBeTested();
+      while (typeof componentOrResult === "function") {
+        componentOrResult = componentOrResult();
+      }
+      //typecheck fails here
+      const l: Exclude<T, () => void> = componentOrResult as any;
+      lastResult = l;
+    } catch (e) {
+      if (e instanceof Error) {
+        lastResult = e;
+      } else {
+        lastResult = new Error(`mounting the hook throw an exception: ${e}`);
+      }
+    }
+
+    // notify to everyone waiting for an update and clean the queue
+    listener.splice(0, listener.length).forEach((cb) => cb());
+    return create(Fragment, {});
+  }
+
+  renderNodeOrBrowser(Component, {}, Context);
+
+  function pullLastResult(): Exclude<T | Error | null, VoidFunction> {
+    const copy: Exclude<T | Error | null, VoidFunction> = lastResult;
+    lastResult = null;
+    return copy;
+  }
+
+  function pullLastResultOrThrow(): Exclude<T, VoidFunction> {
+    const r = pullLastResult();
+    if (r instanceof Error) throw r;
+    //sanity check
+    if (!r) throw Error("there was no last result");
+    return r;
+  }
+
+  async function assertNoPendingUpdate(): Promise<boolean> {
+    await new Promise((res, rej) => {
+      const tid = setTimeout(() => {
+        res(true);
+      }, 10);
+
+      listener.push(() => {
+        clearTimeout(tid);
+        res(false);
+        //   Error(`Expecting no pending result but the hook got updated.
+        //  If the update was not intended you need to check the hook 
dependencies
+        //  (or dependencies of the internal state) but otherwise make
+        //  sure to consume the result before ending the test.`),
+        // );
+      });
+    });
+
+    const r = pullLastResult();
+    if (r) {
+      return Promise.resolve(false);
+    }
+    return Promise.resolve(true);
+    // throw Error(`There are still pending results.
+    //  This may happen because the hook did a new update but the test didn't 
consume the result using pullLastResult`);
+  }
+  async function waitForStateUpdate(): Promise<boolean> {
+    return await new Promise((res, rej) => {
+      const tid = setTimeout(() => {
+        res(false);
+      }, 10);
+
+      listener.push(() => {
+        clearTimeout(tid);
+        res(true);
+      });
+    });
+  }
+
+  return {
+    // unmount,
+    pullLastResultOrThrow,
+    waitForStateUpdate,
+    assertNoPendingUpdate,
+  };
+}
+
+export const nullFunction = (): void => {
+  null;
+};
+export const nullAsyncFunction = (): Promise<void> => {
+  return Promise.resolve();
+};
+
+type HookTestResult = HookTestResultOk | HookTestResultError;
+
+interface HookTestResultOk {
+  result: "ok";
+}
+interface HookTestResultError {
+  result: "fail";
+  error: string;
+  index: number;
+}
+
+/**
+ * Main testing driver.
+ * It will assert that there are no more and no less hook updates than 
expected. 
+ * 
+ * @param hookFunction hook function to be tested
+ * @param props initial props for the hook
+ * @param checks step by step state validation
+ * @param Context additional testing context for overrides
+ * 
+ * @returns testing result, should also be checked to be "ok"
+ */
+export async function hookBehaveLikeThis<T extends object, PropsType>(
+  hookFunction: (p: PropsType) => RecursiveState<T>,
+  props: PropsType,
+  checks: Array<(state: T) => void>,
+  Context?: ({ children }: { children: any }) => VNode | null,
+): Promise<HookTestResult> {
+  const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
+    mountHook<T>(() => hookFunction(props), Context);
+
+  const [firstCheck, ...resultOfTheChecks] = checks;
+  {
+    const state = pullLastResultOrThrow();
+    const checkError = firstCheck(state);
+    if (checkError !== undefined) {
+      return {
+        result: "fail",
+        index: 0,
+        error: `Check return not undefined error: ${checkError}`,
+      };
+    }
+  }
+
+  let index = 1;
+  for (const check of resultOfTheChecks) {
+    const hasNext = await waitForStateUpdate();
+    if (!hasNext) {
+      return {
+        result: "fail",
+        error: "Component didn't update and the test expected one more state",
+        index,
+      };
+    }
+    const state = pullLastResultOrThrow();
+    const checkError = check(state);
+    if (checkError !== undefined) {
+      return {
+        result: "fail",
+        index,
+        error: `Check return not undefined error: ${checkError}`,
+      };
+    }
+    index++;
+  }
+
+  const hasNext = await waitForStateUpdate();
+  if (hasNext) {
+    return {
+      result: "fail",
+      index,
+      error: "Component updated and test didn't expect more states",
+    };
+  }
+  const noMoreUpdates = await assertNoPendingUpdate();
+  if (noMoreUpdates === false) {
+    return {
+      result: "fail",
+      index,
+      error: "Component was updated but the test does not cover the update",
+    };
+  }
+
+  return {
+    result: "ok",
+  };
+}
diff --git a/packages/web-util/src/tests/index.ts 
b/packages/web-util/src/tests/index.ts
new file mode 100644
index 000000000..2c0d929f8
--- /dev/null
+++ b/packages/web-util/src/tests/index.ts
@@ -0,0 +1,2 @@
+export * from "./hook.js";
+// export * from "./axios.js"
diff --git a/packages/web-util/src/tests/mock.ts 
b/packages/web-util/src/tests/mock.ts
new file mode 100644
index 000000000..563e437e5
--- /dev/null
+++ b/packages/web-util/src/tests/mock.ts
@@ -0,0 +1,458 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 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 { Logger } from "@gnu-taler/taler-util";
+
+type HttpMethod =
+  | "get"
+  | "GET"
+  | "delete"
+  | "DELETE"
+  | "head"
+  | "HEAD"
+  | "options"
+  | "OPTIONS"
+  | "post"
+  | "POST"
+  | "put"
+  | "PUT"
+  | "patch"
+  | "PATCH"
+  | "purge"
+  | "PURGE"
+  | "link"
+  | "LINK"
+  | "unlink"
+  | "UNLINK";
+
+export type Query<Req, Res> = {
+  method: HttpMethod;
+  url: string;
+  code?: number;
+};
+
+type ExpectationValues = {
+  query: Query<any, any>;
+  auth?: string;
+  params?: {
+    request?: object;
+    qparam?: Record<string, string>;
+    response?: object;
+  };
+};
+
+type TestValues = {
+  currentExpectedQuery: ExpectationValues | undefined;
+  lastQuery: ExpectationValues | undefined;
+};
+
+const logger = new Logger("testing/swr.ts");
+
+export abstract class MockEnvironment {
+  expectations: Array<ExpectationValues> = [];
+  queriesMade: Array<ExpectationValues> = [];
+  index = 0;
+
+  debug: boolean;
+  constructor(debug: boolean) {
+    this.debug = debug;
+    this.registerRequest.bind(this);
+  }
+
+  public addRequestExpectation<
+    RequestType extends object,
+    ResponseType extends object,
+  >(
+    query: Query<RequestType, ResponseType>,
+    params: {
+      auth?: string;
+      request?: RequestType;
+      qparam?: any;
+      response?: ResponseType;
+    },
+  ): void {
+    const expected = { query, params, auth: params.auth };
+    this.expectations.push(expected);
+    if (this.debug) {
+      logger.info("saving query as expected", expected);
+    }
+    this.mockApiIfNeeded();
+  }
+
+  abstract mockApiIfNeeded(): void;
+
+  public registerRequest<
+    RequestType extends object,
+    ResponseType extends object,
+  >(
+    query: Query<RequestType, ResponseType>,
+    params: {
+      auth?: string;
+      request?: RequestType;
+      qparam?: any;
+      response?: ResponseType;
+    },
+  ): { status: number; payload: ResponseType } | undefined {
+    const queryMade = { query, params, auth: params.auth };
+    this.queriesMade.push(queryMade);
+    const expectedQuery = this.expectations[this.index];
+    if (!expectedQuery) {
+      if (this.debug) {
+        logger.info("unexpected query made", queryMade);
+      }
+      return undefined;
+    }
+    const responseCode = this.expectations[this.index].query.code ?? 200;
+    const mockedResponse = this.expectations[this.index].params
+      ?.response as ResponseType;
+    if (this.debug) {
+      logger.info("tracking query made", {
+        queryMade,
+        expectedQuery,
+      });
+    }
+    this.index++;
+    return { status: responseCode, payload: mockedResponse };
+  }
+
+  public assertJustExpectedRequestWereMade(): AssertStatus {
+    let queryNumber = 0;
+
+    while (queryNumber < this.expectations.length) {
+      const r = this.assertNextRequest(queryNumber);
+      if (r.result !== "ok") return r;
+      queryNumber++;
+    }
+    return this.assertNoMoreRequestWereMade(queryNumber);
+  }
+
+  private getLastTestValues(idx: number): TestValues {
+    const currentExpectedQuery = this.expectations[idx];
+    const lastQuery = this.queriesMade[idx];
+
+    return { currentExpectedQuery, lastQuery };
+  }
+
+  private assertNoMoreRequestWereMade(idx: number): AssertStatus {
+    const { currentExpectedQuery, lastQuery } = this.getLastTestValues(idx);
+
+    if (lastQuery !== undefined) {
+      return {
+        result: "error-did-one-more",
+        made: lastQuery,
+      };
+    }
+    if (currentExpectedQuery !== undefined) {
+      return {
+        result: "error-did-one-less",
+        expected: currentExpectedQuery,
+      };
+    }
+
+    return {
+      result: "ok",
+    };
+  }
+
+  private assertNextRequest(idx: number): AssertStatus {
+    const { currentExpectedQuery, lastQuery } = this.getLastTestValues(idx);
+
+    if (!currentExpectedQuery) {
+      return {
+        result: "error-query-missing",
+      };
+    }
+
+    if (!lastQuery) {
+      return {
+        result: "error-did-one-less",
+        expected: currentExpectedQuery,
+      };
+    }
+
+    if (lastQuery.query.method) {
+      if (currentExpectedQuery.query.method !== lastQuery.query.method) {
+        return {
+          result: "error-difference",
+          diff: "method",
+        };
+      }
+      if (currentExpectedQuery.query.url !== lastQuery.query.url) {
+        return {
+          result: "error-difference",
+          diff: "url",
+        };
+      }
+    }
+    if (
+      !deepEquals(
+        currentExpectedQuery.params?.request,
+        lastQuery.params?.request,
+      )
+    ) {
+      return {
+        result: "error-difference",
+        diff: "query-body",
+      };
+    }
+    if (
+      !deepEquals(currentExpectedQuery.params?.qparam, 
lastQuery.params?.qparam)
+    ) {
+      return {
+        result: "error-difference",
+        diff: "query-params",
+      };
+    }
+    if (!deepEquals(currentExpectedQuery.auth, lastQuery.auth)) {
+      return {
+        result: "error-difference",
+        diff: "query-auth",
+      };
+    }
+
+    return {
+      result: "ok",
+    };
+  }
+}
+
+type AssertStatus =
+  | AssertOk
+  | AssertQueryNotMadeButExpected
+  | AssertQueryMadeButNotExpected
+  | AssertQueryMissing
+  | AssertExpectedQueryMethodMismatch
+  | AssertExpectedQueryUrlMismatch
+  | AssertExpectedQueryAuthMismatch
+  | AssertExpectedQueryBodyMismatch
+  | AssertExpectedQueryParamsMismatch;
+
+interface AssertOk {
+  result: "ok";
+}
+
+//trying to assert for a expected query but there is
+//no expected query in the queue
+interface AssertQueryMissing {
+  result: "error-query-missing";
+}
+
+//tested component did one more query that expected
+interface AssertQueryNotMadeButExpected {
+  result: "error-did-one-more";
+  made: ExpectationValues;
+}
+
+//tested component didn't make an expected query
+interface AssertQueryMadeButNotExpected {
+  result: "error-did-one-less";
+  expected: ExpectationValues;
+}
+
+interface AssertExpectedQueryMethodMismatch {
+  result: "error-difference";
+  diff: "method";
+}
+interface AssertExpectedQueryUrlMismatch {
+  result: "error-difference";
+  diff: "url";
+}
+interface AssertExpectedQueryAuthMismatch {
+  result: "error-difference";
+  diff: "query-auth";
+}
+interface AssertExpectedQueryBodyMismatch {
+  result: "error-difference";
+  diff: "query-body";
+}
+interface AssertExpectedQueryParamsMismatch {
+  result: "error-difference";
+  diff: "query-params";
+}
+
+/**
+ * helpers
+ *
+ */
+export type Tester = (a: any, b: any) => boolean | undefined;
+
+function deepEquals(
+  a: unknown,
+  b: unknown,
+  aStack: Array<unknown> = [],
+  bStack: Array<unknown> = [],
+): boolean {
+  //one if the element is null or undefined
+  if (a === null || b === null || b === undefined || a === undefined) {
+    return a === b;
+  }
+  //both are errors
+  if (a instanceof Error && b instanceof Error) {
+    return a.message == b.message;
+  }
+  //is the same object
+  if (Object.is(a, b)) {
+    return true;
+  }
+  //both the same class
+  const name = Object.prototype.toString.call(a);
+  if (name != Object.prototype.toString.call(b)) {
+    return false;
+  }
+  //
+  switch (name) {
+    case "[object Boolean]":
+    case "[object String]":
+    case "[object Number]":
+      if (typeof a !== typeof b) {
+        // One is a primitive, one a `new Primitive()`
+        return false;
+      } else if (typeof a !== "object" && typeof b !== "object") {
+        // both are proper primitives
+        return Object.is(a, b);
+      } else {
+        // both are `new Primitive()`s
+        return Object.is(a.valueOf(), b.valueOf());
+      }
+    case "[object Date]": {
+      const _a = a as Date;
+      const _b = b as Date;
+      return _a == _b;
+    }
+    case "[object RegExp]": {
+      const _a = a as RegExp;
+      const _b = b as RegExp;
+      return _a.source === _b.source && _a.flags === _b.flags;
+    }
+    case "[object Array]": {
+      const _a = a as Array<any>;
+      const _b = b as Array<any>;
+      if (_a.length !== _b.length) {
+        return false;
+      }
+    }
+  }
+  if (typeof a !== "object" || typeof b !== "object") {
+    return false;
+  }
+
+  if (
+    typeof a === "object" &&
+    typeof b === "object" &&
+    !Array.isArray(a) &&
+    !Array.isArray(b) &&
+    hasIterator(a) &&
+    hasIterator(b)
+  ) {
+    return iterable(a, b);
+  }
+
+  // Used to detect circular references.
+  let length = aStack.length;
+  while (length--) {
+    if (aStack[length] === a) {
+      return bStack[length] === b;
+    } else if (bStack[length] === b) {
+      return false;
+    }
+  }
+  aStack.push(a);
+  bStack.push(b);
+
+  const aKeys = allKeysFromObject(a);
+  const bKeys = allKeysFromObject(b);
+  let keySize = aKeys.length;
+
+  //same number of keys
+  if (bKeys.length !== keySize) {
+    return false;
+  }
+
+  let keyIterator: string;
+  while (keySize--) {
+    const _a = a as Record<string, object>;
+    const _b = b as Record<string, object>;
+
+    keyIterator = aKeys[keySize];
+
+    const de = deepEquals(_a[keyIterator], _b[keyIterator], aStack, bStack);
+    if (!de) {
+      return false;
+    }
+  }
+
+  aStack.pop();
+  bStack.pop();
+
+  return true;
+}
+
+function allKeysFromObject(obj: object): Array<string> {
+  const keys = [];
+  for (const key in obj) {
+    if (Object.prototype.hasOwnProperty.call(obj, key)) {
+      keys.push(key);
+    }
+  }
+  return keys;
+}
+
+const IteratorSymbol = Symbol.iterator;
+
+function hasIterator(object: any): boolean {
+  return !!(object != null && object[IteratorSymbol]);
+}
+
+function iterable(
+  a: unknown,
+  b: unknown,
+  aStack: Array<unknown> = [],
+  bStack: Array<unknown> = [],
+): boolean {
+  if (a === null || b === null || b === undefined || a === undefined) {
+    return a === b;
+  }
+  if (a.constructor !== b.constructor) {
+    return false;
+  }
+  let length = aStack.length;
+  while (length--) {
+    if (aStack[length] === a) {
+      return bStack[length] === b;
+    }
+  }
+  aStack.push(a);
+  bStack.push(b);
+
+  const aIterator = (a as any)[IteratorSymbol]();
+  const bIterator = (b as any)[IteratorSymbol]();
+
+  const nextA = aIterator.next();
+  while (nextA.done) {
+    const nextB = bIterator.next();
+    if (nextB.done || !deepEquals(nextA.value, nextB.value)) {
+      return false;
+    }
+  }
+  if (!bIterator.next().done) {
+    return false;
+  }
+
+  // Remove the first value from the stack of traversed values.
+  aStack.pop();
+  bStack.pop();
+  return true;
+}
diff --git a/packages/web-util/src/tests/swr.ts 
b/packages/web-util/src/tests/swr.ts
new file mode 100644
index 000000000..95c62ebea
--- /dev/null
+++ b/packages/web-util/src/tests/swr.ts
@@ -0,0 +1,82 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 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 { ComponentChildren, FunctionalComponent, h, VNode } from "preact";
+import { MockEnvironment, Query } from "./mock.js";
+import { SWRConfig } from "swr";
+
+export { Query };
+/**
+ * Helper for hook that use SWR inside.
+ * 
+ * buildTestingContext() will return a testing context
+ * 
+ */
+export class SwrMockEnvironment extends MockEnvironment {
+  constructor(debug = false) {
+    super(debug);
+  }
+
+  mockApiIfNeeded(): void {
+    null; // do nothing
+  }
+
+  public buildTestingContext(): FunctionalComponent<{
+    children: ComponentChildren;
+  }> {
+    const __REGISTER_REQUEST = this.registerRequest.bind(this);
+    return function TestingContext({
+      children,
+    }: {
+      children: ComponentChildren;
+    }): VNode {
+      return h(
+        SWRConfig,
+        {
+          value: {
+            fetcher: (url: string, options: object) => {
+              const mocked = __REGISTER_REQUEST(
+                {
+                  method: "get",
+                  url,
+                },
+                {},
+              );
+              if (!mocked) return undefined;
+              if (mocked.status > 400) {
+                const e: any = Error("simulated error for testing");
+                //example error handling from 
https://swr.vercel.app/docs/error-handling
+                e.status = mocked.status;
+                throw e;
+              }
+              return mocked.payload;
+            },
+            //These options are set for ending the test faster
+            //otherwise SWR will create timeouts that will live after the test 
finished
+            loadingTimeout: 0,
+            dedupingInterval: 0,
+            shouldRetryOnError: false,
+            errorRetryInterval: 0,
+            errorRetryCount: 0,
+            //clean cache for every test
+            provider: () => new Map(),
+          },
+        },
+        children,
+      );
+    };
+  }
+}
diff --git a/packages/web-util/src/utils/axios.ts 
b/packages/web-util/src/utils/axios.ts
new file mode 100644
index 000000000..c38314009
--- /dev/null
+++ b/packages/web-util/src/utils/axios.ts
@@ -0,0 +1,79 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 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 axios, { AxiosPromise, AxiosRequestConfig } from "axios";
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+//FIXME: remove this, since it is not used anymore
+/**
+ * @deprecated
+ */
+export let removeAxiosCancelToken = false;
+
+export let axiosHandler = function doAxiosRequest(
+  config: AxiosRequestConfig,
+): AxiosPromise<any> {
+  return axios(config);
+};
+
+const listOfHandlersToUseOnce = new Array<AxiosHandler>();
+
+/**
+ * Set this backend library to testing mode.
+ * Instead of calling the axios library the @handler will be called
+ *
+ * @param handler callback that will mock axios
+ */
+export function setAxiosRequestAsTestingEnvironment(
+  handler: AxiosHandler,
+): void {
+  removeAxiosCancelToken = true;
+  axiosHandler = function defaultTestingHandler(config) {
+    const currentHanlder = listOfHandlersToUseOnce.shift();
+    if (!currentHanlder) {
+      return handler(config);
+    }
+
+    return currentHanlder(config);
+  };
+}
+
+type AxiosHandler = (config: AxiosRequestConfig) => AxiosPromise<any>;
+type AxiosArguments = { args: AxiosRequestConfig | undefined };
+
+/**
+ * Replace Axios handler with a mock.
+ * Throw if is called more than once
+ *
+ * @param handler mock function
+ * @returns savedArgs
+ */
+export function mockAxiosOnce(handler: AxiosHandler): {
+  args: AxiosRequestConfig | undefined;
+} {
+  const savedArgs: AxiosArguments = { args: undefined };
+  listOfHandlersToUseOnce.push(
+    (config: AxiosRequestConfig): AxiosPromise<any> => {
+      savedArgs.args = config;
+      return handler(config);
+    },
+  );
+  return savedArgs;
+}
diff --git a/packages/web-util/src/utils/index.ts 
b/packages/web-util/src/utils/index.ts
new file mode 100644
index 000000000..6dfbd5f8d
--- /dev/null
+++ b/packages/web-util/src/utils/index.ts
@@ -0,0 +1 @@
+export * from "./axios.js";
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 43c45691b..c5255b4f1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -96,24 +96,30 @@ importers:
       '@gnu-taler/pogen': ^0.0.5
       '@gnu-taler/taler-util': workspace:*
       '@gnu-taler/web-util': workspace:*
+      '@types/chai': ^4.3.0
       '@types/history': ^4.7.8
+      '@types/mocha': ^10.0.1
+      '@types/node': ^18.11.14
       '@typescript-eslint/eslint-plugin': ^5.41.0
       '@typescript-eslint/parser': ^5.41.0
+      async_hooks: ^1.0.0
       bulma: ^0.9.4
       bulma-checkbox: ^1.1.1
       bulma-radio: ^1.1.1
+      chai: ^4.3.6
       date-fns: 2.29.3
       esbuild: ^0.15.12
       eslint-config-preact: ^1.2.0
       history: 4.10.1
       jed: 1.1.1
+      mocha: ^9.2.0
       po2json: ^0.4.5
       preact: 10.11.3
       preact-router: 3.2.1
       qrcode-generator: ^1.4.4
       sass: 1.56.1
       swr: 1.3.0
-      typescript: ^4.4.4
+      typescript: 4.8.4
     dependencies:
       '@gnu-taler/taler-util': link:../taler-util
       '@gnu-taler/web-util': link:../web-util
@@ -127,14 +133,20 @@ importers:
     devDependencies:
       '@creativebulma/bulma-tooltip': 1.2.0
       '@gnu-taler/pogen': link:../pogen
+      '@types/chai': 4.3.3
       '@types/history': 4.7.11
+      '@types/mocha': 10.0.1
+      '@types/node': 18.11.14
       '@typescript-eslint/eslint-plugin': 5.41.0_2dmizcyfdgb4npqs6z4fehioli
       '@typescript-eslint/parser': 5.41.0_typescript@4.8.4
+      async_hooks: 1.0.0
       bulma: 0.9.4
       bulma-checkbox: 1.2.1
       bulma-radio: 1.2.0
+      chai: 4.3.6
       esbuild: 0.15.12
       eslint-config-preact: 1.3.0_qqbgcrpnpybc6dh47gt272vyy4
+      mocha: 9.2.2
       po2json: 0.4.5
       sass: 1.56.1
       typescript: 4.8.4
@@ -383,7 +395,7 @@ importers:
       sirv-cli: ^1.0.11
       swr: 1.3.0
       typedoc: ^0.20.36
-      typescript: 4.4.4
+      typescript: 4.8.4
       yup: ^0.32.9
     dependencies:
       '@gnu-taler/taler-util': link:../taler-util
@@ -405,9 +417,9 @@ importers:
       '@gnu-taler/pogen': link:../pogen
       '@storybook/addon-a11y': 6.5.13_@preact+compat@17.1.2
       '@storybook/addon-actions': 6.5.13_@preact+compat@17.1.2
-      '@storybook/addon-essentials': 6.5.13_e4oandlgwkzlaxn6zc3btvol24
+      '@storybook/addon-essentials': 6.5.13_2nt5iz47gcdduxcnvfnexph4hq
       '@storybook/addon-links': 6.5.13_@preact+compat@17.1.2
-      '@storybook/preact': 6.5.13_q57tjbu375p52k2lkxkownwouu
+      '@storybook/preact': 6.5.13_xa5zyoe4qu34opzfrw5imxak3u
       '@storybook/preset-scss': 1.0.3_sass-loader@10.1.1
       '@testing-library/preact': 2.0.1_preact@10.6.5
       '@testing-library/preact-hooks': 1.1.0_vfcmu6iy7nffpurikpgxo6gwxi
@@ -415,8 +427,8 @@ importers:
       '@types/jest': 26.0.24
       '@types/mocha': 8.2.3
       '@types/node': 18.11.5
-      '@typescript-eslint/eslint-plugin': 4.33.0_zrqxgwgitu7trrjeml3nqco3jq
-      '@typescript-eslint/parser': 4.33.0_wnilx7boviscikmvsfkd6ljepe
+      '@typescript-eslint/eslint-plugin': 4.33.0_k4l66av2tbo6kxzw52jzgbfzii
+      '@typescript-eslint/parser': 4.33.0_3rubbgt5ekhqrcgx4uwls3neim
       babel-loader: 8.2.5_@babel+core@7.18.9
       base64-inline-loader: 1.1.1
       bulma: 0.9.4
@@ -428,7 +440,7 @@ importers:
       bulma-upload-control: 1.2.0
       dotenv: 8.6.0
       eslint: 7.32.0
-      eslint-config-preact: 1.3.0_55vw575o5aj4h37h7cossdtfje
+      eslint-config-preact: 1.3.0_nxlzr75jbqkso2fds5zjovs2ii
       eslint-plugin-header: 3.1.1_eslint@7.32.0
       html-webpack-inline-chunk-plugin: 1.1.1
       html-webpack-inline-source-plugin: 0.0.10
@@ -445,8 +457,8 @@ importers:
       sass-loader: 10.1.1_sass@1.55.0
       script-ext-html-webpack-plugin: 2.1.5
       sirv-cli: 1.0.14
-      typedoc: 0.20.37_typescript@4.4.4
-      typescript: 4.4.4
+      typedoc: 0.20.37_typescript@4.8.4
+      typescript: 4.8.4
 
   packages/pogen:
     specifiers:
@@ -697,6 +709,7 @@ importers:
       '@types/node': ^18.11.9
       '@types/web': ^0.0.82
       '@types/ws': ^8.5.3
+      axios: ^1.2.1
       chokidar: ^3.5.3
       esbuild: ^0.14.21
       express: ^4.18.2
@@ -704,6 +717,7 @@ importers:
       preact-render-to-string: ^5.2.6
       prettier: ^2.5.1
       rimraf: ^3.0.2
+      swr: 1.3.0
       tslib: ^2.4.0
       typescript: ^4.8.4
       ws: 7.4.5
@@ -713,6 +727,7 @@ importers:
       '@types/node': 18.11.9
       '@types/web': 0.0.82
       '@types/ws': 8.5.3
+      axios: 1.2.1
       chokidar: 3.5.3
       esbuild: 0.14.54
       express: 4.18.2
@@ -720,6 +735,7 @@ importers:
       preact-render-to-string: 5.2.6_preact@10.11.3
       prettier: 2.7.1
       rimraf: 3.0.2
+      swr: 1.3.0
       tslib: 2.4.1
       typescript: 4.8.4
       ws: 7.4.5
@@ -4635,7 +4651,7 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/addon-controls/6.5.13_ipjevasairp6knvwkrpikcsgoq:
+  /@storybook/addon-controls/6.5.13_j3fy4dsuv6tweqy6dixwnav3v4:
     resolution: {integrity: 
sha512-lYq3uf2mlVevm0bi6ueL3H6TpUMRYW9s/pTNTVJT225l27kLdFR9wEKxAkCBrlKaTgDLJmzzDRsJE3NLZlR/5Q==}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -4650,7 +4666,7 @@ packages:
       '@storybook/api': 6.5.13_@preact+compat@17.1.2
       '@storybook/client-logger': 6.5.13
       '@storybook/components': 6.5.13_@preact+compat@17.1.2
-      '@storybook/core-common': 6.5.13_ipjevasairp6knvwkrpikcsgoq
+      '@storybook/core-common': 6.5.13_j3fy4dsuv6tweqy6dixwnav3v4
       '@storybook/csf': 0.0.2--canary.4566f4d.1
       '@storybook/node-logger': 6.5.13
       '@storybook/store': 6.5.13_@preact+compat@17.1.2
@@ -4668,7 +4684,7 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/addon-docs/6.5.13_dazlt7ye7nu7xsezygxn7bviwy:
+  /@storybook/addon-docs/6.5.13_2nt5iz47gcdduxcnvfnexph4hq:
     resolution: {integrity: 
sha512-RG/NjsheD9FixZ789RJlNyNccaR2Cuy7CtAwph4oUNi3aDFjtOI8Oe9L+FOT7qtVnZLw/YMjF+pZxoDqJNKLPw==}
     peerDependencies:
       '@storybook/mdx2-csf': ^0.0.3
@@ -4685,26 +4701,27 @@ packages:
       '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.18.9
       '@babel/preset-env': 7.19.4_@babel+core@7.18.9
       '@jest/transform': 26.6.2
-      '@mdx-js/react': 1.6.22
-      '@storybook/addons': 6.5.13
-      '@storybook/api': 6.5.13
-      '@storybook/components': 6.5.13
-      '@storybook/core-common': 6.5.13_3rubbgt5ekhqrcgx4uwls3neim
+      '@mdx-js/react': 1.6.22_@preact+compat@17.1.2
+      '@storybook/addons': 6.5.13_@preact+compat@17.1.2
+      '@storybook/api': 6.5.13_@preact+compat@17.1.2
+      '@storybook/components': 6.5.13_@preact+compat@17.1.2
+      '@storybook/core-common': 6.5.13_j3fy4dsuv6tweqy6dixwnav3v4
       '@storybook/core-events': 6.5.13
       '@storybook/csf': 0.0.2--canary.4566f4d.1
-      '@storybook/docs-tools': 6.5.13
+      '@storybook/docs-tools': 6.5.13_@preact+compat@17.1.2
       '@storybook/mdx1-csf': 0.0.1_@babel+core@7.18.9
       '@storybook/node-logger': 6.5.13
       '@storybook/postinstall': 6.5.13
-      '@storybook/preview-web': 6.5.13
-      '@storybook/source-loader': 6.5.13
-      '@storybook/store': 6.5.13
-      '@storybook/theming': 6.5.13
+      '@storybook/preview-web': 6.5.13_@preact+compat@17.1.2
+      '@storybook/source-loader': 6.5.13_@preact+compat@17.1.2
+      '@storybook/store': 6.5.13_@preact+compat@17.1.2
+      '@storybook/theming': 6.5.13_@preact+compat@17.1.2
       babel-loader: 8.2.5_@babel+core@7.18.9
       core-js: 3.26.0
       fast-deep-equal: 3.1.3
       global: 4.4.0
       lodash: 4.17.21
+      react: /@preact/compat/17.1.2_preact@10.6.5
       regenerator-runtime: 0.13.10
       remark-external-links: 8.0.0
       remark-slug: 6.1.0
@@ -4721,7 +4738,7 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/addon-docs/6.5.13_e4oandlgwkzlaxn6zc3btvol24:
+  /@storybook/addon-docs/6.5.13_dazlt7ye7nu7xsezygxn7bviwy:
     resolution: {integrity: 
sha512-RG/NjsheD9FixZ789RJlNyNccaR2Cuy7CtAwph4oUNi3aDFjtOI8Oe9L+FOT7qtVnZLw/YMjF+pZxoDqJNKLPw==}
     peerDependencies:
       '@storybook/mdx2-csf': ^0.0.3
@@ -4738,27 +4755,26 @@ packages:
       '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.18.9
       '@babel/preset-env': 7.19.4_@babel+core@7.18.9
       '@jest/transform': 26.6.2
-      '@mdx-js/react': 1.6.22_@preact+compat@17.1.2
-      '@storybook/addons': 6.5.13_@preact+compat@17.1.2
-      '@storybook/api': 6.5.13_@preact+compat@17.1.2
-      '@storybook/components': 6.5.13_@preact+compat@17.1.2
-      '@storybook/core-common': 6.5.13_ipjevasairp6knvwkrpikcsgoq
+      '@mdx-js/react': 1.6.22
+      '@storybook/addons': 6.5.13
+      '@storybook/api': 6.5.13
+      '@storybook/components': 6.5.13
+      '@storybook/core-common': 6.5.13_3rubbgt5ekhqrcgx4uwls3neim
       '@storybook/core-events': 6.5.13
       '@storybook/csf': 0.0.2--canary.4566f4d.1
-      '@storybook/docs-tools': 6.5.13_@preact+compat@17.1.2
+      '@storybook/docs-tools': 6.5.13
       '@storybook/mdx1-csf': 0.0.1_@babel+core@7.18.9
       '@storybook/node-logger': 6.5.13
       '@storybook/postinstall': 6.5.13
-      '@storybook/preview-web': 6.5.13_@preact+compat@17.1.2
-      '@storybook/source-loader': 6.5.13_@preact+compat@17.1.2
-      '@storybook/store': 6.5.13_@preact+compat@17.1.2
-      '@storybook/theming': 6.5.13_@preact+compat@17.1.2
+      '@storybook/preview-web': 6.5.13
+      '@storybook/source-loader': 6.5.13
+      '@storybook/store': 6.5.13
+      '@storybook/theming': 6.5.13
       babel-loader: 8.2.5_@babel+core@7.18.9
       core-js: 3.26.0
       fast-deep-equal: 3.1.3
       global: 4.4.0
       lodash: 4.17.21
-      react: /@preact/compat/17.1.2_preact@10.6.5
       regenerator-runtime: 0.13.10
       remark-external-links: 8.0.0
       remark-slug: 6.1.0
@@ -4775,7 +4791,7 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/addon-essentials/6.5.13_dazlt7ye7nu7xsezygxn7bviwy:
+  /@storybook/addon-essentials/6.5.13_2nt5iz47gcdduxcnvfnexph4hq:
     resolution: {integrity: 
sha512-G9FVAWV7ixjVLWeLgIX+VT90tcAk6yQxfZQegfg5ucRilGysJCDaNnoab4xuuvm1R40TfFhba3iAGZtQYsddmw==}
     peerDependencies:
       '@babel/core': ^7.9.6
@@ -4833,19 +4849,20 @@ packages:
         optional: true
     dependencies:
       '@babel/core': 7.18.9
-      '@storybook/addon-actions': 6.5.13
-      '@storybook/addon-backgrounds': 6.5.13
-      '@storybook/addon-controls': 6.5.13_3rubbgt5ekhqrcgx4uwls3neim
-      '@storybook/addon-docs': 6.5.13_dazlt7ye7nu7xsezygxn7bviwy
-      '@storybook/addon-measure': 6.5.13
-      '@storybook/addon-outline': 6.5.13
-      '@storybook/addon-toolbars': 6.5.13
-      '@storybook/addon-viewport': 6.5.13
-      '@storybook/addons': 6.5.13
-      '@storybook/api': 6.5.13
-      '@storybook/core-common': 6.5.13_3rubbgt5ekhqrcgx4uwls3neim
+      '@storybook/addon-actions': 6.5.13_@preact+compat@17.1.2
+      '@storybook/addon-backgrounds': 6.5.13_@preact+compat@17.1.2
+      '@storybook/addon-controls': 6.5.13_j3fy4dsuv6tweqy6dixwnav3v4
+      '@storybook/addon-docs': 6.5.13_2nt5iz47gcdduxcnvfnexph4hq
+      '@storybook/addon-measure': 6.5.13_@preact+compat@17.1.2
+      '@storybook/addon-outline': 6.5.13_@preact+compat@17.1.2
+      '@storybook/addon-toolbars': 6.5.13_@preact+compat@17.1.2
+      '@storybook/addon-viewport': 6.5.13_@preact+compat@17.1.2
+      '@storybook/addons': 6.5.13_@preact+compat@17.1.2
+      '@storybook/api': 6.5.13_@preact+compat@17.1.2
+      '@storybook/core-common': 6.5.13_j3fy4dsuv6tweqy6dixwnav3v4
       '@storybook/node-logger': 6.5.13
       core-js: 3.26.0
+      react: /@preact/compat/17.1.2_preact@10.6.5
       regenerator-runtime: 0.13.10
       ts-dedent: 2.2.0
     transitivePeerDependencies:
@@ -4858,7 +4875,7 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/addon-essentials/6.5.13_e4oandlgwkzlaxn6zc3btvol24:
+  /@storybook/addon-essentials/6.5.13_dazlt7ye7nu7xsezygxn7bviwy:
     resolution: {integrity: 
sha512-G9FVAWV7ixjVLWeLgIX+VT90tcAk6yQxfZQegfg5ucRilGysJCDaNnoab4xuuvm1R40TfFhba3iAGZtQYsddmw==}
     peerDependencies:
       '@babel/core': ^7.9.6
@@ -4916,20 +4933,19 @@ packages:
         optional: true
     dependencies:
       '@babel/core': 7.18.9
-      '@storybook/addon-actions': 6.5.13_@preact+compat@17.1.2
-      '@storybook/addon-backgrounds': 6.5.13_@preact+compat@17.1.2
-      '@storybook/addon-controls': 6.5.13_ipjevasairp6knvwkrpikcsgoq
-      '@storybook/addon-docs': 6.5.13_e4oandlgwkzlaxn6zc3btvol24
-      '@storybook/addon-measure': 6.5.13_@preact+compat@17.1.2
-      '@storybook/addon-outline': 6.5.13_@preact+compat@17.1.2
-      '@storybook/addon-toolbars': 6.5.13_@preact+compat@17.1.2
-      '@storybook/addon-viewport': 6.5.13_@preact+compat@17.1.2
-      '@storybook/addons': 6.5.13_@preact+compat@17.1.2
-      '@storybook/api': 6.5.13_@preact+compat@17.1.2
-      '@storybook/core-common': 6.5.13_ipjevasairp6knvwkrpikcsgoq
+      '@storybook/addon-actions': 6.5.13
+      '@storybook/addon-backgrounds': 6.5.13
+      '@storybook/addon-controls': 6.5.13_3rubbgt5ekhqrcgx4uwls3neim
+      '@storybook/addon-docs': 6.5.13_dazlt7ye7nu7xsezygxn7bviwy
+      '@storybook/addon-measure': 6.5.13
+      '@storybook/addon-outline': 6.5.13
+      '@storybook/addon-toolbars': 6.5.13
+      '@storybook/addon-viewport': 6.5.13
+      '@storybook/addons': 6.5.13
+      '@storybook/api': 6.5.13
+      '@storybook/core-common': 6.5.13_3rubbgt5ekhqrcgx4uwls3neim
       '@storybook/node-logger': 6.5.13
       core-js: 3.26.0
-      react: /@preact/compat/17.1.2_preact@10.6.5
       regenerator-runtime: 0.13.10
       ts-dedent: 2.2.0
     transitivePeerDependencies:
@@ -5311,75 +5327,6 @@ packages:
       util-deprecate: 1.0.2
     dev: true
 
-  /@storybook/builder-webpack4/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y:
-    resolution: {integrity: 
sha512-Agqy3IKPv3Nl8QqdS7PjtqLp+c0BD8+/3A2ki/YfKqVz+F+J34EpbZlh3uU053avm1EoNQHSmhZok3ZlWH6O7A==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@babel/core': 7.18.9
-      '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/api': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/channel-postmessage': 6.5.13
-      '@storybook/channels': 6.5.13
-      '@storybook/client-api': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/client-logger': 6.5.13
-      '@storybook/components': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
-      '@storybook/core-events': 6.5.13
-      '@storybook/node-logger': 6.5.13
-      '@storybook/preview-web': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/router': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/semver': 7.3.2
-      '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/theming': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/ui': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@types/node': 16.18.0
-      '@types/webpack': 4.41.33
-      autoprefixer: 9.8.8
-      babel-loader: 8.2.5_7uc2ny5pnz7ums2wq2q562bf6y
-      case-sensitive-paths-webpack-plugin: 2.4.0
-      core-js: 3.26.0
-      css-loader: 3.6.0_webpack@4.46.0
-      file-loader: 6.2.0_webpack@4.46.0
-      find-up: 5.0.0
-      fork-ts-checker-webpack-plugin: 4.1.6_bbqhrndznz6a4k7d23h2kkrexi
-      glob: 7.2.3
-      glob-promise: 3.4.0_glob@7.2.3
-      global: 4.4.0
-      html-webpack-plugin: 4.5.2_webpack@4.46.0
-      pnp-webpack-plugin: 1.6.4_typescript@4.4.4
-      postcss: 7.0.39
-      postcss-flexbugs-fixes: 4.2.1
-      postcss-loader: 4.3.0_gzaxsinx64nntyd3vmdqwl7coe
-      raw-loader: 4.0.2_webpack@4.46.0
-      react: 16.14.0
-      react-dom: 16.14.0_react@16.14.0
-      stable: 0.1.8
-      style-loader: 1.3.0_webpack@4.46.0
-      terser-webpack-plugin: 4.2.3_webpack@4.46.0
-      ts-dedent: 2.2.0
-      typescript: 4.4.4
-      url-loader: 4.1.1_lit45vopotvaqup7lrvlnvtxwy
-      util-deprecate: 1.0.2
-      webpack: 4.46.0
-      webpack-dev-middleware: 3.7.3_webpack@4.46.0
-      webpack-filter-warnings-plugin: 1.2.1_webpack@4.46.0
-      webpack-hot-middleware: 2.25.2
-      webpack-virtual-modules: 0.2.2
-    transitivePeerDependencies:
-      - bluebird
-      - eslint
-      - supports-color
-      - vue-template-compiler
-      - webpack-cli
-      - webpack-command
-    dev: true
-
   /@storybook/builder-webpack4/6.5.13_u5cwnb36e3nipolzgtjnnpepdu:
     resolution: {integrity: 
sha512-Agqy3IKPv3Nl8QqdS7PjtqLp+c0BD8+/3A2ki/YfKqVz+F+J34EpbZlh3uU053avm1EoNQHSmhZok3ZlWH6O7A==}
     peerDependencies:
@@ -5567,80 +5514,6 @@ packages:
       util-deprecate: 1.0.2
     dev: true
 
-  /@storybook/core-client/6.5.13_4z4xstjutcmkuoh5zkinl7lmym:
-    resolution: {integrity: 
sha512-YuELbRokTBdqjbx/R4/7O4rou9kvbBIOJjlUkor9hdLLuJ3P0yGianERGNkZFfvcfMBAxU0p52o7QvDldSR3kA==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      typescript: '*'
-      webpack: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/channel-postmessage': 6.5.13
-      '@storybook/channel-websocket': 6.5.13
-      '@storybook/client-api': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/client-logger': 6.5.13
-      '@storybook/core-events': 6.5.13
-      '@storybook/csf': 0.0.2--canary.4566f4d.1
-      '@storybook/preview-web': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/ui': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      airbnb-js-shims: 2.2.1
-      ansi-to-html: 0.6.15
-      core-js: 3.26.0
-      global: 4.4.0
-      lodash: 4.17.21
-      qs: 6.11.0
-      react: 16.14.0
-      react-dom: 16.14.0_react@16.14.0
-      regenerator-runtime: 0.13.10
-      ts-dedent: 2.2.0
-      typescript: 4.4.4
-      unfetch: 4.2.0
-      util-deprecate: 1.0.2
-      webpack: 5.74.0
-    dev: true
-
-  /@storybook/core-client/6.5.13_6dhvdvok4rm6xhvn3ntojenmae:
-    resolution: {integrity: 
sha512-YuELbRokTBdqjbx/R4/7O4rou9kvbBIOJjlUkor9hdLLuJ3P0yGianERGNkZFfvcfMBAxU0p52o7QvDldSR3kA==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      typescript: '*'
-      webpack: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/channel-postmessage': 6.5.13
-      '@storybook/channel-websocket': 6.5.13
-      '@storybook/client-api': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/client-logger': 6.5.13
-      '@storybook/core-events': 6.5.13
-      '@storybook/csf': 0.0.2--canary.4566f4d.1
-      '@storybook/preview-web': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/ui': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      airbnb-js-shims: 2.2.1
-      ansi-to-html: 0.6.15
-      core-js: 3.26.0
-      global: 4.4.0
-      lodash: 4.17.21
-      qs: 6.11.0
-      react: 16.14.0
-      react-dom: 16.14.0_react@16.14.0
-      regenerator-runtime: 0.13.10
-      ts-dedent: 2.2.0
-      typescript: 4.4.4
-      unfetch: 4.2.0
-      util-deprecate: 1.0.2
-      webpack: 4.46.0
-    dev: true
-
   /@storybook/core-client/6.5.13_plmdyubmb7xm6euvqu3qohl7ea:
     resolution: {integrity: 
sha512-YuELbRokTBdqjbx/R4/7O4rou9kvbBIOJjlUkor9hdLLuJ3P0yGianERGNkZFfvcfMBAxU0p52o7QvDldSR3kA==}
     peerDependencies:
@@ -5784,7 +5657,7 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/core-common/6.5.13_ipjevasairp6knvwkrpikcsgoq:
+  /@storybook/core-common/6.5.13_j3fy4dsuv6tweqy6dixwnav3v4:
     resolution: {integrity: 
sha512-+DVZrRsteE9pw0X5MNffkdBgejQnbnL+UOG3qXkE9xxUamQALnuqS/w1BzpHE9WmOHuf7RWMKflyQEW3OLKAJg==}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -5828,7 +5701,7 @@ packages:
       express: 4.18.2
       file-system-cache: 1.1.0
       find-up: 5.0.0
-      fork-ts-checker-webpack-plugin: 6.5.2_bbqhrndznz6a4k7d23h2kkrexi
+      fork-ts-checker-webpack-plugin: 6.5.2_3n2x3j6farblcaf52bherr6og4
       fs-extra: 9.1.0
       glob: 7.2.3
       handlebars: 4.7.7
@@ -5843,7 +5716,7 @@ packages:
       slash: 3.0.0
       telejson: 6.0.8
       ts-dedent: 2.2.0
-      typescript: 4.4.4
+      typescript: 4.8.4
       util-deprecate: 1.0.2
       webpack: 4.46.0
     transitivePeerDependencies:
@@ -5854,7 +5727,7 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/core-common/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y:
+  /@storybook/core-common/6.5.13_u5cwnb36e3nipolzgtjnnpepdu:
     resolution: {integrity: 
sha512-+DVZrRsteE9pw0X5MNffkdBgejQnbnL+UOG3qXkE9xxUamQALnuqS/w1BzpHE9WmOHuf7RWMKflyQEW3OLKAJg==}
     peerDependencies:
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -5898,7 +5771,7 @@ packages:
       express: 4.18.2
       file-system-cache: 1.1.0
       find-up: 5.0.0
-      fork-ts-checker-webpack-plugin: 6.5.2_bbqhrndznz6a4k7d23h2kkrexi
+      fork-ts-checker-webpack-plugin: 6.5.2_3n2x3j6farblcaf52bherr6og4
       fs-extra: 9.1.0
       glob: 7.2.3
       handlebars: 4.7.7
@@ -5914,7 +5787,7 @@ packages:
       slash: 3.0.0
       telejson: 6.0.8
       ts-dedent: 2.2.0
-      typescript: 4.4.4
+      typescript: 4.8.4
       util-deprecate: 1.0.2
       webpack: 4.46.0
     transitivePeerDependencies:
@@ -5925,173 +5798,25 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/core-common/6.5.13_u5cwnb36e3nipolzgtjnnpepdu:
-    resolution: {integrity: 
sha512-+DVZrRsteE9pw0X5MNffkdBgejQnbnL+UOG3qXkE9xxUamQALnuqS/w1BzpHE9WmOHuf7RWMKflyQEW3OLKAJg==}
+  /@storybook/core-events/6.5.13:
+    resolution: {integrity: 
sha512-kL745tPpRKejzHToA3/CoBNbI+NPRVk186vGxXBmk95OEg0TlwgQExP8BnqEtLlRZMbW08e4+6kilc1M1M4N5w==}
+    dependencies:
+      core-js: 3.26.0
+    dev: true
+
+  /@storybook/core-server/6.5.13_u5cwnb36e3nipolzgtjnnpepdu:
+    resolution: {integrity: 
sha512-vs7tu3kAnFwuINio1p87WyqDNlFyZESmeh9s7vvrZVbe/xS/ElqDscr9DT5seW+jbtxufAaHsx+JUTver1dheQ==}
     peerDependencies:
+      '@storybook/builder-webpack5': '*'
+      '@storybook/manager-webpack5': '*'
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
       react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
       typescript: '*'
     peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@babel/core': 7.18.9
-      '@babel/plugin-proposal-class-properties': 7.18.6_@babel+core@7.18.9
-      '@babel/plugin-proposal-decorators': 7.19.6_@babel+core@7.18.9
-      '@babel/plugin-proposal-export-default-from': 7.18.10_@babel+core@7.18.9
-      '@babel/plugin-proposal-nullish-coalescing-operator': 
7.18.6_@babel+core@7.18.9
-      '@babel/plugin-proposal-object-rest-spread': 7.19.4_@babel+core@7.18.9
-      '@babel/plugin-proposal-optional-chaining': 7.18.9_@babel+core@7.18.9
-      '@babel/plugin-proposal-private-methods': 7.18.6_@babel+core@7.18.9
-      '@babel/plugin-proposal-private-property-in-object': 
7.18.6_@babel+core@7.18.9
-      '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.18.9
-      '@babel/plugin-transform-arrow-functions': 7.18.6_@babel+core@7.18.9
-      '@babel/plugin-transform-block-scoping': 7.19.4_@babel+core@7.18.9
-      '@babel/plugin-transform-classes': 7.19.0_@babel+core@7.18.9
-      '@babel/plugin-transform-destructuring': 7.19.4_@babel+core@7.18.9
-      '@babel/plugin-transform-for-of': 7.18.8_@babel+core@7.18.9
-      '@babel/plugin-transform-parameters': 7.18.8_@babel+core@7.18.9
-      '@babel/plugin-transform-shorthand-properties': 7.18.6_@babel+core@7.18.9
-      '@babel/plugin-transform-spread': 7.19.0_@babel+core@7.18.9
-      '@babel/preset-env': 7.19.4_@babel+core@7.18.9
-      '@babel/preset-react': 7.18.6_@babel+core@7.18.9
-      '@babel/preset-typescript': 7.18.6_@babel+core@7.18.9
-      '@babel/register': 7.18.9_@babel+core@7.18.9
-      '@storybook/node-logger': 6.5.13
-      '@storybook/semver': 7.3.2
-      '@types/node': 16.18.0
-      '@types/pretty-hrtime': 1.0.1
-      babel-loader: 8.2.5_7uc2ny5pnz7ums2wq2q562bf6y
-      babel-plugin-macros: 3.1.0
-      babel-plugin-polyfill-corejs3: 0.1.7_@babel+core@7.18.9
-      chalk: 4.1.2
-      core-js: 3.26.0
-      express: 4.18.2
-      file-system-cache: 1.1.0
-      find-up: 5.0.0
-      fork-ts-checker-webpack-plugin: 6.5.2_3n2x3j6farblcaf52bherr6og4
-      fs-extra: 9.1.0
-      glob: 7.2.3
-      handlebars: 4.7.7
-      interpret: 2.2.0
-      json5: 2.2.1
-      lazy-universal-dotenv: 3.0.1
-      picomatch: 2.3.1
-      pkg-dir: 5.0.0
-      pretty-hrtime: 1.0.3
-      react: 16.14.0
-      react-dom: 16.14.0_react@16.14.0
-      resolve-from: 5.0.0
-      slash: 3.0.0
-      telejson: 6.0.8
-      ts-dedent: 2.2.0
-      typescript: 4.8.4
-      util-deprecate: 1.0.2
-      webpack: 4.46.0
-    transitivePeerDependencies:
-      - eslint
-      - supports-color
-      - vue-template-compiler
-      - webpack-cli
-      - webpack-command
-    dev: true
-
-  /@storybook/core-events/6.5.13:
-    resolution: {integrity: 
sha512-kL745tPpRKejzHToA3/CoBNbI+NPRVk186vGxXBmk95OEg0TlwgQExP8BnqEtLlRZMbW08e4+6kilc1M1M4N5w==}
-    dependencies:
-      core-js: 3.26.0
-    dev: true
-
-  /@storybook/core-server/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y:
-    resolution: {integrity: 
sha512-vs7tu3kAnFwuINio1p87WyqDNlFyZESmeh9s7vvrZVbe/xS/ElqDscr9DT5seW+jbtxufAaHsx+JUTver1dheQ==}
-    peerDependencies:
-      '@storybook/builder-webpack5': '*'
-      '@storybook/manager-webpack5': '*'
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      '@storybook/builder-webpack5':
-        optional: true
-      '@storybook/manager-webpack5':
-        optional: true
-      typescript:
-        optional: true
-    dependencies:
-      '@discoveryjs/json-ext': 0.5.7
-      '@storybook/builder-webpack4': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
-      '@storybook/core-client': 6.5.13_6dhvdvok4rm6xhvn3ntojenmae
-      '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
-      '@storybook/core-events': 6.5.13
-      '@storybook/csf': 0.0.2--canary.4566f4d.1
-      '@storybook/csf-tools': 6.5.13
-      '@storybook/manager-webpack4': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
-      '@storybook/node-logger': 6.5.13
-      '@storybook/semver': 7.3.2
-      '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/telemetry': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
-      '@types/node': 16.18.0
-      '@types/node-fetch': 2.6.2
-      '@types/pretty-hrtime': 1.0.1
-      '@types/webpack': 4.41.33
-      better-opn: 2.1.1
-      boxen: 5.1.2
-      chalk: 4.1.2
-      cli-table3: 0.6.3
-      commander: 6.2.1
-      compression: 1.7.4
-      core-js: 3.26.0
-      cpy: 8.1.2
-      detect-port: 1.5.1
-      express: 4.18.2
-      fs-extra: 9.1.0
-      global: 4.4.0
-      globby: 11.1.0
-      ip: 2.0.0
-      lodash: 4.17.21
-      node-fetch: 2.6.7
-      open: 8.4.0
-      pretty-hrtime: 1.0.3
-      prompts: 2.4.2
-      react: 16.14.0
-      react-dom: 16.14.0_react@16.14.0
-      regenerator-runtime: 0.13.10
-      serve-favicon: 2.5.0
-      slash: 3.0.0
-      telejson: 6.0.8
-      ts-dedent: 2.2.0
-      typescript: 4.4.4
-      util-deprecate: 1.0.2
-      watchpack: 2.4.0
-      webpack: 4.46.0
-      ws: 8.10.0
-      x-default-browser: 0.4.0
-    transitivePeerDependencies:
-      - '@storybook/mdx2-csf'
-      - bluebird
-      - bufferutil
-      - encoding
-      - eslint
-      - supports-color
-      - utf-8-validate
-      - vue-template-compiler
-      - webpack-cli
-      - webpack-command
-    dev: true
-
-  /@storybook/core-server/6.5.13_u5cwnb36e3nipolzgtjnnpepdu:
-    resolution: {integrity: 
sha512-vs7tu3kAnFwuINio1p87WyqDNlFyZESmeh9s7vvrZVbe/xS/ElqDscr9DT5seW+jbtxufAaHsx+JUTver1dheQ==}
-    peerDependencies:
-      '@storybook/builder-webpack5': '*'
-      '@storybook/manager-webpack5': '*'
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      '@storybook/builder-webpack5':
-        optional: true
-      '@storybook/manager-webpack5':
-        optional: true
+      '@storybook/builder-webpack5':
+        optional: true
+      '@storybook/manager-webpack5':
+        optional: true
       typescript:
         optional: true
     dependencies:
@@ -6192,42 +5917,6 @@ packages:
       - webpack-command
     dev: true
 
-  /@storybook/core/6.5.13_ujfskrypehrywuobbsgnsb3724:
-    resolution: {integrity: 
sha512-kw1lCgbsxzUimGww6t5rmuWJmFPe9kGGyzIqvj4RC4BBcEsP40LEu9XhSfvnb8vTOLIULFZeZpdRFfJs4TYbUw==}
-    peerDependencies:
-      '@storybook/builder-webpack5': '*'
-      '@storybook/manager-webpack5': '*'
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      typescript: '*'
-      webpack: '*'
-    peerDependenciesMeta:
-      '@storybook/builder-webpack5':
-        optional: true
-      '@storybook/manager-webpack5':
-        optional: true
-      typescript:
-        optional: true
-    dependencies:
-      '@storybook/core-client': 6.5.13_4z4xstjutcmkuoh5zkinl7lmym
-      '@storybook/core-server': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
-      react: 16.14.0
-      react-dom: 16.14.0_react@16.14.0
-      typescript: 4.4.4
-      webpack: 5.74.0
-    transitivePeerDependencies:
-      - '@storybook/mdx2-csf'
-      - bluebird
-      - bufferutil
-      - encoding
-      - eslint
-      - supports-color
-      - utf-8-validate
-      - vue-template-compiler
-      - webpack-cli
-      - webpack-command
-    dev: true
-
   /@storybook/csf-tools/6.5.13:
     resolution: {integrity: 
sha512-63Ev+VmBqzwSwfUzbuXOLKBD5dMTK2zBYLQ9anTVw70FuTikwTsGIbPgb098K0vsxRCgxl7KM7NpivHqtZtdjw==}
     peerDependencies:
@@ -6292,64 +5981,6 @@ packages:
       - supports-color
     dev: true
 
-  /@storybook/manager-webpack4/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y:
-    resolution: {integrity: 
sha512-pURzS5W3XM0F7bCBWzpl7TRsuy+OXFwLXiWLaexuvo0POZe31Ueo2A1R4rx3MT5Iee8O9mYvG2XTmvK9MlLefQ==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@babel/core': 7.18.9
-      '@babel/plugin-transform-template-literals': 7.18.9_@babel+core@7.18.9
-      '@babel/preset-react': 7.18.6_@babel+core@7.18.9
-      '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/core-client': 6.5.13_6dhvdvok4rm6xhvn3ntojenmae
-      '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
-      '@storybook/node-logger': 6.5.13
-      '@storybook/theming': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/ui': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@types/node': 16.18.0
-      '@types/webpack': 4.41.33
-      babel-loader: 8.2.5_7uc2ny5pnz7ums2wq2q562bf6y
-      case-sensitive-paths-webpack-plugin: 2.4.0
-      chalk: 4.1.2
-      core-js: 3.26.0
-      css-loader: 3.6.0_webpack@4.46.0
-      express: 4.18.2
-      file-loader: 6.2.0_webpack@4.46.0
-      find-up: 5.0.0
-      fs-extra: 9.1.0
-      html-webpack-plugin: 4.5.2_webpack@4.46.0
-      node-fetch: 2.6.7
-      pnp-webpack-plugin: 1.6.4_typescript@4.4.4
-      react: 16.14.0
-      react-dom: 16.14.0_react@16.14.0
-      read-pkg-up: 7.0.1
-      regenerator-runtime: 0.13.10
-      resolve-from: 5.0.0
-      style-loader: 1.3.0_webpack@4.46.0
-      telejson: 6.0.8
-      terser-webpack-plugin: 4.2.3_webpack@4.46.0
-      ts-dedent: 2.2.0
-      typescript: 4.4.4
-      url-loader: 4.1.1_lit45vopotvaqup7lrvlnvtxwy
-      util-deprecate: 1.0.2
-      webpack: 4.46.0
-      webpack-dev-middleware: 3.7.3_webpack@4.46.0
-      webpack-virtual-modules: 0.2.2
-    transitivePeerDependencies:
-      - bluebird
-      - encoding
-      - eslint
-      - supports-color
-      - vue-template-compiler
-      - webpack-cli
-      - webpack-command
-    dev: true
-
   /@storybook/manager-webpack4/6.5.13_u5cwnb36e3nipolzgtjnnpepdu:
     resolution: {integrity: 
sha512-pURzS5W3XM0F7bCBWzpl7TRsuy+OXFwLXiWLaexuvo0POZe31Ueo2A1R4rx3MT5Iee8O9mYvG2XTmvK9MlLefQ==}
     peerDependencies:
@@ -6443,7 +6074,7 @@ packages:
       core-js: 3.26.0
     dev: true
 
-  /@storybook/preact/6.5.13_q57tjbu375p52k2lkxkownwouu:
+  /@storybook/preact/6.5.13_xa5zyoe4qu34opzfrw5imxak3u:
     resolution: {integrity: 
sha512-5/ufRgxh5VypFcOeIBQMg/AqZQ2+KfUw4Glo9HU75dbIe/kYqSnN3+5SEv8J6ykxHHtUWcmnILS1r7/I5R7j/w==}
     engines: {node: '>=10.13.0'}
     hasBin: true
@@ -6454,8 +6085,8 @@ packages:
       '@babel/core': 7.18.9
       '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.18.9
       '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
-      '@storybook/core': 6.5.13_ujfskrypehrywuobbsgnsb3724
-      '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
+      '@storybook/core': 6.5.13_cadditq4xyv3neitvabz3hzhjy
+      '@storybook/core-common': 6.5.13_u5cwnb36e3nipolzgtjnnpepdu
       '@storybook/csf': 0.0.2--canary.4566f4d.1
       '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty
       '@types/node': 16.18.0
@@ -6778,33 +6409,6 @@ packages:
       util-deprecate: 1.0.2
     dev: true
 
-  /@storybook/telemetry/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y:
-    resolution: {integrity: 
sha512-PFJEfGbunmfFWabD3rdCF8EHH+45578OHOkMPpXJjqXl94vPQxUH2XTVKQgEQJbYrgX0Vx9Z4tSkdMHuzYDbWQ==}
-    dependencies:
-      '@storybook/client-logger': 6.5.13
-      '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y
-      chalk: 4.1.2
-      core-js: 3.26.0
-      detect-package-manager: 2.0.1
-      fetch-retry: 5.0.3
-      fs-extra: 9.1.0
-      global: 4.4.0
-      isomorphic-unfetch: 3.1.0
-      nanoid: 3.3.4
-      read-pkg-up: 7.0.1
-      regenerator-runtime: 0.13.10
-    transitivePeerDependencies:
-      - encoding
-      - eslint
-      - react
-      - react-dom
-      - supports-color
-      - typescript
-      - vue-template-compiler
-      - webpack-cli
-      - webpack-command
-    dev: true
-
   /@storybook/telemetry/6.5.13_u5cwnb36e3nipolzgtjnnpepdu:
     resolution: {integrity: 
sha512-PFJEfGbunmfFWabD3rdCF8EHH+45578OHOkMPpXJjqXl94vPQxUH2XTVKQgEQJbYrgX0Vx9Z4tSkdMHuzYDbWQ==}
     dependencies:
@@ -7212,6 +6816,10 @@ packages:
     resolution: {integrity: 
sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
     dev: true
 
+  /@types/mocha/10.0.1:
+    resolution: {integrity: 
sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==}
+    dev: true
+
   /@types/mocha/8.2.3:
     resolution: {integrity: 
sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==}
     dev: true
@@ -7235,6 +6843,10 @@ packages:
     resolution: {integrity: 
sha512-LqYqYzYvnbCaQfLAwRt0zboqnsViwhZm+vjaMSqcfN36vulAg7Pt0T83q4WZO2YOBw3XdyHi8cQ88H22zmULOA==}
     dev: true
 
+  /@types/node/18.11.14:
+    resolution: {integrity: 
sha512-0KXV57tENYmmJMl+FekeW9V3O/rlcqGQQJ/hNh9r8pKIj304pskWuEd8fCyNT86g/TpO0gcOTiLzsHLEURFMIQ==}
+    dev: true
+
   /@types/node/18.11.5:
     resolution: {integrity: 
sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==}
 
@@ -7423,34 +7035,8 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/experimental-utils': 
4.33.0_3rubbgt5ekhqrcgx4uwls3neim
-      '@typescript-eslint/parser': 4.33.0_3rubbgt5ekhqrcgx4uwls3neim
-      '@typescript-eslint/scope-manager': 4.33.0
-      debug: 4.3.4
-      eslint: 7.32.0
-      functional-red-black-tree: 1.0.1
-      ignore: 5.2.0
-      regexpp: 3.2.0
-      semver: 7.3.8
-      tsutils: 3.21.0_typescript@4.8.4
-      typescript: 4.8.4
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
-  /@typescript-eslint/eslint-plugin/4.33.0_zrqxgwgitu7trrjeml3nqco3jq:
-    resolution: {integrity: 
sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==}
-    engines: {node: ^10.12.0 || >=12.0.0}
-    peerDependencies:
-      '@typescript-eslint/parser': ^4.0.0
-      eslint: ^5.0.0 || ^6.0.0 || ^7.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/experimental-utils': 
4.33.0_wnilx7boviscikmvsfkd6ljepe
-      '@typescript-eslint/parser': 4.33.0_wnilx7boviscikmvsfkd6ljepe
+      '@typescript-eslint/experimental-utils': 
4.33.0_3rubbgt5ekhqrcgx4uwls3neim
+      '@typescript-eslint/parser': 4.33.0_3rubbgt5ekhqrcgx4uwls3neim
       '@typescript-eslint/scope-manager': 4.33.0
       debug: 4.3.4
       eslint: 7.32.0
@@ -7458,8 +7044,8 @@ packages:
       ignore: 5.2.0
       regexpp: 3.2.0
       semver: 7.3.8
-      tsutils: 3.21.0_typescript@4.4.4
-      typescript: 4.4.4
+      tsutils: 3.21.0_typescript@4.8.4
+      typescript: 4.8.4
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -7533,24 +7119,6 @@ packages:
       - typescript
     dev: true
 
-  /@typescript-eslint/experimental-utils/4.33.0_wnilx7boviscikmvsfkd6ljepe:
-    resolution: {integrity: 
sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==}
-    engines: {node: ^10.12.0 || >=12.0.0}
-    peerDependencies:
-      eslint: '*'
-    dependencies:
-      '@types/json-schema': 7.0.11
-      '@typescript-eslint/scope-manager': 4.33.0
-      '@typescript-eslint/types': 4.33.0
-      '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.4.4
-      eslint: 7.32.0
-      eslint-scope: 5.1.1
-      eslint-utils: 3.0.0_eslint@7.32.0
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-    dev: true
-
   /@typescript-eslint/experimental-utils/5.41.0_3rubbgt5ekhqrcgx4uwls3neim:
     resolution: {integrity: 
sha512-/qxT2Kd2q/A22JVIllvws4rvc00/3AT4rAo/0YgEN28y+HPhbJbk6X4+MAHEoZzpNyAOugIT7D/OLnKBW8FfhA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -7576,19 +7144,6 @@ packages:
       - typescript
     dev: true
 
-  /@typescript-eslint/experimental-utils/5.41.0_wnilx7boviscikmvsfkd6ljepe:
-    resolution: {integrity: 
sha512-/qxT2Kd2q/A22JVIllvws4rvc00/3AT4rAo/0YgEN28y+HPhbJbk6X4+MAHEoZzpNyAOugIT7D/OLnKBW8FfhA==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    peerDependencies:
-      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
-    dependencies:
-      '@typescript-eslint/utils': 5.41.0_wnilx7boviscikmvsfkd6ljepe
-      eslint: 7.32.0
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-    dev: true
-
   /@typescript-eslint/parser/4.33.0_3rubbgt5ekhqrcgx4uwls3neim:
     resolution: {integrity: 
sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==}
     engines: {node: ^10.12.0 || >=12.0.0}
@@ -7609,26 +7164,6 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/parser/4.33.0_wnilx7boviscikmvsfkd6ljepe:
-    resolution: {integrity: 
sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==}
-    engines: {node: ^10.12.0 || >=12.0.0}
-    peerDependencies:
-      eslint: ^5.0.0 || ^6.0.0 || ^7.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/scope-manager': 4.33.0
-      '@typescript-eslint/types': 4.33.0
-      '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.4.4
-      debug: 4.3.4
-      eslint: 7.32.0
-      typescript: 4.4.4
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/parser/5.41.0_typescript@4.8.4:
     resolution: {integrity: 
sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -7733,27 +7268,6 @@ packages:
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dev: true
 
-  /@typescript-eslint/typescript-estree/4.33.0_typescript@4.4.4:
-    resolution: {integrity: 
sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==}
-    engines: {node: ^10.12.0 || >=12.0.0}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/types': 4.33.0
-      '@typescript-eslint/visitor-keys': 4.33.0
-      debug: 4.3.4
-      globby: 11.1.0
-      is-glob: 4.0.3
-      semver: 7.3.8
-      tsutils: 3.21.0_typescript@4.4.4
-      typescript: 4.4.4
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/typescript-estree/4.33.0_typescript@4.8.4:
     resolution: {integrity: 
sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==}
     engines: {node: ^10.12.0 || >=12.0.0}
@@ -7775,27 +7289,6 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/typescript-estree/5.41.0_typescript@4.4.4:
-    resolution: {integrity: 
sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/types': 5.41.0
-      '@typescript-eslint/visitor-keys': 5.41.0
-      debug: 4.3.4
-      globby: 11.1.0
-      is-glob: 4.0.3
-      semver: 7.3.8
-      tsutils: 3.21.0_typescript@4.4.4
-      typescript: 4.4.4
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/typescript-estree/5.41.0_typescript@4.8.4:
     resolution: {integrity: 
sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -7856,26 +7349,6 @@ packages:
       - typescript
     dev: true
 
-  /@typescript-eslint/utils/5.41.0_wnilx7boviscikmvsfkd6ljepe:
-    resolution: {integrity: 
sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==}
-    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
-    peerDependencies:
-      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
-    dependencies:
-      '@types/json-schema': 7.0.11
-      '@types/semver': 7.3.12
-      '@typescript-eslint/scope-manager': 5.41.0
-      '@typescript-eslint/types': 5.41.0
-      '@typescript-eslint/typescript-estree': 5.41.0_typescript@4.4.4
-      eslint: 7.32.0
-      eslint-scope: 5.1.1
-      eslint-utils: 3.0.0_eslint@7.32.0
-      semver: 7.3.8
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-    dev: true
-
   /@typescript-eslint/utils/5.41.0_wyqvi574yv7oiwfeinomdzmc3m:
     resolution: {integrity: 
sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -8715,6 +8188,10 @@ packages:
     resolution: {integrity: 
sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
     dev: true
 
+  /async_hooks/1.0.0:
+    resolution: {integrity: 
sha512-t4BSJgx48V3e7U6Ll3/WOUNmxIRPzmPdxVfgbyzcnRItEnn4iKp4F//b0sV3L9hzbdr5qxWdNWzOF7t+rjYSfA==}
+    dev: true
+
   /asynckit/0.4.0:
     resolution: {integrity: 
sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
 
@@ -8916,6 +8393,16 @@ packages:
       - debug
     dev: true
 
+  /axios/1.2.1:
+    resolution: {integrity: 
sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==}
+    dependencies:
+      follow-redirects: 1.15.2
+      form-data: 4.0.0
+      proxy-from-env: 1.1.0
+    transitivePeerDependencies:
+      - debug
+    dev: true
+
   /axobject-query/2.2.0:
     resolution: {integrity: 
sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==}
     dev: true
@@ -12488,28 +11975,6 @@ packages:
       eslint-plugin-import: 2.26.0_c2flhriocdzler6lrwbyxxyoca
     dev: true
 
-  /eslint-config-preact/1.3.0_55vw575o5aj4h37h7cossdtfje:
-    resolution: {integrity: 
sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==}
-    peerDependencies:
-      eslint: 6.x || 7.x || 8.x
-    dependencies:
-      '@babel/core': 7.18.9
-      '@babel/eslint-parser': 7.19.1_o5peei4wpze5egwf42u76kwdva
-      '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.18.9
-      '@babel/plugin-syntax-decorators': 7.19.0_@babel+core@7.18.9
-      '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.18.9
-      eslint: 7.32.0
-      eslint-plugin-compat: 4.0.2_eslint@7.32.0
-      eslint-plugin-jest: 25.7.0_55vw575o5aj4h37h7cossdtfje
-      eslint-plugin-react: 7.31.10_eslint@7.32.0
-      eslint-plugin-react-hooks: 4.6.0_eslint@7.32.0
-    transitivePeerDependencies:
-      - '@typescript-eslint/eslint-plugin'
-      - jest
-      - supports-color
-      - typescript
-    dev: true
-
   /eslint-config-preact/1.3.0_nxlzr75jbqkso2fds5zjovs2ii:
     resolution: {integrity: 
sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==}
     peerDependencies:
@@ -12672,28 +12137,6 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-plugin-jest/25.7.0_55vw575o5aj4h37h7cossdtfje:
-    resolution: {integrity: 
sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    peerDependencies:
-      '@typescript-eslint/eslint-plugin': ^4.0.0 || ^5.0.0
-      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
-      jest: '*'
-    peerDependenciesMeta:
-      '@typescript-eslint/eslint-plugin':
-        optional: true
-      jest:
-        optional: true
-    dependencies:
-      '@typescript-eslint/eslint-plugin': 4.33.0_zrqxgwgitu7trrjeml3nqco3jq
-      '@typescript-eslint/experimental-utils': 
5.41.0_wnilx7boviscikmvsfkd6ljepe
-      eslint: 7.32.0
-      jest: 26.6.3
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-    dev: true
-
   /eslint-plugin-jest/25.7.0_nxlzr75jbqkso2fds5zjovs2ii:
     resolution: {integrity: 
sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==}
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
@@ -13661,34 +13104,6 @@ packages:
       - supports-color
     dev: true
 
-  /fork-ts-checker-webpack-plugin/4.1.6_bbqhrndznz6a4k7d23h2kkrexi:
-    resolution: {integrity: 
sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==}
-    engines: {node: '>=6.11.5', yarn: '>=1.0.0'}
-    peerDependencies:
-      eslint: '>= 6'
-      typescript: '>= 2.7'
-      vue-template-compiler: '*'
-      webpack: '>= 4'
-    peerDependenciesMeta:
-      eslint:
-        optional: true
-      vue-template-compiler:
-        optional: true
-    dependencies:
-      '@babel/code-frame': 7.18.6
-      chalk: 2.4.2
-      eslint: 7.32.0
-      micromatch: 3.1.10
-      minimatch: 3.1.2
-      semver: 5.7.1
-      tapable: 1.1.3
-      typescript: 4.4.4
-      webpack: 4.46.0
-      worker-rpc: 0.1.1
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /fork-ts-checker-webpack-plugin/4.1.6_gplzhsecki363wzvnzp4wfrwvi:
     resolution: {integrity: 
sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==}
     engines: {node: '>=6.11.5', yarn: '>=1.0.0'}
@@ -13776,38 +13191,6 @@ packages:
       webpack: 4.46.0
     dev: true
 
-  /fork-ts-checker-webpack-plugin/6.5.2_bbqhrndznz6a4k7d23h2kkrexi:
-    resolution: {integrity: 
sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==}
-    engines: {node: '>=10', yarn: '>=1.0.0'}
-    peerDependencies:
-      eslint: '>= 6'
-      typescript: '>= 2.7'
-      vue-template-compiler: '*'
-      webpack: '>= 4'
-    peerDependenciesMeta:
-      eslint:
-        optional: true
-      vue-template-compiler:
-        optional: true
-    dependencies:
-      '@babel/code-frame': 7.18.6
-      '@types/json-schema': 7.0.11
-      chalk: 4.1.2
-      chokidar: 3.5.3
-      cosmiconfig: 6.0.0
-      deepmerge: 4.2.2
-      eslint: 7.32.0
-      fs-extra: 9.1.0
-      glob: 7.2.3
-      memfs: 3.4.7
-      minimatch: 3.1.2
-      schema-utils: 2.7.0
-      semver: 7.3.8
-      tapable: 1.1.3
-      typescript: 4.4.4
-      webpack: 4.46.0
-    dev: true
-
   /form-data/2.3.3:
     resolution: {integrity: 
sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
     engines: {node: '>= 0.12'}
@@ -18326,15 +17709,6 @@ packages:
     resolution: {integrity: 
sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==}
     dev: true
 
-  /pnp-webpack-plugin/1.6.4_typescript@4.4.4:
-    resolution: {integrity: 
sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==}
-    engines: {node: '>=6'}
-    dependencies:
-      ts-pnp: 1.2.0_typescript@4.4.4
-    transitivePeerDependencies:
-      - typescript
-    dev: true
-
   /pnp-webpack-plugin/1.6.4_typescript@4.8.4:
     resolution: {integrity: 
sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==}
     engines: {node: '>=6'}
@@ -21626,7 +21000,6 @@ packages:
     resolution: {integrity: 
sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==}
     peerDependencies:
       react: ^16.11.0 || ^17.0.0 || ^18.0.0
-    dev: false
 
   /swr/1.3.0_@preact+compat@17.1.2:
     resolution: {integrity: 
sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==}
@@ -22041,18 +21414,6 @@ packages:
       tslib: 2.4.1
     dev: true
 
-  /ts-pnp/1.2.0_typescript@4.4.4:
-    resolution: {integrity: 
sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
-    engines: {node: '>=6'}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      typescript: 4.4.4
-    dev: true
-
   /ts-pnp/1.2.0_typescript@4.6.4:
     resolution: {integrity: 
sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
     engines: {node: '>=6'}
@@ -22085,16 +21446,6 @@ packages:
     resolution: {integrity: 
sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
     dev: true
 
-  /tsutils/3.21.0_typescript@4.4.4:
-    resolution: {integrity: 
sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
-    engines: {node: '>= 6'}
-    peerDependencies:
-      typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || 
>= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
-    dependencies:
-      tslib: 1.14.1
-      typescript: 4.4.4
-    dev: true
-
   /tsutils/3.21.0_typescript@4.8.4:
     resolution: {integrity: 
sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
     engines: {node: '>= 6'}
@@ -22190,27 +21541,6 @@ packages:
     engines: {node: '>= 8'}
     dev: true
 
-  /typedoc/0.20.37_typescript@4.4.4:
-    resolution: {integrity: 
sha512-9+qDhdc4X00qTNOtii6QX2z7ndAeWVOso7w3MPSoSJdXlVhpwPfm1yEp4ooKuWA9fiQILR8FKkyjmeqa13hBbw==}
-    engines: {node: '>= 10.8.0'}
-    hasBin: true
-    peerDependencies:
-      typescript: 3.9.x || 4.0.x || 4.1.x || 4.2.x
-    dependencies:
-      colors: 1.4.0
-      fs-extra: 9.1.0
-      handlebars: 4.7.7
-      lodash: 4.17.21
-      lunr: 2.3.9
-      marked: 2.0.7
-      minimatch: 3.1.2
-      progress: 2.0.3
-      shelljs: 0.8.5
-      shiki: 0.9.15
-      typedoc-default-themes: 0.12.10
-      typescript: 4.4.4
-    dev: true
-
   /typedoc/0.20.37_typescript@4.8.4:
     resolution: {integrity: 
sha512-9+qDhdc4X00qTNOtii6QX2z7ndAeWVOso7w3MPSoSJdXlVhpwPfm1yEp4ooKuWA9fiQILR8FKkyjmeqa13hBbw==}
     engines: {node: '>= 10.8.0'}
@@ -22246,12 +21576,6 @@ packages:
       typescript: 4.8.4
     dev: true
 
-  /typescript/4.4.4:
-    resolution: {integrity: 
sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==}
-    engines: {node: '>=4.2.0'}
-    hasBin: true
-    dev: true
-
   /typescript/4.6.4:
     resolution: {integrity: 
sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==}
     engines: {node: '>=4.2.0'}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]