@naculus/connect-appkit-react 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +4 -4
  2. package/dist/client.cjs +1 -1
  3. package/dist/client.cjs.map +1 -1
  4. package/dist/client.d.cts +144 -0
  5. package/dist/client.d.ts +144 -0
  6. package/dist/client.js +1 -1
  7. package/dist/client.js.map +1 -1
  8. package/dist/index.cjs +2 -1
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +2270 -0
  11. package/dist/index.d.ts +2270 -0
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/package.json +30 -12
  15. package/api-extractor.json +0 -21
  16. package/src/chain-abstraction/index.ts +0 -8
  17. package/src/chain-abstraction/useCompareCosts.ts +0 -137
  18. package/src/chain-abstraction/useExecuteRoute.ts +0 -129
  19. package/src/chain-abstraction/useRouteQuote.ts +0 -168
  20. package/src/client.test.ts +0 -242
  21. package/src/client.ts +0 -265
  22. package/src/hooks/useAccount.test.ts +0 -67
  23. package/src/hooks/useAccount.ts +0 -37
  24. package/src/hooks/useBalance.test.ts +0 -459
  25. package/src/hooks/useBalance.ts +0 -170
  26. package/src/hooks/useChain.test.ts +0 -160
  27. package/src/hooks/useChain.ts +0 -53
  28. package/src/hooks/useConnect.test.ts +0 -112
  29. package/src/hooks/useConnect.ts +0 -29
  30. package/src/hooks/useDisconnect.test.ts +0 -75
  31. package/src/hooks/useDisconnect.ts +0 -32
  32. package/src/hooks/useERC20Allowance.ts +0 -93
  33. package/src/hooks/useERC20Approve.ts +0 -220
  34. package/src/hooks/useERC20Transfer.ts +0 -134
  35. package/src/hooks/useERC20TransferSimulation.ts +0 -147
  36. package/src/hooks/useEmbeddedWallet.test.ts +0 -266
  37. package/src/hooks/useEmbeddedWallet.ts +0 -181
  38. package/src/hooks/useLastTx.test.ts +0 -117
  39. package/src/hooks/useLastTx.ts +0 -73
  40. package/src/hooks/useLookupAddress.ts +0 -131
  41. package/src/hooks/useNotification.ts +0 -308
  42. package/src/hooks/useResolveName.ts +0 -128
  43. package/src/hooks/useSIWxLogin.test.ts +0 -307
  44. package/src/hooks/useSIWxLogin.ts +0 -163
  45. package/src/hooks/useSIWxSession.test.ts +0 -481
  46. package/src/hooks/useSIWxSession.ts +0 -290
  47. package/src/hooks/useSendCalls.ts +0 -103
  48. package/src/hooks/useSendTransaction.test.ts +0 -175
  49. package/src/hooks/useSendTransaction.ts +0 -80
  50. package/src/hooks/useSendUserOperation.ts +0 -313
  51. package/src/hooks/useSession.ts +0 -96
  52. package/src/hooks/useSessionKeys.ts +0 -356
  53. package/src/hooks/useSignInWithEthereum.test.ts +0 -224
  54. package/src/hooks/useSignInWithEthereum.ts +0 -46
  55. package/src/hooks/useSignInWithX.test.ts +0 -210
  56. package/src/hooks/useSignInWithX.ts +0 -141
  57. package/src/hooks/useSignMessage.test.ts +0 -151
  58. package/src/hooks/useSignMessage.ts +0 -65
  59. package/src/hooks/useSimulateTransfer.ts +0 -165
  60. package/src/hooks/useSiwxAuthSession.test.ts +0 -456
  61. package/src/hooks/useSiwxAuthSession.ts +0 -163
  62. package/src/hooks/useSmartAccount.ts +0 -194
  63. package/src/hooks/useSwitchChain.ts +0 -68
  64. package/src/hooks/useTokenBalance.test.ts +0 -337
  65. package/src/hooks/useTokenBalance.ts +0 -210
  66. package/src/hooks/useTransactionSimulation.ts +0 -401
  67. package/src/hooks/useTxHistory.test.ts +0 -108
  68. package/src/hooks/useTxHistory.ts +0 -83
  69. package/src/hooks/useTxMonitor.test.ts +0 -127
  70. package/src/hooks/useTxMonitor.ts +0 -178
  71. package/src/hooks/useUserOpStatus.ts +0 -245
  72. package/src/hooks/useValidateDestination.test.ts +0 -96
  73. package/src/hooks/useValidateDestination.ts +0 -72
  74. package/src/hooks/useViemClient.test.ts +0 -155
  75. package/src/hooks/useViemClient.ts +0 -65
  76. package/src/hooks/useWallet.test.ts +0 -133
  77. package/src/hooks/useWallet.ts +0 -39
  78. package/src/hooks/useWeb3ErrorHandler.ts +0 -102
  79. package/src/index.ts +0 -186
  80. package/src/provider/Web3ConnectProvider.test.tsx +0 -178
  81. package/src/provider/Web3ConnectProvider.tsx +0 -530
  82. package/src/token-list/TokenSelector.tsx +0 -351
  83. package/src/token-list/defaults.ts +0 -39
  84. package/src/token-list/index.ts +0 -14
  85. package/src/token-list/useTokenList.ts +0 -119
  86. package/src/token-list/useTokenSearch.ts +0 -99
  87. package/src/types/index.ts +0 -99
  88. package/src/utils/chains.ts +0 -115
  89. package/src/utils/errorMessages.ts +0 -142
  90. package/src/utils/i18n.ts +0 -90
  91. package/src/wc-generated/components.ts +0 -377
  92. package/test/setup.ts +0 -17
  93. package/test/test-utils.tsx +0 -78
  94. package/tsup.config.ts +0 -18
