edge-core-js 2.2.1 → 2.4.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.
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>edge core dev-server</title>
5
+ <meta charset="utf-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ </head>
8
+ <body>
9
+ <script src="edge-core.js"></script>
10
+ <script>
11
+ function load() {
12
+ var script = document.createElement('script')
13
+ script.charset = 'utf-8'
14
+ script.async = true
15
+ script.addEventListener('error', window.lockEdgeCorePlugins)
16
+ script.addEventListener('load', window.lockEdgeCorePlugins)
17
+ script.src = 'plugin-bundle.js'
18
+ document.head.appendChild(script)
19
+ }
20
+ setTimeout(load, 200)
21
+
22
+ console.log('CORE SERVER!')
23
+ </script>
24
+ </body>
25
+ </html>
@@ -621,8 +621,8 @@ export function makeAccountApi(ai, accountId) {
621
621
  throw new Error(
622
622
  `activateWallet unsupported by walletId ${activateWalletId}`
623
623
  )
624
- const walletId = _optionalChain([paymentInfo, 'optionalAccess', _ => _.walletId])
625
- const wallet = currencyWallets[_nullishCoalesce(walletId, () => ( ''))]
624
+ const walletId = _nullishCoalesce(_optionalChain([paymentInfo, 'optionalAccess', _ => _.walletId]), () => ( ''))
625
+ const wallet = currencyWallets[walletId]
626
626
 
627
627
  if (wallet == null) {
628
628
  throw new Error(`No wallet for walletId ${walletId}`)
@@ -154,10 +154,7 @@ const accountPixie = combinePixies({
154
154
 
155
155
  return {
156
156
  update() {
157
- const { accountOutput } = input.props
158
- if (accountOutput == null) return
159
- const { accountApi } = accountOutput
160
- if (accountApi == null) return
157
+ if (_optionalChain([input, 'access', _ => _.props, 'access', _2 => _2.accountOutput, 'optionalAccess', _3 => _3.accountApi]) == null) return
161
158
 
162
159
  // Start once the EdgeAccount API exists:
163
160
  dataTask.start({ wait: true })
@@ -244,14 +241,14 @@ const accountPixie = combinePixies({
244
241
  lastActiveWalletIds = activeWalletIds
245
242
 
246
243
  let lastOut = {}
247
- if (_optionalChain([accountOutput, 'optionalAccess', _ => _.currencyWallets]) != null) {
244
+ if (_optionalChain([accountOutput, 'optionalAccess', _4 => _4.currencyWallets]) != null) {
248
245
  lastOut = accountOutput.currencyWallets
249
246
  }
250
247
 
251
248
  const out = {}
252
249
  const { wallets } = input.props.output.currency
253
250
  for (const walletId of activeWalletIds) {
254
- const api = _optionalChain([wallets, 'access', _2 => _2[walletId], 'optionalAccess', _3 => _3.walletApi])
251
+ const api = _optionalChain([wallets, 'access', _5 => _5[walletId], 'optionalAccess', _6 => _6.walletApi])
255
252
  if (api !== lastOut[walletId]) dirty = true
256
253
  if (api != null) out[walletId] = api
257
254
  }
@@ -37,9 +37,7 @@ export async function fetchAppIdInfo(
37
37
  appId
38
38
  ) {
39
39
  try {
40
- const infoServerUri = shuffle(
41
- ai.props.state.contextConfig.edgeServers.infoServers
42
- )[0]
40
+ const [infoServerUri] = shuffle(ai.props.state.infoServers)
43
41
  const url = `${infoServerUri}/v1/appIdInfo/${appId}`
44
42
  const response = await ai.props.io.fetch(url)
45
43
  if (response.status === 404) {
@@ -1,9 +1,21 @@
1
- import { combinePixies, stopUpdates, } from 'redux-pixies'
1
+ import {
2
+ combinePixies,
3
+ filterPixie,
4
+ stopUpdates,
5
+
6
+ } from 'redux-pixies'
2
7
  import { close, update } from 'yaob'
3
8
 
4
9
 
10
+ import { makePeriodicTask } from '../../util/periodic-task'
11
+ import { shuffle } from '../../util/shuffle'
5
12
 
6
13
  import { makeContextApi } from './context-api'
14
+ import {
15
+ asInfoCacheFile,
16
+ INFO_CACHE_FILE_NAME,
17
+ infoCacheFile
18
+ } from './info-cache-file'
7
19
 
8
20
 
9
21
 
@@ -41,5 +53,38 @@ export const context = combinePixies({
41
53
  }
42
54
  }
43
55
  }
44
- }
56
+ },
57
+
58
+ infoFetcher: filterPixie(
59
+ (input) => {
60
+ async function doInfoSync() {
61
+ const { dispatch, io } = input.props
62
+
63
+ const [infoServerUri] = shuffle(input.props.state.infoServers)
64
+ const response = await fetch(`${infoServerUri}/v1/coreRollup`, {
65
+ headers: { accept: 'application/json' }
66
+ })
67
+ if (!response.ok) return
68
+ const json = await response.json()
69
+
70
+ const infoCache = asInfoCacheFile(json)
71
+ dispatch({
72
+ type: 'INFO_CACHE_FETCHED',
73
+ payload: infoCache
74
+ })
75
+ await infoCacheFile.save(io.disklet, INFO_CACHE_FILE_NAME, infoCache)
76
+ }
77
+
78
+ const infoTask = makePeriodicTask(doInfoSync, 10 * 60 * 1000)
79
+ infoTask.start()
80
+
81
+ return {
82
+ update() {},
83
+ destroy() {
84
+ infoTask.stop()
85
+ }
86
+ }
87
+ },
88
+ props => (props.state.paused ? undefined : props)
89
+ )
45
90
  })
@@ -0,0 +1,18 @@
1
+ import { asArray, asObject, asString } from 'cleaners'
2
+
3
+
4
+ import { asJsonObject, makeJsonFile } from '../../util/file-helpers'
5
+
6
+
7
+
8
+
9
+
10
+
11
+ export const INFO_CACHE_FILE_NAME = 'infoCache.json'
12
+
13
+ export const asInfoCacheFile = asObject({
14
+ corePlugins: asObject(asJsonObject),
15
+ syncServers: asArray(asString)
16
+ })
17
+
18
+ export const infoCacheFile = makeJsonFile(asInfoCacheFile)
@@ -1,4 +1,6 @@
1
- import { combinePixies, mapPixie, } from 'redux-pixies'
1
+ function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { combinePixies, mapPixie, } from 'redux-pixies'
2
+
3
+ import { matchJson } from '../../util/match-json'
2
4
 
3
5
 
4
6
  import {
@@ -21,5 +23,33 @@ export const currency = combinePixies({
21
23
  walletState: props.state.currency.wallets[walletId],
22
24
  walletOutput: props.output.currency.wallets[walletId]
23
25
  })
24
- )
26
+ ),
27
+
28
+ pluginUpdater(input) {
29
+ let lastInfo
30
+
31
+ return async () => {
32
+ const { infoCache, plugins } = input.props.state
33
+
34
+ // Bail out quickly if nothing has changed:
35
+ if (lastInfo === infoCache) return
36
+
37
+ // Update plugins after the first run:
38
+ if (lastInfo != null) {
39
+ for (const pluginId of Object.keys(plugins.currency)) {
40
+ const plugin = plugins.currency[pluginId]
41
+ const newPayload = _nullishCoalesce(_optionalChain([infoCache, 'access', _ => _.corePlugins, 'optionalAccess', _2 => _2[pluginId]]), () => ( {}))
42
+ const oldPayload = _nullishCoalesce(_optionalChain([lastInfo, 'access', _3 => _3.corePlugins, 'optionalAccess', _4 => _4[pluginId]]), () => ( {}))
43
+
44
+ if (
45
+ plugin.updateInfoPayload != null &&
46
+ !matchJson(oldPayload, newPayload)
47
+ ) {
48
+ await plugin.updateInfoPayload(newPayload)
49
+ }
50
+ }
51
+ }
52
+ lastInfo = infoCache
53
+ }
54
+ }
25
55
  })
@@ -10,6 +10,7 @@ import { upgradeCurrencyCode } from '../../../types/type-helpers'
10
10
 
11
11
 
12
12
 
13
+
13
14
  import { compare } from '../../../util/compare'
14
15
  import { enableTestMode, pushUpdate } from '../../../util/updateQueue'
15
16
  import {
@@ -30,11 +31,7 @@ import {
30
31
 
31
32
 
32
33
 
33
- import {
34
-
35
- mergeTx,
36
-
37
- } from './currency-wallet-reducer'
34
+ import { mergeTx, } from './currency-wallet-reducer'
38
35
  import { uniqueStrings } from './enabled-tokens'
39
36
 
40
37
  let throttleRateLimitMs = 5000
@@ -198,7 +195,7 @@ export function makeCurrencyWalletCallbacks(
198
195
  return
199
196
  }
200
197
  pushUpdate({
201
- id: `${walletId}==${tokenId}`,
198
+ id: `${walletId}==${String(tokenId)}`,
202
199
  action: 'onTokenBalanceChanged',
203
200
  updateFunc: () => {
204
201
  input.props.dispatch({
@@ -219,15 +216,12 @@ export function makeCurrencyWalletCallbacks(
219
216
  const { txs } = input.props.walletState
220
217
  for (const txid of Object.keys(txs)) {
221
218
  const reduxTx = txs[txid]
222
- if (
223
- reduxTx.confirmations !== 'confirmed' &&
224
- reduxTx.confirmations !== 'dropped'
225
- ) {
219
+ if (shouldCoreDetermineConfirmations(reduxTx.confirmations)) {
226
220
  const { requiredConfirmations } =
227
221
  input.props.walletState.currencyInfo
228
222
  const { height } = input.props.walletState
229
223
 
230
- reduxTx.confirmations = validateConfirmations(
224
+ reduxTx.confirmations = determineConfirmations(
231
225
  reduxTx,
232
226
  height,
233
227
  requiredConfirmations
@@ -322,14 +316,11 @@ export function makeCurrencyWalletCallbacks(
322
316
  const { txid } = tx
323
317
 
324
318
  // DEPRECATE: After all currency plugins implement new Confirmations API
325
- if (
326
- tx.confirmations !== 'confirmed' &&
327
- tx.confirmations !== 'dropped'
328
- ) {
319
+ if (shouldCoreDetermineConfirmations(tx.confirmations)) {
329
320
  const { requiredConfirmations } = input.props.walletState.currencyInfo
330
321
  const { height } = input.props.walletState
331
322
 
332
- tx.confirmations = validateConfirmations(
323
+ tx.confirmations = determineConfirmations(
333
324
  tx,
334
325
  height,
335
326
  requiredConfirmations
@@ -417,8 +408,24 @@ export function watchCurrencyWallet(input) {
417
408
  checkChangesLoop()
418
409
  }
419
410
 
420
- export const validateConfirmations = (
421
- tx,
411
+ /**
412
+ * Returns true if the core needs to calculate the transaction's confirmation state,
413
+ * because it still depends on the current block height.
414
+ *
415
+ * @deprecated Remove once all currency plugins support the new confirmations API.
416
+ */
417
+ const shouldCoreDetermineConfirmations = (
418
+ confirmations
419
+ ) => {
420
+ return (
421
+ confirmations !== 'confirmed' &&
422
+ confirmations !== 'dropped' &&
423
+ confirmations !== 'failed'
424
+ )
425
+ }
426
+
427
+ export const determineConfirmations = (
428
+ tx, // Either EdgeTransaction or MergedTransaction
422
429
  blockHeight,
423
430
  requiredConfirmations = 1 // Default confirmation rule is 1 block
424
431
  ) => {
@@ -7,8 +7,9 @@ export const asEdgeMetadata = raw => {
7
7
  const { exchangeAmount = {} } = clean
8
8
 
9
9
  // Delete corrupt amounts that exceed the Javascript number range:
10
- for (const fiat of Object.keys(clean)) {
10
+ for (const fiat of Object.keys(exchangeAmount)) {
11
11
  if (String(exchangeAmount[fiat]).includes('e')) {
12
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
12
13
  delete exchangeAmount[fiat]
13
14
  }
14
15
  }
@@ -30,9 +30,9 @@ export class FakeDb {
30
30
 
31
31
 
32
32
  constructor() {
33
- this.lobbies = {}
33
+ this.lobbies = new Map()
34
34
  this.logins = []
35
- this.repos = {}
35
+ this.repos = new Map()
36
36
  }
37
37
 
38
38
  getLoginById(loginId) {
@@ -80,7 +80,7 @@ export class FakeDb {
80
80
  }
81
81
 
82
82
  setupRepo(syncKey, repo) {
83
- this.repos[syncKey] = repo
83
+ this.repos.set(syncKey, repo)
84
84
  }
85
85
 
86
86
  dumpLogin(login) {
@@ -279,7 +279,7 @@ function createLogin(request, login) {
279
279
  keyBoxes: []
280
280
  }))(body.data)
281
281
  for (const syncKey of keys.newSyncKeys) {
282
- db.repos[syncKey] = {}
282
+ db.repos.set(syncKey, {})
283
283
  }
284
284
 
285
285
  // Start building the new database row:
@@ -326,7 +326,7 @@ const addKeysRoute = withLogin2(request => {
326
326
 
327
327
  // Set up repos:
328
328
  for (const syncKey of clean.newSyncKeys) {
329
- db.repos[syncKey] = {}
329
+ db.repos.set(syncKey, {})
330
330
  }
331
331
  login.keyBoxes = softCat(login.keyBoxes, clean.keyBoxes)
332
332
 
@@ -596,7 +596,7 @@ const withLobby =
596
596
  request => {
597
597
  const { db, path } = request
598
598
  const lobbyId = path.split('/')[4]
599
- const lobby = db.lobbies[lobbyId]
599
+ const lobby = db.lobbies.get(lobbyId)
600
600
  return lobby != null
601
601
  ? server({ ...request, lobby, lobbyId })
602
602
  : fallback({ ...request, lobbyId })
@@ -619,7 +619,7 @@ const createLobbyRoute = withLobby(
619
619
  const { timeout = 600 } = clean
620
620
  const expires = new Date(Date.now() + 1000 * timeout).toISOString()
621
621
 
622
- db.lobbies[lobbyId] = { request: clean, replies: [], expires }
622
+ db.lobbies.set(lobbyId, { request: clean, replies: [], expires })
623
623
  return statusResponse()
624
624
  }
625
625
  )
@@ -643,7 +643,7 @@ const getLobbyRoute = withLobby(request => {
643
643
 
644
644
  const deleteLobbyRoute = withLobby(request => {
645
645
  const { db, lobbyId } = request
646
- delete db.lobbies[lobbyId]
646
+ db.lobbies.delete(lobbyId)
647
647
  return statusResponse()
648
648
  })
649
649
 
@@ -682,7 +682,7 @@ const withRepo =
682
682
  const syncKey = elements[4]
683
683
  // const hash = elements[5]
684
684
 
685
- const repo = db.repos[syncKey]
685
+ const repo = db.repos.get(syncKey)
686
686
  if (repo == null) {
687
687
  // This is not the auth server, so we have a different format:
688
688
  return jsonResponse({ msg: 'Hash not found' }, { status: 404 })
@@ -158,7 +158,9 @@ export function makeFakeWorld(
158
158
 
159
159
  // Find the data on the server:
160
160
  const login = fakeDb.getLoginById(loginId)
161
- if (login == null) throw new Error(`Cannot find user ${account.username}`)
161
+ if (login == null) {
162
+ throw new Error(`Cannot find user ${account.rootLoginId}`)
163
+ }
162
164
 
163
165
  // Figure out which repos to use:
164
166
  const syncKeys = []
@@ -171,7 +173,8 @@ export function makeFakeWorld(
171
173
  }
172
174
  const repos = {}
173
175
  for (const syncKey of syncKeys) {
174
- repos[syncKey] = wasEdgeRepoDump(fakeDb.repos[syncKey])
176
+ const repo = fakeDb.repos.get(syncKey)
177
+ if (repo != null) repos[syncKey] = wasEdgeRepoDump(repo)
175
178
  }
176
179
 
177
180
  return {
@@ -1,4 +1,5 @@
1
- import { navigateDisklet } from 'disklet'
1
+ function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { navigateDisklet } from 'disklet'
2
+
2
3
 
3
4
 
4
5
 
@@ -35,7 +36,7 @@ export function addEdgeCorePlugins(plugins) {
35
36
  }
36
37
 
37
38
  // Save the new plugins:
38
- for (const pluginId in plugins) {
39
+ for (const pluginId of Object.keys(plugins)) {
39
40
  allPlugins[pluginId] = plugins[pluginId]
40
41
  }
41
42
 
@@ -56,6 +57,7 @@ export function lockEdgeCorePlugins() {
56
57
  */
57
58
  export function watchPlugins(
58
59
  ios,
60
+ infoCache,
59
61
  logBackend,
60
62
  pluginsInit,
61
63
  dispatch
@@ -66,7 +68,7 @@ export function watchPlugins(
66
68
  function pluginsAdded(plugins) {
67
69
  const out = {}
68
70
 
69
- for (const pluginId in plugins) {
71
+ for (const pluginId of Object.keys(plugins)) {
70
72
  const plugin = plugins[pluginId]
71
73
  const log = makeLog(logBackend, pluginId)
72
74
  const initOptions = pluginsInit[pluginId]
@@ -76,6 +78,7 @@ export function watchPlugins(
76
78
  try {
77
79
  if (typeof plugin === 'function') {
78
80
  const opts = {
81
+ infoPayload: _nullishCoalesce(_optionalChain([infoCache, 'access', _ => _.corePlugins, 'optionalAccess', _2 => _2[pluginId]]), () => ( {})),
79
82
  initOptions: typeof initOptions === 'object' ? initOptions : {},
80
83
  io: legacyIo,
81
84
  log,
@@ -70,7 +70,7 @@ export async function waitForPlugins(ai) {
70
70
 
71
71
  const { currency, swap } = props.state.plugins
72
72
  const missingPlugins = []
73
- for (const pluginId in init) {
73
+ for (const pluginId of Object.keys(init)) {
74
74
  const shouldLoad = init[pluginId] !== false && init[pluginId] != null
75
75
  if (shouldLoad && currency[pluginId] == null && swap[pluginId] == null) {
76
76
  missingPlugins.push(pluginId)
@@ -3,7 +3,7 @@ import { buildReducer, mapReducer } from 'redux-keto'
3
3
 
4
4
  import { accountReducer, } from './account/account-reducer'
5
5
 
6
- import { contextConfig, } from './context/context-reducer'
6
+
7
7
  import { currency, } from './currency/currency-reducer'
8
8
  import { login, } from './login/login-reducer'
9
9
  import { plugins, } from './plugins/plugins-reducer'
@@ -26,6 +26,8 @@ import { storageWallets, } from './storage/storage-reducer'
26
26
 
27
27
 
28
28
 
29
+
30
+
29
31
 
30
32
 
31
33
  export const defaultLogSettings = {
@@ -64,6 +66,20 @@ export const reducer = buildReducer({
64
66
  return action.type === 'INIT' ? action.payload.hideKeys : state
65
67
  },
66
68
 
69
+ infoCache(state = {}, action) {
70
+ switch (action.type) {
71
+ case 'INIT':
72
+ return action.payload.infoCache
73
+ case 'INFO_CACHE_FETCHED':
74
+ return action.payload
75
+ }
76
+ return state
77
+ },
78
+
79
+ infoServers(state = [], action) {
80
+ return action.type === 'INIT' ? action.payload.infoServers : state
81
+ },
82
+
67
83
  lastAccountId(state, action, next) {
68
84
  return `login${next.accountCount}`
69
85
  },
@@ -90,7 +106,10 @@ export const reducer = buildReducer({
90
106
  return action.type === 'INIT' ? action.payload.skipBlockHeight : state
91
107
  },
92
108
 
93
- contextConfig,
109
+ syncServers(state = [], action) {
110
+ return action.type === 'INIT' ? action.payload.syncServers : state
111
+ },
112
+
94
113
  currency,
95
114
  login,
96
115
  plugins,
package/lib/core/root.js CHANGED
@@ -7,6 +7,7 @@ import { emit } from 'yaob'
7
7
  import { validateServer } from '../util/validateServer'
8
8
 
9
9
  import { CLIENT_FILE_NAME, clientFile } from './context/client-file'
10
+ import { INFO_CACHE_FILE_NAME, infoCacheFile } from './context/info-cache-file'
10
11
  import { filterLogs, makeLog } from './log/log'
11
12
  import { loadStashes } from './login/login-stash'
12
13
  import { watchPlugins } from './plugins/plugins-actions'
@@ -35,23 +36,33 @@ export async function makeContext(
35
36
  apiKey,
36
37
  appId = '',
37
38
  authServer = 'https://login.edge.app/api',
38
- infoServer = ['https://info-eu1.edge.app', 'https://info-us1.edge.app'],
39
- syncServer = [
40
- 'https://sync-us1.edge.app',
41
- 'https://sync-us2.edge.app',
42
- 'https://sync-us3.edge.app',
43
- 'https://sync-us4.edge.app',
44
- 'https://sync-us5.edge.app',
45
- 'https://sync-us6.edge.app',
46
- 'https://sync-eu.edge.app'
47
- ],
39
+ infoServer,
40
+ syncServer,
48
41
  deviceDescription = null,
49
42
  hideKeys = false,
50
43
  plugins: pluginsInit = {},
51
44
  skipBlockHeight = false
52
45
  } = opts
53
- const infoServers = Array.isArray(infoServer) ? infoServer : [infoServer]
54
- const syncServers = Array.isArray(syncServer) ? syncServer : [syncServer]
46
+ const infoServers =
47
+ typeof infoServer === 'string'
48
+ ? [infoServer]
49
+ : infoServer != null && infoServer.length > 0
50
+ ? infoServer
51
+ : ['https://info-eu1.edge.app', 'https://info-us1.edge.app']
52
+ const syncServers =
53
+ typeof syncServer === 'string'
54
+ ? [syncServer]
55
+ : syncServer != null && syncServer.length > 0
56
+ ? syncServer
57
+ : [
58
+ 'https://sync-us1.edge.app',
59
+ 'https://sync-us2.edge.app',
60
+ 'https://sync-us3.edge.app',
61
+ 'https://sync-us4.edge.app',
62
+ 'https://sync-us5.edge.app',
63
+ 'https://sync-us6.edge.app',
64
+ 'https://sync-eu.edge.app'
65
+ ]
55
66
  const logSettings = { ...defaultLogSettings, ...opts.logSettings }
56
67
  if (apiKey == null) {
57
68
  throw new Error('No API key provided')
@@ -71,21 +82,26 @@ export async function makeContext(
71
82
  })
72
83
  const log = makeLog(logBackend, 'edge-core')
73
84
 
74
- // Load the clientId from disk:
75
- let clientInfo = await clientFile.load(io.disklet, CLIENT_FILE_NAME)
85
+ let [clientInfo, infoCache = {}, stashes] = await Promise.all([
86
+ clientFile.load(io.disklet, CLIENT_FILE_NAME),
87
+ infoCacheFile.load(io.disklet, INFO_CACHE_FILE_NAME),
88
+ loadStashes(io.disklet, log)
89
+ ])
90
+
91
+ // Save the clientId if we don't have one:
76
92
  if (clientInfo == null) {
77
93
  clientInfo = { clientId: io.random(16) }
78
94
  await clientFile.save(io.disklet, CLIENT_FILE_NAME, clientInfo)
79
95
  }
80
96
 
81
97
  // Load the login stashes from disk:
82
- const stashes = await loadStashes(io.disklet, log)
83
98
  redux.dispatch({
84
99
  type: 'INIT',
85
100
  payload: {
86
101
  apiKey,
87
102
  appId,
88
103
  authServer,
104
+ infoCache,
89
105
  infoServers,
90
106
  syncServers,
91
107
  clientId: clientInfo.clientId,
@@ -101,13 +117,14 @@ export async function makeContext(
101
117
  // Subscribe to new plugins:
102
118
  const closePlugins = watchPlugins(
103
119
  ios,
120
+ infoCache,
104
121
  logBackend,
105
122
  pluginsInit,
106
123
  redux.dispatch
107
124
  )
108
125
 
109
126
  // Create sync client:
110
- const syncClient = await makeSyncClient({
127
+ const syncClient = makeSyncClient({
111
128
  log,
112
129
  fetch: io.fetch,
113
130
  edgeServers: { infoServers, syncServers }
@@ -43,9 +43,9 @@ export async function addStorageWallet(
43
43
  const { syncKey } = walletInfo.keys
44
44
  const { lastHash } = status
45
45
  ai.props.log.error(
46
- `Could not sync ${syncKey} with last hash ${String(lastHash)}: ${String(
47
- error
48
- )}`
46
+ `Could not sync ${String(syncKey)} with last hash ${String(
47
+ lastHash
48
+ )}: ${String(error)}`
49
49
  )
50
50
  onError(error)
51
51
  })
@@ -1,4 +1,4 @@
1
- function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }import { gt, lt } from 'biggystring'
1
+ function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }import { gt, lt } from 'biggystring'
2
2
  import { bridgifyObject, close } from 'yaob'
3
3
 
4
4
  import {
@@ -33,11 +33,11 @@ export async function fetchSwapQuotes(
33
33
  promoCodes = {},
34
34
  slowResponseMs = 20000
35
35
  } = opts
36
- const { log } = ai.props
36
+ const { log, state } = ai.props
37
37
 
38
- const account = ai.props.state.accounts[accountId]
38
+ const account = state.accounts[accountId]
39
39
  const { swapSettings, userSettings } = account
40
- const swapPlugins = ai.props.state.plugins.swap
40
+ const swapPlugins = state.plugins.swap
41
41
 
42
42
  log.warn(
43
43
  'Requesting swap quotes for: ',
@@ -62,6 +62,7 @@ export async function fetchSwapQuotes(
62
62
  promises.push(
63
63
  swapPlugins[pluginId]
64
64
  .fetchSwapQuote(request, userSettings[pluginId], {
65
+ infoPayload: _nullishCoalesce(_optionalChain([state, 'access', _ => _.infoCache, 'access', _2 => _2.corePlugins, 'optionalAccess', _3 => _3[pluginId]]), () => ( {})),
65
66
  promoCode: promoCodes[pluginId]
66
67
  })
67
68
  .then(