@meshconnect/uwc-core 1.0.0 → 1.0.1-snapshot.c7e65ce
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 +211 -66
- package/dist/events.d.ts +69 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +40 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/logger/create-logger.d.ts +32 -0
- package/dist/logger/create-logger.d.ts.map +1 -0
- package/dist/logger/create-logger.js +69 -0
- package/dist/logger/create-logger.js.map +1 -0
- package/dist/managers/event-manager.d.ts.map +1 -1
- package/dist/managers/event-manager.js +5 -1
- package/dist/managers/event-manager.js.map +1 -1
- package/dist/observability/connect-observer.d.ts +22 -0
- package/dist/observability/connect-observer.d.ts.map +1 -0
- package/dist/observability/connect-observer.js +60 -0
- package/dist/observability/connect-observer.js.map +1 -0
- package/dist/observability/instrument-handoff.d.ts +39 -0
- package/dist/observability/instrument-handoff.d.ts.map +1 -0
- package/dist/observability/instrument-handoff.js +86 -0
- package/dist/observability/instrument-handoff.js.map +1 -0
- package/dist/observability/scrub.d.ts +30 -0
- package/dist/observability/scrub.d.ts.map +1 -0
- package/dist/observability/scrub.js +135 -0
- package/dist/observability/scrub.js.map +1 -0
- package/dist/observability/telemetry.d.ts +77 -0
- package/dist/observability/telemetry.d.ts.map +1 -0
- package/dist/observability/telemetry.js +138 -0
- package/dist/observability/telemetry.js.map +1 -0
- package/dist/services/connection-service.d.ts +2 -1
- package/dist/services/connection-service.d.ts.map +1 -1
- package/dist/services/connection-service.js +35 -15
- package/dist/services/connection-service.js.map +1 -1
- package/dist/services/network-switch-service.d.ts +2 -1
- package/dist/services/network-switch-service.d.ts.map +1 -1
- package/dist/services/network-switch-service.js +33 -15
- package/dist/services/network-switch-service.js.map +1 -1
- package/dist/universal-wallet-connector.d.ts +51 -2
- package/dist/universal-wallet-connector.d.ts.map +1 -1
- package/dist/universal-wallet-connector.js +163 -61
- package/dist/universal-wallet-connector.js.map +1 -1
- package/dist/utils/id.d.ts +2 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js +41 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/to-wallet-error.d.ts +16 -0
- package/dist/utils/to-wallet-error.d.ts.map +1 -0
- package/dist/utils/to-wallet-error.js +33 -0
- package/dist/utils/to-wallet-error.js.map +1 -0
- package/package.json +5 -5
- package/src/events.ts +114 -1
- package/src/index.ts +6 -0
- package/src/logger/create-logger.test.ts +111 -0
- package/src/logger/create-logger.ts +101 -0
- package/src/managers/event-manager.test.ts +25 -0
- package/src/managers/event-manager.ts +5 -1
- package/src/observability/connect-observer.test.ts +100 -0
- package/src/observability/connect-observer.ts +71 -0
- package/src/observability/instrument-handoff.test.ts +150 -0
- package/src/observability/instrument-handoff.ts +122 -0
- package/src/observability/scrub.test.ts +109 -0
- package/src/observability/scrub.ts +142 -0
- package/src/observability/telemetry.test.ts +134 -0
- package/src/observability/telemetry.ts +211 -0
- package/src/services/connection-service.test.ts +66 -1
- package/src/services/connection-service.ts +54 -32
- package/src/services/network-switch-service.test.ts +51 -1
- package/src/services/network-switch-service.ts +43 -23
- package/src/universal-wallet-connector.observability.test.ts +265 -0
- package/src/universal-wallet-connector.ts +244 -71
- package/src/utils/id.test.ts +15 -0
- package/src/utils/id.ts +48 -0
- package/src/utils/to-wallet-error.ts +36 -0
package/README.md
CHANGED
|
@@ -121,11 +121,11 @@ await connector.connect('injected', 'metamask', 'eip155:1')
|
|
|
121
121
|
|
|
122
122
|
Three mutually exclusive ways a user can connect:
|
|
123
123
|
|
|
124
|
-
| Mode | Description
|
|
125
|
-
| --------------- |
|
|
124
|
+
| Mode | Description | Typical wallets |
|
|
125
|
+
| --------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
|
126
126
|
| `injected` | Browser-extension or in-app injected provider (EIP-6963, Solana Wallet Standard, Tron, TON JS Bridge) | MetaMask, Phantom, Tonkeeper extension |
|
|
127
|
-
| `walletConnect` | WalletConnect v2 relay + QR code / deeplink
|
|
128
|
-
| `tonConnect` | TON Connect JS Bridge + QR code / universal link
|
|
127
|
+
| `walletConnect` | WalletConnect v2 relay + QR code / deeplink | Any WC-compatible mobile wallet |
|
|
128
|
+
| `tonConnect` | TON Connect JS Bridge + QR code / universal link | Tonkeeper, OKX TON Wallet |
|
|
129
129
|
|
|
130
130
|
A wallet can support multiple modes. `isConnectionModeAvailable(mode, walletId)`
|
|
131
131
|
tells you which ones are actually viable in the current runtime.
|
|
@@ -141,7 +141,7 @@ interface Session {
|
|
|
141
141
|
activeNetwork: Network | null
|
|
142
142
|
activeAddress: string | null
|
|
143
143
|
publicKey: string | null
|
|
144
|
-
availableNetworks: Network[]
|
|
144
|
+
availableNetworks: Network[] // networks the current wallet supports
|
|
145
145
|
availableAddresses: AvailableAddress[] // one per chain the wallet exposed
|
|
146
146
|
activeWalletCapabilities: Record<string, EVMCapabilities> | null
|
|
147
147
|
activeNetworkWalletCapabilities: EVMCapabilities | null
|
|
@@ -153,24 +153,30 @@ a `sessionChanged` event fires.
|
|
|
153
153
|
|
|
154
154
|
### Observer / event model
|
|
155
155
|
|
|
156
|
-
The connector is an event emitter.
|
|
157
|
-
|
|
158
|
-
| Event
|
|
159
|
-
|
|
|
160
|
-
| `ready`
|
|
161
|
-
| `walletsDetected`
|
|
162
|
-
| `connecting`
|
|
163
|
-
| `connectionUri`
|
|
164
|
-
| `connected`
|
|
165
|
-
| `disconnected`
|
|
166
|
-
| `sessionChanged`
|
|
167
|
-
| `networkSwitching`
|
|
168
|
-
| `networkSwitched`
|
|
169
|
-
| `capabilitiesUpdated`
|
|
170
|
-
| `error`
|
|
171
|
-
| `change`
|
|
172
|
-
|
|
173
|
-
|
|
156
|
+
The connector is an event emitter. The state-change events are:
|
|
157
|
+
|
|
158
|
+
| Event | When it fires |
|
|
159
|
+
| --------------------- | -------------------------------------------------------- |
|
|
160
|
+
| `ready` | Initial wallet detection has completed |
|
|
161
|
+
| `walletsDetected` | Detection completed, payload is the enriched wallet list |
|
|
162
|
+
| `connecting` | `connect()` started |
|
|
163
|
+
| `connectionUri` | A WC/TonConnect pairing URI is now available |
|
|
164
|
+
| `connected` | `connect()` finished successfully |
|
|
165
|
+
| `disconnected` | `disconnect()` finished (session cleared) |
|
|
166
|
+
| `sessionChanged` | Any session field changed |
|
|
167
|
+
| `networkSwitching` | Network switch started or ended |
|
|
168
|
+
| `networkSwitched` | Network switch finished successfully |
|
|
169
|
+
| `capabilitiesUpdated` | `getWalletCapabilities()` refreshed data |
|
|
170
|
+
| `error` | A user-initiated op threw |
|
|
171
|
+
| `change` | Catch-all — fires after every other state-change event |
|
|
172
|
+
|
|
173
|
+
Plus a set of **telemetry-only** events used for logging and wallet-handoff
|
|
174
|
+
visibility (see [Logging & observability](#logging--observability)). These
|
|
175
|
+
deliberately do **not** cascade to `change` (so they never trigger re-renders):
|
|
176
|
+
`log`, `awaitingWallet`, `walletSucceeded`, `walletRejected`, `walletFailed`,
|
|
177
|
+
`walletTimedOut`.
|
|
178
|
+
|
|
179
|
+
Use `on(eventName, listener)` for targeted updates. Every state-change event also
|
|
174
180
|
cascades to `change`, so the legacy `subscribe(listener)` pattern still works.
|
|
175
181
|
|
|
176
182
|
### AbortSignal
|
|
@@ -296,8 +302,8 @@ const connector = new UniversalWalletConnector(
|
|
|
296
302
|
)
|
|
297
303
|
```
|
|
298
304
|
|
|
299
|
-
Constructing a **second** instance logs
|
|
300
|
-
almost always a mistake. For tests and full-logout flows, call
|
|
305
|
+
Constructing a **second** instance logs an error through the configured logger
|
|
306
|
+
— it's almost always a mistake. For tests and full-logout flows, call
|
|
301
307
|
`UniversalWalletConnector.resetInstance()` to clear the cached reference.
|
|
302
308
|
|
|
303
309
|
---
|
|
@@ -307,15 +313,15 @@ almost always a mistake. For tests and full-logout flows, call
|
|
|
307
313
|
All reads are synchronous and cheap. Call them any time.
|
|
308
314
|
|
|
309
315
|
```ts
|
|
310
|
-
connector.getSession()
|
|
311
|
-
connector.getState()
|
|
312
|
-
connector.isReady()
|
|
313
|
-
connector.getWallets()
|
|
314
|
-
connector.getNetworks()
|
|
316
|
+
connector.getSession() // current Session
|
|
317
|
+
connector.getState() // { session } — parity with older API
|
|
318
|
+
connector.isReady() // true once detection completed
|
|
319
|
+
connector.getWallets() // wallets with `installed` flags set
|
|
320
|
+
connector.getNetworks() // the configured networks array
|
|
315
321
|
connector.isConnectionModeAvailable('walletConnect', 'metamask')
|
|
316
|
-
connector.getConnectionURI()
|
|
322
|
+
connector.getConnectionURI() // WC/TonConnect pairing URI, if any
|
|
317
323
|
connector.getNetworkSwitchLoadingState()
|
|
318
|
-
|
|
324
|
+
// { isLoading, isWaitingForUserApproval }
|
|
319
325
|
connector.getActiveWalletCapabilities() // Record<NetworkId, EVMCapabilities> | null
|
|
320
326
|
```
|
|
321
327
|
|
|
@@ -363,18 +369,21 @@ connector.off('connectionUri', handler)
|
|
|
363
369
|
import type { UWCEventMap } from '@meshconnect/uwc-core'
|
|
364
370
|
|
|
365
371
|
// Narrowed per event:
|
|
366
|
-
connector.on('connecting',
|
|
367
|
-
connector.on('connected',
|
|
368
|
-
connector.on('disconnected',
|
|
372
|
+
connector.on('connecting', ({ connectionMode, walletId }) => {})
|
|
373
|
+
connector.on('connected', ({ session }) => {})
|
|
374
|
+
connector.on('disconnected', () => {})
|
|
369
375
|
connector.on('connectionUri', ({ uri, connectionMode }) => {})
|
|
370
|
-
connector.on(
|
|
371
|
-
|
|
372
|
-
|
|
376
|
+
connector.on(
|
|
377
|
+
'networkSwitching',
|
|
378
|
+
({ isLoading, isWaitingForUserApproval }) => {}
|
|
379
|
+
)
|
|
380
|
+
connector.on('networkSwitched', ({ network }) => {})
|
|
381
|
+
connector.on('sessionChanged', ({ session }) => {})
|
|
373
382
|
connector.on('capabilitiesUpdated', ({ capabilities }) => {})
|
|
374
|
-
connector.on('walletsDetected',
|
|
383
|
+
connector.on('walletsDetected', ({ wallets }) => {})
|
|
375
384
|
connector.on('ready', () => {})
|
|
376
385
|
connector.on('error', ({ error, operation }) => {})
|
|
377
|
-
connector.on('change', () => {})
|
|
386
|
+
connector.on('change', () => {}) // catch-all; no payload
|
|
378
387
|
```
|
|
379
388
|
|
|
380
389
|
### Legacy `subscribe()`
|
|
@@ -473,8 +482,8 @@ await connector.switchNetwork('eip155:8453') // Base
|
|
|
473
482
|
// Track loading for UI
|
|
474
483
|
connector.on('networkSwitching', ({ isLoading, isWaitingForUserApproval }) => {
|
|
475
484
|
if (isWaitingForUserApproval) showBanner('Approve in your wallet…')
|
|
476
|
-
else if (isLoading)
|
|
477
|
-
else
|
|
485
|
+
else if (isLoading) showBanner('Switching network…')
|
|
486
|
+
else hideBanner()
|
|
478
487
|
})
|
|
479
488
|
```
|
|
480
489
|
|
|
@@ -647,8 +656,8 @@ interface WalletError {
|
|
|
647
656
|
```
|
|
648
657
|
|
|
649
658
|
- `rejected` — user dismissed the prompt.
|
|
650
|
-
- `expired`
|
|
651
|
-
- `unknown`
|
|
659
|
+
- `expired` — WalletConnect pairing proposal timed out.
|
|
660
|
+
- `unknown` — everything else (network errors, bad wallet state, …).
|
|
652
661
|
|
|
653
662
|
### Per-call handling
|
|
654
663
|
|
|
@@ -670,20 +679,20 @@ try {
|
|
|
670
679
|
```ts
|
|
671
680
|
import type { UWCOperation } from '@meshconnect/uwc-core'
|
|
672
681
|
|
|
673
|
-
connector.on(
|
|
674
|
-
error
|
|
675
|
-
operation: UWCOperation
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
}
|
|
682
|
-
|
|
682
|
+
connector.on(
|
|
683
|
+
'error',
|
|
684
|
+
({ error, operation }: { error: WalletError; operation: UWCOperation }) => {
|
|
685
|
+
analytics.track('wallet.error', {
|
|
686
|
+
operation,
|
|
687
|
+
type: error.type,
|
|
688
|
+
message: error.message
|
|
689
|
+
})
|
|
690
|
+
}
|
|
691
|
+
)
|
|
683
692
|
```
|
|
684
693
|
|
|
685
694
|
`operation` is one of:
|
|
686
|
-
`'connect' | 'disconnect' | 'switchNetwork' | 'signMessage' | 'sendTransaction' | 'getWalletCapabilities' | 'initialize'`.
|
|
695
|
+
`'connect' | 'disconnect' | 'switchNetwork' | 'signMessage' | 'signTypedData' | 'sendTransaction' | 'signSolanaTransaction' | 'getWalletCapabilities' | 'initialize'`.
|
|
687
696
|
|
|
688
697
|
### AbortError
|
|
689
698
|
|
|
@@ -705,6 +714,122 @@ try {
|
|
|
705
714
|
|
|
706
715
|
---
|
|
707
716
|
|
|
717
|
+
## Logging & observability
|
|
718
|
+
|
|
719
|
+
UWC ships **no** third-party telemetry SDK. Instead it exposes two opt-in seams
|
|
720
|
+
you wire to whatever stack you run (Datadog, Amplitude, Segment, a plain
|
|
721
|
+
console). With neither configured, there is **zero external egress** — the
|
|
722
|
+
security-first default for a sign-only wallet layer.
|
|
723
|
+
|
|
724
|
+
### Logging
|
|
725
|
+
|
|
726
|
+
A pluggable, level-gated logger backs UWC's internal logging. Configure it via
|
|
727
|
+
`UWCConfig`:
|
|
728
|
+
|
|
729
|
+
```ts
|
|
730
|
+
const connector = new UniversalWalletConnector({
|
|
731
|
+
networks,
|
|
732
|
+
wallets,
|
|
733
|
+
logLevel: 'info', // console threshold; default 'warn'
|
|
734
|
+
logger: myAppLogger // optional: redirect output into your own logger
|
|
735
|
+
})
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
`logger` (any object with `debug`/`info`/`warn`/`error`) receives the raw
|
|
739
|
+
`(message, ...args)`; omit it and a console sink is used with an ISO/level prefix.
|
|
740
|
+
|
|
741
|
+
Tune the threshold at runtime — useful when triaging in a wallet's in-app
|
|
742
|
+
browser where you can't redeploy:
|
|
743
|
+
|
|
744
|
+
```ts
|
|
745
|
+
connector.setLogLevel('debug') // programmatic
|
|
746
|
+
window.UWC_DEBUG = true // or from the console: surfaces everything
|
|
747
|
+
window.UWC_DEBUG = 'info' // or a specific level (only ever lowers it)
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
### Observer (telemetry)
|
|
751
|
+
|
|
752
|
+
Implement `UWCObserver` to receive a normalized, PII-safe event stream plus all
|
|
753
|
+
log lines. The vendor code lives in **your** app, never in UWC:
|
|
754
|
+
|
|
755
|
+
```ts
|
|
756
|
+
import type { UWCObserver } from '@meshconnect/uwc-core'
|
|
757
|
+
|
|
758
|
+
const observer: UWCObserver = {
|
|
759
|
+
onEvent: e => datadogRum.addAction(`uwc.${e.name}`, e), // or amplitude.track / …
|
|
760
|
+
onLog: (level, message, args) =>
|
|
761
|
+
myAppLogger[level](`[uwc] ${message}`, ...args)
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
const connector = new UniversalWalletConnector({ networks, wallets, observer })
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
> **Keep `onEvent` / `onLog` non-blocking.** They are called synchronously on the
|
|
768
|
+
> wallet-operation path — a terminal event fires between the wallet returning a
|
|
769
|
+
> result and that result reaching your `await`, so a slow handler adds latency to
|
|
770
|
+
> connect / sign / sendTransaction. Queue-backed sinks (Datadog `addAction`,
|
|
771
|
+
> Segment `track`) are already non-blocking; for anything heavy, defer it yourself
|
|
772
|
+
> (`onEvent: e => queueMicrotask(() => …)`).
|
|
773
|
+
|
|
774
|
+
Every `onEvent` record is a `UWCTelemetryEvent` — only routing facets
|
|
775
|
+
(`operation`, `connectionMode`, `namespace`, `chainId`, `walletId`, `durationMs`,
|
|
776
|
+
outcome…) plus a `sdkSessionId` correlation id. By default `sdkSessionId` is a
|
|
777
|
+
generated per-instance id; pass `correlationId` (a string or getter) to align it
|
|
778
|
+
to your own session key (e.g. `link_sess_id`) so UWC events join your existing
|
|
779
|
+
Datadog/RUM telemetry without a separate mapping:
|
|
780
|
+
|
|
781
|
+
````ts
|
|
782
|
+
new UniversalWalletConnector({
|
|
783
|
+
...config,
|
|
784
|
+
observer,
|
|
785
|
+
correlationId: () => myLinkSession.id // resolved per-event; getter may be lazy/dynamic
|
|
786
|
+
})
|
|
787
|
+
``` **Structured fields
|
|
788
|
+
never carry a signing payload or wallet address** — the shape has no slot for
|
|
789
|
+
them. The two free-form surfaces (`error.message` and `onLog` args) additionally
|
|
790
|
+
pass through a key + content scrubber that redacts sensitive keys, EVM hex blobs
|
|
791
|
+
(addresses / signatures / keys), secret URL params, and bearer tokens. Note this
|
|
792
|
+
last pass is best-effort: a base58 (Solana) or TON address embedded in a
|
|
793
|
+
free-form error string is a documented gap (it can't be matched without
|
|
794
|
+
false-positives), so don't rely on it for non-EVM address redaction.
|
|
795
|
+
|
|
796
|
+
### Wallet-handoff funnel
|
|
797
|
+
|
|
798
|
+
The moment UWC hands control to a wallet (extension popup, WC deeplink, TON
|
|
799
|
+
sheet) it emits `awaitingWallet`; when the wallet answers it emits exactly one
|
|
800
|
+
terminal — all sharing a `handoffId` and carrying `durationMs`:
|
|
801
|
+
|
|
802
|
+
````
|
|
803
|
+
|
|
804
|
+
awaitingWallet ─┬─ walletSucceeded success
|
|
805
|
+
├─ walletRejected user said no (4001 / rejected)
|
|
806
|
+
└─ walletFailed any other error
|
|
807
|
+
|
|
808
|
+
````
|
|
809
|
+
|
|
810
|
+
A non-cancelling `walletTimedOut` marker also fires if a non-TON handoff is still
|
|
811
|
+
pending past `walletResponseTimeoutMs` (default 60s, `0` disables). It is purely
|
|
812
|
+
observational — it never rejects, aborts, or mutates state, and is cleared the
|
|
813
|
+
instant the op settles, so a fast op never false-fires it. This turns the
|
|
814
|
+
previously-blind connect/sign/approve window into a per-(chain × wallet × flow)
|
|
815
|
+
timed funnel.
|
|
816
|
+
|
|
817
|
+
> A failed or rejected op emits **both** a handoff terminal
|
|
818
|
+
> (`walletFailed` / `walletRejected`) **and** the back-compat `error` event. For
|
|
819
|
+
> failure metrics, count the handoff terminals and treat `error` as the legacy
|
|
820
|
+
> channel — counting both double-counts each failure.
|
|
821
|
+
|
|
822
|
+
### Teardown
|
|
823
|
+
|
|
824
|
+
Call `dispose()` on full logout to release observer subscriptions and clear all
|
|
825
|
+
listeners:
|
|
826
|
+
|
|
827
|
+
```ts
|
|
828
|
+
connector.dispose()
|
|
829
|
+
````
|
|
830
|
+
|
|
831
|
+
---
|
|
832
|
+
|
|
708
833
|
## Testing
|
|
709
834
|
|
|
710
835
|
The shared singleton can leak state between tests. Reset it in `beforeEach`:
|
|
@@ -726,7 +851,9 @@ When unit-testing consumer code, mock the whole module:
|
|
|
726
851
|
vi.mock('@meshconnect/uwc-core', () => ({
|
|
727
852
|
UniversalWalletConnector: class {
|
|
728
853
|
static getInstance = () => new this()
|
|
729
|
-
getSession = () => ({
|
|
854
|
+
getSession = () => ({
|
|
855
|
+
/* fixture */
|
|
856
|
+
})
|
|
730
857
|
on = () => () => {}
|
|
731
858
|
once = () => () => {}
|
|
732
859
|
off = () => {}
|
|
@@ -757,12 +884,12 @@ connector.on('sessionChanged', ({ session }) => {
|
|
|
757
884
|
session.activeAddress ?? 'not connected'
|
|
758
885
|
})
|
|
759
886
|
|
|
760
|
-
document
|
|
761
|
-
|
|
762
|
-
)
|
|
763
|
-
document
|
|
764
|
-
|
|
765
|
-
)
|
|
887
|
+
document
|
|
888
|
+
.querySelector('#connect')!
|
|
889
|
+
.addEventListener('click', () => connector.connect('injected', 'metamask'))
|
|
890
|
+
document
|
|
891
|
+
.querySelector('#disconnect')!
|
|
892
|
+
.addEventListener('click', () => connector.disconnect())
|
|
766
893
|
```
|
|
767
894
|
|
|
768
895
|
### Show QR and auto-close modal on pair
|
|
@@ -805,7 +932,9 @@ const controller = new AbortController()
|
|
|
805
932
|
window.addEventListener('beforeunload', () => controller.abort())
|
|
806
933
|
|
|
807
934
|
try {
|
|
808
|
-
const sig = await connector.signMessage('Sign in', {
|
|
935
|
+
const sig = await connector.signMessage('Sign in', {
|
|
936
|
+
signal: controller.signal
|
|
937
|
+
})
|
|
809
938
|
submitLogin(sig)
|
|
810
939
|
} catch (error) {
|
|
811
940
|
if ((error as { name?: string }).name === 'AbortError') return
|
|
@@ -828,6 +957,12 @@ export interface UWCConfig {
|
|
|
828
957
|
walletConnectConfig?: WalletConnectConfig
|
|
829
958
|
tonConnectConfig?: TonConnectConfig
|
|
830
959
|
tronConnectorConfig?: TronConnectorConfig
|
|
960
|
+
// Observability (all optional; defaults preserve current behaviour)
|
|
961
|
+
observer?: UWCObserver // vendor-agnostic telemetry sink; default = no egress
|
|
962
|
+
logger?: Logger // redirect internal logging; default = console
|
|
963
|
+
logLevel?: LogLevel // console threshold; default 'warn'
|
|
964
|
+
walletResponseTimeoutMs?: number // walletTimedOut deadline; default 60_000, 0 disables
|
|
965
|
+
correlationId?: string | (() => string) // align sdkSessionId to your session key
|
|
831
966
|
}
|
|
832
967
|
|
|
833
968
|
export interface OperationOptions {
|
|
@@ -836,9 +971,15 @@ export interface OperationOptions {
|
|
|
836
971
|
|
|
837
972
|
export type UWCEventName = keyof UWCEventMap
|
|
838
973
|
export type UWCOperation =
|
|
839
|
-
| 'connect'
|
|
840
|
-
| '
|
|
841
|
-
| '
|
|
974
|
+
| 'connect'
|
|
975
|
+
| 'disconnect'
|
|
976
|
+
| 'switchNetwork'
|
|
977
|
+
| 'signMessage'
|
|
978
|
+
| 'signTypedData'
|
|
979
|
+
| 'sendTransaction'
|
|
980
|
+
| 'signSolanaTransaction'
|
|
981
|
+
| 'getWalletCapabilities'
|
|
982
|
+
| 'initialize'
|
|
842
983
|
```
|
|
843
984
|
|
|
844
985
|
### Static methods
|
|
@@ -879,6 +1020,10 @@ getNetworkSwitchLoadingState(): {
|
|
|
879
1020
|
getActiveWalletCapabilities(): Record<string, EVMCapabilities> | null
|
|
880
1021
|
isConnectionModeAvailable(mode: ConnectionMode, walletId: string): boolean
|
|
881
1022
|
|
|
1023
|
+
// Observability
|
|
1024
|
+
setLogLevel(level: LogLevel): void // tune the console threshold at runtime
|
|
1025
|
+
dispose(): void // release observer subs + clear listeners
|
|
1026
|
+
|
|
882
1027
|
// Events
|
|
883
1028
|
on<K extends UWCEventName>(event: K, listener: UWCEventListener<K>): () => void
|
|
884
1029
|
once<K extends UWCEventName>(event: K, listener: UWCEventListener<K>): () => void
|
package/dist/events.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Session, Network, WalletMetadata, ConnectionMode, WalletError, EVMCapabilities } from '@meshconnect/uwc-types';
|
|
1
|
+
import type { Session, Network, WalletMetadata, ConnectionMode, WalletError, EVMCapabilities, LogLevel, WalletFlowType, Platform, Namespace, NetworkId } from '@meshconnect/uwc-types';
|
|
2
2
|
/**
|
|
3
3
|
* User-initiated operations that can surface through the `error` event.
|
|
4
4
|
*/
|
|
5
|
-
export type UWCOperation = 'connect' | 'disconnect' | 'switchNetwork' | 'signMessage' | 'sendTransaction' | 'getWalletCapabilities' | 'initialize';
|
|
5
|
+
export type UWCOperation = 'connect' | 'disconnect' | 'switchNetwork' | 'signMessage' | 'signTypedData' | 'sendTransaction' | 'signSolanaTransaction' | 'getWalletCapabilities' | 'initialize';
|
|
6
6
|
/**
|
|
7
7
|
* Typed event map emitted by UniversalWalletConnector.
|
|
8
8
|
*
|
|
@@ -60,12 +60,79 @@ export interface UWCEventMap {
|
|
|
60
60
|
error: WalletError;
|
|
61
61
|
operation: UWCOperation;
|
|
62
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* A line emitted through the internal `Logger`. Fires for ALL levels regardless
|
|
65
|
+
* of the console threshold so an observer can capture `debug`/`info` even when
|
|
66
|
+
* the console is quiet. `args` is scrubbed before reaching `observer.onLog`.
|
|
67
|
+
*/
|
|
68
|
+
log: {
|
|
69
|
+
level: LogLevel;
|
|
70
|
+
message: string;
|
|
71
|
+
args: unknown[];
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Emitted immediately BEFORE control is handed to the wallet for a boundary op
|
|
75
|
+
* (the moment the blind window opens). Pair with exactly one terminal event via
|
|
76
|
+
* `handoffId`. Carries no signing payload and no address — only routing facets.
|
|
77
|
+
*/
|
|
78
|
+
awaitingWallet: {
|
|
79
|
+
operation: UWCOperation;
|
|
80
|
+
connectionMode: ConnectionMode;
|
|
81
|
+
walletId?: string | undefined;
|
|
82
|
+
/** CAIP namespace (eip155 | solana | tron | tvm …) — not an address. */
|
|
83
|
+
namespace?: Namespace | undefined;
|
|
84
|
+
/** CAIP chain id (e.g. `eip155:1`) — not an address. */
|
|
85
|
+
chainId?: NetworkId | undefined;
|
|
86
|
+
handoffId: string;
|
|
87
|
+
/** Derived, best-effort flow taxonomy (heuristic — see deriveWalletFlowType). */
|
|
88
|
+
walletFlowType: WalletFlowType;
|
|
89
|
+
/** Coarse runtime surface (heuristic — see derivePlatform). */
|
|
90
|
+
platform: Platform;
|
|
91
|
+
timestamp: number;
|
|
92
|
+
};
|
|
93
|
+
/** The wallet resolved the op successfully. Closes a handoff. */
|
|
94
|
+
walletSucceeded: {
|
|
95
|
+
handoffId: string;
|
|
96
|
+
operation: UWCOperation;
|
|
97
|
+
durationMs: number;
|
|
98
|
+
};
|
|
99
|
+
/** The user explicitly rejected (4001 / WalletError.type === 'rejected'). Closes a handoff. */
|
|
100
|
+
walletRejected: {
|
|
101
|
+
handoffId: string;
|
|
102
|
+
operation: UWCOperation;
|
|
103
|
+
durationMs: number;
|
|
104
|
+
};
|
|
105
|
+
/** The op failed for any non-rejection reason. Closes a handoff. */
|
|
106
|
+
walletFailed: {
|
|
107
|
+
handoffId: string;
|
|
108
|
+
operation: UWCOperation;
|
|
109
|
+
durationMs: number;
|
|
110
|
+
error: WalletError;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Side marker: the deadline passed with the op still pending. OBSERVATIONAL —
|
|
114
|
+
* it does NOT reject, abort, or mutate state; the wallet may still complete and
|
|
115
|
+
* produce the real terminal. Never fires for an op that settled before the
|
|
116
|
+
* deadline. Not itself a terminal.
|
|
117
|
+
*/
|
|
118
|
+
walletTimedOut: {
|
|
119
|
+
handoffId: string;
|
|
120
|
+
operation: UWCOperation;
|
|
121
|
+
durationMs: number;
|
|
122
|
+
};
|
|
63
123
|
/**
|
|
64
124
|
* Back-compat catch-all. Fires after every other event above.
|
|
65
125
|
* New code should prefer the specific events.
|
|
66
126
|
*/
|
|
67
127
|
change: void;
|
|
68
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Events that describe telemetry rather than a state change. `EventManager.emit`
|
|
131
|
+
* skips the legacy `change` cascade for these so high-frequency logging / handoff
|
|
132
|
+
* instrumentation can't trigger React re-renders through `subscribe()`.
|
|
133
|
+
*/
|
|
134
|
+
export declare const TELEMETRY_ONLY_EVENTS: ReadonlySet<UWCEventName>;
|
|
69
135
|
export type UWCEventName = keyof UWCEventMap;
|
|
70
136
|
export type UWCEventListener<K extends UWCEventName> = (data: UWCEventMap[K]) => void;
|
|
137
|
+
export declare const UWC_EVENT_NAMES: UWCEventName[];
|
|
71
138
|
//# sourceMappingURL=events.d.ts.map
|
package/dist/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,OAAO,EACP,cAAc,EACd,cAAc,EACd,WAAW,EACX,eAAe,
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/dist/events.js
CHANGED
|
@@ -1,2 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Events that describe telemetry rather than a state change. `EventManager.emit`
|
|
3
|
+
* skips the legacy `change` cascade for these so high-frequency logging / handoff
|
|
4
|
+
* instrumentation can't trigger React re-renders through `subscribe()`.
|
|
5
|
+
*/
|
|
6
|
+
export const TELEMETRY_ONLY_EVENTS = new Set([
|
|
7
|
+
'log',
|
|
8
|
+
'awaitingWallet',
|
|
9
|
+
'walletSucceeded',
|
|
10
|
+
'walletRejected',
|
|
11
|
+
'walletFailed',
|
|
12
|
+
'walletTimedOut'
|
|
13
|
+
]);
|
|
14
|
+
/**
|
|
15
|
+
* Runtime list of every event name. The `Record<UWCEventName, true>` literal
|
|
16
|
+
* forces this to stay exhaustive — adding an event to `UWCEventMap` without
|
|
17
|
+
* listing it here is a compile error — so the observer bridge can never silently
|
|
18
|
+
* drop a new event.
|
|
19
|
+
*/
|
|
20
|
+
const EVENT_NAME_FLAGS = {
|
|
21
|
+
ready: true,
|
|
22
|
+
walletsDetected: true,
|
|
23
|
+
connecting: true,
|
|
24
|
+
connected: true,
|
|
25
|
+
disconnected: true,
|
|
26
|
+
connectionUri: true,
|
|
27
|
+
sessionChanged: true,
|
|
28
|
+
networkSwitching: true,
|
|
29
|
+
networkSwitched: true,
|
|
30
|
+
capabilitiesUpdated: true,
|
|
31
|
+
error: true,
|
|
32
|
+
log: true,
|
|
33
|
+
awaitingWallet: true,
|
|
34
|
+
walletSucceeded: true,
|
|
35
|
+
walletRejected: true,
|
|
36
|
+
walletFailed: true,
|
|
37
|
+
walletTimedOut: true,
|
|
38
|
+
change: true
|
|
39
|
+
};
|
|
40
|
+
export const UWC_EVENT_NAMES = Object.keys(EVENT_NAME_FLAGS);
|
|
2
41
|
//# sourceMappingURL=events.js.map
|
package/dist/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AA2IA;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAA8B,IAAI,GAAG,CAAC;IACtE,KAAK;IACL,gBAAgB;IAChB,iBAAiB;IACjB,gBAAgB;IAChB,cAAc;IACd,gBAAgB;CACjB,CAAC,CAAA;AAOF;;;;;GAKG;AACH,MAAM,gBAAgB,GAA+B;IACnD,KAAK,EAAE,IAAI;IACX,eAAe,EAAE,IAAI;IACrB,UAAU,EAAE,IAAI;IAChB,SAAS,EAAE,IAAI;IACf,YAAY,EAAE,IAAI;IAClB,aAAa,EAAE,IAAI;IACnB,cAAc,EAAE,IAAI;IACpB,gBAAgB,EAAE,IAAI;IACtB,eAAe,EAAE,IAAI;IACrB,mBAAmB,EAAE,IAAI;IACzB,KAAK,EAAE,IAAI;IACX,GAAG,EAAE,IAAI;IACT,cAAc,EAAE,IAAI;IACpB,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,IAAI;IACpB,YAAY,EAAE,IAAI;IAClB,cAAc,EAAE,IAAI;IACpB,MAAM,EAAE,IAAI;CACb,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAmB,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { UniversalWalletConnector, type UWCConfig, type OperationOptions } from './universal-wallet-connector';
|
|
2
2
|
export type { UWCEventMap, UWCEventName, UWCEventListener, UWCOperation } from './events';
|
|
3
|
+
export { createLogger, type ManagedLogger, type CreateLoggerOptions } from './logger/create-logger';
|
|
4
|
+
export type { UWCObserver, UWCTelemetryEvent } from './observability/telemetry';
|
|
3
5
|
export { toBaseUnits } from './utils/to-base-units';
|
|
4
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACb,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAA;AACrC,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACb,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EAGzB,MAAM,8BAA8B,CAAA;AAOrC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EAGzB,MAAM,8BAA8B,CAAA;AAOrC,OAAO,EACL,YAAY,EAGb,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { LogLevel, Logger } from '@meshconnect/uwc-types';
|
|
2
|
+
/** The logger returned by `createLogger`, with runtime-tunable level controls. */
|
|
3
|
+
export interface ManagedLogger extends Logger {
|
|
4
|
+
/** Lower/raise the console threshold at runtime (e.g. from a support toggle). */
|
|
5
|
+
setLevel(level: LogLevel): void;
|
|
6
|
+
/** The currently configured threshold (ignores the global override). */
|
|
7
|
+
getLevel(): LogLevel;
|
|
8
|
+
}
|
|
9
|
+
export interface CreateLoggerOptions {
|
|
10
|
+
/** Console threshold. Default `'warn'` — UWC stays quiet unless asked. */
|
|
11
|
+
level?: LogLevel | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Pre-gate tap: invoked for EVERY log line regardless of the console threshold.
|
|
14
|
+
* The observer bridge subscribes here so `debug`/`info` reach remote telemetry
|
|
15
|
+
* even when the console is silent. Throws are swallowed — a bad sink must not
|
|
16
|
+
* break a log call.
|
|
17
|
+
*/
|
|
18
|
+
onLog?: ((level: LogLevel, message: string, args: unknown[]) => void) | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Output sink for gated lines. When provided (e.g. a consumer's own logger), it
|
|
21
|
+
* receives the RAW `(message, ...args)` so it can apply its own formatting. When
|
|
22
|
+
* omitted, the default `console` sink is used with an ISO/level prefix.
|
|
23
|
+
*/
|
|
24
|
+
sink?: Logger | undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Console-backed, level-gated logger. ~zero-dep. Two seams:
|
|
28
|
+
* - `onLog` fires pre-gate (all levels) → drives the observer.
|
|
29
|
+
* - the console sink fires only at/above the threshold.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createLogger(options?: CreateLoggerOptions): ManagedLogger;
|
|
32
|
+
//# sourceMappingURL=create-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-logger.d.ts","sourceRoot":"","sources":["../../src/logger/create-logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAS9D,kFAAkF;AAClF,MAAM,WAAW,aAAc,SAAQ,MAAM;IAC3C,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAA;IAC/B,wEAAwE;IACxE,QAAQ,IAAI,QAAQ,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC5B;;;;;OAKG;IACH,KAAK,CAAC,EACF,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,GAC7D,SAAS,CAAA;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1B;AA2BD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,aAAa,CAiC7E"}
|