@meshconnect/uwc-react 0.6.10-snapshot.75ebef9 → 0.6.10-snapshot.bcb597e

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.
@@ -9,4 +9,5 @@ export * from './useSignMessage';
9
9
  export * from './useTransaction';
10
10
  export * from './useWalletCapabilities';
11
11
  export * from './useDetectedWallets';
12
+ export * from './useSignSolanaTransaction';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA"}
@@ -9,4 +9,5 @@ export * from './useSignMessage';
9
9
  export * from './useTransaction';
10
10
  export * from './useWalletCapabilities';
11
11
  export * from './useDetectedWallets';
12
+ export * from './useSignSolanaTransaction';
12
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,oBAAoB,CAAA;AAClC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA"}
@@ -0,0 +1,8 @@
1
+ import type { WalletError } from '@meshconnect/uwc-types';
2
+ export interface UseSignSolanaTransactionReturn {
3
+ signSolanaTransaction: (serializedTx: Uint8Array) => Promise<Uint8Array>;
4
+ isLoading: boolean;
5
+ error: WalletError | undefined;
6
+ }
7
+ export declare function useSignSolanaTransaction(): UseSignSolanaTransactionReturn;
8
+ //# sourceMappingURL=useSignSolanaTransaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSignSolanaTransaction.d.ts","sourceRoot":"","sources":["../../src/hooks/useSignSolanaTransaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD,MAAM,WAAW,8BAA8B;IAC7C,qBAAqB,EAAE,CAAC,YAAY,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;IACxE,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,WAAW,GAAG,SAAS,CAAA;CAC/B;AAED,wBAAgB,wBAAwB,IAAI,8BAA8B,CA2CzE"}
@@ -0,0 +1,34 @@
1
+ import { useContext, useCallback, useState } from 'react';
2
+ import { ConnectionContext } from '../providers/ConnectionProvider';
3
+ export function useSignSolanaTransaction() {
4
+ const context = useContext(ConnectionContext);
5
+ if (!context) {
6
+ throw new Error('useSignSolanaTransaction must be used within a ConnectionProvider');
7
+ }
8
+ const { connector } = context;
9
+ const [isLoading, setIsLoading] = useState(false);
10
+ const [error, setError] = useState();
11
+ const signSolanaTransaction = useCallback(async (serializedTx) => {
12
+ setIsLoading(true);
13
+ setError(undefined);
14
+ try {
15
+ // [UWC ONC-3267] TEMP — revert before merge
16
+ // eslint-disable-next-line no-console
17
+ console.log('[UWC ONC-3267] hook.useSignSolanaTransaction entry, bytes=', serializedTx.length);
18
+ const result = await connector.signSolanaTransaction(serializedTx);
19
+ // eslint-disable-next-line no-console
20
+ console.log('[UWC ONC-3267] hook.useSignSolanaTransaction returned, bytes=', result.length);
21
+ return result;
22
+ }
23
+ catch (err) {
24
+ const walletError = err;
25
+ setError(walletError);
26
+ throw err;
27
+ }
28
+ finally {
29
+ setIsLoading(false);
30
+ }
31
+ }, [connector]);
32
+ return { signSolanaTransaction, isLoading, error };
33
+ }
34
+ //# sourceMappingURL=useSignSolanaTransaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSignSolanaTransaction.js","sourceRoot":"","sources":["../../src/hooks/useSignSolanaTransaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AASnE,MAAM,UAAU,wBAAwB;IACtC,MAAM,OAAO,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAA;IAE7C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,mEAAmE,CACpE,CAAA;IACH,CAAC;IAED,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IAC7B,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACjD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,EAA2B,CAAA;IAE7D,MAAM,qBAAqB,GAAG,WAAW,CACvC,KAAK,EAAE,YAAwB,EAAuB,EAAE;QACtD,YAAY,CAAC,IAAI,CAAC,CAAA;QAClB,QAAQ,CAAC,SAAS,CAAC,CAAA;QACnB,IAAI,CAAC;YACH,4CAA4C;YAC5C,sCAAsC;YACtC,OAAO,CAAC,GAAG,CACT,4DAA4D,EAC5D,YAAY,CAAC,MAAM,CACpB,CAAA;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAAA;YAClE,sCAAsC;YACtC,OAAO,CAAC,GAAG,CACT,+DAA+D,EAC/D,MAAM,CAAC,MAAM,CACd,CAAA;YACD,OAAO,MAAM,CAAA;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,WAAW,GAAG,GAAkB,CAAA;YACtC,QAAQ,CAAC,WAAW,CAAC,CAAA;YACrB,MAAM,GAAG,CAAA;QACX,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAA;QACrB,CAAC;IACH,CAAC,EACD,CAAC,SAAS,CAAC,CACZ,CAAA;IAED,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;AACpD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meshconnect/uwc-react",
3
- "version": "0.6.10-snapshot.75ebef9",
3
+ "version": "0.6.10-snapshot.bcb597e",
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-core": "0.7.10-snapshot.75ebef9",
20
- "@meshconnect/uwc-types": "0.12.1-snapshot.75ebef9"
19
+ "@meshconnect/uwc-core": "0.7.10-snapshot.bcb597e",
20
+ "@meshconnect/uwc-types": "0.12.1-snapshot.bcb597e"
21
21
  },
