@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/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
- const { application } = ioc.getByType('module')
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([assetsModule.clear()])
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 = [logify({ createLogger }), namespaceConfig(), alias()]
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,3 @@
1
+ import logLifecyclePlugin from './log-lifecycle'
2
+
3
+ export default [logLifecyclePlugin]
@@ -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
+ }