-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Expand file tree
/
Copy pathsetup-initial-state-hooks.js
More file actions
112 lines (105 loc) · 4.21 KB
/
setup-initial-state-hooks.js
File metadata and controls
112 lines (105 loc) · 4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app';
import { getEnvironmentType } from '../../../shared/lib/environment-type';
import { getManifestFlags } from '../../../shared/lib/manifestFlags';
import { maskObject } from '../../../shared/lib/object.utils';
import ExtensionPlatform from '../platforms/extension';
import { SENTRY_BACKGROUND_STATE } from '../constants/sentry-state';
import { FixtureExtensionStore } from './stores/fixture-extension-store';
import ExtensionStore from './stores/extension-store';
import { PersistenceManager } from './stores/persistence-manager';
const platform = new ExtensionPlatform();
const useFixtureStore =
process.env.IN_TEST &&
getManifestFlags().testing?.forceExtensionStore !== true;
let isBackground = false;
if (useFixtureStore) {
// Use globalThis.self (not window) so this works in both the UI and the background/service worker, where window is undefined.
const locationHref = globalThis.self?.location?.href;
if (!locationHref) {
throw new Error(
'setup-initial-state-hooks: globalThis.self?.location?.href is not defined; expected to run in a document or service worker context.',
);
}
isBackground =
getEnvironmentType(locationHref) === ENVIRONMENT_TYPE_BACKGROUND;
}
const localStore = useFixtureStore
? new FixtureExtensionStore({ initialize: isBackground })
: new ExtensionStore();
// Single PersistenceManager per context: one in background, one per UI context.
export const persistenceManager = new PersistenceManager({ localStore });
/**
* Get the persisted wallet state.
*
* @returns The persisted wallet state.
*/
globalThis.stateHooks.getPersistedState = async function () {
return await persistenceManager.get({ validateVault: false });
};
/**
* Get the backup state from IndexedDB.
* This is used as a fallback when primary storage is unavailable.
*
* @returns The backup state, or null if unavailable.
*/
globalThis.stateHooks.getBackupState = async function () {
return await persistenceManager.getBackup();
};
const persistedStateMask = {
data: SENTRY_BACKGROUND_STATE,
meta: {
storageKind: true,
version: true,
},
};
/**
* Get a state snapshot for Sentry. This is used to add additional context to
* error reports, and it's used when processing errors and breadcrumbs to
* determine whether the user has opted into Metametrics.
*
* This uses the persisted state pre-initialization, and the in-memory state
* post-initialization. In both cases the state is anonymized.
*
* @returns A Sentry state snapshot.
*/
globalThis.stateHooks.getSentryState = function () {
const sentryState = {
browser: window.navigator.userAgent,
// we use the manifest.json version from getVersion and not
// `process.env.METAMASK_VERSION` as they can be different (see `getVersion`
// for more info)
version: platform.getVersion(),
};
// If `getSentryAppState` is set, it implies that initialization has completed
if (globalThis.stateHooks.getSentryAppState) {
persistenceManager.cleanUpMostRecentRetrievedState();
return {
...sentryState,
state: globalThis.stateHooks.getSentryAppState(),
};
} else if (
// This is truthy if Sentry has retrieved state at least once already. This
// should always be true when getting context for an error report, but can
// be unset when Sentry is performing the opt-in check.
persistenceManager.mostRecentRetrievedState ||
// This is only set in the background process.
globalThis.stateHooks.getMostRecentPersistedState
) {
const persistedState =
persistenceManager.mostRecentRetrievedState ||
globalThis.stateHooks.getMostRecentPersistedState();
// This can be unset when this method is called in the background for an
// opt-in check, but the state hasn't been loaded yet.
if (persistedState) {
return {
...sentryState,
persistedState: maskObject(persistedState, persistedStateMask),
};
}
}
// This branch means that local storage has not yet been read, so we have
// no choice but to omit the application state.
// This should be unreachable when getting context for an error report, but
// can be false when Sentry is performing the opt-in check.
return sentryState;
};