22
22
  "peerDependencies": {
23
23
  "react": "^18.0.0",
@@ -9,3 +9,4 @@ export * from './useSignMessage'
9
9
  export * from './useTransaction'
10
10
  export * from './useWalletCapabilities'
11
11
  export * from './useDetectedWallets'
12
+ export * from './useSignSolanaTransaction'
@@ -0,0 +1,241 @@
1
+ import React, { act } from 'react'
2
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
3
+ import { createRoot } from 'react-dom/client'
4
+ import { ConnectionContext } from '../providers/ConnectionProvider'
5
+ import { useSignSolanaTransaction } from './useSignSolanaTransaction'
6
+ import type { UseSignSolanaTransactionReturn } from './useSignSolanaTransaction'
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Helpers
10
+ // ---------------------------------------------------------------------------
11
+
12
+ /** Minimal stub that satisfies ConnectionContextValue's connector shape. */
13
+ function makeConnector(
14
+ signSolanaTransaction: (tx: Uint8Array) => Promise<Uint8Array>
15
+ ) {
16
+ return {
17
+ signSolanaTransaction,
18
+ // other connector methods are not exercised by this hook
19
+ getSession: () => ({ isConnected: false }),
20
+ isReady: () => true,
21
+ subscribe: () => () => {},
22
+ getWallets: () => [],
23
+ getNetworks: () => []
24
+ }
25
+ }
26
+
27
+ /** Minimal context value that wraps a connector stub. */
28
+ function makeContextValue(connector: ReturnType<typeof makeConnector>) {
29
+ return {
30
+ connector,
31
+ session: {
32
+ isConnected: false,
33
+ walletId: undefined,
34
+ networkId: undefined,
35
+ activeAddress: undefined
36
+ },
37
+ wallets: [],
38
+ networks: [],
39
+ isReady: true
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Renders `useSignSolanaTransaction` inside a component that exposes its
45
+ * return value via a captured ref. Returns the ref and cleanup helpers.
46
+ *
47
+ * Pattern mirrors ConnectionProvider.singleton.test.tsx: createRoot + act,
48
+ * no @testing-library/react (not installed in this package).
49
+ */
50
+ function renderHookInContext(
51
+ contextValue: ReturnType<typeof makeContextValue>
52
+ ) {
53
+ const captured: { current: UseSignSolanaTransactionReturn | null } = {
54
+ current: null
55
+ }
56
+
57
+ function Capture() {
58
+ captured.current = useSignSolanaTransaction()
59
+ return null
60
+ }
61
+
62
+ const container = document.createElement('div')
63
+ document.body.appendChild(container)
64
+ const root = createRoot(container)
65
+
66
+ async function render() {
67
+ await act(async () => {
68
+ root.render(
69
+ <ConnectionContext.Provider value={contextValue as never}>
70
+ <Capture />
71
+ </ConnectionContext.Provider>
72
+ )
73
+ })
74
+ }
75
+
76
+ async function unmount() {
77
+ await act(async () => {
78
+ root.unmount()
79
+ })
80
+ document.body.removeChild(container)
81
+ }
82
+
83
+ return { captured, render, unmount }
84
+ }
85
+
86
+ // ---------------------------------------------------------------------------
87
+ // Tests
88
+ // ---------------------------------------------------------------------------
89
+
90
+ describe('useSignSolanaTransaction', () => {
91
+ let container: HTMLDivElement
92
+ let root: ReturnType<typeof createRoot>
93
+
94
+ beforeEach(() => {
95
+ container = document.createElement('div')
96
+ document.body.appendChild(container)
97
+ root = createRoot(container)
98
+ })
99
+
100
+ afterEach(async () => {
101
+ await act(async () => {
102
+ root.unmount()
103
+ })
104
+ if (document.body.contains(container)) {
105
+ document.body.removeChild(container)
106
+ }
107
+ })
108
+
109
+ // (a) throws when used outside ConnectionProvider
110
+ it('throws when rendered outside ConnectionProvider', () => {
111
+ function BareHook() {
112
+ useSignSolanaTransaction()
113
+ return null
114
+ }
115
+
116
+ expect(() => {
117
+ // Synchronous render — React will throw during render, caught here.
118
+ // Suppress the React error boundary console.error noise.
119
+ const originalError = console.error
120
+ console.error = () => {}
121
+ try {
122
+ act(() => {
123
+ root.render(<BareHook />)
124
+ })
125
+ } finally {
126
+ console.error = originalError
127
+ }
128
+ }).toThrowError(
129
+ 'useSignSolanaTransaction must be used within a ConnectionProvider'
130
+ )
131
+ })
132
+
133
+ // (b) returns the Uint8Array from connector.signSolanaTransaction on success
134
+ it('returns the signed bytes from connector on success', async () => {
135
+ const signedBytes = new Uint8Array([1, 2, 3, 4])
136
+ const mockSign = vi.fn().mockResolvedValue(signedBytes)
137
+ const ctxValue = makeContextValue(makeConnector(mockSign))
138
+ const { captured, render, unmount } = renderHookInContext(ctxValue)
139
+
140
+ await render()
141
+ expect(captured.current).not.toBeNull()
142
+
143
+ const input = new Uint8Array([9, 8, 7])
144
+ let result: Uint8Array | undefined
145
+
146
+ await act(async () => {
147
+ result = await captured.current!.signSolanaTransaction(input)
148
+ })
149
+
150
+ expect(mockSign).toHaveBeenCalledOnce()
151
+ expect(mockSign).toHaveBeenCalledWith(input)
152
+ expect(result).toBe(signedBytes)
153
+ await unmount()
154
+ })
155
+
156
+ // (c) sets error state and re-throws when connector.signSolanaTransaction rejects
157
+ it('sets error state and re-throws when connector rejects', async () => {
158
+ const walletError = { code: 4001, message: 'User rejected' }
159
+ const mockSign = vi.fn().mockRejectedValue(walletError)
160
+ const ctxValue = makeContextValue(makeConnector(mockSign))
161
+ const { captured, render, unmount } = renderHookInContext(ctxValue)
162
+
163
+ await render()
164
+
165
+ let thrownError: unknown
166
+ await act(async () => {
167
+ try {
168
+ await captured.current!.signSolanaTransaction(new Uint8Array([1]))
169
+ } catch (err) {
170
+ thrownError = err
171
+ }
172
+ })
173
+
174
+ expect(thrownError).toBe(walletError)
175
+ expect(captured.current!.error).toBe(walletError)
176
+ await unmount()
177
+ })
178
+
179
+ // (d) isLoading is true during the call and false after — success path
180
+ it('sets isLoading=true during call and false after success', async () => {
181
+ let resolveSign!: (v: Uint8Array) => void
182
+ const pendingSign = new Promise<Uint8Array>(res => {
183
+ resolveSign = res
184
+ })
185
+ const mockSign = vi.fn().mockReturnValue(pendingSign)
186
+ const ctxValue = makeContextValue(makeConnector(mockSign))
187
+ const { captured, render, unmount } = renderHookInContext(ctxValue)
188
+
189
+ await render()
190
+
191
+ // Start the async call but don't await it yet — capture loading mid-flight
192
+ let callPromise: Promise<Uint8Array>
193
+ await act(async () => {
194
+ callPromise = captured.current!.signSolanaTransaction(new Uint8Array([5]))
195
+ })
196
+
197
+ // At this point the hook has flipped isLoading=true (setIsLoading runs before the await)
198
+ expect(captured.current!.isLoading).toBe(true)
199
+
200
+ // Settle the promise
201
+ await act(async () => {
202
+ resolveSign(new Uint8Array([99]))
203
+ await callPromise!
204
+ })
205
+
206
+ expect(captured.current!.isLoading).toBe(false)
207
+ await unmount()
208
+ })
209
+
210
+ // (d) isLoading is false after failure path
211
+ it('sets isLoading=false after connector rejects', async () => {
212
+ let rejectSign!: (err: unknown) => void
213
+ const pendingSign = new Promise<Uint8Array>((_, rej) => {
214
+ rejectSign = rej
215
+ })
216
+ const mockSign = vi.fn().mockReturnValue(pendingSign)
217
+ const ctxValue = makeContextValue(makeConnector(mockSign))
218
+ const { captured, render, unmount } = renderHookInContext(ctxValue)
219
+
220
+ await render()
221
+
222
+ let callPromise: Promise<Uint8Array>
223
+ await act(async () => {
224
+ callPromise = captured.current!.signSolanaTransaction(new Uint8Array([6]))
225
+ })
226
+
227
+ expect(captured.current!.isLoading).toBe(true)
228
+
229
+ await act(async () => {
230
+ rejectSign({ code: 4001, message: 'cancelled' })
231
+ try {
232
+ await callPromise!
233
+ } catch {
234
+ // expected
235
+ }
236
+ })
237
+
238
+ expect(captured.current!.isLoading).toBe(false)
239
+ await unmount()
240
+ })
241
+ })
@@ -0,0 +1,54 @@
1
+ import { useContext, useCallback, useState } from 'react'
2
+ import { ConnectionContext } from '../providers/ConnectionProvider'
3
+ import type { WalletError } from '@meshconnect/uwc-types'
4
+
5
+ export interface UseSignSolanaTransactionReturn {
6
+ signSolanaTransaction: (serializedTx: Uint8Array) => Promise<Uint8Array>
7
+ isLoading: boolean
8
+ error: WalletError | undefined
9
+ }
10
+
11
+ export function useSignSolanaTransaction(): UseSignSolanaTransactionReturn {
12
+ const context = useContext(ConnectionContext)
13
+
14
+ if (!context) {
15
+ throw new Error(
16
+ 'useSignSolanaTransaction must be used within a ConnectionProvider'
17
+ )
18
+ }
19
+
20
+ const { connector } = context
21
+ const [isLoading, setIsLoading] = useState(false)
22
+ const [error, setError] = useState<WalletError | undefined>()
23
+
24
+ const signSolanaTransaction = useCallback(
25
+ async (serializedTx: Uint8Array): Promise<Uint8Array> => {
26
+ setIsLoading(true)
27
+ setError(undefined)
28
+ try {
29
+ // [UWC ONC-3267] TEMP — revert before merge
30
+ // eslint-disable-next-line no-console
31
+ console.log(
32
+ '[UWC ONC-3267] hook.useSignSolanaTransaction entry, bytes=',
33
+ serializedTx.length
34
+ )
35
+ const result = await connector.signSolanaTransaction(serializedTx)
36
+ // eslint-disable-next-line no-console
37
+ console.log(
38
+ '[UWC ONC-3267] hook.useSignSolanaTransaction returned, bytes=',
39
+ result.length
40
+ )
41
+ return result
42
+ } catch (err) {
43
+ const walletError = err as WalletError
44
+ setError(walletError)
45
+ throw err
46
+ } finally {
47
+ setIsLoading(false)
48
+ }
49
+ },
50
+ [connector]
51
+ )
52
+
53
+ return { signSolanaTransaction, isLoading, error }
54
+ }