@meshconnect/uwc-react 0.10.0 → 0.11.0-snapshot.86f6845

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/README.md CHANGED
@@ -239,6 +239,17 @@ Props:
239
239
  - `usingIntegratedBrowser?: boolean` - Whether using integrated browser (default: false)
240
240
  - `walletConnectConfig?: WalletConnectConfig` - Optional WalletConnect configuration
241
241
  - `tonConnectConfig?: TonConnectConfig` - Optional TON Connect configuration (requires `manifestUrl`)
242
+ - `tronConnectorConfig?: TronConnectorConfig` - Optional TRON connector configuration
243
+ - `observer?: UWCObserver` - Optional telemetry sink (`onEvent`, optional `onLog`) for wallet-handoff observability; with no observer wired nothing leaves the browser
244
+ - `logger?: Logger` / `logLevel?: LogLevel` - Optional runtime logging configuration
245
+ - `correlationId?: string | (() => string)` - Optional id stamped on every telemetry event; pass the **getter form** for an id that resolves late (e.g. a session id)
246
+
247
+ > **Read once.** The provider builds one shared connector on the first render
248
+ > where `wallets` is non-empty, capturing `observer` / `logger` / `logLevel` /
249
+ > `correlationId` at that instant — later prop changes are ignored. Pass a
250
+ > stable `observer` from the first render (its `onEvent` can no-op until your
251
+ > sink is ready), use the `correlationId` getter for late ids, and
252
+ > `connector.setLogLevel()` for runtime level changes.
242
253
 
243
254
  ### Hooks
244
255
 
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { UniversalWalletConnector } from '@meshconnect/uwc-core';
3
- import type { Session, Network, WalletMetadata, WalletConnectConfig, TonConnectConfig, TronConnectorConfig } from '@meshconnect/uwc-types';
2
+ import { UniversalWalletConnector, type UWCObserver } from '@meshconnect/uwc-core';
3
+ import type { Session, Network, WalletMetadata, WalletConnectConfig, TonConnectConfig, TronConnectorConfig, Logger, LogLevel } from '@meshconnect/uwc-types';
4
4
  export interface ConnectionContextValue {
5
5
  /**
6
6
  * `null` when the provider is mounted without wallets. `@meshconnect/uwc-core`
@@ -25,7 +25,19 @@ interface ConnectionProviderProps {
25
25
  walletConnectConfig?: WalletConnectConfig;
26
26
  tonConnectConfig?: TonConnectConfig;
27
27
  tronConnectorConfig?: TronConnectorConfig;
28
+ /**
29
+ * Observability — forwarded to the connector (see @meshconnect/uwc-core).
30
+ * READ ONCE at connector construction (the first render with a non-empty
31
+ * wallet list); the shared singleton ignores later prop changes. Pass a
32
+ * stable `observer`/`logger`, prefer the getter form of `correlationId` for
33
+ * an id that arrives late (it is resolved per-event), and use the
34
+ * connector's `setLogLevel()` for runtime level changes.
35
+ */
36
+ observer?: UWCObserver;
37
+ logger?: Logger;
38
+ logLevel?: LogLevel;
39
+ correlationId?: string | (() => string);
28
40
  }
29
- export declare function ConnectionProvider({ children, networks, wallets, usingIntegratedBrowser, walletConnectConfig, tonConnectConfig, tronConnectorConfig }: ConnectionProviderProps): import("react/jsx-runtime").JSX.Element;
41
+ export declare function ConnectionProvider({ children, networks, wallets, usingIntegratedBrowser, walletConnectConfig, tonConnectConfig, tronConnectorConfig, observer, logger, logLevel, correlationId }: ConnectionProviderProps): import("react/jsx-runtime").JSX.Element;
30
42
  export { ConnectionContext };
31
43
  //# sourceMappingURL=ConnectionProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ConnectionProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EACV,OAAO,EACP,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,wBAAwB,CAAA;AAwB/B,MAAM,WAAW,sBAAsB;IACrC;;;;;;;OAOG;IACH,SAAS,EAAE,wBAAwB,GAAG,IAAI,CAAA;IAC1C,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,QAAA,MAAM,iBAAiB,8CAAqD,CAAA;AAE5E,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;CAC1C;AAED,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,sBAA8B,EAC9B,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACpB,EAAE,uBAAuB,2CAmDzB;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
