gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (cb2f4c21d -> a906263f7)


From: gnunet
Subject: [taler-wallet-core] branch master updated (cb2f4c21d -> a906263f7)
Date: Thu, 16 Feb 2023 03:24:22 +0100

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

dold pushed a change to branch master
in repository wallet-core.

    from cb2f4c21d use custom babel plugin to fix linaria
     new 825d2c435 make wallet-cli runnable under qtart
     new 8e78bf73a web-util fixes
     new 08b120bc8 put platform-independent stuff in http-common.ts
     new a906263f7 use node16 module resolution

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 packages/anastasis-core/src/cli.ts                 |   2 +-
 packages/demobank-ui/src/hooks/access.ts           |  10 +-
 packages/demobank-ui/src/hooks/circuit.ts          |   8 +-
 packages/demobank-ui/src/pages/Routing.tsx         |   4 +-
 packages/demobank-ui/tsconfig.json                 |   4 +-
 .../merchant-backoffice-ui/src/utils/regex.test.ts |   2 +-
 packages/taler-harness/src/bench1.ts               |  17 +-
 packages/taler-harness/src/bench2.ts               |  11 +-
 packages/taler-harness/src/bench3.ts               |  15 +-
 packages/taler-harness/src/harness/harness.ts      |   9 +-
 packages/taler-harness/src/index.ts                |  13 +-
 .../integrationtests/test-exchange-timetravel.ts   |  10 +-
 .../taler-harness/src/integrationtests/test-kyc.ts |  14 +-
 .../test-merchant-spec-public-orders.ts            |   5 +-
 .../src/integrationtests/test-payment-on-demo.ts   |   4 +-
 .../integrationtests/test-wallet-cryptoworker.ts   |  13 --
 .../src/integrationtests/test-wallet-dbless.ts     |  11 +-
 packages/taler-harness/src/lint.ts                 |  10 +-
 packages/taler-util/package.json                   |  31 ++-
 packages/taler-util/src/clk.ts                     |  53 ++---
 .../config.ts => taler-util/src/compat.d.ts}       |  24 +--
 packages/taler-util/src/compat.node.ts             |  59 +++++
 packages/taler-util/src/compat.qtart.ts            |  53 +++++
 .../src/errors.ts                                  |   0
 .../util/http.ts => taler-util/src/http-common.ts} |  64 +++---
 packages/taler-util/src/http-impl.node.d.ts        |  17 ++
 packages/taler-util/src/http-impl.node.ts          | 175 +++++++++++++++
 packages/taler-util/src/http-impl.qtart.ts         | 127 +++++++++++
 .../index.browser.ts => taler-util/src/http.ts}    |  24 ++-
 packages/taler-util/src/index.browser.ts           |   4 +
 packages/taler-util/src/index.node.ts              |   1 -
 packages/taler-util/src/index.ts                   |   1 +
 packages/taler-util/src/qtart.ts                   |  36 ++++
 packages/taler-util/src/twrpc-impl.missing.ts      |   9 +
 packages/taler-wallet-cli/build.mjs                |   6 +-
 packages/taler-wallet-cli/src/index.ts             | 131 ++++++------
 packages/taler-wallet-core/package.json            |  10 +-
 packages/taler-wallet-core/src/bank-api-client.ts  |   7 +-
 .../src/crypto/workers/crypto-dispatcher.test.ts   |   2 -
 .../src/crypto/workers/crypto-dispatcher.ts        |   2 +-
 .../src/crypto/workers/rpcClient.ts                |  92 --------
 .../crypto/workers/synchronousWorkerFactoryNode.ts |  36 ----
 .../src/crypto/workers/synchronousWorkerNode.ts    | 174 ---------------
 .../src/crypto/workers/worker-common.ts            |   2 +-
 packages/taler-wallet-core/src/db.ts               |   3 +
 packages/taler-wallet-core/src/dbless.ts           |   2 +-
 packages/taler-wallet-core/src/dev-experiments.ts  |   2 +-
 .../taler-wallet-core/src/headless/NodeHttpLib.ts  | 183 ----------------
 packages/taler-wallet-core/src/host-common.ts      |  60 ++++++
 .../src/{headless/helpers.ts => host-impl.node.ts} |  78 ++-----
 packages/taler-wallet-core/src/host-impl.qtart.ts  | 120 +++++++++++
 .../src/host.ts}                                   |  48 ++---
 packages/taler-wallet-core/src/index.browser.ts    |   2 +-
 packages/taler-wallet-core/src/index.node.ts       |  11 +-
 packages/taler-wallet-core/src/index.ts            |   6 +-
 .../taler-wallet-core/src/internal-wallet-state.ts |  13 +-
 .../src/operations/backup/index.ts                 |   4 +-
 .../taler-wallet-core/src/operations/common.ts     |   2 +-
 .../taler-wallet-core/src/operations/deposits.ts   |   6 +-
 .../taler-wallet-core/src/operations/exchanges.ts  |   9 +-
 .../taler-wallet-core/src/operations/merchants.ts  |   2 +-
 .../src/operations/pay-merchant.ts                 |   7 +-
 .../taler-wallet-core/src/operations/pay-peer.ts   |   5 +-
 .../taler-wallet-core/src/operations/recoup.ts     |   2 +-
 .../taler-wallet-core/src/operations/refresh.ts    |   4 +-
 .../taler-wallet-core/src/operations/testing.ts    |   2 +-
 packages/taler-wallet-core/src/operations/tip.ts   |   4 +-
 .../taler-wallet-core/src/operations/withdraw.ts   |   4 +-
 packages/taler-wallet-core/src/remote.ts           |   2 +-
 packages/taler-wallet-core/src/util/retries.ts     |   2 +-
 packages/taler-wallet-core/src/wallet.ts           |   4 +-
 packages/taler-wallet-embedded/build.mjs           |   1 +
 packages/taler-wallet-embedded/src/index.ts        |  28 ++-
 packages/taler-wallet-embedded/src/wallet-qjs.ts   | 237 ++-------------------
 .../src/browserHttpLib.ts                          |  16 +-
 .../src/browserWorkerEntry.ts                      |   7 +-
 .../src/components/index.stories.tsx               |   2 +-
 .../src/cta/InvoiceCreate/state.ts                 |   2 +-
 .../src/cta/InvoicePay/state.ts                    |   6 +-
 .../src/cta/TransferCreate/state.ts                |   6 +-
 .../src/cta/TransferPickup/state.ts                |   7 +-
 .../src/cta/Withdraw/state.ts                      |   3 +-
 .../src/hooks/useAsyncAsHook.ts                    |   3 +-
 .../taler-wallet-webextension/src/mui/Button.tsx   |   4 +-
 .../taler-wallet-webextension/src/mui/Grid.tsx     |   2 +-
 .../src/mui/Menu.stories.tsx                       |   3 +-
 .../taler-wallet-webextension/src/mui/Modal.tsx    |   4 +-
 .../taler-wallet-webextension/src/mui/Paper.tsx    |   4 +-
 .../taler-wallet-webextension/src/mui/Popover.tsx  |   6 +-
 .../taler-wallet-webextension/src/mui/Portal.tsx   |   8 +-
 .../src/mui/TextField.tsx                          |   2 +-
 .../src/mui/Typography.tsx                         |   2 +-
 .../src/mui/input/FormControl.tsx                  |   2 +-
 .../src/mui/input/FormHelperText.tsx               |   2 +-
 .../src/mui/input/FormLabel.tsx                    |   2 +-
 .../src/mui/input/InputBase.tsx                    |   2 +-
 .../src/mui/input/InputFilled.tsx                  |   2 +-
 .../src/mui/input/InputLabel.tsx                   |   2 +-
 .../src/mui/input/InputStandard.tsx                |   2 +-
 .../taler-wallet-webextension/src/mui/style.tsx    |   4 +-
 .../src/platform/chrome.ts                         |   3 +-
 .../src/popup/Application.tsx                      |   2 +-
 .../src/serviceWorkerCryptoWorkerFactory.ts        |   4 +-
 .../src/serviceWorkerHttpLib.ts                    |   6 +-
 .../src/wallet/Application.tsx                     |   2 +-
 .../src/wallet/QrReader.tsx                        |   2 +-
 packages/taler-wallet-webextension/src/wxApi.ts    |   8 +-
 .../taler-wallet-webextension/src/wxBackend.ts     |   4 +-
 .../taler-wallet-webextension/trim-extension.cjs   |   2 +-
 packages/taler-wallet-webextension/tsconfig.json   |   6 +-
 packages/web-util/package.json                     |  20 +-
 packages/web-util/src/cli.ts                       |   3 +-
 packages/web-util/src/serve.ts                     |   4 +-
 packages/web-util/tsconfig.json                    |   4 +-
 114 files changed, 1134 insertions(+), 1196 deletions(-)
 copy packages/{merchant-backend-ui/src/context/config.ts => 
taler-util/src/compat.d.ts} (67%)
 create mode 100644 packages/taler-util/src/compat.node.ts
 create mode 100644 packages/taler-util/src/compat.qtart.ts
 rename packages/{taler-wallet-core => taler-util}/src/errors.ts (100%)
 rename packages/{taler-wallet-core/src/util/http.ts => 
taler-util/src/http-common.ts} (87%)
 create mode 100644 packages/taler-util/src/http-impl.node.d.ts
 create mode 100644 packages/taler-util/src/http-impl.node.ts
 create mode 100644 packages/taler-util/src/http-impl.qtart.ts
 copy packages/{taler-wallet-core/src/index.browser.ts => 
taler-util/src/http.ts} (58%)
 create mode 100644 packages/taler-util/src/qtart.ts
 delete mode 100644 packages/taler-wallet-core/src/crypto/workers/rpcClient.ts
 delete mode 100644 
packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts
 delete mode 100644 
packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts
 delete mode 100644 packages/taler-wallet-core/src/headless/NodeHttpLib.ts
 create mode 100644 packages/taler-wallet-core/src/host-common.ts
 rename packages/taler-wallet-core/src/{headless/helpers.ts => 
host-impl.node.ts} (67%)
 create mode 100644 packages/taler-wallet-core/src/host-impl.qtart.ts
 copy packages/{taler-util/src/ReserveStatus.ts => 
taler-wallet-core/src/host.ts} (51%)

