@ledgerhq/coin-framework 0.3.5 → 0.3.6-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.eslintrc.js +8 -46
  2. package/CHANGELOG.md +13 -0
  3. package/package.json +9 -18
  4. package/src/account/accountId.ts +20 -30
  5. package/src/account/accountName.ts +1 -4
  6. package/src/account/balanceHistoryCache.ts +18 -37
  7. package/src/account/groupOperations.ts +4 -6
  8. package/src/account/helpers.test.ts +6 -26
  9. package/src/account/helpers.ts +33 -66
  10. package/src/account/ordering.ts +10 -18
  11. package/src/account/pending.ts +6 -15
  12. package/src/account/serialization.ts +8 -19
  13. package/src/account/support.ts +8 -18
  14. package/src/account.test.ts +25 -40
  15. package/src/bot/specs.ts +24 -43
  16. package/src/bot/types.ts +1 -1
  17. package/src/bridge/getAddressWrapper.ts +5 -13
  18. package/src/bridge/jsHelpers.ts +215 -259
  19. package/src/cache.ts +4 -4
  20. package/src/currencies/BigNumberToLocaleString.test.ts +25 -33
  21. package/src/currencies/BigNumberToLocaleString.ts +3 -8
  22. package/src/currencies/CurrencyURIScheme.ts +1 -3
  23. package/src/currencies/chopCurrencyUnitDecimals.ts +1 -4
  24. package/src/currencies/formatCurrencyUnit.ts +11 -21
  25. package/src/currencies/index.ts +1 -4
  26. package/src/currencies/localeUtility.ts +2 -4
  27. package/src/currencies/parseCurrencyUnit.ts +1 -4
  28. package/src/currencies/sanitizeValueString.ts +1 -1
  29. package/src/currencies/support.ts +3 -9
  30. package/src/derivation.test.ts +1 -4
  31. package/src/derivation.ts +45 -95
  32. package/src/errors.test.ts +1 -1
  33. package/src/errors.ts +2 -6
  34. package/src/mocks/account.ts +27 -80
  35. package/src/mocks/fixtures/nfts.test.ts +2 -6
  36. package/src/mocks/fixtures/nfts.ts +12 -38
  37. package/src/mocks/helpers.ts +2 -8
  38. package/src/nft/nftId.ts +2 -2
  39. package/src/operation.test.ts +6 -31
  40. package/src/operation.ts +12 -26
  41. package/src/transaction/common.ts +9 -22
