summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-02-15 23:32:42 +0100
committerFlorian Dold <florian@dold.me>2023-02-16 02:50:29 +0100
commit825d2c4352022e7397854b2bd9ba7d3589873c07 (patch)
treed23530bf8408367439e6b3820ea0c4269bfeb39a /packages/taler-wallet-core
parentcb2f4c21d85707abb0221cbf2a859a98836b2d44 (diff)
downloadwallet-core-825d2c4352022e7397854b2bd9ba7d3589873c07.tar.gz
wallet-core-825d2c4352022e7397854b2bd9ba7d3589873c07.tar.bz2
wallet-core-825d2c4352022e7397854b2bd9ba7d3589873c07.zip
make wallet-cli runnable under qtart
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/package.json8
-rw-r--r--packages/taler-wallet-core/src/bank-api-client.ts7
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.test.ts2
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/crypto-dispatcher.ts2
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/rpcClient.ts92
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/synchronousWorkerFactoryNode.ts36
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/synchronousWorkerNode.ts174
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/worker-common.ts2
-rw-r--r--packages/taler-wallet-core/src/db.ts3
-rw-r--r--packages/taler-wallet-core/src/dbless.ts2
-rw-r--r--packages/taler-wallet-core/src/dev-experiments.ts2
-rw-r--r--packages/taler-wallet-core/src/errors.ts248
-rw-r--r--packages/taler-wallet-core/src/headless/NodeHttpLib.ts183
-rw-r--r--packages/taler-wallet-core/src/host-common.ts60
-rw-r--r--packages/taler-wallet-core/src/host-impl.node.ts (renamed from packages/taler-wallet-core/src/headless/helpers.ts)78
-rw-r--r--packages/taler-wallet-core/src/host-impl.qtart.ts120
-rw-r--r--packages/taler-wallet-core/src/host.ts47
-rw-r--r--packages/taler-wallet-core/src/index.node.ts11
-rw-r--r--packages/taler-wallet-core/src/index.ts6
-rw-r--r--packages/taler-wallet-core/src/internal-wallet-state.ts13
-rw-r--r--packages/taler-wallet-core/src/operations/backup/index.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/common.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts6
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts9
-rw-r--r--packages/taler-wallet-core/src/operations/merchants.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts7
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer.ts5
-rw-r--r--packages/taler-wallet-core/src/operations/recoup.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/testing.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/tip.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts4
-rw-r--r--packages/taler-wallet-core/src/remote.ts2
-rw-r--r--packages/taler-wallet-core/src/util/http.ts354
-rw-r--r--packages/taler-wallet-core/src/util/retries.ts2
-rw-r--r--packages/taler-wallet-core/src/wallet.ts4
36 files changed, 295 insertions, 1214 deletions
diff --git a/packages/taler-wallet-core/package.json b/packages/taler-wallet-core/package.json
index 4f1692872..72b4eb410 100644
--- a/packages/taler-wallet-core/package.json
+++ b/packages/taler-wallet-core/package.json
@@ -38,7 +38,13 @@
"default": "./lib/index.js"
},
"./remote": {
- "node": "./lib/remote.js"
+ "default": "./lib/remote.js"
+ }
+ },
+ "imports": {
+ "#host-impl": {
+ "node": "./lib/host-impl.node.js",
+ "qtart": "./lib/host-impl.qtart.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/errors.ts b/packages/taler-wallet-core/src/errors.ts
deleted file mode 100644
index 038bdbc7c..000000000
--- a/packages/taler-wallet-core/src/errors.ts
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019-2020 Taler Systems SA
-
- 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/>
- */
-
-/**
- * Classes and helpers for error handling specific to wallet operations.
- *
- * @author Florian Dold <dold@taler.net>
- */
-
-/**
- * Imports.
- */
-import {
- AbsoluteTime,
- PayMerchantInsufficientBalanceDetails,
- PayPeerInsufficientBalanceDetails,
- TalerErrorCode,
- TalerErrorDetail,
- TransactionType,
-} from "@gnu-taler/taler-util";
-
-type empty = Record<string, never>;
-
-export interface DetailsMap {
- [TalerErrorCode.WALLET_PENDING_OPERATION_FAILED]: {
- innerError: TalerErrorDetail;
- transactionId?: string;
- };
- [TalerErrorCode.WALLET_EXCHANGE_DENOMINATIONS_INSUFFICIENT]: {
- exchangeBaseUrl: string;
- };
- [TalerErrorCode.WALLET_EXCHANGE_PROTOCOL_VERSION_INCOMPATIBLE]: {
- exchangeProtocolVersion: string;
- walletProtocolVersion: string;
- };
- [TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK]: empty;
- [TalerErrorCode.WALLET_TIPPING_COIN_SIGNATURE_INVALID]: empty;
- [TalerErrorCode.WALLET_ORDER_ALREADY_CLAIMED]: {
- orderId: string;
- claimUrl: string;
- };
- [TalerErrorCode.WALLET_CONTRACT_TERMS_MALFORMED]: empty;
- [TalerErrorCode.WALLET_CONTRACT_TERMS_SIGNATURE_INVALID]: {
- merchantPub: string;
- orderId: string;
- };
- [TalerErrorCode.WALLET_CONTRACT_TERMS_BASE_URL_MISMATCH]: {
- baseUrlForDownload: string;
- baseUrlFromContractTerms: string;
- };
- [TalerErrorCode.WALLET_INVALID_TALER_PAY_URI]: {
- talerPayUri: string;
- };
- [TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR]: {
- requestUrl: string;
- requestMethod: string;
- httpStatusCode: number;
- errorResponse?: any;
- };
- [TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION]: {
- stack?: string;
- };
- [TalerErrorCode.WALLET_BANK_INTEGRATION_PROTOCOL_VERSION_INCOMPATIBLE]: {
- exchangeProtocolVersion: string;
- walletProtocolVersion: string;
- };
- [TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN]: {
- operation: string;
- };
- [TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED]: {
- requestUrl: string;
- requestMethod: string;
- throttleStats: Record<string, unknown>;
- };
- [TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT]: empty;
- [TalerErrorCode.WALLET_NETWORK_ERROR]: {
- requestUrl: string;
- requestMethod: string;
- };
- [TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE]: {
- requestUrl: string;
- requestMethod: string;
- httpStatusCode: number;
- validationError?: string;
- };
- [TalerErrorCode.WALLET_EXCHANGE_COIN_SIGNATURE_INVALID]: empty;
- [TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE]: {
- errorsPerCoin: Record<number, TalerErrorDetail>;
- };
- [TalerErrorCode.WALLET_CORE_NOT_AVAILABLE]: empty;
- [TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR]: {
- httpStatusCode: number;
- };
- [TalerErrorCode.WALLET_PAY_MERCHANT_SERVER_ERROR]: {
- requestError: TalerErrorDetail;
- };
- [TalerErrorCode.WALLET_CRYPTO_WORKER_ERROR]: {
- innerError: TalerErrorDetail;
- };
- [TalerErrorCode.WALLET_CRYPTO_WORKER_BAD_REQUEST]: {
- detail: string;
- };
- [TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED]: {
- kycUrl: string;
- };
- [TalerErrorCode.WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE]: {
- insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails;
- };
- [TalerErrorCode.WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE]: {
- insufficientBalanceDetails: PayPeerInsufficientBalanceDetails;
- };
-}
-
-type ErrBody<Y> = Y extends keyof DetailsMap ? DetailsMap[Y] : empty;
-
-export function makeErrorDetail<C extends TalerErrorCode>(
- code: C,
- detail: ErrBody<C>,
- hint?: string,
-): TalerErrorDetail {
- if (!hint && !(detail as any).hint) {
- hint = getDefaultHint(code);
- }
- const when = AbsoluteTime.now();
- return { code, when, hint, ...detail };
-}
-
-export function makePendingOperationFailedError(
- innerError: TalerErrorDetail,
- tag: TransactionType,
- uid: string,
-): TalerError {
- return TalerError.fromDetail(TalerErrorCode.WALLET_PENDING_OPERATION_FAILED, {
- innerError,
- transactionId: `${tag}:${uid}`,
- });
-}
-
-export function summarizeTalerErrorDetail(ed: TalerErrorDetail): string {
- const errName = TalerErrorCode[ed.code] ?? "<unknown>";
- return `Error (${ed.code}/${errName})`;
-}
-
-function getDefaultHint(code: number): string {
- const errName = TalerErrorCode[code];
- if (errName) {
- return `Error (${errName})`;
- } else {
- return `Error (<unknown>)`;
- }
-}
-
-export class TalerProtocolViolationError extends Error {
- constructor(hint?: string) {
- let msg: string;
- if (hint) {
- msg = `Taler protocol violation error (${hint})`;
- } else {
- msg = `Taler protocol violation error`;
- }
- super(msg);
- Object.setPrototypeOf(this, TalerProtocolViolationError.prototype);
- }
-}
-
-export class TalerError<T = any> extends Error {
- errorDetail: TalerErrorDetail & T;
- private constructor(d: TalerErrorDetail & T) {
- super(d.hint ?? `Error (code ${d.code})`);
- this.errorDetail = d;
- Object.setPrototypeOf(this, TalerError.prototype);
- }
-
- static fromDetail<C extends TalerErrorCode>(
- code: C,
- detail: ErrBody<C>,
- hint?: string,
- ): TalerError {
- if (!hint) {
- hint = getDefaultHint(code);
- }
- const when = AbsoluteTime.now();
- return new TalerError<unknown>({ code, when, hint, ...detail });
- }
-
- static fromUncheckedDetail(d: TalerErrorDetail): TalerError {
- return new TalerError<unknown>({ ...d });
- }
-
- static fromException(e: any): TalerError {
- const errDetail = getErrorDetailFromException(e);
- return new TalerError(errDetail);
- }
-
- hasErrorCode<C extends keyof DetailsMap>(
- code: C,
- ): this is TalerError<DetailsMap[C]> {
- return this.errorDetail.code === code;
- }
-}
-
-/**
- * Convert an exception (or anything that was thrown) into
- * a TalerErrorDetail object.
- */
-export function getErrorDetailFromException(e: any): TalerErrorDetail {
- if (e instanceof TalerError) {
- return e.errorDetail;
- }
- if (e instanceof Error) {
- const err = makeErrorDetail(
- TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION,
- {
- stack: e.stack,
- },
- `unexpected exception (message: ${e.message})`,
- );
- return err;
- }
- // Something was thrown that is not even an exception!
- // Try to stringify it.
- let excString: string;
- try {
- excString = e.toString();
- } catch (e) {
- // Something went horribly wrong.
- excString = "can't stringify exception";
- }
- const err = makeErrorDetail(
- TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION,
- {},
- `unexpected exception (not an exception, ${excString})`,
- );
- return err;
-}
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
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-wallet-core/src/host.ts b/packages/taler-wallet-core/src/host.ts
new file mode 100644
index 000000000..4b319f081
--- /dev/null
+++ b/packages/taler-wallet-core/src/host.ts
@@ -0,0 +1,47 @@
+/*
+ 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 { DefaultNodeWalletArgs } from "./host-common.js";
+import { Wallet } from "./index.js";
+
+import * as hostImpl from "#host-impl";
+import { AccessStats } from "@gnu-taler/idb-bridge";
+
+/**
+ * Helpers to initiate a wallet in a host environment.
+ */
+
+/**
+ * Get a wallet instance.
+ */
+export async function createNativeWalletHost2(
+ args: DefaultNodeWalletArgs = {},
+): Promise<{
+ wallet: Wallet;
+ getDbStats: () => AccessStats;
+}> {
+ return hostImpl.createNativeWalletHost2(args);
+}
+
+/**
+ * Get a wallet instance.
+ */
+export async function createNativeWalletHost(
+ args: DefaultNodeWalletArgs = {},
+): Promise<Wallet> {
+ const res = await hostImpl.createNativeWalletHost2(args);
+ return res.wallet;
+}
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/http.ts b/packages/taler-wallet-core/src/util/http.ts
deleted file mode 100644
index 1da31a315..000000000
--- a/packages/taler-wallet-core/src/util/http.ts
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- This file is part of TALER
- (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
- 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
- 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/>
- */
-
-/**
- * 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 {
- 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";
-
-const logger = new Logger("http.ts");
-
-/**
- * An HTTP response that is returned by all request methods of this library.
- */
-export interface HttpResponse {
- requestUrl: string;
- requestMethod: string;
- status: number;
- headers: Headers;
- json(): Promise<any>;
- text(): Promise<string>;
- bytes(): Promise<ArrayBuffer>;
-}
-
-export const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
-
-export interface HttpRequestOptions {
- method?: "POST" | "PUT" | "GET";
- headers?: { [name: string]: string };
-
- /**
- * Timeout after which the request should be aborted.
- */
- timeout?: Duration;
-
- /**
- * Cancellation token that should abort the request when
- * cancelled.
- */
- cancellationToken?: CancellationToken;
-
- body?: string | ArrayBuffer | Record<string, unknown>;
-}
-
-/**
- * Headers, roughly modeled after the fetch API's headers object.
- */
-export class Headers {
- private headerMap = new Map<string, string>();
-
- get(name: string): string | null {
- const r = this.headerMap.get(name.toLowerCase());
- if (r) {
- return r;
- }
- return null;
- }
-
- set(name: string, value: string): void {
- const normalizedName = name.toLowerCase();
- const existing = this.headerMap.get(normalizedName);
- if (existing !== undefined) {
- this.headerMap.set(normalizedName, existing + "," + value);
- } else {
- this.headerMap.set(normalizedName, value);
- }
- }
-
- toJSON(): any {
- const m: Record<string, string> = {};
- this.headerMap.forEach((v, k) => (m[k] = v));
- return m;
- }
-}
-
-/**
- * Interface for the HTTP request library used by the wallet.
- *
- * The request library is bundled into an interface to make mocking and
- * request tunneling easy.
- */
-export interface HttpRequestLibrary {
- /**
- * Make an HTTP GET request.
- *
- * FIXME: Get rid of this, we want the API surface to be minimal.
- */
- get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse>;
-
- /**
- * Make an HTTP POST request with a JSON body.
- *
- * FIXME: Get rid of this, we want the API surface to be minimal.
- */
- postJson(
- url: string,
- body: any,
- opt?: HttpRequestOptions,
- ): Promise<HttpResponse>;
-
- /**
- * Make an HTTP POST request with a JSON body.
- */
- fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse>;
-}
-
-type TalerErrorResponse = {
- code: number;
-} & unknown;
-
-type ResponseOrError<T> =
- | { isError: false; response: T }
- | { isError: true; talerErrorResponse: TalerErrorResponse };
-
-export async function readTalerErrorResponse(
- httpResponse: HttpResponse,
-): Promise<TalerErrorDetail> {
- const errJson = await httpResponse.json();
- const talerErrorCode = errJson.code;
- if (typeof talerErrorCode !== "number") {
- logger.warn(
- `malformed error response (status ${httpResponse.status}): ${j2s(
- errJson,
- )}`,
- );
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- requestUrl: httpResponse.requestUrl,
- requestMethod: httpResponse.requestMethod,
- httpStatusCode: httpResponse.status,
- },
- "Error response did not contain error code",
- );
- }
- return errJson;
-}
-
-export async function readUnexpectedResponseDetails(
- httpResponse: HttpResponse,
-): Promise<TalerErrorDetail> {
- const errJson = await httpResponse.json();
- const talerErrorCode = errJson.code;
- if (typeof talerErrorCode !== "number") {
- return makeErrorDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- requestUrl: httpResponse.requestUrl,
- requestMethod: httpResponse.requestMethod,
- httpStatusCode: httpResponse.status,
- },
- "Error response did not contain error code",
- );
- }
- return makeErrorDetail(
- TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
- {
- requestUrl: httpResponse.requestUrl,
- requestMethod: httpResponse.requestMethod,
- httpStatusCode: httpResponse.status,
- errorResponse: errJson,
- },
- `Unexpected HTTP status (${httpResponse.status}) in response`,
- );
-}
-
-export async function readSuccessResponseJsonOrErrorCode<T>(
- httpResponse: HttpResponse,
- codec: Codec<T>,
-): Promise<ResponseOrError<T>> {
- if (!(httpResponse.status >= 200 && httpResponse.status < 300)) {
- return {
- isError: true,
- talerErrorResponse: await readTalerErrorResponse(httpResponse),
- };
- }
- const respJson = await httpResponse.json();
- let parsedResponse: T;
- try {
- parsedResponse = codec.decode(respJson);
- } catch (e: any) {
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- requestUrl: httpResponse.requestUrl,
- requestMethod: httpResponse.requestMethod,
- httpStatusCode: httpResponse.status,
- validationError: e.toString(),
- },
- "Response invalid",
- );
- }
- return {
- isError: false,
- response: parsedResponse,
- };
-}
-
-type HttpErrorDetails = {
- requestUrl: string;
- requestMethod: string;
- httpStatusCode: number;
-};
-
-export function getHttpResponseErrorDetails(
- httpResponse: HttpResponse,
-): HttpErrorDetails {
- return {
- requestUrl: httpResponse.requestUrl,
- requestMethod: httpResponse.requestMethod,
- httpStatusCode: httpResponse.status,
- };
-}
-
-export function throwUnexpectedRequestError(
- httpResponse: HttpResponse,
- talerErrorResponse: TalerErrorResponse,
-): never {
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
- {
- requestUrl: httpResponse.requestUrl,
- requestMethod: httpResponse.requestMethod,
- httpStatusCode: httpResponse.status,
- errorResponse: talerErrorResponse,
- },
- `Unexpected HTTP status ${httpResponse.status} in response`,
- );
-}
-
-export async function readSuccessResponseJsonOrThrow<T>(
- httpResponse: HttpResponse,
- codec: Codec<T>,
-): Promise<T> {
- const r = await readSuccessResponseJsonOrErrorCode(httpResponse, codec);
- if (!r.isError) {
- return r.response;
- }
- throwUnexpectedRequestError(httpResponse, r.talerErrorResponse);
-}
-
-export async function readSuccessResponseTextOrErrorCode<T>(
- httpResponse: HttpResponse,
-): Promise<ResponseOrError<string>> {
- if (!(httpResponse.status >= 200 && httpResponse.status < 300)) {
- const errJson = await httpResponse.json();
- const talerErrorCode = errJson.code;
- if (typeof talerErrorCode !== "number") {
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- httpStatusCode: httpResponse.status,
- requestUrl: httpResponse.requestUrl,
- requestMethod: httpResponse.requestMethod,
- },
- "Error response did not contain error code",
- );
- }
- return {
- isError: true,
- talerErrorResponse: errJson,
- };
- }
- const respJson = await httpResponse.text();
- return {
- isError: false,
- response: respJson,
- };
-}
-
-export async function checkSuccessResponseOrThrow(
- httpResponse: HttpResponse,
-): Promise<void> {
- if (!(httpResponse.status >= 200 && httpResponse.status < 300)) {
- const errJson = await httpResponse.json();
- const talerErrorCode = errJson.code;
- if (typeof talerErrorCode !== "number") {
- throw TalerError.fromDetail(
- TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
- {
- httpStatusCode: httpResponse.status,
- requestUrl: httpResponse.requestUrl,
- requestMethod: httpResponse.requestMethod,
- },
- "Error response did not contain error code",
- );
- }
- throwUnexpectedRequestError(httpResponse, errJson);
- }
-}
-
-export async function readSuccessResponseTextOrThrow<T>(
- httpResponse: HttpResponse,
-): Promise<string> {
- const r = await readSuccessResponseTextOrErrorCode(httpResponse);
- if (!r.isError) {
- return r.response;
- }
- throwUnexpectedRequestError(httpResponse, r.talerErrorResponse);
-}
-
-/**
- * Get the timestamp at which the response's content is considered expired.
- */
-export function getExpiry(
- httpResponse: HttpResponse,
- opt: { minDuration?: Duration },
-): AbsoluteTime {
- const expiryDateMs = new Date(
- httpResponse.headers.get("expiry") ?? "",
- ).getTime();
- let t: AbsoluteTime;
- if (Number.isNaN(expiryDateMs)) {
- t = AbsoluteTime.now();
- } else {
- t = {
- t_ms: expiryDateMs,
- };
- }
- if (opt.minDuration) {
- const t2 = AbsoluteTime.addDuration(AbsoluteTime.now(), opt.minDuration);
- return AbsoluteTime.max(t, t2);
- }
- return t;
-}
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,