Skip to content

Commit 5cae3b4

Browse files
committed
fix: align extension storage 'set' and 'observeAll' with pouchdb storage behavior
deleting a wallet does: 1. delete it from repository 2. check remaining wallets, activate if some wallet exists there was a bug where step 2. would find the wallet that was just deleted and try to activate it, because extension storage 'observeAll' emits an slightly later
1 parent 9990c88 commit 5cae3b4

File tree

1 file changed

+25
-9
lines changed

1 file changed

+25
-9
lines changed

apps/browser-extension-wallet/src/lib/scripts/background/storage/extension-document-store.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
/* eslint-disable @typescript-eslint/ban-types */
22
import { storage as sdkStorage } from '@cardano-sdk/wallet';
3-
import { EMPTY, filter, from, map, mergeMap, Observable, of, share } from 'rxjs';
3+
import { EMPTY, filter, from, map, mergeMap, Observable, of, share, firstValueFrom } from 'rxjs';
44
import { Logger } from 'ts-log';
55
import { contextLogger, fromSerializableObject, toSerializableObject } from '@cardano-sdk/util';
66
import { ExtensionStore } from './extension-store';
7+
import isEqual from 'lodash/isEqual';
78

89
export type DocumentChange<T> = {
910
oldValue?: T;
1011
newValue?: T;
1112
};
1213

13-
const undefinedIfEmpty = <T>(value: T | undefined): T | undefined => {
14-
if (typeof value === 'object' && (value === null || Object.keys(value).length === 0)) return undefined;
14+
const undefinedIfEmptyObj = <T>(value: T | undefined): T | undefined => {
15+
if (typeof value === 'object' && !Array.isArray(value) && (value === null || Object.keys(value).length === 0))
16+
return undefined;
1517
// eslint-disable-next-line consistent-return
1618
return value;
1719
};
@@ -34,8 +36,8 @@ export class ExtensionDocumentStore<T extends {}> extends ExtensionStore impleme
3436
filter(({ key }) => key === docId),
3537
map(
3638
({ change }): DocumentChange<T> => ({
37-
oldValue: undefinedIfEmpty(change.oldValue),
38-
newValue: undefinedIfEmpty(change.newValue)
39+
oldValue: undefinedIfEmptyObj(change.oldValue),
40+
newValue: undefinedIfEmptyObj(change.newValue)
3941
})
4042
),
4143
share()
@@ -55,11 +57,25 @@ export class ExtensionDocumentStore<T extends {}> extends ExtensionStore impleme
5557
set(doc: T): Observable<void> {
5658
this.logger.debug('set', doc);
5759
return from(
58-
(this.idle = this.idle.then(() =>
59-
this.storage.set({
60+
(this.idle = this.idle.then(async () => {
61+
const previousValueMap = await this.storage.get(this.docId);
62+
const previousValue = fromSerializableObject(previousValueMap[this.docId]);
63+
if (isEqual(previousValue, doc)) {
64+
// if values are equal, then we would set to the same value and
65+
// this.documentChange$ won't emit and this promise will never resolve
66+
return;
67+
}
68+
69+
const storageChange = firstValueFrom(this.documentChange$);
70+
await this.storage.set({
6071
[this.docId]: toSerializableObject(doc)
61-
})
62-
))
72+
});
73+
// do not emit until documentChange$ emits
74+
// in order to avoid race conditions:
75+
// users expect `observeAll` to emit new value when subscribing
76+
// to it immediatelly after `set` emits
77+
await storageChange;
78+
}))
6379
);
6480
}
6581

0 commit comments

Comments
 (0)