@@ -82,13 +82,12 @@ export type AccountShapeInfo = {
82
82
 
83
83
  export type GetAccountShape = (
84
84
  arg0: AccountShapeInfo,
85
- arg1: SyncConfig
85
+ arg1: SyncConfig,
86
86
  ) => Promise<Partial<Account>>;
87
87
  type AccountUpdater = (arg0: Account) => Account;
88
88
 
89
89
  // compare that two dates are roughly the same date in order to update the case it would have drastically changed
90
- const sameDate = (a: Date, b: Date) =>
91
- Math.abs(a.getTime() - b.getTime()) < 1000 * 60 * 30;
90
+ const sameDate = (a: Date, b: Date) => Math.abs(a.getTime() - b.getTime()) < 1000 * 60 * 30;
92
91
 
93
92
  // an operation is relatively immutable, however we saw that sometimes it can temporarily change due to reorg,..
94
93
  export const sameOp = (a: Operation, b: Operation): boolean =>
@@ -104,7 +103,7 @@ export const sameOp = (a: Operation, b: Operation): boolean =>
104
103
  // efficiently prepend newFetched operations to existing operations
105
104
  export function mergeOps( // existing operations. sorted (newer to older). deduped.
106
105
  existing: Operation[], // new fetched operations. not sorted. not deduped. time is allowed to overlap inside existing.
107
- newFetched: Operation[]
106
+ newFetched: Operation[],
108
107
  ): // return a list of operations, deduped and sorted from newer to older
109
108
  Operation[] {
110
109
  // there is new fetched
@@ -118,12 +117,12 @@ Operation[] {
118
117
 
119
118
  // only keep the newFetched that are not in existing. this array will be mutated
120
119
  let newOps = newFetched
121
- .filter((o) => !existingIds[o.id] || !sameOp(existingIds[o.id], o))
120
+ .filter(o => !existingIds[o.id] || !sameOp(existingIds[o.id], o))
122
121
  .sort((a, b) => b.date.valueOf() - a.date.valueOf());
123
122
 
124
123
  // Deduplicate new ops to guarantee operations don't have dups
125
124
  const newOpsIds: Record<string, Operation> = {};
126
- newOps.forEach((op) => {
125
+ newOps.forEach(op => {
127
126
  newOpsIds[op.id] = op;
128
127
  });
129
128
  newOps = Object.values(newOpsIds);
@@ -149,13 +148,10 @@ Operation[] {
149
148
  return all;
150
149
  }
151
150
 
152
- export const mergeNfts = (
153
- oldNfts: ProtoNFT[],
154
- newNfts: ProtoNFT[]
155
- ): ProtoNFT[] => {
151
+ export const mergeNfts = (oldNfts: ProtoNFT[], newNfts: ProtoNFT[]): ProtoNFT[] => {
156
152
  // Getting a map of id => NFT
157
153
  const newNftsPerId: Record<string, ProtoNFT> = {};
158
- newNfts.forEach((n) => {
154
+ newNfts.forEach(n => {
159
155
  newNftsPerId[n.id] = n;
160
156
  });
161
157
 
@@ -206,7 +202,7 @@ export const makeSync =
206
202
  try {
207
203
  const freshAddressPath = getSeedIdentifierDerivation(
208
204
  initial.currency,
209
- initial.derivationMode as DerivationMode
205
+ initial.derivationMode as DerivationMode,
210
206
  );
211
207
 
212
208
  const shape = await getAccountShape(
@@ -218,7 +214,7 @@ export const makeSync =
218
214
  derivationMode: initial.derivationMode as DerivationMode,
219
215
  initialAccount: needClear ? clearAccount(initial) : initial,
220
216
  },
221
- syncConfig
217
+ syncConfig,
222
218
  );
223
219
 
224
220
  const updater = (acc: Account): Account => {
@@ -240,13 +236,11 @@ export const makeSync =
240
236
  operationsCount: shape.operationsCount || operations.length,
241
237
  lastSyncDate: new Date(),
242
238
  creationDate:
243
- operations.length > 0
244
- ? operations[operations.length - 1].date
245
- : new Date(),
239
+ operations.length > 0 ? operations[operations.length - 1].date : new Date(),
246
240
  ...shape,
247
241
  operations,
248
- pendingOperations: a.pendingOperations.filter((op) =>
249
- shouldRetainPendingOperation(a, op)
242
+ pendingOperations: a.pendingOperations.filter(op =>
243
+ shouldRetainPendingOperation(a, op),
250
244
  ),
251
245
  });
252
246
 
@@ -271,7 +265,7 @@ export const makeSync =
271
265
 
272
266
  // Use for withDevice
273
267
  export type DeviceCommunication = (
274
- deviceId: string
268
+ deviceId: string,
275
269
  ) => <T>(job: (transport: Transport) => Observable<T>) => Observable<T>;
276
270
 
277
271
  const defaultIterateResultBuilder = (getAddressFn: Resolver) => () =>
@@ -304,7 +298,7 @@ const defaultIterateResultBuilder = (getAddressFn: Resolver) => () =>
304
298
  derivationsCache[freshAddressPath] = res;
305
299
  }
306
300
  return res as Result;
307
- }
301
+ },
308
302
  );
309
303
 
310
304
  export const makeScanAccounts =
@@ -320,266 +314,235 @@ export const makeScanAccounts =
320
314
  getAddressFn: Resolver;
321
315
  }): CurrencyBridge["scanAccounts"] =>
322
316
  ({ currency, deviceId, syncConfig }): Observable<ScanAccountEvent> =>
323
- deviceCommunication(deviceId)((transport) =>
324
- Observable.create(
325
- (o: Observer<{ type: "discovered"; account: Account }>) => {
326
- let finished = false;
317
+ deviceCommunication(deviceId)(transport =>
318
+ Observable.create((o: Observer<{ type: "discovered"; account: Account }>) => {
319
+ let finished = false;
327
320
 
328
- const unsubscribe = () => {
329
- finished = true;
330
- };
321
+ const unsubscribe = () => {
322
+ finished = true;
323
+ };
331
324
 
332
- const derivationsCache: Record<string, Result> = {};
325
+ const derivationsCache: Record<string, Result> = {};
333
326
 
334
- async function stepAccount(
335
- index: number,
336
- res: Result,
337
- derivationMode: DerivationMode,
338
- seedIdentifier: string,
339
- transport: Transport
340
- ): Promise<Account | null | undefined> {
341
- if (finished) return;
327
+ async function stepAccount(
328
+ index: number,
329
+ res: Result,
330
+ derivationMode: DerivationMode,
331
+ seedIdentifier: string,
332
+ transport: Transport,
333
+ ): Promise<Account | null | undefined> {
334
+ if (finished) return;
342
335
 
343
- const { address, path: freshAddressPath, ...rest } = res;
336
+ const { address, path: freshAddressPath, ...rest } = res;
344
337
 
345
- const accountShape: Partial<Account> = await getAccountShape(
338
+ const accountShape: Partial<Account> = await getAccountShape(
339
+ {
340
+ transport,
341
+ currency,
342
+ index,
343
+ address,
344
+ derivationPath: freshAddressPath,
345
+ derivationMode,
346
+ rest,
347
+ },
348
+ syncConfig,
349
+ );
350
+ if (finished) return;
351
+
352
+ const freshAddress = address;
353
+ const operations = accountShape.operations || [];
354
+ const operationsCount = accountShape.operationsCount || operations.length;
355
+ const creationDate =
356
+ operations.length > 0 ? operations[operations.length - 1].date : new Date();
357
+ const balance = accountShape.balance || new BigNumber(0);
358
+ const spendableBalance = accountShape.spendableBalance || new BigNumber(0);
359
+ if (!accountShape.id) throw new Error("account ID must be provided");
360
+ if (balance.isNaN()) throw new Error("invalid balance NaN");
361
+ const initialAccount: Account = {
362
+ type: "Account",
363
+ id: accountShape.id,
364
+ seedIdentifier,
365
+ freshAddress,
366
+ freshAddressPath,
367
+ freshAddresses: [
346
368
  {
347
- transport,
348
- currency,
349
- index,
350
- address,
369
+ address: freshAddress,
351
370
  derivationPath: freshAddressPath,
352
- derivationMode,
353
- rest,
354
371
  },
355
- syncConfig
356
- );
357
- if (finished) return;
358
-
359
- const freshAddress = address;
360
- const operations = accountShape.operations || [];
361
- const operationsCount =
362
- accountShape.operationsCount || operations.length;
363
- const creationDate =
364
- operations.length > 0
365
- ? operations[operations.length - 1].date
366
- : new Date();
367
- const balance = accountShape.balance || new BigNumber(0);
368
- const spendableBalance =
369
- accountShape.spendableBalance || new BigNumber(0);
370
- if (!accountShape.id)
371
- throw new Error("account ID must be provided");
372
- if (balance.isNaN()) throw new Error("invalid balance NaN");
373
- const initialAccount: Account = {
374
- type: "Account",
375
- id: accountShape.id,
376
- seedIdentifier,
377
- freshAddress,
378
- freshAddressPath,
379
- freshAddresses: [
380
- {
381
- address: freshAddress,
382
- derivationPath: freshAddressPath,
383
- },
384
- ],
385
- derivationMode,
386
- name: "",
387
- starred: false,
388
- used: false,
389
- index,
390
- currency,
391
- operationsCount,
392
- operations: [],
393
- swapHistory: [],
394
- pendingOperations: [],
395
- unit: currency.units[0],
396
- lastSyncDate: new Date(),
397
- creationDate,
398
- // overrides
399
- balance,
400
- spendableBalance,
401
- blockHeight: 0,
402
- balanceHistoryCache: emptyHistoryCache,
403
- };
404
- const account = { ...initialAccount, ...accountShape };
405
-
406
- if (account.balanceHistoryCache === emptyHistoryCache) {
407
- account.balanceHistoryCache =
408
- generateHistoryFromOperations(account);
409
- }
372
+ ],
373
+ derivationMode,
374
+ name: "",
375
+ starred: false,
376
+ used: false,
377
+ index,
378
+ currency,
379
+ operationsCount,
380
+ operations: [],
381
+ swapHistory: [],
382
+ pendingOperations: [],
383
+ unit: currency.units[0],
384
+ lastSyncDate: new Date(),
385
+ creationDate,
386
+ // overrides
387
+ balance,
388
+ spendableBalance,
389
+ blockHeight: 0,
390
+ balanceHistoryCache: emptyHistoryCache,
391
+ };
392
+ const account = { ...initialAccount, ...accountShape };
410
393
 
411
- if (!account.used) {
412
- account.used = !isAccountEmpty(account);
413
- }
394
+ if (account.balanceHistoryCache === emptyHistoryCache) {
395
+ account.balanceHistoryCache = generateHistoryFromOperations(account);
396
+ }
414
397
 
415
- // Bitcoin needs to compute the freshAddressPath itself,
416
- // so we update it afterwards
417
- if (account?.freshAddressPath) {
418
- res.address = account.freshAddress;
419
- derivationsCache[account.freshAddressPath] = res;
420
- }
398
+ if (!account.used) {
399
+ account.used = !isAccountEmpty(account);
400
+ }
401
+
402
+ // Bitcoin needs to compute the freshAddressPath itself,
403
+ // so we update it afterwards
404
+ if (account?.freshAddressPath) {
405
+ res.address = account.freshAddress;
406
+ derivationsCache[account.freshAddressPath] = res;
407
+ }
408
+
409
+ log("scanAccounts", "derivationsCache", res);
421
410
 
422
- log("scanAccounts", "derivationsCache", res);
411
+ log(
412
+ "scanAccounts",
413
+ `scanning ${currency.id} at ${freshAddressPath}: ${res.address} resulted of ${
414
+ account ? `Account with ${account.operations.length} txs` : "no account"
415
+ }`,
416
+ );
417
+ if (!account) return;
418
+ account.name = !account.used
419
+ ? getNewAccountPlaceholderName({
420
+ currency,
421
+ index,
422
+ derivationMode,
423
+ })
424
+ : getAccountPlaceholderName({
425
+ currency,
426
+ index,
427
+ derivationMode,
428
+ });
429
+
430
+ const showNewAccount = shouldShowNewAccount(currency, derivationMode);
423
431
 
432
+ if (account.used || showNewAccount) {
424
433
  log(
425
- "scanAccounts",
426
- `scanning ${currency.id} at ${freshAddressPath}: ${
427
- res.address
428
- } resulted of ${
429
- account
430
- ? `Account with ${account.operations.length} txs`
431
- : "no account"
432
- }`
434
+ "debug",
435
+ `Emit 'discovered' event for a new account found. AccountUsed: ${account.used} - showNewAccount: ${showNewAccount}`,
433
436
  );
434
- if (!account) return;
435
- account.name = !account.used
436
- ? getNewAccountPlaceholderName({
437
- currency,
438
- index,
439
- derivationMode,
440
- })
441
- : getAccountPlaceholderName({
442
- currency,
443
- index,
444
- derivationMode,
445
- });
437
+ o.next({
438
+ type: "discovered",
439
+ account,
440
+ });
441
+ }
446
442
 
447
- const showNewAccount = shouldShowNewAccount(
448
- currency,
449
- derivationMode
450
- );
443
+ return account;
444
+ }
451
445
 
452
- if (account.used || showNewAccount) {
453
- log(
454
- "debug",
455
- `Emit 'discovered' event for a new account found. AccountUsed: ${account.used} - showNewAccount: ${showNewAccount}`
456
- );
457
- o.next({
458
- type: "discovered",
459
- account,
460
- });
461
- }
446
+ if (buildIterateResult === undefined) {
447
+ buildIterateResult = defaultIterateResultBuilder(getAddressFn);
448
+ }
462
449
 
463
- return account;
464
- }
450
+ async function main() {
451
+ try {
452
+ const derivationModes = getDerivationModesForCurrency(currency);
465
453
 
466
- if (buildIterateResult === undefined) {
467
- buildIterateResult = defaultIterateResultBuilder(getAddressFn);
468
- }
454
+ for (const derivationMode of derivationModes) {
455
+ if (finished) break;
456
+ const path = getSeedIdentifierDerivation(currency, derivationMode);
457
+ log("scanAccounts", `scanning ${currency.id} on derivationMode=${derivationMode}`);
458
+ let result: Result = derivationsCache[path];
469
459
 
470
- async function main() {
471
- try {
472
- const derivationModes = getDerivationModesForCurrency(currency);
460
+ if (!result) {
461
+ try {
462
+ result = await getAddressFn(transport, {
463
+ currency,
464
+ path,
465
+ derivationMode,
466
+ });
473
467
 
474
- for (const derivationMode of derivationModes) {
475
- if (finished) break;
476
- const path = getSeedIdentifierDerivation(
477
- currency,
478
- derivationMode
479
- );
480
- log(
481
- "scanAccounts",
482
- `scanning ${currency.id} on derivationMode=${derivationMode}`
483
- );
484
- let result: Result = derivationsCache[path];
485
-
486
- if (!result) {
487
- try {
488
- result = await getAddressFn(transport, {
489
- currency,
490
- path,
491
- derivationMode,
492
- });
493
-
494
- derivationsCache[path] = result;
495
- } catch (e) {
496
- if (e instanceof UnsupportedDerivation) {
497
- log(
498
- "scanAccounts",
499
- "ignore derivationMode=" + derivationMode
500
- );
501
- continue;
502
- }
503
- throw e;
468
+ derivationsCache[path] = result;
469
+ } catch (e) {
470
+ if (e instanceof UnsupportedDerivation) {
471
+ log("scanAccounts", "ignore derivationMode=" + derivationMode);
472
+ continue;
504
473
  }
474
+ throw e;
505
475
  }
476
+ }
506
477
 
507
- if (!result) continue;
508
- const seedIdentifier = result.publicKey;
509
- let emptyCount = 0;
510
- const mandatoryEmptyAccountSkip =
511
- getMandatoryEmptyAccountSkip(derivationMode);
512
- const derivationScheme = getDerivationScheme({
513
- derivationMode,
514
- currency,
515
- });
478
+ if (!result) continue;
479
+ const seedIdentifier = result.publicKey;
480
+ let emptyCount = 0;
481
+ const mandatoryEmptyAccountSkip = getMandatoryEmptyAccountSkip(derivationMode);
482
+ const derivationScheme = getDerivationScheme({
483
+ derivationMode,
484
+ currency,
485
+ });
516
486
 
517
- const stopAt = isIterableDerivationMode(derivationMode)
518
- ? 255
519
- : 1;
520
- const startsAt = getDerivationModeStartsAt(derivationMode);
487
+ const stopAt = isIterableDerivationMode(derivationMode) ? 255 : 1;
488
+ const startsAt = getDerivationModeStartsAt(derivationMode);
521
489
 
522
- log(
523
- "debug",
524
- `start scanning account process. MandatoryEmptyAccountSkip ${mandatoryEmptyAccountSkip} / StartsAt: ${startsAt} - StopAt: ${stopAt}`
525
- );
490
+ log(
491
+ "debug",
492
+ `start scanning account process. MandatoryEmptyAccountSkip ${mandatoryEmptyAccountSkip} / StartsAt: ${startsAt} - StopAt: ${stopAt}`,
493
+ );
526
494
 
527
- const iterateResult = await buildIterateResult!({
528
- result,
529
- derivationMode,
530
- derivationScheme,
531
- });
495
+ const iterateResult = await buildIterateResult!({
496
+ result,
497
+ derivationMode,
498
+ derivationScheme,
499
+ });
532
500
 
533
- for (let index = startsAt; index < stopAt; index++) {
534
- log("debug", `start to scan a new account. Index: ${index}`);
501
+ for (let index = startsAt; index < stopAt; index++) {
502
+ log("debug", `start to scan a new account. Index: ${index}`);
535
503
 
536
- if (finished) {
537
- log(
538
- "debug",
539
- `new account scanning process has been finished`
540
- );
541
- break;
542
- }
504
+ if (finished) {
505
+ log("debug", `new account scanning process has been finished`);
506
+ break;
507
+ }
543
508
 
544
- if (!derivationModeSupportsIndex(derivationMode, index))
545
- continue;
509
+ if (!derivationModeSupportsIndex(derivationMode, index)) continue;
546
510
 
547
- const res = await iterateResult({
548
- transport,
549
- index,
550
- derivationsCache,
551
- derivationMode,
552
- derivationScheme,
553
- currency,
554
- });
511
+ const res = await iterateResult({
512
+ transport,
513
+ index,
514
+ derivationsCache,
515
+ derivationMode,
516
+ derivationScheme,
517
+ currency,
518
+ });
555
519
 
556
- if (!res) break;
520
+ if (!res) break;
557
521
 
558
- const account = await stepAccount(
559
- index,
560
- res,
561
- derivationMode,
562
- seedIdentifier,
563
- transport
564
- );
522
+ const account = await stepAccount(
523
+ index,
524
+ res,
525
+ derivationMode,
526
+ seedIdentifier,
527
+ transport,
528
+ );
565
529
 
566
- if (account && !account.used) {
567
- if (emptyCount >= mandatoryEmptyAccountSkip) break;
568
- emptyCount++;
569
- }
530
+ if (account && !account.used) {
531
+ if (emptyCount >= mandatoryEmptyAccountSkip) break;
532
+ emptyCount++;
570
533
  }
571
534
  }
572
-
573
- o.complete();
574
- } catch (e) {
575
- o.error(e);
576
535
  }
577
- }
578
536
 
579
- main();
580
- return unsubscribe;
537
+ o.complete();
538
+ } catch (e) {
539
+ o.error(e);
540
+ }
581
541
  }
582
- )
542
+
543
+ main();
544
+ return unsubscribe;
545
+ }),
583
546
  );
584
547
  export function makeAccountBridgeReceive(
585
548
  getAddressFn: Resolver,
@@ -588,7 +551,7 @@ export function makeAccountBridgeReceive(
588
551
  injectGetAddressParams,
589
552
  }: {
590
553
  injectGetAddressParams?: (account: Account) => any;
591
- } = {}
554
+ } = {},
592
555
  ): (
593
556
  account: Account,
594
557
  option: {
@@ -596,7 +559,7 @@ export function makeAccountBridgeReceive(
596
559
  deviceId: string;
597
560
  subAccountId?: string;
598
561
  freshAddressIndex?: number;
599
- }
562
+ },
600
563
  ) => Observable<{
601
564
  address: string;
602
565
  path: string;
@@ -616,30 +579,23 @@ export function makeAccountBridgeReceive(
616
579
  verify,
617
580
  currency: account.currency,
618
581
  derivationMode: account.derivationMode,
619
- path: freshAddress
620
- ? freshAddress.derivationPath
621
- : account.freshAddressPath,
582
+ path: freshAddress ? freshAddress.derivationPath : account.freshAddressPath,
622
583
  ...(injectGetAddressParams && injectGetAddressParams(account)),
623
584
  };
624
585
  return deviceCommunication(deviceId)((transport: Transport) =>
625
586
  from(
626
- getAddressFn(transport, arg).then((r) => {
627
- const accountAddress = freshAddress
628
- ? freshAddress.address
629
- : account.freshAddress;
587
+ getAddressFn(transport, arg).then(r => {
588
+ const accountAddress = freshAddress ? freshAddress.address : account.freshAddress;
630
589
 
631
590
  if (r.address !== accountAddress) {
632
- throw new WrongDeviceForAccount(
633
- `WrongDeviceForAccount ${account.name}`,
634
- {
635
- accountName: account.name,
636
- }
637
- );
591
+ throw new WrongDeviceForAccount(`WrongDeviceForAccount ${account.name}`, {
592
+ accountName: account.name,
593
+ });
638
594
  }
639
595
 
640
596
  return r;
641
- })
642
- )
597
+ }),
598
+ ),
643
599
  );
644
600
  };
645
601
  }
package/src/cache.ts CHANGED
@@ -15,20 +15,20 @@ export type CacheRes<A extends Array<any>, T> = {
15
15
  export type LRUCacheFn = <A extends Array<any>, T>(
16
16
  f: (...args: A) => Promise<T>,
17
17
  keyExtractor?: (...args: A) => string,
18
- lruOpts?: LRU.Options<string, any>
18
+ lruOpts?: LRU.Options<string, any>,
19
19
  ) => CacheRes<A, T>;
20
20
 
21
21
  export const makeNoCache: LRUCacheFn = <A extends Array<any>, T>(
22
- f: (...args: A) => Promise<T>
22
+ f: (...args: A) => Promise<T>,
23
23
  ): CacheRes<A, T> => {
24
24
  const result = (...args: A) => {
25
- return f(...args).catch((e) => {
25
+ return f(...args).catch(e => {
26
26
  throw e;
27
27
  });
28
28
  };
29
29
 
30
30
  result.force = (...args: A) => {
31
- return f(...args).catch((e) => {
31
+ return f(...args).catch(e => {
32
32
  throw e;
33
33
  });
34
34
  };