diff --git a/packages/anastasis-core/src/cli.ts 
b/packages/anastasis-core/src/cli.ts
index 517f2876d..df53d6bd0 100644
--- a/packages/anastasis-core/src/cli.ts
+++ b/packages/anastasis-core/src/cli.ts
@@ -1,4 +1,4 @@
-import { clk } from "@gnu-taler/taler-util";
+import { clk } from "@gnu-taler/taler-util/clk";
 import {
   getBackupStartState,
   getRecoveryStartState,
diff --git a/packages/demobank-ui/src/hooks/access.ts 
b/packages/demobank-ui/src/hooks/access.ts
index 9c162acfe..9314af557 100644
--- a/packages/demobank-ui/src/hooks/access.ts
+++ b/packages/demobank-ui/src/hooks/access.ts
@@ -162,7 +162,7 @@ export function useAccountDetails(
 > {
   const { fetcher } = useAuthenticatedBackend();
 
-  const { data, error } = useSWR<
+  const { data, error } = useSWR.default<
     HttpResponseOk<SandboxBackend.Access.BankAccountBalanceResponse>,
     RequestError<SandboxBackend.SandboxError>
   >([`access-api/accounts/${account}`], fetcher, {
@@ -192,7 +192,7 @@ export function useWithdrawalDetails(
 > {
   const { fetcher } = useAuthenticatedBackend();
 
-  const { data, error } = useSWR<
+  const { data, error } = useSWR.default<
     HttpResponseOk<SandboxBackend.Access.BankAccountGetWithdrawalResponse>,
     RequestError<SandboxBackend.SandboxError>
   >([`access-api/accounts/${account}/withdrawals/${wid}`], fetcher, {
@@ -222,7 +222,7 @@ export function useTransactionDetails(
 > {
   const { fetcher } = useAuthenticatedBackend();
 
-  const { data, error } = useSWR<
+  const { data, error } = useSWR.default<
     HttpResponseOk<SandboxBackend.Access.BankAccountTransactionInfo>,
     RequestError<SandboxBackend.SandboxError>
   >([`access-api/accounts/${account}/transactions/${tid}`], fetcher, {
@@ -261,7 +261,7 @@ export function usePublicAccounts(
     data: afterData,
     error: afterError,
     isValidating: loadingAfter,
-  } = useSWR<
+  } = useSWR.default<
     HttpResponseOk<SandboxBackend.Access.PublicAccountsResponse>,
     RequestError<SandboxBackend.SandboxError>
   >([`public-accounts`, args?.page, PAGE_SIZE], paginatedFetcher);
@@ -329,7 +329,7 @@ export function useTransactions(
     data: afterData,
     error: afterError,
     isValidating: loadingAfter,
-  } = useSWR<
+  } = useSWR.default<
     HttpResponseOk<SandboxBackend.Access.BankAccountTransactionsResponse>,
     RequestError<SandboxBackend.SandboxError>
   >(
diff --git a/packages/demobank-ui/src/hooks/circuit.ts 
b/packages/demobank-ui/src/hooks/circuit.ts
index 91922a6ba..19a48224f 100644
--- a/packages/demobank-ui/src/hooks/circuit.ts
+++ b/packages/demobank-ui/src/hooks/circuit.ts
@@ -194,7 +194,7 @@ export function useBusinessAccountDetails(
 > {
   const { fetcher } = useAuthenticatedBackend();
 
-  const { data, error } = useSWR<
+  const { data, error } = useSWR.default<
     HttpResponseOk<SandboxBackend.Circuit.CircuitAccountData>,
     RequestError<SandboxBackend.SandboxError>
   >([`circuit-api/accounts/${account}`], fetcher, {
@@ -232,7 +232,7 @@ export function useBusinessAccounts(
     data: afterData,
     error: afterError,
     // isValidating: loadingAfter,
-  } = useSWR<
+  } = useSWR.default<
     HttpResponseOk<SandboxBackend.Circuit.CircuitAccounts>,
     RequestError<SandboxBackend.SandboxError>
   >(
@@ -302,7 +302,7 @@ export function useCashouts(): HttpResponse<
 > {
   const { fetcher, multiFetcher } = useAuthenticatedBackend();
 
-  const { data: list, error: listError } = useSWR<
+  const { data: list, error: listError } = useSWR.default<
     HttpResponseOk<SandboxBackend.Circuit.Cashouts>,
     RequestError<SandboxBackend.SandboxError>
   >([`circuit-api/cashouts`], fetcher, {
@@ -316,7 +316,7 @@ export function useCashouts(): HttpResponse<
   const paths = (list?.data.cashouts || []).map(
     (cashoutId) => `circuit-api/cashouts/${cashoutId}`,
   );
-  const { data: cashouts, error: productError } = useSWR<
+  const { data: cashouts, error: productError } = useSWR.default<
     HttpResponseOk<SandboxBackend.Circuit.CashoutStatusResponse>[],
     RequestError<SandboxBackend.SandboxError>
   >([paths], multiFetcher, {
diff --git a/packages/demobank-ui/src/pages/Routing.tsx 
b/packages/demobank-ui/src/pages/Routing.tsx
index cff561aac..55317f4ed 100644
--- a/packages/demobank-ui/src/pages/Routing.tsx
+++ b/packages/demobank-ui/src/pages/Routing.tsx
@@ -19,8 +19,8 @@ import {
   useTranslationContext,
 } from "@gnu-taler/web-util/lib/index.browser";
 import { createHashHistory } from "history";
-import { h, VNode } from "preact";
-import Router, { route, Route } from "preact-router";
+import { h, VNode, } from "preact";
+import { Router, route, Route } from "preact-router";
 import { useEffect } from "preact/hooks";
 import { Loading } from "../components/Loading.js";
 import { PageStateType, usePageContext } from "../context/pageState.js";
diff --git a/packages/demobank-ui/tsconfig.json 
b/packages/demobank-ui/tsconfig.json
index daa274983..78a686aff 100644
--- a/packages/demobank-ui/tsconfig.json
+++ b/packages/demobank-ui/tsconfig.json
@@ -25,7 +25,7 @@
     // "noImplicitReturns": true,             /* Report error when not all 
code paths in function return a value. */
     // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough 
cases in switch statement. */
     /* Module Resolution Options */
-    "moduleResolution": "Node" /* Specify module resolution strategy: 'node' 
(Node.js) or 'classic' (TypeScript pre-1.6). */,
+    "moduleResolution": "Node16" /* Specify module resolution strategy: 'node' 
(Node.js) or 'classic' (TypeScript pre-1.6). */,
     "esModuleInterop": true /* */,
     // "baseUrl": "./",                       /* Base directory to resolve 
non-absolute module names. */
     // "paths": {},                           /* A series of entries which 
re-map imports to lookup locations relative to the 'baseUrl'. */
@@ -48,4 +48,4 @@
   "include": [
     "src/**/*"
   ]
-}
\ No newline at end of file
+}
diff --git a/packages/merchant-backoffice-ui/src/utils/regex.test.ts 
b/packages/merchant-backoffice-ui/src/utils/regex.test.ts
index 341a19fb1..d473bd08c 100644
--- a/packages/merchant-backoffice-ui/src/utils/regex.test.ts
+++ b/packages/merchant-backoffice-ui/src/utils/regex.test.ts
@@ -20,7 +20,7 @@
  */
 
 import { expect } from "chai";
-import { AMOUNT_REGEX, PAYTO_REGEX } from "../../src/utils/constants.js";
+import { AMOUNT_REGEX, PAYTO_REGEX } from "./constants.js";
 
 describe("payto uri format", () => {
   const valids = [
diff --git a/packages/taler-harness/src/bench1.ts 
b/packages/taler-harness/src/bench1.ts
index 84786d25a..0a4118ec1 100644
--- a/packages/taler-harness/src/bench1.ts
+++ b/packages/taler-harness/src/bench1.ts
@@ -19,19 +19,19 @@
  */
 import {
   buildCodecForObject,
+  codecForBoolean,
   codecForNumber,
   codecForString,
-  codecForBoolean,
   codecOptional,
   j2s,
   Logger,
 } from "@gnu-taler/taler-util";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
 import {
-  getDefaultNodeWallet2,
-  NodeHttpLib,
-  WalletApiOperation,
-  Wallet,
   AccessStats,
+  createNativeWalletHost2,
+  Wallet,
+  WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 
 /**
@@ -46,8 +46,9 @@ export async function runBench1(configJson: any): 
Promise<void> {
   // Validate the configuration file for this benchmark.
   const b1conf = codecForBench1Config().decode(configJson);
 
-  const myHttpLib = new NodeHttpLib();
-  myHttpLib.setThrottling(false);
+  const myHttpLib = createPlatformHttpLib({
+    enableThrottling: false,
+  });
 
   const numIter = b1conf.iterations ?? 1;
   const numDeposits = b1conf.deposits ?? 5;
@@ -81,7 +82,7 @@ export async function runBench1(configJson: any): 
Promise<void> {
         console.log("wallet DB stats", j2s(getDbStats!()));
       }
 
-      const res = await getDefaultNodeWallet2({
+      const res = await createNativeWalletHost2({
         // No persistent DB storage.
         persistentStoragePath: undefined,
         httpLib: myHttpLib,
diff --git a/packages/taler-harness/src/bench2.ts 
b/packages/taler-harness/src/bench2.ts
index 9fa5d7caf..ff87da52a 100644
--- a/packages/taler-harness/src/bench2.ts
+++ b/packages/taler-harness/src/bench2.ts
@@ -24,6 +24,7 @@ import {
   codecOptional,
   Logger,
 } from "@gnu-taler/taler-util";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
 import {
   checkReserve,
   createFakebankReserve,
@@ -31,9 +32,8 @@ import {
   depositCoin,
   downloadExchangeInfo,
   findDenomOrThrow,
-  NodeHttpLib,
   refreshCoin,
-  SynchronousCryptoWorkerFactoryNode,
+  SynchronousCryptoWorkerFactoryPlain,
   withdrawCoin,
 } from "@gnu-taler/taler-wallet-core";
 
@@ -50,12 +50,13 @@ export async function runBench2(configJson: any): 
Promise<void> {
   const benchConf = codecForBench2Config().decode(configJson);
   const curr = benchConf.currency;
   const cryptoDisp = new CryptoDispatcher(
-    new SynchronousCryptoWorkerFactoryNode(),
+    new SynchronousCryptoWorkerFactoryPlain(),
   );
   const cryptoApi = cryptoDisp.cryptoApi;
 
-  const http = new NodeHttpLib();
-  http.setThrottling(false);
+  const http = createPlatformHttpLib({
+    enableThrottling: false,
+  });
 
   const numIter = benchConf.iterations ?? 1;
   const numDeposits = benchConf.deposits ?? 5;
diff --git a/packages/taler-harness/src/bench3.ts 
b/packages/taler-harness/src/bench3.ts
index 9679f05a6..5e8fac0e9 100644
--- a/packages/taler-harness/src/bench3.ts
+++ b/packages/taler-harness/src/bench3.ts
@@ -25,12 +25,12 @@ import {
   j2s,
   Logger,
 } from "@gnu-taler/taler-util";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
 import {
-  getDefaultNodeWallet2,
-  NodeHttpLib,
-  WalletApiOperation,
-  Wallet,
   AccessStats,
+  createNativeWalletHost2,
+  Wallet,
+  WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import benchMerchantIDGenerator from "./benchMerchantIDGenerator.js";
 
@@ -50,8 +50,9 @@ export async function runBench3(configJson: any): 
Promise<void> {
     throw new Error("Payto template url must contain '${id}' placeholder");
   }
 
-  const myHttpLib = new NodeHttpLib();
-  myHttpLib.setThrottling(false);
+  const myHttpLib = createPlatformHttpLib({
+    enableThrottling: false,
+  });
 
   const numIter = b3conf.iterations ?? 1;
   const numDeposits = b3conf.deposits ?? 5;
@@ -89,7 +90,7 @@ export async function runBench3(configJson: any): 
Promise<void> {
         console.log("wallet DB stats", j2s(getDbStats!()));
       }
 
-      const res = await getDefaultNodeWallet2({
+      const res = await createNativeWalletHost2({
         // No persistent DB storage.
         persistentStoragePath: undefined,
         httpLib: myHttpLib,
diff --git a/packages/taler-harness/src/harness/harness.ts 
b/packages/taler-harness/src/harness/harness.ts
index 0b7ba14cf..518b98d82 100644
--- a/packages/taler-harness/src/harness/harness.ts
+++ b/packages/taler-harness/src/harness/harness.ts
@@ -41,17 +41,15 @@ import {
   MerchantTemplateAddDetails,
   parsePaytoUri,
   stringToBytes,
+  TalerError,
   TalerProtocolDuration,
   WalletNotification,
 } from "@gnu-taler/taler-util";
 import {
-  BankAccessApi,
   BankApi,
   BankServiceHandle,
   HarnessExchangeBankAccount,
-  NodeHttpLib,
   openPromise,
-  TalerError,
   WalletCoreApiClient,
 } from "@gnu-taler/taler-wallet-core";
 import { deepStrictEqual } from "assert";
@@ -83,6 +81,7 @@ import {
   RemoteWallet,
   WalletNotificationWaiter,
 } from "@gnu-taler/taler-wallet-core/remote";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
 
 const logger = new Logger("harness.ts");
 
@@ -507,7 +506,7 @@ class LibEuFinBankService extends BankServiceBase 
implements BankServiceHandle {
   sandboxProc: ProcessWrapper | undefined;
   nexusProc: ProcessWrapper | undefined;
 
-  http = new NodeHttpLib();
+  http = createPlatformHttpLib();
 
   static async create(
     gc: GlobalTestState,
@@ -794,7 +793,7 @@ export class FakebankService
 {
   proc: ProcessWrapper | undefined;
 
-  http = new NodeHttpLib();
+  http = createPlatformHttpLib();
 
   // We store "created" accounts during setup and
   // register them after startup.
diff --git a/packages/taler-harness/src/index.ts 
b/packages/taler-harness/src/index.ts
index e4ee25dae..14b8a4302 100644
--- a/packages/taler-harness/src/index.ts
+++ b/packages/taler-harness/src/index.ts
@@ -23,7 +23,6 @@ import os from "os";
 import path from "path";
 import {
   Amounts,
-  clk,
   Configuration,
   decodeCrock,
   Logger,
@@ -38,6 +37,7 @@ import { GlobalTestState, runTestWithState } from 
"./harness/harness.js";
 import { getTestInfo, runTests } from "./integrationtests/testrunner.js";
 import { lintExchangeDeployment } from "./lint.js";
 import { runEnvFull } from "./env-full.js";
+import { clk } from "@gnu-taler/taler-util/clk";
 
 const logger = new Logger("taler-harness:index.ts");
 
@@ -74,6 +74,15 @@ const advancedCli = testingCli.subcommand("advancedArgs", 
"advanced", {
   help: "Subcommands for advanced operations (only use if you know what you're 
doing!).",
 });
 
+advancedCli
+  .subcommand("decode", "decode", {
+    help: "Decode base32-crockford.",
+  })
+  .action((args) => {
+    const enc = fs.readFileSync(0, "utf8");
+    console.log(decodeCrock(enc.trim()));
+  });
+
 advancedCli
   .subcommand("bench1", "bench1", {
     help: "Run the 'bench1' benchmark",
@@ -272,7 +281,7 @@ testingCli
     help: "Produce less output.",
   })
   .flag("noTimeout", ["--no-timeout"], {
-    help: "Do not time out tests."
+    help: "Do not time out tests.",
   })
   .action(async (args) => {
     await runTests({
diff --git 
a/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts 
b/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts
index 074126e9f..20285cb6a 100644
--- a/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts
+++ b/packages/taler-harness/src/integrationtests/test-exchange-timetravel.ts
@@ -24,22 +24,18 @@ import {
   Duration,
   durationFromSpec,
 } from "@gnu-taler/taler-util";
-import {
-  NodeHttpLib,
-  readSuccessResponseJsonOrThrow,
-} from "@gnu-taler/taler-wallet-core";
+import { createPlatformHttpLib, readSuccessResponseJsonOrThrow } from 
"@gnu-taler/taler-util/http";
 import { makeNoFeeCoinConfig } from "../harness/denomStructures.js";
 import {
   BankService,
   ExchangeService,
   GlobalTestState,
-  MerchantPrivateApi,
   MerchantService,
   setupDb,
   WalletCli,
   getPayto,
 } from "../harness/harness.js";
-import { startWithdrawViaBank, withdrawViaBank } from "../harness/helpers.js";
+import { withdrawViaBank } from "../harness/helpers.js";
 
 async function applyTimeTravel(
   timetravelDuration: Duration,
@@ -69,7 +65,7 @@ async function applyTimeTravel(
   }
 }
 
-const http = new NodeHttpLib();
+const http = createPlatformHttpLib();
 
 /**
  * Basic time travel test.
diff --git a/packages/taler-harness/src/integrationtests/test-kyc.ts 
b/packages/taler-harness/src/integrationtests/test-kyc.ts
index 490673cee..915c3d470 100644
--- a/packages/taler-harness/src/integrationtests/test-kyc.ts
+++ b/packages/taler-harness/src/integrationtests/test-kyc.ts
@@ -17,11 +17,14 @@
 /**
  * Imports.
  */
-import { Duration, j2s, NotificationType } from "@gnu-taler/taler-util";
+import {
+  Duration,
+  j2s,
+  NotificationType,
+} from "@gnu-taler/taler-util";
 import {
   BankAccessApi,
   BankApi,
-  NodeHttpLib,
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
@@ -37,6 +40,7 @@ import {
 } from "../harness/harness.js";
 import { EnvOptions, SimpleTestEnvironmentNg } from "../harness/helpers.js";
 import * as http from "node:http";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
 
 export async function createKycTestkudosEnvironment(
   t: GlobalTestState,
@@ -336,12 +340,12 @@ export async function runKycTest(t: GlobalTestState) {
   // We now simulate the user interacting with the KYC service,
   // which would usually done in the browser.
 
-  const httpClient = new NodeHttpLib();
-  const kycServerResp = await httpClient.get(kycNotif.kycUrl);
+  const httpLib = createPlatformHttpLib();
+  const kycServerResp = await httpLib.get(kycNotif.kycUrl);
   const kycLoginResp = await kycServerResp.json();
   console.log("kyc server resp:", j2s(kycLoginResp));
   const kycProofUrl = kycLoginResp.redirect_uri;
-  const proofHttpResp = await httpClient.get(kycProofUrl);
+  const proofHttpResp = await httpLib.get(kycProofUrl);
   console.log("proof resp status", proofHttpResp.status);
   console.log("resp headers", proofHttpResp.headers.toJSON());
 
diff --git 
a/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts
 
b/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts
index 70edaaf0c..2fafe7584 100644
--- 
a/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts
+++ 
b/packages/taler-harness/src/integrationtests/test-merchant-spec-public-orders.ts
@@ -24,7 +24,8 @@ import {
   encodeCrock,
   getRandomBytes,
 } from "@gnu-taler/taler-util";
-import { NodeHttpLib, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import {
   BankService,
   ExchangeService,
@@ -38,7 +39,7 @@ import {
   withdrawViaBank,
 } from "../harness/helpers.js";
 
-const httpLib = new NodeHttpLib();
+const httpLib = createPlatformHttpLib();
 
 interface Context {
   merchant: MerchantService;
diff --git 
a/packages/taler-harness/src/integrationtests/test-payment-on-demo.ts 
b/packages/taler-harness/src/integrationtests/test-payment-on-demo.ts
index 737620ce7..22e88c8a0 100644
--- a/packages/taler-harness/src/integrationtests/test-payment-on-demo.ts
+++ b/packages/taler-harness/src/integrationtests/test-payment-on-demo.ts
@@ -24,8 +24,8 @@ import {
   BankApi,
   BankAccessApi,
   BankServiceHandle,
-  NodeHttpLib,
 } from "@gnu-taler/taler-wallet-core";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
 
 /**
  * Run test for basic, bank-integrated withdrawal and payment.
@@ -35,7 +35,7 @@ export async function runPaymentDemoTest(t: GlobalTestState) {
   let bankInterface: BankServiceHandle = {
     baseUrl: "https://bank.demo.taler.net/";,
     bankAccessApiBaseUrl: "https://bank.demo.taler.net/";,
-    http: new NodeHttpLib(),
+    http: createPlatformHttpLib(),
   };
   let user = await BankApi.createRandomBankUser(bankInterface);
   let wop = await BankAccessApi.createWithdrawalOperation(
diff --git 
a/packages/taler-harness/src/integrationtests/test-wallet-cryptoworker.ts 
b/packages/taler-harness/src/integrationtests/test-wallet-cryptoworker.ts
index a9f1c4d80..6c2006636 100644
--- a/packages/taler-harness/src/integrationtests/test-wallet-cryptoworker.ts
+++ b/packages/taler-harness/src/integrationtests/test-wallet-cryptoworker.ts
@@ -17,23 +17,10 @@
 /**
  * Imports.
  */
-import { j2s } from "@gnu-taler/taler-util";
 import {
-  checkReserve,
-  CryptoDispatcher,
-  depositCoin,
-  downloadExchangeInfo,
-  findDenomOrThrow,
-  NodeHttpLib,
-  refreshCoin,
-  SynchronousCryptoWorkerFactoryNode,
-  TalerError,
-  topupReserveWithDemobank,
   WalletApiOperation,
-  withdrawCoin,
 } from "@gnu-taler/taler-wallet-core";
 import { GlobalTestState, WalletCli } from "../harness/harness.js";
-import { createSimpleTestkudosEnvironment } from "../harness/helpers.js";
 
 /**
  * Run test for the different crypto workers.
diff --git a/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts 
b/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts
index 7692f12b2..08c10fd91 100644
--- a/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts
+++ b/packages/taler-harness/src/integrationtests/test-wallet-dbless.ts
@@ -17,17 +17,16 @@
 /**
  * Imports.
  */
-import { j2s } from "@gnu-taler/taler-util";
+import { j2s, TalerError } from "@gnu-taler/taler-util";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
 import {
   checkReserve,
   CryptoDispatcher,
   depositCoin,
   downloadExchangeInfo,
   findDenomOrThrow,
-  NodeHttpLib,
   refreshCoin,
-  SynchronousCryptoWorkerFactoryNode,
-  TalerError,
+  SynchronousCryptoWorkerFactoryPlain,
   topupReserveWithDemobank,
   withdrawCoin,
 } from "@gnu-taler/taler-wallet-core";
@@ -42,9 +41,9 @@ export async function runWalletDblessTest(t: GlobalTestState) 
{
 
   const { bank, exchange } = await createSimpleTestkudosEnvironment(t);
 
-  const http = new NodeHttpLib();
+  const http = createPlatformHttpLib();
   const cryptiDisp = new CryptoDispatcher(
-    new SynchronousCryptoWorkerFactoryNode(),
+    new SynchronousCryptoWorkerFactoryPlain(),
   );
   const cryptoApi = cryptiDisp.cryptoApi;
 
diff --git a/packages/taler-harness/src/lint.ts 
b/packages/taler-harness/src/lint.ts
index 49fb9dc86..3d3805e79 100644
--- a/packages/taler-harness/src/lint.ts
+++ b/packages/taler-harness/src/lint.ts
@@ -37,13 +37,13 @@ import {
   Configuration,
   decodeCrock,
 } from "@gnu-taler/taler-util";
-import {
-  NodeHttpLib,
-  readSuccessResponseJsonOrThrow,
-} from "@gnu-taler/taler-wallet-core";
 import { URL } from "url";
 import { spawn } from "child_process";
 import { delayMs } from "./harness/harness.js";
+import {
+  createPlatformHttpLib,
+  readSuccessResponseJsonOrThrow,
+} from "@gnu-taler/taler-util/http";
 
 interface BasicConf {
   mainCurrency: string;
@@ -53,7 +53,7 @@ interface PubkeyConf {
   masterPublicKey: string;
 }
 
-const httpLib = new NodeHttpLib();
+const httpLib = createPlatformHttpLib();
 
 interface ShellResult {
   stdout: string;
diff --git a/packages/taler-util/package.json b/packages/taler-util/package.json
index 23ff5dcfa..21bee4683 100644
--- a/packages/taler-util/package.json
+++ b/packages/taler-util/package.json
@@ -15,12 +15,39 @@
     },
     "./twrpc": {
       "default": "./lib/twrpc.js"
+    },
+    "./compat": {
+      "types": "./lib/compat.node.js",
+      "node": "./lib/compat.node.js",
+      "qtart": "./lib/compat.qtart.js",
+      "default": "./lib/not-implemented.js"
+    },
+    "./clk": {
+      "default": "./lib/clk.js"
+    },
+    "./http": {
+      "default": "./lib/http.js"
+    },
+    "./qtart": {
+      "types": "./lib/qtart.js",
+      "qtart": "./lib/qtart.js",
+      "default": "./lib/not-implemented.js"
     }
   },
   "imports": {
     "#twrpc-impl": {
-      "node": "./lib/twrpc-impl.node.js",
-      "default": "./lib/twrpc-impl.missing.js"
+      "node": "./lib/twrpc-impl.node.js"
+    },
+    "#compat-impl": {
+      "node": "./lib/compat.node.js",
+      "qtart": "./lib/compat.qtart.js",
+      "type": "./lib/compat.d.ts"
+    },
+    "#http-impl": {
+      "type": "./lib/http-impl.node.js",
+      "node": "./lib/http-impl.node.js",
+      "qtart": "./lib/http-impl.qtart.js",
+      "default": "./lib/http-impl.missing.js"
     }
   },
   "scripts": {
diff --git a/packages/taler-util/src/clk.ts b/packages/taler-util/src/clk.ts
index e99ebf733..7bcd19b04 100644
--- a/packages/taler-util/src/clk.ts
+++ b/packages/taler-util/src/clk.ts
@@ -17,10 +17,12 @@
 /**
  * Imports.
  */
-import process from "process";
-import path from "path";
-import readline from "readline";
-import { devNull } from "os";
+import {
+  processExit,
+  processArgv,
+  readlinePrompt,
+  pathBasename,
+} from "#compat-impl";
 
 export namespace clk {
   class Converter<T> {}
@@ -359,13 +361,13 @@ export namespace clk {
               console.error(
                 `error: unknown option '--${r.key}' for ${currentName}`,
               );
-              process.exit(-1);
+              processExit(-1);
               throw Error("not reached");
             }
             if (d.isFlag) {
               if (r.value !== undefined) {
                 console.error(`error: flag '--${r.key}' does not take a 
value`);
-                process.exit(-1);
+                processExit(-1);
                 throw Error("not reached");
               }
               storeFlag(d, true);
@@ -373,7 +375,7 @@ export namespace clk {
               if (r.value === undefined) {
                 if (i === unparsedArgs.length - 1) {
                   console.error(`error: option '--${r.key}' needs an 
argument`);
-                  process.exit(-1);
+                  processExit(-1);
                   throw Error("not reached");
                 }
                 storeOption(d, unparsedArgs[i + 1]);
@@ -391,7 +393,7 @@ export namespace clk {
               const opt = this.shortOptions[chr];
               if (!opt) {
                 console.error(`error: option '-${chr}' not known`);
-                process.exit(-1);
+                processExit(-1);
               }
               if (opt.isFlag) {
                 storeFlag(opt, true);
@@ -399,7 +401,7 @@ export namespace clk {
                 if (si == optShort.length - 1) {
                   if (i === unparsedArgs.length - 1) {
                     console.error(`error: option '-${chr}' needs an argument`);
-                    process.exit(-1);
+                    processExit(-1);
                     throw Error("not reached");
                   } else {
                     storeOption(opt, unparsedArgs[i + 1]);
@@ -418,7 +420,7 @@ export namespace clk {
           const subcmd = this.subcommandMap[argVal];
           if (!subcmd) {
             console.error(`error: unknown command '${argVal}'`);
-            process.exit(-1);
+            processExit(-1);
             throw Error("not reached");
           }
           foundSubcommand = subcmd.commandGroup;
@@ -427,7 +429,7 @@ export namespace clk {
           const d = this.arguments[posArgIndex];
           if (!d) {
             console.error(`error: too many arguments for ${currentName}`);
-            process.exit(-1);
+            processExit(-1);
             throw Error("not reached");
           }
           myArgs[d.name] = unparsedArgs[i];
@@ -437,7 +439,7 @@ export namespace clk {
 
       if (parsedArgs[this.argKey].help) {
         this.printHelp(progname, parents);
-        process.exit(0);
+        processExit(0);
         throw Error("not reached");
       }
 
@@ -450,7 +452,7 @@ export namespace clk {
             console.error(
               `error: missing positional argument '${d.name}' for 
${currentName}`,
             );
-            process.exit(-1);
+            processExit(-1);
             throw Error("not reached");
           }
         }
@@ -464,7 +466,7 @@ export namespace clk {
             } else {
               const name = option.flagspec.join(",");
               console.error(`error: missing option '${name}'`);
-              process.exit(-1);
+              processExit(-1);
               throw Error("not reached");
             }
           }
@@ -492,16 +494,16 @@ export namespace clk {
         } catch (e) {
           console.error(`An error occurred while running ${currentName}`);
           console.error(e);
-          process.exit(1);
+          processExit(1);
         }
         Promise.resolve(r).catch((e) => {
           console.error(`An error occurred while running ${currentName}`);
           console.error(e);
-          process.exit(1);
+          processExit(1);
         });
       } else {
         this.printHelp(progname, parents);
-        process.exit(-1);
+        processExit(-1);
         throw Error("not reached");
       }
     }
@@ -524,15 +526,15 @@ export namespace clk {
       if (cmdlineArgs) {
         args = cmdlineArgs;
       } else {
-        args = process.argv.slice(1);
+        args = processArgv().slice(1);
       }
       if (args.length < 1) {
         console.error(
           "Error while parsing command line arguments: not enough arguments",
         );
-        process.exit(-1);
+        processExit(-1);
       }
-      const progname = path.basename(args[0]);
+      const progname = pathBasename(args[0]);
       const rest = args.slice(1);
 
       this.mainCommand.run(progname, [], rest, {});
@@ -622,15 +624,6 @@ export namespace clk {
   }
 
   export function prompt(question: string): Promise<string> {
-    const stdinReadline = readline.createInterface({
-      input: process.stdin,
-      output: process.stdout,
-    });
-    return new Promise<string>((resolve, reject) => {
-      stdinReadline.question(question, (res) => {
-        resolve(res);
-        stdinReadline.close();
-      });
-    });
+    return readlinePrompt(question);
   }
 }
diff --git a/packages/merchant-backend-ui/src/context/config.ts 
b/packages/taler-util/src/compat.d.ts
similarity index 67%
copy from packages/merchant-backend-ui/src/context/config.ts
copy to packages/taler-util/src/compat.d.ts
index 5cd772380..12ba31124 100644
--- a/packages/merchant-backend-ui/src/context/config.ts
+++ b/packages/taler-util/src/compat.d.ts
@@ -1,6 +1,6 @@
 /*
  This file is part of GNU Taler
- (C) 2021 Taler Systems S.A.
+ (C) 2023 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
@@ -14,19 +14,9 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createContext } from 'preact'
-import { useContext } from 'preact/hooks'
-
-interface Type {
-  currency: string;
-  version: string;
-}
-const Context = createContext<Type>(null!)
-
-export const ConfigContextProvider = Context.Provider
-export const useConfigContext = (): Type => useContext(Context);
+export function processExit(status: number): never;
+export function processArgv(): string[];
+export function readlinePrompt(prompt: string): Promise<string>;
+export function pathBasename(s: string): string;
+export function setUnhandledRejectionHandler(h: (e: any) => void): void;
+export function getenv(name: string): string | undefined;
\ No newline at end of file
diff --git a/packages/taler-util/src/compat.node.ts 
b/packages/taler-util/src/compat.node.ts
new file mode 100644
index 000000000..ed27a7acd
--- /dev/null
+++ b/packages/taler-util/src/compat.node.ts
@@ -0,0 +1,59 @@
+/*
+ This file is part of GNU Taler
+ (C) 2023 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 process from "node:process";
+import readline from "node:readline";
+import path from "node:path";
+import os from "node:os";
+
+export function processExit(status: number): never {
+  process.exit(1);
+}
+
+export function processArgv(): string[] {
+  return [...process.argv];
+}
+
+export function readlinePrompt(prompt: string): Promise<string> {
+  const stdinReadline = readline.createInterface({
+    input: process.stdin,
+    output: process.stdout,
+  });
+  return new Promise<string>((resolve, reject) => {
+    stdinReadline.question(prompt, (res) => {
+      resolve(res);
+      stdinReadline.close();
+    });
+  });
+}
+
+export function pathBasename(p: string): string {
+  return path.basename(p);
+}
+
+export function pathHomedir(): string {
+  return os.homedir();
+}
+
+export function setUnhandledRejectionHandler(h: (e: any) => void): void {
+  process.on("unhandledRejection", (e) => {
+    h(e);
+  });
+}
+
+export function getenv(name: string): string | undefined {
+  return process.env[name];
+}
diff --git a/packages/taler-util/src/compat.qtart.ts 
b/packages/taler-util/src/compat.qtart.ts
new file mode 100644
index 000000000..f8b336b11
--- /dev/null
+++ b/packages/taler-util/src/compat.qtart.ts
@@ -0,0 +1,53 @@
+/*
+ This file is part of GNU Taler
+ (C) 2023 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/>
+ */
+
+// qtart "std" library
+// @ts-ignore
+import * as std from "std";
+
+export function processExit(status: number): never {
+  std.exit(status);
+  throw Error("not reached");
+}
+
+export function processArgv(): string[] {
+  // @ts-ignore
+  return ["qtart", ...globalThis.scriptArgs];
+}
+
+export function readlinePrompt(prompt: string): Promise<string> {
+  throw new Error("not supported");
+}
+
+export function pathBasename(p: string): string {
+  const slashIndex = p.lastIndexOf("/");
+  if (slashIndex < 0) {
+    return p;
+  }
+  return p.substring(0, slashIndex);
+}
+
+export function pathHomedir(): string {
+  return std.getenv("HOME");
+}
+
+export function setUnhandledRejectionHandler(h: (e: any) => void): void {
+  // not supported
+}
+
+export function getenv(name: string): string | undefined {
+  return std.getenv(name);
+}
diff --git a/packages/taler-wallet-core/src/errors.ts 
b/packages/taler-util/src/errors.ts
similarity index 100%
rename from packages/taler-wallet-core/src/errors.ts
rename to packages/taler-util/src/errors.ts
diff --git a/packages/taler-wallet-core/src/util/http.ts 
b/packages/taler-util/src/http-common.ts
similarity index 87%
rename from packages/taler-wallet-core/src/util/http.ts
rename to packages/taler-util/src/http-common.ts
index 1da31a315..54f26e615 100644
--- a/packages/taler-wallet-core/src/util/http.ts
+++ b/packages/taler-util/src/http-common.ts
@@ -1,40 +1,31 @@
 /*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
+ This file is part of GNU Taler
+ (C) 2023 Taler Systems S.A.
 
- TALER is free software; you can redistribute it and/or modify it under the
+ 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.
 
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ 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
- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 
-/**
- * Helpers for doing XMLHttpRequest-s that are based on ES6 promises.
- * Allows for easy mocking for test cases.
- *
- * The API is inspired by the HTML5 fetch API.
- */
+ SPDX-License-Identifier: AGPL3.0-or-later
+*/
 
-/**
- * Imports
- */
-import {
-  Logger,
-  Duration,
-  AbsoluteTime,
-  TalerErrorDetail,
-  Codec,
-  j2s,
-  CancellationToken,
-} from "@gnu-taler/taler-util";
-import { TalerErrorCode } from "@gnu-taler/taler-util";
-import { makeErrorDetail, TalerError } from "../errors.js";
+import { CancellationToken } from "./CancellationToken.js";
+import { Codec } from "./codec.js";
+import { j2s } from "./helpers.js";
+import { TalerError, makeErrorDetail } from "./index.js";
+import { Logger } from "./logging.js";
+import { TalerErrorCode } from "./taler-error-codes.js";
+import { Duration, AbsoluteTime } from "./time.js";
+import { TalerErrorDetail } from "./wallet-types.js";
+
+const textEncoder = new TextEncoder();
 
 const logger = new Logger("http.ts");
 
@@ -352,3 +343,24 @@ export function getExpiry(
   }
   return t;
 }
+
+
+export interface HttpLibArgs {
+  enableThrottling?: boolean,
+}
+
+export function encodeBody(body: any): ArrayBuffer {
+  if (body == null) {
+    return new ArrayBuffer(0);
+  }
+  if (typeof body === "string") {
+    return textEncoder.encode(body).buffer;
+  } else if (ArrayBuffer.isView(body)) {
+    return body.buffer;
+  } else if (body instanceof ArrayBuffer) {
+    return body;
+  } else if (typeof body === "object") {
+    return textEncoder.encode(JSON.stringify(body)).buffer;
+  }
+  throw new TypeError("unsupported request body type");
+}
diff --git a/packages/taler-util/src/http-impl.node.d.ts 
b/packages/taler-util/src/http-impl.node.d.ts
new file mode 100644
index 000000000..b0fba9b30
--- /dev/null
+++ b/packages/taler-util/src/http-impl.node.d.ts
@@ -0,0 +1,17 @@
+import { HttpLibArgs } from "./http-common.js";
+import { HttpRequestLibrary, HttpRequestOptions, HttpResponse } from 
"./http.js";
+/**
+ * Implementation of the HTTP request library interface for node.
+ */
+export declare class HttpLibImpl implements HttpRequestLibrary {
+    private throttle;
+    private throttlingEnabled;
+    constructor(args?: HttpLibArgs);
+    /**
+     * Set whether requests should be throttled.
+     */
+    setThrottling(enabled: boolean): void;
+    fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse>;
+    get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse>;
+    postJson(url: string, body: any, opt?: HttpRequestOptions): 
Promise<HttpResponse>;
+}
diff --git a/packages/taler-util/src/http-impl.node.ts 
b/packages/taler-util/src/http-impl.node.ts
new file mode 100644
index 000000000..5f2b3ac8a
--- /dev/null
+++ b/packages/taler-util/src/http-impl.node.ts
@@ -0,0 +1,175 @@
+/*
+ This file is part of GNU Taler
+ (C) 2019 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/>
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+*/
+
+/**
+ * Imports.
+ */
+import * as http from "node:http";
+import { RequestOptions } from "node:http";
+import { TalerError } from "./errors.js";
+import { encodeBody, HttpLibArgs } from "./http-common.js";
+import {
+  DEFAULT_REQUEST_TIMEOUT_MS,
+  Headers,
+  HttpRequestLibrary,
+  HttpRequestOptions,
+  HttpResponse,
+} from "./http.js";
+import {
+  Logger,
+  RequestThrottler,
+  TalerErrorCode,
+  typedArrayConcat,
+  URL,
+} from "./index.js";
+
+const logger = new Logger("http-impl.node.ts");
+
+const textDecoder = new TextDecoder();
+
+/**
+ * Implementation of the HTTP request library interface for node.
+ */
+export class HttpLibImpl implements HttpRequestLibrary {
+  private throttle = new RequestThrottler();
+  private throttlingEnabled = true;
+
+  constructor(args?: HttpLibArgs) {
+    this.throttlingEnabled = args?.enableThrottling ?? false;
+  }
+
+  /**
+   * Set whether requests should be throttled.
+   */
+  setThrottling(enabled: boolean): void {
+    this.throttlingEnabled = enabled;
+  }
+
+  async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
+    const method = opt?.method?.toUpperCase() ?? "GET";
+    let body = opt?.body;
+
+    logger.trace(`Requesting ${method} ${url}`);
+
+    const parsedUrl = new URL(url);
+    if (this.throttlingEnabled && this.throttle.applyThrottle(url)) {
+      throw TalerError.fromDetail(
+        TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
+        {
+          requestMethod: method,
+          requestUrl: url,
+          throttleStats: this.throttle.getThrottleStats(url),
+        },
+        `request to origin ${parsedUrl.origin} was throttled`,
+      );
+    }
+    let timeoutMs: number | undefined;
+    if (typeof opt?.timeout?.d_ms === "number") {
+      timeoutMs = opt.timeout.d_ms;
+    } else {
+      timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
+    }
+
+    const headers = { ...opt?.headers };
+    headers["Content-Type"] = "application/json";
+
+    let reqBody: ArrayBuffer | undefined;
+
+    if (opt?.method == "POST") {
+      reqBody = encodeBody(opt.body);
+    }
+
+    const options: RequestOptions = {
+      protocol: parsedUrl.protocol,
+      port: parsedUrl.port,
+      host: parsedUrl.host,
+      method: method,
+      path: parsedUrl.pathname,
+      headers: opt?.headers,
+    };
+
+    const chunks: Uint8Array[] = [];
+
+    return new Promise((resolve, reject) => {
+      const req = http.request(options, (res) => {
+        res.on("data", (d) => {
+          chunks.push(d);
+        });
+        res.on("end", () => {
+          const headers: Headers = new Headers();
+          for (const [k, v] of Object.entries(res.headers)) {
+            if (!v) {
+              continue;
+            }
+            if (typeof v === "string") {
+              headers.set(k, v);
+            } else {
+              headers.set(k, v.join(", "));
+            }
+          }
+          const data = typedArrayConcat(chunks);
+          const resp: HttpResponse = {
+            requestMethod: method,
+            requestUrl: parsedUrl.href,
+            status: res.statusCode || 0,
+            headers,
+            async bytes() {
+              return data;
+            },
+            json() {
+              const text = textDecoder.decode(data);
+              return JSON.parse(text);
+            },
+            async text() {
+              const text = textDecoder.decode(data);
+              return text;
+            },
+          };
+          resolve(resp);
+        });
+        res.on("error", (e) => {
+          reject(e);
+        });
+      });
+
+      if (reqBody) {
+        req.write(reqBody);
+      }
+      req.end();
+    });
+  }
+
+  async get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "GET",
+      ...opt,
+    });
+  }
+
+  async postJson(
+    url: string,
+    body: any,
+    opt?: HttpRequestOptions,
+  ): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "POST",
+      body,
+      ...opt,
+    });
+  }
+}
diff --git a/packages/taler-util/src/http-impl.qtart.ts 
b/packages/taler-util/src/http-impl.qtart.ts
new file mode 100644
index 000000000..954b41802
--- /dev/null
+++ b/packages/taler-util/src/http-impl.qtart.ts
@@ -0,0 +1,127 @@
+/*
+ This file is part of GNU Taler
+ (C) 2019 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/>
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+*/
+
+/**
+ * Imports.
+ */
+import { Logger } from "@gnu-taler/taler-util";
+import { TalerError } from "./errors.js";
+import { encodeBody, HttpLibArgs } from "./http-common.js";
+import {
+  Headers,
+  HttpRequestLibrary,
+  HttpRequestOptions,
+  HttpResponse,
+} from "./http.js";
+import { RequestThrottler, TalerErrorCode, URL } from "./index.js";
+import { qjsOs } from "./qtart.js";
+
+const logger = new Logger("http-impl.qtart.ts");
+
+const textDecoder = new TextDecoder();
+
+/**
+ * Implementation of the HTTP request library interface for node.
+ */
+export class HttpLibImpl implements HttpRequestLibrary {
+  private throttle = new RequestThrottler();
+  private throttlingEnabled = true;
+
+  constructor(args?: HttpLibArgs) {
+    this.throttlingEnabled = args?.enableThrottling ?? false;
+  }
+
+  /**
+   * Set whether requests should be throttled.
+   */
+  setThrottling(enabled: boolean): void {
+    this.throttlingEnabled = enabled;
+  }
+
+  async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
+    const method = opt?.method ?? "GET";
+
+    logger.trace(`Requesting ${method} ${url}`);
+
+    const parsedUrl = new URL(url);
+    if (this.throttlingEnabled && this.throttle.applyThrottle(url)) {
+      throw TalerError.fromDetail(
+        TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
+        {
+          requestMethod: method,
+          requestUrl: url,
+          throttleStats: this.throttle.getThrottleStats(url),
+        },
+        `request to origin ${parsedUrl.origin} was throttled`,
+      );
+    }
+
+    let data: ArrayBuffer | undefined = undefined;
+    let headers: string[] = [];
+    if (opt?.headers) {
+      for (let headerName of Object.keys(opt.headers)) {
+        headers.push(`${headerName}: ${opt.headers[headerName]}`);
+      }
+    }
+    if (method.toUpperCase() === "POST") {
+      data = encodeBody(opt?.body);
+    }
+    const res = await qjsOs.fetchHttp(url, {
+      method,
+      data,
+      headers,
+    });
+    return {
+      requestMethod: method,
+      // FIXME: We don't return headers!
+      headers: new Headers(),
+      async bytes() {
+        return res.data;
+      },
+      json() {
+        const text = textDecoder.decode(res.data);
+        return JSON.parse(text);
+      },
+      async text() {
+        const text = textDecoder.decode(res.data);
+        return text;
+      },
+      requestUrl: url,
+      status: res.status,
+    };
+  }
+
+  async get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "GET",
+      ...opt,
+    });
+  }
+
+  async postJson(
+    url: string,
+    body: any,
+    opt?: HttpRequestOptions,
+  ): Promise<HttpResponse> {
+    return this.fetch(url, {
+      method: "POST",
+      body,
+      ...opt,
+    });
+  }
+}
diff --git a/packages/taler-wallet-core/src/index.browser.ts 
b/packages/taler-util/src/http.ts
similarity index 58%
copy from packages/taler-wallet-core/src/index.browser.ts
copy to packages/taler-util/src/http.ts
index 02d3665c2..725117140 100644
--- a/packages/taler-wallet-core/src/index.browser.ts
+++ b/packages/taler-util/src/http.ts
@@ -1,6 +1,6 @@
 /*
  This file is part of TALER
- (C) 2019 GNUnet e.V.
+ (C) 2016 GNUnet e.V.
 
  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
@@ -14,5 +14,23 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-export * from "./index.js";
-export { SynchronousCryptoWorkerPlain as SynchronousCryptoWorker } from 
"./crypto/workers/synchronousWorkerPlain.js";
+/**
+ * Helpers for doing XMLHttpRequest-s that are based on ES6 promises.
+ * Allows for easy mocking for test cases.
+ *
+ * The API is inspired by the HTML5 fetch API.
+ */
+
+/**
+ * Imports
+ */
+
+import * as impl from "#http-impl";
+import * as common from "./http-common.js";
+
+export * from "./http-common.js";
+
+
+export function createPlatformHttpLib(args?: common.HttpLibArgs): 
common.HttpRequestLibrary {
+  return new impl.HttpLibImpl(args);
+}
diff --git a/packages/taler-util/src/index.browser.ts 
b/packages/taler-util/src/index.browser.ts
index 3b8e194b3..ec77b10c0 100644
--- a/packages/taler-util/src/index.browser.ts
+++ b/packages/taler-util/src/index.browser.ts
@@ -19,3 +19,7 @@
 import { loadBrowserPrng } from "./prng-browser.js";
 loadBrowserPrng();
 export * from "./index.js";
+
+// The web stuff doesn't support package.json export declarations yet,
+// so we export more stuff here than we should.
+export * from "./http-common.js";
diff --git a/packages/taler-util/src/index.node.ts 
b/packages/taler-util/src/index.node.ts
index bd59f320a..018b4767f 100644
--- a/packages/taler-util/src/index.node.ts
+++ b/packages/taler-util/src/index.node.ts
@@ -21,4 +21,3 @@ initNodePrng();
 export * from "./index.js";
 export * from "./talerconfig.js";
 export * from "./globbing/minimatch.js";
-export { clk } from "./clk.js";
diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts
index 661b0332f..cf4f545a4 100644
--- a/packages/taler-util/src/index.ts
+++ b/packages/taler-util/src/index.ts
@@ -36,3 +36,4 @@ export * from "./CancellationToken.js";
 export * from "./contract-terms.js";
 export * from "./base64.js";
 export * from "./merchant-api-types.js";
+export * from "./errors.js";
diff --git a/packages/taler-util/src/qtart.ts b/packages/taler-util/src/qtart.ts
new file mode 100644
index 000000000..f8edf234e
--- /dev/null
+++ b/packages/taler-util/src/qtart.ts
@@ -0,0 +1,36 @@
+
+// @ts-ignore
+import * as _qjsOsImp from "os";
+// @ts-ignore
+import * as _qjsStdImp from "std";
+
+
+export interface QjsHttpResp {
+  status: number;
+  data: ArrayBuffer;
+}
+
+export interface QjsHttpOptions {
+  method: string;
+  debug?: boolean;
+  data?: ArrayBuffer;
+  headers?: string[];
+}
+
+
+export interface QjsOsLib {
+  fetchHttp(url: string, options?: QjsHttpOptions): Promise<QjsHttpResp>;
+  postMessageToHost(s: string): void;
+  setMessageFromHostHandler(h: (s: string) => void): void;
+  rename(oldPath: string, newPath: string): number;
+}
+
+export interface QjsStdLib {
+  writeFile(filename: string, contents: string): void;
+  loadFile(filename: string): string;
+}
+
+// This is not the nodejs "os" module, but the qjs "os" module.
+export const qjsOs: QjsOsLib = _qjsOsImp as any;
+
+export const qjsStd: QjsStdLib = _qjsStdImp as any;
\ No newline at end of file
diff --git a/packages/taler-util/src/twrpc-impl.missing.ts 
b/packages/taler-util/src/twrpc-impl.missing.ts
index d9ed37815..7d7fa84ae 100644
--- a/packages/taler-util/src/twrpc-impl.missing.ts
+++ b/packages/taler-util/src/twrpc-impl.missing.ts
@@ -14,4 +14,13 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import type { RpcConnectArgs, RpcServerArgs } from "./twrpc.js";
+
 // Not implemented.
+export async function connectRpc<T>(args: RpcConnectArgs<T>): Promise<T> {
+  throw Error("not implemented");
+}
+
+export async function runRpcServer(args: RpcServerArgs): Promise<void> {
+  throw Error("not implemented");
+}
diff --git a/packages/taler-wallet-cli/build.mjs 
b/packages/taler-wallet-cli/build.mjs
index 14b626815..b2ed2c937 100755
--- a/packages/taler-wallet-cli/build.mjs
+++ b/packages/taler-wallet-cli/build.mjs
@@ -53,7 +53,7 @@ function git_hash() {
 
 export const buildConfig = {
   entryPoints: ["src/index.ts"],
-  outfile: "dist/taler-wallet-cli.mjs",
+  outfile: "dist/taler-wallet-cli.qtart.mjs",
   bundle: true,
   minify: false,
   target: [
@@ -61,7 +61,11 @@ export const buildConfig = {
   ],
   format: 'esm',
   platform: 'neutral',
+  mainFields: ["module", "main"],
+  conditions: ["qtart"],
   sourcemap: true,
+  // quickjs standard library
+  external: ["std", "os"],
   define: {
     '__VERSION__': `"${_package.version}"`,
     '__GIT_HASH__': `"${GIT_HASH}"`,
diff --git a/packages/taler-wallet-cli/src/index.ts 
b/packages/taler-wallet-cli/src/index.ts
index 228395991..aed9a24c0 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -21,12 +21,11 @@ import {
   addPaytoQueryParams,
   AgeRestriction,
   classifyTalerUri,
-  clk,
   codecForList,
   codecForString,
   CoreApiResponse,
-  decodeCrock,
   encodeCrock,
+  getErrorDetailFromException,
   getRandomBytes,
   j2s,
   Logger,
@@ -35,20 +34,26 @@ import {
   RecoveryMergeStrategy,
   setDangerousTimetravel,
   setGlobalLogLevelFromString,
+  summarizeTalerErrorDetail,
   TalerUriType,
   WalletNotification,
 } from "@gnu-taler/taler-util";
+import { clk } from "@gnu-taler/taler-util/clk";
+import {
+  getenv,
+  pathHomedir,
+  processExit,
+  setUnhandledRejectionHandler,
+} from "@gnu-taler/taler-util/compat";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
 import { JsonMessage, runRpcServer } from "@gnu-taler/taler-util/twrpc";
 import {
+  createNativeWalletHost,
+  createNativeWalletHost2,
   CryptoDispatcher,
-  getDefaultNodeWallet,
-  getDefaultNodeWallet2,
-  getErrorDetailFromException,
   nativeCrypto,
-  NodeHttpLib,
-  NodeThreadCryptoWorkerFactory,
-  summarizeTalerErrorDetail,
-  SynchronousCryptoWorkerFactoryNode,
+  //NodeThreadCryptoWorkerFactory,
+  //SynchronousCryptoWorkerFactoryPlain,
   TalerCryptoInterface,
   Wallet,
   WalletApiOperation,
@@ -60,8 +65,6 @@ import {
   getClientFromRemoteWallet,
   makeNotificationWaiter,
 } from "@gnu-taler/taler-wallet-core/remote";
-import fs from "fs";
-import os from "os";
 
 // This module also serves as the entry point for the crypto
 // thread worker, and thus must expose these two handlers.
@@ -76,13 +79,13 @@ const EXIT_EXCEPTION = 4;
 const EXIT_API_ERROR = 5;
 const EXIT_RETRIES_EXCEEDED = 6;
 
-process.on("unhandledRejection", (error: any) => {
+setUnhandledRejectionHandler((error: any) => {
   logger.error("unhandledRejection", error.message);
   logger.error("stack", error.stack);
-  process.exit(2);
+  processExit(1);
 });
 
-const defaultWalletDbPath = os.homedir + "/" + ".talerwalletdb.json";
+const defaultWalletDbPath = pathHomedir() + "/" + ".talerwalletdb.json";
 
 function assertUnreachable(x: never): never {
   throw new Error("Didn't expect to get here");
@@ -99,7 +102,7 @@ async function doPay(
   if (result.status === PreparePayResultType.InsufficientBalance) {
     console.log("contract", result.contractTerms);
     console.error("insufficient balance");
-    process.exit(1);
+    processExit(1);
     return;
   }
   if (result.status === PreparePayResultType.AlreadyConfirmed) {
@@ -108,8 +111,7 @@ async function doPay(
     } else {
       console.log("payment already in progress");
     }
-
-    process.exit(0);
+    processExit(0);
     return;
   }
   if (result.status === "payment-possible") {
@@ -154,7 +156,7 @@ function applyVerbose(verbose: boolean): void {
 declare const __VERSION__: string;
 function printVersion(): void {
   console.log(__VERSION__);
-  process.exit(0);
+  processExit(0);
 }
 
 export const walletCli = clk
@@ -203,7 +205,7 @@ export const walletCli = clk
 type WalletCliArgsType = clk.GetArgType<typeof walletCli>;
 
 function checkEnvFlag(name: string): boolean {
-  const val = process.env[name];
+  const val = getenv(name);
   if (val == "1") {
     return true;
   }
@@ -238,11 +240,10 @@ async function createLocalWallet(
   notificationHandler?: (n: WalletNotification) => void,
 ): Promise<Wallet> {
   const dbPath = walletCliArgs.wallet.walletDbFile ?? defaultWalletDbPath;
-  const myHttpLib = new NodeHttpLib();
-  if (walletCliArgs.wallet.noThrottle) {
-    myHttpLib.setThrottling(false);
-  }
-  const wallet = await getDefaultNodeWallet({
+  const myHttpLib = createPlatformHttpLib({
+    enableThrottling: walletCliArgs.wallet.noThrottle ? false : true,
+  });
+  const wallet = await createNativeWalletHost({
     persistentStoragePath: dbPath !== ":memory:" ? dbPath : undefined,
     httpLib: myHttpLib,
     notifyHandler: (n) => {
@@ -268,7 +269,7 @@ async function createLocalWallet(
     const ed = getErrorDetailFromException(e);
     console.error("Operation failed: " + summarizeTalerErrorDetail(ed));
     console.error("Error details:", JSON.stringify(ed, undefined, 2));
-    process.exit(1);
+    processExit(1);
   } finally {
     logger.trace("operation with wallet finished, stopping");
     logger.trace("stopped wallet");
@@ -357,7 +358,7 @@ walletCli
         requestJson = JSON.parse(args.api.request);
       } catch (e) {
         console.error("Invalid JSON");
-        process.exit(1);
+        processExit(1);
       }
       try {
         const resp = await wallet.makeCoreApiRequest(
@@ -367,12 +368,12 @@ walletCli
         console.log(JSON.stringify(resp, undefined, 2));
         if (resp.type === "error") {
           if (args.api.expectSuccess) {
-            process.exit(EXIT_API_ERROR);
+            processExit(EXIT_API_ERROR);
           }
         }
       } catch (e) {
         logger.error(`Got exception while handling API request ${e}`);
-        process.exit(EXIT_EXCEPTION);
+        processExit(EXIT_EXCEPTION);
       }
     });
     logger.info("finished handling API request");
@@ -475,7 +476,7 @@ walletCli
       });
       wallet.ws.stop();
       if (resp.retriesExceeded && args.finishPendingOpt.failOnMaxRetries) {
-        process.exit(EXIT_RETRIES_EXCEEDED);
+        processExit(EXIT_RETRIES_EXCEEDED);
       }
     });
   });
@@ -594,7 +595,7 @@ walletCli
             const selectedExchange = withdrawInfo.defaultExchangeBaseUrl;
             if (!selectedExchange) {
               console.error("no suggested exchange!");
-              process.exit(1);
+              processExit(1);
               return;
             }
             const res = await wallet.client.call(
@@ -1014,9 +1015,10 @@ advancedCli
     help: "Run the 'bench-internal' benchmark",
   })
   .action(async (args) => {
-    const myHttpLib = new NodeHttpLib();
-    myHttpLib.setThrottling(false);
-    const res = await getDefaultNodeWallet2({
+    const myHttpLib = createPlatformHttpLib({
+      enableThrottling: false,
+    });
+    const res = await createNativeWalletHost2({
       // No persistent DB storage.
       persistentStoragePath: undefined,
       httpLib: myHttpLib,
@@ -1060,15 +1062,6 @@ advancedCli
     });
   });
 
-advancedCli
-  .subcommand("decode", "decode", {
-    help: "Decode base32-crockford.",
-  })
-  .action((args) => {
-    const enc = fs.readFileSync(0, "utf8");
-    console.log(decodeCrock(enc.trim()));
-  });
-
 advancedCli
   .subcommand("genSegwit", "gen-segwit")
   .requiredArgument("paytoUri", clk.STRING)
@@ -1229,7 +1222,7 @@ advancedCli
         );
       } catch (e: any) {
         console.log("could not parse coin list:", e.message);
-        process.exit(1);
+        processExit(1);
       }
       for (const c of coinPubList) {
         await wallet.client.call(WalletApiOperation.SetCoinSuspended, {
@@ -1254,7 +1247,7 @@ advancedCli
         );
       } catch (e: any) {
         console.log("could not parse coin list:", e.message);
-        process.exit(1);
+        processExit(1);
       }
       for (const c of coinPubList) {
         await wallet.client.call(WalletApiOperation.SetCoinSuspended, {
@@ -1420,33 +1413,33 @@ async function read(stream: NodeJS.ReadStream) {
   return Buffer.concat(chunks).toString("utf8");
 }
 
-testCli
-  .subcommand("cryptoworker", "cryptoworker")
-  .maybeOption("impl", ["--impl"], clk.STRING)
-  .action(async (args) => {
-    let cryptoApi: TalerCryptoInterface;
-    if (!args.cryptoworker.impl || args.cryptoworker.impl === "node") {
-      const workerFactory = new NodeThreadCryptoWorkerFactory();
-      const cryptoDisp = new CryptoDispatcher(workerFactory);
-      cryptoApi = cryptoDisp.cryptoApi;
-    } else if (args.cryptoworker.impl === "sync") {
-      const workerFactory = new SynchronousCryptoWorkerFactoryNode();
-      const cryptoDisp = new CryptoDispatcher(workerFactory);
-      cryptoApi = cryptoDisp.cryptoApi;
-    } else if (args.cryptoworker.impl === "none") {
-      cryptoApi = nativeCrypto;
-    } else {
-      throw Error(`invalid crypto worker type ${args.cryptoworker.impl}`);
-    }
-
-    const input = "foo";
-    console.log(`testing crypto worker by hashing string '${input}'`);
-    const res = await cryptoApi.hashString({ str: input });
-    console.log(res);
-  });
+// testCli
+//   .subcommand("cryptoworker", "cryptoworker")
+//   .maybeOption("impl", ["--impl"], clk.STRING)
+//   .action(async (args) => {
+//     let cryptoApi: TalerCryptoInterface;
+//     if (!args.cryptoworker.impl || args.cryptoworker.impl === "node") {
+//       const workerFactory = new NodeThreadCryptoWorkerFactory();
+//       const cryptoDisp = new CryptoDispatcher(workerFactory);
+//       cryptoApi = cryptoDisp.cryptoApi;
+//     } else if (args.cryptoworker.impl === "sync") {
+//       const workerFactory = new SynchronousCryptoWorkerFactoryPlain();
+//       const cryptoDisp = new CryptoDispatcher(workerFactory);
+//       cryptoApi = cryptoDisp.cryptoApi;
+//     } else if (args.cryptoworker.impl === "none") {
+//       cryptoApi = nativeCrypto;
+//     } else {
+//       throw Error(`invalid crypto worker type ${args.cryptoworker.impl}`);
+//     }
+
+//     const input = "foo";
+//     console.log(`testing crypto worker by hashing string '${input}'`);
+//     const res = await cryptoApi.hashString({ str: input });
+//     console.log(res);
+//   });
 
 export function main() {
-  if (process.env["TALER_WALLET_DEBUG_DENOMSEL_ALLOW_LATE"]) {
+  if (getenv("TALER_WALLET_DEBUG_DENOMSEL_ALLOW_LATE")) {
     logger.warn("Allowing withdrawal of late denominations for debugging");
     walletCoreDebugFlags.denomselAllowLate = true;
   }
diff --git a/packages/taler-wallet-core/package.json 
b/packages/taler-wallet-core/package.json
index 4f1692872..14c407e99 100644
--- a/packages/taler-wallet-core/package.json
+++ b/packages/taler-wallet-core/package.json
@@ -38,7 +38,15 @@
       "default": "./lib/index.js"
     },
     "./remote": {
-      "node": "./lib/remote.js"
+      "default": "./lib/remote.js"
+    }
+  },
+  "imports": {
+    "#host-impl": {
+      "types": "./lib/host-impl.node.js",
+      "node": "./lib/host-impl.node.js",
+      "qtart": "./lib/host-impl.qtart.js",
+      "default": "./lib/host-impl.missing.js"
     }
   },
   "devDependencies": {
diff --git a/packages/taler-wallet-core/src/bank-api-client.ts 
b/packages/taler-wallet-core/src/bank-api-client.ts
index dc7845150..addec709f 100644
--- a/packages/taler-wallet-core/src/bank-api-client.ts
+++ b/packages/taler-wallet-core/src/bank-api-client.ts
@@ -33,13 +33,10 @@ import {
   j2s,
   Logger,
   stringToBytes,
+  TalerError,
   TalerErrorCode,
 } from "@gnu-taler/taler-util";
-import { TalerError } from "./errors.js";
-import {
-  HttpRequestLibrary,
-  readSuccessResponseJsonOrThrow,
-} from "./util/http.js";
+import { HttpRequestLibrary, readSuccessResponseJsonOrThrow } from 
"@gnu-taler/taler-util/http";
 
 const logger = new Logger("bank-api-client.ts");
 
diff --git 
a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts 
b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts
index d8d53a839..1e9d82f66 100644
--- a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts
@@ -21,8 +21,6 @@ import {
   CryptoWorker,
   CryptoWorkerResponseMessage,
 } from "./cryptoWorkerInterface.js";
-import { SynchronousCryptoWorkerFactoryNode } from 
"./synchronousWorkerFactoryNode.js";
-import { processRequestWithImpl } from "./worker-common.js";
 
 export class MyCryptoWorker implements CryptoWorker {
   /**
diff --git a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts 
b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts
index f086691e5..192e9cda1 100644
--- a/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts
@@ -24,7 +24,7 @@
  * Imports.
  */
 import { j2s, Logger, TalerErrorCode } from "@gnu-taler/taler-util";
-import { TalerError } from "../../errors.js";
+import { TalerError } from "@gnu-taler/taler-util";
 import { openPromise } from "../../util/promiseUtils.js";
 import { timer, performanceNow, TimerHandle } from "../../util/timer.js";
 import { nullCrypto, TalerCryptoInterface } from "../cryptoImplementation.js";
diff --git a/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts 
b/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts
deleted file mode 100644
index 21d88fffa..000000000
--- a/packages/taler-wallet-core/src/crypto/workers/rpcClient.ts
+++ /dev/null
@@ -1,92 +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/>
- */
-
-/**
- * Imports.
- */
-import { Logger } from "@gnu-taler/taler-util";
-import child_process from "child_process";
-import type internal from "stream";
-import { OpenedPromise, openPromise } from "../../util/promiseUtils.js";
-
-const logger = new Logger("synchronousWorkerFactory.ts");
-
-/**
- * Client for the crypto helper process (taler-crypto-worker from 
exchange.git).
- */
-export class CryptoRpcClient {
-  proc: child_process.ChildProcessByStdio<
-    internal.Writable,
-    internal.Readable,
-    null
-  >;
-  requests: Array<{
-    p: OpenedPromise<any>;
-    req: any;
-  }> = [];
-
-  constructor() {
-    const stdoutChunks: Buffer[] = [];
-    this.proc = child_process.spawn("taler-crypto-worker", {
-      //stdio: ["pipe", "pipe", "inherit"],
-      stdio: ["pipe", "pipe", "inherit"],
-      detached: true,
-    });
-    this.proc.on("close", (): void => {
-      logger.error("child process exited");
-    });
-    (this.proc.stdout as any).unref();
-    (this.proc.stdin as any).unref();
-    this.proc.unref();
-
-    this.proc.stdout.on("data", (x) => {
-      if (x instanceof Buffer) {
-        const nlIndex = x.indexOf("\n");
-        if (nlIndex >= 0) {
-          const before = x.slice(0, nlIndex);
-          const after = x.slice(nlIndex + 1);
-          stdoutChunks.push(after);
-          const str = Buffer.concat([...stdoutChunks, before]).toString(
-            "utf-8",
-          );
-          const req = this.requests.shift();
-          if (!req) {
-            throw Error("request was undefined");
-          }
-          if (this.requests.length === 0) {
-            this.proc.unref();
-          }
-          //logger.info(`got response: ${str}`);
-          req.p.resolve(JSON.parse(str));
-        } else {
-          stdoutChunks.push(x);
-        }
-      } else {
-        throw Error(`unexpected data chunk type (${typeof x})`);
-      }
-    });
-  }
-
-  async queueRequest(req: any): Promise<any> {
-    const p = openPromise<any>();
-    if (this.requests.length === 0) {
-      this.proc.ref();
-    }
-    this.requests.push({ req, p });
-    this.proc.stdin.write(`${JSON.stringify(req)}\n`);
-    return p.promise;
-  }
-}
diff --git 
a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts 
b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts
deleted file mode 100644
index 90f9a43fa..000000000
--- 
a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- 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/>
- */
-
-/**
- * Imports.
- */
-import { CryptoWorkerFactory } from "./crypto-dispatcher.js";
-import { CryptoWorker } from "./cryptoWorkerInterface.js";
-import { SynchronousCryptoWorkerNode } from "./synchronousWorkerNode.js";
-
-/**
- * The synchronous crypto worker produced by this factory doesn't run in the
- * background, but actually blocks the caller until the operation is done.
- */
-export class SynchronousCryptoWorkerFactoryNode implements CryptoWorkerFactory 
{
-  startWorker(): CryptoWorker {
-    return new SynchronousCryptoWorkerNode();
-  }
-
-  getConcurrency(): number {
-    return 1;
-  }
-}
diff --git 
a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts 
b/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts
deleted file mode 100644
index b2653158c..000000000
--- a/packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- 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 { j2s, Logger } from "@gnu-taler/taler-util";
-import {
-  nativeCryptoR,
-  TalerCryptoInterfaceR,
-} from "../cryptoImplementation.js";
-import { CryptoWorker } from "./cryptoWorkerInterface.js";
-import { CryptoRpcClient } from "./rpcClient.js";
-import { processRequestWithImpl } from "./worker-common.js";
-
-const logger = new Logger("synchronousWorker.ts");
-
-/**
- * Worker implementation that uses node subprocesses.
- *
- * The node crypto worker can also use IPC to offload cryptographic
- * operations to a helper process (usually written in C / part of 
taler-exchange).
- */
-export class SynchronousCryptoWorkerNode implements CryptoWorker {
-  /**
-   * Function to be called when we receive a message from the worker thread.
-   */
-  onmessage: undefined | ((m: any) => void);
-
-  /**
-   * Function to be called when we receive an error from the worker thread.
-   */
-  onerror: undefined | ((m: any) => void);
-
-  cryptoImplR: TalerCryptoInterfaceR;
-
-  rpcClient: CryptoRpcClient | undefined;
-
-  constructor() {
-    this.onerror = undefined;
-    this.onmessage = undefined;
-
-    this.cryptoImplR = { ...nativeCryptoR };
-
-    if (process.env["TALER_WALLET_PRIMITIVE_WORKER"]) {
-      logger.info("using RPC for some crypto operations");
-      const rpc = (this.rpcClient = new CryptoRpcClient());
-      this.cryptoImplR.eddsaSign = async (_, req) => {
-        return await rpc.queueRequest({
-          op: "eddsa_sign",
-          args: {
-            msg: req.msg,
-            priv: req.priv,
-          },
-        });
-      };
-      this.cryptoImplR.setupRefreshPlanchet = async (_, req) => {
-        const res = await rpc.queueRequest({
-          op: "setup_refresh_planchet",
-          args: {
-            coin_index: req.coinNumber,
-            transfer_secret: req.transferSecret,
-          },
-        });
-        return {
-          bks: res.blinding_key,
-          coinPriv: res.coin_priv,
-          coinPub: res.coin_pub,
-        };
-      };
-      this.cryptoImplR.rsaBlind = async (_, req) => {
-        const res = await rpc.queueRequest({
-          op: "rsa_blind",
-          args: {
-            bks: req.bks,
-            hm: req.hm,
-            pub: req.pub,
-          },
-        });
-        return {
-          blinded: res.blinded,
-        };
-      };
-      this.cryptoImplR.keyExchangeEcdheEddsa = async (_, req) => {
-        const res = await rpc.queueRequest({
-          op: "kx_ecdhe_eddsa",
-          args: {
-            ecdhe_priv: req.ecdhePriv,
-            eddsa_pub: req.eddsaPub,
-          },
-        });
-        return {
-          h: res.h,
-        };
-      };
-      this.cryptoImplR.eddsaGetPublic = async (_, req) => {
-        const res = await rpc.queueRequest({
-          op: "eddsa_get_public",
-          args: {
-            eddsa_priv: req.priv,
-          },
-        });
-        return {
-          pub: res.eddsa_pub,
-        };
-      };
-      this.cryptoImplR.ecdheGetPublic = async (_, req) => {
-        const res = await rpc.queueRequest({
-          op: "ecdhe_get_public",
-          args: {
-            ecdhe_priv: req.priv,
-          },
-        });
-        return {
-          pub: res.ecdhe_pub,
-        };
-      };
-    }
-  }
-
-  /**
-   * Add an event listener for either an "error" or "message" event.
-   */
-  addEventListener(event: "message" | "error", fn: (x: any) => void): void {
-    switch (event) {
-      case "message":
-        this.onmessage = fn;
-        break;
-      case "error":
-        this.onerror = fn;
-        break;
-    }
-  }
-
-  private dispatchMessage(msg: any): void {
-    if (this.onmessage) {
-      this.onmessage(msg);
-    }
-  }
-
-  /**
-   * Send a message to the worker thread.
-   */
-  postMessage(msg: any): void {
-    const handleRequest = async () => {
-      const responseMsg = await processRequestWithImpl(msg, this.cryptoImplR);
-      try {
-        setTimeout(() => this.dispatchMessage(responseMsg), 0);
-      } catch (e) {
-        logger.error("got error during dispatch", e);
-      }
-    };
-    handleRequest().catch((e) => {
-      logger.error("Error while handling crypto request:", e);
-    });
-  }
-
-  /**
-   * Forcibly terminate the worker thread.
-   */
-  terminate(): void {
-    // This is a no-op.
-  }
-}
diff --git a/packages/taler-wallet-core/src/crypto/workers/worker-common.ts 
b/packages/taler-wallet-core/src/crypto/workers/worker-common.ts
index 8a74a5231..9f23cf685 100644
--- a/packages/taler-wallet-core/src/crypto/workers/worker-common.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/worker-common.ts
@@ -23,7 +23,7 @@ import {
   stringifyError as safeStringifyError,
   TalerErrorCode,
 } from "@gnu-taler/taler-util";
-import { getErrorDetailFromException, makeErrorDetail } from "../../errors.js";
+import { getErrorDetailFromException, makeErrorDetail } from 
"@gnu-taler/taler-util";
 import { TalerCryptoInterfaceR } from "../cryptoImplementation.js";
 import {
   CryptoWorkerRequestMessage,
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 8bb8d519f..75e6408f7 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -2659,6 +2659,9 @@ function onMetaDbUpgradeNeeded(
 /**
  * Return a promise that resolves
  * to the taler wallet db.
+ *
+ * @param onVersionChange Called when another client concurrenctly connects to 
the database
+ * with a higher version.
  */
 export async function openTalerDatabase(
   idbFactory: IDBFactory,
diff --git a/packages/taler-wallet-core/src/dbless.ts 
b/packages/taler-wallet-core/src/dbless.ts
index 544e2d458..99596edd8 100644
--- a/packages/taler-wallet-core/src/dbless.ts
+++ b/packages/taler-wallet-core/src/dbless.ts
@@ -58,7 +58,7 @@ import {
 import {
   HttpRequestLibrary,
   readSuccessResponseJsonOrThrow,
-} from "./util/http.js";
+} from "@gnu-taler/taler-util/http";
 import {
   getBankStatusUrl,
   getBankWithdrawalInfo,
diff --git a/packages/taler-wallet-core/src/dev-experiments.ts 
b/packages/taler-wallet-core/src/dev-experiments.ts
index 6c36d6f6c..3e6194ccd 100644
--- a/packages/taler-wallet-core/src/dev-experiments.ts
+++ b/packages/taler-wallet-core/src/dev-experiments.ts
@@ -32,7 +32,7 @@ import {
   HttpRequestLibrary,
   HttpRequestOptions,
   HttpResponse,
-} from "./util/http.js";
+} from "@gnu-taler/taler-util/http";
 
 const logger = new Logger("dev-experiments.ts");
 
diff --git a/packages/taler-wallet-core/src/headless/NodeHttpLib.ts 
b/packages/taler-wallet-core/src/headless/NodeHttpLib.ts
deleted file mode 100644
index c1d42796d..000000000
--- a/packages/taler-wallet-core/src/headless/NodeHttpLib.ts
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 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/>
-
- SPDX-License-Identifier: AGPL3.0-or-later
-*/
-
-/**
- * Imports.
- */
-import {
-  DEFAULT_REQUEST_TIMEOUT_MS,
-  Headers,
-  HttpRequestLibrary,
-  HttpRequestOptions,
-  HttpResponse,
-} from "../util/http.js";
-import { RequestThrottler } from "@gnu-taler/taler-util";
-import axios, { AxiosResponse } from "axios";
-import { TalerError } from "../errors.js";
-import { Logger, bytesToString } from "@gnu-taler/taler-util";
-import { TalerErrorCode, URL } from "@gnu-taler/taler-util";
-
-const logger = new Logger("NodeHttpLib.ts");
-
-/**
- * Implementation of the HTTP request library interface for node.
- */
-export class NodeHttpLib implements HttpRequestLibrary {
-  private throttle = new RequestThrottler();
-  private throttlingEnabled = true;
-
-  /**
-   * Set whether requests should be throttled.
-   */
-  setThrottling(enabled: boolean): void {
-    this.throttlingEnabled = enabled;
-  }
-
-  async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
-    const method = opt?.method ?? "GET";
-    let body = opt?.body;
-
-    logger.trace(`Requesting ${method} ${url}`);
-
-    const parsedUrl = new URL(url);
-    if (this.throttlingEnabled && this.throttle.applyThrottle(url)) {
-      throw TalerError.fromDetail(
-        TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
-        {
-          requestMethod: method,
-          requestUrl: url,
-          throttleStats: this.throttle.getThrottleStats(url),
-        },
-        `request to origin ${parsedUrl.origin} was throttled`,
-      );
-    }
-    let timeoutMs: number | undefined;
-    if (typeof opt?.timeout?.d_ms === "number") {
-      timeoutMs = opt.timeout.d_ms;
-    } else {
-      timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
-    }
-    // FIXME: Use AbortController / etc. to handle cancellation
-    let resp: AxiosResponse;
-    try {
-      let respPromise = axios.default({
-        method,
-        url: url,
-        responseType: "arraybuffer",
-        headers: opt?.headers,
-        validateStatus: () => true,
-        transformResponse: (x) => x,
-        data: body,
-        timeout: timeoutMs,
-        maxRedirects: 0,
-      });
-      if (opt?.cancellationToken) {
-        respPromise = opt.cancellationToken.racePromise(respPromise);
-      }
-      resp = await respPromise;
-    } catch (e: any) {
-      throw TalerError.fromDetail(
-        TalerErrorCode.WALLET_NETWORK_ERROR,
-        {
-          requestUrl: url,
-          requestMethod: method,
-        },
-        `${e.message}`,
-      );
-    }
-
-    const makeText = async (): Promise<string> => {
-      opt?.cancellationToken?.throwIfCancelled();
-      const respText = new Uint8Array(resp.data);
-      return bytesToString(respText);
-    };
-
-    const makeJson = async (): Promise<any> => {
-      opt?.cancellationToken?.throwIfCancelled();
-      let responseJson;
-      const respText = await makeText();
-      try {
-        responseJson = JSON.parse(respText);
-      } catch (e) {
-        logger.trace(`invalid json: '${resp.data}'`);
-        throw TalerError.fromDetail(
-          TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
-          {
-            httpStatusCode: resp.status,
-            requestUrl: url,
-            requestMethod: method,
-          },
-          "Could not parse response body as JSON",
-        );
-      }
-      if (responseJson === null || typeof responseJson !== "object") {
-        logger.trace(`invalid json (not an object): '${respText}'`);
-        throw TalerError.fromDetail(
-          TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
-          {
-            httpStatusCode: resp.status,
-            requestUrl: url,
-            requestMethod: method,
-          },
-          `invalid JSON`,
-        );
-      }
-      return responseJson;
-    };
-    const makeBytes = async () => {
-      opt?.cancellationToken?.throwIfCancelled();
-      if (typeof resp.data.byteLength !== "number") {
-        throw Error("expected array buffer");
-      }
-      const buf = resp.data;
-      return buf;
-    };
-    const headers = new Headers();
-    for (const hn of Object.keys(resp.headers)) {
-      headers.set(hn, resp.headers[hn]);
-    }
-    return {
-      requestUrl: url,
-      requestMethod: method,
-      headers,
-      status: resp.status,
-      text: makeText,
-      json: makeJson,
-      bytes: makeBytes,
-    };
-  }
-
-  async get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
-    return this.fetch(url, {
-      method: "GET",
-      ...opt,
-    });
-  }
-
-  async postJson(
-    url: string,
-    body: any,
-    opt?: HttpRequestOptions,
-  ): Promise<HttpResponse> {
-    return this.fetch(url, {
-      method: "POST",
-      body,
-      ...opt,
-    });
-  }
-}
diff --git a/packages/taler-wallet-core/src/host-common.ts 
b/packages/taler-wallet-core/src/host-common.ts
new file mode 100644
index 000000000..7651e5a12
--- /dev/null
+++ b/packages/taler-wallet-core/src/host-common.ts
@@ -0,0 +1,60 @@
+/*
+ This file is part of GNU Taler
+ (C) 2019 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 { WalletNotification } from "@gnu-taler/taler-util";
+import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
+
+/**
+ * Helpers to initiate a wallet in a host environment.
+ */
+
+/**
+ */
+export interface DefaultNodeWalletArgs {
+  /**
+   * Location of the wallet database.
+   *
+   * If not specified, the wallet starts out with an empty database and
+   * the wallet database is stored only in memory.
+   */
+  persistentStoragePath?: string;
+
+  /**
+   * Handler for asynchronous notifications from the wallet.
+   */
+  notifyHandler?: (n: WalletNotification) => void;
+
+  /**
+   * If specified, use this as HTTP request library instead
+   * of the default one.
+   */
+  httpLib?: HttpRequestLibrary;
+
+  cryptoWorkerType?: "sync" | "node-worker-thread";
+}
+
+/**
+ * Generate a random alphanumeric ID.  Does *not* use cryptographically
+ * secure randomness.
+ */
+export function makeTempfileId(length: number): string {
+  let result = "";
+  const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
+  for (let i = 0; i < length; i++) {
+    result += characters.charAt(Math.floor(Math.random() * characters.length));
+  }
+  return result;
+}
diff --git a/packages/taler-wallet-core/src/headless/helpers.ts 
b/packages/taler-wallet-core/src/host-impl.node.ts
similarity index 67%
rename from packages/taler-wallet-core/src/headless/helpers.ts
rename to packages/taler-wallet-core/src/host-impl.node.ts
index fbeb84c67..ec57e0ebe 100644
--- a/packages/taler-wallet-core/src/headless/helpers.ts
+++ b/packages/taler-wallet-core/src/host-impl.node.ts
@@ -30,70 +30,27 @@ import {
   shimIndexedDB,
 } from "@gnu-taler/idb-bridge";
 import { AccessStats } from "@gnu-taler/idb-bridge";
-import { Logger, WalletNotification } from "@gnu-taler/taler-util";
+import { Logger } from "@gnu-taler/taler-util";
 import * as fs from "fs";
-import { NodeThreadCryptoWorkerFactory } from 
"../crypto/workers/nodeThreadWorker.js";
-import { SynchronousCryptoWorkerFactoryNode } from 
"../crypto/workers/synchronousWorkerFactoryNode.js";
-import { openTalerDatabase } from "../index.js";
-import { HttpRequestLibrary } from "../util/http.js";
-import { SetTimeoutTimerAPI } from "../util/timer.js";
-import { Wallet } from "../wallet.js";
-import { NodeHttpLib } from "./NodeHttpLib.js";
-
-const logger = new Logger("headless/helpers.ts");
-
-export interface DefaultNodeWalletArgs {
-  /**
-   * Location of the wallet database.
-   *
-   * If not specified, the wallet starts out with an empty database and
-   * the wallet database is stored only in memory.
-   */
-  persistentStoragePath?: string;
-
-  /**
-   * Handler for asynchronous notifications from the wallet.
-   */
-  notifyHandler?: (n: WalletNotification) => void;
-
-  /**
-   * If specified, use this as HTTP request library instead
-   * of the default one.
-   */
-  httpLib?: HttpRequestLibrary;
-
-  cryptoWorkerType?: "sync" | "node-worker-thread";
-}
+import { NodeThreadCryptoWorkerFactory } from 
"./crypto/workers/nodeThreadWorker.js";
+import { SynchronousCryptoWorkerFactoryPlain } from 
"./crypto/workers/synchronousWorkerFactoryPlain.js";
+import { openTalerDatabase } from "./index.js";
+import {
+  createPlatformHttpLib,
+} from "@gnu-taler/taler-util/http";
+import { SetTimeoutTimerAPI } from "./util/timer.js";
+import { Wallet } from "./wallet.js";
+import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js";
 
-/**
- * Generate a random alphanumeric ID.  Does *not* use cryptographically
- * secure randomness.
- */
-function makeId(length: number): string {
-  let result = "";
-  const characters = "abcdefghijklmnopqrstuvwxyz0123456789";
-  for (let i = 0; i < length; i++) {
-    result += characters.charAt(Math.floor(Math.random() * characters.length));
-  }
-  return result;
-}
+const logger = new Logger("host-impl.node.ts");
 
-/**
- * Get a wallet instance with default settings for node.
- */
-export async function getDefaultNodeWallet(
-  args: DefaultNodeWalletArgs = {},
-): Promise<Wallet> {
-  const res = await getDefaultNodeWallet2(args);
-  return res.wallet;
-}
 
 /**
  * Get a wallet instance with default settings for node.
  *
  * Extended version that allows getting DB stats.
  */
-export async function getDefaultNodeWallet2(
+export async function createNativeWalletHost2(
   args: DefaultNodeWalletArgs = {},
 ): Promise<{
   wallet: Wallet;
@@ -127,7 +84,8 @@ export async function getDefaultNodeWallet2(
       if (args.persistentStoragePath === undefined) {
         return;
       }
-      const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`;
+      const tmpPath = `${args.persistentStoragePath}-${makeTempfileId(5)}.tmp`;
+      logger.trace("exported DB dump");
       const dbContent = myBackend.exportDump();
       fs.writeFileSync(tmpPath, JSON.stringify(dbContent, undefined, 2), {
         encoding: "utf-8",
@@ -147,7 +105,9 @@ export async function getDefaultNodeWallet2(
   if (args.httpLib) {
     myHttpLib = args.httpLib;
   } else {
-    myHttpLib = new NodeHttpLib();
+    myHttpLib = createPlatformHttpLib({
+      enableThrottling: true,
+    });
   }
 
   const myVersionChange = (): Promise<void> => {
@@ -165,7 +125,7 @@ export async function getDefaultNodeWallet2(
   const cryptoWorkerType = args.cryptoWorkerType ?? "node-worker-thread";
   if (cryptoWorkerType === "sync") {
     logger.info("using synchronous crypto worker");
-    workerFactory = new SynchronousCryptoWorkerFactoryNode();
+    workerFactory = new SynchronousCryptoWorkerFactoryPlain();
   } else if (cryptoWorkerType === "node-worker-thread") {
     try {
       // Try if we have worker threads available, fails in older node versions.
@@ -179,7 +139,7 @@ export async function getDefaultNodeWallet2(
       logger.warn(
         "worker threads not available, falling back to synchronous workers",
       );
-      workerFactory = new SynchronousCryptoWorkerFactoryNode();
+      workerFactory = new SynchronousCryptoWorkerFactoryPlain();
     }
   } else {
     throw Error(`unsupported crypto worker type '${cryptoWorkerType}'`);
diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts 
b/packages/taler-wallet-core/src/host-impl.qtart.ts
new file mode 100644
index 000000000..337914292
--- /dev/null
+++ b/packages/taler-wallet-core/src/host-impl.qtart.ts
@@ -0,0 +1,120 @@
+/*
+ This file is part of GNU Taler
+ (C) 2019 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/>
+ */
+
+/**
+ * Helpers to create headless wallets.
+ * @author Florian Dold <dold@taler.net>
+ */
+
+/**
+ * Imports.
+ */
+import type { IDBFactory } from "@gnu-taler/idb-bridge";
+// eslint-disable-next-line no-duplicate-imports
+import {
+  BridgeIDBFactory,
+  MemoryBackend,
+  shimIndexedDB,
+} from "@gnu-taler/idb-bridge";
+import { AccessStats } from "@gnu-taler/idb-bridge";
+import { SynchronousCryptoWorkerFactoryPlain } from 
"./crypto/workers/synchronousWorkerFactoryPlain.js";
+import { openTalerDatabase } from "./index.js";
+import { Logger } from "@gnu-taler/taler-util";
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
+import { SetTimeoutTimerAPI } from "./util/timer.js";
+import { Wallet } from "./wallet.js";
+import { qjsOs, qjsStd } from "@gnu-taler/taler-util/qtart";
+import { DefaultNodeWalletArgs, makeTempfileId } from "./host-common.js";
+
+const logger = new Logger("host-impl.qtart.ts");
+
+export async function createNativeWalletHost2(
+  args: DefaultNodeWalletArgs = {},
+): Promise<{
+  wallet: Wallet;
+  getDbStats: () => AccessStats;
+}> {
+  BridgeIDBFactory.enableTracing = false;
+  const myBackend = new MemoryBackend();
+  myBackend.enableTracing = false;
+
+  const storagePath = args.persistentStoragePath;
+  if (storagePath) {
+    const dbContentStr = qjsStd.loadFile(storagePath);
+    if (dbContentStr != null) {
+      const dbContent = JSON.parse(dbContentStr);
+      myBackend.importDump(dbContent);
+    }
+
+    myBackend.afterCommitCallback = async () => {
+      logger.trace("committing database");
+      // Allow caller to stop persisting the wallet.
+      if (args.persistentStoragePath === undefined) {
+        return;
+      }
+      const tmpPath = `${args.persistentStoragePath}-${makeTempfileId(5)}.tmp`;
+      const dbContent = myBackend.exportDump();
+      logger.trace("exported DB dump");
+      qjsStd.writeFile(tmpPath, JSON.stringify(dbContent, undefined, 2));
+      // Atomically move the temporary file onto the DB path.
+      const res = qjsOs.rename(tmpPath, args.persistentStoragePath);
+      if (res != 0) {
+        throw Error("db commit failed at rename");
+      }
+      logger.trace("committing database done");
+    };
+  }
+
+  logger.info("done processing storage path");
+
+  BridgeIDBFactory.enableTracing = false;
+
+  const myBridgeIdbFactory = new BridgeIDBFactory(myBackend);
+  const myIdbFactory: IDBFactory = myBridgeIdbFactory as any as IDBFactory;
+
+  let myHttpLib;
+  if (args.httpLib) {
+    myHttpLib = args.httpLib;
+  } else {
+    myHttpLib = createPlatformHttpLib();
+  }
+
+  const myVersionChange = (): Promise<void> => {
+    logger.error("version change requested, should not happen");
+    throw Error(
+      "BUG: wallet DB version change event can't happen with memory IDB",
+    );
+  };
+
+  shimIndexedDB(myBridgeIdbFactory);
+
+  const myDb = await openTalerDatabase(myIdbFactory, myVersionChange);
+
+  let workerFactory;
+  workerFactory = new SynchronousCryptoWorkerFactoryPlain();
+
+  const timer = new SetTimeoutTimerAPI();
+
+  const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory);
+
+  if (args.notifyHandler) {
+    w.addNotificationListener(args.notifyHandler);
+  }
+  return {
+    wallet: w,
+    getDbStats: () => myBackend.accessStats,
+  };
+}
diff --git a/packages/taler-util/src/ReserveStatus.ts 
b/packages/taler-wallet-core/src/host.ts
similarity index 51%
copy from packages/taler-util/src/ReserveStatus.ts
copy to packages/taler-wallet-core/src/host.ts
index be9fa9e8e..4b319f081 100644
--- a/packages/taler-util/src/ReserveStatus.ts
+++ b/packages/taler-wallet-core/src/host.ts
@@ -14,38 +14,34 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { DefaultNodeWalletArgs } from "./host-common.js";
+import { Wallet } from "./index.js";
+
+import * as hostImpl from "#host-impl";
+import { AccessStats } from "@gnu-taler/idb-bridge";
+
 /**
- * @author Florian Dold <dold@taler.net>
+ * Helpers to initiate a wallet in a host environment.
  */
 
 /**
- * Imports.
+ * Get a wallet instance.
  */
-import {
-  codecForString,
-  buildCodecForObject,
-  codecForList,
-  Codec,
-} from "./codec.js";
-import { AmountString } from "./taler-types.js";
-import {
-  ReserveTransaction,
-  codecForReserveTransaction,
-} from "./ReserveTransaction.js";
+export async function createNativeWalletHost2(
+  args: DefaultNodeWalletArgs = {},
+): Promise<{
+  wallet: Wallet;
+  getDbStats: () => AccessStats;
+}> {
+  return hostImpl.createNativeWalletHost2(args);
+}
 
 /**
- * Status of a reserve.
- *
- * Schema type for the exchange's response to "/reserve/status".
+ * Get a wallet instance.
  */
-export interface ReserveStatus {
-  /**
-   * Balance left in the reserve.
-   */
-  balance: AmountString;
+export async function createNativeWalletHost(
+  args: DefaultNodeWalletArgs = {},
+): Promise<Wallet> {
+  const res = await hostImpl.createNativeWalletHost2(args);
+  return res.wallet;
 }
-
-export const codecForReserveStatus = (): Codec<ReserveStatus> =>
-  buildCodecForObject<ReserveStatus>()
-    .property("balance", codecForString())
-    .build("ReserveStatus");
diff --git a/packages/taler-wallet-core/src/index.browser.ts 
b/packages/taler-wallet-core/src/index.browser.ts
index 02d3665c2..9409673a0 100644
--- a/packages/taler-wallet-core/src/index.browser.ts
+++ b/packages/taler-wallet-core/src/index.browser.ts
@@ -15,4 +15,4 @@
  */
 
 export * from "./index.js";
-export { SynchronousCryptoWorkerPlain as SynchronousCryptoWorker } from 
"./crypto/workers/synchronousWorkerPlain.js";
+export { SynchronousCryptoWorkerPlain } from 
"./crypto/workers/synchronousWorkerPlain.js";
diff --git a/packages/taler-wallet-core/src/index.node.ts 
b/packages/taler-wallet-core/src/index.node.ts
index 8567d13ac..13392d39c 100644
--- a/packages/taler-wallet-core/src/index.node.ts
+++ b/packages/taler-wallet-core/src/index.node.ts
@@ -16,15 +16,8 @@
 
 export * from "./index.js";
 
-// Utils for using the wallet under node
-export { NodeHttpLib } from "./headless/NodeHttpLib.js";
-export {
-  getDefaultNodeWallet,
-  getDefaultNodeWallet2,
-  DefaultNodeWalletArgs,
-} from "./headless/helpers.js";
 export * from "./crypto/workers/nodeThreadWorker.js";
-export { SynchronousCryptoWorkerNode as SynchronousCryptoWorker } from 
"./crypto/workers/synchronousWorkerNode.js";
+export { SynchronousCryptoWorkerPlain } from 
"./crypto/workers/synchronousWorkerPlain.js";
 
 export type { AccessStats } from "@gnu-taler/idb-bridge";
-export * from "./crypto/workers/synchronousWorkerFactoryNode.js";
+export * from "./crypto/workers/synchronousWorkerFactoryPlain.js";
diff --git a/packages/taler-wallet-core/src/index.ts 
b/packages/taler-wallet-core/src/index.ts
index 031656a6c..7b21d8f91 100644
--- a/packages/taler-wallet-core/src/index.ts
+++ b/packages/taler-wallet-core/src/index.ts
@@ -18,13 +18,9 @@
  * Module entry point for the wallet when used as a node module.
  */
 
-// Errors
-export * from "./errors.js";
-
 // Util functionality
 export * from "./util/promiseUtils.js";
 export * from "./util/query.js";
-export * from "./util/http.js";
 
 export * from "./versions.js";
 
@@ -67,3 +63,5 @@ export * from "./util/timer.js";
 export * from "./util/denominations.js";
 
 export { SynchronousCryptoWorkerFactoryPlain } from 
"./crypto/workers/synchronousWorkerFactoryPlain.js";
+export * from "./host-common.js";
+export * from "./host.js";
diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts 
b/packages/taler-wallet-core/src/internal-wallet-state.ts
index d180861f8..8434c3b8f 100644
--- a/packages/taler-wallet-core/src/internal-wallet-state.ts
+++ b/packages/taler-wallet-core/src/internal-wallet-state.ts
@@ -30,18 +30,14 @@
  * Imports.
  */
 import {
-  WalletNotification,
-  BalancesResponse,
-  AmountJson,
-  DenominationPubKey,
-  TalerProtocolTimestamp,
   CancellationToken,
+  CoinRefreshRequest,
   DenominationInfo,
   RefreshGroupId,
-  CoinRefreshRequest,
   RefreshReason,
+  WalletNotification,
 } from "@gnu-taler/taler-util";
-import { CryptoDispatcher } from "./crypto/workers/crypto-dispatcher.js";
+import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
 import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
 import {
   ExchangeDetailsRecord,
@@ -49,9 +45,6 @@ import {
   RefreshReasonDetails,
   WalletStoresV1,
 } from "./db.js";
-import { PendingOperationsResponse } from "./pending-types.js";
-import { AsyncOpMemoMap, AsyncOpMemoSingle } from "./util/asyncMemo.js";
-import { HttpRequestLibrary } from "./util/http.js";
 import { AsyncCondition } from "./util/promiseUtils.js";
 import {
   DbAccess,
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts 
b/packages/taler-wallet-core/src/operations/backup/index.ts
index 7d3953ebb..3dae26087 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -85,13 +85,13 @@ import {
   ConfigRecordKey,
   WalletBackupConfState,
 } from "../../db.js";
-import { TalerError } from "../../errors.js";
+import { TalerError } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../../internal-wallet-state.js";
 import { assertUnreachable } from "../../util/assertUnreachable.js";
 import {
   readSuccessResponseJsonOrThrow,
   readTalerErrorResponse,
-} from "../../util/http.js";
+} from "@gnu-taler/taler-util/http";
 import {
   checkDbInvariant,
   checkLogicInvariant,
diff --git a/packages/taler-wallet-core/src/operations/common.ts 
b/packages/taler-wallet-core/src/operations/common.ts
index 3ea02012b..e61a6fe95 100644
--- a/packages/taler-wallet-core/src/operations/common.ts
+++ b/packages/taler-wallet-core/src/operations/common.ts
@@ -42,7 +42,7 @@ import {
   ExchangeDetailsRecord,
   ExchangeRecord,
 } from "../db.js";
-import { makeErrorDetail, TalerError } from "../errors.js";
+import { makeErrorDetail, TalerError } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
 import { GetReadWriteAccess } from "../util/query.js";
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 4ff6a65cd..9d71f020f 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -62,10 +62,10 @@ import {
   OperationStatus,
   TransactionStatus,
 } from "../db.js";
-import { TalerError } from "../errors.js";
-import { checkWithdrawalKycStatus, KycPendingInfo, KycUserType } from 
"../index.js";
+import { TalerError } from "@gnu-taler/taler-util";
+import { KycPendingInfo, KycUserType } from "../index.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
-import { readSuccessResponseJsonOrThrow } from "../util/http.js";
+import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
 import { OperationAttemptResult } from "../util/retries.js";
 import { makeTransactionId, spendCoins } from "./common.js";
 import { getExchangeDetails } from "./exchanges.js";
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts 
b/packages/taler-wallet-core/src/operations/exchanges.ts
index 67f77de77..2b6a881dd 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -41,6 +41,7 @@ import {
   NotificationType,
   parsePaytoUri,
   Recoup,
+  TalerError,
   TalerErrorCode,
   TalerProtocolDuration,
   TalerProtocolTimestamp,
@@ -49,6 +50,7 @@ import {
   WireFeeMap,
   WireInfo,
 } from "@gnu-taler/taler-util";
+import { HttpRequestLibrary, readSuccessResponseTextOrThrow, 
readSuccessResponseJsonOrThrow, getExpiry } from "@gnu-taler/taler-util/http";
 import {
   DenominationRecord,
   DenominationVerificationStatus,
@@ -56,14 +58,7 @@ import {
   ExchangeRecord,
   WalletStoresV1,
 } from "../db.js";
-import { TalerError } from "../errors.js";
 import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js";
-import {
-  getExpiry,
-  HttpRequestLibrary,
-  readSuccessResponseJsonOrThrow,
-  readSuccessResponseTextOrThrow,
-} from "../util/http.js";
 import { checkDbInvariant } from "../util/invariants.js";
 import {
   DbAccess,
diff --git a/packages/taler-wallet-core/src/operations/merchants.ts 
b/packages/taler-wallet-core/src/operations/merchants.ts
index eeefc0f79..c47ec4a0a 100644
--- a/packages/taler-wallet-core/src/operations/merchants.ts
+++ b/packages/taler-wallet-core/src/operations/merchants.ts
@@ -25,7 +25,7 @@ import {
   LibtoolVersion,
 } from "@gnu-taler/taler-util";
 import { InternalWalletState, MerchantInfo } from 
"../internal-wallet-state.js";
-import { readSuccessResponseJsonOrThrow } from "../util/http.js";
+import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
 
 const logger = new Logger("taler-wallet-core:merchants.ts");
 
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts 
b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 2a89c59ed..f84ac2567 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -94,13 +94,12 @@ import {
   makePendingOperationFailedError,
   TalerError,
   TalerProtocolViolationError,
-} from "../errors.js";
-import { GetReadWriteAccess } from "../index.browser.js";
+} from "@gnu-taler/taler-util";
+import { GetReadWriteAccess } from "../index.js";
 import {
   EXCHANGE_COINS_LOCK,
   InternalWalletState,
 } from "../internal-wallet-state.js";
-import { PendingTaskType } from "../pending-types.js";
 import { assertUnreachable } from "../util/assertUnreachable.js";
 import {
   CoinSelectionTally,
@@ -114,7 +113,7 @@ import {
   readTalerErrorResponse,
   readUnexpectedResponseDetails,
   throwUnexpectedRequestError,
-} from "../util/http.js";
+} from "@gnu-taler/taler-util/http";
 import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
 import {
   OperationAttemptResult,
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts 
b/packages/taler-wallet-core/src/operations/pay-peer.ts
index 7dc7b67fe..022a824de 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -81,16 +81,15 @@ import {
   WithdrawalGroupStatus,
   WithdrawalRecordType,
 } from "../db.js";
-import { TalerError } from "../errors.js";
+import { TalerError } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import {
   makeTransactionId,
   runOperationWithErrorReporting,
   spendCoins,
 } from "../operations/common.js";
-import { readSuccessResponseJsonOrThrow } from "../util/http.js";
+import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
 import { checkDbInvariant } from "../util/invariants.js";
-import { GetReadOnlyAccess } from "../util/query.js";
 import {
   OperationAttemptResult,
   OperationAttemptResultType,
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts 
b/packages/taler-wallet-core/src/operations/recoup.ts
index 00dd0e1c6..3b423474b 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -49,7 +49,7 @@ import {
   WithdrawCoinSource,
 } from "../db.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
-import { readSuccessResponseJsonOrThrow } from "../util/http.js";
+import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
 import { checkDbInvariant } from "../util/invariants.js";
 import { GetReadWriteAccess } from "../util/query.js";
 import {
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index 5b7bf8d83..773689635 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -63,7 +63,7 @@ import {
   RefreshReasonDetails,
   WalletStoresV1,
 } from "../db.js";
-import { TalerError } from "../errors.js";
+import { TalerError } from "@gnu-taler/taler-util";
 import {
   EXCHANGE_COINS_LOCK,
   InternalWalletState,
@@ -72,7 +72,7 @@ import { assertUnreachable } from 
"../util/assertUnreachable.js";
 import {
   readSuccessResponseJsonOrThrow,
   readUnexpectedResponseDetails,
-} from "../util/http.js";
+} from "@gnu-taler/taler-util/http";
 import { checkDbInvariant } from "../util/invariants.js";
 import { GetReadWriteAccess } from "../util/query.js";
 import {
diff --git a/packages/taler-wallet-core/src/operations/testing.ts 
b/packages/taler-wallet-core/src/operations/testing.ts
index 50454a920..873fac021 100644
--- a/packages/taler-wallet-core/src/operations/testing.ts
+++ b/packages/taler-wallet-core/src/operations/testing.ts
@@ -29,7 +29,7 @@ import {
   HttpRequestLibrary,
   readSuccessResponseJsonOrThrow,
   checkSuccessResponseOrThrow,
-} from "../util/http.js";
+} from "@gnu-taler/taler-util/http";
 import {
   AmountString,
   codecForAny,
diff --git a/packages/taler-wallet-core/src/operations/tip.ts 
b/packages/taler-wallet-core/src/operations/tip.ts
index 2bf216102..ec7546992 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -45,12 +45,12 @@ import {
   DenominationRecord,
   TipRecord,
 } from "../db.js";
-import { makeErrorDetail } from "../errors.js";
+import { makeErrorDetail } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import {
   getHttpResponseErrorDetails,
   readSuccessResponseJsonOrThrow,
-} from "../util/http.js";
+} from "@gnu-taler/taler-util/http";
 import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
 import {
   OperationAttemptResult,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index bcc8600c7..f6d79b229 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -85,7 +85,7 @@ import {
   getErrorDetailFromException,
   makeErrorDetail,
   TalerError,
-} from "../errors.js";
+} from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import {
   makeCoinAvailable,
@@ -99,7 +99,7 @@ import {
   readSuccessResponseJsonOrErrorCode,
   readSuccessResponseJsonOrThrow,
   throwUnexpectedRequestError,
-} from "../util/http.js";
+} from "@gnu-taler/taler-util/http";
 import {
   checkDbInvariant,
   checkLogicInvariant,
diff --git a/packages/taler-wallet-core/src/remote.ts 
b/packages/taler-wallet-core/src/remote.ts
index bc0be9d30..89348698e 100644
--- a/packages/taler-wallet-core/src/remote.ts
+++ b/packages/taler-wallet-core/src/remote.ts
@@ -19,10 +19,10 @@ import {
   CoreApiResponse,
   j2s,
   Logger,
+  TalerError,
   WalletNotification,
 } from "@gnu-taler/taler-util";
 import { connectRpc, JsonMessage } from "@gnu-taler/taler-util/twrpc";
-import { TalerError } from "./errors.js";
 import { OpenedPromise, openPromise } from "./index.js";
 import { WalletCoreApiClient } from "./wallet-api-types.js";
 
diff --git a/packages/taler-wallet-core/src/util/retries.ts 
b/packages/taler-wallet-core/src/util/retries.ts
index fcb63ecd1..742381f7b 100644
--- a/packages/taler-wallet-core/src/util/retries.ts
+++ b/packages/taler-wallet-core/src/util/retries.ts
@@ -40,7 +40,7 @@ import {
   WalletStoresV1,
   WithdrawalGroupRecord,
 } from "../db.js";
-import { TalerError } from "../errors.js";
+import { TalerError } from "@gnu-taler/taler-util";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { PendingTaskType } from "../pending-types.js";
 import { GetReadWriteAccess } from "./query.js";
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index a57c71bcf..0d02b667b 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -129,7 +129,7 @@ import {
   maybeInitDevMode,
   setDevMode,
 } from "./dev-experiments.js";
-import { getErrorDetailFromException, TalerError } from "./errors.js";
+import { getErrorDetailFromException, TalerError } from 
"@gnu-taler/taler-util";
 import {
   ActiveLongpollInfo,
   ExchangeOperations,
@@ -247,7 +247,7 @@ import {
 import {
   HttpRequestLibrary,
   readSuccessResponseJsonOrThrow,
-} from "./util/http.js";
+} from "@gnu-taler/taler-util/http";
 import { checkDbInvariant } from "./util/invariants.js";
 import {
   AsyncCondition,
diff --git a/packages/taler-wallet-embedded/build.mjs 
b/packages/taler-wallet-embedded/build.mjs
index 537a4fbc0..28351e6e5 100755
--- a/packages/taler-wallet-embedded/build.mjs
+++ b/packages/taler-wallet-embedded/build.mjs
@@ -55,6 +55,7 @@ export const buildConfig = {
   format: 'esm',
   platform: 'neutral',
   mainFields: ["module", "main"],
+  conditions: ["qtart"],
   sourcemap: true,
   define: {
     '__VERSION__': `"${_package.version}"`,
diff --git a/packages/taler-wallet-embedded/src/index.ts 
b/packages/taler-wallet-embedded/src/index.ts
index b505a2d9d..e0a13390d 100644
--- a/packages/taler-wallet-embedded/src/index.ts
+++ b/packages/taler-wallet-embedded/src/index.ts
@@ -18,27 +18,25 @@
  * Imports.
  */
 import {
+  createNativeWalletHost,
   DefaultNodeWalletArgs,
-  getDefaultNodeWallet,
-  getErrorDetailFromException,
   handleWorkerError,
   handleWorkerMessage,
-  Headers,
-  HttpRequestLibrary,
-  HttpRequestOptions,
-  HttpResponse,
-  NodeHttpLib,
   OpenedPromise,
   openPromise,
   Wallet,
-  WALLET_EXCHANGE_PROTOCOL_VERSION,
-  WALLET_MERCHANT_PROTOCOL_VERSION,
 } from "@gnu-taler/taler-wallet-core";
 
 import {
   CoreApiMessageEnvelope,
   CoreApiResponse,
   CoreApiResponseSuccess,
+  createPlatformHttpLib,
+  getErrorDetailFromException,
+  Headers,
+  HttpRequestLibrary,
+  HttpRequestOptions,
+  HttpResponse,
   Logger,
   WalletNotification,
 } from "@gnu-taler/taler-util";
@@ -51,7 +49,7 @@ const logger = new Logger("taler-wallet-embedded/index.ts");
 export class NativeHttpLib implements HttpRequestLibrary {
   useNfcTunnel = false;
 
-  private nodeHttpLib: HttpRequestLibrary = new NodeHttpLib();
+  private httpLib: HttpRequestLibrary = createPlatformHttpLib();
 
   private requestId = 1;
 
@@ -62,7 +60,7 @@ export class NativeHttpLib implements HttpRequestLibrary {
   constructor(private sendMessage: (m: string) => void) {}
 
   fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
-    return this.nodeHttpLib.fetch(url, opt);
+    return this.httpLib.fetch(url, opt);
   }
 
   get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
@@ -83,7 +81,7 @@ export class NativeHttpLib implements HttpRequestLibrary {
       );
       return p.promise;
     } else {
-      return this.nodeHttpLib.get(url, opt);
+      return this.httpLib.get(url, opt);
     }
   }
 
@@ -106,7 +104,7 @@ export class NativeHttpLib implements HttpRequestLibrary {
       );
       return p.promise;
     } else {
-      return this.nodeHttpLib.postJson(url, body, opt);
+      return this.httpLib.postJson(url, body, opt);
     }
   }
 
@@ -158,7 +156,7 @@ class NativeWalletMessageHandler {
   walletArgs: DefaultNodeWalletArgs | undefined;
   maybeWallet: Wallet | undefined;
   wp = openPromise<Wallet>();
-  httpLib = new NodeHttpLib();
+  httpLib = createPlatformHttpLib();
 
   /**
    * Handle a request from the native wallet.
@@ -181,7 +179,7 @@ class NativeWalletMessageHandler {
 
     const reinit = async () => {
       logger.info("in reinit");
-      const w = await getDefaultNodeWallet(this.walletArgs);
+      const w = await createNativeWalletHost(this.walletArgs);
       this.maybeWallet = w;
       const resp = await w.handleCoreApiRequest(
         "initWallet",
diff --git a/packages/taler-wallet-embedded/src/wallet-qjs.ts 
b/packages/taler-wallet-embedded/src/wallet-qjs.ts
index f7b73711c..2d780c34c 100644
--- a/packages/taler-wallet-embedded/src/wallet-qjs.ts
+++ b/packages/taler-wallet-embedded/src/wallet-qjs.ts
@@ -17,44 +17,26 @@
 /**
  * Imports.
  */
-import {
-  AccessStats,
-  DefaultNodeWalletArgs,
-  getErrorDetailFromException,
-  Headers,
-  HttpRequestLibrary,
-  HttpRequestOptions,
-  HttpResponse,
-  openPromise,
-  openTalerDatabase,
-  SetTimeoutTimerAPI,
-  SynchronousCryptoWorkerFactoryPlain,
-  Wallet,
-  WalletApiOperation,
-} from "@gnu-taler/taler-wallet-core";
-
 import {
   CoreApiMessageEnvelope,
   CoreApiResponse,
   CoreApiResponseSuccess,
+  getErrorDetailFromException,
   InitRequest,
-  j2s,
   Logger,
   setGlobalLogLevelFromString,
   setPRNG,
   WalletNotification,
 } from "@gnu-taler/taler-util";
-import { BridgeIDBFactory } from "@gnu-taler/idb-bridge";
-import { MemoryBackend } from "@gnu-taler/idb-bridge";
-import { shimIndexedDB } from "@gnu-taler/idb-bridge";
-import { IDBFactory } from "@gnu-taler/idb-bridge";
-
-import * as _qjsOsImp from "os";
-// @ts-ignore
-import * as _qjsStdImp from "std";
-
-const textDecoder = new TextDecoder();
-const textEncoder = new TextEncoder();
+import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
+import { qjsOs } from "@gnu-taler/taler-util/qtart";
+import {
+  createNativeWalletHost2,
+  DefaultNodeWalletArgs,
+  openPromise,
+  Wallet,
+  WalletApiOperation,
+} from "@gnu-taler/taler-wallet-core";
 
 setGlobalLogLevelFromString("trace");
 
@@ -66,210 +48,19 @@ setPRNG(function (x: Uint8Array, n: number) {
   for (let i = 0; i < v.length; i++) v[i] = 0;
 });
 
-export interface QjsHttpResp {
-  status: number;
-  data: ArrayBuffer;
-}
-
-export interface QjsHttpOptions {
-  method: string;
-  debug?: boolean;
-  data?: ArrayBuffer;
-  headers?: string[];
-}
-
-export interface QjsOsLib {
-  fetchHttp(url: string, options?: QjsHttpOptions): Promise<QjsHttpResp>;
-  postMessageToHost(s: string): void;
-  setMessageFromHostHandler(h: (s: string) => void): void;
-  rename(oldPath: string, newPath: string): number;
-}
-
-export interface QjsStdLib {
-  writeFile(filename: string, contents: string): void;
-  loadFile(filename: string): string;
-}
-
-// This is not the nodejs "os" module, but the qjs "os" module.
-const qjsOs: QjsOsLib = _qjsOsImp as any;
-
-const qjsStd: QjsStdLib = _qjsStdImp as any;
-
 const logger = new Logger("taler-wallet-embedded/index.ts");
 
-export class NativeHttpLib implements HttpRequestLibrary {
-  get(
-    url: string,
-    opt?: HttpRequestOptions | undefined,
-  ): Promise<HttpResponse> {
-    return this.fetch(url, {
-      method: "GET",
-      ...opt,
-    });
-  }
-  postJson(
-    url: string,
-    body: any,
-    opt?: HttpRequestOptions | undefined,
-  ): Promise<HttpResponse> {
-    return this.fetch(url, {
-      method: "POST",
-      body,
-      ...opt,
-    });
-  }
-  async fetch(
-    url: string,
-    opt?: HttpRequestOptions | undefined,
-  ): Promise<HttpResponse> {
-    const method = opt?.method ?? "GET";
-    let data: ArrayBuffer | undefined = undefined;
-    let headers: string[] = [];
-    if (opt?.headers) {
-      for (let headerName of Object.keys(opt.headers)) {
-        headers.push(`${headerName}: ${opt.headers[headerName]}`);
-      }
-    }
-    if (method.toUpperCase() === "POST") {
-      if (opt?.body) {
-        if (typeof opt.body === "string") {
-          data = textEncoder.encode(opt.body).buffer;
-        } else if (ArrayBuffer.isView(opt.body)) {
-          data = opt.body.buffer;
-        } else if (opt.body instanceof ArrayBuffer) {
-          data = opt.body;
-        } else if (typeof opt.body === "object") {
-          data = textEncoder.encode(JSON.stringify(opt.body)).buffer;
-        }
-      } else {
-        data = new ArrayBuffer(0);
-      }
-    }
-    const res = await qjsOs.fetchHttp(url, {
-      method,
-      data,
-      headers,
-    });
-    return {
-      requestMethod: method,
-      headers: new Headers(),
-      async bytes() {
-        return res.data;
-      },
-      json() {
-        const text = textDecoder.decode(res.data);
-        return JSON.parse(text);
-      },
-      async text() {
-        const text = textDecoder.decode(res.data);
-        return text;
-      },
-      requestUrl: url,
-      status: res.status,
-    };
-  }
-}
-
 function sendNativeMessage(ev: CoreApiMessageEnvelope): void {
   const m = JSON.stringify(ev);
   qjsOs.postMessageToHost(m);
 }
 
-/**
- * Generate a random alphanumeric ID.  Does *not* use cryptographically
- * secure randomness.
- */
-function makeId(length: number): string {
-  let result = "";
-  const characters =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-  for (let i = 0; i < length; i++) {
-    result += characters.charAt(Math.floor(Math.random() * characters.length));
-  }
-  return result;
-}
-
-export async function getWallet(args: DefaultNodeWalletArgs = {}): Promise<{
-  wallet: Wallet;
-  getDbStats: () => AccessStats;
-}> {
-  BridgeIDBFactory.enableTracing = false;
-  const myBackend = new MemoryBackend();
-  myBackend.enableTracing = false;
-
-  const storagePath = args.persistentStoragePath;
-  if (storagePath) {
-    const dbContentStr = qjsStd.loadFile(storagePath);
-    if (dbContentStr != null) {
-      const dbContent = JSON.parse(dbContentStr);
-      myBackend.importDump(dbContent);
-    }
-
-    myBackend.afterCommitCallback = async () => {
-      logger.trace("committing database");
-      // Allow caller to stop persisting the wallet.
-      if (args.persistentStoragePath === undefined) {
-        return;
-      }
-      const tmpPath = `${args.persistentStoragePath}-${makeId(5)}.tmp`;
-      const dbContent = myBackend.exportDump();
-      qjsStd.writeFile(tmpPath, JSON.stringify(dbContent, undefined, 2));
-      // Atomically move the temporary file onto the DB path.
-      const res = qjsOs.rename(tmpPath, args.persistentStoragePath);
-      if (res != 0) {
-        throw Error("db commit failed at rename");
-      }
-      logger.trace("committing database done");
-    };
-  }
-
-  console.log("done processing storage path");
-
-  BridgeIDBFactory.enableTracing = false;
-
-  const myBridgeIdbFactory = new BridgeIDBFactory(myBackend);
-  const myIdbFactory: IDBFactory = myBridgeIdbFactory as any as IDBFactory;
-
-  let myHttpLib;
-  if (args.httpLib) {
-    myHttpLib = args.httpLib;
-  } else {
-    myHttpLib = new NativeHttpLib();
-  }
-
-  const myVersionChange = (): Promise<void> => {
-    logger.error("version change requested, should not happen");
-    throw Error(
-      "BUG: wallet DB version change event can't happen with memory IDB",
-    );
-  };
-
-  shimIndexedDB(myBridgeIdbFactory);
-
-  const myDb = await openTalerDatabase(myIdbFactory, myVersionChange);
-
-  let workerFactory;
-  workerFactory = new SynchronousCryptoWorkerFactoryPlain();
-
-  const timer = new SetTimeoutTimerAPI();
-
-  const w = await Wallet.create(myDb, myHttpLib, timer, workerFactory);
-
-  if (args.notifyHandler) {
-    w.addNotificationListener(args.notifyHandler);
-  }
-  return {
-    wallet: w,
-    getDbStats: () => myBackend.accessStats,
-  };
-}
-
 class NativeWalletMessageHandler {
   walletArgs: DefaultNodeWalletArgs | undefined;
   initRequest: InitRequest = {};
   maybeWallet: Wallet | undefined;
   wp = openPromise<Wallet>();
-  httpLib = new NativeHttpLib();
+  httpLib = createPlatformHttpLib();
 
   /**
    * Handle a request from the native wallet.
@@ -292,7 +83,7 @@ class NativeWalletMessageHandler {
 
     const reinit = async () => {
       logger.info("in reinit");
-      const wR = await getWallet(this.walletArgs);
+      const wR = await createNativeWalletHost2(this.walletArgs);
       const w = wR.wallet;
       this.maybeWallet = w;
       const resp = await w.handleCoreApiRequest("initWallet", "native-init", {
@@ -422,7 +213,7 @@ globalThis.installNativeWalletListener = 
installNativeWalletListener;
 globalThis.makeWallet = getWallet;
 
 export async function testWithGv() {
-  const w = await getWallet();
+  const w = await createNativeWalletHost2();
   await w.wallet.client.call(WalletApiOperation.InitWallet, {});
   await w.wallet.client.call(WalletApiOperation.RunIntegrationTest, {
     amountToSpend: "KUDOS:1",
@@ -438,7 +229,7 @@ export async function testWithGv() {
 
 export async function testWithLocal() {
   console.log("running local test");
-  const w = await getWallet({
+  const w = await createNativeWalletHost2({
     persistentStoragePath: "walletdb.json",
   });
   console.log("created wallet");
diff --git a/packages/taler-wallet-webextension/src/browserHttpLib.ts 
b/packages/taler-wallet-webextension/src/browserHttpLib.ts
index 165a0037c..2b6ca019c 100644
--- a/packages/taler-wallet-webextension/src/browserHttpLib.ts
+++ b/packages/taler-wallet-webextension/src/browserHttpLib.ts
@@ -17,20 +17,20 @@
 /**
  * Imports.
  */
-import {
-  HttpRequestLibrary,
-  HttpRequestOptions,
-  HttpResponse,
-  Headers,
-  TalerError,
-} from "@gnu-taler/taler-wallet-core";
 import {
   Logger,
   RequestThrottler,
-  stringToBytes,
   TalerErrorCode,
+  TalerError,
 } from "@gnu-taler/taler-util";
 
+import {
+  HttpRequestLibrary,
+  HttpRequestOptions,
+  HttpResponse,
+  Headers,
+} from "@gnu-taler/taler-util/http";
+
 const logger = new Logger("browserHttpLib");
 
 /**
diff --git a/packages/taler-wallet-webextension/src/browserWorkerEntry.ts 
b/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
index 2f1a26e36..bb1794e56 100644
--- a/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
+++ b/packages/taler-wallet-webextension/src/browserWorkerEntry.ts
@@ -22,11 +22,12 @@
  * Imports.
  */
 
-import { j2s, Logger } from "@gnu-taler/taler-util";
 import {
+  j2s,
+  Logger,
   getErrorDetailFromException,
-  nativeCrypto,
-} from "@gnu-taler/taler-wallet-core";
+} from "@gnu-taler/taler-util";
+import { nativeCrypto } from "@gnu-taler/taler-wallet-core";
 
 const logger = new Logger("browserWorkerEntry.ts");
 
diff --git 
a/packages/taler-wallet-webextension/src/components/index.stories.tsx 
b/packages/taler-wallet-webextension/src/components/index.stories.tsx
index 469ed82fa..4a7a068d3 100644
--- a/packages/taler-wallet-webextension/src/components/index.stories.tsx
+++ b/packages/taler-wallet-webextension/src/components/index.stories.tsx
@@ -24,5 +24,5 @@ export * as a2 from "./PendingTransactions.stories.js";
 export * as a3 from "./Amount.stories.js";
 export * as a4 from "./ShowFullContractTermPopup.stories.js";
 export * as a5 from "./TermsOfService/stories.js";
-export * as a6 from "./QR.stories";
+export * as a6 from "./QR.stories.js";
 export * as a7 from "./AmountField.stories.js";
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
index ee5375859..670a67599 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
@@ -16,7 +16,7 @@
 
 /* eslint-disable react-hooks/rules-of-hooks */
 import { Amounts, TalerProtocolTimestamp } from "@gnu-taler/taler-util";
-import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { isFuture, parse } from "date-fns";
 import { useState } from "preact/hooks";
 import { alertFromError, useAlertContext } from "../../context/alert.js";
diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts 
b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
index 66c018ddf..8459d5ca2 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
@@ -20,16 +20,14 @@ import {
   NotificationType,
   PreparePayResult,
   PreparePayResultType,
-  TalerErrorDetail,
   TalerProtocolTimestamp,
 } from "@gnu-taler/taler-util";
-import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
-import { useEffect, useState } from "preact/hooks";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { useEffect } from "preact/hooks";
 import { alertFromError, useAlertContext } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import { withSafe } from "../../mui/handlers.js";
 import { Props, State } from "./index.js";
 
 export function useComponentState({
diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts 
b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
index 6574d6ba1..b306ca122 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
@@ -15,11 +15,9 @@
  */
 
 import {
-  Amounts,
-  TalerErrorDetail,
-  TalerProtocolTimestamp,
+  Amounts, TalerProtocolTimestamp
 } from "@gnu-taler/taler-util";
-import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { isFuture, parse } from "date-fns";
 import { useState } from "preact/hooks";
 import { alertFromError, useAlertContext } from "../../context/alert.js";
diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts 
b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
index 12643b893..6b50faf10 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
@@ -16,12 +16,9 @@
 
 import {
   AbsoluteTime,
-  Amounts,
-  TalerErrorDetail,
-  TalerProtocolTimestamp,
+  Amounts, TalerProtocolTimestamp
 } from "@gnu-taler/taler-util";
-import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
-import { useState } from "preact/hooks";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { alertFromError, useAlertContext } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
 import { useTranslationContext } from "../../context/translation.js";
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
index 5f149064c..9522c2bfb 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
@@ -20,8 +20,9 @@ import {
   Amounts,
   ExchangeListItem,
   ExchangeTosStatus,
+  TalerError,
 } from "@gnu-taler/taler-util";
-import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
 import { alertFromError, useAlertContext } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
diff --git a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts 
b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
index cf9409bad..a5e357f7d 100644
--- a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
@@ -13,8 +13,7 @@
  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 { TalerErrorDetail } from "@gnu-taler/taler-util";
-import { TalerError } from "@gnu-taler/taler-wallet-core";
+import { TalerErrorDetail, TalerError } from "@gnu-taler/taler-util";
 import { useEffect, useMemo, useState } from "preact/hooks";
 import { BackgroundError } from "../wxApi.js";
 
diff --git a/packages/taler-wallet-webextension/src/mui/Button.tsx 
b/packages/taler-wallet-webextension/src/mui/Button.tsx
index 31e97f008..aad8f5002 100644
--- a/packages/taler-wallet-webextension/src/mui/Button.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Button.tsx
@@ -16,9 +16,9 @@
 import { ComponentChildren, h, VNode, JSX } from "preact";
 import { css } from "@linaria/core";
 // eslint-disable-next-line import/extensions
-import { theme, Colors, rippleEnabled, rippleEnabledOutlined } from "./style";
+import { theme, Colors, rippleEnabled, rippleEnabledOutlined } from 
"./style.js";
 // eslint-disable-next-line import/extensions
-import { alpha } from "./colors/manipulation";
+import { alpha } from "./colors/manipulation.js";
 import { useState } from "preact/hooks";
 import { SafeHandler } from "./handlers.js";
 
diff --git a/packages/taler-wallet-webextension/src/mui/Grid.tsx 
b/packages/taler-wallet-webextension/src/mui/Grid.tsx
index e9b839b2f..2db439778 100644
--- a/packages/taler-wallet-webextension/src/mui/Grid.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Grid.tsx
@@ -17,7 +17,7 @@ import { css } from "@linaria/core";
 import { h, JSX, VNode, ComponentChildren, createContext } from "preact";
 import { useContext } from "preact/hooks";
 // eslint-disable-next-line import/extensions
-import { theme } from "./style";
+import { theme } from "./style.js";
 
 type ResponsiveKeys = "xs" | "sm" | "md" | "lg" | "xl";
 
diff --git a/packages/taler-wallet-webextension/src/mui/Menu.stories.tsx 
b/packages/taler-wallet-webextension/src/mui/Menu.stories.tsx
index e2bba2678..200af8f57 100644
--- a/packages/taler-wallet-webextension/src/mui/Menu.stories.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Menu.stories.tsx
@@ -47,8 +47,7 @@ export const BasicExample = (): VNode => {
 };
 
 import { styled } from "@linaria/react";
-// eslint-disable-next-line import/extensions
-import { theme } from "./style";
+import { theme } from "./style.js";
 import { Typography } from "./Typography.js";
 import { Divider } from "./Divider.js";
 
diff --git a/packages/taler-wallet-webextension/src/mui/Modal.tsx 
b/packages/taler-wallet-webextension/src/mui/Modal.tsx
index 7b1cf3f3a..0ea1372fa 100644
--- a/packages/taler-wallet-webextension/src/mui/Modal.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Modal.tsx
@@ -18,11 +18,11 @@ import { css } from "@linaria/core";
 import { h, JSX, VNode, ComponentChildren } from "preact";
 import { useCallback, useEffect, useRef, useState } from "preact/hooks";
 // eslint-disable-next-line import/extensions
-import { alpha } from "./colors/manipulation";
+import { alpha } from "./colors/manipulation.js";
 import { ModalManager } from "./ModalManager.js";
 import { Portal } from "./Portal.js";
 // eslint-disable-next-line import/extensions
-import { theme } from "./style";
+import { theme } from "./style.js";
 
 const baseStyle = css`
   position: fixed;
diff --git a/packages/taler-wallet-webextension/src/mui/Paper.tsx 
b/packages/taler-wallet-webextension/src/mui/Paper.tsx
index 0c805e307..a44b1be0d 100644
--- a/packages/taler-wallet-webextension/src/mui/Paper.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Paper.tsx
@@ -16,9 +16,9 @@
 import { css } from "@linaria/core";
 import { h, JSX, VNode, ComponentChildren } from "preact";
 // eslint-disable-next-line import/extensions
-import { alpha } from "./colors/manipulation";
+import { alpha } from "./colors/manipulation.js";
 // eslint-disable-next-line import/extensions
-import { theme } from "./style";
+import { theme } from "./style.js";
 
 const borderVariant = {
   outlined: css`
diff --git a/packages/taler-wallet-webextension/src/mui/Popover.tsx 
b/packages/taler-wallet-webextension/src/mui/Popover.tsx
index 69e0ab10a..da551c65d 100644
--- a/packages/taler-wallet-webextension/src/mui/Popover.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Popover.tsx
@@ -15,11 +15,7 @@
  */
 
 import { css } from "@linaria/core";
-import { h, JSX, VNode, ComponentChildren } from "preact";
-// eslint-disable-next-line import/extensions
-import { alpha } from "./colors/manipulation";
-// eslint-disable-next-line import/extensions
-import { theme } from "./style";
+import { h, VNode, ComponentChildren } from "preact";
 
 const baseStyle = css``;
 
diff --git a/packages/taler-wallet-webextension/src/mui/Portal.tsx 
b/packages/taler-wallet-webextension/src/mui/Portal.tsx
index 2026d7e5a..1d835abac 100644
--- a/packages/taler-wallet-webextension/src/mui/Portal.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Portal.tsx
@@ -26,11 +26,9 @@ import {
   cloneElement,
   Fragment,
 } from "preact";
-import { Ref, useEffect, useMemo, useState } from "preact/hooks";
-// eslint-disable-next-line import/extensions
-import { alpha } from "./colors/manipulation";
-// eslint-disable-next-line import/extensions
-import { theme } from "./style";
+import { Ref, useEffect, useState } from "preact/hooks";
+
+import { theme } from "./style.js";
 
 const baseStyle = css`
   position: fixed;
diff --git a/packages/taler-wallet-webextension/src/mui/TextField.tsx 
b/packages/taler-wallet-webextension/src/mui/TextField.tsx
index 42ac49a00..4d7c9a472 100644
--- a/packages/taler-wallet-webextension/src/mui/TextField.tsx
+++ b/packages/taler-wallet-webextension/src/mui/TextField.tsx
@@ -23,7 +23,7 @@ import { SelectFilled } from "./input/SelectFilled.js";
 import { SelectOutlined } from "./input/SelectOutlined.js";
 import { SelectStandard } from "./input/SelectStandard.js";
 // eslint-disable-next-line import/extensions
-import { Colors } from "./style";
+import { Colors } from "./style.js";
 
 export interface Props {
   autoComplete?: string;
diff --git a/packages/taler-wallet-webextension/src/mui/Typography.tsx 
b/packages/taler-wallet-webextension/src/mui/Typography.tsx
index b3a9e0010..3b4357918 100644
--- a/packages/taler-wallet-webextension/src/mui/Typography.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Typography.tsx
@@ -17,7 +17,7 @@ import { css } from "@linaria/core";
 import { ComponentChildren, h, VNode } from "preact";
 import { useTranslationContext } from "../context/translation.js";
 // eslint-disable-next-line import/extensions
-import { theme } from "./style";
+import { theme } from "./style.js";
 
 type VariantEnum =
   | "body1"
diff --git a/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx 
b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
index e80e7f8d8..23dfcfd08 100644
--- a/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
@@ -17,7 +17,7 @@ import { css } from "@linaria/core";
 import { ComponentChildren, createContext, h, VNode } from "preact";
 import { useContext, useMemo, useState } from "preact/hooks";
 // eslint-disable-next-line import/extensions
-import { Colors } from "../style";
+import { Colors } from "../style.js";
 
 export interface Props {
   color: Colors;
diff --git 
a/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx 
b/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx
index 5e40ba616..5fa48a169 100644
--- a/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx
@@ -16,7 +16,7 @@
 import { css } from "@linaria/core";
 import { ComponentChildren, h, VNode } from "preact";
 // eslint-disable-next-line import/extensions
-import { theme } from "../style";
+import { theme } from "../style.js";
 import { useFormControl } from "./FormControl.js";
 
 const root = css`
diff --git a/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx 
b/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx
index 11404b5c1..68fbdc38e 100644
--- a/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx
@@ -16,7 +16,7 @@
 import { css } from "@linaria/core";
 import { ComponentChildren, h, VNode } from "preact";
 // eslint-disable-next-line import/extensions
-import { Colors, theme } from "../style";
+import { Colors, theme } from "../style.js";
 import { useFormControl } from "./FormControl.js";
 
 export interface Props {
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx
index 94304f16b..d811a3dbb 100644
--- a/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx
@@ -23,7 +23,7 @@ import {
   useState,
 } from "preact/hooks";
 // eslint-disable-next-line import/extensions
-import { theme } from "../style";
+import { theme } from "../style.js";
 import { FormControlContext, useFormControl } from "./FormControl.js";
 
 const rootStyle = css`
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx
index 9ab91e7fd..a984f8451 100644
--- a/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx
@@ -16,7 +16,7 @@
 import { css } from "@linaria/core";
 import { h, VNode } from "preact";
 // eslint-disable-next-line import/extensions
-import { Colors, theme } from "../style";
+import { Colors, theme } from "../style.js";
 import { useFormControl } from "./FormControl.js";
 import { InputBase, InputBaseComponent, InputBaseRoot } from "./InputBase.js";
 
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx
index 35cbd7a41..2d4743e59 100644
--- a/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx
@@ -16,7 +16,7 @@
 import { css } from "@linaria/core";
 import { ComponentChildren, h, VNode } from "preact";
 // eslint-disable-next-line import/extensions
-import { Colors, theme } from "../style";
+import { Colors, theme } from "../style.js";
 import { useFormControl } from "./FormControl.js";
 import { FormLabel } from "./FormLabel.js";
 
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx 
b/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx
index 45614f618..f5b70f07c 100644
--- a/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx
@@ -16,7 +16,7 @@
 import { css } from "@linaria/core";
 import { h, VNode } from "preact";
 // eslint-disable-next-line import/extensions
-import { Colors, theme } from "../style";
+import { Colors, theme } from "../style.js";
 import { useFormControl } from "./FormControl.js";
 import { InputBase, InputBaseComponent, InputBaseRoot } from "./InputBase.js";
 
diff --git a/packages/taler-wallet-webextension/src/mui/style.tsx 
b/packages/taler-wallet-webextension/src/mui/style.tsx
index c3071b314..3fcf3ac1e 100644
--- a/packages/taler-wallet-webextension/src/mui/style.tsx
+++ b/packages/taler-wallet-webextension/src/mui/style.tsx
@@ -26,9 +26,9 @@ import {
   purple,
   red,
   // eslint-disable-next-line import/extensions
-} from "./colors/constants";
+} from "./colors/constants.js";
 // eslint-disable-next-line import/extensions
-import { getContrastRatio } from "./colors/manipulation";
+import { getContrastRatio } from "./colors/manipulation.js";
 
 export type Colors =
   | "primary"
diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts 
b/packages/taler-wallet-webextension/src/platform/chrome.ts
index 07829641e..beb65b2d0 100644
--- a/packages/taler-wallet-webextension/src/platform/chrome.ts
+++ b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -19,8 +19,9 @@ import {
   Logger,
   TalerErrorCode,
   TalerUriType,
+  TalerError,
 } from "@gnu-taler/taler-util";
-import { TalerError, WalletOperations } from "@gnu-taler/taler-wallet-core";
+import { WalletOperations } from "@gnu-taler/taler-wallet-core";
 import { BackgroundOperations } from "../wxApi.js";
 import {
   BackgroundPlatformAPI,
diff --git a/packages/taler-wallet-webextension/src/popup/Application.tsx 
b/packages/taler-wallet-webextension/src/popup/Application.tsx
index ebbbc4c2a..acb16b1d5 100644
--- a/packages/taler-wallet-webextension/src/popup/Application.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Application.tsx
@@ -22,7 +22,7 @@
 
 import { createHashHistory } from "history";
 import { ComponentChildren, Fragment, h, VNode } from "preact";
-import Router, { route, Route } from "preact-router";
+import { route, Route, Router } from "preact-router";
 import { useEffect, useState } from "preact/hooks";
 import PendingTransactions from "../components/PendingTransactions.js";
 import { PopupBox } from "../components/styled/index.js";
diff --git 
a/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts 
b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts
index 0742d5ccd..4ee572435 100644
--- a/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts
+++ b/packages/taler-wallet-webextension/src/serviceWorkerCryptoWorkerFactory.ts
@@ -22,12 +22,12 @@
 import {
   CryptoWorker,
   CryptoWorkerFactory,
-  SynchronousCryptoWorker,
+  SynchronousCryptoWorkerPlain,
 } from "@gnu-taler/taler-wallet-core";
 
 export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
   startWorker(): CryptoWorker {
-    return new SynchronousCryptoWorker();
+    return new SynchronousCryptoWorkerPlain();
   }
 
   getConcurrency(): number {
diff --git a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts 
b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
index 4b47e89d5..921acd63b 100644
--- a/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
+++ b/packages/taler-wallet-webextension/src/serviceWorkerHttpLib.ts
@@ -18,17 +18,17 @@
  * Imports.
  */
 import {
-  Logger,
   RequestThrottler,
   TalerErrorCode,
+  TalerError,
 } from "@gnu-taler/taler-util";
+
 import {
   Headers,
   HttpRequestLibrary,
   HttpRequestOptions,
   HttpResponse,
-  TalerError,
-} from "@gnu-taler/taler-wallet-core";
+} from "@gnu-taler/taler-util/http";
 
 /**
  * An implementation of the [[HttpRequestLibrary]] using the
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx 
b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index 007f12bb7..bc6678a21 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -23,7 +23,7 @@
 import { TranslatedString } from "@gnu-taler/taler-util";
 import { createHashHistory } from "history";
 import { ComponentChildren, Fragment, h, VNode } from "preact";
-import Router, { route, Route } from "preact-router";
+import { route, Route, Router } from "preact-router";
 import { useEffect } from "preact/hooks";
 import { CurrentAlerts } from "../components/CurrentAlerts.js";
 import { LogoHeader } from "../components/LogoHeader.js";
diff --git a/packages/taler-wallet-webextension/src/wallet/QrReader.tsx 
b/packages/taler-wallet-webextension/src/wallet/QrReader.tsx
index c1972823a..0cbb12d40 100644
--- a/packages/taler-wallet-webextension/src/wallet/QrReader.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/QrReader.tsx
@@ -115,7 +115,7 @@ function drawIntoCanvasAndGetQR(
   context.clearRect(0, 0, canvas.width, canvas.height);
   context.drawImage(tag, 0, 0, canvas.width, canvas.height);
   const imgData = context.getImageData(0, 0, canvas.width, canvas.height);
-  const code = jsQR(imgData.data, canvas.width, canvas.height, {
+  const code = jsQR.default(imgData.data, canvas.width, canvas.height, {
     inversionAttempts: "attemptBoth",
   });
   if (code) {
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index c064d7111..5f3d09619 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -29,20 +29,18 @@ import {
   NotificationType,
   TalerErrorCode,
   TalerErrorDetail,
-  WalletDiagnostics,
+  WalletDiagnostics
 } from "@gnu-taler/taler-util";
 import {
-  TalerError,
   WalletCoreApiClient,
   WalletCoreOpKeys,
   WalletCoreRequestType,
-  WalletCoreResponseType,
-  WalletOperations,
+  WalletCoreResponseType
 } from "@gnu-taler/taler-wallet-core";
 import {
   MessageFromBackend,
   MessageFromFrontendBackground,
-  MessageFromFrontendWallet,
+  MessageFromFrontendWallet
 } from "./platform/api.js";
 import { platform } from "./platform/foreground.js";
 
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts 
b/packages/taler-wallet-webextension/src/wxBackend.ts
index 99602445d..cca07941a 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -32,14 +32,14 @@ import {
   TalerErrorCode,
   TalerUriType,
   WalletDiagnostics,
+  makeErrorDetail,
+  getErrorDetailFromException,
 } from "@gnu-taler/taler-util";
 import {
   DbAccess,
   deleteTalerDatabase,
   exportDb,
-  getErrorDetailFromException,
   importDb,
-  makeErrorDetail,
   OpenedPromise,
   openPromise,
   openTalerDatabase,
diff --git a/packages/taler-wallet-webextension/trim-extension.cjs 
b/packages/taler-wallet-webextension/trim-extension.cjs
index 4305e792b..00e8f9f01 100644
--- a/packages/taler-wallet-webextension/trim-extension.cjs
+++ b/packages/taler-wallet-webextension/trim-extension.cjs
@@ -7,7 +7,7 @@ module.exports = function({ types: t }) {
     visitor: {
       ImportDeclaration: (x) => {
         const src = x.node.source;
-        if (src.value.startsWith("./")) {
+        if (src.value.startsWith(".")) {
           if (src.value.endsWith(".js")) {
             const newVal = src.value.replace(/[.]js$/, "")
             x.node.source = t.stringLiteral(newVal);
diff --git a/packages/taler-wallet-webextension/tsconfig.json 
b/packages/taler-wallet-webextension/tsconfig.json
index 5fc45caae..303cf879e 100644
--- a/packages/taler-wallet-webextension/tsconfig.json
+++ b/packages/taler-wallet-webextension/tsconfig.json
@@ -8,8 +8,8 @@
     "jsx": "react", /* Specify JSX code generation: 'preserve', 
'react-native', or 'react'. */
     "jsxFactory": "h", /* Specify the JSX factory function to use when 
targeting react JSX emit, e.g. React.createElement or h. */
     "jsxFragmentFactory": "Fragment", // 
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#custom-jsx-factories
-    "moduleResolution": "Node",
-    "module": "ESNext",
+    "moduleResolution": "Node16",
+    "module": "ES2020",
     "target": "ES6",
     "skipLibCheck": true,
     "preserveSymlinks": true,
@@ -41,4 +41,4 @@
   "include": [
     "src/**/*"
   ]
-}
\ No newline at end of file
+}
diff --git a/packages/web-util/package.json b/packages/web-util/package.json
index 5ff01d06a..4b2f0d27c 100644
--- a/packages/web-util/package.json
+++ b/packages/web-util/package.json
@@ -12,10 +12,22 @@
   "license": "AGPL-3.0-or-later",
   "private": false,
   "exports": {
-    "./lib/tests/swr": "./lib/tests/swr.mjs",
-    "./lib/tests/mock": "./lib/tests/mock.mjs",
-    "./lib/index.browser": "./lib/index.browser.mjs",
-    "./lib/index.node": "./lib/index.node.cjs"
+    "./lib/tests/swr": {
+      "types": "./lib/tests/swr.js",
+      "default": "./lib/tests/swr.mjs"
+    },
+    "./lib/tests/mock": {
+      "types": "./lib/tests/mock.js",
+      "default": "./lib/tests/mock.mjs"
+    },
+    "./lib/index.browser": {
+      "types": "./lib/index.browser.js",
+      "default": "./lib/index.browser.mjs"
+    },
+    "./lib/index.node": {
+      "types": "./lib/index.node.js",
+      "default": "./lib/index.node.cjs"
+    }
   },
   "scripts": {
     "prepare": "tsc && ./build.mjs",
diff --git a/packages/web-util/src/cli.ts b/packages/web-util/src/cli.ts
index dca4fc664..b02947f7a 100644
--- a/packages/web-util/src/cli.ts
+++ b/packages/web-util/src/cli.ts
@@ -1,4 +1,5 @@
-import { clk, setGlobalLogLevelFromString } from "@gnu-taler/taler-util";
+import { setGlobalLogLevelFromString } from "@gnu-taler/taler-util";
+import { clk } from "@gnu-taler/taler-util/clk";
 import { serve } from "./serve.js";
 
 export const walletCli = clk
diff --git a/packages/web-util/src/serve.ts b/packages/web-util/src/serve.ts
index f3a97e2e2..34982c656 100644
--- a/packages/web-util/src/serve.ts
+++ b/packages/web-util/src/serve.ts
@@ -3,7 +3,7 @@ import chokidar from "chokidar";
 import express from "express";
 import https from "https";
 import { parse } from "url";
-import WebSocket, { Server } from "ws";
+import WebSocket from "ws";
 
 import locahostCrt from "./keys/localhost.crt";
 import locahostKey from "./keys/localhost.key";
@@ -45,7 +45,7 @@ export async function serve(opts: {
   logger.info(`  ${PATHS.NOTIFY}: broadcast`);
 
   if (opts.development) {
-    const wss = new Server({ noServer: true });
+    const wss = new WebSocket.Server({ noServer: true });
 
     wss.on("connection", function connection(ws) {
       ws.send("welcome");
diff --git a/packages/web-util/tsconfig.json b/packages/web-util/tsconfig.json
index aede0a0ac..3965f537d 100644
--- a/packages/web-util/tsconfig.json
+++ b/packages/web-util/tsconfig.json
@@ -6,7 +6,7 @@
     "jsx": "react",
     "jsxFactory": "h",
     "jsxFragmentFactory": "Fragment",
-    "moduleResolution": "Node",
+    "moduleResolution": "Node16",
     "sourceMap": true,
     "lib": [
       "es6"
@@ -31,4 +31,4 @@
   "include": [
     "src/**/*"
   ]
-}
\ No newline at end of file
+}

-- 
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]