stricter type checking

This commit is contained in:
Florian Dold 2016-09-12 17:41:12 +02:00
parent 17581b946d
commit e3cc9c59bc
7 changed files with 140 additions and 113 deletions

View File

@ -35,7 +35,7 @@ namespace TalerNotify {
* Wallet-internal version of offerContractFrom, used for 402 payments. * Wallet-internal version of offerContractFrom, used for 402 payments.
*/ */
function internalOfferContractFrom(url: string) { function internalOfferContractFrom(url: string) {
function handle_contract(contract_wrapper) { function handle_contract(contract_wrapper: any) {
var cEvent = new CustomEvent("taler-confirm-contract", { var cEvent = new CustomEvent("taler-confirm-contract", {
detail: { detail: {
contract_wrapper: contract_wrapper, contract_wrapper: contract_wrapper,
@ -88,7 +88,7 @@ namespace TalerNotify {
* Try to notify the wallet first, before we show a potentially * Try to notify the wallet first, before we show a potentially
* synchronous error message (such as an alert) or leave the page. * synchronous error message (such as an alert) or leave the page.
*/ */
function handleFailedPayment(status) { function handleFailedPayment(status: any) {
const msg = { const msg = {
type: "payment-failed", type: "payment-failed",
detail: {}, detail: {},
@ -99,19 +99,22 @@ namespace TalerNotify {
} }
function handleResponse(evt) { function handleResponse(evt: CustomEvent) {
console.log("handling taler-notify-payment"); console.log("handling taler-notify-payment");
// Payment timeout in ms. // Payment timeout in ms.
let timeout_ms = 1000; let timeout_ms = 1000;
// Current request. // Current request.
let r; let r: XMLHttpRequest | null = null;
let timeoutHandle = null; let timeoutHandle: number|null = null;
function sendPay() { function sendPay() {
r = new XMLHttpRequest(); r = new XMLHttpRequest();
r.open("post", payUrl); r.open("post", payUrl);
r.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); r.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
r.send(JSON.stringify(evt.detail.payment)); r.send(JSON.stringify(evt.detail.payment));
r.onload = function() { r.onload = function() {
if (!r) {
throw Error("invariant");
}
switch (r.status) { switch (r.status) {
case 200: case 200:
window.location.href = subst(evt.detail.contract.fulfillment_url, window.location.href = subst(evt.detail.contract.fulfillment_url,
@ -152,13 +155,17 @@ namespace TalerNotify {
document.dispatchEvent(eve); document.dispatchEvent(eve);
} }
function subst(url: string, H_contract) { function subst(url: string, H_contract: string) {
url = url.replace("${H_contract}", H_contract); url = url.replace("${H_contract}", H_contract);
url = url.replace("${$}", "$"); url = url.replace("${$}", "$");
return url; return url;
} }
const handlers = []; interface Handler {
type: string;
listener: (e: CustomEvent) => void;
}
const handlers: Handler[] = [];
function init() { function init() {
chrome.runtime.sendMessage({type: "ping"}, (resp) => { chrome.runtime.sendMessage({type: "ping"}, (resp) => {
@ -197,9 +204,7 @@ namespace TalerNotify {
init(); init();
function registerHandlers() { function registerHandlers() {
const $ = (x) => document.getElementById(x); function addHandler(type: string, listener: (e: CustomEvent) => void) {
function addHandler(type, listener) {
document.addEventListener(type, listener); document.addEventListener(type, listener);
handlers.push({type, listener}); handlers.push({type, listener});
} }

View File

@ -125,6 +125,8 @@ const tsBaseArgs = {
noLib: true, noLib: true,
noImplicitReturns: true, noImplicitReturns: true,
noFallthroughCasesInSwitch: true, noFallthroughCasesInSwitch: true,
strictNullChecks: true,
noImplicitAny: true,
}; };

View File

@ -24,7 +24,7 @@
function subst(url: string, H_contract) { function subst(url: string, H_contract: string) {
url = url.replace("${H_contract}", H_contract); url = url.replace("${H_contract}", H_contract);
url = url.replace("${$}", "$"); url = url.replace("${$}", "$");
return url; return url;
@ -138,7 +138,7 @@ export function fetchPayment(H_contract: any, offering_url: any) {
* Offer a contract to the wallet after * Offer a contract to the wallet after
* downloading it from the given URL. * downloading it from the given URL.
*/ */
function offerContractFrom(url) { function offerContractFrom(url: string) {
var contract_request = new XMLHttpRequest(); var contract_request = new XMLHttpRequest();
console.log("downloading contract from '" + url + "'"); console.log("downloading contract from '" + url + "'");
contract_request.open("GET", url, true); contract_request.open("GET", url, true);

View File

@ -24,7 +24,7 @@
"use strict"; "use strict";
export function Query(db) { export function Query(db: IDBDatabase) {
return new QueryRoot(db); return new QueryRoot(db);
} }
@ -36,24 +36,27 @@ export interface QueryStream<T> {
indexJoin<S>(storeName: string, indexJoin<S>(storeName: string,
indexName: string, indexName: string,
keyFn: (obj: any) => any): QueryStream<[T,S]>; keyFn: (obj: any) => any): QueryStream<[T,S]>;
filter(f: (any) => boolean): QueryStream<T>; filter(f: (x: any) => boolean): QueryStream<T>;
reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>; reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>;
flatMap(f: (T) => T[]): QueryStream<T>; flatMap(f: (x: T) => T[]): QueryStream<T>;
} }
/** /**
* Get an unresolved promise together with its extracted resolve / reject * Get an unresolved promise together with its extracted resolve / reject
* function. * function.
*
* @returns {{resolve: any, reject: any, promise: Promise<T>}}
*/ */
function openPromise<T>() { function openPromise<T>() {
let resolve, reject; let resolve: ((value?: T | PromiseLike<T>) => void) | null = null;
let reject: ((reason?: any) => void) | null = null;
const promise = new Promise<T>((res, rej) => { const promise = new Promise<T>((res, rej) => {
resolve = res; resolve = res;
reject = rej; reject = rej;
}); });
if (!(resolve && reject)) {
// Never happens, unless JS implementation is broken
throw Error();
}
return {resolve, reject, promise}; return {resolve, reject, promise};
} }
@ -61,7 +64,7 @@ function openPromise<T>() {
abstract class QueryStreamBase<T> implements QueryStream<T> { abstract class QueryStreamBase<T> implements QueryStream<T> {
abstract subscribe(f: (isDone: boolean, abstract subscribe(f: (isDone: boolean,
value: any, value: any,
tx: IDBTransaction) => void); tx: IDBTransaction) => void): void;
root: QueryRoot; root: QueryRoot;
@ -69,30 +72,28 @@ abstract class QueryStreamBase<T> implements QueryStream<T> {
this.root = root; this.root = root;
} }
flatMap(f: (T) => T[]): QueryStream<T> { flatMap(f: (x: T) => T[]): QueryStream<T> {
return new QueryStreamFlatMap(this, f); return new QueryStreamFlatMap(this, f);
} }
indexJoin<S>(storeName: string, indexJoin<S>(storeName: string,
indexName: string, indexName: string,
key: any): QueryStream<[T,S]> { key: any): QueryStream<[T,S]> {
this.root.addWork(null, storeName, false); this.root.addStoreAccess(storeName, false);
return new QueryStreamIndexJoin(this, storeName, indexName, key); return new QueryStreamIndexJoin(this, storeName, indexName, key);
} }
filter(f: (any) => boolean): QueryStream<T> { filter(f: (x: any) => boolean): QueryStream<T> {
return new QueryStreamFilter(this, f); return new QueryStreamFilter(this, f);
} }
reduce(f, acc?): Promise<any> { reduce<A>(f: (x: any, acc?: A) => A, init?: A): Promise<any> {
let leakedResolve; let {resolve, promise} = openPromise();
let p = new Promise((resolve, reject) => { let acc = init;
leakedResolve = resolve;
});
this.subscribe((isDone, value) => { this.subscribe((isDone, value) => {
if (isDone) { if (isDone) {
leakedResolve(acc); resolve(acc);
return; return;
} }
acc = f(value, acc); acc = f(value, acc);
@ -100,22 +101,28 @@ abstract class QueryStreamBase<T> implements QueryStream<T> {
return Promise.resolve() return Promise.resolve()
.then(() => this.root.finish()) .then(() => this.root.finish())
.then(() => p); .then(() => promise);
} }
} }
type FilterFn = (e: any) => boolean;
type SubscribeFn = (done: boolean, value: any, tx: IDBTransaction) => void;
interface FlatMapFn<T> {
(v: T): T[];
}
class QueryStreamFilter<T> extends QueryStreamBase<T> { class QueryStreamFilter<T> extends QueryStreamBase<T> {
s: QueryStreamBase<T>; s: QueryStreamBase<T>;
filterFn; filterFn: FilterFn;
constructor(s: QueryStreamBase<T>, filterFn) { constructor(s: QueryStreamBase<T>, filterFn: FilterFn) {
super(s.root); super(s.root);
this.s = s; this.s = s;
this.filterFn = filterFn; this.filterFn = filterFn;
} }
subscribe(f) { subscribe(f: SubscribeFn) {
this.s.subscribe((isDone, value, tx) => { this.s.subscribe((isDone, value, tx) => {
if (isDone) { if (isDone) {
f(true, undefined, tx); f(true, undefined, tx);
@ -131,15 +138,15 @@ class QueryStreamFilter<T> extends QueryStreamBase<T> {
class QueryStreamFlatMap<T> extends QueryStreamBase<T> { class QueryStreamFlatMap<T> extends QueryStreamBase<T> {
s: QueryStreamBase<T>; s: QueryStreamBase<T>;
flatMapFn; flatMapFn: (v: T) => T[];
constructor(s: QueryStreamBase<T>, flatMapFn) { constructor(s: QueryStreamBase<T>, flatMapFn: (v: T) => T[]) {
super(s.root); super(s.root);
this.s = s; this.s = s;
this.flatMap = flatMapFn; this.flatMapFn = flatMapFn;
} }
subscribe(f) { subscribe(f: SubscribeFn) {
this.s.subscribe((isDone, value, tx) => { this.s.subscribe((isDone, value, tx) => {
if (isDone) { if (isDone) {
f(true, undefined, tx); f(true, undefined, tx);
@ -154,13 +161,13 @@ class QueryStreamFlatMap<T> extends QueryStreamBase<T> {
} }
class QueryStreamIndexJoin<T> extends QueryStreamBase<T> { class QueryStreamIndexJoin<T,S> extends QueryStreamBase<[T, S]> {
s: QueryStreamBase<T>; s: QueryStreamBase<T>;
storeName; storeName: string;
key; key: any;
indexName; indexName: string;
constructor(s, storeName: string, indexName: string, key: any) { constructor(s: QueryStreamBase<T>, storeName: string, indexName: string, key: any) {
super(s.root); super(s.root);
this.s = s; this.s = s;
this.storeName = storeName; this.storeName = storeName;
@ -168,7 +175,7 @@ class QueryStreamIndexJoin<T> extends QueryStreamBase<T> {
this.indexName = indexName; this.indexName = indexName;
} }
subscribe(f) { subscribe(f: SubscribeFn) {
this.s.subscribe((isDone, value, tx) => { this.s.subscribe((isDone, value, tx) => {
if (isDone) { if (isDone) {
f(true, undefined, tx); f(true, undefined, tx);
@ -192,31 +199,31 @@ class QueryStreamIndexJoin<T> extends QueryStreamBase<T> {
class IterQueryStream<T> extends QueryStreamBase<T> { class IterQueryStream<T> extends QueryStreamBase<T> {
private storeName; private storeName: string;
private options; private options: any;
private subscribers; private subscribers: SubscribeFn[];
constructor(qr, storeName, options) { constructor(qr: QueryRoot, storeName: string, options: any) {
super(qr); super(qr);
this.options = options; this.options = options;
this.storeName = storeName; this.storeName = storeName;
this.subscribers = []; this.subscribers = [];
let doIt = (tx) => { let doIt = (tx: IDBTransaction) => {
const {indexName = void 0, only = void 0} = this.options; const {indexName = void 0, only = void 0} = this.options;
let s; let s: any;
if (indexName !== void 0) { if (indexName !== void 0) {
s = tx.objectStore(this.storeName) s = tx.objectStore(this.storeName)
.index(this.options.indexName); .index(this.options.indexName);
} else { } else {
s = tx.objectStore(this.storeName); s = tx.objectStore(this.storeName);
} }
let kr = undefined; let kr: IDBKeyRange|undefined = undefined;
if (only !== void 0) { if (only !== undefined) {
kr = IDBKeyRange.only(this.options.only); kr = IDBKeyRange.only(this.options.only);
} }
let req = s.openCursor(kr); let req = s.openCursor(kr);
req.onsuccess = (e) => { req.onsuccess = () => {
let cursor: IDBCursorWithValue = req.result; let cursor: IDBCursorWithValue = req.result;
if (cursor) { if (cursor) {
for (let f of this.subscribers) { for (let f of this.subscribers) {
@ -231,32 +238,33 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
} }
}; };
this.root.addWork(doIt, null, false); this.root.addWork(doIt);
} }
subscribe(f) { subscribe(f: SubscribeFn) {
this.subscribers.push(f); this.subscribers.push(f);
} }
} }
class QueryRoot { class QueryRoot {
private work = []; private work: ((t: IDBTransaction) => void)[] = [];
private db: IDBDatabase; private db: IDBDatabase;
private stores = new Set(); private stores = new Set();
private kickoffPromise; private kickoffPromise: Promise<void>;
/** /**
* Some operations is a write operation, * Some operations is a write operation,
* and we need to do a "readwrite" transaction/ * and we need to do a "readwrite" transaction/
*/ */
private hasWrite; private hasWrite: boolean;
constructor(db) { constructor(db: IDBDatabase) {
this.db = db; this.db = db;
} }
iter<T>(storeName, {only = void 0, indexName = void 0} = {}): QueryStream<T> { iter<T>(storeName: string,
{only = <string|undefined>undefined, indexName = <string|undefined>undefined} = {}): QueryStream<T> {
this.stores.add(storeName); this.stores.add(storeName);
return new IterQueryStream(this, storeName, {only, indexName}); return new IterQueryStream(this, storeName, {only, indexName});
} }
@ -266,7 +274,7 @@ class QueryRoot {
* Overrides if an existing object with the same key exists * Overrides if an existing object with the same key exists
* in the store. * in the store.
*/ */
put(storeName, val): QueryRoot { put(storeName: string, val: any): QueryRoot {
let doPut = (tx: IDBTransaction) => { let doPut = (tx: IDBTransaction) => {
tx.objectStore(storeName).put(val); tx.objectStore(storeName).put(val);
}; };
@ -280,7 +288,7 @@ class QueryRoot {
* Fails if the object's key is already present * Fails if the object's key is already present
* in the object store. * in the object store.
*/ */
putAll(storeName, iterable): QueryRoot { putAll(storeName: string, iterable: any[]): QueryRoot {
const doPutAll = (tx: IDBTransaction) => { const doPutAll = (tx: IDBTransaction) => {
for (const obj of iterable) { for (const obj of iterable) {
tx.objectStore(storeName).put(obj); tx.objectStore(storeName).put(obj);
@ -295,7 +303,7 @@ class QueryRoot {
* Fails if the object's key is already present * Fails if the object's key is already present
* in the object store. * in the object store.
*/ */
add(storeName, val): QueryRoot { add(storeName: string, val: any): QueryRoot {
const doAdd = (tx: IDBTransaction) => { const doAdd = (tx: IDBTransaction) => {
tx.objectStore(storeName).add(val); tx.objectStore(storeName).add(val);
}; };
@ -306,16 +314,16 @@ class QueryRoot {
/** /**
* Get one object from a store by its key. * Get one object from a store by its key.
*/ */
get(storeName, key): Promise<any> { get(storeName: any, key: any): Promise<any> {
if (key === void 0) { if (key === void 0) {
throw Error("key must not be undefined"); throw Error("key must not be undefined");
} }
const {resolve, promise} = openPromise(); const {resolve, promise} = openPromise();
const doGet = (tx) => { const doGet = (tx: IDBTransaction) => {
const req = tx.objectStore(storeName).get(key); const req = tx.objectStore(storeName).get(key);
req.onsuccess = (r) => { req.onsuccess = () => {
resolve(req.result); resolve(req.result);
}; };
}; };
@ -329,16 +337,16 @@ class QueryRoot {
/** /**
* Get one object from a store by its key. * Get one object from a store by its key.
*/ */
getIndexed(storeName, indexName, key): Promise<any> { getIndexed(storeName: string, indexName: string, key: any): Promise<any> {
if (key === void 0) { if (key === void 0) {
throw Error("key must not be undefined"); throw Error("key must not be undefined");
} }
const {resolve, promise} = openPromise(); const {resolve, promise} = openPromise();
const doGetIndexed = (tx) => { const doGetIndexed = (tx: IDBTransaction) => {
const req = tx.objectStore(storeName).index(indexName).get(key); const req = tx.objectStore(storeName).index(indexName).get(key);
req.onsuccess = (r) => { req.onsuccess = () => {
resolve(req.result); resolve(req.result);
}; };
}; };
@ -356,7 +364,7 @@ class QueryRoot {
if (this.kickoffPromise) { if (this.kickoffPromise) {
return this.kickoffPromise; return this.kickoffPromise;
} }
this.kickoffPromise = new Promise((resolve, reject) => { this.kickoffPromise = new Promise<void>((resolve, reject) => {
if (this.work.length == 0) { if (this.work.length == 0) {
resolve(); resolve();
return; return;
@ -376,8 +384,8 @@ class QueryRoot {
/** /**
* Delete an object by from the given object store. * Delete an object by from the given object store.
*/ */
delete(storeName: string, key): QueryRoot { delete(storeName: string, key: any): QueryRoot {
const doDelete = (tx) => { const doDelete = (tx: IDBTransaction) => {
tx.objectStore(storeName).delete(key); tx.objectStore(storeName).delete(key);
}; };
this.addWork(doDelete, storeName, true); this.addWork(doDelete, storeName, true);
@ -387,17 +395,21 @@ class QueryRoot {
/** /**
* Low-level function to add a task to the internal work queue. * Low-level function to add a task to the internal work queue.
*/ */
addWork(workFn: (IDBTransaction) => void, addWork(workFn: (t: IDBTransaction) => void,
storeName: string, storeName?: string,
isWrite: boolean) { isWrite?: boolean) {
this.work.push(workFn);
if (storeName) {
this.addStoreAccess(storeName, isWrite);
}
}
addStoreAccess(storeName: string, isWrite?: boolean) {
if (storeName) { if (storeName) {
this.stores.add(storeName); this.stores.add(storeName);
} }
if (isWrite) { if (isWrite) {
this.hasWrite = true; this.hasWrite = true;
} }
if (workFn) {
this.work.push(workFn);
}
} }
} }

View File

@ -154,12 +154,12 @@ interface Transaction {
export interface Badge { export interface Badge {
setText(s: string): void; setText(s: string): void;
setColor(c: string): void; setColor(c: string): void;
startBusy(); startBusy(): void;
stopBusy(); stopBusy(): void;
} }
function deepEquals(x, y) { function deepEquals(x: any, y: any): boolean {
if (x === y) { if (x === y) {
return true; return true;
} }
@ -179,7 +179,7 @@ function flatMap<T, U>(xs: T[], f: (x: T) => U[]): U[] {
} }
function getTalerStampSec(stamp: string): number { function getTalerStampSec(stamp: string): number|null {
const m = stamp.match(/\/?Date\(([0-9]*)\)\/?/); const m = stamp.match(/\/?Date\(([0-9]*)\)\/?/);
if (!m) { if (!m) {
return null; return null;
@ -188,7 +188,7 @@ function getTalerStampSec(stamp: string): number {
} }
function setTimeout(f, t) { function setTimeout(f: any, t: number) {
return chrome.extension.getBackgroundPage().setTimeout(f, t); return chrome.extension.getBackgroundPage().setTimeout(f, t);
} }
@ -211,13 +211,13 @@ interface HttpRequestLibrary {
get(url: string|uri.URI): Promise<HttpResponse>; get(url: string|uri.URI): Promise<HttpResponse>;
postJson(url: string|uri.URI, body): Promise<HttpResponse>; postJson(url: string|uri.URI, body: any): Promise<HttpResponse>;
postForm(url: string|uri.URI, form): Promise<HttpResponse>; postForm(url: string|uri.URI, form: any): Promise<HttpResponse>;
} }
function copy(o) { function copy(o: any) {
return JSON.parse(JSON.stringify(o)); return JSON.parse(JSON.stringify(o));
} }
@ -240,7 +240,7 @@ interface KeyUpdateInfo {
function getWithdrawDenomList(amountAvailable: AmountJson, function getWithdrawDenomList(amountAvailable: AmountJson,
denoms: Denomination[]): Denomination[] { denoms: Denomination[]): Denomination[] {
let remaining = Amounts.copy(amountAvailable); let remaining = Amounts.copy(amountAvailable);
let ds: Denomination[] = []; const ds: Denomination[] = [];
console.log("available denoms"); console.log("available denoms");
console.log(denoms); console.log(denoms);
@ -362,7 +362,7 @@ export class Wallet {
let x: number; let x: number;
function storeExchangeCoin(mc, url) { function storeExchangeCoin(mc: any, url: string) {
let exchange: IExchangeInfo = mc[0]; let exchange: IExchangeInfo = mc[0];
console.log("got coin for exchange", url); console.log("got coin for exchange", url);
let coin: Coin = mc[1]; let coin: Coin = mc[1];
@ -471,7 +471,7 @@ export class Wallet {
private recordConfirmPay(offer: Offer, private recordConfirmPay(offer: Offer,
payCoinInfo: PayCoinInfo, payCoinInfo: PayCoinInfo,
chosenExchange: string): Promise<void> { chosenExchange: string): Promise<void> {
let payReq = {}; let payReq: any = {};
payReq["amount"] = offer.contract.amount; payReq["amount"] = offer.contract.amount;
payReq["coins"] = payCoinInfo.map((x) => x.sig); payReq["coins"] = payCoinInfo.map((x) => x.sig);
payReq["H_contract"] = offer.H_contract; payReq["H_contract"] = offer.H_contract;
@ -588,7 +588,7 @@ export class Wallet {
* Retrieve all necessary information for looking up the contract * Retrieve all necessary information for looking up the contract
* with the given hash. * with the given hash.
*/ */
executePayment(H_contract): Promise<any> { executePayment(H_contract: string): Promise<any> {
return Promise.resolve().then(() => { return Promise.resolve().then(() => {
return Query(this.db) return Query(this.db)
.get("transactions", H_contract) .get("transactions", H_contract)
@ -614,7 +614,7 @@ export class Wallet {
* First fetch information requred to withdraw from the reserve, * First fetch information requred to withdraw from the reserve,
* then deplete the reserve, withdrawing coins until it is empty. * then deplete the reserve, withdrawing coins until it is empty.
*/ */
private processReserve(reserveRecord): void { private processReserve(reserveRecord: any): void {
let retryDelayMs = 100; let retryDelayMs = 100;
const opId = "reserve-" + reserveRecord.reserve_pub; const opId = "reserve-" + reserveRecord.reserve_pub;
this.startOperation(opId); this.startOperation(opId);
@ -644,7 +644,7 @@ export class Wallet {
} }
private processPreCoin(preCoin, retryDelayMs = 100): void { private processPreCoin(preCoin: any, retryDelayMs = 100): void {
this.withdrawExecute(preCoin) this.withdrawExecute(preCoin)
.then((c) => this.storeCoin(c)) .then((c) => this.storeCoin(c))
.catch((e) => { .catch((e) => {
@ -810,7 +810,7 @@ export class Wallet {
/** /**
* Withdraw coins from a reserve until it is empty. * Withdraw coins from a reserve until it is empty.
*/ */
private depleteReserve(reserve, exchange: IExchangeInfo): Promise<void> { private depleteReserve(reserve: any, exchange: IExchangeInfo): Promise<void> {
let denomsAvailable: Denomination[] = copy(exchange.active_denoms); let denomsAvailable: Denomination[] = copy(exchange.active_denoms);
let denomsForWithdraw = getWithdrawDenomList(reserve.current_amount, let denomsForWithdraw = getWithdrawDenomList(reserve.current_amount,
denomsAvailable); denomsAvailable);
@ -919,7 +919,7 @@ export class Wallet {
* Optionally link the reserve entry to the new or existing * Optionally link the reserve entry to the new or existing
* exchange entry in then DB. * exchange entry in then DB.
*/ */
updateExchangeFromUrl(baseUrl): Promise<IExchangeInfo> { updateExchangeFromUrl(baseUrl: string): Promise<IExchangeInfo> {
baseUrl = canonicalizeBaseUrl(baseUrl); baseUrl = canonicalizeBaseUrl(baseUrl);
let reqUrl = URI("keys").absoluteTo(baseUrl); let reqUrl = URI("keys").absoluteTo(baseUrl);
return this.http.get(reqUrl).then((resp) => { return this.http.get(reqUrl).then((resp) => {
@ -934,8 +934,8 @@ export class Wallet {
private updateExchangeFromJson(baseUrl: string, private updateExchangeFromJson(baseUrl: string,
exchangeKeysJson: KeysJson): Promise<IExchangeInfo> { exchangeKeysJson: KeysJson): Promise<IExchangeInfo> {
let updateTimeSec = getTalerStampSec(exchangeKeysJson.list_issue_date); const updateTimeSec = getTalerStampSec(exchangeKeysJson.list_issue_date);
if (!updateTimeSec) { if (updateTimeSec === null) {
throw Error("invalid update time"); throw Error("invalid update time");
} }
@ -973,9 +973,9 @@ export class Wallet {
{indexName: "exchangeBaseUrl", only: baseUrl}) {indexName: "exchangeBaseUrl", only: baseUrl})
.reduce((coin: Coin, suspendedCoins: Coin[]) => { .reduce((coin: Coin, suspendedCoins: Coin[]) => {
if (!updatedExchangeInfo.active_denoms.find((c) => c.denom_pub == coin.denomPub)) { if (!updatedExchangeInfo.active_denoms.find((c) => c.denom_pub == coin.denomPub)) {
return [].concat(suspendedCoins, [coin]); return Array.prototype.concat(suspendedCoins, [coin]);
} }
return [].concat(suspendedCoins); return Array.prototype.concat(suspendedCoins);
}, []) }, [])
.then((suspendedCoins: Coin[]) => { .then((suspendedCoins: Coin[]) => {
let q = Query(this.db); let q = Query(this.db);
@ -1006,8 +1006,8 @@ export class Wallet {
let found = false; let found = false;
for (let oldDenom of exchangeInfo.all_denoms) { for (let oldDenom of exchangeInfo.all_denoms) {
if (oldDenom.denom_pub === newDenom.denom_pub) { if (oldDenom.denom_pub === newDenom.denom_pub) {
let a = Object.assign({}, oldDenom); let a: any = Object.assign({}, oldDenom);
let b = Object.assign({}, newDenom); let b: any = Object.assign({}, newDenom);
// pub hash is only there for convenience in the wallet // pub hash is only there for convenience in the wallet
delete a["pub_hash"]; delete a["pub_hash"];
delete b["pub_hash"]; delete b["pub_hash"];
@ -1055,7 +1055,7 @@ export class Wallet {
* that is currenctly available for spending in the wallet. * that is currenctly available for spending in the wallet.
*/ */
getBalances(): Promise<any> { getBalances(): Promise<any> {
function collectBalances(c: Coin, byCurrency) { function collectBalances(c: Coin, byCurrency: any) {
if (c.suspended) { if (c.suspended) {
return byCurrency; return byCurrency;
} }
@ -1081,7 +1081,7 @@ export class Wallet {
* Retrive the full event history for this wallet. * Retrive the full event history for this wallet.
*/ */
getHistory(): Promise<any> { getHistory(): Promise<any> {
function collect(x, acc) { function collect(x: any, acc: any) {
acc.push(x); acc.push(x);
return acc; return acc;
} }
@ -1106,7 +1106,7 @@ export class Wallet {
[contract.merchant_pub, contract.repurchase_correlation_id]) [contract.merchant_pub, contract.repurchase_correlation_id])
.then((result: Transaction) => { .then((result: Transaction) => {
console.log("db result", result); console.log("db result", result);
let isRepurchase; let isRepurchase: boolean;
if (result) { if (result) {
console.assert(result.contract.repurchase_correlation_id == contract.repurchase_correlation_id); console.assert(result.contract.repurchase_correlation_id == contract.repurchase_correlation_id);
return { return {

View File

@ -54,8 +54,12 @@ function makeHandlers(db: IDBDatabase,
return exportDb(db); return exportDb(db);
}, },
["ping"]: function(detail, sender) { ["ping"]: function(detail, sender) {
let info = paymentRequestCookies[sender.tab.id]; if (!sender || !sender.tab || !sender.tab.id) {
delete paymentRequestCookies[sender.tab.id]; return Promise.resolve();
}
let id: number = sender.tab.id;
let info: any = <any>paymentRequestCookies[id];
delete paymentRequestCookies[id];
return Promise.resolve(info); return Promise.resolve(info);
}, },
["reset"]: function(detail, sender) { ["reset"]: function(detail, sender) {
@ -89,7 +93,7 @@ function makeHandlers(db: IDBDatabase,
return wallet.confirmReserve(req); return wallet.confirmReserve(req);
}, },
["confirm-pay"]: function(detail, sender) { ["confirm-pay"]: function(detail, sender) {
let offer; let offer: Offer;
try { try {
offer = Offer.checked(detail.offer); offer = Offer.checked(detail.offer);
} catch (e) { } catch (e) {
@ -108,7 +112,7 @@ function makeHandlers(db: IDBDatabase,
return wallet.confirmPay(offer); return wallet.confirmPay(offer);
}, },
["check-pay"]: function(detail, sender) { ["check-pay"]: function(detail, sender) {
let offer; let offer: Offer;
try { try {
offer = Offer.checked(detail.offer); offer = Offer.checked(detail.offer);
} catch (e) { } catch (e) {
@ -181,14 +185,14 @@ class ChromeBadge implements Badge {
} }
function dispatch(handlers, req, sender, sendResponse) { function dispatch(handlers: any, req: any, sender: any, sendResponse: any) {
if (req.type in handlers) { if (req.type in handlers) {
Promise Promise
.resolve() .resolve()
.then(() => { .then(() => {
const p = handlers[req.type](req.detail, sender); const p = handlers[req.type](req.detail, sender);
return p.then((r) => { return p.then((r: any) => {
sendResponse(r); sendResponse(r);
}) })
}) })
@ -242,13 +246,15 @@ class ChromeNotifier implements Notifier {
/** /**
* Mapping from tab ID to payment information (if any). * Mapping from tab ID to payment information (if any).
*/ */
let paymentRequestCookies = {}; let paymentRequestCookies: {[n: number]: any} = {};
function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[], function handleHttpPayment(headerList: chrome.webRequest.HttpHeader[],
url: string, tabId: number): any { url: string, tabId: number): any {
const headers = {}; const headers: {[s: string]: string} = {};
for (let kv of headerList) { for (let kv of headerList) {
headers[kv.name.toLowerCase()] = kv.value; if (kv.value) {
headers[kv.name.toLowerCase()] = kv.value;
}
} }
const contractUrl = headers["x-taler-contract-url"]; const contractUrl = headers["x-taler-contract-url"];
@ -288,7 +294,7 @@ export function wxMain() {
chrome.tabs.query({}, function(tabs) { chrome.tabs.query({}, function(tabs) {
for (let tab of tabs) { for (let tab of tabs) {
if (!tab.url) { if (!tab.url || !tab.id) {
return; return;
} }
let uri = URI(tab.url); let uri = URI(tab.url);
@ -338,7 +344,7 @@ export function wxMain() {
return; return;
} }
console.log(`got 402 from ${details.url}`); console.log(`got 402 from ${details.url}`);
return handleHttpPayment(details.responseHeaders, return handleHttpPayment(details.responseHeaders || [],
details.url, details.url,
details.tabId); details.tabId);
}, {urls: ["<all_urls>"]}, ["responseHeaders", "blocking"]); }, {urls: ["<all_urls>"]}, ["responseHeaders", "blocking"]);

View File

@ -7,7 +7,9 @@
"sourceMap": true, "sourceMap": true,
"noLib": true, "noLib": true,
"noImplicitReturns": true, "noImplicitReturns": true,
"noFallthroughCasesInSwitch": true "noFallthroughCasesInSwitch": true,
"strictNullChecks": true,
"noImplicitAny": true
}, },
"files": [ "files": [
"lib/i18n.ts", "lib/i18n.ts",