@exodus/headless 2.4.0 → 3.1.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [3.1.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@3.0.0...@exodus/headless@3.1.0) (2024-01-27)
7
+
8
+ ### Features
9
+
10
+ - catch assets synced hook ([#5537](https://github.com/ExodusMovement/exodus-hydra/issues/5537)) ([b811d8d](https://github.com/ExodusMovement/exodus-hydra/commit/b811d8de338ae2c10b2900c68b15e931b6a8e740))
11
+ - **geolocation:** update handler to use v3 with App-Name and App-Version ([#5529](https://github.com/ExodusMovement/exodus-hydra/issues/5529)) ([2a12c3e](https://github.com/ExodusMovement/exodus-hydra/commit/2a12c3e8568af4cdf689815ec7e70d2580ae9a6c))
12
+
13
+ ## [3.0.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.4.0...@exodus/headless@3.0.0) (2024-01-25)
14
+
15
+ ### ⚠ BREAKING CHANGES
16
+
17
+ - make wallet application agnostic (#5469)
18
+
19
+ ### Features
20
+
21
+ - make wallet application agnostic ([#5469](https://github.com/ExodusMovement/exodus-hydra/issues/5469)) ([5edce20](https://github.com/ExodusMovement/exodus-hydra/commit/5edce206e12d35a6acdccd597bc52352772ed9c3))
22
+
6
23
  ## [2.4.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.3.0...@exodus/headless@2.4.0) (2024-01-24)
7
24
 
8
25
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/headless",
3
- "version": "2.4.0",
3
+ "version": "3.1.0",
4
4
  "description": "The platform-agnostic Exodus wallet SDK",
5
5
  "author": "Exodus Movement Inc.",
6
6
  "main": "src/index.js",
@@ -26,7 +26,7 @@
26
26
  "test": "NODE_OPTIONS=--max-old-space-size=4096 jest"
27
27
  },
28
28
  "dependencies": {
29
- "@exodus/address-provider": "^9.0.1",
29
+ "@exodus/address-provider": "^9.2.0",
30
30
  "@exodus/assets-feature": "^4.0.1",
31
31
  "@exodus/atoms": "^7.0.0",
32
32
  "@exodus/available-assets": "^8.0.0",
@@ -40,7 +40,8 @@
40
40
  "@exodus/fee-data-monitors": "^3.0.0",
41
41
  "@exodus/fetch": "^1.2.1",
42
42
  "@exodus/filesystem": "^1.1.0",
43
- "@exodus/geolocation": "^4.0.0",
43
+ "@exodus/fusion-atoms": "^1.1.2",
44
+ "@exodus/geolocation": "^4.1.0",
44
45
  "@exodus/hd-key-slip-10": "^2.0.0",
45
46
  "@exodus/key-identifier-provider": "^1.4.0",
46
47
  "@exodus/keychain": "^4.3.0",
@@ -54,7 +55,7 @@
54
55
  "@exodus/sodium-crypto": "^3.2.0",
55
56
  "@exodus/startup-counter": "^1.0.0",
56
57
  "@exodus/tx-signer": "^1.1.0",
57
- "@exodus/wallet": "^10.3.0",
58
+ "@exodus/wallet": "^11.0.0",
58
59
  "@exodus/wallet-accounts": "^15.0.0",
59
60
  "@exodus/wallet-compatibility-modes": "^3.2.0",
60
61
  "bip39": "^2.6.0",
@@ -66,7 +67,7 @@
66
67
  "@exodus/ab-testing": "^7.3.0",
67
68
  "@exodus/algorand-lib": "^2.0.1",
68
69
  "@exodus/algorand-meta": "^1.1.4",
69
- "@exodus/analytics": "^12.0.0",
70
+ "@exodus/analytics": "^12.0.1",
70
71
  "@exodus/apy-rates": "^3.3.1",
71
72
  "@exodus/assets-feature": "workspace:^",
72
73
  "@exodus/bitcoin-plugin": "^1.0.14",
@@ -101,5 +102,5 @@
101
102
  "msw": "^2.0.0",
102
103
  "p-defer": "^4.0.0"
103
104
  },
104
- "gitHead": "bc598a9f55c95dabe5dffb4c3e710d81817a3a0e"
105
+ "gitHead": "38053d333d27638496b513254340e94a230d86fc"
105
106
  }
@@ -0,0 +1,9 @@
1
+ import { createStorageAtomFactory } from '@exodus/atoms'
2
+
3
+ const createBackedUpAtom = ({ storage }) => {
4
+ const atomFactory = createStorageAtomFactory({ storage })
5
+
6
+ return atomFactory({ key: 'backedUp', defaultValue: false, isSoleWriter: true })
7
+ }
8
+
9
+ export default createBackedUpAtom
@@ -0,0 +1,4 @@
1
+ import { createFusionAtom } from '@exodus/fusion-atoms'
2
+
3
+ export const createWalletCreatedAtAtom = ({ fusion, logger }) =>
4
+ createFusionAtom({ fusion, logger, path: 'createdAt', defaultValue: new Date().toISOString() })
@@ -0,0 +1,40 @@
1
+ import createBackedUpAtom from './backed-up'
2
+ import { createWalletCreatedAtAtom } from './created-at'
3
+ import createLockHistoryAtom from './lock-history'
4
+ import createdLockedAtom from './locked'
5
+ import createRestoreAtom from './restore'
6
+
7
+ export const lockedAtomDefinition = {
8
+ id: 'lockedAtom',
9
+ type: 'atom',
10
+ factory: createdLockedAtom,
11
+ dependencies: [],
12
+ }
13
+
14
+ export const lockHistoryAtomDefinition = {
15
+ id: 'lockHistoryAtom',
16
+ type: 'atom',
17
+ factory: createLockHistoryAtom,
18
+ dependencies: ['lockedAtom', 'config?'],
19
+ }
20
+
21
+ export const restoreAtomDefinition = {
22
+ id: 'restoreAtom',
23
+ type: 'atom',
24
+ factory: createRestoreAtom,
25
+ dependencies: [],
26
+ }
27
+
28
+ export const backedUpAtomDefinition = {
29
+ id: 'backedUpAtom',
30
+ type: 'atom',
31
+ factory: createBackedUpAtom,
32
+ dependencies: ['storage'],
33
+ }
34
+
35
+ export const walletCreatedAtAtomDefinition = {
36
+ id: 'walletCreatedAtAtom',
37
+ type: 'atom',
38
+ factory: createWalletCreatedAtAtom,
39
+ dependencies: ['fusion', 'logger'],
40
+ }
@@ -0,0 +1,15 @@
1
+ import { createInMemoryAtom, difference } from '@exodus/atoms'
2
+
3
+ const createLockHistoryAtom = ({ lockedAtom, config: { maxEntries = 10 } = {} }) => {
4
+ const lockHistory = createInMemoryAtom({ defaultValue: [] })
5
+
6
+ difference(lockedAtom).observe(async ({ current: locked, previous: previouslyLocked }) => {
7
+ await lockHistory.set((current) =>
8
+ [{ locked, timestamp: new Date() }, ...current].slice(0, maxEntries)
9
+ )
10
+ })
11
+
12
+ return lockHistory
13
+ }
14
+
15
+ export default createLockHistoryAtom
@@ -0,0 +1,5 @@
1
+ import { createInMemoryAtom } from '@exodus/atoms'
2
+
3
+ const createLockedAtom = () => createInMemoryAtom({ defaultValue: true })
4
+
5
+ export default createLockedAtom
@@ -0,0 +1,5 @@
1
+ import { createInMemoryAtom } from '@exodus/atoms'
2
+
3
+ const createRestoreAtom = () => createInMemoryAtom() // eslint-disable-line @exodus/hydra/in-memory-atom-default-value
4
+
5
+ export default createRestoreAtom
@@ -0,0 +1,30 @@
1
+ import {
2
+ backedUpAtomDefinition,
3
+ lockedAtomDefinition,
4
+ lockHistoryAtomDefinition,
5
+ restoreAtomDefinition,
6
+ walletCreatedAtAtomDefinition,
7
+ } from './atoms'
8
+ import applicationDefinition from './module'
9
+ import applicationLifecyclePluginDefinition from './plugins/lifecycle'
10
+
11
+ const application = () => {
12
+ return {
13
+ id: 'application',
14
+ definitions: [
15
+ { definition: applicationDefinition },
16
+ { definition: lockedAtomDefinition },
17
+ { definition: restoreAtomDefinition },
18
+ { definition: lockHistoryAtomDefinition },
19
+ { definition: walletCreatedAtAtomDefinition },
20
+ { definition: applicationLifecyclePluginDefinition },
21
+ {
22
+ definition: backedUpAtomDefinition,
23
+ storage: { namespace: 'wallet' },
24
+ aliases: [{ interfaceId: 'storage', implementationId: 'unsafeStorage' }],
25
+ },
26
+ ],
27
+ }
28
+ }
29
+
30
+ export default application
@@ -3,7 +3,7 @@
3
3
  import ExodusModule from '@exodus/module'
4
4
  import assert from 'minimalistic-assert'
5
5
 
6
- import { LifecycleHook as Hook } from './constants'
6
+ import { LifecycleHook as Hook } from '../constants'
7
7
 
8
8
  // Because we are forced to restart wallet after deleting/importing, we need to store certain flags to persist state between executions
9
9
 
@@ -33,14 +33,22 @@ class Application extends ExodusModule {
33
33
  #hooks = {}
34
34
  #wallet = null
35
35
  #storage = null
36
+ #backedUpAtom = null
36
37
  #passphraseCache = null
37
38
  #applicationStarted = null
38
39
  #resolveStart = null
39
40
 
40
- constructor({ wallet, unsafeStorage, passphraseCache = passphraseCachePlaceholder, logger }) {
41
+ constructor({
42
+ wallet,
43
+ unsafeStorage,
44
+ backedUpAtom,
45
+ passphraseCache = passphraseCachePlaceholder,
46
+ logger,
47
+ }) {
41
48
  super({ name: 'Application', logger })
42
49
 
43
50
  this.#wallet = wallet
51
+ this.#backedUpAtom = backedUpAtom
44
52
  this.#passphraseCache = passphraseCache
45
53
  this.#storage = unsafeStorage.namespace('flags')
46
54
 
@@ -72,7 +80,7 @@ class Application extends ExodusModule {
72
80
  const [hasPassphraseSet, isLocked, isBackedUp, isRestoring] = await Promise.all([
73
81
  this.#wallet.hasPassphraseSet(),
74
82
  this.#wallet.isLocked(),
75
- this.#wallet.isBackedUp(),
83
+ this.isBackedUp(),
76
84
  this.isRestoring(),
77
85
  ])
78
86
 
@@ -99,7 +107,7 @@ class Application extends ExodusModule {
99
107
  this.#wallet.exists(),
100
108
  this.#wallet.hasPassphraseSet(),
101
109
  this.#wallet.isLocked(),
102
- this.#wallet.isBackedUp(),
110
+ this.isBackedUp(),
103
111
  this.isRestoring(),
104
112
  ])
105
113
 
@@ -200,7 +208,6 @@ class Application extends ExodusModule {
200
208
  getMnemonic = async (opts) => this.#wallet.getMnemonic(opts)
201
209
 
202
210
  setBackedUp = async () => {
203
- await this.#wallet.setBackedUp()
204
211
  await this.fire(Hook.Backup)
205
212
  }
206
213
 
@@ -224,7 +231,9 @@ class Application extends ExodusModule {
224
231
  await this.fire(Hook.RestoreCompleted)
225
232
  }
226
233
 
227
- this.fire(Hook.AssetsSynced)
234
+ this.fire(Hook.AssetsSynced).catch((e) => {
235
+ console.warn('failed to execute onAssetsSynced hooks', e)
236
+ })
228
237
  }
229
238
 
230
239
  restore = async () => {
@@ -301,6 +310,11 @@ class Application extends ExodusModule {
301
310
  isRestoring = async () => {
302
311
  return this.#storage.get(RESTORE_FLAG)
303
312
  }
313
+
314
+ // TODO: stop emitting this on hooks?
315
+ isBackedUp = async () => {
316
+ return this.#backedUpAtom.get()
317
+ }
304
318
  }
305
319
 
306
320
  const createApplication = (args = {}) => new Application({ ...args })
@@ -0,0 +1,10 @@
1
+ import createApplication from './application'
2
+
3
+ const applicationDefinition = {
4
+ id: 'application',
5
+ type: 'module',
6
+ factory: createApplication,
7
+ dependencies: ['unsafeStorage', 'backedUpAtom', 'passphraseCache?', 'wallet', 'logger'],
8
+ }
9
+
10
+ export default applicationDefinition
@@ -0,0 +1 @@
1
+ export { default as lifecyclePluginDefinition } from './lifecycle'
@@ -0,0 +1,63 @@
1
+ import { createAtomObserver } from '@exodus/atoms'
2
+
3
+ const applicationLifecyclePlugin = ({
4
+ port,
5
+ lockedAtom,
6
+ lockHistoryAtom,
7
+ restoreAtom,
8
+ backedUpAtom,
9
+ }) => {
10
+ const observers = [
11
+ createAtomObserver({ port, atom: lockedAtom, event: 'locked' }),
12
+ createAtomObserver({ port, atom: lockHistoryAtom, event: 'lockHistory' }),
13
+ createAtomObserver({ port, atom: restoreAtom, event: 'restore' }),
14
+ createAtomObserver({ port, atom: backedUpAtom, event: 'backedUp' }),
15
+ ]
16
+
17
+ const onStart = ({ isRestoring }) => {
18
+ restoreAtom.set(isRestoring)
19
+ }
20
+
21
+ const onLoad = async () => {
22
+ observers.forEach((observer) => observer.start())
23
+ }
24
+
25
+ const onImport = () => {
26
+ restoreAtom.set(true)
27
+ }
28
+
29
+ const onAssetsSynced = async () => {
30
+ await restoreAtom.set(false)
31
+ }
32
+
33
+ const onLock = async () => {
34
+ await lockedAtom.set(true)
35
+ }
36
+
37
+ const onUnlock = async () => {
38
+ await lockedAtom.set(false)
39
+ }
40
+
41
+ const onBackup = async () => {
42
+ await backedUpAtom.set(true)
43
+ }
44
+
45
+ const onStop = () => {
46
+ observers.forEach((observer) => observer.unregister())
47
+ }
48
+
49
+ const onClear = async () => {
50
+ await backedUpAtom.set(undefined)
51
+ }
52
+
53
+ return { onStart, onLoad, onImport, onAssetsSynced, onLock, onUnlock, onBackup, onStop, onClear }
54
+ }
55
+
56
+ const applicationLifecyclePluginDefinition = {
57
+ id: 'applicationLifecyclePlugin',
58
+ type: 'plugin',
59
+ factory: applicationLifecyclePlugin,
60
+ dependencies: ['port', 'lockedAtom', 'lockHistoryAtom', 'restoreAtom', 'backedUpAtom'],
61
+ }
62
+
63
+ export default applicationLifecyclePluginDefinition
@@ -1,19 +1,11 @@
1
1
  import createKeyIdentifierProvider from '@exodus/key-identifier-provider'
2
2
  import walletCompatibilityModesDefinition from '@exodus/wallet-compatibility-modes/module'
3
3
 
4
- import createApplication from '../application'
5
4
  import unlockEncryptedStorageDefinition from '../unlock-encrypted-storage'
6
5
  import { withType } from './utils'
7
6
 
8
7
  const createModuleDependencies = ({ config }) =>
9
8
  [
10
- {
11
- definition: {
12
- id: 'application',
13
- factory: createApplication,
14
- dependencies: ['unsafeStorage', 'passphraseCache?', 'wallet', 'logger'],
15
- },
16
- },
17
9
  {
18
10
  definition: {
19
11
  id: 'keyIdentifierProvider',
package/src/index.js CHANGED
@@ -21,6 +21,7 @@ import wallet from '@exodus/wallet'
21
21
  import walletAccounts from '@exodus/wallet-accounts'
22
22
 
23
23
  import createApi from './api'
24
+ import application from './application'
24
25
  import createIOC from './ioc'
25
26
  import attachMigrations from './migrations/attach'
26
27
  import attachPlugins from './plugins/attach'
@@ -28,6 +29,7 @@ import attachPlugins from './plugins/attach'
28
29
  const createExodus = ({ adapters, config, port, debug = false }) => {
29
30
  const ioc = createIOC({ adapters, config, debug })
30
31
 
32
+ ioc.use(application())
31
33
  ioc.use(addressProvider({ config: config.addressProvider, debug }))
32
34
  ioc.use(assetsFeature())
33
35
  ioc.use(availableAssets())
@@ -1,4 +1,4 @@
1
- import { LifecycleHook } from '../constants'
1
+ import { LifecycleHook } from '../application/constants'
2
2
 
3
3
  const LIFECYCLE_METHOD_TO_HOOK_NAME = Object.fromEntries(
4
4
  Object.entries(LifecycleHook).map(([pascalCaseName, hookName]) => [
File without changes