wallet-core: use numeric status field to allow range queries
This commit is contained in:
parent
5d31803c92
commit
7d6bcd42ea
@ -62,6 +62,8 @@ import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
|
||||
* will have an index.
|
||||
* - Amounts are stored as strings, except when they are needed for
|
||||
* indexing.
|
||||
* - Every record that has a corresponding transaction item must have
|
||||
* an index for a mandatory timestamp field.
|
||||
* - Optional fields should be avoided, use "T | undefined" instead.
|
||||
*
|
||||
* @author Florian Dold <dold@taler.net>
|
||||
@ -94,38 +96,45 @@ export const CURRENT_DB_CONFIG_KEY = "currentMainDbName";
|
||||
*/
|
||||
export const WALLET_DB_MINOR_VERSION = 1;
|
||||
|
||||
export namespace OperationStatusRange {
|
||||
export const ACTIVE_START = 10;
|
||||
export const ACTIVE_END = 29;
|
||||
export const DORMANT_START = 40;
|
||||
export const DORMANT_END = 59;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of a withdrawal.
|
||||
*/
|
||||
export enum ReserveRecordStatus {
|
||||
export enum WithdrawalGroupStatus {
|
||||
/**
|
||||
* Reserve must be registered with the bank.
|
||||
*/
|
||||
RegisteringBank = "registering-bank",
|
||||
RegisteringBank = OperationStatusRange.ACTIVE_START,
|
||||
|
||||
/**
|
||||
* We've registered reserve's information with the bank
|
||||
* and are now waiting for the user to confirm the withdraw
|
||||
* with the bank (typically 2nd factor auth).
|
||||
*/
|
||||
WaitConfirmBank = "wait-confirm-bank",
|
||||
WaitConfirmBank = OperationStatusRange.ACTIVE_START + 1,
|
||||
|
||||
/**
|
||||
* Querying reserve status with the exchange.
|
||||
*/
|
||||
QueryingStatus = "querying-status",
|
||||
QueryingStatus = OperationStatusRange.ACTIVE_START + 2,
|
||||
|
||||
/**
|
||||
* The corresponding withdraw record has been created.
|
||||
* No further processing is done, unless explicitly requested
|
||||
* by the user.
|
||||
*/
|
||||
Dormant = "dormant",
|
||||
Finished = OperationStatusRange.DORMANT_START,
|
||||
|
||||
/**
|
||||
* The bank aborted the withdrawal.
|
||||
*/
|
||||
BankAborted = "bank-aborted",
|
||||
BankAborted = OperationStatusRange.DORMANT_START + 1,
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1354,20 +1363,12 @@ export interface WithdrawalGroupRecord {
|
||||
*/
|
||||
timestampFinish?: TalerProtocolTimestamp;
|
||||
|
||||
/**
|
||||
* Operation status of the withdrawal group.
|
||||
* Used for indexing in the database.
|
||||
*
|
||||
* FIXME: Redundant with reserveStatus
|
||||
*/
|
||||
operationStatus: OperationStatus;
|
||||
|
||||
/**
|
||||
* Current status of the reserve.
|
||||
*
|
||||
* FIXME: Wrong name!
|
||||
*/
|
||||
reserveStatus: ReserveRecordStatus;
|
||||
status: WithdrawalGroupStatus;
|
||||
|
||||
/**
|
||||
* Amount that was sent by the user to fund the reserve.
|
||||
@ -1947,7 +1948,7 @@ export const WalletStoresV1 = {
|
||||
}),
|
||||
{
|
||||
byReservePub: describeIndex("byReservePub", "reservePub"),
|
||||
byStatus: describeIndex("byStatus", "operationStatus"),
|
||||
byStatus: describeIndex("byStatus", "status"),
|
||||
byTalerWithdrawUri: describeIndex(
|
||||
"byTalerWithdrawUri",
|
||||
"wgInfo.bankInfo.talerWithdrawUri",
|
||||
|
@ -71,6 +71,7 @@ import {
|
||||
RefreshCoinStatus,
|
||||
RefundState,
|
||||
WALLET_BACKUP_STATE_KEY,
|
||||
WithdrawalGroupStatus,
|
||||
WithdrawalRecordType,
|
||||
} from "../../db.js";
|
||||
import { InternalWalletState } from "../../internal-wallet-state.js";
|
||||
@ -167,8 +168,9 @@ export async function exportBackup(
|
||||
instructed_amount: Amounts.stringify(wg.instructedAmount),
|
||||
reserve_priv: wg.reservePriv,
|
||||
restrict_age: wg.restrictAge,
|
||||
// FIXME: proper status conversion!
|
||||
operation_status:
|
||||
wg.operationStatus == OperationStatus.Finished
|
||||
wg.status == WithdrawalGroupStatus.Finished
|
||||
? BackupOperationStatus.Finished
|
||||
: BackupOperationStatus.Pending,
|
||||
selected_denoms_uid: wg.denomSelUid,
|
||||
|
@ -52,7 +52,7 @@ import {
|
||||
RefreshSessionRecord,
|
||||
RefundState,
|
||||
ReserveBankInfo,
|
||||
ReserveRecordStatus,
|
||||
WithdrawalGroupStatus,
|
||||
WalletContractData,
|
||||
WalletRefundItem,
|
||||
WalletStoresV1,
|
||||
@ -531,9 +531,6 @@ export async function importBackup(
|
||||
exchangeBaseUrl: backupWg.exchange_base_url,
|
||||
instructedAmount: Amounts.parseOrThrow(backupWg.instructed_amount),
|
||||
secretSeed: backupWg.secret_seed,
|
||||
operationStatus: backupWg.timestamp_finish
|
||||
? OperationStatus.Finished
|
||||
: OperationStatus.Pending,
|
||||
denomsSel: await getDenomSelStateFromBackup(
|
||||
tx,
|
||||
backupWg.exchange_base_url,
|
||||
@ -545,9 +542,9 @@ export async function importBackup(
|
||||
),
|
||||
reservePriv: backupWg.reserve_priv,
|
||||
reservePub,
|
||||
reserveStatus: backupWg.timestamp_finish
|
||||
? ReserveRecordStatus.Dormant
|
||||
: ReserveRecordStatus.QueryingStatus, // FIXME!
|
||||
status: backupWg.timestamp_finish
|
||||
? WithdrawalGroupStatus.Finished
|
||||
: WithdrawalGroupStatus.QueryingStatus, // FIXME!
|
||||
timestampStart: backupWg.timestamp_created,
|
||||
wgInfo,
|
||||
restrictAge: backupWg.restrict_age,
|
||||
|
@ -65,7 +65,7 @@ import {
|
||||
import {
|
||||
CoinStatus,
|
||||
MergeReserveInfo,
|
||||
ReserveRecordStatus,
|
||||
WithdrawalGroupStatus,
|
||||
WalletStoresV1,
|
||||
WithdrawalRecordType,
|
||||
} from "../db.js";
|
||||
@ -544,7 +544,7 @@ export async function acceptPeerPushPayment(
|
||||
contractTerms: peerInc.contractTerms,
|
||||
},
|
||||
exchangeBaseUrl: peerInc.exchangeBaseUrl,
|
||||
reserveStatus: ReserveRecordStatus.QueryingStatus,
|
||||
reserveStatus: WithdrawalGroupStatus.QueryingStatus,
|
||||
reserveKeyPair: {
|
||||
priv: mergeReserveInfo.reservePriv,
|
||||
pub: mergeReserveInfo.reservePub,
|
||||
@ -828,7 +828,7 @@ export async function initiatePeerRequestForPay(
|
||||
contractPriv: econtractResp.contractPriv,
|
||||
},
|
||||
exchangeBaseUrl: req.exchangeBaseUrl,
|
||||
reserveStatus: ReserveRecordStatus.QueryingStatus,
|
||||
reserveStatus: WithdrawalGroupStatus.QueryingStatus,
|
||||
reserveKeyPair: {
|
||||
priv: mergeReserveInfo.reservePriv,
|
||||
pub: mergeReserveInfo.reservePub,
|
||||
|
@ -28,6 +28,9 @@ import {
|
||||
BackupProviderStateTag,
|
||||
RefreshCoinStatus,
|
||||
OperationStatus,
|
||||
WithdrawalGroupRecord,
|
||||
WithdrawalGroupStatus,
|
||||
OperationStatusRange,
|
||||
} from "../db.js";
|
||||
import {
|
||||
PendingOperationsResponse,
|
||||
@ -38,6 +41,7 @@ import { InternalWalletState } from "../internal-wallet-state.js";
|
||||
import { GetReadOnlyAccess } from "../util/query.js";
|
||||
import { RetryTags } from "../util/retries.js";
|
||||
import { Wallet } from "../wallet.js";
|
||||
import { GlobalIDB } from "@gnu-taler/idb-bridge";
|
||||
|
||||
async function gatherExchangePending(
|
||||
tx: GetReadOnlyAccess<{
|
||||
@ -120,7 +124,10 @@ async function gatherWithdrawalPending(
|
||||
resp: PendingOperationsResponse,
|
||||
): Promise<void> {
|
||||
const wsrs = await tx.withdrawalGroups.indexes.byStatus.getAll(
|
||||
OperationStatus.Pending,
|
||||
GlobalIDB.KeyRange.bound(
|
||||
OperationStatusRange.ACTIVE_START,
|
||||
OperationStatusRange.ACTIVE_END,
|
||||
),
|
||||
);
|
||||
for (const wsr of wsrs) {
|
||||
if (wsr.timestampFinish) {
|
||||
|
@ -44,7 +44,7 @@ import {
|
||||
CoinStatus,
|
||||
RecoupGroupRecord,
|
||||
RefreshCoinSource,
|
||||
ReserveRecordStatus,
|
||||
WithdrawalGroupStatus,
|
||||
WalletStoresV1,
|
||||
WithdrawalRecordType,
|
||||
WithdrawCoinSource,
|
||||
@ -382,7 +382,7 @@ export async function processRecoupGroupHandler(
|
||||
await internalCreateWithdrawalGroup(ws, {
|
||||
amount: Amounts.parseOrThrow(result.balance),
|
||||
exchangeBaseUrl: recoupGroup.exchangeBaseUrl,
|
||||
reserveStatus: ReserveRecordStatus.QueryingStatus,
|
||||
reserveStatus: WithdrawalGroupStatus.QueryingStatus,
|
||||
reserveKeyPair: {
|
||||
pub: reservePub,
|
||||
priv: reservePrivMap[reservePub],
|
||||
|
@ -31,11 +31,9 @@ import {
|
||||
TalerProtocolTimestamp,
|
||||
Transaction,
|
||||
TransactionByIdRequest,
|
||||
TransactionRefund,
|
||||
TransactionsRequest,
|
||||
TransactionsResponse,
|
||||
TransactionType,
|
||||
WithdrawalDetails,
|
||||
WithdrawalType,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import {
|
||||
|
@ -71,7 +71,7 @@ import {
|
||||
ExchangeRecord,
|
||||
OperationStatus,
|
||||
PlanchetRecord,
|
||||
ReserveRecordStatus,
|
||||
WithdrawalGroupStatus,
|
||||
WalletStoresV1,
|
||||
WgInfo,
|
||||
WithdrawalGroupRecord,
|
||||
@ -91,7 +91,11 @@ import {
|
||||
readSuccessResponseJsonOrThrow,
|
||||
throwUnexpectedRequestError,
|
||||
} from "../util/http.js";
|
||||
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
|
||||
import {
|
||||
checkDbInvariant,
|
||||
checkLogicInvariant,
|
||||
InvariantViolatedError,
|
||||
} from "../util/invariants.js";
|
||||
import { DbAccess, GetReadOnlyAccess } from "../util/query.js";
|
||||
import {
|
||||
OperationAttemptResult,
|
||||
@ -962,7 +966,7 @@ async function queryReserve(
|
||||
withdrawalGroupId,
|
||||
});
|
||||
checkDbInvariant(!!withdrawalGroup);
|
||||
if (withdrawalGroup.reserveStatus !== ReserveRecordStatus.QueryingStatus) {
|
||||
if (withdrawalGroup.status !== WithdrawalGroupStatus.QueryingStatus) {
|
||||
return { ready: true };
|
||||
}
|
||||
const reservePub = withdrawalGroup.reservePub;
|
||||
@ -1010,7 +1014,7 @@ async function queryReserve(
|
||||
logger.warn(`withdrawal group ${withdrawalGroupId} not found`);
|
||||
return;
|
||||
}
|
||||
wg.reserveStatus = ReserveRecordStatus.Dormant;
|
||||
wg.status = WithdrawalGroupStatus.Finished;
|
||||
await tx.withdrawalGroups.put(wg);
|
||||
});
|
||||
|
||||
@ -1039,13 +1043,13 @@ export async function processWithdrawalGroup(
|
||||
throw Error(`withdrawal group ${withdrawalGroupId} not found`);
|
||||
}
|
||||
|
||||
switch (withdrawalGroup.reserveStatus) {
|
||||
case ReserveRecordStatus.RegisteringBank:
|
||||
switch (withdrawalGroup.status) {
|
||||
case WithdrawalGroupStatus.RegisteringBank:
|
||||
await processReserveBankStatus(ws, withdrawalGroupId);
|
||||
return await processWithdrawalGroup(ws, withdrawalGroupId, {
|
||||
forceNow: true,
|
||||
});
|
||||
case ReserveRecordStatus.QueryingStatus: {
|
||||
case WithdrawalGroupStatus.QueryingStatus: {
|
||||
const res = await queryReserve(ws, withdrawalGroupId);
|
||||
if (res.ready) {
|
||||
return await processWithdrawalGroup(ws, withdrawalGroupId, {
|
||||
@ -1057,7 +1061,7 @@ export async function processWithdrawalGroup(
|
||||
result: undefined,
|
||||
};
|
||||
}
|
||||
case ReserveRecordStatus.WaitConfirmBank: {
|
||||
case WithdrawalGroupStatus.WaitConfirmBank: {
|
||||
const res = await processReserveBankStatus(ws, withdrawalGroupId);
|
||||
switch (res.status) {
|
||||
case BankStatusResultCode.Aborted:
|
||||
@ -1075,23 +1079,20 @@ export async function processWithdrawalGroup(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ReserveRecordStatus.BankAborted: {
|
||||
case WithdrawalGroupStatus.BankAborted: {
|
||||
// FIXME
|
||||
return {
|
||||
type: OperationAttemptResultType.Pending,
|
||||
result: undefined,
|
||||
};
|
||||
}
|
||||
case ReserveRecordStatus.Dormant:
|
||||
case WithdrawalGroupStatus.Finished:
|
||||
// We can try to withdraw, nothing needs to be done with the reserve.
|
||||
break;
|
||||
default:
|
||||
logger.warn(
|
||||
"unknown reserve record status:",
|
||||
withdrawalGroup.reserveStatus,
|
||||
throw new InvariantViolatedError(
|
||||
`unknown reserve record status: ${withdrawalGroup.status}`,
|
||||
);
|
||||
assertUnreachable(withdrawalGroup.reserveStatus);
|
||||
break;
|
||||
}
|
||||
|
||||
await ws.exchangeOps.updateExchangeFromUrl(
|
||||
@ -1108,7 +1109,7 @@ export async function processWithdrawalGroup(
|
||||
if (!wg) {
|
||||
return;
|
||||
}
|
||||
wg.operationStatus = OperationStatus.Finished;
|
||||
wg.status = WithdrawalGroupStatus.Finished;
|
||||
wg.timestampFinish = TalerProtocolTimestamp.now();
|
||||
await tx.withdrawalGroups.put(wg);
|
||||
});
|
||||
@ -1192,7 +1193,7 @@ export async function processWithdrawalGroup(
|
||||
if (wg.timestampFinish === undefined && numFinished === numTotalCoins) {
|
||||
finishedForFirstTime = true;
|
||||
wg.timestampFinish = TalerProtocolTimestamp.now();
|
||||
wg.operationStatus = OperationStatus.Finished;
|
||||
wg.status = WithdrawalGroupStatus.Finished;
|
||||
}
|
||||
|
||||
await tx.withdrawalGroups.put(wg);
|
||||
@ -1508,9 +1509,9 @@ async function registerReserveWithBank(
|
||||
.runReadOnly(async (tx) => {
|
||||
return await tx.withdrawalGroups.get(withdrawalGroupId);
|
||||
});
|
||||
switch (withdrawalGroup?.reserveStatus) {
|
||||
case ReserveRecordStatus.WaitConfirmBank:
|
||||
case ReserveRecordStatus.RegisteringBank:
|
||||
switch (withdrawalGroup?.status) {
|
||||
case WithdrawalGroupStatus.WaitConfirmBank:
|
||||
case WithdrawalGroupStatus.RegisteringBank:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -1544,9 +1545,9 @@ async function registerReserveWithBank(
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
switch (r.reserveStatus) {
|
||||
case ReserveRecordStatus.RegisteringBank:
|
||||
case ReserveRecordStatus.WaitConfirmBank:
|
||||
switch (r.status) {
|
||||
case WithdrawalGroupStatus.RegisteringBank:
|
||||
case WithdrawalGroupStatus.WaitConfirmBank:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -1557,8 +1558,7 @@ async function registerReserveWithBank(
|
||||
r.wgInfo.bankInfo.timestampReserveInfoPosted = AbsoluteTime.toTimestamp(
|
||||
AbsoluteTime.now(),
|
||||
);
|
||||
r.reserveStatus = ReserveRecordStatus.WaitConfirmBank;
|
||||
r.operationStatus = OperationStatus.Pending;
|
||||
r.status = WithdrawalGroupStatus.WaitConfirmBank;
|
||||
await tx.withdrawalGroups.put(r);
|
||||
});
|
||||
ws.notify({ type: NotificationType.ReserveRegisteredWithBank });
|
||||
@ -1575,9 +1575,9 @@ async function processReserveBankStatus(
|
||||
const withdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {
|
||||
withdrawalGroupId,
|
||||
});
|
||||
switch (withdrawalGroup?.reserveStatus) {
|
||||
case ReserveRecordStatus.WaitConfirmBank:
|
||||
case ReserveRecordStatus.RegisteringBank:
|
||||
switch (withdrawalGroup?.status) {
|
||||
case WithdrawalGroupStatus.WaitConfirmBank:
|
||||
case WithdrawalGroupStatus.RegisteringBank:
|
||||
break;
|
||||
default:
|
||||
return {
|
||||
@ -1616,9 +1616,9 @@ async function processReserveBankStatus(
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
switch (r.reserveStatus) {
|
||||
case ReserveRecordStatus.RegisteringBank:
|
||||
case ReserveRecordStatus.WaitConfirmBank:
|
||||
switch (r.status) {
|
||||
case WithdrawalGroupStatus.RegisteringBank:
|
||||
case WithdrawalGroupStatus.WaitConfirmBank:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -1628,8 +1628,7 @@ async function processReserveBankStatus(
|
||||
}
|
||||
const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
|
||||
r.wgInfo.bankInfo.timestampBankConfirmed = now;
|
||||
r.reserveStatus = ReserveRecordStatus.BankAborted;
|
||||
r.operationStatus = OperationStatus.Finished;
|
||||
r.status = WithdrawalGroupStatus.BankAborted;
|
||||
await tx.withdrawalGroups.put(r);
|
||||
});
|
||||
return {
|
||||
@ -1644,7 +1643,7 @@ async function processReserveBankStatus(
|
||||
}
|
||||
|
||||
// FIXME: Why do we do this?!
|
||||
if (withdrawalGroup.reserveStatus === ReserveRecordStatus.RegisteringBank) {
|
||||
if (withdrawalGroup.status === WithdrawalGroupStatus.RegisteringBank) {
|
||||
await registerReserveWithBank(ws, withdrawalGroupId);
|
||||
return await processReserveBankStatus(ws, withdrawalGroupId);
|
||||
}
|
||||
@ -1657,9 +1656,9 @@ async function processReserveBankStatus(
|
||||
return;
|
||||
}
|
||||
// Re-check reserve status within transaction
|
||||
switch (r.reserveStatus) {
|
||||
case ReserveRecordStatus.RegisteringBank:
|
||||
case ReserveRecordStatus.WaitConfirmBank:
|
||||
switch (r.status) {
|
||||
case WithdrawalGroupStatus.RegisteringBank:
|
||||
case WithdrawalGroupStatus.WaitConfirmBank:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -1671,8 +1670,7 @@ async function processReserveBankStatus(
|
||||
logger.info("withdrawal: transfer confirmed by bank.");
|
||||
const now = AbsoluteTime.toTimestamp(AbsoluteTime.now());
|
||||
r.wgInfo.bankInfo.timestampBankConfirmed = now;
|
||||
r.reserveStatus = ReserveRecordStatus.QueryingStatus;
|
||||
r.operationStatus = OperationStatus.Pending;
|
||||
r.status = WithdrawalGroupStatus.QueryingStatus;
|
||||
} else {
|
||||
logger.info("withdrawal: transfer not yet confirmed by bank");
|
||||
r.wgInfo.bankInfo.confirmUrl = status.confirm_transfer_url;
|
||||
@ -1689,7 +1687,7 @@ async function processReserveBankStatus(
|
||||
export async function internalCreateWithdrawalGroup(
|
||||
ws: InternalWalletState,
|
||||
args: {
|
||||
reserveStatus: ReserveRecordStatus;
|
||||
reserveStatus: WithdrawalGroupStatus;
|
||||
amount: AmountJson;
|
||||
exchangeBaseUrl: string;
|
||||
forcedDenomSel?: ForcedDenomSel;
|
||||
@ -1728,12 +1726,11 @@ export async function internalCreateWithdrawalGroup(
|
||||
exchangeBaseUrl: canonExchange,
|
||||
instructedAmount: amount,
|
||||
timestampStart: now,
|
||||
operationStatus: OperationStatus.Pending,
|
||||
rawWithdrawalAmount: initialDenomSel.totalWithdrawCost,
|
||||
secretSeed,
|
||||
reservePriv: reserveKeyPair.priv,
|
||||
reservePub: reserveKeyPair.pub,
|
||||
reserveStatus: args.reserveStatus,
|
||||
status: args.reserveStatus,
|
||||
withdrawalGroupId,
|
||||
restrictAge: args.restrictAge,
|
||||
senderWire: undefined,
|
||||
@ -1839,7 +1836,7 @@ export async function acceptWithdrawalFromUri(
|
||||
},
|
||||
restrictAge: req.restrictAge,
|
||||
forcedDenomSel: req.forcedDenomSel,
|
||||
reserveStatus: ReserveRecordStatus.RegisteringBank,
|
||||
reserveStatus: WithdrawalGroupStatus.RegisteringBank,
|
||||
});
|
||||
|
||||
const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
|
||||
@ -1850,9 +1847,7 @@ export async function acceptWithdrawalFromUri(
|
||||
const processedWithdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {
|
||||
withdrawalGroupId,
|
||||
});
|
||||
if (
|
||||
processedWithdrawalGroup?.reserveStatus === ReserveRecordStatus.BankAborted
|
||||
) {
|
||||
if (processedWithdrawalGroup?.status === WithdrawalGroupStatus.BankAborted) {
|
||||
throw TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK,
|
||||
{},
|
||||
@ -1898,7 +1893,7 @@ export async function createManualWithdrawal(
|
||||
exchangeBaseUrl: req.exchangeBaseUrl,
|
||||
forcedDenomSel: req.forcedDenomSel,
|
||||
restrictAge: req.restrictAge,
|
||||
reserveStatus: ReserveRecordStatus.QueryingStatus,
|
||||
reserveStatus: WithdrawalGroupStatus.QueryingStatus,
|
||||
});
|
||||
|
||||
const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
|
||||
|
@ -14,6 +14,13 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
export class InvariantViolatedError extends Error {
|
||||
constructor(message?: string) {
|
||||
super(message);
|
||||
Object.setPrototypeOf(this, InvariantViolatedError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers for invariants.
|
||||
*/
|
||||
|
@ -36,8 +36,6 @@ import {
|
||||
IDBKeyRange,
|
||||
} from "@gnu-taler/idb-bridge";
|
||||
import { Logger } from "@gnu-taler/taler-util";
|
||||
import { performanceNow } from "./timer.js";
|
||||
import { access } from "fs";
|
||||
|
||||
const logger = new Logger("query.ts");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user