@exodus/headless 2.0.0-alpha.2 → 2.0.0-alpha.21
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.
- package/CHANGELOG.md +159 -0
- package/README.md +146 -20
- package/package.json +41 -13
- package/src/api.js +86 -3
- package/src/application.js +50 -40
- package/src/atoms/attach.js +40 -0
- package/src/constants.js +12 -0
- package/src/dependencies/atom-collections.js +25 -0
- package/src/dependencies/atoms.js +125 -1
- package/src/dependencies/index.js +15 -0
- package/src/dependencies/modules.js +98 -7
- package/src/dependencies/monitors.js +35 -0
- package/src/dependencies/plugins.js +7 -0
- package/src/index.js +88 -4
- package/src/ioc.js +15 -1
- package/src/plugins/attach.js +19 -0
- package/src/plugins/index.js +3 -0
- package/src/plugins/log-lifecycle.js +25 -0
- package/src/unlock-encrypted-storage.js +19 -0
- package/src/utils/blockchain-metadata.js +11 -0
package/src/index.js
CHANGED
|
@@ -1,35 +1,119 @@
|
|
|
1
|
+
import { pick } from '@exodus/basic-utils'
|
|
1
2
|
import createIOC from './ioc'
|
|
2
3
|
import createApi from './api'
|
|
4
|
+
import { createLoadWalletAccountsHandler } from './utils/blockchain-metadata'
|
|
5
|
+
|
|
6
|
+
import attachPlugins from './plugins/attach'
|
|
7
|
+
import attachAtoms from './atoms/attach'
|
|
8
|
+
import { atomsToAttach } from './constants'
|
|
3
9
|
|
|
4
10
|
const createExodus = ({ adapters, config, port }) => {
|
|
5
11
|
const ioc = createIOC({ adapters, config })
|
|
12
|
+
const { headless: headlessConfig } = config
|
|
6
13
|
|
|
7
14
|
const resolve = () => {
|
|
8
15
|
ioc.resolve()
|
|
9
16
|
|
|
10
|
-
const { assetsModule } = ioc.getByType('adapter')
|
|
17
|
+
const { assetsModule, storage } = ioc.getByType('adapter')
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
application,
|
|
21
|
+
blockchainMetadata,
|
|
22
|
+
enabledAssets,
|
|
23
|
+
featureFlags,
|
|
24
|
+
kyc,
|
|
25
|
+
referrals,
|
|
26
|
+
remoteConfig,
|
|
27
|
+
unlockEncryptedStorage,
|
|
28
|
+
walletAccounts,
|
|
29
|
+
} = ioc.getByType('module')
|
|
30
|
+
|
|
31
|
+
const { geolocationMonitor, marketHistory, ratesMonitor } = ioc.getByType('monitor')
|
|
32
|
+
|
|
33
|
+
const { featureFlagAtoms } = ioc.getByType('atom-collection')
|
|
34
|
+
|
|
35
|
+
const handleLoadWalletAccounts = createLoadWalletAccountsHandler({
|
|
36
|
+
blockchainMetadata,
|
|
37
|
+
port,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
blockchainMetadata.on('load-wallet-accounts', handleLoadWalletAccounts)
|
|
41
|
+
blockchainMetadata.on('tx-logs-update', (payload) => port.emit('tx-logs-update', payload))
|
|
42
|
+
blockchainMetadata.on('account-states-update', (payload) =>
|
|
43
|
+
port.emit('account-states-update', payload)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
remoteConfig.on('sync', ({ current }) => port.emit('remote-config', current))
|
|
11
47
|
|
|
12
|
-
|
|
48
|
+
// TODO: migrate to marketHistoryAtom. Will be easier once it's on headless
|
|
49
|
+
marketHistory.on('market-history', (payload) => port.emit('market-history', payload))
|
|
50
|
+
|
|
51
|
+
// TODO: migrate to ratesAtom. Will be easier once it's on headless
|
|
52
|
+
ratesMonitor.on('rates', (payload) => port.emit('rates', payload))
|
|
13
53
|
|
|
14
54
|
application.hook('start', () => {
|
|
55
|
+
remoteConfig.load()
|
|
56
|
+
featureFlags.load()
|
|
57
|
+
|
|
15
58
|
port.emit('start')
|
|
16
59
|
})
|
|
17
60
|
|
|
18
61
|
application.hook('unlock', async () => {
|
|
62
|
+
if (typeof storage.unlock === 'function') unlockEncryptedStorage(storage)
|
|
63
|
+
|
|
64
|
+
remoteConfig.sync()
|
|
65
|
+
marketHistory.start()
|
|
66
|
+
ratesMonitor.start()
|
|
67
|
+
geolocationMonitor.start()
|
|
68
|
+
|
|
19
69
|
await assetsModule.load()
|
|
70
|
+
await walletAccounts.load()
|
|
71
|
+
await Promise.all([
|
|
72
|
+
//
|
|
73
|
+
blockchainMetadata.load(),
|
|
74
|
+
enabledAssets.load(),
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
featureFlagAtoms.referrals?.get().then(({ isOn }) => {
|
|
78
|
+
if (!isOn) return
|
|
79
|
+
kyc.load()
|
|
80
|
+
referrals.load()
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
application.on('unlock', () => {
|
|
85
|
+
port.emit('unlock')
|
|
20
86
|
})
|
|
21
87
|
|
|
22
88
|
application.hook('clear', async () => {
|
|
23
|
-
await Promise.all([
|
|
89
|
+
await Promise.all([
|
|
90
|
+
//
|
|
91
|
+
assetsModule.clear(),
|
|
92
|
+
walletAccounts.clear(),
|
|
93
|
+
blockchainMetadata.clear(),
|
|
94
|
+
enabledAssets.clear(),
|
|
95
|
+
])
|
|
96
|
+
|
|
97
|
+
port.emit('clear')
|
|
24
98
|
})
|
|
25
99
|
|
|
26
100
|
application.on('restart', (payload) => {
|
|
27
101
|
port.emit('restart', payload)
|
|
28
102
|
})
|
|
29
103
|
|
|
104
|
+
attachAtoms({
|
|
105
|
+
port,
|
|
106
|
+
application,
|
|
107
|
+
logger: ioc.get('createLogger')('attachAtoms'),
|
|
108
|
+
atoms: pick(ioc.getByType('atom'), atomsToAttach),
|
|
109
|
+
lifecycleEvents: headlessConfig?.attachAtomsLifecycleEvents,
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
attachPlugins({ application, plugins: ioc.getByType('plugin') })
|
|
113
|
+
|
|
30
114
|
application.start()
|
|
31
115
|
|
|
32
|
-
return createApi({ ioc })
|
|
116
|
+
return createApi({ ioc, port })
|
|
33
117
|
}
|
|
34
118
|
|
|
35
119
|
return { ...ioc, resolve }
|
package/src/ioc.js
CHANGED
|
@@ -3,15 +3,29 @@ import preprocess from '@exodus/dependency-preprocessors'
|
|
|
3
3
|
import alias from '@exodus/dependency-preprocessors/src/preprocessors/alias'
|
|
4
4
|
import logify from '@exodus/dependency-preprocessors/src/preprocessors/logify'
|
|
5
5
|
import namespaceConfig from '@exodus/dependency-preprocessors/src/preprocessors/namespace-config'
|
|
6
|
+
import namespaceStorage from '@exodus/dependency-preprocessors/src/preprocessors/namespace-storage'
|
|
7
|
+
import readOnlyAtoms from '@exodus/dependency-preprocessors/src/preprocessors/read-only-atoms'
|
|
6
8
|
|
|
7
9
|
import createDependencies from './dependencies'
|
|
8
10
|
|
|
9
11
|
const createIOC = ({ adapters, config }) => {
|
|
10
12
|
const { createLogger } = adapters
|
|
13
|
+
const { readOnlyAtoms: readOnlyAtomsConfig } = config.ioc ?? {}
|
|
11
14
|
|
|
12
15
|
const logger = createLogger('exodus:ioc')
|
|
13
16
|
const dependencies = createDependencies({ adapters, config })
|
|
14
|
-
const preprocessors = [
|
|
17
|
+
const preprocessors = [
|
|
18
|
+
logify({ createLogger }),
|
|
19
|
+
namespaceConfig(),
|
|
20
|
+
alias(),
|
|
21
|
+
// NOTE: order matters, this should come after `alias`
|
|
22
|
+
namespaceStorage(),
|
|
23
|
+
readOnlyAtoms({
|
|
24
|
+
logger: createLogger('exodus:read-only-atoms'),
|
|
25
|
+
warn: true,
|
|
26
|
+
...readOnlyAtomsConfig,
|
|
27
|
+
}),
|
|
28
|
+
]
|
|
15
29
|
const definitions = preprocess({ dependencies, preprocessors })
|
|
16
30
|
const ioc = createIocContainer({ logger })
|
|
17
31
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { kebabCase, memoize } from 'lodash'
|
|
2
|
+
|
|
3
|
+
// e.g. onUnlock -> unlock -> onUnlock, onChangePassphrase -> change-passphrase
|
|
4
|
+
const getApplicationHookName = memoize((lifecycleMethod) =>
|
|
5
|
+
kebabCase(lifecycleMethod.replace(/^on/, ''))
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
const attachPlugins = ({ plugins, application }) => {
|
|
9
|
+
Object.entries(plugins).forEach(([name, lifecycleMethods]) => {
|
|
10
|
+
const entries = Object.entries(lifecycleMethods || {})
|
|
11
|
+
|
|
12
|
+
for (const [lifecycleMethod, fn] of entries) {
|
|
13
|
+
const hookName = getApplicationHookName(lifecycleMethod)
|
|
14
|
+
application.hook(hookName, fn)
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default attachPlugins
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const logLifecycle = {
|
|
2
|
+
id: 'logLifecyclePlugin',
|
|
3
|
+
type: 'plugin',
|
|
4
|
+
factory: ({ logger }) => {
|
|
5
|
+
return {
|
|
6
|
+
onLock: () => logger.debug('onLock'),
|
|
7
|
+
onUnlock: () => logger.debug('onUnlock'),
|
|
8
|
+
onClear: () => logger.debug('onClear'),
|
|
9
|
+
onImport: () => logger.debug('onImport'),
|
|
10
|
+
onMigrate: () => logger.debug('onMigrate'),
|
|
11
|
+
onStart: () => logger.debug('onStart'),
|
|
12
|
+
onLoad: () => logger.debug('onLoad'),
|
|
13
|
+
onUnload: () => logger.debug('onUnload'),
|
|
14
|
+
onCreate: () => logger.debug('onCreate'),
|
|
15
|
+
onBackup: () => logger.debug('onBackup'),
|
|
16
|
+
onRestore: () => logger.debug('onRestore'),
|
|
17
|
+
onRestoreCompleted: () => logger.debug('onRestoreCompleted'),
|
|
18
|
+
onAssetsSynced: () => logger.debug('onAssetsSynced'),
|
|
19
|
+
onChangePassphrase: () => logger.debug('onChangePassphrase'),
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
dependencies: ['logger'],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default logLifecycle
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EXODUS_KEY_IDS } from '@exodus/keychain/module'
|
|
2
|
+
|
|
3
|
+
const createUnlockEncryptedStorage = ({ keychain }) => {
|
|
4
|
+
return async (encryptedStorage) => {
|
|
5
|
+
// should the key id be part of a `config` dep?
|
|
6
|
+
const sodiumEncryptor = keychain.createSodiumEncryptor(EXODUS_KEY_IDS.WALLET_INFO)
|
|
7
|
+
|
|
8
|
+
await encryptedStorage.unlock({
|
|
9
|
+
encrypt: (data) => sodiumEncryptor.encryptSecretBox({ data }),
|
|
10
|
+
decrypt: (data) => sodiumEncryptor.decryptSecretBox({ data }),
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
id: 'unlockEncryptedStorage',
|
|
17
|
+
factory: createUnlockEncryptedStorage,
|
|
18
|
+
dependencies: ['keychain'],
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function createLoadWalletAccountsHandler({ port, blockchainMetadata }) {
|
|
2
|
+
return async () => {
|
|
3
|
+
const [txLogs, accountStates] = await Promise.all([
|
|
4
|
+
blockchainMetadata.getLoadedTxLogs(),
|
|
5
|
+
blockchainMetadata.getLoadedAccountStates(),
|
|
6
|
+
])
|
|
7
|
+
|
|
8
|
+
port.emit('tx-logs', txLogs)
|
|
9
|
+
port.emit('account-states', accountStates)
|
|
10
|
+
}
|
|
11
|
+
}
|