make linter less grumpy

This commit is contained in:
Florian Dold 2020-04-06 23:32:01 +05:30
parent f36bb7a04e
commit 47787c0b0b
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
32 changed files with 509 additions and 1761 deletions

View File

@ -1,13 +1,26 @@
module.exports = { module.exports = {
root: true, root: true,
parser: '@typescript-eslint/parser', parser: "@typescript-eslint/parser",
plugins: [ plugins: ["@typescript-eslint"],
'@typescript-eslint',
],
extends: [ extends: [
'eslint:recommended', "eslint:recommended",
'plugin:@typescript-eslint/eslint-recommended', "plugin:@typescript-eslint/eslint-recommended",
'plugin:@typescript-eslint/recommended', "plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
], ],
rules: {}, rules: {
"no-constant-condition": ["error", { "checkLoops": false }],
"prefer-const": ["warn", { destructuring: "all" }],
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": ["warn", { args: "none" }],
"@typescript-eslint/explicit-function-return-type": [
"warn",
{ allowExpressions: true },
],
"@typescript-eslint/no-use-before-define": [
"error",
{ functions: false, classes: false },
],
},
}; };

View File

@ -84,3 +84,6 @@ endif
rollup: tsc rollup: tsc
./node_modules/.bin/rollup -c ./node_modules/.bin/rollup -c
.PHONY: lint
lint:
./node_modules/.bin/eslint 'src/**/*'

File diff suppressed because it is too large Load Diff

View File

