@meshconnect/uwc-react 0.9.4 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/useConnection.d.ts.map +1 -1
- package/dist/hooks/useConnection.js +15 -6
- package/dist/hooks/useConnection.js.map +1 -1
- package/dist/hooks/useConnectionContext.d.ts +15 -0
- package/dist/hooks/useConnectionContext.d.ts.map +1 -0
- package/dist/hooks/useConnectionContext.js +22 -0
- package/dist/hooks/useConnectionContext.js.map +1 -0
- package/dist/hooks/useDetectedWallets.d.ts.map +1 -1
- package/dist/hooks/useDetectedWallets.js +6 -6
- package/dist/hooks/useDetectedWallets.js.map +1 -1
- package/dist/hooks/useDisconnect.d.ts.map +1 -1
- package/dist/hooks/useDisconnect.js +6 -6
- package/dist/hooks/useDisconnect.js.map +1 -1
- package/dist/hooks/useNetworks.d.ts.map +1 -1
- package/dist/hooks/useNetworks.js +2 -6
- package/dist/hooks/useNetworks.js.map +1 -1
- package/dist/hooks/useSession.d.ts.map +1 -1
- package/dist/hooks/useSession.js +2 -6
- package/dist/hooks/useSession.js.map +1 -1
- package/dist/hooks/useSignMessage.d.ts.map +1 -1
- package/dist/hooks/useSignMessage.js +4 -7
- package/dist/hooks/useSignMessage.js.map +1 -1
- package/dist/hooks/useSignSolanaTransaction.d.ts.map +1 -1
- package/dist/hooks/useSignSolanaTransaction.js +4 -7
- package/dist/hooks/useSignSolanaTransaction.js.map +1 -1
- package/dist/hooks/useSignTypedData.d.ts.map +1 -1
- package/dist/hooks/useSignTypedData.js +4 -7
- package/dist/hooks/useSignTypedData.js.map +1 -1
- package/dist/hooks/useSwitchNetwork.d.ts.map +1 -1
- package/dist/hooks/useSwitchNetwork.js +9 -6
- package/dist/hooks/useSwitchNetwork.js.map +1 -1
- package/dist/hooks/useTransaction.d.ts.map +1 -1
- package/dist/hooks/useTransaction.js +4 -7
- package/dist/hooks/useTransaction.js.map +1 -1
- package/dist/hooks/useWallet.d.ts.map +1 -1
- package/dist/hooks/useWallet.js +2 -6
- package/dist/hooks/useWallet.js.map +1 -1
- package/dist/hooks/useWalletCapabilities.d.ts.map +1 -1
- package/dist/hooks/useWalletCapabilities.js +6 -8
- package/dist/hooks/useWalletCapabilities.js.map +1 -1
- package/dist/hooks/useWallets.d.ts.map +1 -1
- package/dist/hooks/useWallets.js +2 -6
- package/dist/hooks/useWallets.js.map +1 -1
- package/dist/providers/ConnectionProvider.d.ts +10 -2
- package/dist/providers/ConnectionProvider.d.ts.map +1 -1
- package/dist/providers/ConnectionProvider.js +32 -5
- package/dist/providers/ConnectionProvider.js.map +1 -1
- package/package.json +2 -2
- package/src/hooks/useConnection.ts +18 -8
- package/src/hooks/useConnectionContext.ts +25 -0
- package/src/hooks/useDetectedWallets.ts +6 -10
- package/src/hooks/useDisconnect.ts +6 -8
- package/src/hooks/useNetworks.ts +2 -8
- package/src/hooks/useSession.ts +2 -8
- package/src/hooks/useSignMessage.ts +4 -9
- package/src/hooks/useSignSolanaTransaction.ts +4 -11
- package/src/hooks/useSignTypedData.ts +4 -9
- package/src/hooks/useSwitchNetwork.ts +10 -8
- package/src/hooks/useTransaction.ts +4 -9
- package/src/hooks/useWallet.ts +2 -8
- package/src/hooks/useWalletCapabilities.ts +6 -12
- package/src/hooks/useWallets.ts +2 -8
- package/src/providers/ConnectionProvider.emptyWallets.test.tsx +105 -0
- package/src/providers/ConnectionProvider.singleton.test.tsx +18 -7
- package/src/providers/ConnectionProvider.tsx +46 -7
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { UniversalWalletConnector } from '@meshconnect/uwc-core';
|
|
3
3
|
import type { Session, Network, WalletMetadata, WalletConnectConfig, TonConnectConfig, TronConnectorConfig } from '@meshconnect/uwc-types';
|
|
4
|
-
interface ConnectionContextValue {
|
|
5
|
-
|
|
4
|
+
export interface ConnectionContextValue {
|
|
5
|
+
/**
|
|
6
|
+
* `null` when the provider is mounted without wallets. `@meshconnect/uwc-core`
|
|
7
|
+
* requires at least one wallet to construct a connector, so a wallet-less
|
|
8
|
+
* session (e.g. a CEX-only catalog) legitimately has none. Hooks treat a null
|
|
9
|
+
* connector as "no wallet session" and return inert values instead of
|
|
10
|
+
* throwing, so a host that mounts this provider for every session — wallet or
|
|
11
|
+
* not — does not crash.
|
|
12
|
+
*/
|
|
13
|
+
connector: UniversalWalletConnector | null;
|
|
6
14
|
session: Session;
|
|
7
15
|
wallets: WalletMetadata[];
|
|
8
16
|
networks: Network[];
|
|
@@ -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;
|
|
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"}
|
|
@@ -3,15 +3,42 @@ 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
|
+
/**
|
|
7
|
+
* Session served before any wallet is connected — and while the provider is
|
|
8
|
+
* mounted without wallets (a wallet-less session; see `connector` below). Every
|
|
9
|
+
* field is at its natural empty per the `Session` type, so the read-only hooks
|
|
10
|
+
* (`useSession`/`useNetworks`/`useWallets`) work unchanged and the sign/transfer
|
|
11
|
+
* hooks short-circuit on their existing `activeAddress` guard.
|
|
12
|
+
*/
|
|
13
|
+
const EMPTY_SESSION = {
|
|
14
|
+
connectionMode: null,
|
|
15
|
+
activeNetwork: null,
|
|
16
|
+
activeWalletCapabilities: null,
|
|
17
|
+
activeNetworkWalletCapabilities: null,
|
|
18
|
+
activeAddress: null,
|
|
19
|
+
publicKey: null,
|
|
20
|
+
availableNetworks: [],
|
|
21
|
+
activeWallet: null,
|
|
22
|
+
availableAddresses: []
|
|
23
|
+
};
|
|
6
24
|
const ConnectionContext = createContext(null);
|
|
7
25
|
export function ConnectionProvider({ children, networks, wallets, usingIntegratedBrowser = false, walletConnectConfig, tonConnectConfig, tronConnectorConfig }) {
|
|
8
|
-
|
|
26
|
+
// Core rejects an empty wallet list, so only construct once there is at least
|
|
27
|
+
// one wallet. A wallet-less session keeps `connector` null; the effect below
|
|
28
|
+
// adopts the connector if wallets arrive later (async catalog population).
|
|
29
|
+
if (!sharedConnector && wallets.length > 0) {
|
|
9
30
|
sharedConnector = new UniversalWalletConnector(networks, wallets, usingIntegratedBrowser, walletConnectConfig, tonConnectConfig, tronConnectorConfig);
|
|
10
31
|
}
|
|
11
32
|
const connector = sharedConnector;
|
|
12
|
-
const [session, setSession] = useState(() => connector
|
|
13
|
-
const [isReady, setIsReady] = useState(() => connector
|
|
33
|
+
const [session, setSession] = useState(() => connector?.getSession() ?? EMPTY_SESSION);
|
|
34
|
+
const [isReady, setIsReady] = useState(() => connector?.isReady() ?? false);
|
|
14
35
|
useEffect(() => {
|
|
36
|
+
if (!connector)
|
|
37
|
+
return;
|
|
38
|
+
// Sync once on adoption — covers the case where the connector was created
|
|
39
|
+
// after the first render (wallets populated asynchronously).
|
|
40
|
+
setSession(connector.getSession());
|
|
41
|
+
setIsReady(connector.isReady());
|
|
15
42
|
const unsubscribe = connector.subscribe(() => {
|
|
16
43
|
setSession(connector.getSession());
|
|
17
44
|
setIsReady(connector.isReady());
|
|
@@ -21,8 +48,8 @@ export function ConnectionProvider({ children, networks, wallets, usingIntegrate
|
|
|
21
48
|
const value = {
|
|
22
49
|
connector,
|
|
23
50
|
session,
|
|
24
|
-
wallets: connector.getWallets(),
|
|
25
|
-
networks: connector.getNetworks(),
|
|
51
|
+
wallets: connector ? connector.getWallets() : wallets,
|
|
52
|
+
networks: connector ? connector.getNetworks() : networks,
|
|
26
53
|
isReady
|
|
27
54
|
};
|
|
28
55
|
return (_jsx(ConnectionContext.Provider, { value: value, children: children }));
|
|
@@ -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;
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshconnect/uwc-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "React hooks and components for Universal Wallet Connector",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@meshconnect/uwc-core": "1.0.
|
|
19
|
+
"@meshconnect/uwc-core": "1.0.3",
|
|
20
20
|
"@meshconnect/uwc-types": "0.16.1"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState, useEffect } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
import type {
|
|
4
4
|
NetworkId,
|
|
5
5
|
UseConnectionReturn,
|
|
@@ -26,12 +26,7 @@ import type {
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export function useConnection(walletId: string): UseConnectionReturn {
|
|
29
|
-
const context =
|
|
30
|
-
|
|
31
|
-
if (!context) {
|
|
32
|
-
throw new Error('useConnection must be used within a ConnectionProvider')
|
|
33
|
-
}
|
|
34
|
-
|
|
29
|
+
const context = useConnectionContext('useConnection')
|
|
35
30
|
const { connector, isReady } = context
|
|
36
31
|
|
|
37
32
|
const [walletConnectLoading, setWalletConnectLoading] = useState(false)
|
|
@@ -52,6 +47,9 @@ export function useConnection(walletId: string): UseConnectionReturn {
|
|
|
52
47
|
|
|
53
48
|
// Update connection URI and availability when they change
|
|
54
49
|
useEffect(() => {
|
|
50
|
+
// No connector (wallet-less session): nothing to connect or track.
|
|
51
|
+
if (!connector) return
|
|
52
|
+
|
|
55
53
|
const checkState = () => {
|
|
56
54
|
const uri = connector.getConnectionURI()
|
|
57
55
|
|
|
@@ -89,6 +87,10 @@ export function useConnection(walletId: string): UseConnectionReturn {
|
|
|
89
87
|
|
|
90
88
|
const connectWalletConnect = useCallback(
|
|
91
89
|
async (networkId?: NetworkId) => {
|
|
90
|
+
if (!connector) {
|
|
91
|
+
throw new Error('No wallet connected')
|
|
92
|
+
}
|
|
93
|
+
|
|
92
94
|
setWalletConnectLoading(true)
|
|
93
95
|
setWalletConnectError(undefined)
|
|
94
96
|
setWalletConnectURI(undefined)
|
|
@@ -123,6 +125,10 @@ export function useConnection(walletId: string): UseConnectionReturn {
|
|
|
123
125
|
|
|
124
126
|
const connectInjected = useCallback(
|
|
125
127
|
async (networkId?: NetworkId) => {
|
|
128
|
+
if (!connector) {
|
|
129
|
+
throw new Error('No wallet connected')
|
|
130
|
+
}
|
|
131
|
+
|
|
126
132
|
setInjectedLoading(true)
|
|
127
133
|
setInjectedError(undefined)
|
|
128
134
|
try {
|
|
@@ -140,6 +146,10 @@ export function useConnection(walletId: string): UseConnectionReturn {
|
|
|
140
146
|
|
|
141
147
|
const connectTonConnect = useCallback(
|
|
142
148
|
async (networkId?: NetworkId) => {
|
|
149
|
+
if (!connector) {
|
|
150
|
+
throw new Error('No wallet connected')
|
|
151
|
+
}
|
|
152
|
+
|
|
143
153
|
setTonConnectLoading(true)
|
|
144
154
|
setTonConnectError(undefined)
|
|
145
155
|
setTonConnectURI(undefined)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useContext } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
ConnectionContext,
|
|
4
|
+
type ConnectionContextValue
|
|
5
|
+
} from '../providers/ConnectionProvider'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Reads the connection context, throwing the canonical
|
|
9
|
+
* "must be used within a ConnectionProvider" error when the hook is used
|
|
10
|
+
* outside the provider tree. Centralizes the guard every hook needs so the
|
|
11
|
+
* check and its message live in one place.
|
|
12
|
+
*
|
|
13
|
+
* Note: a non-null context can still carry a `null` connector (a wallet-less
|
|
14
|
+
* session — see `ConnectionContextValue.connector`). Callers that need the
|
|
15
|
+
* connector must handle that case; this guard only covers "no provider".
|
|
16
|
+
*
|
|
17
|
+
* @param hookName - Name used in the error, e.g. `'useSession'`.
|
|
18
|
+
*/
|
|
19
|
+
export function useConnectionContext(hookName: string): ConnectionContextValue {
|
|
20
|
+
const context = useContext(ConnectionContext)
|
|
21
|
+
if (!context) {
|
|
22
|
+
throw new Error(`${hookName} must be used within a ConnectionProvider`)
|
|
23
|
+
}
|
|
24
|
+
return context
|
|
25
|
+
}
|
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
import type {
|
|
4
4
|
UseDetectedWalletsReturn,
|
|
5
5
|
WalletMetadata
|
|
6
6
|
} from '@meshconnect/uwc-types'
|
|
7
7
|
|
|
8
8
|
export function useDetectedWallets(): UseDetectedWalletsReturn {
|
|
9
|
-
const context =
|
|
10
|
-
|
|
11
|
-
if (!context) {
|
|
12
|
-
throw new Error(
|
|
13
|
-
'useInjectedAvailableWallets must be used within a ConnectionProvider'
|
|
14
|
-
)
|
|
15
|
-
}
|
|
16
|
-
|
|
9
|
+
const context = useConnectionContext('useInjectedAvailableWallets')
|
|
17
10
|
const { connector, wallets, isReady } = context
|
|
18
11
|
|
|
19
12
|
const [detectedWallets, setDetectedWallets] = useState<WalletMetadata[]>([])
|
|
20
13
|
|
|
21
14
|
useEffect(() => {
|
|
15
|
+
// No connector (wallet-less session): nothing can be detected.
|
|
16
|
+
if (!connector) return
|
|
17
|
+
|
|
22
18
|
const checkState = () => {
|
|
23
19
|
const newDetectedWallets = wallets.filter(wallet =>
|
|
24
20
|
connector.isConnectionModeAvailable('injected', wallet.id)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
|
|
4
4
|
interface UseDisconnectReturn {
|
|
5
5
|
disconnect: () => Promise<void>
|
|
@@ -27,16 +27,14 @@ interface UseDisconnectReturn {
|
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
29
|
export function useDisconnect(): UseDisconnectReturn {
|
|
30
|
-
const context =
|
|
31
|
-
|
|
32
|
-
if (!context) {
|
|
33
|
-
throw new Error('useDisconnect must be used within a ConnectionProvider')
|
|
34
|
-
}
|
|
35
|
-
|
|
30
|
+
const context = useConnectionContext('useDisconnect')
|
|
36
31
|
const { connector } = context
|
|
37
32
|
const [isLoading, setIsLoading] = useState(false)
|
|
38
33
|
|
|
39
34
|
const disconnect = useCallback(async () => {
|
|
35
|
+
// No connector (wallet-less session) means nothing to disconnect.
|
|
36
|
+
if (!connector) return
|
|
37
|
+
|
|
40
38
|
setIsLoading(true)
|
|
41
39
|
try {
|
|
42
40
|
await connector.disconnect()
|
package/src/hooks/useNetworks.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ConnectionContext } from '../providers/ConnectionProvider'
|
|
1
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
2
|
import type { Network } from '@meshconnect/uwc-types'
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -16,11 +15,6 @@ import type { Network } from '@meshconnect/uwc-types'
|
|
|
16
15
|
* ```
|
|
17
16
|
*/
|
|
18
17
|
export function useNetworks(): Network[] {
|
|
19
|
-
const context =
|
|
20
|
-
|
|
21
|
-
if (!context) {
|
|
22
|
-
throw new Error('useNetworks must be used within a ConnectionProvider')
|
|
23
|
-
}
|
|
24
|
-
|
|
18
|
+
const context = useConnectionContext('useNetworks')
|
|
25
19
|
return context.networks
|
|
26
20
|
}
|
package/src/hooks/useSession.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ConnectionContext } from '../providers/ConnectionProvider'
|
|
1
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
2
|
import type { UseSessionReturn } from '@meshconnect/uwc-types'
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -18,12 +17,7 @@ import type { UseSessionReturn } from '@meshconnect/uwc-types'
|
|
|
18
17
|
* ```
|
|
19
18
|
*/
|
|
20
19
|
export function useSession(): UseSessionReturn {
|
|
21
|
-
const context =
|
|
22
|
-
|
|
23
|
-
if (!context) {
|
|
24
|
-
throw new Error('useSession must be used within a ConnectionProvider')
|
|
25
|
-
}
|
|
26
|
-
|
|
20
|
+
const context = useConnectionContext('useSession')
|
|
27
21
|
const { session } = context
|
|
28
22
|
|
|
29
23
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
import type {
|
|
4
4
|
SignatureType,
|
|
5
5
|
UseSignMessageReturn,
|
|
@@ -26,12 +26,7 @@ import type {
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export function useSignMessage(): UseSignMessageReturn {
|
|
29
|
-
const context =
|
|
30
|
-
|
|
31
|
-
if (!context) {
|
|
32
|
-
throw new Error('useSignMessage must be used within a ConnectionProvider')
|
|
33
|
-
}
|
|
34
|
-
|
|
29
|
+
const context = useConnectionContext('useSignMessage')
|
|
35
30
|
const { connector, session } = context
|
|
36
31
|
const [isLoading, setIsLoading] = useState(false)
|
|
37
32
|
const [signature, setSignature] = useState<SignatureType | undefined>()
|
|
@@ -39,7 +34,7 @@ export function useSignMessage(): UseSignMessageReturn {
|
|
|
39
34
|
|
|
40
35
|
const signMessage = useCallback(
|
|
41
36
|
async (message: string): Promise<SignatureType> => {
|
|
42
|
-
if (!session.activeAddress) {
|
|
37
|
+
if (!connector || !session.activeAddress) {
|
|
43
38
|
throw new Error('No wallet connected')
|
|
44
39
|
}
|
|
45
40
|
|
|
@@ -1,26 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
import type {
|
|
4
4
|
UseSignSolanaTransactionReturn,
|
|
5
5
|
WalletError
|
|
6
6
|
} from '@meshconnect/uwc-types'
|
|
7
7
|
|
|
8
8
|
export function useSignSolanaTransaction(): UseSignSolanaTransactionReturn {
|
|
9
|
-
const context =
|
|
10
|
-
|
|
11
|
-
if (!context) {
|
|
12
|
-
throw new Error(
|
|
13
|
-
'useSignSolanaTransaction must be used within a ConnectionProvider'
|
|
14
|
-
)
|
|
15
|
-
}
|
|
16
|
-
|
|
9
|
+
const context = useConnectionContext('useSignSolanaTransaction')
|
|
17
10
|
const { connector, session } = context
|
|
18
11
|
const [isLoading, setIsLoading] = useState(false)
|
|
19
12
|
const [error, setError] = useState<WalletError | undefined>()
|
|
20
13
|
|
|
21
14
|
const signSolanaTransaction = useCallback(
|
|
22
15
|
async (serializedTx: Uint8Array): Promise<Uint8Array> => {
|
|
23
|
-
if (!session.activeAddress) {
|
|
16
|
+
if (!connector || !session.activeAddress) {
|
|
24
17
|
throw new Error('No wallet connected')
|
|
25
18
|
}
|
|
26
19
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
import type {
|
|
4
4
|
EIP712TypedData,
|
|
5
5
|
UseSignTypedDataReturn,
|
|
@@ -30,12 +30,7 @@ import type {
|
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
32
|
export function useSignTypedData(): UseSignTypedDataReturn {
|
|
33
|
-
const context =
|
|
34
|
-
|
|
35
|
-
if (!context) {
|
|
36
|
-
throw new Error('useSignTypedData must be used within a ConnectionProvider')
|
|
37
|
-
}
|
|
38
|
-
|
|
33
|
+
const context = useConnectionContext('useSignTypedData')
|
|
39
34
|
const { connector, session } = context
|
|
40
35
|
const [isLoading, setIsLoading] = useState(false)
|
|
41
36
|
const [signature, setSignature] = useState<string | undefined>()
|
|
@@ -43,7 +38,7 @@ export function useSignTypedData(): UseSignTypedDataReturn {
|
|
|
43
38
|
|
|
44
39
|
const signTypedData = useCallback(
|
|
45
40
|
async (typedData: EIP712TypedData): Promise<string> => {
|
|
46
|
-
if (!session.activeAddress) {
|
|
41
|
+
if (!connector || !session.activeAddress) {
|
|
47
42
|
throw new Error('No wallet connected')
|
|
48
43
|
}
|
|
49
44
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState, useEffect } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
import type {
|
|
4
4
|
NetworkId,
|
|
5
5
|
UseSwitchNetworkReturn,
|
|
@@ -32,12 +32,7 @@ import type {
|
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
export function useSwitchNetwork(): UseSwitchNetworkReturn {
|
|
35
|
-
const context =
|
|
36
|
-
|
|
37
|
-
if (!context) {
|
|
38
|
-
throw new Error('useSwitchNetwork must be used within a ConnectionProvider')
|
|
39
|
-
}
|
|
40
|
-
|
|
35
|
+
const context = useConnectionContext('useSwitchNetwork')
|
|
41
36
|
const { connector } = context
|
|
42
37
|
const [isLoading, setIsLoading] = useState(false)
|
|
43
38
|
const [isWaitingForUserApproval, setIsWaitingForUserApproval] =
|
|
@@ -46,6 +41,9 @@ export function useSwitchNetwork(): UseSwitchNetworkReturn {
|
|
|
46
41
|
|
|
47
42
|
// Subscribe to loading state changes from the core
|
|
48
43
|
useEffect(() => {
|
|
44
|
+
// No connector (wallet-less session): no switch state to track.
|
|
45
|
+
if (!connector) return
|
|
46
|
+
|
|
49
47
|
const updateLoadingState = () => {
|
|
50
48
|
const state = connector.getNetworkSwitchLoadingState()
|
|
51
49
|
setIsLoading(state.isLoading)
|
|
@@ -63,6 +61,10 @@ export function useSwitchNetwork(): UseSwitchNetworkReturn {
|
|
|
63
61
|
|
|
64
62
|
const switchNetwork = useCallback(
|
|
65
63
|
async (networkId: NetworkId) => {
|
|
64
|
+
if (!connector) {
|
|
65
|
+
throw new Error('No wallet connected')
|
|
66
|
+
}
|
|
67
|
+
|
|
66
68
|
setError(undefined)
|
|
67
69
|
try {
|
|
68
70
|
await connector.switchNetwork(networkId)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
import type {
|
|
4
4
|
TransactionRequest,
|
|
5
5
|
TransactionResult,
|
|
@@ -30,12 +30,7 @@ import type {
|
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
32
|
export function useTransaction(): UseTransactionReturn {
|
|
33
|
-
const context =
|
|
34
|
-
|
|
35
|
-
if (!context) {
|
|
36
|
-
throw new Error('useTransaction must be used within a ConnectionProvider')
|
|
37
|
-
}
|
|
38
|
-
|
|
33
|
+
const context = useConnectionContext('useTransaction')
|
|
39
34
|
const { connector, session } = context
|
|
40
35
|
const [isLoading, setIsLoading] = useState(false)
|
|
41
36
|
const [transactionResult, setTransactionResult] = useState<
|
|
@@ -45,7 +40,7 @@ export function useTransaction(): UseTransactionReturn {
|
|
|
45
40
|
|
|
46
41
|
const sendTransaction = useCallback(
|
|
47
42
|
async (request: TransactionRequest): Promise<TransactionResult> => {
|
|
48
|
-
if (!session.activeAddress) {
|
|
43
|
+
if (!connector || !session.activeAddress) {
|
|
49
44
|
throw new Error('No wallet connected')
|
|
50
45
|
}
|
|
51
46
|
|
package/src/hooks/useWallet.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ConnectionContext } from '../providers/ConnectionProvider'
|
|
1
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
2
|
import type { WalletMetadata, UseWalletReturn } from '@meshconnect/uwc-types'
|
|
4
3
|
import { WalletConnectorError } from '@meshconnect/uwc-types'
|
|
5
4
|
|
|
@@ -18,12 +17,7 @@ import { WalletConnectorError } from '@meshconnect/uwc-types'
|
|
|
18
17
|
* }
|
|
19
18
|
*/
|
|
20
19
|
export function useWallet(walletId: string): UseWalletReturn {
|
|
21
|
-
const context =
|
|
22
|
-
|
|
23
|
-
if (!context) {
|
|
24
|
-
throw new Error('useWallet must be used within a ConnectionProvider')
|
|
25
|
-
}
|
|
26
|
-
|
|
20
|
+
const context = useConnectionContext('useWallet')
|
|
27
21
|
const selectedWallet = context.wallets.find(
|
|
28
22
|
(wallet: WalletMetadata) => wallet.id === walletId
|
|
29
23
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useState } from 'react'
|
|
2
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
3
|
import type {
|
|
4
4
|
UseWalletCapabilitiesReturn,
|
|
5
5
|
WalletError
|
|
@@ -27,14 +27,7 @@ import type {
|
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
29
|
export function useWalletCapabilities(): UseWalletCapabilitiesReturn {
|
|
30
|
-
const context =
|
|
31
|
-
|
|
32
|
-
if (!context) {
|
|
33
|
-
throw new Error(
|
|
34
|
-
'useWalletCapabilities must be used within a ConnectionProvider'
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
30
|
+
const context = useConnectionContext('useWalletCapabilities')
|
|
38
31
|
const { connector, session } = context
|
|
39
32
|
|
|
40
33
|
const [isLoading, setIsLoading] = useState(false)
|
|
@@ -42,8 +35,9 @@ export function useWalletCapabilities(): UseWalletCapabilitiesReturn {
|
|
|
42
35
|
|
|
43
36
|
// Manual fetch function to be called from the app
|
|
44
37
|
const fetchCapabilities = useCallback(async () => {
|
|
45
|
-
//
|
|
46
|
-
|
|
38
|
+
// No connector (wallet-less session) or no active session/address: nothing
|
|
39
|
+
// to fetch.
|
|
40
|
+
if (!connector || !session?.activeAddress || !session?.connectionMode) {
|
|
47
41
|
return
|
|
48
42
|
}
|
|
49
43
|
|
package/src/hooks/useWallets.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ConnectionContext } from '../providers/ConnectionProvider'
|
|
1
|
+
import { useConnectionContext } from './useConnectionContext'
|
|
3
2
|
import type { WalletMetadata } from '@meshconnect/uwc-types'
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -16,11 +15,6 @@ import type { WalletMetadata } from '@meshconnect/uwc-types'
|
|
|
16
15
|
* ```
|
|
17
16
|
*/
|
|
18
17
|
export function useWallets(): WalletMetadata[] {
|
|
19
|
-
const context =
|
|
20
|
-
|
|
21
|
-
if (!context) {
|
|
22
|
-
throw new Error('useWallets must be used within a ConnectionProvider')
|
|
23
|
-
}
|
|
24
|
-
|
|
18
|
+
const context = useConnectionContext('useWallets')
|
|
25
19
|
return context.wallets
|
|
26
20
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useContext, act } from 'react'
|
|
2
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
3
|
+
import { createRoot } from 'react-dom/client'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A wallet-less session (e.g. a CEX-only catalog) mounts the provider with an
|
|
7
|
+
* empty wallet list. `@meshconnect/uwc-core` rejects an empty wallet list, so
|
|
8
|
+
* the provider must NOT construct a connector — it serves a null connector and
|
|
9
|
+
* an empty session, and the hooks stay inert instead of crashing. This guards
|
|
10
|
+
* the exact regression where bumping core to a version that throws on empty
|
|
11
|
+
* wallets took down the whole widget for CEX-only sessions.
|
|
12
|
+
*/
|
|
13
|
+
describe('ConnectionProvider — wallet-less session', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.resetModules()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('does not construct a connector and exposes a null connector + empty session', async () => {
|
|
19
|
+
vi.doMock('@meshconnect/uwc-core', () => {
|
|
20
|
+
class UniversalWalletConnector {
|
|
21
|
+
static calls = 0
|
|
22
|
+
constructor() {
|
|
23
|
+
UniversalWalletConnector.calls++
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { UniversalWalletConnector }
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const { ConnectionProvider, ConnectionContext } =
|
|
30
|
+
await import('./ConnectionProvider')
|
|
31
|
+
const { useSession } = await import('../hooks/useSession')
|
|
32
|
+
const { UniversalWalletConnector } = await import('@meshconnect/uwc-core')
|
|
33
|
+
|
|
34
|
+
let connector: unknown = 'unset'
|
|
35
|
+
let activeAddress: unknown = 'unset'
|
|
36
|
+
let availableNetworks: unknown = 'unset'
|
|
37
|
+
|
|
38
|
+
function Capture() {
|
|
39
|
+
const ctx = useContext(ConnectionContext)
|
|
40
|
+
connector = ctx?.connector
|
|
41
|
+
const session = useSession()
|
|
42
|
+
activeAddress = session.activeAddress
|
|
43
|
+
availableNetworks = session.availableNetworks
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const container = document.createElement('div')
|
|
48
|
+
document.body.appendChild(container)
|
|
49
|
+
const root = createRoot(container)
|
|
50
|
+
|
|
51
|
+
await act(async () => {
|
|
52
|
+
root.render(
|
|
53
|
+
<ConnectionProvider networks={[]} wallets={[]}>
|
|
54
|
+
<Capture />
|
|
55
|
+
</ConnectionProvider>
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// Core was never constructed (its guard would have thrown on []).
|
|
60
|
+
// @ts-expect-error test-only property
|
|
61
|
+
expect(UniversalWalletConnector.calls).toBe(0)
|
|
62
|
+
expect(connector).toBeNull()
|
|
63
|
+
// Read-only session hooks return the empty session, not a crash.
|
|
64
|
+
expect(activeAddress).toBeNull()
|
|
65
|
+
expect(availableNetworks).toEqual([])
|
|
66
|
+
|
|
67
|
+
await act(async () => {
|
|
68
|
+
root.unmount()
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('keeps action hooks inert — switchNetwork rejects with "No wallet connected"', async () => {
|
|
73
|
+
const { ConnectionProvider } = await import('./ConnectionProvider')
|
|
74
|
+
const { useSwitchNetwork } = await import('../hooks/useSwitchNetwork')
|
|
75
|
+
|
|
76
|
+
let switchNetwork:
|
|
77
|
+
| ((networkId: `${string}:${string}`) => Promise<void>)
|
|
78
|
+
| undefined
|
|
79
|
+
|
|
80
|
+
function Capture() {
|
|
81
|
+
switchNetwork = useSwitchNetwork().switchNetwork
|
|
82
|
+
return null
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const container = document.createElement('div')
|
|
86
|
+
document.body.appendChild(container)
|
|
87
|
+
const root = createRoot(container)
|
|
88
|
+
|
|
89
|
+
await act(async () => {
|
|
90
|
+
root.render(
|
|
91
|
+
<ConnectionProvider networks={[]} wallets={[]}>
|
|
92
|
+
<Capture />
|
|
93
|
+
</ConnectionProvider>
|
|
94
|
+
)
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
await expect(switchNetwork?.('eip155:1')).rejects.toThrow(
|
|
98
|
+
'No wallet connected'
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
await act(async () => {
|
|
102
|
+
root.unmount()
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
})
|