1
+ {"version":3,"file":"ConnectionProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ConnectionProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAA;AACjE,OAAO,EACL,wBAAwB,EAExB,KAAK,WAAW,EACjB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,EACV,OAAO,EACP,OAAO,EACP,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,MAAM,EACN,QAAQ,EACT,MAAM,wBAAwB,CAAA;AAkC/B,MAAM,WAAW,sBAAsB;IACrC;;;;;;;OAOG;IACH,SAAS,EAAE,wBAAwB,GAAG,IAAI,CAAA;IAC1C,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,QAAA,MAAM,iBAAiB,8CAAqD,CAAA;AAE5E,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAA;IACtB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAA;CACxC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,sBAA8B,EAC9B,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,aAAa,EACd,EAAE,uBAAuB,2CAkFzB;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
@@ -3,6 +3,11 @@ import React, { createContext, useEffect, useState } from 'react';
3
3
  import { UniversalWalletConnector } from '@meshconnect/uwc-core';
4
4
  // Guard against double initialization
5
5
  let sharedConnector = null;
6
+ // What the singleton captured at construction — kept to diagnose the one
7
+ // silent failure mode: an observability prop that ARRIVES on a later render
8
+ // is ignored, and without a warning telemetry just never fires.
9
+ let capturedObservability = null;
10
+ let warnedLateObservability = false;
6
11
  /**
7
12
  * Session served before any wallet is connected — and while the provider is
8
13
  * mounted without wallets (a wallet-less session; see `connector` below). Every
@@ -22,14 +27,60 @@ const EMPTY_SESSION = {
22
27
  availableAddresses: []
23
28
  };
24
29
  const ConnectionContext = createContext(null);
25
- export function ConnectionProvider({ children, networks, wallets, usingIntegratedBrowser = false, walletConnectConfig, tonConnectConfig, tronConnectorConfig }) {
30
+ export function ConnectionProvider({ children, networks, wallets, usingIntegratedBrowser = false, walletConnectConfig, tonConnectConfig, tronConnectorConfig, observer, logger, logLevel, correlationId }) {
26
31
  // Core rejects an empty wallet list, so only construct once there is at least
27
32
  // one wallet. A wallet-less session keeps `connector` null; the effect below
28
33
  // adopts the connector if wallets arrive later (async catalog population).
29
34
  if (!sharedConnector && wallets.length > 0) {
30
- sharedConnector = new UniversalWalletConnector(networks, wallets, usingIntegratedBrowser, walletConnectConfig, tonConnectConfig, tronConnectorConfig);
35
+ // Build the config object conditionally — under exactOptionalPropertyTypes an
36
+ // explicit `undefined` can't be assigned to an optional field.
37
+ const config = { networks, wallets, usingIntegratedBrowser };
38
+ if (walletConnectConfig)
39
+ config.walletConnectConfig = walletConnectConfig;
40
+ if (tonConnectConfig)
41
+ config.tonConnectConfig = tonConnectConfig;
42
+ if (tronConnectorConfig)
43
+ config.tronConnectorConfig = tronConnectorConfig;
44
+ if (observer)
45
+ config.observer = observer;
46
+ if (logger)
47
+ config.logger = logger;
48
+ if (logLevel)
49
+ config.logLevel = logLevel;
50
+ if (correlationId !== undefined)
51
+ config.correlationId = correlationId;
52
+ sharedConnector = new UniversalWalletConnector(config);
53
+ capturedObservability = {
54
+ hadObserver: !!observer,
55
+ hadLogger: !!logger,
56
+ hadLogLevel: !!logLevel,
57
+ hadCorrelationId: correlationId !== undefined
58
+ };
31
59
  }
32
60
  const connector = sharedConnector;
61
+ // Diagnose the read-once footgun: an observability prop supplied only AFTER
62
+ // the shared connector was built is silently ignored — warn once instead of
63
+ // letting telemetry die with no signal. Props that were present at
64
+ // construction are fine (the captured values keep flowing). Runs in an
65
+ // effect: a render must stay side-effect free.
66
+ useEffect(() => {
67
+ if (!connector || !capturedObservability || warnedLateObservability)
68
+ return;
69
+ const late = [];
70
+ if (observer && !capturedObservability.hadObserver)
71
+ late.push('observer');
72
+ if (logger && !capturedObservability.hadLogger)
73
+ late.push('logger');
74
+ if (logLevel && !capturedObservability.hadLogLevel)
75
+ late.push('logLevel');
76
+ if (correlationId !== undefined && !capturedObservability.hadCorrelationId)
77
+ late.push('correlationId');
78
+ if (late.length > 0) {
79
+ warnedLateObservability = true;
80
+ console.warn(`[uwc-react] ConnectionProvider received ${late.join(', ')} after the shared connector was constructed — these props are read once and the late value is ignored. ` +
81
+ 'Pass them from the first render with a non-empty wallet list (observer/logger may be stable no-op shells until your sink is ready; correlationId supports a getter for late ids).');
82
+ }
83
+ }, [connector, observer, logger, logLevel, correlationId]);
33
84
  const [session, setSession] = useState(() => connector?.getSession() ?? EMPTY_SESSION);
34
85
  const [isReady, setIsReady] = useState(() => connector?.isReady() ?? false);
35
86
  useEffect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionProvider.js","sourceRoot":"","sources":["../../src/providers/ConnectionProvider.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAUhE,sCAAsC;AACtC,IAAI,eAAe,GAAoC,IAAI,CAAA;AAE3D;;;;;;GAMG;AACH,MAAM,aAAa,GAAY;IAC7B,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,IAAI;IACnB,wBAAwB,EAAE,IAAI;IAC9B,+BAA+B,EAAE,IAAI;IACrC,aAAa,EAAE,IAAI;IACnB,SAAS,EAAE,IAAI;IACf,iBAAiB,EAAE,EAAE;IACrB,YAAY,EAAE,IAAI;IAClB,kBAAkB,EAAE,EAAE;CACvB,CAAA;AAkBD,MAAM,iBAAiB,GAAG,aAAa,CAAgC,IAAI,CAAC,CAAA;AAY5E,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,sBAAsB,GAAG,KAAK,EAC9B,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACK;IACxB,8EAA8E;IAC9E,6EAA6E;IAC7E,2EAA2E;IAC3E,IAAI,CAAC,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,eAAe,GAAG,IAAI,wBAAwB,CAC5C,QAAQ,EACR,OAAO,EACP,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,CACpB,CAAA;IACH,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,CAAA;IAEjC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CACpC,GAAG,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,aAAa,CAC/C,CAAA;IACD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,KAAK,CAAC,CAAA;IAE3E,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS;YAAE,OAAM;QAEtB,0EAA0E;QAC1E,6DAA6D;QAC7D,UAAU,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,CAAA;QAClC,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAA;QAE/B,MAAM,WAAW,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE;YAC3C,UAAU,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,CAAA;YAClC,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,OAAO,WAAW,CAAA;IACpB,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IAEf,MAAM,KAAK,GAA2B;QACpC,SAAS;QACT,OAAO;QACP,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO;QACrD,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,QAAQ;QACxD,OAAO;KACR,CAAA;IAED,OAAO,CACL,KAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACrC,QAAQ,GACkB,CAC9B,CAAA;AACH,CAAC;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
1
+ {"version":3,"file":"ConnectionProvider.js","sourceRoot":"","sources":["../../src/providers/ConnectionProvider.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshconnect/uwc-react",
3
- "version": "0.10.0",
3
+ "version": "0.11.0-snapshot.86f6845",
4
4
  "description": "React hooks and components for Universal Wallet Connector",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,8 +16,8 @@
16
16
  "src"
17
17
  ],
18
18
  "dependencies": {
19
- "@meshconnect/uwc-types": "0.16.1",
20
- "@meshconnect/uwc-core": "1.0.2"
19
+ "@meshconnect/uwc-core": "1.1.0-snapshot.86f6845",
20
+ "@meshconnect/uwc-types": "0.17.0-snapshot.86f6845"
21
21
  },
22
22
  "peerDependencies": {
23
23
  "react": "^18.0.0",
@@ -159,13 +159,223 @@ describe('ConnectionProvider singleton behavior', () => {
159
159
  )
160
160
  })
161
161
 
162
- // Constructor signature: (networks, wallets, usingIntegratedBrowser,
163
- // walletConnectConfig, tonConnectConfig, tronConnectorConfig)
162
+ // Constructor now receives a single UWCConfig object (config-object form),
163
+ // so the provider can also forward the observability fields.
164
164
  expect(ctorArgs.length).toBe(1)
165
- expect(ctorArgs[0]?.[5]).toBe(tronConnectorConfig)
165
+ expect(ctorArgs[0]?.[0]?.tronConnectorConfig).toBe(tronConnectorConfig)
166
166
 
167
167
  await act(async () => {
168
168
  root.unmount()
169
169
  })
170
170
  })
171
+
172
+ it('forwards the observer to the UniversalWalletConnector config', async () => {
173
+ const ctorArgs: unknown[][] = []
174
+ vi.doMock('@meshconnect/uwc-core', () => {
175
+ class UniversalWalletConnector {
176
+ constructor(...args: unknown[]) {
177
+ ctorArgs.push(args)
178
+ }
179
+ getSession() {
180
+ return {
181
+ isConnected: false,
182
+ walletId: undefined,
183
+ networkId: undefined
184
+ }
185
+ }
186
+ isReady() {
187
+ return true
188
+ }
189
+ subscribe() {
190
+ return () => {}
191
+ }
192
+ getWallets() {
193
+ return []
194
+ }
195
+ getNetworks() {
196
+ return []
197
+ }
198
+ }
199
+ return { UniversalWalletConnector }
200
+ })
201
+
202
+ const { ConnectionProvider } = await import('./ConnectionProvider')
203
+ const observer = { onEvent: () => {} }
204
+
205
+ const container = document.createElement('div')
206
+ document.body.appendChild(container)
207
+ const root = createRoot(container)
208
+
209
+ await act(async () => {
210
+ root.render(
211
+ <ConnectionProvider
212
+ networks={[]}
213
+ wallets={TEST_WALLETS}
214
+ observer={observer}
215
+ >
216
+ <div />
217
+ </ConnectionProvider>
218
+ )
219
+ })
220
+
221
+ expect(ctorArgs.length).toBe(1)
222
+ expect((ctorArgs[0]?.[0] as { observer?: unknown })?.observer).toBe(
223
+ observer
224
+ )
225
+
226
+ await act(async () => {
227
+ root.unmount()
228
+ })
229
+ })
230
+
231
+ it('forwards logger, logLevel and correlationId (including the empty string) to the config', async () => {
232
+ const ctorArgs: unknown[][] = []
233
+ vi.doMock('@meshconnect/uwc-core', () => {
234
+ class UniversalWalletConnector {
235
+ constructor(...args: unknown[]) {
236
+ ctorArgs.push(args)
237
+ }
238
+ getSession() {
239
+ return {
240
+ isConnected: false,
241
+ walletId: undefined,
242
+ networkId: undefined
243
+ }
244
+ }
245
+ isReady() {
246
+ return true
247
+ }
248
+ subscribe() {
249
+ return () => {}
250
+ }
251
+ getWallets() {
252
+ return []
253
+ }
254
+ getNetworks() {
255
+ return []
256
+ }
257
+ }
258
+ return { UniversalWalletConnector }
259
+ })
260
+
261
+ const { ConnectionProvider } = await import('./ConnectionProvider')
262
+ const logger = {
263
+ debug: () => {},
264
+ info: () => {},
265
+ warn: () => {},
266
+ error: () => {}
267
+ }
268
+
269
+ const container = document.createElement('div')
270
+ document.body.appendChild(container)
271
+ const root = createRoot(container)
272
+
273
+ await act(async () => {
274
+ root.render(
275
+ <ConnectionProvider
276
+ networks={[]}
277
+ wallets={TEST_WALLETS}
278
+ logger={logger}
279
+ logLevel="debug"
280
+ correlationId=""
281
+ >
282
+ <div />
283
+ </ConnectionProvider>
284
+ )
285
+ })
286
+
287
+ expect(ctorArgs.length).toBe(1)
288
+ const config = ctorArgs[0]?.[0] as {
289
+ logger?: unknown
290
+ logLevel?: unknown
291
+ correlationId?: unknown
292
+ }
293
+ expect(config?.logger).toBe(logger)
294
+ expect(config?.logLevel).toBe('debug')
295
+ // '' must forward: the guard is deliberately `!== undefined`, not
296
+ // truthiness — an empty-string correlation id is a valid consumer value.
297
+ expect(config?.correlationId).toBe('')
298
+
299
+ await act(async () => {
300
+ root.unmount()
301
+ })
302
+ })
303
+
304
+ it('warns once (from an effect, not render) when an observability prop arrives after construction', async () => {
305
+ vi.doMock('@meshconnect/uwc-core', () => {
306
+ class UniversalWalletConnector {
307
+ getSession() {
308
+ return {
309
+ isConnected: false,
310
+ walletId: undefined,
311
+ networkId: undefined
312
+ }
313
+ }
314
+ isReady() {
315
+ return true
316
+ }
317
+ subscribe() {
318
+ return () => {}
319
+ }
320
+ getWallets() {
321
+ return []
322
+ }
323
+ getNetworks() {
324
+ return []
325
+ }
326
+ }
327
+ return { UniversalWalletConnector }
328
+ })
329
+
330
+ const { ConnectionProvider } = await import('./ConnectionProvider')
331
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
332
+
333
+ const container = document.createElement('div')
334
+ document.body.appendChild(container)
335
+ const root = createRoot(container)
336
+
337
+ // First render: connector constructed WITHOUT an observer.
338
+ await act(async () => {
339
+ root.render(
340
+ <ConnectionProvider networks={[]} wallets={TEST_WALLETS}>
341
+ <div />
342
+ </ConnectionProvider>
343
+ )
344
+ })
345
+ expect(warnSpy).not.toHaveBeenCalled()
346
+
347
+ // Late observer: read-once means it is ignored — must warn, exactly once
348
+ // across re-renders.
349
+ const observer = { onEvent: () => {} }
350
+ await act(async () => {
351
+ root.render(
352
+ <ConnectionProvider
353
+ networks={[]}
354
+ wallets={TEST_WALLETS}
355
+ observer={observer}
356
+ >
357
+ <div />
358
+ </ConnectionProvider>
359
+ )
360
+ })
361
+ await act(async () => {
362
+ root.render(
363
+ <ConnectionProvider
364
+ networks={[]}
365
+ wallets={TEST_WALLETS}
366
+ observer={observer}
367
+ >
368
+ <div />
369
+ </ConnectionProvider>
370
+ )
371
+ })
372
+
373
+ expect(warnSpy).toHaveBeenCalledTimes(1)
374
+ expect(warnSpy.mock.calls[0]?.[0]).toContain('observer')
375
+
376
+ warnSpy.mockRestore()
377
+ await act(async () => {
378
+ root.unmount()
379
+ })
380
+ })
171
381
  })
@@ -1,16 +1,32 @@
1
1
  import React, { createContext, useEffect, useState } from 'react'
2
- import { UniversalWalletConnector } from '@meshconnect/uwc-core'
2
+ import {
3
+ UniversalWalletConnector,
4
+ type UWCConfig,
5
+ type UWCObserver
6
+ } from '@meshconnect/uwc-core'
3
7
  import type {
4
8
  Session,
5
9
  Network,
6
10
  WalletMetadata,
7
11
  WalletConnectConfig,
8
12
  TonConnectConfig,
9
- TronConnectorConfig
13
+ TronConnectorConfig,
14
+ Logger,
15
+ LogLevel
10
16
  } from '@meshconnect/uwc-types'
11
17
 
12
18
  // Guard against double initialization
13
19
  let sharedConnector: UniversalWalletConnector | null = null
20
+ // What the singleton captured at construction — kept to diagnose the one
21
+ // silent failure mode: an observability prop that ARRIVES on a later render
22
+ // is ignored, and without a warning telemetry just never fires.
23
+ let capturedObservability: {
24
+ hadObserver: boolean
25
+ hadLogger: boolean
26
+ hadLogLevel: boolean
27
+ hadCorrelationId: boolean
28
+ } | null = null
29
+ let warnedLateObservability = false
14
30
 
15
31
  /**
16
32
  * Session served before any wallet is connected — and while the provider is
@@ -57,6 +73,18 @@ interface ConnectionProviderProps {
57
73
  walletConnectConfig?: WalletConnectConfig
58
74
  tonConnectConfig?: TonConnectConfig
59
75
  tronConnectorConfig?: TronConnectorConfig
76
+ /**
77
+ * Observability — forwarded to the connector (see @meshconnect/uwc-core).
78
+ * READ ONCE at connector construction (the first render with a non-empty
79
+ * wallet list); the shared singleton ignores later prop changes. Pass a
80
+ * stable `observer`/`logger`, prefer the getter form of `correlationId` for
81
+ * an id that arrives late (it is resolved per-event), and use the
82
+ * connector's `setLogLevel()` for runtime level changes.
83
+ */
84
+ observer?: UWCObserver
85
+ logger?: Logger
86
+ logLevel?: LogLevel
87
+ correlationId?: string | (() => string)
60
88
  }
