@meshconnect/uwc-core 1.2.3-snapshot.dcfdbbf → 1.3.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/dist/events.d.ts +40 -5
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +4 -0
- package/dist/events.js.map +1 -1
- package/dist/observability/focus-tracker.d.ts +30 -11
- package/dist/observability/focus-tracker.d.ts.map +1 -1
- package/dist/observability/focus-tracker.js +54 -18
- package/dist/observability/focus-tracker.js.map +1 -1
- package/dist/observability/instrument-handoff.d.ts.map +1 -1
- package/dist/observability/instrument-handoff.js +25 -6
- package/dist/observability/instrument-handoff.js.map +1 -1
- package/dist/observability/lifecycle-bridge.d.ts +13 -31
- package/dist/observability/lifecycle-bridge.d.ts.map +1 -1
- package/dist/observability/lifecycle-bridge.js +92 -167
- package/dist/observability/lifecycle-bridge.js.map +1 -1
- package/dist/observability/relay-drop-tracker.d.ts +37 -0
- package/dist/observability/relay-drop-tracker.d.ts.map +1 -0
- package/dist/observability/relay-drop-tracker.js +30 -0
- package/dist/observability/relay-drop-tracker.js.map +1 -0
- package/dist/observability/telemetry.d.ts +8 -0
- package/dist/observability/telemetry.d.ts.map +1 -1
- package/dist/observability/telemetry.js +32 -5
- package/dist/observability/telemetry.js.map +1 -1
- package/dist/services/connection-service.d.ts +0 -43
- package/dist/services/connection-service.d.ts.map +1 -1
- package/dist/services/connection-service.js +9 -163
- 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 +1 -4
- package/dist/services/network-switch-service.js.map +1 -1
- package/dist/universal-wallet-connector.d.ts.map +1 -1
- package/dist/universal-wallet-connector.js +18 -11
- package/dist/universal-wallet-connector.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 +50 -6
- package/src/observability/focus-tracker.test.ts +95 -8
- package/src/observability/focus-tracker.ts +72 -22
- package/src/observability/instrument-handoff.test.ts +62 -0
- package/src/observability/instrument-handoff.ts +37 -6
- package/src/observability/lifecycle-bridge.test.ts +0 -197
- package/src/observability/lifecycle-bridge.ts +99 -211
- package/src/observability/relay-drop-tracker.test.ts +84 -0
- package/src/observability/relay-drop-tracker.ts +53 -0
- package/src/observability/telemetry.test.ts +18 -0
- package/src/observability/telemetry.ts +41 -6
- package/src/services/connection-service.test.ts +0 -272
- package/src/services/connection-service.ts +10 -190
- package/src/services/network-switch-service.test.ts +0 -33
- package/src/services/network-switch-service.ts +1 -4
- package/src/universal-wallet-connector.observability.test.ts +54 -8
- package/src/universal-wallet-connector.ts +22 -12
- package/src/version.ts +1 -1
|
@@ -26,12 +26,6 @@ export class ConnectionService {
|
|
|
26
26
|
private activeConnector: Connector | null = null
|
|
27
27
|
/** Tears down the post-connect lifecycle subscription; set while connected. */
|
|
28
28
|
private lifecycleTeardown: (() => void) | undefined
|
|
29
|
-
/**
|
|
30
|
-
* Teardowns for the accounts-sync attachments of the session's SECONDARY
|
|
31
|
-
* namespaces (see `attachSecondaryAccountSync`); set while connected,
|
|
32
|
-
* cleared together with `lifecycleTeardown`.
|
|
33
|
-
*/
|
|
34
|
-
private secondaryAccountSyncTeardowns: Array<() => void> = []
|
|
35
29
|
/**
|
|
36
30
|
* Abort handle for the CURRENT in-flight connect attempt. A re-entrant
|
|
37
31
|
* connect() aborts this before starting, so a superseded attempt's URI poll
|
|
@@ -206,11 +200,6 @@ export class ConnectionService {
|
|
|
206
200
|
// disconnect, expiry) from the live provider — telemetry only, never changes
|
|
207
201
|
// connection behaviour. Torn down on disconnect.
|
|
208
202
|
this.attachLifecycle(connectionMode, wallet.id, network.namespace)
|
|
209
|
-
this.attachSecondaryAccountSync(
|
|
210
|
-
connectionMode,
|
|
211
|
-
wallet.id,
|
|
212
|
-
network.namespace
|
|
213
|
-
)
|
|
214
203
|
}
|
|
215
204
|
|
|
216
205
|
/** Wire the active connector's lifecycle stream onto the bus (or signal absence). */
|
|
@@ -218,7 +207,7 @@ export class ConnectionService {
|
|
|
218
207
|
connectionMode: ConnectionMode,
|
|
219
208
|
walletId: string,
|
|
220
209
|
namespace: Namespace,
|
|
221
|
-
initialSwitch?: { chainId: NetworkId;
|
|
210
|
+
initialSwitch?: { chainId: NetworkId; at: number }
|
|
222
211
|
): void {
|
|
223
212
|
this.teardownLifecycle()
|
|
224
213
|
const connector = this.activeConnector
|
|
@@ -238,16 +227,6 @@ export class ConnectionService {
|
|
|
238
227
|
walletId
|
|
239
228
|
})
|
|
240
229
|
: undefined,
|
|
241
|
-
subscribeAccounts: connector?.onAccountsChanged
|
|
242
|
-
? listener =>
|
|
243
|
-
connector.onAccountsChanged!(listener, {
|
|
244
|
-
connectionMode,
|
|
245
|
-
namespace,
|
|
246
|
-
walletId
|
|
247
|
-
})
|
|
248
|
-
: undefined,
|
|
249
|
-
onAccountsChanged: accounts =>
|
|
250
|
-
this.handleAccountsChanged(accounts, namespace),
|
|
251
230
|
getRouting: () => {
|
|
252
231
|
const s = this.sessionManager.getSession()
|
|
253
232
|
return {
|
|
@@ -270,63 +249,6 @@ export class ConnectionService {
|
|
|
270
249
|
})
|
|
271
250
|
}
|
|
272
251
|
|
|
273
|
-
/**
|
|
274
|
-
* Apply a REAL account-list change (from `Connector.onAccountsChanged`, via
|
|
275
|
-
* the lifecycle bridge's second stream) to the session. `namespace` is the
|
|
276
|
-
* namespace of the provider that reported the change — `activeAddress`
|
|
277
|
-
* only moves when that matches the session's currently active network; an
|
|
278
|
-
* empty list is a full, wallet-initiated disconnect.
|
|
279
|
-
*/
|
|
280
|
-
private handleAccountsChanged(
|
|
281
|
-
accounts: string[],
|
|
282
|
-
namespace: Namespace
|
|
283
|
-
): void {
|
|
284
|
-
if (accounts.length === 0) {
|
|
285
|
-
// Idempotency guard: this runs synchronously FROM INSIDE the
|
|
286
|
-
// connector's own accountsChanged dispatch — finishDisconnect() below
|
|
287
|
-
// tears down (among other things) the very subscription that is
|
|
288
|
-
// currently delivering this callback. If a wallet double-fires the
|
|
289
|
-
// empty-array disconnect signal (or one slips through before teardown
|
|
290
|
-
// takes effect), `activeConnector` is already null from the first call
|
|
291
|
-
// — skip re-clearing an already-cleared session and re-emitting
|
|
292
|
-
// disconnected/sessionChanged a second time. Scoped to THIS wallet-
|
|
293
|
-
// initiated path only; the public disconnect() below still always
|
|
294
|
-
// runs finishDisconnect() defensively, even with no active connector.
|
|
295
|
-
if (this.activeConnector === null) return
|
|
296
|
-
// The wallet ended the session on its own side, but the connector's
|
|
297
|
-
// OWN local state (e.g. EthereumWalletService's cached account/
|
|
298
|
-
// provider/uuid) is never cleared by finishDisconnect() below — it
|
|
299
|
-
// only clears core's sessionManager. Left uncleared, a later connect
|
|
300
|
-
// to a DIFFERENT wallet reads that stale cached account via
|
|
301
|
-
// checkExistingConnections() and never rebinds to the new wallet's
|
|
302
|
-
// provider/uuid, silently keeping the old wallet's address live under
|
|
303
|
-
// the new wallet's session. disconnect() is fire-and-forget and
|
|
304
|
-
// error-swallowed here: for injected connectors it's local-only
|
|
305
|
-
// cleanup (safe to call any number of times), and for protocol-based
|
|
306
|
-
// connectors that might reject on an already-closed session, there is
|
|
307
|
-
// no caller to propagate that error to anyway.
|
|
308
|
-
this.activeConnector?.disconnect?.().catch(() => {})
|
|
309
|
-
this.finishDisconnect()
|
|
310
|
-
return
|
|
311
|
-
}
|
|
312
|
-
const newAddress = accounts[0]!
|
|
313
|
-
const session = this.sessionManager.getSession()
|
|
314
|
-
const availableAddresses = session.availableAddresses.map(addr => {
|
|
315
|
-
const network = this.networks.find(n => n.id === addr.networkId)
|
|
316
|
-
return network?.namespace === namespace
|
|
317
|
-
? { ...addr, address: newAddress }
|
|
318
|
-
: addr
|
|
319
|
-
})
|
|
320
|
-
const activeAddress =
|
|
321
|
-
session.activeNetwork?.namespace === namespace
|
|
322
|
-
? newAddress
|
|
323
|
-
: session.activeAddress
|
|
324
|
-
this.sessionManager.updateSession({ activeAddress, availableAddresses })
|
|
325
|
-
this.eventManager.emit('sessionChanged', {
|
|
326
|
-
session: this.sessionManager.getSession()
|
|
327
|
-
})
|
|
328
|
-
}
|
|
329
|
-
|
|
330
252
|
/**
|
|
331
253
|
* Remove the active provider-lifecycle subscription (EIP-1193 `.on` / wallet-
|
|
332
254
|
* adapter / SignClient listeners) WITHOUT disconnecting the wallet. Idempotent.
|
|
@@ -337,8 +259,6 @@ export class ConnectionService {
|
|
|
337
259
|
teardownLifecycle(): void {
|
|
338
260
|
this.lifecycleTeardown?.()
|
|
339
261
|
this.lifecycleTeardown = undefined
|
|
340
|
-
for (const teardown of this.secondaryAccountSyncTeardowns) teardown()
|
|
341
|
-
this.secondaryAccountSyncTeardowns = []
|
|
342
262
|
}
|
|
343
263
|
|
|
344
264
|
/**
|
|
@@ -363,93 +283,11 @@ export class ConnectionService {
|
|
|
363
283
|
session.connectionMode,
|
|
364
284
|
session.activeWallet.id,
|
|
365
285
|
session.activeNetwork.namespace,
|
|
366
|
-
// The reattach follows a JUST-completed switch to the now-active chain
|
|
367
|
-
//
|
|
368
|
-
//
|
|
369
|
-
|
|
370
|
-
{
|
|
371
|
-
chainId: session.activeNetwork.id,
|
|
372
|
-
...(session.activeAddress && { address: session.activeAddress }),
|
|
373
|
-
at: Date.now()
|
|
374
|
-
}
|
|
286
|
+
// The reattach follows a JUST-completed switch to the now-active chain —
|
|
287
|
+
// arm echo suppression for it so the new provider's echo isn't mistaken
|
|
288
|
+
// for a wallet-initiated change (one-shot, same as bus-armed switches).
|
|
289
|
+
{ chainId: session.activeNetwork.id, at: Date.now() }
|
|
375
290
|
)
|
|
376
|
-
// Re-derive the secondary set against the NOW-active namespace — a
|
|
377
|
-
// cross-namespace switch swaps which namespace is "secondary" (the
|
|
378
|
-
// attachLifecycle above already tore the previous set down via
|
|
379
|
-
// teardownLifecycle).
|
|
380
|
-
this.attachSecondaryAccountSync(
|
|
381
|
-
session.connectionMode,
|
|
382
|
-
session.activeWallet.id,
|
|
383
|
-
session.activeNetwork.namespace
|
|
384
|
-
)
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Attach account-sync for every OTHER namespace the session's
|
|
389
|
-
* `availableAddresses` span. `attachLifecycle` observes only the ACTIVE
|
|
390
|
-
* network's namespace, but the cross-namespace gather seeds addresses from
|
|
391
|
-
* other namespaces' live surfaces at connect time — without their own
|
|
392
|
-
* subscription, a wallet-side account switch on such a namespace is never
|
|
393
|
-
* observed and the session serves the connect-time addresses forever (e.g.
|
|
394
|
-
* a Solana-active MetaMask session whose eip155 addresses never follow the
|
|
395
|
-
* extension's account switch).
|
|
396
|
-
*
|
|
397
|
-
* Accounts-sync ONLY, no lifecycle-telemetry stream: the active namespace
|
|
398
|
-
* stays the single source of wallet* telemetry and of the wallet-initiated
|
|
399
|
-
* disconnect signal.
|
|
400
|
-
*/
|
|
401
|
-
private attachSecondaryAccountSync(
|
|
402
|
-
connectionMode: ConnectionMode,
|
|
403
|
-
walletId: string,
|
|
404
|
-
activeNamespace: Namespace
|
|
405
|
-
): void {
|
|
406
|
-
const connector = this.activeConnector
|
|
407
|
-
if (!connector?.onAccountsChanged) return
|
|
408
|
-
|
|
409
|
-
const session = this.sessionManager.getSession()
|
|
410
|
-
const secondaryNamespaces = new Set<Namespace>()
|
|
411
|
-
for (const addr of session.availableAddresses) {
|
|
412
|
-
const namespace = this.networks.find(
|
|
413
|
-
n => n.id === addr.networkId
|
|
414
|
-
)?.namespace
|
|
415
|
-
if (namespace && namespace !== activeNamespace) {
|
|
416
|
-
secondaryNamespaces.add(namespace)
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
const runtime =
|
|
421
|
-
(globalThis as { UWCBridgeChildInitialized?: boolean })
|
|
422
|
-
.UWCBridgeChildInitialized === true
|
|
423
|
-
? ('iframe' as const)
|
|
424
|
-
: ('direct' as const)
|
|
425
|
-
|
|
426
|
-
for (const namespace of secondaryNamespaces) {
|
|
427
|
-
this.secondaryAccountSyncTeardowns.push(
|
|
428
|
-
attachLifecycle({
|
|
429
|
-
eventManager: this.eventManager,
|
|
430
|
-
subscribe: undefined,
|
|
431
|
-
subscribeAccounts: listener =>
|
|
432
|
-
connector.onAccountsChanged!(listener, {
|
|
433
|
-
connectionMode,
|
|
434
|
-
namespace,
|
|
435
|
-
walletId
|
|
436
|
-
}),
|
|
437
|
-
onAccountsChanged: accounts => {
|
|
438
|
-
// An empty list from a SECONDARY namespace means that namespace's
|
|
439
|
-
// own authorization ended — NOT the session. Only the active
|
|
440
|
-
// namespace's stream may signal the full wallet-initiated
|
|
441
|
-
// disconnect (handleAccountsChanged's empty-list path).
|
|
442
|
-
if (accounts.length === 0) return
|
|
443
|
-
this.handleAccountsChanged(accounts, namespace)
|
|
444
|
-
},
|
|
445
|
-
getRouting: () => ({ connectionMode, walletId, namespace }),
|
|
446
|
-
connectionMode,
|
|
447
|
-
walletId,
|
|
448
|
-
namespace,
|
|
449
|
-
runtime
|
|
450
|
-
})
|
|
451
|
-
)
|
|
452
|
-
}
|
|
453
291
|
}
|
|
454
292
|
|
|
455
293
|
private async connectWithURIPoll(
|
|
@@ -648,32 +486,14 @@ export class ConnectionService {
|
|
|
648
486
|
await this.activeConnector.disconnect()
|
|
649
487
|
}
|
|
650
488
|
} finally {
|
|
651
|
-
this.
|
|
489
|
+
this.activeConnector = null
|
|
490
|
+
this.sessionManager.clearSession()
|
|
491
|
+
const session = this.sessionManager.getSession()
|
|
492
|
+
this.eventManager.emit('disconnected', undefined)
|
|
493
|
+
this.eventManager.emit('sessionChanged', { session })
|
|
652
494
|
}
|
|
653
495
|
}
|
|
654
496
|
|
|
655
|
-
/**
|
|
656
|
-
* Clears core's own local state (session, active connector reference,
|
|
657
|
-
* lifecycle subscription) and emits the disconnect events. Does NOT itself
|
|
658
|
-
* call the connector's `disconnect()` — that happens in each CALLER,
|
|
659
|
-
* because the two callers need different semantics: the public
|
|
660
|
-
* `disconnect()` above awaits it (the caller may care whether the wallet
|
|
661
|
-
* side actually tore down); the wallet-initiated path in
|
|
662
|
-
* `handleAccountsChanged` fires it and swallows the result (the wallet
|
|
663
|
-
* already ended the session on its own side, but the connector's own
|
|
664
|
-
* LOCAL state — e.g. a cached account/uuid — still needs clearing, or a
|
|
665
|
-
* later connect to a different wallet reads it as stale and never
|
|
666
|
-
* rebinds).
|
|
667
|
-
*/
|
|
668
|
-
private finishDisconnect(): void {
|
|
669
|
-
this.teardownLifecycle()
|
|
670
|
-
this.activeConnector = null
|
|
671
|
-
this.sessionManager.clearSession()
|
|
672
|
-
const session = this.sessionManager.getSession()
|
|
673
|
-
this.eventManager.emit('disconnected', undefined)
|
|
674
|
-
this.eventManager.emit('sessionChanged', { session })
|
|
675
|
-
}
|
|
676
|
-
|
|
677
497
|
getConnectionURI(): string | undefined {
|
|
678
498
|
if (
|
|
679
499
|
this.activeConnector &&
|
|
@@ -234,37 +234,4 @@ 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
|
-
})
|
|
270
237
|
})
|
|
@@ -188,10 +188,7 @@ export class NetworkSwitchService {
|
|
|
188
188
|
})
|
|
189
189
|
})
|
|
190
190
|
|
|
191
|
-
this.eventManager.emit('networkSwitched', {
|
|
192
|
-
network,
|
|
193
|
-
address: result.address
|
|
194
|
-
})
|
|
191
|
+
this.eventManager.emit('networkSwitched', { network })
|
|
195
192
|
this.eventManager.emit('sessionChanged', {
|
|
196
193
|
session: this.sessionManager.getSession()
|
|
197
194
|
})
|
|
@@ -26,10 +26,10 @@ const reattachLifecycleMock = vi.fn()
|
|
|
26
26
|
const switchNetworkMock = vi.fn()
|
|
27
27
|
const sendTransactionMock = vi.fn()
|
|
28
28
|
const getWalletCapabilitiesMock = vi.fn()
|
|
29
|
-
// Captures the
|
|
30
|
-
// (config, networkRpcMap,
|
|
31
|
-
//
|
|
32
|
-
//
|
|
29
|
+
// Captures the args the façade passes to the WalletConnect connector
|
|
30
|
+
// (config, networkRpcMap, telemetryObserver) so a test can invoke the relay
|
|
31
|
+
// telemetry sinks and assert the emitted event — this is the only place the
|
|
32
|
+
// sink→bus wiring is exercised.
|
|
33
33
|
const wcConnectorCapture: { args: unknown[] } = { args: [] }
|
|
34
34
|
|
|
35
35
|
const connectedSession: Session = {
|
|
@@ -187,10 +187,14 @@ describe('UniversalWalletConnector — observability wiring', () => {
|
|
|
187
187
|
walletConnectConfig: { projectId: 'test' }
|
|
188
188
|
})
|
|
189
189
|
|
|
190
|
-
// The façade passes the connector (config, networkRpcMap,
|
|
191
|
-
// onInitError
|
|
192
|
-
//
|
|
193
|
-
|
|
190
|
+
// The façade passes the connector (config, networkRpcMap, telemetryObserver).
|
|
191
|
+
// Grabbing the observer's onInitError sink and firing it guards the wiring;
|
|
192
|
+
// the named field can't be confused with onRelayError the way a positional
|
|
193
|
+
// arg could (the reason #3350 moved to a typed options object).
|
|
194
|
+
const telemetryObserver = wcConnectorCapture.args[2] as {
|
|
195
|
+
onInitError: (e: unknown) => void
|
|
196
|
+
}
|
|
197
|
+
const onInitError = telemetryObserver.onInitError
|
|
194
198
|
expect(typeof onInitError).toBe('function')
|
|
195
199
|
onInitError(
|
|
196
200
|
new Error(
|
|
@@ -207,6 +211,48 @@ describe('UniversalWalletConnector — observability wiring', () => {
|
|
|
207
211
|
expect(JSON.stringify(initError)).not.toContain('0xAbC123')
|
|
208
212
|
})
|
|
209
213
|
|
|
214
|
+
it('wires the relay observer sinks → each emits its own telemetry event to the observer', () => {
|
|
215
|
+
// The whole point of #3350: a single typed observer whose named sinks map
|
|
216
|
+
// 1:1 to bus events. Fire each and assert the right event lands — this is
|
|
217
|
+
// the connector→bus lambda wiring, previously only covered end-to-end.
|
|
218
|
+
const events: UWCTelemetryEvent[] = []
|
|
219
|
+
const observer: UWCObserver = { onEvent: e => events.push(e) }
|
|
220
|
+
new UniversalWalletConnector({
|
|
221
|
+
networks,
|
|
222
|
+
wallets,
|
|
223
|
+
observer,
|
|
224
|
+
walletConnectConfig: { projectId: 'test' }
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
const telemetryObserver = wcConnectorCapture.args[2] as {
|
|
228
|
+
onRelayError: (e: unknown) => void
|
|
229
|
+
onRelayDisconnect: () => void
|
|
230
|
+
onRelayReconnect: () => void
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
telemetryObserver.onRelayError(
|
|
234
|
+
new Error(
|
|
235
|
+
'WebSocket closed abnormally 0xAbC1230000000000000000000000000000000000'
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
telemetryObserver.onRelayDisconnect()
|
|
239
|
+
telemetryObserver.onRelayReconnect()
|
|
240
|
+
|
|
241
|
+
const relayError = events.find(e => e.name === 'relayError')
|
|
242
|
+
expect(relayError).toBeDefined()
|
|
243
|
+
expect(relayError!.connectionMode).toBe('walletConnect')
|
|
244
|
+
// Same egress scrubbing as every other error record.
|
|
245
|
+
expect(JSON.stringify(relayError)).not.toContain('0xAbC123')
|
|
246
|
+
|
|
247
|
+
const dropped = events.find(e => e.name === 'relayDisconnected')
|
|
248
|
+
expect(dropped).toBeDefined()
|
|
249
|
+
expect(dropped!.connectionMode).toBe('walletConnect')
|
|
250
|
+
|
|
251
|
+
const recovered = events.find(e => e.name === 'relayReconnected')
|
|
252
|
+
expect(recovered).toBeDefined()
|
|
253
|
+
expect(recovered!.connectionMode).toBe('walletConnect')
|
|
254
|
+
})
|
|
255
|
+
|
|
210
256
|
it('stamps a consumer-supplied correlationId (string) as its own field', async () => {
|
|
211
257
|
const events: UWCTelemetryEvent[] = []
|
|
212
258
|
const uwc = new UniversalWalletConnector({
|
|
@@ -314,18 +314,28 @@ export class UniversalWalletConnector {
|
|
|
314
314
|
new WalletConnectConnector(
|
|
315
315
|
configuredWalletConnectConfig,
|
|
316
316
|
this.networkRpcMap,
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
317
|
+
{
|
|
318
|
+
// Surface relay-socket failures (e.g. code 3000 JWT clock skew) that are
|
|
319
|
+
// detached from the connect handoff, as a telemetry event.
|
|
320
|
+
onRelayError: (error: unknown) =>
|
|
321
|
+
this.eventManager.emit('relayError', {
|
|
322
|
+
error: toWalletError(error)
|
|
323
|
+
}),
|
|
324
|
+
// Surface a failed SignClient.init as its own signal — otherwise it has no
|
|
325
|
+
// dedicated telemetry and only appears as a generic connect failure.
|
|
326
|
+
onInitError: (error: unknown) =>
|
|
327
|
+
this.eventManager.emit('walletConnectInitError', {
|
|
328
|
+
error: toWalletError(error)
|
|
329
|
+
}),
|
|
330
|
+
// Relay transport dropped (once per outage) — the FACT is the signal; the
|
|
331
|
+
// relayer carries no payload, so emit the bare event (CARE-263).
|
|
332
|
+
onRelayDisconnect: () =>
|
|
333
|
+
this.eventManager.emit('relayDisconnected', undefined),
|
|
334
|
+
// Relay transport recovered — pair with `relayDisconnected` (same
|
|
335
|
+
// sdkSessionId) to measure the dead window.
|
|
336
|
+
onRelayReconnect: () =>
|
|
337
|
+
this.eventManager.emit('relayReconnected', undefined)
|
|
338
|
+
}
|
|
329
339
|
)
|
|
330
340
|
)
|
|
331
341
|
}
|
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.
|
|
2
|
+
export const UWC_CORE_VERSION = '1.3.0'
|