@exodus/headless 2.3.0 → 3.0.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,27 @@
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.0.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.4.0...@exodus/headless@3.0.0) (2024-01-25)
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ - make wallet application agnostic (#5469)
11
+
12
+ ### Features
13
+
14
+ - make wallet application agnostic ([#5469](https://github.com/ExodusMovement/exodus-hydra/issues/5469)) ([5edce20](https://github.com/ExodusMovement/exodus-hydra/commit/5edce206e12d35a6acdccd597bc52352772ed9c3))
15
+
16
+ ## [2.4.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.3.0...@exodus/headless@2.4.0) (2024-01-24)
17
+
18
+ ### Features
19
+
20
+ - **headless:** build analytics default properties ([#5441](https://github.com/ExodusMovement/exodus-hydra/issues/5441)) ([66efbb2](https://github.com/ExodusMovement/exodus-hydra/commit/66efbb225eda2826ee5cbed169b009501bcdc639))
21
+
22
+ ### Bug Fixes
23
+
24
+ - **headless:** bump @exodus/geolocation major version ([#5500](https://github.com/ExodusMovement/exodus-hydra/issues/5500)) ([27ea226](https://github.com/ExodusMovement/exodus-hydra/commit/27ea22654721f628e9995a16e60d5c946173c0e0))
25
+ - **headless:** do not return debug namespace when not in debug mode ([#5463](https://github.com/ExodusMovement/exodus-hydra/issues/5463)) ([91c7481](https://github.com/ExodusMovement/exodus-hydra/commit/91c7481ea97ae775f44630956f47aace743d132d))
26
+
6
27
  ## [2.3.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.2.2...@exodus/headless@2.3.0) (2024-01-15)
7
28
 
8
29
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/headless",
3
- "version": "2.3.0",
3
+ "version": "3.0.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": "^3.1.0",
43
+ "@exodus/fusion-atoms": "^1.1.2",
44
+ "@exodus/geolocation": "^4.0.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": "^11.0.0",
70
+ "@exodus/analytics": "^12.0.0",
70
71
  "@exodus/apy-rates": "^3.3.1",
71
72
  "@exodus/assets-feature": "workspace:^",
72
73
  "@exodus/bitcoin-plugin": "^1.0.14",
@@ -81,7 +82,7 @@
81
82
  "@exodus/litecoin-meta": "^1.0.0",
82
83
  "@exodus/market-history": "^7.3.1",
83
84
  "@exodus/models": "^10.1.0",
84
- "@exodus/nfts": "^7.11.0",
85
+ "@exodus/nfts": "^8.0.0",
85
86
  "@exodus/personal-notes": "^3.6.0",
86
87
  "@exodus/referrals": "^8.1.2",
87
88
  "@exodus/solana-lib": "^1.3.11",
@@ -101,5 +102,5 @@
101
102
  "msw": "^2.0.0",
102
103
  "p-defer": "^4.0.0"
103
104
  },
104
- "gitHead": "035a21e35481a7819a24348a5eb97f4c71b37d0b"
105
+ "gitHead": "5052dcafa0b903350e25ed7df175a6d65ce37afe"
105
106
  }
package/src/api/index.js CHANGED
@@ -40,14 +40,19 @@ const createApi = ({ ioc, port, config, debug }) => {
40
40
 
41
41
  const reportingApi = createReporting({ ioc, config })
42
42
 
43
- return {
43
+ const api = {
44
44
  ...featureApis,
45
- debug: debugApi,
46
45
  reporting: reportingApi,
47
46
  isMnemonicValid,
48
47
  subscribe: port.subscribe.bind(port),
49
48
  unsubscribe: port.unsubscribe.bind(port),
50
49
  }
50
+
51
+ if (debugApi) {
52
+ api.debug = debugApi
53
+ }
54
+
55
+ return api
51
56
  }
52
57
 
53
58
  export default createApi
@@ -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
 
@@ -301,6 +308,11 @@ class Application extends ExodusModule {
301
308
  isRestoring = async () => {
302
309
  return this.#storage.get(RESTORE_FLAG)
303
310
  }
311
+
312
+ // TODO: stop emitting this on hooks?
313
+ isBackedUp = async () => {
314
+ return this.#backedUpAtom.get()
315
+ }
304
316
  }
305
317
 
306
318
  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,9 +1,17 @@
1
1
  const setBuildMetadataProperties = async ({ analytics, getBuildMetadata }) => {
2
2
  analytics.requireDefaultProperties(['appId', 'osName'])
3
3
 
4
- const { appId, osName, deviceModel } = await getBuildMetadata()
4
+ const { appId, osName, deviceModel, platformVersion, deviceManufacturer } =
5
+ await getBuildMetadata()
6
+
7
+ analytics.setDefaultProperties({
8
+ appId,
9
+ osName,
10
+ deviceModel,
11
+ deviceManufacturer,
12
+ osVersion: platformVersion,
13
+ })
5
14
 
6
- analytics.setDefaultProperties({ appId, osName, deviceModel })
7
15
  analytics.setDefaultPropertiesForSanitizationErrors({ osName })
8
16
  }
9
17
 
@@ -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