@meshconnect/uwc-core 1.1.0 → 1.1.1-snapshot.7a97a0f
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/dist/events.d.ts +5 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/observability/lifecycle-bridge.d.ts +31 -13
- package/dist/observability/lifecycle-bridge.d.ts.map +1 -1
- package/dist/observability/lifecycle-bridge.js +167 -92
- package/dist/observability/lifecycle-bridge.js.map +1 -1
- package/dist/services/connection-service.d.ts +22 -0
- package/dist/services/connection-service.d.ts.map +1 -1
- package/dist/services/connection-service.js +92 -9
- package/dist/services/connection-service.js.map +1 -1
- package/dist/services/network-switch-service.d.ts.map +1 -1
- package/dist/services/network-switch-service.js +4 -1
- package/dist/services/network-switch-service.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -5
- package/src/events.ts +5 -2
- package/src/observability/lifecycle-bridge.test.ts +197 -0
- package/src/observability/lifecycle-bridge.ts +211 -99
- package/src/services/connection-service.test.ts +165 -0
- package/src/services/connection-service.ts +100 -10
- package/src/services/network-switch-service.test.ts +33 -0
- package/src/services/network-switch-service.ts +4 -1
- package/src/version.ts +1 -1
|
@@ -161,7 +161,7 @@ export class ConnectionService {
|
|
|
161
161
|
connectionMode: ConnectionMode,
|
|
162
162
|
walletId: string,
|
|
163
163
|
namespace: Namespace,
|
|
164
|
-
initialSwitch?: { chainId: NetworkId; at: number }
|
|
164
|
+
initialSwitch?: { chainId: NetworkId; address?: string; at: number }
|
|
165
165
|
): void {
|
|
166
166
|
this.teardownLifecycle()
|
|
167
167
|
const connector = this.activeConnector
|
|
@@ -181,6 +181,16 @@ export class ConnectionService {
|
|
|
181
181
|
walletId
|
|
182
182
|
})
|
|
183
183
|
: undefined,
|
|
184
|
+
subscribeAccounts: connector?.onAccountsChanged
|
|
185
|
+
? listener =>
|
|
186
|
+
connector.onAccountsChanged!(listener, {
|
|
187
|
+
connectionMode,
|
|
188
|
+
namespace,
|
|
189
|
+
walletId
|
|
190
|
+
})
|
|
191
|
+
: undefined,
|
|
192
|
+
onAccountsChanged: accounts =>
|
|
193
|
+
this.handleAccountsChanged(accounts, namespace),
|
|
184
194
|
getRouting: () => {
|
|
185
195
|
const s = this.sessionManager.getSession()
|
|
186
196
|
return {
|
|
@@ -203,6 +213,63 @@ export class ConnectionService {
|
|
|
203
213
|
})
|
|
204
214
|
}
|
|
205
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Apply a REAL account-list change (from `Connector.onAccountsChanged`, via
|
|
218
|
+
* the lifecycle bridge's second stream) to the session. `namespace` is the
|
|
219
|
+
* namespace of the provider that reported the change — `activeAddress`
|
|
220
|
+
* only moves when that matches the session's currently active network; an
|
|
221
|
+
* empty list is a full, wallet-initiated disconnect.
|
|
222
|
+
*/
|
|
223
|
+
private handleAccountsChanged(
|
|
224
|
+
accounts: string[],
|
|
225
|
+
namespace: Namespace
|
|
226
|
+
): void {
|
|
227
|
+
if (accounts.length === 0) {
|
|
228
|
+
// Idempotency guard: this runs synchronously FROM INSIDE the
|
|
229
|
+
// connector's own accountsChanged dispatch — finishDisconnect() below
|
|
230
|
+
// tears down (among other things) the very subscription that is
|
|
231
|
+
// currently delivering this callback. If a wallet double-fires the
|
|
232
|
+
// empty-array disconnect signal (or one slips through before teardown
|
|
233
|
+
// takes effect), `activeConnector` is already null from the first call
|
|
234
|
+
// — skip re-clearing an already-cleared session and re-emitting
|
|
235
|
+
// disconnected/sessionChanged a second time. Scoped to THIS wallet-
|
|
236
|
+
// initiated path only; the public disconnect() below still always
|
|
237
|
+
// runs finishDisconnect() defensively, even with no active connector.
|
|
238
|
+
if (this.activeConnector === null) return
|
|
239
|
+
// The wallet ended the session on its own side, but the connector's
|
|
240
|
+
// OWN local state (e.g. EthereumWalletService's cached account/
|
|
241
|
+
// provider/uuid) is never cleared by finishDisconnect() below — it
|
|
242
|
+
// only clears core's sessionManager. Left uncleared, a later connect
|
|
243
|
+
// to a DIFFERENT wallet reads that stale cached account via
|
|
244
|
+
// checkExistingConnections() and never rebinds to the new wallet's
|
|
245
|
+
// provider/uuid, silently keeping the old wallet's address live under
|
|
246
|
+
// the new wallet's session. disconnect() is fire-and-forget and
|
|
247
|
+
// error-swallowed here: for injected connectors it's local-only
|
|
248
|
+
// cleanup (safe to call any number of times), and for protocol-based
|
|
249
|
+
// connectors that might reject on an already-closed session, there is
|
|
250
|
+
// no caller to propagate that error to anyway.
|
|
251
|
+
this.activeConnector?.disconnect?.().catch(() => {})
|
|
252
|
+
this.finishDisconnect()
|
|
253
|
+
return
|
|
254
|
+
}
|
|
255
|
+
const newAddress = accounts[0]!
|
|
256
|
+
const session = this.sessionManager.getSession()
|
|
257
|
+
const availableAddresses = session.availableAddresses.map(addr => {
|
|
258
|
+
const network = this.networks.find(n => n.id === addr.networkId)
|
|
259
|
+
return network?.namespace === namespace
|
|
260
|
+
? { ...addr, address: newAddress }
|
|
261
|
+
: addr
|
|
262
|
+
})
|
|
263
|
+
const activeAddress =
|
|
264
|
+
session.activeNetwork?.namespace === namespace
|
|
265
|
+
? newAddress
|
|
266
|
+
: session.activeAddress
|
|
267
|
+
this.sessionManager.updateSession({ activeAddress, availableAddresses })
|
|
268
|
+
this.eventManager.emit('sessionChanged', {
|
|
269
|
+
session: this.sessionManager.getSession()
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
206
273
|
/**
|
|
207
274
|
* Remove the active provider-lifecycle subscription (EIP-1193 `.on` / wallet-
|
|
208
275
|
* adapter / SignClient listeners) WITHOUT disconnecting the wallet. Idempotent.
|
|
@@ -237,10 +304,15 @@ export class ConnectionService {
|
|
|
237
304
|
session.connectionMode,
|
|
238
305
|
session.activeWallet.id,
|
|
239
306
|
session.activeNetwork.namespace,
|
|
240
|
-
// The reattach follows a JUST-completed switch to the now-active chain
|
|
241
|
-
// arm echo suppression for
|
|
242
|
-
// for a wallet-initiated change (one-shot, same as
|
|
243
|
-
|
|
307
|
+
// The reattach follows a JUST-completed switch to the now-active chain
|
|
308
|
+
// (and address) — arm echo suppression for both so the new provider's
|
|
309
|
+
// echo isn't mistaken for a wallet-initiated change (one-shot, same as
|
|
310
|
+
// bus-armed switches).
|
|
311
|
+
{
|
|
312
|
+
chainId: session.activeNetwork.id,
|
|
313
|
+
...(session.activeAddress && { address: session.activeAddress }),
|
|
314
|
+
at: Date.now()
|
|
315
|
+
}
|
|
244
316
|
)
|
|
245
317
|
}
|
|
246
318
|
|
|
@@ -420,14 +492,32 @@ export class ConnectionService {
|
|
|
420
492
|
await this.activeConnector.disconnect()
|
|
421
493
|
}
|
|
422
494
|
} finally {
|
|
423
|
-
this.
|
|
424
|
-
this.sessionManager.clearSession()
|
|
425
|
-
const session = this.sessionManager.getSession()
|
|
426
|
-
this.eventManager.emit('disconnected', undefined)
|
|
427
|
-
this.eventManager.emit('sessionChanged', { session })
|
|
495
|
+
this.finishDisconnect()
|
|
428
496
|
}
|
|
429
497
|
}
|
|
430
498
|
|
|
499
|
+
/**
|
|
500
|
+
* Clears core's own local state (session, active connector reference,
|
|
501
|
+
* lifecycle subscription) and emits the disconnect events. Does NOT itself
|
|
502
|
+
* call the connector's `disconnect()` — that happens in each CALLER,
|
|
503
|
+
* because the two callers need different semantics: the public
|
|
504
|
+
* `disconnect()` above awaits it (the caller may care whether the wallet
|
|
505
|
+
* side actually tore down); the wallet-initiated path in
|
|
506
|
+
* `handleAccountsChanged` fires it and swallows the result (the wallet
|
|
507
|
+
* already ended the session on its own side, but the connector's own
|
|
508
|
+
* LOCAL state — e.g. a cached account/uuid — still needs clearing, or a
|
|
509
|
+
* later connect to a different wallet reads it as stale and never
|
|
510
|
+
* rebinds).
|
|
511
|
+
*/
|
|
512
|
+
private finishDisconnect(): void {
|
|
513
|
+
this.teardownLifecycle()
|
|
514
|
+
this.activeConnector = null
|
|
515
|
+
this.sessionManager.clearSession()
|
|
516
|
+
const session = this.sessionManager.getSession()
|
|
517
|
+
this.eventManager.emit('disconnected', undefined)
|
|
518
|
+
this.eventManager.emit('sessionChanged', { session })
|
|
519
|
+
}
|
|
520
|
+
|
|
431
521
|
getConnectionURI(): string | undefined {
|
|
432
522
|
if (
|
|
433
523
|
this.activeConnector &&
|
|
@@ -234,4 +234,37 @@ describe('NetworkSwitchService', () => {
|
|
|
234
234
|
expect(events[0].data.operation).toBe('switchNetwork')
|
|
235
235
|
expect(events[0].data.chainId).toBe('eip155:137')
|
|
236
236
|
})
|
|
237
|
+
|
|
238
|
+
it('includes the new address on the emitted networkSwitched event', async () => {
|
|
239
|
+
sessionManager.updateSession({
|
|
240
|
+
connectionMode: 'injected',
|
|
241
|
+
activeWallet: {
|
|
242
|
+
id: 'metamask',
|
|
243
|
+
name: 'MetaMask',
|
|
244
|
+
metadata: {
|
|
245
|
+
icon: 'test',
|
|
246
|
+
downloadUrl: 'test',
|
|
247
|
+
supportedChains: ['eip155:1', 'eip155:137']
|
|
248
|
+
},
|
|
249
|
+
extensionInjectedProvider: {
|
|
250
|
+
supportedNetworkIds: ['eip155:1', 'eip155:137']
|
|
251
|
+
}
|
|
252
|
+
} as any
|
|
253
|
+
})
|
|
254
|
+
mockConnector.switchNetwork = vi.fn().mockResolvedValue({
|
|
255
|
+
address: '0xabc',
|
|
256
|
+
availableAddresses: [{ address: '0xabc', networkId: 'eip155:137' }]
|
|
257
|
+
})
|
|
258
|
+
const switched: Array<{ network: unknown; address?: string }> = []
|
|
259
|
+
eventManager.on('networkSwitched', d => switched.push(d))
|
|
260
|
+
|
|
261
|
+
await networkSwitchService.switchNetwork('eip155:137')
|
|
262
|
+
|
|
263
|
+
expect(switched).toEqual([
|
|
264
|
+
{
|
|
265
|
+
network: expect.objectContaining({ id: 'eip155:137' }),
|
|
266
|
+
address: '0xabc'
|
|
267
|
+
}
|
|
268
|
+
])
|
|
269
|
+
})
|
|
237
270
|
})
|
|
@@ -188,7 +188,10 @@ export class NetworkSwitchService {
|
|
|
188
188
|
})
|
|
189
189
|
})
|
|
190
190
|
|
|
191
|
-
this.eventManager.emit('networkSwitched', {
|
|
191
|
+
this.eventManager.emit('networkSwitched', {
|
|
192
|
+
network,
|
|
193
|
+
address: result.address
|
|
194
|
+
})
|
|
192
195
|
this.eventManager.emit('sessionChanged', {
|
|
193
196
|
session: this.sessionManager.getSession()
|
|
194
197
|
})
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated from package.json by scripts/generate-version.mjs — do not edit.
|
|
2
|
-
export const UWC_CORE_VERSION = '1.1.
|
|
2
|
+
export const UWC_CORE_VERSION = '1.1.1'
|