@meshconnect/uwc-core 1.0.3 → 1.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.
Files changed (121) hide show
  1. package/README.md +247 -76
  2. package/dist/events.d.ts +241 -5
  3. package/dist/events.d.ts.map +1 -1
  4. package/dist/events.js +77 -1
  5. package/dist/events.js.map +1 -1
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/logger/create-logger.d.ts +32 -0
  11. package/dist/logger/create-logger.d.ts.map +1 -0
  12. package/dist/logger/create-logger.js +79 -0
  13. package/dist/logger/create-logger.js.map +1 -0
  14. package/dist/managers/event-manager.d.ts.map +1 -1
  15. package/dist/managers/event-manager.js +5 -1
  16. package/dist/managers/event-manager.js.map +1 -1
  17. package/dist/observability/connect-observer.d.ts +33 -0
  18. package/dist/observability/connect-observer.d.ts.map +1 -0
  19. package/dist/observability/connect-observer.js +115 -0
  20. package/dist/observability/connect-observer.js.map +1 -0
  21. package/dist/observability/focus-tracker.d.ts +42 -0
  22. package/dist/observability/focus-tracker.d.ts.map +1 -0
  23. package/dist/observability/focus-tracker.js +57 -0
  24. package/dist/observability/focus-tracker.js.map +1 -0
  25. package/dist/observability/instrument-handoff.d.ts +54 -0
  26. package/dist/observability/instrument-handoff.d.ts.map +1 -0
  27. package/dist/observability/instrument-handoff.js +173 -0
  28. package/dist/observability/instrument-handoff.js.map +1 -0
  29. package/dist/observability/lifecycle-bridge.d.ts +69 -0
  30. package/dist/observability/lifecycle-bridge.d.ts.map +1 -0
  31. package/dist/observability/lifecycle-bridge.js +155 -0
  32. package/dist/observability/lifecycle-bridge.js.map +1 -0
  33. package/dist/observability/scrub.d.ts +31 -0
  34. package/dist/observability/scrub.d.ts.map +1 -0
  35. package/dist/observability/scrub.js +167 -0
  36. package/dist/observability/scrub.js.map +1 -0
  37. package/dist/observability/telemetry.d.ts +157 -0
  38. package/dist/observability/telemetry.d.ts.map +1 -0
  39. package/dist/observability/telemetry.js +373 -0
  40. package/dist/observability/telemetry.js.map +1 -0
  41. package/dist/services/connection-service.d.ts +23 -1
  42. package/dist/services/connection-service.d.ts.map +1 -1
  43. package/dist/services/connection-service.js +128 -19
  44. package/dist/services/connection-service.js.map +1 -1
  45. package/dist/services/network-switch-service.d.ts +2 -1
  46. package/dist/services/network-switch-service.d.ts.map +1 -1
  47. package/dist/services/network-switch-service.js +45 -16
  48. package/dist/services/network-switch-service.js.map +1 -1
  49. package/dist/services/signature-service.d.ts +14 -7
  50. package/dist/services/signature-service.d.ts.map +1 -1
  51. package/dist/services/signature-service.js +56 -58
  52. package/dist/services/signature-service.js.map +1 -1
  53. package/dist/services/transaction-service.d.ts +19 -5
  54. package/dist/services/transaction-service.d.ts.map +1 -1
  55. package/dist/services/transaction-service.js +55 -38
  56. package/dist/services/transaction-service.js.map +1 -1
  57. package/dist/universal-wallet-connector.d.ts +56 -1
  58. package/dist/universal-wallet-connector.d.ts.map +1 -1
  59. package/dist/universal-wallet-connector.js +207 -110
  60. package/dist/universal-wallet-connector.js.map +1 -1
  61. package/dist/utils/id.d.ts +2 -0
  62. package/dist/utils/id.d.ts.map +1 -0
  63. package/dist/utils/id.js +41 -0
  64. package/dist/utils/id.js.map +1 -0
  65. package/dist/utils/resolve-session-provider.d.ts +10 -0
  66. package/dist/utils/resolve-session-provider.d.ts.map +1 -0
  67. package/dist/utils/resolve-session-provider.js +21 -0
  68. package/dist/utils/resolve-session-provider.js.map +1 -0
  69. package/dist/utils/to-wallet-error.d.ts +35 -0
  70. package/dist/utils/to-wallet-error.d.ts.map +1 -0
  71. package/dist/utils/to-wallet-error.js +130 -0
  72. package/dist/utils/to-wallet-error.js.map +1 -0
  73. package/dist/utils/validate-wallet-session.d.ts +15 -0
  74. package/dist/utils/validate-wallet-session.d.ts.map +1 -0
  75. package/dist/utils/validate-wallet-session.js +29 -0
  76. package/dist/utils/validate-wallet-session.js.map +1 -0
  77. package/dist/version.d.ts +2 -0
  78. package/dist/version.d.ts.map +1 -0
  79. package/dist/version.js +3 -0
  80. package/dist/version.js.map +1 -0
  81. package/package.json +6 -6
  82. package/src/events.ts +326 -14
  83. package/src/index.ts +10 -0
  84. package/src/logger/create-logger.test.ts +126 -0
  85. package/src/logger/create-logger.ts +112 -0
  86. package/src/managers/event-manager.test.ts +55 -0
  87. package/src/managers/event-manager.ts +5 -1
  88. package/src/observability/connect-observer.test.ts +214 -0
  89. package/src/observability/connect-observer.ts +128 -0
  90. package/src/observability/focus-tracker.test.ts +191 -0
  91. package/src/observability/focus-tracker.ts +96 -0
  92. package/src/observability/instrument-handoff.test.ts +397 -0
  93. package/src/observability/instrument-handoff.ts +231 -0
  94. package/src/observability/lifecycle-bridge.test.ts +398 -0
  95. package/src/observability/lifecycle-bridge.ts +216 -0
  96. package/src/observability/scrub.test.ts +183 -0
  97. package/src/observability/scrub.ts +174 -0
  98. package/src/observability/telemetry.test.ts +549 -0
  99. package/src/observability/telemetry.ts +546 -0
  100. package/src/services/connection-service.test.ts +261 -1
  101. package/src/services/connection-service.ts +167 -38
  102. package/src/services/network-switch-service.test.ts +51 -1
  103. package/src/services/network-switch-service.ts +56 -24
  104. package/src/services/signature-service.test.ts +181 -76
  105. package/src/services/signature-service.ts +75 -85
  106. package/src/services/transaction-service.test.ts +270 -69
  107. package/src/services/transaction-service.ts +74 -51
  108. package/src/universal-wallet-connector.instrumentation-guard.test.ts +199 -0
  109. package/src/universal-wallet-connector.observability.test.ts +610 -0
  110. package/src/universal-wallet-connector.test.ts +27 -146
  111. package/src/universal-wallet-connector.ts +279 -142
  112. package/src/utils/id.test.ts +15 -0
  113. package/src/utils/id.ts +48 -0
  114. package/src/utils/resolve-session-provider.test.ts +54 -0
  115. package/src/utils/resolve-session-provider.ts +25 -0
  116. package/src/utils/to-wallet-error.test.ts +181 -0
  117. package/src/utils/to-wallet-error.ts +152 -0
  118. package/src/utils/validate-wallet-session.test.ts +77 -0
  119. package/src/utils/validate-wallet-session.ts +40 -0
  120. package/src/version.test.ts +11 -0
  121. package/src/version.ts +2 -0