@@ -1,131 +0,0 @@
1
- import { useState, useEffect, useCallback, useRef } from "react";
2
- import { NameResolver } from "@naculus/connect-core";
3
- import type { NameResult, NameResolverConfig } from "@naculus/connect-core";
4
-
5
- /**
6
- * Options for the useLookupAddress hook.
7
- */
8
- export interface UseLookupAddressOptions {
9
- /** Optional CAIP-2 chain ID to hint which provider to use. */
10
- chainId?: string;
11
- /** Whether to skip lookup. Default: false. */
12
- skip?: boolean;
13
- /** Custom resolver configuration (overrides default RPC URLs). */
14
- resolverConfig?: NameResolverConfig;
15
- }
16
-
17
- /**
18
- * Result of an address reverse-lookup query.
19
- */
20
- export interface UseLookupAddressResult {
21
- /** Resolved name, or null if not found / not started. */
22
- data: NameResult | null;
23
- /** Whether the lookup is in progress. */
24
- isLoading: boolean;
25
- /** Error that occurred during lookup, if any. */
26
- error: Error | null;
27
- /** Manually trigger re-lookup of the current address. */
28
- refetch: () => void;
29
- }
30
-
31
- // Lazy singleton resolver to avoid creating one per component instance.
32
- let sharedResolver: NameResolver | null = null;
33
-
34
- function getResolver(config?: NameResolverConfig): NameResolver {
35
- if (config) {
36
- return new NameResolver(config);
37
- }
38
- if (!sharedResolver) {
39
- sharedResolver = new NameResolver();
40
- }
41
- return sharedResolver;
42
- }
43
-
44
- /**
45
- * React hook to reverse-lookup a blockchain address to find its human-readable name.
46
- *
47
- * Supports ENS (.eth) and SNS (.sol) names.
48
- * Auto-detects the name service from the address format or chainId hint.
49
- *
50
- * @example
51
- * ```tsx
52
- * function TransactionRow({ address }: { address: string }) {
53
- * const { data, isLoading } = useLookupAddress(address);
54
- * return <span>{data?.name ?? address}</span>;
55
- * }
56
- * ```
57
- */
58
- export function useLookupAddress(
59
- address: string,
60
- options?: UseLookupAddressOptions,
61
- ): UseLookupAddressResult {
62
- const [data, setData] = useState<NameResult | null>(null);
63
- const [isLoading, setIsLoading] = useState(false);
64
- const [error, setError] = useState<Error | null>(null);
65
- const chainId = options?.chainId;
66
- const skip = options?.skip ?? false;
67
- const resolverRef = useRef<NameResolver | null>(null);
68
- const activeAddrRef = useRef<string>("");
69
- const mountedRef = useRef(true);
70
-
71
- // Keep mounted ref current
72
- useEffect(() => {
73
- mountedRef.current = true;
74
- return () => {
75
- mountedRef.current = false;
76
- };
77
- }, []);
78
-
79
- const resolver = resolverRef.current ?? getResolver(options?.resolverConfig);
80
- resolverRef.current = resolver;
81
-
82
- const lookup = useCallback(() => {
83
- const cleanAddr = address.trim();
84
-
85
- if (!cleanAddr || skip) {
86
- setData(null);
87
- setIsLoading(false);
88
- setError(null);
89
- return;
90
- }
91
-
92
- // Avoid re-looking-up the same address
93
- if (activeAddrRef.current === cleanAddr && data) {
94
- return;
95
- }
96
-
97
- activeAddrRef.current = cleanAddr;
98
- setIsLoading(true);
99
- setError(null);
100
-
101
- resolver
102
- .lookupAddress(cleanAddr, chainId)
103
- .then((result) => {
104
- if (mountedRef.current) {
105
- setData(result);
106
- setIsLoading(false);
107
- }
108
- })
109
- .catch((err: unknown) => {
110
- if (mountedRef.current) {
111
- const resolutionError =
112
- err instanceof Error ? err : new Error(String(err));
113
- setError(resolutionError);
114
- setData(null);
115
- setIsLoading(false);
116
- }
117
- });
118
- }, [address, chainId, skip]);
119
-
120
- // Lookup when address or chainId changes
121
- useEffect(() => {
122
- lookup();
123
- }, [lookup]);
124
-
125
- const refetch = useCallback(() => {
126
- activeAddrRef.current = "";
127
- lookup();
128
- }, [lookup]);
129
-
130
- return { data, isLoading, error, refetch };
131
- }
@@ -1,308 +0,0 @@
1
- /**
2
- * useNotification — React hook for push notification state.
3
- *
4
- * Provides notifications, settings, and control methods for the
5
- * in-app notification center.
6
- *
7
- * @example
8
- * ```tsx
9
- * import { useNotification } from "@naculus/connect-appkit-react";
10
- *
11
- * function NotificationCenter() {
12
- * const { notifications, unreadCount, clear, markAsRead } = useNotification();
13
- * return (
14
- * <div>
15
- * <span>Unread: {unreadCount}</span>
16
- * <ul>
17
- * {notifications.map(n => (
18
- * <li key={n.id} onClick={() => markAsRead(n.id)}>
19
- * {n.title} — {n.body}
20
- * </li>
21
- * ))}
22
- * </ul>
23
- * <button onClick={clear}>Clear all</button>
24
- * </div>
25
- * );
26
- * }
27
- * ```
28
- */
29
-
30
- import { useState, useCallback, useMemo, useEffect, useRef } from "react";
31
- import {
32
- InAppChannel,
33
- type NotificationItem,
34
- type NotificationSettings,
35
- type NotificationFrequency,
36
- type TxStatus,
37
- } from "@naculus/connect-core";
38
- import { createStorageAdapter } from "@naculus/connect-core";
39
-
40
- // ─── Default settings ─────────────────────────────────────────────────
41
-
42
- const DEFAULT_SETTINGS: NotificationSettings = {
43
- telegram: false,
44
- webpush: false,
45
- inapp: true,
46
- frequency: "final-only" as NotificationFrequency,
47
- mutedChains: [],
48
- mutedTypes: [],
49
- };
50
-
51
- const STORAGE_KEY_SETTINGS = "naculus_notif_react_settings";
52
-
53
- // ─── Hook ──────────────────────────────────────────────────────────────
54
-
55
- /**
56
- * Hook for consuming in-app notifications in React components.
57
- *
58
- * Uses InAppChannel internally to manage the notification queue.
59
- * All persistent state is stored via localStorage.
60
- */
61
- export function useNotification(options?: {
62
- /** External InAppChannel instance (for sharing between hooks). If omitted, creates one. */
63
- channel?: InAppChannel;
64
- /** Custom storage for settings (defaults to localStorage) */
65
- storage?: {
66
- getItem: <T>(key: string) => Promise<T | null>;
67
- setItem: <T>(key: string, value: T) => Promise<void>;
68
- removeItem: (key: string) => Promise<void>;
69
- };
70
- }) {
71
- // ── Channel ──────────────────────────────────────────────────────
72
-
73
- const channelRef = useRef<InAppChannel | null>(null);
74
-
75
- if (!channelRef.current) {
76
- channelRef.current = options?.channel ?? new InAppChannel();
77
- }
78
-
79
- const channel = channelRef.current;
80
-
81
- // ── State ────────────────────────────────────────────────────────
82
-
83
- const [notifications, setNotifications] = useState<NotificationItem[]>(() =>
84
- channel.getHistory(),
85
- );
86
-
87
- const [settings, setSettingsState] = useState<NotificationSettings>(() => {
88
- // Try to load from storage, fall back to default
89
- return DEFAULT_SETTINGS;
90
- });
91
-
92
- // ── Load persisted settings on mount ──────────────────────────────
93
-
94
- useEffect(() => {
95
- const storage = options?.storage ?? createReactStorage();
96
- storage.getItem<NotificationSettings>(STORAGE_KEY_SETTINGS).then((saved) => {
97
- if (saved) {
98
- setSettingsState(saved);
99
- }
100
- });
101
- // eslint-disable-next-line react-hooks/exhaustive-deps
102
- }, []);
103
-
104
- // ── Sync notifications with channel ──────────────────────────────
105
-
106
- useEffect(() => {
107
- // Set up callback to reactively update state when new notifications arrive
108
- channel.onNotification = (item) => {
109
- setNotifications((prev) => [...prev, item]);
110
- };
111
-
112
- // Restore persisted history
113
- channel.restore().then(() => {
114
- setNotifications(channel.getHistory());
115
- });
116
-
117
- return () => {
118
- // Cleanup: deregister callback on unmount
119
- channel.onNotification = undefined;
120
- };
121
- // eslint-disable-next-line react-hooks/exhaustive-deps
122
- }, []);
123
-
124
- // ── Computed ─────────────────────────────────────────────────────
125
-
126
- const unreadCount = useMemo(() => {
127
- return notifications.filter((n) => !n.read).length;
128
- }, [notifications]);
129
-
130
- // ── Actions ──────────────────────────────────────────────────────
131
-
132
- const clear = useCallback(() => {
133
- channel.clear();
134
- setNotifications([]);
135
- }, [channel]);
136
-
137
- const clearOne = useCallback((id: string) => {
138
- const updated = channel.getHistory().filter((n) => n.id !== id);
139
- // Mutate channel history in place (we recreate from the in-memory history)
140
- channel.clear();
141
- // Re-add the ones we want to keep
142
- Promise.all(
143
- updated.map((item) =>
144
- channel.send({
145
- id: item.id,
146
- userId: "",
147
- txHash: item.txHash,
148
- chainId: "",
149
- chainName: item.chainName,
150
- status: item.status,
151
- title: item.title,
152
- body: item.body,
153
- valueFormatted: item.valueFormatted,
154
- explorerUrl: item.explorerUrl,
155
- timestamp: item.timestamp,
156
- }),
157
- ),
158
- ).then(() => {
159
- // Force re-sync
160
- setNotifications(channel.getHistory());
161
- });
162
- }, [channel]);
163
-
164
- const markAsRead = useCallback(
165
- (id: string) => {
166
- channel.markAsRead(id);
167
- setNotifications((prev) =>
168
- prev.map((n) => (n.id === id ? { ...n, read: true } : n)),
169
- );
170
- },
171
- [channel],
172
- );
173
-
174
- const markAllAsRead = useCallback(() => {
175
- channel.markAllAsRead();
176
- setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
177
- }, [channel]);
178
-
179
- // ── Add single notification ──────────────────────────────────────
180
-
181
- const addNotification = useCallback(
182
- (item: Omit<NotificationItem, "id" | "timestamp">) => {
183
- const full: NotificationItem = {
184
- ...item,
185
- id: `notif_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
186
- timestamp: Date.now(),
187
- };
188
- channel.send({
189
- id: full.id,
190
- userId: "",
191
- txHash: full.txHash,
192
- chainId: "",
193
- chainName: full.chainName,
194
- status: full.status,
195
- title: full.title,
196
- body: full.body,
197
- valueFormatted: full.valueFormatted,
198
- explorerUrl: full.explorerUrl,
199
- timestamp: full.timestamp,
200
- });
201
- // The onNotification callback will update state
202
- },
203
- [channel],
204
- );
205
-
206
- // ── Settings ──────────────────────────────────────────────────────
207
-
208
- const updateSettings = useCallback(
209
- (update: Partial<NotificationSettings>) => {
210
- setSettingsState((prev) => {
211
- const next = { ...prev, ...update };
212
- const storage = options?.storage ?? createReactStorage();
213
- storage.setItem(STORAGE_KEY_SETTINGS, next).catch(() => {});
214
- return next;
215
- });
216
- },
217
- [options?.storage],
218
- );
219
-
220
- const setChannels = useCallback(
221
- (channels: string[]) => {
222
- const update: Partial<NotificationSettings> = {};
223
- if (channels.includes("telegram")) update.telegram = true;
224
- if (channels.includes("webpush")) update.webpush = true;
225
- if (channels.includes("inapp")) update.inapp = true;
226
- updateSettings(update);
227
- },
228
- [updateSettings],
229
- );
230
-
231
- const muteChain = useCallback(
232
- (chainId: string) => {
233
- updateSettings({
234
- mutedChains: [...new Set([...settings.mutedChains, chainId])],
235
- });
236
- },
237
- [settings.mutedChains, updateSettings],
238
- );
239
-
240
- const unmuteChain = useCallback(
241
- (chainId: string) => {
242
- updateSettings({
243
- mutedChains: settings.mutedChains.filter((c) => c !== chainId),
244
- });
245
- },
246
- [settings.mutedChains, updateSettings],
247
- );
248
-
249
- // ── Return ───────────────────────────────────────────────────────
250
-
251
- return {
252
- /** All in-app notifications (newest last) */
253
- notifications,
254
- /** Number of unread notifications */
255
- unreadCount,
256
- /** Add a single notification manually */
257
- addNotification,
258
- /** Clear all in-app notifications */
259
- clear,
260
- /** Clear a single notification */
261
- clearOne,
262
- /** Mark a notification as read */
263
- markAsRead,
264
- /** Mark all as read */
265
- markAllAsRead,
266
- /** Current notification settings */
267
- settings,
268
- /** Update notification settings */
269
- updateSettings,
270
- /** Set active channels by id */
271
- setChannels,
272
- /** Mute a chain */
273
- muteChain,
274
- /** Unmute a chain */
275
- unmuteChain,
276
- };
277
- }
278
-
279
- // ─── Storage helper ───────────────────────────────────────────────────
280
-
281
- function createReactStorage() {
282
- const storage = createStorageAdapter("local", "naculus_notif_");
283
-
284
- return {
285
- getItem: async <T>(key: string): Promise<T | null> => {
286
- try {
287
- return await storage.get<T>(key);
288
- } catch (e) {
289
- console.warn("useNotification: failed to read from storage:", e);
290
- return null;
291
- }
292
- },
293
- setItem: async <T>(key: string, value: T): Promise<void> => {
294
- try {
295
- await storage.set(key, value);
296
- } catch (e) {
297
- console.warn("useNotification: failed to write to storage:", e);
298
- }
299
- },
300
- removeItem: async (key: string): Promise<void> => {
301
- try {
302
- await storage.remove(key);
303
- } catch (e) {
304
- console.warn("useNotification: failed to remove from storage:", e);
305
- }
306
- },
307
- };
308
- }
@@ -1,128 +0,0 @@
1
- import { useState, useEffect, useCallback, useRef } from "react";
2
- import { NameResolver } from "@naculus/connect-core";
3
- import type { AddressResult, NameResolverConfig } from "@naculus/connect-core";
4
-
5
- /**
6
- * Options for the useResolveName hook.
7
- */
8
- export interface UseResolveNameOptions {
9
- /** Whether to skip resolution (e.g. if input is invalid). Default: false. */
10
- skip?: boolean;
11
- /** Custom resolver configuration (overrides default RPC URLs). */
12
- resolverConfig?: NameResolverConfig;
13
- }
14
-
15
- /**
16
- * Result of a name resolution query.
17
- */
18
- export interface UseResolveNameResult {
19
- /** Resolved address, or null if not found / not started. */
20
- data: AddressResult | null;
21
- /** Whether the resolution is in progress. */
22
- isLoading: boolean;
23
- /** Error that occurred during resolution, if any. */
24
- error: Error | null;
25
- /** Manually trigger re-resolution of the current name. */
26
- refetch: () => void;
27
- }
28
-
29
- // Lazy singleton resolver to avoid creating one per component instance.
30
- let sharedResolver: NameResolver | null = null;
31
-
32
- function getResolver(config?: NameResolverConfig): NameResolver {
33
- if (config) {
34
- return new NameResolver(config);
35
- }
36
- if (!sharedResolver) {
37
- sharedResolver = new NameResolver();
38
- }
39
- return sharedResolver;
40
- }
41
-
42
- /**
43
- * React hook to resolve a human-readable name to a blockchain address.
44
- *
45
- * Supports ENS (.eth) and SNS (.sol) names.
46
- * Automatically detects the name service from the suffix.
47
- *
48
- * @example
49
- * ```tsx
50
- * function AddressInput() {
51
- * const { data, isLoading, error } = useResolveName('vitalik.eth');
52
- * return <div>{data?.address ?? 'Enter a name'}</div>;
53
- * }
54
- * ```
55
- */
56
- export function useResolveName(
57
- name: string,
58
- options?: UseResolveNameOptions,
59
- ): UseResolveNameResult {
60
- const [data, setData] = useState<AddressResult | null>(null);
61
- const [isLoading, setIsLoading] = useState(false);
62
- const [error, setError] = useState<Error | null>(null);
63
- const skip = options?.skip ?? false;
64
- const resolverRef = useRef<NameResolver | null>(null);
65
- const activeNameRef = useRef<string>("");
66
- const mountedRef = useRef(true);
67
-
68
- // Keep mounted ref current
69
- useEffect(() => {
70
- mountedRef.current = true;
71
- return () => {
72
- mountedRef.current = false;
73
- };
74
- }, []);
75
-
76
- const resolver = resolverRef.current ?? getResolver(options?.resolverConfig);
77
- resolverRef.current = resolver;
78
-
79
- const resolve = useCallback(() => {
80
- const cleanName = name.trim();
81
-
82
- if (!cleanName || skip) {
83
- setData(null);
84
- setIsLoading(false);
85
- setError(null);
86
- return;
87
- }
88
-
89
- // Avoid re-resolving the same name
90
- if (activeNameRef.current === cleanName && data) {
91
- return;
92
- }
93
-
94
- activeNameRef.current = cleanName;
95
- setIsLoading(true);
96
- setError(null);
97
-
98
- resolver
99
- .resolveName(cleanName)
100
- .then((result) => {
101
- if (mountedRef.current) {
102
- setData(result);
103
- setIsLoading(false);
104
- }
105
- })
106
- .catch((err: unknown) => {
107
- if (mountedRef.current) {
108
- const resolutionError =
109
- err instanceof Error ? err : new Error(String(err));
110
- setError(resolutionError);
111
- setData(null);
112
- setIsLoading(false);
113
- }
114
- });
115
- }, [name, skip]);
116
-
117
- // Resolve when name changes
118
- useEffect(() => {
119
- resolve();
120
- }, [resolve]);
121
-
122
- const refetch = useCallback(() => {
123
- activeNameRef.current = "";
124
- resolve();
125
- }, [resolve]);
126
-
127
- return { data, isLoading, error, refetch };
128
- }