61
89
 
62
90
  export function ConnectionProvider({
@@ -66,24 +94,59 @@ export function ConnectionProvider({
66
94
  usingIntegratedBrowser = false,
67
95
  walletConnectConfig,
68
96
  tonConnectConfig,
69
- tronConnectorConfig
97
+ tronConnectorConfig,
98
+ observer,
99
+ logger,
100
+ logLevel,
101
+ correlationId
70
102
  }: ConnectionProviderProps) {
71
103
  // Core rejects an empty wallet list, so only construct once there is at least
72
104
  // one wallet. A wallet-less session keeps `connector` null; the effect below
73
105
  // adopts the connector if wallets arrive later (async catalog population).
74
106
  if (!sharedConnector && wallets.length > 0) {
75
- sharedConnector = new UniversalWalletConnector(
76
- networks,
77
- wallets,
78
- usingIntegratedBrowser,
79
- walletConnectConfig,
80
- tonConnectConfig,
81
- tronConnectorConfig
82
- )
107
+ // Build the config object conditionally — under exactOptionalPropertyTypes an
108
+ // explicit `undefined` can't be assigned to an optional field.
109
+ const config: UWCConfig = { networks, wallets, usingIntegratedBrowser }
110
+ if (walletConnectConfig) config.walletConnectConfig = walletConnectConfig
111
+ if (tonConnectConfig) config.tonConnectConfig = tonConnectConfig
112
+ if (tronConnectorConfig) config.tronConnectorConfig = tronConnectorConfig
113
+ if (observer) config.observer = observer
114
+ if (logger) config.logger = logger
115
+ if (logLevel) config.logLevel = logLevel
116
+ if (correlationId !== undefined) config.correlationId = correlationId
117
+ sharedConnector = new UniversalWalletConnector(config)
118
+ capturedObservability = {
119
+ hadObserver: !!observer,
120
+ hadLogger: !!logger,
121
+ hadLogLevel: !!logLevel,
122
+ hadCorrelationId: correlationId !== undefined
123
+ }
83
124
  }
84
125
 
85
126
  const connector = sharedConnector
86
127
 
128
+ // Diagnose the read-once footgun: an observability prop supplied only AFTER
129
+ // the shared connector was built is silently ignored — warn once instead of
130
+ // letting telemetry die with no signal. Props that were present at
131
+ // construction are fine (the captured values keep flowing). Runs in an
132
+ // effect: a render must stay side-effect free.
133
+ useEffect(() => {
134
+ if (!connector || !capturedObservability || warnedLateObservability) return
135
+ const late: string[] = []
136
+ if (observer && !capturedObservability.hadObserver) late.push('observer')
137
+ if (logger && !capturedObservability.hadLogger) late.push('logger')
138
+ if (logLevel && !capturedObservability.hadLogLevel) late.push('logLevel')
139
+ if (correlationId !== undefined && !capturedObservability.hadCorrelationId)
140
+ late.push('correlationId')
141
+ if (late.length > 0) {
142
+ warnedLateObservability = true
143
+ console.warn(
144
+ `[uwc-react] ConnectionProvider received ${late.join(', ')} after the shared connector was constructed — these props are read once and the late value is ignored. ` +
145
+ 'Pass them from the first render with a non-empty wallet list (observer/logger may be stable no-op shells until your sink is ready; correlationId supports a getter for late ids).'
146
+ )
147
+ }
148
+ }, [connector, observer, logger, logLevel, correlationId])
149
+
87
150
  const [session, setSession] = useState<Session>(
88
151
  () => connector?.getSession() ?? EMPTY_SESSION
89
152
  )