@@ -0,0 +1,373 @@
1
+ import { UWC_CORE_VERSION } from '../version';
2
+ import { scrubMessage } from './scrub';
3
+ /**
4
+ * Telemetry record schema version. Bump on any breaking change to the
5
+ * `UWCTelemetryEvent` shape so a downstream consumer can branch on it.
6
+ */
7
+ export const TELEMETRY_SCHEMA_VERSION = 1;
8
+ /**
9
+ * Egress bounds for `networkMismatch`. `walletNetworkIds` comes from catalog
10
+ * wallet metadata (`provider.supportedNetworkIds`), not live wallet input — but
11
+ * it is unbounded upstream, so cap cardinality and element length here as
12
+ * defense-in-depth. Elements are NOT scrubbed: a legitimate
13
+ * `solana:<32-char-base58-ref>` CAIP-2 id would be eaten by the base58 rule.
14
+ */
15
+ const MAX_NETWORK_MISMATCH_IDS = 20;
16
+ const MAX_NETWORK_ID_LENGTH = 64;
17
+ function capNetworkMismatch(mismatch) {
18
+ if (!mismatch)
19
+ return undefined;
20
+ const cap = (ids) => ids
21
+ .slice(0, MAX_NETWORK_MISMATCH_IDS)
22
+ .map(id => id.slice(0, MAX_NETWORK_ID_LENGTH));
23
+ return {
24
+ walletNetworkIds: cap(mismatch.walletNetworkIds),
25
+ configuredNetworkIds: cap(mismatch.configuredNetworkIds)
26
+ };
27
+ }
28
+ /**
29
+ * Best-effort coarse runtime surface. HEURISTIC — user agents lie and in-app
30
+ * browsers are hard to detect; treat `webview` as a hint, not a guarantee.
31
+ * Never returns the raw UA (PII / high-cardinality).
32
+ */
33
+ export function derivePlatform() {
34
+ if (typeof navigator === 'undefined' || !navigator.userAgent)
35
+ return 'unknown';
36
+ const ua = navigator.userAgent;
37
+ const isIOS = /iPhone|iPad|iPod/i.test(ua);
38
+ const isAndroid = /Android/i.test(ua);
39
+ // Android in-app browsers tag the UA with `; wv`; iOS WKWebViews lack `Safari`.
40
+ const isWebview = (isAndroid && /; wv\)/i.test(ua)) || (isIOS && !/Safari/i.test(ua));
41
+ if (isWebview)
42
+ return 'webview';
43
+ if (isIOS || isAndroid)
44
+ return 'mobile';
45
+ return 'desktop';
46
+ }
47
+ /**
48
+ * Derive the flow taxonomy from connection mode + surface. HEURISTIC — UWC does
49
+ * not always know whether a WalletConnect handoff used a deeplink vs a QR scan;
50
+ * we infer from the platform (mobile ⇒ deeplink, desktop ⇒ QR), matching link-v2's
51
+ * historical intent. Consumers with better context may override downstream.
52
+ */
53
+ export function deriveWalletFlowType(connectionMode, platform) {
54
+ const isDesktop = platform === 'desktop';
55
+ switch (connectionMode) {
56
+ case 'injected':
57
+ // Injected on a phone almost always means we're inside a wallet's browser.
58
+ return isDesktop ? 'browser_extension_flow' : 'in_wallet_browser_flow';
59
+ case 'walletConnect':
60
+ return isDesktop
61
+ ? 'wallet_connect_qr_flow'
62
+ : 'wallet_connect_deep_link_flow';
63
+ case 'tonConnect':
64
+ return isDesktop ? 'ton_connect_qr_flow' : 'ton_connect_deep_link_flow';
65
+ default:
66
+ return 'unknown';
67
+ }
68
+ }
69
+ /**
70
+ * Per-namespace address coverage for a session — telemetry-only, non-PII
71
+ * (namespace names + counts, never an address). Derived purely from the session:
72
+ * `availableNetworks` is the connected wallet's supported networks already
73
+ * filtered to the session's configured set, and `availableAddresses` is what the
74
+ * connect actually gathered, so `missing` is precise per-connect (no cross-wallet
75
+ * discovery join that could false-positive on a different installed wallet).
76
+ *
77
+ * `missing` is the observable symptom of a dropped secondary-namespace gather:
78
+ * the wallet supports the namespace for a configured network, but no address for
79
+ * it came back.
80
+ */
81
+ function summarizeAddressCoverage(session) {
82
+ // Defensive `?? []`: this runs on the wallet path, so a partial/malformed
83
+ // session must never throw here (a real session always has both arrays).
84
+ const addressNamespaces = {};
85
+ const present = new Set();
86
+ for (const { networkId } of session.availableAddresses ?? []) {
87
+ const namespace = networkId.split(':')[0];
88
+ if (!namespace)
89
+ continue;
90
+ present.add(namespace);
91
+ addressNamespaces[namespace] = (addressNamespaces[namespace] ?? 0) + 1;
92
+ }
93
+ const supported = new Set((session.availableNetworks ?? []).map(n => n.namespace));
94
+ const missing = [...supported].filter(namespace => !present.has(namespace));
95
+ return { addressNamespaces, missing };
96
+ }
97
+ /**
98
+ * Map a raw `UWCEventMap` event to its PII-safe `UWCTelemetryEvent`.
99
+ *
100
+ * Per-event allow-listing: only known-safe fields are copied. Payloads carrying a
101
+ * `Session`/`Network` (which include the wallet address) are reduced to
102
+ * `namespace` + `chainId` + `walletId`. Unknown/noisy payloads collapse to just
103
+ * the name. `error.message` is scrubbed.
104
+ */
105
+ function buildTelemetryEvent(name, data, sdkSessionId, now, correlationId) {
106
+ // `correlationId` is added to the key only when supplied — never aliased to
107
+ // `sdkSessionId`, so a consumer can tell "I gave no id" from "id == session".
108
+ const base = {
109
+ schemaVersion: TELEMETRY_SCHEMA_VERSION,
110
+ uwcVersion: UWC_CORE_VERSION,
111
+ name,
112
+ sdkSessionId,
113
+ timestamp: now,
114
+ ...(correlationId !== undefined ? { correlationId } : {})
115
+ };
116
+ switch (name) {
117
+ case 'connecting': {
118
+ const d = data;
119
+ return {
120
+ ...base,
121
+ operation: 'connect',
122
+ connectionMode: d.connectionMode,
123
+ walletId: d.walletId
124
+ };
125
+ }
126
+ case 'connected':
127
+ case 'sessionChanged': {
128
+ const d = data;
129
+ const session = d.session;
130
+ const { addressNamespaces, missing } = summarizeAddressCoverage(session);
131
+ return {
132
+ ...base,
133
+ connectionMode: session.connectionMode ?? undefined,
134
+ namespace: session.activeNetwork?.namespace,
135
+ chainId: session.activeNetwork?.id,
136
+ walletId: session.activeWallet?.id,
137
+ addressNamespaces,
138
+ ...(missing.length > 0 && { missingNamespaces: missing })
139
+ };
140
+ }
141
+ case 'networkSwitched': {
142
+ const d = data;
143
+ return {
144
+ ...base,
145
+ operation: 'switchNetwork',
146
+ namespace: d.network.namespace,
147
+ chainId: d.network.id
148
+ };
149
+ }
150
+ case 'connectionUri': {
151
+ // Carry the mode but NEVER the URI itself (a relay/pairing string).
152
+ const d = data;
153
+ return { ...base, connectionMode: d.connectionMode };
154
+ }
155
+ case 'error': {
156
+ const d = data;
157
+ return {
158
+ ...base,
159
+ operation: d.operation,
160
+ error: { type: d.error.type, message: scrubMessage(d.error.message) },
161
+ // Telemetry-only classification — undefined for ordinary errors, set for
162
+ // pre-wallet validation failures (e.g. no_common_network) that never
163
+ // reach the handoff funnel.
164
+ errorCode: d.errorCode,
165
+ failureKind: d.failureKind,
166
+ source: d.source,
167
+ networkMismatch: capNetworkMismatch(d.networkMismatch),
168
+ handoffCovered: d.handoffCovered
169
+ };
170
+ }
171
+ case 'awaitingWallet': {
172
+ const d = data;
173
+ return {
174
+ ...base,
175
+ operation: d.operation,
176
+ connectionMode: d.connectionMode,
177
+ walletId: d.walletId,
178
+ namespace: d.namespace,
179
+ chainId: d.chainId,
180
+ handoffId: d.handoffId,
181
+ walletFlowType: d.walletFlowType,
182
+ platform: d.platform,
183
+ targetAlreadyActive: d.targetAlreadyActive
184
+ };
185
+ }
186
+ case 'walletSucceeded': {
187
+ const d = data;
188
+ return {
189
+ ...base,
190
+ operation: d.operation,
191
+ connectionMode: d.connectionMode,
192
+ walletId: d.walletId,
193
+ namespace: d.namespace,
194
+ chainId: d.chainId,
195
+ handoffId: d.handoffId,
196
+ durationMs: d.durationMs,
197
+ timedOut: d.timedOut,
198
+ timeoutMs: d.timeoutMs,
199
+ targetAlreadyActive: d.targetAlreadyActive
200
+ };
201
+ }
202
+ case 'walletRejected': {
203
+ const d = data;
204
+ return {
205
+ ...base,
206
+ operation: d.operation,
207
+ connectionMode: d.connectionMode,
208
+ walletId: d.walletId,
209
+ namespace: d.namespace,
210
+ chainId: d.chainId,
211
+ handoffId: d.handoffId,
212
+ durationMs: d.durationMs,
213
+ timedOut: d.timedOut,
214
+ timeoutMs: d.timeoutMs,
215
+ targetAlreadyActive: d.targetAlreadyActive,
216
+ errorCode: d.errorCode,
217
+ failureKind: d.failureKind,
218
+ source: d.source
219
+ };
220
+ }
221
+ case 'walletTimedOut': {
222
+ const d = data;
223
+ return {
224
+ ...base,
225
+ operation: d.operation,
226
+ connectionMode: d.connectionMode,
227
+ walletId: d.walletId,
228
+ namespace: d.namespace,
229
+ chainId: d.chainId,
230
+ handoffId: d.handoffId,
231
+ durationMs: d.durationMs,
232
+ timeoutMs: d.timeoutMs,
233
+ targetAlreadyActive: d.targetAlreadyActive
234
+ };
235
+ }
236
+ case 'walletFailed': {
237
+ const d = data;
238
+ return {
239
+ ...base,
240
+ operation: d.operation,
241
+ connectionMode: d.connectionMode,
242
+ walletId: d.walletId,
243
+ namespace: d.namespace,
244
+ chainId: d.chainId,
245
+ handoffId: d.handoffId,
246
+ durationMs: d.durationMs,
247
+ timedOut: d.timedOut,
248
+ timeoutMs: d.timeoutMs,
249
+ targetAlreadyActive: d.targetAlreadyActive,
250
+ errorCode: d.errorCode,
251
+ failureKind: d.failureKind,
252
+ source: d.source,
253
+ error: { type: d.error.type, message: scrubMessage(d.error.message) }
254
+ };
255
+ }
256
+ case 'capabilitiesUpdated': {
257
+ const d = data;
258
+ // Summarize to per-chain lists of the capability names that are not
259
+ // 'unsupported'. Compact + non-PII (chain ids + bounded feature names).
260
+ const capabilities = {};
261
+ for (const [chainId, caps] of Object.entries(d.capabilities)) {
262
+ const enabled = Object.entries(caps)
263
+ .filter(([, cap]) => cap && cap.status !== 'unsupported')
264
+ .map(([feature]) => feature);
265
+ if (enabled.length > 0)
266
+ capabilities[chainId] = enabled;
267
+ }
268
+ return { ...base, capabilities };
269
+ }
270
+ case 'walletsDetected': {
271
+ const d = data;
272
+ // Carry only the compact requested-vs-matched summary; never the wallet list.
273
+ return { ...base, ...(d.discovery ? { discovery: d.discovery } : {}) };
274
+ }
275
+ case 'walletDiscoveryFailed': {
276
+ const d = data;
277
+ return {
278
+ ...base,
279
+ connectionMode: d.connectionMode,
280
+ namespace: d.namespace,
281
+ error: { type: d.error.type, message: scrubMessage(d.error.message) }
282
+ };
283
+ }
284
+ case 'pageHiddenDuringHandoff':
285
+ case 'pageVisibleDuringHandoff': {
286
+ const d = data;
287
+ return { ...base, handoffId: d.handoffId, platform: d.platform };
288
+ }
289
+ case 'bridgeError': {
290
+ const d = data;
291
+ return {
292
+ ...base,
293
+ namespace: d.namespace,
294
+ source: 'bridge',
295
+ failureKind: 'bridge_error',
296
+ error: { type: d.error.type, message: scrubMessage(d.error.message) }
297
+ };
298
+ }
299
+ case 'relayError': {
300
+ const d = data;
301
+ // A relay-socket transport failure (WalletConnect only). The scrubbed message
302
+ // carries the diagnostic detail (e.g. "code: 3000 (JWT ... not yet valid)").
303
+ return {
304
+ ...base,
305
+ connectionMode: 'walletConnect',
306
+ source: 'provider',
307
+ failureKind: 'network_error',
308
+ error: { type: d.error.type, message: scrubMessage(d.error.message) }
309
+ };
310
+ }
311
+ case 'walletAccountChanged':
312
+ case 'walletDisconnected':
313
+ case 'walletSessionExpired': {
314
+ const d = data;
315
+ return {
316
+ ...base,
317
+ connectionMode: d.connectionMode,
318
+ walletId: d.walletId,
319
+ namespace: d.namespace
320
+ };
321
+ }
322
+ case 'walletChainChanged': {
323
+ const d = data;
324
+ return {
325
+ ...base,
326
+ connectionMode: d.connectionMode,
327
+ walletId: d.walletId,
328
+ namespace: d.namespace,
329
+ chainId: d.chainId
330
+ };
331
+ }
332
+ case 'lifecycleTelemetryUnavailable': {
333
+ const d = data;
334
+ return {
335
+ ...base,
336
+ connectionMode: d.connectionMode,
337
+ walletId: d.walletId,
338
+ namespace: d.namespace,
339
+ reason: d.reason,
340
+ runtime: d.runtime
341
+ };
342
+ }
343
+ default:
344
+ // ready / disconnected / networkSwitching / change / log — name only
345
+ // (log goes via onLog).
346
+ return base;
347
+ }
348
+ }
349
+ /**
350
+ * Drop keys whose value is `undefined` so a record never carries a
351
+ * present-but-undefined optional (e.g. `errorCode: undefined` on a non-error
352
+ * event), which would make `'errorCode' in event` misleading. Shallow by design:
353
+ * nested objects (`error`, `networkMismatch`, `discovery`, `capabilities`,
354
+ * `addressNamespaces`) are only ever built with defined values.
355
+ */
356
+ function compactUndefined(event) {
357
+ const record = event;
358
+ const out = {};
359
+ for (const key of Object.keys(record)) {
360
+ const value = record[key];
361
+ if (value !== undefined)
362
+ out[key] = value;
363
+ }
364
+ return out;
365
+ }
366
+ /**
367
+ * Normalize a bus event into a PII-safe `UWCTelemetryEvent`, dropping undefined
368
+ * optionals so the emitted shape is consistent across event kinds.
369
+ */
370
+ export function normalizeEvent(name, data, sdkSessionId, now, correlationId) {
371
+ return compactUndefined(buildTelemetryEvent(name, data, sdkSessionId, now, correlationId));
372
+ }
373
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/observability/telemetry.ts"],"names":[],"mappings":"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"}
@@ -11,9 +11,31 @@ export declare class ConnectionService {
11
11
  private connectors;
12
12
  private usingIntegratedBrowser;
13
13
  private eventManager;
14
+ private walletResponseTimeoutMs;
14
15
  private activeConnector;
15
- constructor(networks: Network[], wallets: WalletMetadata[], sessionManager: SessionManager, connectors: Map<ConnectionMode, Connector>, usingIntegratedBrowser: boolean, eventManager: EventManager);
16
+ /** Tears down the post-connect lifecycle subscription; set while connected. */
17
+ private lifecycleTeardown;
18
+ constructor(networks: Network[], wallets: WalletMetadata[], sessionManager: SessionManager, connectors: Map<ConnectionMode, Connector>, usingIntegratedBrowser: boolean, eventManager: EventManager, walletResponseTimeoutMs: number);
16
19
  connect(connectionMode: ConnectionMode, walletId: string, networkId?: NetworkId, options?: ServiceOptions): Promise<void>;
20
+ /** Wire the active connector's lifecycle stream onto the bus (or signal absence). */
21
+ private attachLifecycle;
22
+ /**
23
+ * Remove the active provider-lifecycle subscription (EIP-1193 `.on` / wallet-
24
+ * adapter / SignClient listeners) WITHOUT disconnecting the wallet. Idempotent.
25
+ * Exposed so a full `dispose()` that bypasses `disconnect()` still releases these
26
+ * listeners — leaving them attached is the zombie-listener class this layer
27
+ * exists to prevent.
28
+ */
29
+ teardownLifecycle(): void;
30
+ /**
31
+ * Re-evaluate the lifecycle source for the CURRENT session. Used after a
32
+ * cross-namespace switchNetwork: the live provider changes with the namespace,
33
+ * so the connect-time subscription would keep observing the old namespace's
34
+ * provider and label its events with the new session's routing. Tears the old
35
+ * subscription down and re-attaches against the active session's facets.
36
+ * Safe no-op when nothing is connected.
37
+ */
38
+ reattachLifecycle(): void;
17
39
  private connectWithURIPoll;
18
40
  private getConnector;
19
41
  private findWallet;
@@ -1 +1 @@
1
- {"version":3,"file":"connection-service.d.ts","sourceRoot":"","sources":["../../src/services/connection-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,cAAc,EACd,cAAc,EACd,SAAS,EAMV,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAG7D,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,YAAY;IARtB,OAAO,CAAC,eAAe,CAAyB;gBAGtC,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,cAAc,EAAE,EACzB,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,EAC1C,sBAAsB,EAAE,OAAO,EAC/B,YAAY,EAAE,YAAY;IAG9B,OAAO,CACX,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,SAAS,EACrB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC;YAuFF,kBAAkB;IAqDhC,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,kBAAkB;IA2C1B,OAAO,CAAC,2BAA2B;IA6C7B,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBzD,gBAAgB,IAAI,MAAM,GAAG,SAAS;IAiBtC,UAAU,IAAI,cAAc,EAAE;IAI9B,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI;IAI9C,WAAW,IAAI,OAAO,EAAE;IAIxB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,wBAAwB;CAiBjC"}
1
+ {"version":3,"file":"connection-service.d.ts","sourceRoot":"","sources":["../../src/services/connection-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EAET,cAAc,EACd,cAAc,EACd,SAAS,EAMV,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAK7D,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED,qBAAa,iBAAiB;IAM1B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,sBAAsB;IAC9B,OAAO,CAAC,YAAY;IAEpB,OAAO,CAAC,uBAAuB;IAZjC,OAAO,CAAC,eAAe,CAAyB;IAChD,+EAA+E;IAC/E,OAAO,CAAC,iBAAiB,CAA0B;gBAGzC,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,cAAc,EAAE,EACzB,cAAc,EAAE,cAAc,EAC9B,UAAU,EAAE,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,EAC1C,sBAAsB,EAAE,OAAO,EAC/B,YAAY,EAAE,YAAY,EAE1B,uBAAuB,EAAE,MAAM;IAGnC,OAAO,CACX,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,SAAS,EACrB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC;IAiHhB,qFAAqF;IACrF,OAAO,CAAC,eAAe;IA8CvB;;;;;;OAMG;IACH,iBAAiB,IAAI,IAAI;IAKzB;;;;;;;OAOG;IACH,iBAAiB,IAAI,IAAI;YAqBX,kBAAkB;IAqDhC,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,kBAAkB;IA2C1B,OAAO,CAAC,2BAA2B;IAiD7B,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBzD,gBAAgB,IAAI,MAAM,GAAG,SAAS;IAiBtC,UAAU,IAAI,cAAc,EAAE;IAI9B,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,IAAI;IAI9C,WAAW,IAAI,OAAO,EAAE;IAIxB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,wBAAwB;CAiBjC"}
@@ -1,4 +1,7 @@
1
+ import { NoCommonNetworkError } from '@meshconnect/uwc-types';
1
2
  import { raceAbort } from '../utils/abort';
3
+ import { instrumentHandoff } from '../observability/instrument-handoff';
4
+ import { attachLifecycle } from '../observability/lifecycle-bridge';
2
5
  export class ConnectionService {
3
6
  networks;
4
7
  wallets;
@@ -6,14 +9,20 @@ export class ConnectionService {
6
9
  connectors;
7
10
  usingIntegratedBrowser;
8
11
  eventManager;
12
+ walletResponseTimeoutMs;
9
13
  activeConnector = null;
10
- constructor(networks, wallets, sessionManager, connectors, usingIntegratedBrowser, eventManager) {
14
+ /** Tears down the post-connect lifecycle subscription; set while connected. */
15
+ lifecycleTeardown;
16
+ constructor(networks, wallets, sessionManager, connectors, usingIntegratedBrowser, eventManager,
17
+ // Observational wallet-response deadline for the handoff timeout marker.
18
+ walletResponseTimeoutMs) {
11
19
  this.networks = networks;
12
20
  this.wallets = wallets;
13
21
  this.sessionManager = sessionManager;
14
22
  this.connectors = connectors;
15
23
  this.usingIntegratedBrowser = usingIntegratedBrowser;
16
24
  this.eventManager = eventManager;
25
+ this.walletResponseTimeoutMs = walletResponseTimeoutMs;
17
26
  }
18
27
  async connect(connectionMode, walletId, networkId, options) {
19
28
  options?.signal?.throwIfAborted();
@@ -33,28 +42,46 @@ export class ConnectionService {
33
42
  this.activeConnector = connector;
34
43
  let result;
35
44
  try {
36
- // Race the connector call against the AbortSignal so a mid-flight abort
37
- // (e.g. user cancels the WalletConnect QR while the prompt is open)
38
- // rejects the caller's await promptly. The underlying wallet prompt
39
- // itself can't be cancelled, but the dapp UI is no longer blocked on it.
40
- if (connectionMode === 'injected') {
41
- result = await raceAbort(connector.connect(network, provider), options?.signal);
42
- }
43
- else if (connectionMode === 'tonConnect' ||
44
- connectionMode === 'walletConnect') {
45
- result = await raceAbort(this.connectWithURIPoll(connector, network, provider, connectionMode, options?.signal), options?.signal);
46
- }
47
- else {
48
- throw new Error(`Unsupported connection mode: ${connectionMode}`);
49
- }
45
+ // Instrument the wallet hand-off HERE after validation + the `connecting`
46
+ // emit so `awaitingWallet` marks the real wallet boundary. A pre-wallet
47
+ // lookup/validation failure throws above and never enters the funnel. The
48
+ // resolved `network` gives accurate namespace/chainId facets.
49
+ result = await instrumentHandoff({
50
+ eventManager: this.eventManager,
51
+ timeoutMs: this.walletResponseTimeoutMs,
52
+ signal: options?.signal
53
+ }, {
54
+ operation: 'connect',
55
+ connectionMode,
56
+ walletId,
57
+ namespace: network.namespace,
58
+ chainId: network.id
59
+ }, async () => {
60
+ // Race the connector call against the AbortSignal so a mid-flight abort
61
+ // (e.g. user cancels the WalletConnect QR while the prompt is open)
62
+ // rejects the caller's await promptly. The underlying wallet prompt
63
+ // itself can't be cancelled, but the dapp UI is no longer blocked on it.
64
+ if (connectionMode === 'injected') {
65
+ return await raceAbort(connector.connect(network, provider), options?.signal);
66
+ }
67
+ else if (connectionMode === 'tonConnect' ||
68
+ connectionMode === 'walletConnect') {
69
+ return await raceAbort(this.connectWithURIPoll(connector, network, provider, connectionMode, options?.signal), options?.signal);
70
+ }
71
+ else {
72
+ throw new Error(`Unsupported connection mode: ${connectionMode}`);
73
+ }
74
+ });
75
+ // Belt-and-suspenders: if the signal fired between raceAbort resolving
76
+ // and this point, still bail before mutating session. Inside the try so
77
+ // the half-attached connector is released on this late abort too — a
78
+ // stale activeConnector would keep serving the aborted attempt's URI.
79
+ options?.signal?.throwIfAborted();
50
80
  }
51
81
  catch (error) {
52
82
  this.activeConnector = null;
53
83
  throw error;
54
84
  }
55
- // Belt-and-suspenders: if the signal fired between raceAbort resolving
56
- // and this point, still bail before mutating session.
57
- options?.signal?.throwIfAborted();
58
85
  // Filter available addresses to only include those for configured networks
59
86
  const filteredAvailableAddresses = result.availableAddresses.filter(addr => this.networks.some(n => n.id === addr.networkId));
60
87
  this.sessionManager.updateSession({
@@ -69,6 +96,82 @@ export class ConnectionService {
69
96
  const session = this.sessionManager.getSession();
70
97
  this.eventManager.emit('connected', { session });
71
98
  this.eventManager.emit('sessionChanged', { session });
99
+ // Observe post-connect wallet lifecycle (account/chain switch in the wallet,
100
+ // disconnect, expiry) from the live provider — telemetry only, never changes
101
+ // connection behaviour. Torn down on disconnect.
102
+ this.attachLifecycle(connectionMode, wallet.id, network.namespace);
103
+ }
104
+ /** Wire the active connector's lifecycle stream onto the bus (or signal absence). */
105
+ attachLifecycle(connectionMode, walletId, namespace, initialSwitch) {
106
+ this.teardownLifecycle();
107
+ const connector = this.activeConnector;
108
+ this.lifecycleTeardown = attachLifecycle({
109
+ eventManager: this.eventManager,
110
+ // Reattach-after-switch only: seed echo suppression, because the fresh
111
+ // subscription never saw the completed switch's bus events.
112
+ ...(initialSwitch && { initialSwitch }),
113
+ // The context names the session being attached FOR — the connector routes
114
+ // by it (never by its own ambient state, which is ambiguous when the
115
+ // secondary-namespace gather left several live surfaces).
116
+ subscribe: connector?.onLifecycleEvent
117
+ ? listener => connector.onLifecycleEvent(listener, {
118
+ connectionMode,
119
+ namespace,
120
+ walletId
121
+ })
122
+ : undefined,
123
+ getRouting: () => {
124
+ const s = this.sessionManager.getSession();
125
+ return {
126
+ connectionMode: s.connectionMode ?? connectionMode,
127
+ walletId: s.activeWallet?.id ?? walletId,
128
+ namespace: s.activeNetwork?.namespace ?? namespace
129
+ };
130
+ },
131
+ connectionMode,
132
+ walletId,
133
+ namespace,
134
+ // The bridge child sets this when UWC runs inside the Link iframe; it tells
135
+ // a `lifecycleTelemetryUnavailable` consumer whether lifecycle was silent on
136
+ // the direct page or (expected, pending P3) over the production bridge.
137
+ runtime: globalThis
138
+ .UWCBridgeChildInitialized === true
139
+ ? 'iframe'
140
+ : 'direct'
141
+ });
142
+ }
143
+ /**
144
+ * Remove the active provider-lifecycle subscription (EIP-1193 `.on` / wallet-
145
+ * adapter / SignClient listeners) WITHOUT disconnecting the wallet. Idempotent.
146
+ * Exposed so a full `dispose()` that bypasses `disconnect()` still releases these
147
+ * listeners — leaving them attached is the zombie-listener class this layer
148
+ * exists to prevent.
149
+ */
150
+ teardownLifecycle() {
151
+ this.lifecycleTeardown?.();
152
+ this.lifecycleTeardown = undefined;
153
+ }
154
+ /**
155
+ * Re-evaluate the lifecycle source for the CURRENT session. Used after a
156
+ * cross-namespace switchNetwork: the live provider changes with the namespace,
157
+ * so the connect-time subscription would keep observing the old namespace's
158
+ * provider and label its events with the new session's routing. Tears the old
159
+ * subscription down and re-attaches against the active session's facets.
160
+ * Safe no-op when nothing is connected.
161
+ */
162
+ reattachLifecycle() {
163
+ const session = this.sessionManager.getSession();
164
+ if (!this.activeConnector ||
165
+ !session.connectionMode ||
166
+ !session.activeWallet ||
167
+ !session.activeNetwork) {
168
+ return;
169
+ }
170
+ this.attachLifecycle(session.connectionMode, session.activeWallet.id, session.activeNetwork.namespace,
171
+ // The reattach follows a JUST-completed switch to the now-active chain —
172
+ // arm echo suppression for it so the new provider's echo isn't mistaken
173
+ // for a wallet-initiated change (one-shot, same as bus-armed switches).
174
+ { chainId: session.activeNetwork.id, at: Date.now() });
72
175
  }
73
176
  async connectWithURIPoll(connector, network, provider, connectionMode, signal) {
74
177
  const connectPromise = connector.connect(network, provider);
@@ -170,7 +273,10 @@ export class ConnectionService {
170
273
  // Use the first supported network that exists in both wallet and configured networks
171
274
  const supportedNetwork = provider.supportedNetworkIds.find(id => this.networks.some(n => n.id === id));
172
275
  if (!supportedNetwork) {
173
- throw new Error('No common supported network found between wallet and configured networks');
276
+ // The #1 production connection failure. Throw a typed, self-describing
277
+ // error carrying both CAIP-2 id lists (non-PII) so telemetry can tell a
278
+ // metadata gap from a client-config mistake — see NoCommonNetworkError.
279
+ throw new NoCommonNetworkError(provider.supportedNetworkIds, this.networks.map(n => n.id));
174
280
  }
175
281
  targetNetworkId = supportedNetwork;
176
282
  }
@@ -183,6 +289,9 @@ export class ConnectionService {
183
289
  }
184
290
  async disconnect(options) {
185
291
  options?.signal?.throwIfAborted();
292
+ // Remove the lifecycle listeners first so a provider 'disconnect' fired during
293
+ // teardown doesn't re-enter as a wallet-initiated `walletDisconnected`.
294
+ this.teardownLifecycle();
186
295
  try {
187
296
  if (this.activeConnector &&
188
297
  typeof this.activeConnector.disconnect === 'function') {