@ -620,7 +620,7 @@ export async function processDownloadProposal(
proposalId: string, proposalId: string,
forceNow = false, forceNow = false,
): Promise<void> { ): Promise<void> {
const onOpErr = (err: OperationError) => const onOpErr = (err: OperationError): Promise<void> =>
incrementProposalRetry(ws, proposalId, err); incrementProposalRetry(ws, proposalId, err);
await guardOperationException( await guardOperationException(
() => processDownloadProposalImpl(ws, proposalId, forceNow), () => processDownloadProposalImpl(ws, proposalId, forceNow),
@ -631,7 +631,7 @@ export async function processDownloadProposal(
async function resetDownloadProposalRetry( async function resetDownloadProposalRetry(
ws: InternalWalletState, ws: InternalWalletState,
proposalId: string, proposalId: string,
) { ): Promise<void> {
await ws.db.mutate(Stores.proposals, proposalId, (x) => { await ws.db.mutate(Stores.proposals, proposalId, (x) => {
if (x.retryInfo.active) { if (x.retryInfo.active) {
x.retryInfo = initRetryInfo(); x.retryInfo = initRetryInfo();
@ -1108,7 +1108,7 @@ export async function processPurchasePay(
proposalId: string, proposalId: string,
forceNow = false, forceNow = false,
): Promise<void> { ): Promise<void> {
const onOpErr = (e: OperationError) => const onOpErr = (e: OperationError): Promise<void> =>
incrementPurchasePayRetry(ws, proposalId, e); incrementPurchasePayRetry(ws, proposalId, e);
await guardOperationException( await guardOperationException(
() => processPurchasePayImpl(ws, proposalId, forceNow), () => processPurchasePayImpl(ws, proposalId, forceNow),
@ -1119,7 +1119,7 @@ export async function processPurchasePay(
async function resetPurchasePayRetry( async function resetPurchasePayRetry(
ws: InternalWalletState, ws: InternalWalletState,
proposalId: string, proposalId: string,
) { ): Promise<void> {
await ws.db.mutate(Stores.purchases, proposalId, (x) => { await ws.db.mutate(Stores.purchases, proposalId, (x) => {
if (x.payRetryInfo.active) { if (x.payRetryInfo.active) {
x.payRetryInfo = initRetryInfo(); x.payRetryInfo = initRetryInfo();
@ -1150,7 +1150,7 @@ async function processPurchasePayImpl(
export async function refuseProposal( export async function refuseProposal(
ws: InternalWalletState, ws: InternalWalletState,
proposalId: string, proposalId: string,
) { ): Promise<void> {
const success = await ws.db.runWithWriteTransaction( const success = await ws.db.runWithWriteTransaction(
[Stores.proposals], [Stores.proposals],
async (tx) => { async (tx) => {

View File

@ -302,7 +302,7 @@ export async function processPurchaseQueryRefund(
proposalId: string, proposalId: string,
forceNow = false, forceNow = false,
): Promise<void> { ): Promise<void> {
const onOpErr = (e: OperationError) => const onOpErr = (e: OperationError): Promise<void> =>
incrementPurchaseQueryRefundRetry(ws, proposalId, e); incrementPurchaseQueryRefundRetry(ws, proposalId, e);
await guardOperationException( await guardOperationException(
() => processPurchaseQueryRefundImpl(ws, proposalId, forceNow), () => processPurchaseQueryRefundImpl(ws, proposalId, forceNow),
@ -313,7 +313,7 @@ export async function processPurchaseQueryRefund(
async function resetPurchaseQueryRefundRetry( async function resetPurchaseQueryRefundRetry(
ws: InternalWalletState, ws: InternalWalletState,
proposalId: string, proposalId: string,
) { ): Promise<void> {
await ws.db.mutate(Stores.purchases, proposalId, (x) => { await ws.db.mutate(Stores.purchases, proposalId, (x) => {
if (x.refundStatusRetryInfo.active) { if (x.refundStatusRetryInfo.active) {
x.refundStatusRetryInfo = initRetryInfo(); x.refundStatusRetryInfo = initRetryInfo();
@ -368,7 +368,7 @@ export async function processPurchaseApplyRefund(
proposalId: string, proposalId: string,
forceNow = false, forceNow = false,
): Promise<void> { ): Promise<void> {
const onOpErr = (e: OperationError) => const onOpErr = (e: OperationError): Promise<void> =>
incrementPurchaseApplyRefundRetry(ws, proposalId, e); incrementPurchaseApplyRefundRetry(ws, proposalId, e);
await guardOperationException( await guardOperationException(
() => processPurchaseApplyRefundImpl(ws, proposalId, forceNow), () => processPurchaseApplyRefundImpl(ws, proposalId, forceNow),
@ -379,7 +379,7 @@ export async function processPurchaseApplyRefund(
async function resetPurchaseApplyRefundRetry( async function resetPurchaseApplyRefundRetry(
ws: InternalWalletState, ws: InternalWalletState,
proposalId: string, proposalId: string,
) { ): Promise<void> {
await ws.db.mutate(Stores.purchases, proposalId, (x) => { await ws.db.mutate(Stores.purchases, proposalId, (x) => {
if (x.refundApplyRetryInfo.active) { if (x.refundApplyRetryInfo.active) {
x.refundApplyRetryInfo = initRetryInfo(); x.refundApplyRetryInfo = initRetryInfo();
@ -435,11 +435,10 @@ async function processPurchaseApplyRefundImpl(
// We're too late, refund is expired. // We're too late, refund is expired.
newRefundsFailed[pk] = info; newRefundsFailed[pk] = info;
break; break;
default: default: {
let body: string | null = null; let body: string | null = null;
try { // FIXME: error handling!
body = await resp.json(); body = await resp.json();
} catch {}
const m = "refund request (at exchange) failed"; const m = "refund request (at exchange) failed";
throw new OperationFailedError({ throw new OperationFailedError({
message: m, message: m,
@ -448,6 +447,7 @@ async function processPurchaseApplyRefundImpl(
body, body,
}, },
}); });
}
} }
} }
let allRefundsProcessed = false; let allRefundsProcessed = false;

View File

@ -23,11 +23,9 @@
*/ */
import { import {
codecForString, codecForString,
typecheckedCodec,
makeCodecForObject, makeCodecForObject,
makeCodecForConstString,
makeCodecForUnion,
makeCodecForList, makeCodecForList,
Codec,
} from "../util/codec"; } from "../util/codec";
import { AmountString } from "./talerTypes"; import { AmountString } from "./talerTypes";
import { import {
@ -52,10 +50,8 @@ export interface ReserveStatus {
history: ReserveTransaction[]; history: ReserveTransaction[];
} }
export const codecForReserveStatus = () => export const codecForReserveStatus = (): Codec<ReserveStatus> =>
typecheckedCodec<ReserveStatus>(
makeCodecForObject<ReserveStatus>() makeCodecForObject<ReserveStatus>()
.property("balance", codecForString) .property("balance", codecForString)
.property("history", makeCodecForList(codecForReserveTransaction())) .property("history", makeCodecForList(codecForReserveTransaction()))
.build("ReserveStatus"), .build("ReserveStatus");
);

View File

@ -23,10 +23,10 @@
*/ */
import { import {
codecForString, codecForString,
typecheckedCodec,
makeCodecForObject, makeCodecForObject,
makeCodecForConstString, makeCodecForConstString,
makeCodecForUnion, makeCodecForUnion,
Codec,
} from "../util/codec"; } from "../util/codec";
import { import {
AmountString, AmountString,
@ -179,8 +179,7 @@ export type ReserveTransaction =
| ReserveClosingTransaction | ReserveClosingTransaction
| ReserveRecoupTransaction; | ReserveRecoupTransaction;
export const codecForReserveWithdrawTransaction = () => export const codecForReserveWithdrawTransaction = (): Codec<ReserveWithdrawTransaction> =>
typecheckedCodec<ReserveWithdrawTransaction>(
makeCodecForObject<ReserveWithdrawTransaction>() makeCodecForObject<ReserveWithdrawTransaction>()
.property("amount", codecForString) .property("amount", codecForString)
.property("h_coin_envelope", codecForString) .property("h_coin_envelope", codecForString)
@ -191,22 +190,18 @@ export const codecForReserveWithdrawTransaction = () =>
makeCodecForConstString(ReserveTransactionType.Withdraw), makeCodecForConstString(ReserveTransactionType.Withdraw),
) )
.property("withdraw_fee", codecForString) .property("withdraw_fee", codecForString)
.build("ReserveWithdrawTransaction"), .build("ReserveWithdrawTransaction");
);
export const codecForReserveCreditTransaction = () => export const codecForReserveCreditTransaction = (): Codec<ReserveCreditTransaction> =>
typecheckedCodec<ReserveCreditTransaction>(
makeCodecForObject<ReserveCreditTransaction>() makeCodecForObject<ReserveCreditTransaction>()
.property("amount", codecForString) .property("amount", codecForString)
.property("sender_account_url", codecForString) .property("sender_account_url", codecForString)
.property("timestamp", codecForTimestamp) .property("timestamp", codecForTimestamp)
.property("wire_reference", codecForString) .property("wire_reference", codecForString)
.property("type", makeCodecForConstString(ReserveTransactionType.Credit)) .property("type", makeCodecForConstString(ReserveTransactionType.Credit))
.build("ReserveCreditTransaction"), .build("ReserveCreditTransaction");
);
export const codecForReserveClosingTransaction = () => export const codecForReserveClosingTransaction = (): Codec<ReserveClosingTransaction> =>
typecheckedCodec<ReserveClosingTransaction>(
makeCodecForObject<ReserveClosingTransaction>() makeCodecForObject<ReserveClosingTransaction>()
.property("amount", codecForString) .property("amount", codecForString)
.property("closing_fee", codecForString) .property("closing_fee", codecForString)
@ -216,11 +211,9 @@ export const codecForReserveClosingTransaction = () =>
.property("timestamp", codecForTimestamp) .property("timestamp", codecForTimestamp)
.property("type", makeCodecForConstString(ReserveTransactionType.Closing)) .property("type", makeCodecForConstString(ReserveTransactionType.Closing))
.property("wtid", codecForString) .property("wtid", codecForString)
.build("ReserveClosingTransaction"), .build("ReserveClosingTransaction");
);
export const codecForReserveRecoupTransaction = () => export const codecForReserveRecoupTransaction = (): Codec<ReserveRecoupTransaction> =>
typecheckedCodec<ReserveRecoupTransaction>(
makeCodecForObject<ReserveRecoupTransaction>() makeCodecForObject<ReserveRecoupTransaction>()
.property("amount", codecForString) .property("amount", codecForString)
.property("coin_pub", codecForString) .property("coin_pub", codecForString)
@ -228,11 +221,9 @@ export const codecForReserveRecoupTransaction = () =>
.property("exchange_sig", codecForString) .property("exchange_sig", codecForString)
.property("timestamp", codecForTimestamp) .property("timestamp", codecForTimestamp)
.property("type", makeCodecForConstString(ReserveTransactionType.Recoup)) .property("type", makeCodecForConstString(ReserveTransactionType.Recoup))
.build("ReserveRecoupTransaction"), .build("ReserveRecoupTransaction");
);
export const codecForReserveTransaction = () => export const codecForReserveTransaction = (): Codec<ReserveTransaction> =>
typecheckedCodec<ReserveTransaction>(
makeCodecForUnion<ReserveTransaction>() makeCodecForUnion<ReserveTransaction>()
.discriminateOn("type") .discriminateOn("type")
.alternative( .alternative(
@ -251,5 +242,4 @@ export const codecForReserveTransaction = () =>
ReserveTransactionType.Credit, ReserveTransactionType.Credit,
codecForReserveCreditTransaction(), codecForReserveCreditTransaction(),
) )
.build<ReserveTransaction>("ReserveTransaction"), .build<ReserveTransaction>("ReserveTransaction");
);

View File

@ -28,7 +28,6 @@
*/ */
import { import {
typecheckedCodec,
makeCodecForObject, makeCodecForObject,
codecForString, codecForString,
makeCodecForList, makeCodecForList,
@ -37,6 +36,7 @@ import {
codecForNumber, codecForNumber,
codecForBoolean, codecForBoolean,
makeCodecForMap, makeCodecForMap,
Codec,
} from "../util/codec"; } from "../util/codec";
import { import {
Timestamp, Timestamp,
@ -786,222 +786,183 @@ export type EddsaSignatureString = string;
export type EddsaPublicKeyString = string; export type EddsaPublicKeyString = string;
export type CoinPublicKeyString = string; export type CoinPublicKeyString = string;
export const codecForDenomination = () => export const codecForDenomination = (): Codec<Denomination> =>
typecheckedCodec<Denomination>( makeCodecForObject<Denomination>()
makeCodecForObject<Denomination>() .property("value", codecForString)
.property("value", codecForString) .property("denom_pub", codecForString)
.property("denom_pub", codecForString) .property("fee_withdraw", codecForString)
.property("fee_withdraw", codecForString) .property("fee_deposit", codecForString)
.property("fee_deposit", codecForString) .property("fee_refresh", codecForString)
.property("fee_refresh", codecForString) .property("fee_refund", codecForString)
.property("fee_refund", codecForString) .property("stamp_start", codecForTimestamp)
.property("stamp_start", codecForTimestamp) .property("stamp_expire_withdraw", codecForTimestamp)
.property("stamp_expire_withdraw", codecForTimestamp) .property("stamp_expire_legal", codecForTimestamp)
.property("stamp_expire_legal", codecForTimestamp) .property("stamp_expire_deposit", codecForTimestamp)
.property("stamp_expire_deposit", codecForTimestamp) .property("master_sig", codecForString)
.property("master_sig", codecForString) .build("Denomination");
.build("Denomination"),
);
export const codecForAuditorDenomSig = () => export const codecForAuditorDenomSig = (): Codec<AuditorDenomSig> =>
typecheckedCodec<AuditorDenomSig>( makeCodecForObject<AuditorDenomSig>()
makeCodecForObject<AuditorDenomSig>() .property("denom_pub_h", codecForString)
.property("denom_pub_h", codecForString) .property("auditor_sig", codecForString)
.property("auditor_sig", codecForString) .build("AuditorDenomSig");
.build("AuditorDenomSig"),
);
export const codecForAuditor = () => export const codecForAuditor = (): Codec<Auditor> =>
typecheckedCodec<Auditor>( makeCodecForObject<Auditor>()
makeCodecForObject<Auditor>() .property("auditor_pub", codecForString)
.property("auditor_pub", codecForString) .property("auditor_url", codecForString)
.property("auditor_url", codecForString) .property("denomination_keys", makeCodecForList(codecForAuditorDenomSig()))
.property( .build("Auditor");
"denomination_keys",
makeCodecForList(codecForAuditorDenomSig()),
)
.build("Auditor"),
);
export const codecForExchangeHandle = () => export const codecForExchangeHandle = (): Codec<ExchangeHandle> =>
typecheckedCodec<ExchangeHandle>( makeCodecForObject<ExchangeHandle>()
makeCodecForObject<ExchangeHandle>() .property("master_pub", codecForString)
.property("master_pub", codecForString) .property("url", codecForString)
.property("url", codecForString) .build("ExchangeHandle");
.build("ExchangeHandle"),
);
export const codecForAuditorHandle = () => export const codecForAuditorHandle = (): Codec<AuditorHandle> =>
typecheckedCodec<AuditorHandle>( makeCodecForObject<AuditorHandle>()
makeCodecForObject<AuditorHandle>() .property("name", codecForString)
.property("name", codecForString) .property("master_pub", codecForString)
.property("master_pub", codecForString) .property("url", codecForString)
.property("url", codecForString) .build("AuditorHandle");
.build("AuditorHandle"),
);
export const codecForContractTerms = () => export const codecForContractTerms = (): Codec<ContractTerms> =>
typecheckedCodec<ContractTerms>( makeCodecForObject<ContractTerms>()
makeCodecForObject<ContractTerms>() .property("order_id", codecForString)
.property("order_id", codecForString) .property("fulfillment_url", codecForString)
.property("fulfillment_url", codecForString) .property("merchant_base_url", codecForString)
.property("merchant_base_url", codecForString) .property("h_wire", codecForString)
.property("h_wire", codecForString) .property("auto_refund", makeCodecOptional(codecForDuration))
.property("auto_refund", makeCodecOptional(codecForDuration)) .property("wire_method", codecForString)
.property("wire_method", codecForString) .property("summary", codecForString)
.property("summary", codecForString) .property("nonce", codecForString)
.property("nonce", codecForString) .property("amount", codecForString)
.property("amount", codecForString) .property("auditors", makeCodecForList(codecForAuditorHandle()))
.property("auditors", makeCodecForList(codecForAuditorHandle())) .property("pay_deadline", codecForTimestamp)
.property("pay_deadline", codecForTimestamp) .property("refund_deadline", codecForTimestamp)
.property("refund_deadline", codecForTimestamp) .property("wire_transfer_deadline", codecForTimestamp)
.property("wire_transfer_deadline", codecForTimestamp) .property("timestamp", codecForTimestamp)
.property("timestamp", codecForTimestamp) .property("locations", codecForAny)
.property("locations", codecForAny) .property("max_fee", codecForString)
.property("max_fee", codecForString) .property("max_wire_fee", makeCodecOptional(codecForString))
.property("max_wire_fee", makeCodecOptional(codecForString)) .property("merchant", codecForAny)
.property("merchant", codecForAny) .property("merchant_pub", codecForString)
.property("merchant_pub", codecForString) .property("exchanges", makeCodecForList(codecForExchangeHandle()))
.property("exchanges", makeCodecForList(codecForExchangeHandle())) .property("products", makeCodecOptional(makeCodecForList(codecForAny)))
.property("products", makeCodecOptional(makeCodecForList(codecForAny))) .property("extra", codecForAny)
.property("extra", codecForAny) .build("ContractTerms");
.build("ContractTerms"),
);
export const codecForMerchantRefundPermission = () => export const codecForMerchantRefundPermission = (): Codec<
typecheckedCodec<MerchantRefundPermission>( MerchantRefundPermission
makeCodecForObject<MerchantRefundPermission>() > =>
.property("refund_amount", codecForString) makeCodecForObject<MerchantRefundPermission>()
.property("refund_fee", codecForString) .property("refund_amount", codecForString)
.property("coin_pub", codecForString) .property("refund_fee", codecForString)
.property("rtransaction_id", codecForNumber) .property("coin_pub", codecForString)
.property("merchant_sig", codecForString) .property("rtransaction_id", codecForNumber)
.build("MerchantRefundPermission"), .property("merchant_sig", codecForString)
); .build("MerchantRefundPermission");
export const codecForMerchantRefundResponse = () => export const codecForMerchantRefundResponse = (): Codec<
typecheckedCodec<MerchantRefundResponse>( MerchantRefundResponse
makeCodecForObject<MerchantRefundResponse>() > =>
.property("merchant_pub", codecForString) makeCodecForObject<MerchantRefundResponse>()
.property("h_contract_terms", codecForString) .property("merchant_pub", codecForString)
.property( .property("h_contract_terms", codecForString)
"refund_permissions", .property(
makeCodecForList(codecForMerchantRefundPermission()), "refund_permissions",
) makeCodecForList(codecForMerchantRefundPermission()),
.build("MerchantRefundResponse"), )
); .build("MerchantRefundResponse");
export const codecForReserveSigSingleton = () => export const codecForReserveSigSingleton = (): Codec<ReserveSigSingleton> =>
typecheckedCodec<ReserveSigSingleton>( makeCodecForObject<ReserveSigSingleton>()
makeCodecForObject<ReserveSigSingleton>() .property("reserve_sig", codecForString)
.property("reserve_sig", codecForString) .build("ReserveSigSingleton");
.build("ReserveSigSingleton"),
);
export const codecForTipResponse = () => export const codecForTipResponse = (): Codec<TipResponse> =>
typecheckedCodec<TipResponse>( makeCodecForObject<TipResponse>()
makeCodecForObject<TipResponse>() .property("reserve_pub", codecForString)
.property("reserve_pub", codecForString) .property("reserve_sigs", makeCodecForList(codecForReserveSigSingleton()))
.property("reserve_sigs", makeCodecForList(codecForReserveSigSingleton())) .build("TipResponse");
.build("TipResponse"),
);
export const codecForRecoup = () => export const codecForRecoup = (): Codec<Recoup> =>
typecheckedCodec<Recoup>( makeCodecForObject<Recoup>()
makeCodecForObject<Recoup>() .property("h_denom_pub", codecForString)
.property("h_denom_pub", codecForString) .build("Recoup");
.build("Payback"),
);
export const codecForExchangeSigningKey = () => export const codecForExchangeSigningKey = (): Codec<ExchangeSignKeyJson> =>
typecheckedCodec<ExchangeSignKeyJson>( makeCodecForObject<ExchangeSignKeyJson>()
makeCodecForObject<ExchangeSignKeyJson>() .property("key", codecForString)
.property("key", codecForString) .property("master_sig", codecForString)
.property("master_sig", codecForString) .property("stamp_end", codecForTimestamp)
.property("stamp_end", codecForTimestamp) .property("stamp_start", codecForTimestamp)
.property("stamp_start", codecForTimestamp) .property("stamp_expire", codecForTimestamp)
.property("stamp_expire", codecForTimestamp) .build("ExchangeSignKeyJson");
.build("ExchangeSignKeyJson"),
);
export const codecForExchangeKeysJson = () => export const codecForExchangeKeysJson = (): Codec<ExchangeKeysJson> =>
typecheckedCodec<ExchangeKeysJson>( makeCodecForObject<ExchangeKeysJson>()
makeCodecForObject<ExchangeKeysJson>() .property("denoms", makeCodecForList(codecForDenomination()))
.property("denoms", makeCodecForList(codecForDenomination())) .property("master_public_key", codecForString)
.property("master_public_key", codecForString) .property("auditors", makeCodecForList(codecForAuditor()))
.property("auditors", makeCodecForList(codecForAuditor())) .property("list_issue_date", codecForTimestamp)
.property("list_issue_date", codecForTimestamp) .property("recoup", makeCodecOptional(makeCodecForList(codecForRecoup())))
.property("recoup", makeCodecOptional(makeCodecForList(codecForRecoup()))) .property("signkeys", makeCodecForList(codecForExchangeSigningKey()))
.property("signkeys", makeCodecForList(codecForExchangeSigningKey())) .property("version", codecForString)
.property("version", codecForString) .build("KeysJson");
.build("KeysJson"),
);
export const codecForWireFeesJson = () => export const codecForWireFeesJson = (): Codec<WireFeesJson> =>
typecheckedCodec<WireFeesJson>( makeCodecForObject<WireFeesJson>()
makeCodecForObject<WireFeesJson>() .property("wire_fee", codecForString)
.property("wire_fee", codecForString) .property("closing_fee", codecForString)
.property("closing_fee", codecForString) .property("sig", codecForString)
.property("sig", codecForString) .property("start_date", codecForTimestamp)
.property("start_date", codecForTimestamp) .property("end_date", codecForTimestamp)
.property("end_date", codecForTimestamp) .build("WireFeesJson");
.build("WireFeesJson"),
);
export const codecForAccountInfo = () => export const codecForAccountInfo = (): Codec<AccountInfo> =>
typecheckedCodec<AccountInfo>( makeCodecForObject<AccountInfo>()
makeCodecForObject<AccountInfo>() .property("payto_uri", codecForString)
.property("payto_uri", codecForString) .property("master_sig", codecForString)
.property("master_sig", codecForString) .build("AccountInfo");
.build("AccountInfo"),
);
export const codecForExchangeWireJson = () => export const codecForExchangeWireJson = (): Codec<ExchangeWireJson> =>
typecheckedCodec<ExchangeWireJson>( makeCodecForObject<ExchangeWireJson>()
makeCodecForObject<ExchangeWireJson>() .property("accounts", makeCodecForList(codecForAccountInfo()))
.property("accounts", makeCodecForList(codecForAccountInfo())) .property("fees", makeCodecForMap(makeCodecForList(codecForWireFeesJson())))
.property( .build("ExchangeWireJson");
"fees",
makeCodecForMap(makeCodecForList(codecForWireFeesJson())),
)
.build("ExchangeWireJson"),
);
export const codecForProposal = () => export const codecForProposal = (): Codec<Proposal> =>
typecheckedCodec<Proposal>( makeCodecForObject<Proposal>()
makeCodecForObject<Proposal>() .property("contract_terms", codecForAny)
.property("contract_terms", codecForAny) .property("sig", codecForString)
.property("sig", codecForString) .build("Proposal");
.build("Proposal"),
);
export const codecForCheckPaymentResponse = () => export const codecForCheckPaymentResponse = (): Codec<CheckPaymentResponse> =>
typecheckedCodec<CheckPaymentResponse>( makeCodecForObject<CheckPaymentResponse>()
makeCodecForObject<CheckPaymentResponse>() .property("paid", codecForBoolean)
.property("paid", codecForBoolean) .property("refunded", makeCodecOptional(codecForBoolean))
.property("refunded", makeCodecOptional(codecForBoolean)) .property("refunded_amount", makeCodecOptional(codecForString))
.property("refunded_amount", makeCodecOptional(codecForString)) .property("contract_terms", makeCodecOptional(codecForAny))
.property("contract_terms", makeCodecOptional(codecForAny)) .property("taler_pay_uri", makeCodecOptional(codecForString))
.property("taler_pay_uri", makeCodecOptional(codecForString)) .property("contract_url", makeCodecOptional(codecForString))
.property("contract_url", makeCodecOptional(codecForString)) .build("CheckPaymentResponse");
.build("CheckPaymentResponse"),
);
export const codecForWithdrawOperationStatusResponse = () => export const codecForWithdrawOperationStatusResponse = (): Codec<
typecheckedCodec<WithdrawOperationStatusResponse>( WithdrawOperationStatusResponse
makeCodecForObject<WithdrawOperationStatusResponse>() > =>
.property("selection_done", codecForBoolean) makeCodecForObject<WithdrawOperationStatusResponse>()
.property("transfer_done", codecForBoolean) .property("selection_done", codecForBoolean)
.property("amount", codecForString) .property("transfer_done", codecForBoolean)
.property("sender_wire", makeCodecOptional(codecForString)) .property("amount", codecForString)
.property("suggested_exchange", makeCodecOptional(codecForString)) .property("sender_wire", makeCodecOptional(codecForString))
.property("confirm_transfer_url", makeCodecOptional(codecForString)) .property("suggested_exchange", makeCodecOptional(codecForString))
.property("wire_types", makeCodecForList(codecForString)) .property("confirm_transfer_url", makeCodecOptional(codecForString))
.build("WithdrawOperationStatusResponse"), .property("wire_types", makeCodecForList(codecForString))
); .build("WithdrawOperationStatusResponse");
export const codecForTipPickupGetResponse = () => export const codecForTipPickupGetResponse = (): Codec<TipPickupGetResponse> =>
typecheckedCodec<TipPickupGetResponse>(
makeCodecForObject<TipPickupGetResponse>() makeCodecForObject<TipPickupGetResponse>()
.property("extra", codecForAny) .property("extra", codecForAny)
.property("amount", codecForString) .property("amount", codecForString)
@ -1009,20 +970,15 @@ export const codecForTipPickupGetResponse = () =>
.property("exchange_url", codecForString) .property("exchange_url", codecForString)
.property("stamp_expire", codecForTimestamp) .property("stamp_expire", codecForTimestamp)
.property("stamp_created", codecForTimestamp) .property("stamp_created", codecForTimestamp)
.build("TipPickupGetResponse"), .build("TipPickupGetResponse");
);
export const codecForRecoupConfirmation = () => export const codecForRecoupConfirmation = (): Codec<RecoupConfirmation> =>
typecheckedCodec<RecoupConfirmation>(
makeCodecForObject<RecoupConfirmation>() makeCodecForObject<RecoupConfirmation>()
.property("reserve_pub", makeCodecOptional(codecForString)) .property("reserve_pub", makeCodecOptional(codecForString))
.property("old_coin_pub", makeCodecOptional(codecForString)) .property("old_coin_pub", makeCodecOptional(codecForString))
.build("RecoupConfirmation"), .build("RecoupConfirmation");
);
export const codecForWithdrawResponse = () => export const codecForWithdrawResponse = (): Codec<WithdrawResponse> =>
typecheckedCodec<WithdrawResponse>(
makeCodecForObject<WithdrawResponse>() makeCodecForObject<WithdrawResponse>()
.property("ev_sig", codecForString) .property("ev_sig", codecForString)
.build("WithdrawResponse"), .build("WithdrawResponse");
);

View File

@ -30,18 +30,16 @@
import { AmountJson, codecForAmountJson } from "../util/amounts"; import { AmountJson, codecForAmountJson } from "../util/amounts";
import * as LibtoolVersion from "../util/libtoolVersion"; import * as LibtoolVersion from "../util/libtoolVersion";
import { import {
CoinRecord,
DenominationRecord, DenominationRecord,
ExchangeRecord, ExchangeRecord,
ExchangeWireInfo, ExchangeWireInfo,
} from "./dbTypes"; } from "./dbTypes";
import { CoinDepositPermission, ContractTerms } from "./talerTypes";
import { Timestamp } from "../util/time"; import { Timestamp } from "../util/time";
import { import {
typecheckedCodec,
makeCodecForObject, makeCodecForObject,
codecForString, codecForString,
makeCodecOptional, makeCodecOptional,
Codec,
} from "../util/codec"; } from "../util/codec";
/** /**
@ -261,16 +259,14 @@ export interface CreateReserveRequest {
bankWithdrawStatusUrl?: string; bankWithdrawStatusUrl?: string;
} }
export const codecForCreateReserveRequest = () => export const codecForCreateReserveRequest = (): Codec<CreateReserveRequest> =>
typecheckedCodec<CreateReserveRequest>(
makeCodecForObject<CreateReserveRequest>() makeCodecForObject<CreateReserveRequest>()
.property("amount", codecForAmountJson()) .property("amount", codecForAmountJson())
.property("exchange", codecForString) .property("exchange", codecForString)
.property("exchangeWire", codecForString) .property("exchangeWire", codecForString)
.property("senderWire", makeCodecOptional(codecForString)) .property("senderWire", makeCodecOptional(codecForString))
.property("bankWithdrawStatusUrl", makeCodecOptional(codecForString)) .property("bankWithdrawStatusUrl", makeCodecOptional(codecForString))
.build("CreateReserveRequest"), .build("CreateReserveRequest");
);
/** /**
* Request to mark a reserve as confirmed. * Request to mark a reserve as confirmed.
@ -283,12 +279,10 @@ export interface ConfirmReserveRequest {
reservePub: string; reservePub: string;
} }
export const codecForConfirmReserveRequest = () => export const codecForConfirmReserveRequest = (): Codec<ConfirmReserveRequest> =>
typecheckedCodec<ConfirmReserveRequest>(
makeCodecForObject<ConfirmReserveRequest>() makeCodecForObject<ConfirmReserveRequest>()
.property("reservePub", codecForString) .property("reservePub", codecForString)
.build("ConfirmReserveRequest"), .build("ConfirmReserveRequest");
);
/** /**
* Wire coins to the user's own bank account. * Wire coins to the user's own bank account.

View File

@ -22,10 +22,10 @@
* Imports. * Imports.
*/ */
import { import {
typecheckedCodec,
makeCodecForObject, makeCodecForObject,
codecForString, codecForString,
codecForNumber, codecForNumber,
Codec,
} from "./codec"; } from "./codec";
/** /**
@ -66,14 +66,12 @@ export interface AmountJson {
readonly currency: string; readonly currency: string;
} }
export const codecForAmountJson = () => export const codecForAmountJson = (): Codec<AmountJson> =>
typecheckedCodec<AmountJson>(
makeCodecForObject<AmountJson>() makeCodecForObject<AmountJson>()
.property("currency", codecForString) .property("currency", codecForString)
.property("value", codecForNumber) .property("value", codecForNumber)
.property("fraction", codecForNumber) .property("fraction", codecForNumber)
.build("AmountJson"), .build("AmountJson");
);
/** /**
* Result of a possibly overflowing operation. * Result of a possibly overflowing operation.
@ -100,7 +98,7 @@ export function getZero(currency: string): AmountJson {
}; };
} }
export function sum(amounts: AmountJson[]) { export function sum(amounts: AmountJson[]): Result {
if (amounts.length <= 0) { if (amounts.length <= 0) {
throw Error("can't sum zero amounts"); throw Error("can't sum zero amounts");
} }
@ -287,7 +285,7 @@ export function parseOrThrow(s: string): AmountJson {
* Convert a float to a Taler amount. * Convert a float to a Taler amount.
* Loss of precision possible. * Loss of precision possible.
*/ */
export function fromFloat(floatVal: number, currency: string) { export function fromFloat(floatVal: number, currency: string): AmountJson {
return { return {
currency, currency,
fraction: Math.floor((floatVal - Math.floor(floatVal)) * fractionalBase), fraction: Math.floor((floatVal - Math.floor(floatVal)) * fractionalBase),

View File

@ -24,7 +24,7 @@ export class AsyncOpMemoMap<T> {
private n = 0; private n = 0;
private memoMap: { [k: string]: MemoEntry<T> } = {}; private memoMap: { [k: string]: MemoEntry<T> } = {};
private cleanUp(key: string, n: number) { private cleanUp(key: string, n: number): void {
const r = this.memoMap[key]; const r = this.memoMap[key];
if (r && r.n === n) { if (r && r.n === n) {
delete this.memoMap[key]; delete this.memoMap[key];
@ -48,7 +48,7 @@ export class AsyncOpMemoMap<T> {
this.cleanUp(key, n); this.cleanUp(key, n);
}); });
} }
clear() { clear(): void {
this.memoMap = {}; this.memoMap = {};
} }
} }
@ -57,7 +57,7 @@ export class AsyncOpMemoSingle<T> {
private n = 0; private n = 0;
private memoEntry: MemoEntry<T> | undefined; private memoEntry: MemoEntry<T> | undefined;
private cleanUp(n: number) { private cleanUp(n: number): void {
if (this.memoEntry && this.memoEntry.n === n) { if (this.memoEntry && this.memoEntry.n === n) {
this.memoEntry = undefined; this.memoEntry = undefined;
} }
@ -81,7 +81,7 @@ export class AsyncOpMemoSingle<T> {
}; };
return p; return p;
} }
clear() { clear(): void {
this.memoEntry = undefined; this.memoEntry = undefined;
} }
} }

View File

@ -346,8 +346,4 @@ export function makeCodecOptional<V>(
return innerCodec.decode(x, c); return innerCodec.decode(x, c);
}, },
}; };
} }
export function typecheckedCodec<T = undefined>(c: Codec<T>): Codec<T> {
return c;
}

View File

@ -116,7 +116,7 @@ export class BrowserHttpLib implements HttpRequestLibrary {
); );
return; return;
} }
const makeJson = async () => { const makeJson = async (): Promise<any> => {
let responseJson; let responseJson;
try { try {
responseJson = JSON.parse(myRequest.responseText); responseJson = JSON.parse(myRequest.responseText);
@ -152,15 +152,15 @@ export class BrowserHttpLib implements HttpRequestLibrary {
}); });
} }
get(url: string, opt?: HttpRequestOptions) { get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
return this.req("get", url, undefined, opt); return this.req("get", url, undefined, opt);
} }
postJson(url: string, body: any, opt?: HttpRequestOptions) { postJson(url: string, body: any, opt?: HttpRequestOptions): Promise<HttpResponse> {
return this.req("post", url, JSON.stringify(body), opt); return this.req("post", url, JSON.stringify(body), opt);
} }
stop() { stop(): void {
// Nothing to do // Nothing to do
} }
} }

View File

@ -24,7 +24,7 @@ function writeNodeLog(
tag: string, tag: string,
level: string, level: string,
args: any[], args: any[],
) { ): void {
process.stderr.write(`${new Date().toISOString()} ${tag} ${level} `); process.stderr.write(`${new Date().toISOString()} ${tag} ${level} `);
process.stderr.write(message); process.stderr.write(message);
if (args.length != 0) { if (args.length != 0) {
@ -41,7 +41,7 @@ function writeNodeLog(
export class Logger { export class Logger {
constructor(private tag: string) {} constructor(private tag: string) {}
info(message: string, ...args: any[]) { info(message: string, ...args: any[]): void {
if (isNode()) { if (isNode()) {
writeNodeLog(message, this.tag, "INFO", args); writeNodeLog(message, this.tag, "INFO", args);
} else { } else {
@ -52,7 +52,7 @@ export class Logger {
} }
} }
warn(message: string, ...args: any[]) { warn(message: string, ...args: any[]): void {
if (isNode()) { if (isNode()) {
writeNodeLog(message, this.tag, "WARN", args); writeNodeLog(message, this.tag, "WARN", args);
} else { } else {
@ -63,7 +63,7 @@ export class Logger {
} }
} }
error(message: string, ...args: any[]) { error(message: string, ...args: any[]): void {
if (isNode()) { if (isNode()) {
writeNodeLog(message, this.tag, "ERROR", args); writeNodeLog(message, this.tag, "ERROR", args);
} else { } else {
@ -74,7 +74,7 @@ export class Logger {
} }
} }
trace(message: any, ...args: any[]) { trace(message: any, ...args: any[]): void {
if (isNode()) { if (isNode()) {
writeNodeLog(message, this.tag, "TRACE", args); writeNodeLog(message, this.tag, "TRACE", args);
} else { } else {

View File

@ -25,6 +25,11 @@
*/ */
import { openPromise } from "./promiseUtils"; import { openPromise } from "./promiseUtils";
/**
* Exception that should be thrown by client code to abort a transaction.
*/
export const TransactionAbort = Symbol("transaction_abort");
/** /**
* Definition of an object store. * Definition of an object store.
*/ */
@ -430,11 +435,6 @@ export function openDatabase(
}); });
} }
/**
* Exception that should be thrown by client code to abort a transaction.
*/
export const TransactionAbort = Symbol("transaction_abort");
export class Database { export class Database {
constructor(private db: IDBDatabase) {} constructor(private db: IDBDatabase) {}

View File

@ -36,7 +36,7 @@ export interface Duration {
let timeshift = 0; let timeshift = 0;
export function setDangerousTimetravel(dt: number) { export function setDangerousTimetravel(dt: number): void {
timeshift = dt; timeshift = dt;
} }
@ -121,7 +121,7 @@ export function timestampSubtractDuraction(
return { t_ms: Math.max(0, t1.t_ms - d.d_ms) }; return { t_ms: Math.max(0, t1.t_ms - d.d_ms) };
} }
export function stringifyTimestamp(t: Timestamp) { export function stringifyTimestamp(t: Timestamp): string {
if (t.t_ms === "never") { if (t.t_ms === "never") {
return "never"; return "never";
} }
@ -142,7 +142,7 @@ export function timestampIsBetween(
t: Timestamp, t: Timestamp,
start: Timestamp, start: Timestamp,
end: Timestamp, end: Timestamp,
) { ): boolean {
if (timestampCmp(t, start) < 0) { if (timestampCmp(t, start) < 0) {
return false; return false;
} }

View File

@ -16,9 +16,6 @@
import test from "ava"; import test from "ava";
import * as dbTypes from "./types/dbTypes";
import * as types from "./types/walletTypes";
import { AmountJson } from "./util/amounts"; import { AmountJson } from "./util/amounts";
import * as Amounts from "./util/amounts"; import * as Amounts from "./util/amounts";
import { selectPayCoins, AvailableCoinInfo } from "./operations/pay"; import { selectPayCoins, AvailableCoinInfo } from "./operations/pay";

View File

@ -47,7 +47,6 @@ import {
CurrencyRecord, CurrencyRecord,
DenominationRecord, DenominationRecord,
ExchangeRecord, ExchangeRecord,
ProposalRecord,
PurchaseRecord, PurchaseRecord,
ReserveRecord, ReserveRecord,
Stores, Stores,
@ -155,7 +154,7 @@ export class Wallet {
this.ws = new InternalWalletState(db, http, cryptoWorkerFactory); this.ws = new InternalWalletState(db, http, cryptoWorkerFactory);
} }
getExchangePaytoUri(exchangeBaseUrl: string, supportedTargetTypes: string[]) { getExchangePaytoUri(exchangeBaseUrl: string, supportedTargetTypes: string[]): Promise<string> {
return getExchangePaytoUri(this.ws, exchangeBaseUrl, supportedTargetTypes); return getExchangePaytoUri(this.ws, exchangeBaseUrl, supportedTargetTypes);
} }
@ -371,7 +370,7 @@ export class Wallet {
* auditors into the database, unless these defaults have * auditors into the database, unless these defaults have
* already been applied. * already been applied.
*/ */
async fillDefaults() { async fillDefaults(): Promise<void> {
await this.db.runWithWriteTransaction( await this.db.runWithWriteTransaction(
[Stores.config, Stores.currencies], [Stores.config, Stores.currencies],
async (tx) => { async (tx) => {
@ -549,7 +548,7 @@ export class Wallet {
async acceptExchangeTermsOfService( async acceptExchangeTermsOfService(
exchangeBaseUrl: string, exchangeBaseUrl: string,
etag: string | undefined, etag: string | undefined,
) { ): Promise<void> {
return acceptExchangeTermsOfService(this.ws, exchangeBaseUrl, etag); return acceptExchangeTermsOfService(this.ws, exchangeBaseUrl, etag);
} }
@ -596,7 +595,7 @@ export class Wallet {
/** /**
* Stop ongoing processing. * Stop ongoing processing.
*/ */
stop() { stop(): void {
this.stopped = true; this.stopped = true;
this.timerGroup.stopCurrentAndFutureTimers(); this.timerGroup.stopCurrentAndFutureTimers();
this.ws.cryptoApi.stop(); this.ws.cryptoApi.stop();
@ -685,7 +684,7 @@ export class Wallet {
* Inform the wallet that the status of a reserve has changed (e.g. due to a * Inform the wallet that the status of a reserve has changed (e.g. due to a
* confirmation from the bank.). * confirmation from the bank.).
*/ */
public async handleNotifyReserve() { public async handleNotifyReserve(): Promise<void> {
const reserves = await this.db.iter(Stores.reserves).toArray(); const reserves = await this.db.iter(Stores.reserves).toArray();
for (const r of reserves) { for (const r of reserves) {
if (r.reserveStatus === ReserveRecordStatus.WAIT_CONFIRM_BANK) { if (r.reserveStatus === ReserveRecordStatus.WAIT_CONFIRM_BANK) {
@ -702,7 +701,7 @@ export class Wallet {
* Remove unreferenced / expired data from the wallet's database * Remove unreferenced / expired data from the wallet's database
* based on the current system time. * based on the current system time.
*/ */
async collectGarbage() { async collectGarbage(): Promise<void> {
// FIXME(#5845) // FIXME(#5845)
// We currently do not garbage-collect the wallet database. This might change // We currently do not garbage-collect the wallet database. This might change
// after the feature has been properly re-designed, and we have come up with a // after the feature has been properly re-designed, and we have come up with a

View File

@ -20,7 +20,7 @@ import { isFirefox } from "./compat";
* Polyfill for requestAnimationFrame, which * Polyfill for requestAnimationFrame, which
* doesn't work from a background page. * doesn't work from a background page.
*/ */
function rAF(cb: (ts: number) => void) { function rAF(cb: (ts: number) => void): void {
window.setTimeout(() => { window.setTimeout(() => {
cb(performance.now()); cb(performance.now());
}, 100 /* 100 ms delay between frames */); }, 100 /* 100 ms delay between frames */);
@ -99,14 +99,18 @@ export class ChromeBadge {
// size in draw() as well! // size in draw() as well!
this.canvas.width = 32; this.canvas.width = 32;
this.canvas.height = 32; this.canvas.height = 32;
this.ctx = this.canvas.getContext("2d")!; const ctx = this.canvas.getContext("2d");
if (!ctx) {
throw Error("unable to get canvas context");
}
this.ctx = ctx;
this.draw(); this.draw();
} }
/** /**
* Draw the badge based on the current state. * Draw the badge based on the current state.
*/ */
private draw() { private draw(): void {
this.ctx.setTransform(1, 0, 0, 1, 0, 0); this.ctx.setTransform(1, 0, 0, 1, 0, 0);
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
@ -202,7 +206,7 @@ export class ChromeBadge {
} }
} }
private animate() { private animate(): void {
if (this.animationRunning) { if (this.animationRunning) {
return; return;
} }
@ -212,7 +216,7 @@ export class ChromeBadge {
} }
this.animationRunning = true; this.animationRunning = true;
let start: number | undefined; let start: number | undefined;
const step = (timestamp: number) => { const step = (timestamp: number): void => {
if (!this.animationRunning) { if (!this.animationRunning) {
return; return;
} }
@ -257,7 +261,7 @@ export class ChromeBadge {
* Draw the badge such that it shows the * Draw the badge such that it shows the
* user that something happened (balance changed). * user that something happened (balance changed).
*/ */
showNotification() { showNotification(): void {
this.hasNotification = true; this.hasNotification = true;
this.draw(); this.draw();
} }
@ -265,12 +269,12 @@ export class ChromeBadge {
/** /**
* Draw the badge without the notification mark. * Draw the badge without the notification mark.
*/ */
clearNotification() { clearNotification(): void {
this.hasNotification = false; this.hasNotification = false;
this.draw(); this.draw();
} }
startBusy() { startBusy(): void {
if (this.isBusy) { if (this.isBusy) {
return; return;
} }
@ -278,7 +282,7 @@ export class ChromeBadge {
this.animate(); this.animate();
} }
stopBusy() { stopBusy(): void {
this.isBusy = false; this.isBusy = false;
} }
} }

View File

@ -47,7 +47,7 @@ const handlers: Handler[] = [];
let sheet: CSSStyleSheet | null; let sheet: CSSStyleSheet | null;
function initStyle() { function initStyle(): void {
logVerbose && console.log("taking over styles"); logVerbose && console.log("taking over styles");
const name = "taler-presence-stylesheet"; const name = "taler-presence-stylesheet";
const content = "/* Taler stylesheet controlled by JS */"; const content = "/* Taler stylesheet controlled by JS */";
@ -78,7 +78,7 @@ function initStyle() {
} }
} }
function setStyles(installed: boolean) { function setStyles(installed: boolean): void {
if (!sheet || !sheet.cssRules) { if (!sheet || !sheet.cssRules) {
return; return;
} }
@ -93,7 +93,7 @@ function setStyles(installed: boolean) {
} }
} }
function onceOnComplete(cb: () => void) { function onceOnComplete(cb: () => void): void {
if (document.readyState === "complete") { if (document.readyState === "complete") {
cb(); cb();
} else { } else {
@ -105,7 +105,7 @@ function onceOnComplete(cb: () => void) {
} }
} }
function init() { function init(): void {
onceOnComplete(() => { onceOnComplete(() => {
if (document.documentElement.getAttribute("data-taler-nojs")) { if (document.documentElement.getAttribute("data-taler-nojs")) {
initStyle(); initStyle();
@ -129,13 +129,13 @@ function init() {
type HandlerFn = (detail: any, sendResponse: (msg: any) => void) => void; type HandlerFn = (detail: any, sendResponse: (msg: any) => void) => void;
function registerHandlers() { function registerHandlers(): void {
/** /**
* Add a handler for a DOM event, which automatically * Add a handler for a DOM event, which automatically
* handles adding sequence numbers to responses. * handles adding sequence numbers to responses.
*/ */
function addHandler(type: string, handler: HandlerFn) { function addHandler(type: string, handler: HandlerFn): void {
const handlerWrap = (e: Event) => { const handlerWrap = (e: Event): void => {
if (!(e instanceof Event)) { if (!(e instanceof Event)) {
console.log("unexpected event", e); console.log("unexpected event", e);
throw Error(`invariant violated`); throw Error(`invariant violated`);
@ -154,7 +154,7 @@ function registerHandlers() {
callId = e.detail.callId; callId = e.detail.callId;
detail = e.detail; detail = e.detail;
} }
const responder = (msg?: any) => { const responder = (msg?: any): void => {
const fullMsg = Object.assign({}, msg, { callId }); const fullMsg = Object.assign({}, msg, { callId });
let opts = { detail: fullMsg }; let opts = { detail: fullMsg };
if ("function" === typeof cloneInto) { if ("function" === typeof cloneInto) {

View File

@ -31,10 +31,10 @@ interface ConfirmAuditorProps {
expirationStamp: number; expirationStamp: number;
} }
function ConfirmAuditor(props: ConfirmAuditorProps) { function ConfirmAuditor(props: ConfirmAuditorProps): JSX.Element {
const [addDone, setAddDone] = useState(false); const [addDone, setAddDone] = useState(false);
const add = async () => { const add = async (): Promise<void> => {
const currencies = await getCurrencies(); const currencies = await getCurrencies();
let currency: CurrencyRecord | undefined; let currency: CurrencyRecord | undefined;

View File

@ -34,7 +34,7 @@ interface BenchmarkRunnerState {
running: boolean; running: boolean;
} }
function BenchmarkDisplay(props: BenchmarkRunnerState) { function BenchmarkDisplay(props: BenchmarkRunnerState): JSX.Element {
const result = props.result; const result = props.result;
if (!result) { if (!result) {
if (props.running) { if (props.running) {
@ -55,7 +55,7 @@ function BenchmarkDisplay(props: BenchmarkRunnerState) {
{Object.keys(result.time) {Object.keys(result.time)
.sort() .sort()
.map((k) => ( .map((k) => (
<tr> <tr key={k}>
<td>{k}</td> <td>{k}</td>
<td>{result.time[k] / result.repetitions}</td> <td>{result.time[k] / result.repetitions}</td>
</tr> </tr>
@ -75,13 +75,13 @@ class BenchmarkRunner extends React.Component<any, BenchmarkRunnerState> {
}; };
} }
async run() { async run(): Promise<void> {
this.setState({ result: undefined, running: true }); this.setState({ result: undefined, running: true });
const result = await wxApi.benchmarkCrypto(this.state.repetitions); const result = await wxApi.benchmarkCrypto(this.state.repetitions);
this.setState({ result, running: false }); this.setState({ result, running: false });
} }
render() { render(): JSX.Element {
return ( return (
<div> <div>
<label>Repetitions:</label> <label>Repetitions:</label>
@ -99,6 +99,6 @@ class BenchmarkRunner extends React.Component<any, BenchmarkRunnerState> {
} }
} }
export function makeBenchmarkPage() { export function makeBenchmarkPage(): JSX.Element {
return <BenchmarkRunner />; return <BenchmarkRunner />;
} }

View File

@ -34,7 +34,7 @@ import React, { useState, useEffect } from "react";
import * as Amounts from "../../util/amounts"; import * as Amounts from "../../util/amounts";
import { codecForContractTerms, ContractTerms } from "../../types/talerTypes"; import { codecForContractTerms, ContractTerms } from "../../types/talerTypes";
function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) { function TalerPayDialog({ talerPayUri }: { talerPayUri: string }): JSX.Element {
const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(); const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>();
const [payErrMsg, setPayErrMsg] = useState<string | undefined>(""); const [payErrMsg, setPayErrMsg] = useState<string | undefined>("");
const [numTries, setNumTries] = useState(0); const [numTries, setNumTries] = useState(0);
@ -42,7 +42,7 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) {
let totalFees: Amounts.AmountJson | undefined = undefined; let totalFees: Amounts.AmountJson | undefined = undefined;
useEffect(() => { useEffect(() => {
const doFetch = async () => { const doFetch = async (): Promise<void> => {
const p = await wxApi.preparePay(talerPayUri); const p = await wxApi.preparePay(talerPayUri);
setPayStatus(p); setPayStatus(p);
}; };
@ -108,7 +108,7 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) {
<strong>{renderAmount(Amounts.parseOrThrow(contractTerms.amount))}</strong> <strong>{renderAmount(Amounts.parseOrThrow(contractTerms.amount))}</strong>
); );
const doPayment = async () => { const doPayment = async (): Promise<void> => {
if (payStatus.status !== "payment-possible") { if (payStatus.status !== "payment-possible") {
throw Error(`invalid state: ${payStatus.status}`); throw Error(`invalid state: ${payStatus.status}`);
} }
@ -178,11 +178,11 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) {
); );
} }
export function makePayPage() { export function makePayPage(): JSX.Element {
const url = new URL(document.location.href); const url = new URL(document.location.href);
const talerPayUri = url.searchParams.get("talerPayUri"); const talerPayUri = url.searchParams.get("talerPayUri");
if (!talerPayUri) { if (!talerPayUri) {
throw Error("invalid parameter"); throw Error("invalid parameter");
} }
return <TalerPayDialog talerPayUri={talerPayUri} />; return <TalerPayDialog talerPayUri={talerPayUri} />;
} }

View File

@ -46,7 +46,7 @@ import { Timestamp } from "../../util/time";
function onUpdateNotification(f: () => void): () => void { function onUpdateNotification(f: () => void): () => void {
const port = chrome.runtime.connect({ name: "notifications" }); const port = chrome.runtime.connect({ name: "notifications" });
const listener = () => { const listener = (): void => {
f(); f();
}; };
port.onMessage.addListener(listener); port.onMessage.addListener(listener);
@ -75,7 +75,7 @@ class Router extends React.Component<any, any> {
private static routeHandlers: any[] = []; private static routeHandlers: any[] = [];
componentWillMount() { componentWillMount(): void {
console.log("router mounted"); console.log("router mounted");
window.onhashchange = () => { window.onhashchange = () => {
this.setState({}); this.setState({});
@ -85,10 +85,6 @@ class Router extends React.Component<any, any> {
}; };
} }
componentWillUnmount() {
console.log("router unmounted");
}
render(): JSX.Element { render(): JSX.Element {
const route = window.location.hash.substring(1); const route = window.location.hash.substring(1);
console.log("rendering route", route); console.log("rendering route", route);
@ -120,12 +116,12 @@ interface TabProps {
children?: React.ReactNode; children?: React.ReactNode;
} }
function Tab(props: TabProps) { function Tab(props: TabProps): JSX.Element {
let cssClass = ""; let cssClass = "";
if (props.target === Router.getRoute()) { if (props.target === Router.getRoute()) {
cssClass = "active"; cssClass = "active";
} }
const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => { const onClick = (e: React.MouseEvent<HTMLAnchorElement>): void => {
Router.setRoute(props.target); Router.setRoute(props.target);
e.preventDefault(); e.preventDefault();
}; };
@ -139,19 +135,19 @@ function Tab(props: TabProps) {
class WalletNavBar extends React.Component<any, any> { class WalletNavBar extends React.Component<any, any> {
private cancelSubscription: any; private cancelSubscription: any;
componentWillMount() { componentWillMount(): void {
this.cancelSubscription = Router.onRoute(() => { this.cancelSubscription = Router.onRoute(() => {
this.setState({}); this.setState({});
}); });
} }
componentWillUnmount() { componentWillUnmount(): void {
if (this.cancelSubscription) { if (this.cancelSubscription) {
this.cancelSubscription(); this.cancelSubscription();
} }
} }
render() { render(): JSX.Element {
console.log("rendering nav bar"); console.log("rendering nav bar");
return ( return (
<div className="nav" id="header"> <div className="nav" id="header">
@ -163,20 +159,6 @@ class WalletNavBar extends React.Component<any, any> {
} }
} }
function ExtensionLink(props: any) {
const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
chrome.tabs.create({
url: chrome.extension.getURL(props.target),
});
e.preventDefault();
};
return (
<a onClick={onClick} href={props.target}>
{props.children}
</a>
);
}
/** /**
* Render an amount as a large number with a small currency symbol. * Render an amount as a large number with a small currency symbol.
*/ */
@ -190,7 +172,7 @@ function bigAmount(amount: AmountJson): JSX.Element {
); );
} }
function EmptyBalanceView() { function EmptyBalanceView(): JSX.Element {
return ( return (
<i18n.Translate wrap="p"> <i18n.Translate wrap="p">
You have no balance to show. Need some{" "} You have no balance to show. Need some{" "}
@ -205,12 +187,12 @@ class WalletBalanceView extends React.Component<any, any> {
private canceler: (() => void) | undefined = undefined; private canceler: (() => void) | undefined = undefined;
private unmount = false; private unmount = false;
componentWillMount() { componentWillMount(): void {
this.canceler = onUpdateNotification(() => this.updateBalance()); this.canceler = onUpdateNotification(() => this.updateBalance());
this.updateBalance(); this.updateBalance();
} }
componentWillUnmount() { componentWillUnmount(): void {
console.log("component WalletBalanceView will unmount"); console.log("component WalletBalanceView will unmount");
if (this.canceler) { if (this.canceler) {
this.canceler(); this.canceler();
@ -218,7 +200,7 @@ class WalletBalanceView extends React.Component<any, any> {
this.unmount = true; this.unmount = true;
} }
async updateBalance() { async updateBalance(): Promise<void> {
let balance: WalletBalance; let balance: WalletBalance;
try { try {
balance = await wxApi.getBalance(); balance = await wxApi.getBalance();
@ -325,11 +307,11 @@ class WalletBalanceView extends React.Component<any, any> {
} }
} }
function Icon({ l }: { l: string }) { function Icon({ l }: { l: string }): JSX.Element {
return <div className={"icon"}>{l}</div>; return <div className={"icon"}>{l}</div>;
} }
function formatAndCapitalize(text: string) { function formatAndCapitalize(text: string): string {
text = text.replace("-", " "); text = text.replace("-", " ");
text = text.replace(/^./, text[0].toUpperCase()); text = text.replace(/^./, text[0].toUpperCase());
return text; return text;
@ -357,8 +339,8 @@ function HistoryItem({
timestamp, timestamp,
icon, icon,
negative = false, negative = false,
}: HistoryItemProps) { }: HistoryItemProps): JSX.Element {
function formatDate(timestamp: number | "never") { function formatDate(timestamp: number | "never"): string | null {
if (timestamp !== "never") { if (timestamp !== "never") {
const itemDate = moment(timestamp); const itemDate = moment(timestamp);
if (itemDate.isBetween(moment().subtract(2, "days"), moment())) { if (itemDate.isBetween(moment().subtract(2, "days"), moment())) {
@ -444,7 +426,7 @@ function parseSummary(summary: string) {
}; };
} }
function formatHistoryItem(historyItem: HistoryEvent) { function formatHistoryItem(historyItem: HistoryEvent): JSX.Element {
switch (historyItem.type) { switch (historyItem.type) {
case "refreshed": { case "refreshed": {
return ( return (
@ -637,7 +619,7 @@ function formatHistoryItem(historyItem: HistoryEvent) {
} }
} }
const HistoryComponent = (props: any) => { const HistoryComponent = (props: any): JSX.Element => {
const record = props.record; const record = props.record;
return formatHistoryItem(record); return formatHistoryItem(record);
}; };
@ -655,18 +637,18 @@ class WalletHistory extends React.Component<any, any> {
"exchange-added", "exchange-added",
]; ];
componentWillMount() { componentWillMount(): void {
this.update(); this.update();
this.setState({ filter: true }); this.setState({ filter: true });
onUpdateNotification(() => this.update()); onUpdateNotification(() => this.update());
} }
componentWillUnmount() { componentWillUnmount(): void {
console.log("history component unmounted"); console.log("history component unmounted");
this.unmounted = true; this.unmounted = true;
} }
update() { update(): void {
chrome.runtime.sendMessage({ type: "get-history" }, (resp) => { chrome.runtime.sendMessage({ type: "get-history" }, (resp) => {
if (this.unmounted) { if (this.unmounted) {
return; return;
@ -727,7 +709,7 @@ class WalletHistory extends React.Component<any, any> {
} }
} }
function reload() { function reload(): void {
try { try {
chrome.runtime.reload(); chrome.runtime.reload();
window.close(); window.close();
@ -736,7 +718,7 @@ function reload() {
} }
} }
function confirmReset() { function confirmReset(): void {
if ( if (
confirm( confirm(
"Do you want to IRREVOCABLY DESTROY everything inside your" + "Do you want to IRREVOCABLY DESTROY everything inside your" +
@ -748,7 +730,7 @@ function confirmReset() {
} }
} }
function WalletDebug(props: any) { function WalletDebug(props: any): JSX.Element {
return ( return (
<div> <div>
<p>Debug tools:</p> <p>Debug tools:</p>
@ -791,7 +773,7 @@ function openTab(page: string) {
}; };
} }
function WalletPopup() { function WalletPopup(): JSX.Element {
return ( return (
<div> <div>
<WalletNavBar /> <WalletNavBar />
@ -806,7 +788,7 @@ function WalletPopup() {
); );
} }
export function createPopup() { export function createPopup(): JSX.Element {
chrome.runtime.connect({ name: "popup" }); chrome.runtime.connect({ name: "popup" });
return <WalletPopup />; return <WalletPopup />;
} }

View File

@ -21,13 +21,12 @@
*/ */
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import * as wxApi from "../wxApi"; import * as wxApi from "../wxApi";
import { PurchaseDetails } from "../../types/walletTypes"; import { PurchaseDetails } from "../../types/walletTypes";
import { AmountView } from "../renderHtml"; import { AmountView } from "../renderHtml";
function RefundStatusView(props: { talerRefundUri: string }) { function RefundStatusView(props: { talerRefundUri: string }): JSX.Element {
const [applied, setApplied] = useState(false); const [applied, setApplied] = useState(false);
const [purchaseDetails, setPurchaseDetails] = useState< const [purchaseDetails, setPurchaseDetails] = useState<
PurchaseDetails | undefined PurchaseDetails | undefined
@ -35,7 +34,7 @@ function RefundStatusView(props: { talerRefundUri: string }) {
const [errMsg, setErrMsg] = useState<string | undefined>(undefined); const [errMsg, setErrMsg] = useState<string | undefined>(undefined);
useEffect(() => { useEffect(() => {
const doFetch = async () => { const doFetch = async (): Promise<void> => {
try { try {
const hc = await wxApi.applyRefund(props.talerRefundUri); const hc = await wxApi.applyRefund(props.talerRefundUri);
setApplied(true); setApplied(true);
@ -73,19 +72,17 @@ function RefundStatusView(props: { talerRefundUri: string }) {
); );
} }
export function createRefundPage() { export function createRefundPage(): JSX.Element {
const url = new URL(document.location.href); const url = new URL(document.location.href);
const container = document.getElementById("container"); const container = document.getElementById("container");
if (!container) { if (!container) {
console.error("fatal: can't mount component, container missing"); throw Error("fatal: can't mount component, container missing")
return;
} }
const talerRefundUri = url.searchParams.get("talerRefundUri"); const talerRefundUri = url.searchParams.get("talerRefundUri");
if (!talerRefundUri) { if (!talerRefundUri) {
console.error("taler refund URI requred"); throw Error("taler refund URI requred");
return;
} }
return <RefundStatusView talerRefundUri={talerRefundUri} />; return <RefundStatusView talerRefundUri={talerRefundUri} />;

View File

@ -38,7 +38,6 @@ import { getBalance, getSenderWireInfos, returnCoins } from "../wxApi";
import { renderAmount } from "../renderHtml"; import { renderAmount } from "../renderHtml";
import * as React from "react"; import * as React from "react";
import * as ReactDOM from "react-dom";
interface ReturnSelectionItemProps extends ReturnSelectionListProps { interface ReturnSelectionItemProps extends ReturnSelectionListProps {
exchangeUrl: string; exchangeUrl: string;
@ -129,7 +128,7 @@ class ReturnSelectionItem extends React.Component<
); );
} }
select() { select(): void {
let val: number; let val: number;
let selectedWire: number; let selectedWire: number;
try { try {
@ -188,7 +187,7 @@ interface ReturnConfirmationProps {
} }
class ReturnConfirmation extends React.Component<ReturnConfirmationProps, {}> { class ReturnConfirmation extends React.Component<ReturnConfirmationProps, {}> {
render() { render(): JSX.Element {
return ( return (
<div> <div>
<p> <p>
@ -238,7 +237,7 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
this.state = {} as any; this.state = {} as any;
} }
async update() { async update(): Promise<void> {
const balance = await getBalance(); const balance = await getBalance();
const senderWireInfos = await getSenderWireInfos(); const senderWireInfos = await getSenderWireInfos();
console.log("got swi", senderWireInfos); console.log("got swi", senderWireInfos);
@ -246,11 +245,11 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
this.setState({ balance, senderWireInfos }); this.setState({ balance, senderWireInfos });
} }
selectDetail(d: SelectedDetail) { selectDetail(d: SelectedDetail): void {
this.setState({ selectedReturn: d }); this.setState({ selectedReturn: d });
} }
async confirm() { async confirm(): Promise<void> {
const selectedReturn = this.state.selectedReturn; const selectedReturn = this.state.selectedReturn;
if (!selectedReturn) { if (!selectedReturn) {
return; return;
@ -263,14 +262,14 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
}); });
} }
async cancel() { async cancel(): Promise<void> {
this.setState({ this.setState({
selectedReturn: undefined, selectedReturn: undefined,
lastConfirmedDetail: undefined, lastConfirmedDetail: undefined,
}); });
} }
render() { render(): JSX.Element {
const balance = this.state.balance; const balance = this.state.balance;
const senderWireInfos = this.state.senderWireInfos; const senderWireInfos = this.state.senderWireInfos;
if (!balance || !senderWireInfos) { if (!balance || !senderWireInfos) {
@ -310,6 +309,6 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
} }
} }
export function createReturnCoinsPage() { export function createReturnCoinsPage(): JSX.Element {
return <ReturnCoins />; return <ReturnCoins />;
} }

View File

@ -22,30 +22,25 @@
*/ */
import * as React from "react"; import * as React from "react";
import * as ReactDOM from "react-dom";
import * as i18n from "../i18n"; import { acceptTip, getTipStatus } from "../wxApi";
import { acceptTip, getReserveCreationInfo, getTipStatus } from "../wxApi";
import { import {
WithdrawDetailView,
renderAmount, renderAmount,
ProgressButton, ProgressButton,
} from "../renderHtml"; } from "../renderHtml";
import * as Amounts from "../../util/amounts";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { TipStatus } from "../../types/walletTypes"; import { TipStatus } from "../../types/walletTypes";
function TipDisplay(props: { talerTipUri: string }) { function TipDisplay(props: { talerTipUri: string }): JSX.Element {
const [tipStatus, setTipStatus] = useState<TipStatus | undefined>(undefined); const [tipStatus, setTipStatus] = useState<TipStatus | undefined>(undefined);
const [discarded, setDiscarded] = useState(false); const [discarded, setDiscarded] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [finished, setFinished] = useState(false); const [finished, setFinished] = useState(false);
useEffect(() => { useEffect(() => {
const doFetch = async () => { const doFetch = async (): Promise<void> => {
const ts = await getTipStatus(props.talerTipUri); const ts = await getTipStatus(props.talerTipUri);
setTipStatus(ts); setTipStatus(ts);
}; };
@ -53,7 +48,7 @@ function TipDisplay(props: { talerTipUri: string }) {
}, []); }, []);
if (discarded) { if (discarded) {
return <span>You've discarded the tip.</span>; return <span>You&apos;ve discarded the tip.</span>;
} }
if (finished) { if (finished) {
@ -64,11 +59,11 @@ function TipDisplay(props: { talerTipUri: string }) {
return <span>Loading ...</span>; return <span>Loading ...</span>;
} }
const discard = () => { const discard = (): void => {
setDiscarded(true); setDiscarded(true);
}; };
const accept = async () => { const accept = async (): Promise<void> => {
setLoading(true); setLoading(true);
await acceptTip(tipStatus.tipId); await acceptTip(tipStatus.tipId);
setFinished(true); setFinished(true);
@ -100,7 +95,7 @@ function TipDisplay(props: { talerTipUri: string }) {
); );
} }
export function createTipPage() { export function createTipPage(): JSX.Element {
const url = new URL(document.location.href); const url = new URL(document.location.href);
const talerTipUri = url.searchParams.get("talerTipUri"); const talerTipUri = url.searchParams.get("talerTipUri");
if (typeof talerTipUri !== "string") { if (typeof talerTipUri !== "string") {

View File

@ -25,7 +25,7 @@ import { getDiagnostics } from "../wxApi";
import { PageLink } from "../renderHtml"; import { PageLink } from "../renderHtml";
import { WalletDiagnostics } from "../../types/walletTypes"; import { WalletDiagnostics } from "../../types/walletTypes";
function Diagnostics() { function Diagnostics(): JSX.Element {
const [timedOut, setTimedOut] = useState(false); const [timedOut, setTimedOut] = useState(false);
const [diagnostics, setDiagnostics] = useState<WalletDiagnostics | undefined>( const [diagnostics, setDiagnostics] = useState<WalletDiagnostics | undefined>(
undefined, undefined,
@ -39,7 +39,7 @@ function Diagnostics() {
setTimedOut(true); setTimedOut(true);
} }
}, 1000); }, 1000);
const doFetch = async () => { const doFetch = async (): Promise<void> => {
const d = await getDiagnostics(); const d = await getDiagnostics();
console.log("got diagnostics", d); console.log("got diagnostics", d);
gotDiagnostics = true; gotDiagnostics = true;
@ -95,7 +95,7 @@ function Diagnostics() {
return <p>Running diagnostics ...</p>; return <p>Running diagnostics ...</p>;
} }
function Welcome() { function Welcome(): JSX.Element {
return ( return (
<> <>
<p>Thank you for installing the wallet.</p> <p>Thank you for installing the wallet.</p>
@ -110,6 +110,6 @@ function Welcome() {
); );
} }
export function createWelcomePage() { export function createWelcomePage(): JSX.Element {
return <Welcome />; return <Welcome />;
} }

View File

@ -28,10 +28,9 @@ import { WithdrawDetails } from "../../types/walletTypes";
import { WithdrawDetailView, renderAmount } from "../renderHtml"; import { WithdrawDetailView, renderAmount } from "../renderHtml";
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import * as ReactDOM from "react-dom";
import { getWithdrawDetails, acceptWithdrawal } from "../wxApi"; import { getWithdrawDetails, acceptWithdrawal } from "../wxApi";
function NewExchangeSelection(props: { talerWithdrawUri: string }) { function NewExchangeSelection(props: { talerWithdrawUri: string }): JSX.Element {
const [details, setDetails] = useState<WithdrawDetails | undefined>(); const [details, setDetails] = useState<WithdrawDetails | undefined>();
const [selectedExchange, setSelectedExchange] = useState< const [selectedExchange, setSelectedExchange] = useState<
string | undefined string | undefined
@ -43,7 +42,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
const [errMsg, setErrMsg] = useState<string | undefined>(""); const [errMsg, setErrMsg] = useState<string | undefined>("");
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async (): Promise<void> => {
console.log("getting from", talerWithdrawUri); console.log("getting from", talerWithdrawUri);
let d: WithdrawDetails | undefined = undefined; let d: WithdrawDetails | undefined = undefined;
try { try {
@ -145,7 +144,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
); );
} }
const accept = async () => { const accept = async (): Promise<void> => {
console.log("accepting exchange", selectedExchange); console.log("accepting exchange", selectedExchange);
const res = await acceptWithdrawal(talerWithdrawUri, selectedExchange!); const res = await acceptWithdrawal(talerWithdrawUri, selectedExchange!);
console.log("accept withdrawal response", res); console.log("accept withdrawal response", res);
@ -197,27 +196,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
); );
} }
async function main() { export function createWithdrawPage(): JSX.Element {
try {
const url = new URL(document.location.href);
const talerWithdrawUri = url.searchParams.get("talerWithdrawUri");
if (!talerWithdrawUri) {
throw Error("withdraw URI required");
}
ReactDOM.render(
<NewExchangeSelection talerWithdrawUri={talerWithdrawUri} />,
document.getElementById("exchange-selection")!,
);
} catch (e) {
// TODO: provide more context information, maybe factor it out into a
// TODO:generic error reporting function or component.
document.body.innerText = i18n.str`Fatal error: "${e.message}".`;
console.error("got error", e);
}
}
export function createWithdrawPage() {
const url = new URL(document.location.href); const url = new URL(document.location.href);
const talerWithdrawUri = url.searchParams.get("talerWithdrawUri"); const talerWithdrawUri = url.searchParams.get("talerWithdrawUri");
if (!talerWithdrawUri) { if (!talerWithdrawUri) {

View File

@ -29,14 +29,13 @@ import { DenominationRecord } from "../types/dbTypes";
import { ExchangeWithdrawDetails } from "../types/walletTypes"; import { ExchangeWithdrawDetails } from "../types/walletTypes";
import * as i18n from "./i18n"; import * as i18n from "./i18n";
import React from "react"; import React from "react";
import ReactDOM from "react-dom";
import { stringifyTimestamp } from "../util/time"; import { stringifyTimestamp } from "../util/time";
/** /**
* Render amount as HTML, which non-breaking space between * Render amount as HTML, which non-breaking space between
* decimal value and currency. * decimal value and currency.
*/ */
export function renderAmount(amount: AmountJson | string) { export function renderAmount(amount: AmountJson | string): JSX.Element {
let a; let a;
if (typeof amount === "string") { if (typeof amount === "string") {
a = Amounts.parse(amount); a = Amounts.parse(amount);
@ -54,14 +53,17 @@ export function renderAmount(amount: AmountJson | string) {
); );
} }
export const AmountView = ({ amount }: { amount: AmountJson | string }) => export const AmountView = ({
renderAmount(amount); amount,
}: {
amount: AmountJson | string;
}): JSX.Element => renderAmount(amount);
/** /**
* Abbreviate a string to a given length, and show the full * Abbreviate a string to a given length, and show the full
* string on hover as a tooltip. * string on hover as a tooltip.
*/ */
export function abbrev(s: string, n = 5) { export function abbrev(s: string, n = 5): JSX.Element {
let sAbbrev = s; let sAbbrev = s;
if (s.length > n) { if (s.length > n) {
sAbbrev = s.slice(0, n) + ".."; sAbbrev = s.slice(0, n) + "..";
@ -94,12 +96,12 @@ export class Collapsible extends React.Component<
super(props); super(props);
this.state = { collapsed: props.initiallyCollapsed }; this.state = { collapsed: props.initiallyCollapsed };
} }
render() { render(): JSX.Element {
const doOpen = (e: any) => { const doOpen = (e: any): void => {
this.setState({ collapsed: false }); this.setState({ collapsed: false });
e.preventDefault(); e.preventDefault();
}; };
const doClose = (e: any) => { const doClose = (e: any): void => {
this.setState({ collapsed: true }); this.setState({ collapsed: true });
e.preventDefault(); e.preventDefault();
}; };
@ -188,7 +190,7 @@ function FeeDetailsView(props: {
countByPub[x.denomPub] = c; countByPub[x.denomPub] = c;
}); });
function row(denom: DenominationRecord) { function row(denom: DenominationRecord): JSX.Element {
return ( return (
<tr> <tr>
<td>{countByPub[denom.denomPub] + "x"}</td> <td>{countByPub[denom.denomPub] + "x"}</td>
@ -296,7 +298,7 @@ interface ExpanderTextProps {
/** /**
* Show a heading with a toggle to show/hide the expandable content. * Show a heading with a toggle to show/hide the expandable content.
*/ */
export function ExpanderText({ text }: ExpanderTextProps) { export function ExpanderText({ text }: ExpanderTextProps): JSX.Element {
return <span>{text}</span>; return <span>{text}</span>;
} }
@ -310,7 +312,7 @@ export function ProgressButton(
React.ButtonHTMLAttributes<HTMLButtonElement>, React.ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement HTMLButtonElement
>, >,
) { ): JSX.Element {
return ( return (
<button <button
className="pure-button pure-button-primary" className="pure-button pure-button-primary"
@ -330,7 +332,9 @@ export function ProgressButton(
); );
} }
export function PageLink(props: React.PropsWithChildren<{ pageName: string }>) { export function PageLink(
props: React.PropsWithChildren<{ pageName: string }>,
): JSX.Element {
const url = chrome.extension.getURL(`/src/webex/pages/${props.pageName}`); const url = chrome.extension.getURL(`/src/webex/pages/${props.pageName}`);
return ( return (
<a className="actionLink" href={url} target="_blank"> <a className="actionLink" href={url} target="_blank">

View File

@ -38,6 +38,9 @@ import {
WalletBalance, WalletBalance,
PurchaseDetails, PurchaseDetails,
WalletDiagnostics, WalletDiagnostics,
WithdrawDetails,
PreparePayResult,
AcceptWithdrawalResponse,
} from "../types/walletTypes"; } from "../types/walletTypes";
import { MessageMap, MessageType } from "./messages"; import { MessageMap, MessageType } from "./messages";
@ -271,7 +274,7 @@ export function applyRefund(refundUrl: string): Promise<string> {
/** /**
* Abort a failed payment and try to get a refund. * Abort a failed payment and try to get a refund.
*/ */
export function abortFailedPayment(contractTermsHash: string) { export function abortFailedPayment(contractTermsHash: string): Promise<void> {
return callBackend("abort-failed-payment", { contractTermsHash }); return callBackend("abort-failed-payment", { contractTermsHash });
} }
@ -288,7 +291,7 @@ export function benchmarkCrypto(repetitions: number): Promise<BenchmarkResult> {
export function getWithdrawDetails( export function getWithdrawDetails(
talerWithdrawUri: string, talerWithdrawUri: string,
maybeSelectedExchange: string | undefined, maybeSelectedExchange: string | undefined,
) { ): Promise<WithdrawDetails> {
return callBackend("get-withdraw-details", { return callBackend("get-withdraw-details", {
talerWithdrawUri, talerWithdrawUri,
maybeSelectedExchange, maybeSelectedExchange,
@ -298,7 +301,7 @@ export function getWithdrawDetails(
/** /**
* Get details about a pay operation. * Get details about a pay operation.
*/ */
export function preparePay(talerPayUri: string) { export function preparePay(talerPayUri: string): Promise<PreparePayResult> {
return callBackend("prepare-pay", { talerPayUri }); return callBackend("prepare-pay", { talerPayUri });
} }
@ -308,7 +311,7 @@ export function preparePay(talerPayUri: string) {
export function acceptWithdrawal( export function acceptWithdrawal(
talerWithdrawUri: string, talerWithdrawUri: string,
selectedExchange: string, selectedExchange: string,
) { ): Promise<AcceptWithdrawalResponse> {
return callBackend("accept-withdrawal", { return callBackend("accept-withdrawal", {
talerWithdrawUri, talerWithdrawUri,
selectedExchange, selectedExchange,

View File

@ -40,7 +40,6 @@ import { BrowserHttpLib } from "../util/http";
import { OpenedPromise, openPromise } from "../util/promiseUtils"; import { OpenedPromise, openPromise } from "../util/promiseUtils";
import { classifyTalerUri, TalerUriType } from "../util/taleruri"; import { classifyTalerUri, TalerUriType } from "../util/taleruri";
import { Wallet } from "../wallet"; import { Wallet } from "../wallet";
import { ChromeBadge } from "./chromeBadge";
import { isFirefox } from "./compat"; import { isFirefox } from "./compat";
import { MessageType } from "./messages"; import { MessageType } from "./messages";
import * as wxApi from "./wxApi"; import * as wxApi from "./wxApi";
@ -49,6 +48,21 @@ import { Database } from "../util/query";
const NeedsWallet = Symbol("NeedsWallet"); const NeedsWallet = Symbol("NeedsWallet");
/**
* Currently active wallet instance. Might be unloaded and
* re-instantiated when the database is reset.
*/
let currentWallet: Wallet | undefined;
let currentDatabase: IDBDatabase | undefined;
/**
* Last version if an outdated DB, if applicable.
*/
let outdatedDbVersion: number | undefined;
const walletInit: OpenedPromise<void> = openPromise<void>();
async function handleMessage( async function handleMessage(
sender: MessageSender, sender: MessageSender,
type: MessageType, type: MessageType,
@ -57,14 +71,12 @@ async function handleMessage(
function assertNotFound(t: never): never { function assertNotFound(t: never): never {
console.error(`Request type ${t as string} unknown`); console.error(`Request type ${t as string} unknown`);
console.error(`Request detail was ${detail}`); console.error(`Request detail was ${detail}`);
return ( return {
{ error: {
error: { message: `request type ${t as string} unknown`,
message: `request type ${t as string} unknown`, requestType: type,
requestType: type, },
}, } as never;
} as never
);
} }
function needsWallet(): Wallet { function needsWallet(): Wallet {
if (!currentWallet) { if (!currentWallet) {
@ -320,7 +332,7 @@ function getTab(tabId: number): Promise<chrome.tabs.Tab> {
}); });
} }
function setBadgeText(options: chrome.browserAction.BadgeTextDetails) { function setBadgeText(options: chrome.browserAction.BadgeTextDetails): void {
// not supported by all browsers ... // not supported by all browsers ...
if (chrome && chrome.browserAction && chrome.browserAction.setBadgeText) { if (chrome && chrome.browserAction && chrome.browserAction.setBadgeText) {
chrome.browserAction.setBadgeText(options); chrome.browserAction.setBadgeText(options);
@ -331,9 +343,12 @@ function setBadgeText(options: chrome.browserAction.BadgeTextDetails) {
function waitMs(timeoutMs: number): Promise<void> { function waitMs(timeoutMs: number): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
chrome.extension const bgPage = chrome.extension.getBackgroundPage();
.getBackgroundPage()! if (!bgPage) {
.setTimeout(() => resolve(), timeoutMs); reject("fatal: no background page");
return;
}
bgPage.setTimeout(() => resolve(), timeoutMs);
}); });
} }
@ -359,7 +374,7 @@ function makeSyncWalletRedirect(
if (isFirefox()) { if (isFirefox()) {
// Some platforms don't support the sync redirect (yet), so fall back to // Some platforms don't support the sync redirect (yet), so fall back to
// async redirect after a timeout. // async redirect after a timeout.
const doit = async () => { const doit = async (): Promise<void> => {
await waitMs(150); await waitMs(150);
const tab = await getTab(tabId); const tab = await getTab(tabId);
if (tab.url === oldUrl) { if (tab.url === oldUrl) {
@ -371,29 +386,13 @@ function makeSyncWalletRedirect(
return { redirectUrl: outerUrl.href }; return { redirectUrl: outerUrl.href };
} }
/** async function reinitWallet(): Promise<void> {
* Currently active wallet instance. Might be unloaded and
* re-instantiated when the database is reset.
*/
let currentWallet: Wallet | undefined;
let currentDatabase: IDBDatabase | undefined;
/**
* Last version if an outdated DB, if applicable.
*/
let outdatedDbVersion: number | undefined;
const walletInit: OpenedPromise<void> = openPromise<void>();
async function reinitWallet() {
if (currentWallet) { if (currentWallet) {
currentWallet.stop(); currentWallet.stop();
currentWallet = undefined; currentWallet = undefined;
} }
currentDatabase = undefined; currentDatabase = undefined;
setBadgeText({ text: "" }); setBadgeText({ text: "" });
const badge = new ChromeBadge();
try { try {
currentDatabase = await openTalerDatabase(indexedDB, reinitWallet); currentDatabase = await openTalerDatabase(indexedDB, reinitWallet);
} catch (e) { } catch (e) {
@ -461,7 +460,7 @@ try {
* *
* Sets up all event handlers and other machinery. * Sets up all event handlers and other machinery.
*/ */
export async function wxMain() { export async function wxMain(): Promise<void> {
// Explicitly unload the extension page as soon as an update is available, // Explicitly unload the extension page as soon as an update is available,
// so the update gets installed as soon as possible. // so the update gets installed as soon as possible.
chrome.runtime.onUpdateAvailable.addListener((details) => { chrome.runtime.onUpdateAvailable.addListener((details) => {
@ -505,8 +504,13 @@ export async function wxMain() {
chrome.tabs.onRemoved.addListener((tabId, changeInfo) => { chrome.tabs.onRemoved.addListener((tabId, changeInfo) => {
const tt = tabTimers[tabId] || []; const tt = tabTimers[tabId] || [];
const bgPage = chrome.extension.getBackgroundPage();
if (!bgPage) {
console.error("background page unavailable");
return;
}
for (const t of tt) { for (const t of tt) {
chrome.extension.getBackgroundPage()!.clearTimeout(t); bgPage.clearTimeout(t);
} }
}); });
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => { chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
@ -515,12 +519,7 @@ export async function wxMain() {
} }
const timers: number[] = []; const timers: number[] = [];
const addRun = (dt: number) => { const run = (): void => {
const id = chrome.extension.getBackgroundPage()!.setTimeout(run, dt);
timers.push(id);
};
const run = () => {
timers.shift(); timers.shift();
chrome.tabs.get(tabId, (tab) => { chrome.tabs.get(tabId, (tab) => {
if (chrome.runtime.lastError) { if (chrome.runtime.lastError) {
@ -538,10 +537,20 @@ export async function wxMain() {
document.dispatchEvent(new Event("taler-probe-result")); document.dispatchEvent(new Event("taler-probe-result"));
} }
`; `;
injectScript(tab.id!, { code, runAt: "document_start" }, uri.href); injectScript(tab.id, { code, runAt: "document_start" }, uri.href);
}); });
}; };
const addRun = (dt: number): void => {
const bgPage = chrome.extension.getBackgroundPage();
if (!bgPage) {
console.error("no background page");
return;
}
const id = bgPage.setTimeout(run, dt);
timers.push(id);
};
addRun(0); addRun(0);
addRun(50); addRun(50);
addRun(300); addRun(300);