@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,72 +0,0 @@
1
- /**
2
- * useValidateDestination — address blackhole prevention hook.
3
- *
4
- * Validates that a destination address is not a known burn/zero address
5
- * before sending a transaction. Returns { isValid, warning, level }.
6
- *
7
- * Level: "safe" | "warning" | "blocked"
8
- */
9
-
10
- import { useMemo } from "react";
11
- import { t } from "../utils/i18n";
12
-
13
- // ── Known burn / zero addresses ─────────────────────────────────
14
-
15
- const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
16
- const DEAD_ADDRESSES = new Set([
17
- ZERO_ADDRESS,
18
- "0x0000000000000000000000000000000000000001",
19
- "0x000000000000000000000000000000000000dead",
20
- "0x000000000000000000000000000000000000dEaD",
21
- ]);
22
-
23
- function isBurnAddress(addr: string): boolean {
24
- const lower = addr.toLowerCase();
25
- if (DEAD_ADDRESSES.has(lower)) return true;
26
- return lower.includes("dead") && lower.length >= 40;
27
- }
28
-
29
- function isZeroAddress(addr: string): boolean {
30
- return addr === ZERO_ADDRESS;
31
- }
32
-
33
- function isValidFormat(addr: string): boolean {
34
- return /^0x[0-9a-fA-F]{40}$/.test(addr);
35
- }
36
-
37
- export type AddressValidationLevel = "safe" | "warning" | "blocked";
38
-
39
- export interface AddressValidationResult {
40
- isValid: boolean;
41
- level: AddressValidationLevel;
42
- warning: string | null;
43
- }
44
-
45
- export function validateDestination(address: string): AddressValidationResult {
46
- if (!address) {
47
- return { isValid: false, level: "blocked", warning: t("address.empty") };
48
- }
49
- if (!isValidFormat(address)) {
50
- return { isValid: false, level: "blocked", warning: t("address.invalid_format") };
51
- }
52
- if (isZeroAddress(address)) {
53
- return { isValid: false, level: "blocked", warning: t("address.zero_address") };
54
- }
55
- if (isBurnAddress(address)) {
56
- return { isValid: false, level: "blocked", warning: t("address.burn_address") };
57
- }
58
- return { isValid: true, level: "safe", warning: null };
59
- }
60
-
61
- export interface UseValidateDestinationOptions {
62
- address: string;
63
- }
64
-
65
- export interface UseValidateDestinationReturn {
66
- validation: AddressValidationResult;
67
- }
68
-
69
- export function useValidateDestination({ address }: UseValidateDestinationOptions): UseValidateDestinationReturn {
70
- const validation = useMemo(() => validateDestination(address), [address]);
71
- return { validation };
72
- }
@@ -1,155 +0,0 @@
1
- /// <reference types="vitest" />
2
- /// @vitest-environment jsdom
3
-
4
- import { describe, it, expect, vi, beforeEach } from "vitest";
5
- import { renderHook } from "@testing-library/react";
6
-
7
- const mockUseAccount = vi.fn();
8
- vi.mock("./useAccount", () => ({
9
- useAccount: () => mockUseAccount(),
10
- }));
11
-
12
- const mockUseChain = vi.fn();
13
- vi.mock("./useChain", () => ({
14
- useChain: () => mockUseChain(),
15
- }));
16
-
17
- vi.mock("../utils/chains", () => ({
18
- getDefaultChains: () => [
19
- { id: 1, namespace: "eip155", name: "Ethereum", rpcUrl: "https://eth.llamarpc.com", token: "ETH" },
20
- ],
21
- }));
22
-
23
- import { useViemClient } from "./useViemClient";
24
-
25
- describe("useViemClient", () => {
26
- beforeEach(() => {
27
- vi.clearAllMocks();
28
- });
29
-
30
- it("should return null clients when not connected", () => {
31
- mockUseAccount.mockReturnValue({
32
- evmAccount: null,
33
- isConnected: false,
34
- });
35
- mockUseChain.mockReturnValue({
36
- currentChain: null,
37
- chains: [{ id: 1, namespace: "eip155", name: "Ethereum", rpcUrl: "https://eth.llamarpc.com", token: "ETH" }],
38
- });
39
-
40
- const { result } = renderHook(() => useViemClient());
41
-
42
- expect(result.current.publicClient).toBeNull();
43
- expect(result.current.walletClient).toBeNull();
44
- expect(result.current.chains).toHaveLength(1);
45
- });
46
-
47
- it("should create public client when chain has rpcUrl", () => {
48
- mockUseAccount.mockReturnValue({
49
- evmAccount: null,
50
- isConnected: false,
51
- });
52
- mockUseChain.mockReturnValue({
53
- currentChain: {
54
- id: 1,
55
- namespace: "eip155",
56
- name: "Ethereum",
57
- rpcUrl: "https://eth.llamarpc.com",
58
- token: "ETH",
59
- },
60
- });
61
-
62
- const { result } = renderHook(() => useViemClient());
63
-
64
- expect(result.current.publicClient).not.toBeNull();
65
- expect(result.current.publicClient?.chain?.id).toBe(1);
66
- // walletClient should still be null since not connected
67
- expect(result.current.walletClient).toBeNull();
68
- });
69
-
70
- it("should create both public and wallet client when connected with evm account", () => {
71
- mockUseAccount.mockReturnValue({
72
- evmAccount: "eip155:1:0x1234567890123456789012345678901234567890",
73
- isConnected: true,
74
- });
75
- mockUseChain.mockReturnValue({
76
- currentChain: {
77
- id: 1,
78
- namespace: "eip155",
79
- name: "Ethereum",
80
- rpcUrl: "https://eth.llamarpc.com",
81
- token: "ETH",
82
- },
83
- });
84
-
85
- const { result } = renderHook(() => useViemClient());
86
-
87
- expect(result.current.publicClient).not.toBeNull();
88
- expect(result.current.walletClient).not.toBeNull();
89
- expect(result.current.walletClient?.account?.address).toBe("0x1234567890123456789012345678901234567890");
90
- });
91
-
92
- it("should handle plain address format (without eip155 prefix)", () => {
93
- mockUseAccount.mockReturnValue({
94
- evmAccount: "0xabcdef1234567890abcdef1234567890abcdef12",
95
- isConnected: true,
96
- });
97
- mockUseChain.mockReturnValue({
98
- currentChain: {
99
- id: 137,
100
- namespace: "eip155",
101
- name: "Polygon",
102
- rpcUrl: "https://polygon-rpc.com",
103
- token: "MATIC",
104
- },
105
- });
106
-
107
- const { result } = renderHook(() => useViemClient());
108
-
109
- expect(result.current.publicClient).not.toBeNull();
110
- expect(result.current.walletClient).not.toBeNull();
111
- expect(result.current.walletClient?.account?.address).toBe("0xabcdef1234567890abcdef1234567890abcdef12");
112
- });
113
-
114
- it("should return null wallet client when not connected", () => {
115
- mockUseAccount.mockReturnValue({
116
- evmAccount: null,
117
- isConnected: true,
118
- });
119
- mockUseChain.mockReturnValue({
120
- currentChain: {
121
- id: 1,
122
- namespace: "eip155",
123
- name: "Ethereum",
124
- rpcUrl: "https://eth.llamarpc.com",
125
- token: "ETH",
126
- },
127
- });
128
-
129
- const { result } = renderHook(() => useViemClient());
130
-
131
- expect(result.current.publicClient).not.toBeNull();
132
- expect(result.current.walletClient).toBeNull();
133
- });
134
-
135
- it("should return null clients when no rpcUrl", () => {
136
- mockUseAccount.mockReturnValue({
137
- evmAccount: null,
138
- isConnected: false,
139
- });
140
- mockUseChain.mockReturnValue({
141
- currentChain: {
142
- id: 1,
143
- namespace: "eip155",
144
- name: "Ethereum",
145
- rpcUrl: undefined,
146
- token: "ETH",
147
- },
148
- });
149
-
150
- const { result } = renderHook(() => useViemClient());
151
-
152
- expect(result.current.publicClient).toBeNull();
153
- expect(result.current.walletClient).toBeNull();
154
- });
155
- });
@@ -1,65 +0,0 @@
1
- import { useMemo } from "react";
2
- import { createPublicClient, http, createWalletClient, type PublicClient, type WalletClient } from "viem";
3
- import type { WalletChain } from "../types";
4
- import { useAccount } from "./useAccount";
5
- import { useChain } from "./useChain";
6
-
7
- export function useViemClient(): {
8
- publicClient: PublicClient | null;
9
- walletClient: WalletClient | null;
10
- chains: WalletChain[];
11
- } {
12
- const { evmAccount, isConnected } = useAccount();
13
- const { currentChain, chains } = useChain();
14
-
15
- const publicClient = useMemo<PublicClient | null>(() => {
16
- if (!currentChain?.rpcUrl) return null;
17
-
18
- return createPublicClient({
19
- transport: http(currentChain.rpcUrl),
20
- chain: {
21
- id: currentChain.id,
22
- name: currentChain.name,
23
- nativeCurrency: {
24
- name: currentChain.token ?? "ETH",
25
- symbol: currentChain.token ?? "ETH",
26
- decimals: 18
27
- },
28
- rpcUrls: {
29
- default: { http: [currentChain.rpcUrl] },
30
- public: { http: [currentChain.rpcUrl] }
31
- }
32
- }
33
- });
34
- }, [currentChain]);
35
-
36
- const walletClient = useMemo<WalletClient | null>(() => {
37
- if (!isConnected || !evmAccount || !currentChain?.rpcUrl) return null;
38
-
39
- const address = evmAccount.includes(":") ? evmAccount.split(":").pop()! : evmAccount;
40
-
41
- return createWalletClient({
42
- transport: http(currentChain.rpcUrl),
43
- chain: {
44
- id: currentChain.id,
45
- name: currentChain.name,
46
- nativeCurrency: {
47
- name: currentChain.token ?? "ETH",
48
- symbol: currentChain.token ?? "ETH",
49
- decimals: 18
50
- },
51
- rpcUrls: {
52
- default: { http: [currentChain.rpcUrl] },
53
- public: { http: [currentChain.rpcUrl] }
54
- }
55
- },
56
- account: address as `0x${string}`
57
- });
58
- }, [isConnected, evmAccount, currentChain]);
59
-
60
- return {
61
- publicClient,
62
- walletClient,
63
- chains
64
- };
65
- }
@@ -1,133 +0,0 @@
1
- /// <reference types="vitest" />
2
- /// @vitest-environment jsdom
3
-
4
- import { describe, it, expect, vi, beforeEach } from "vitest";
5
- import { renderHook } from "@testing-library/react";
6
-
7
- // Mock useWeb3 before importing hooks
8
- const mockUseWeb3 = vi.fn();
9
- vi.mock("../provider/Web3ConnectProvider", () => ({
10
- useWeb3: () => mockUseWeb3(),
11
- Web3ConnectProvider: ({ children }: { children: React.ReactNode }) => children,
12
- }));
13
-
14
- import { useWallet } from "./useWallet";
15
- import type { Web3ContextValue } from "../provider/Web3ConnectProvider";
16
-
17
- function createMockWeb3(overrides: Partial<Web3ContextValue> = {}): Web3ContextValue {
18
- const base: Web3ContextValue = {
19
- status: "disconnected",
20
- session: null,
21
- accounts: [],
22
- chainId: null,
23
- error: null,
24
- isConnected: false,
25
- chains: [],
26
- sessionManager: null,
27
- clearError: () => {},
28
- connect: vi.fn(),
29
- disconnect: vi.fn(),
30
- reconnect: vi.fn(),
31
- switchChain: vi.fn(),
32
- startPairing: vi.fn(),
33
- completePairing: vi.fn(),
34
- connectInjected: vi.fn(),
35
- connectEmbedded: vi.fn(),
36
- connectPasskeys: vi.fn(),
37
- ...overrides,
38
- };
39
- return base;
40
- }
41
-
42
- describe("useWallet", () => {
43
- beforeEach(() => {
44
- vi.clearAllMocks();
45
- });
46
-
47
- it("should return disconnected state by default", () => {
48
- mockUseWeb3.mockReturnValue(createMockWeb3());
49
- const { result } = renderHook(() => useWallet());
50
-
51
- expect(result.current.isConnected).toBe(false);
52
- expect(result.current.isConnecting).toBe(false);
53
- expect(result.current.isReconnecting).toBe(false);
54
- expect(result.current.status).toBe("disconnected");
55
- expect(result.current.currentAccount).toBeNull();
56
- });
57
-
58
- it("should reflect connected state", () => {
59
- mockUseWeb3.mockReturnValue(
60
- createMockWeb3({
61
- status: "connected",
62
- isConnected: true,
63
- accounts: ["eip155:1:0x1234"],
64
- chainId: "eip155:1",
65
- })
66
- );
67
- const { result } = renderHook(() => useWallet());
68
-
69
- expect(result.current.isConnected).toBe(true);
70
- expect(result.current.status).toBe("connected");
71
- expect(result.current.currentAccount).toBe("eip155:1:0x1234");
72
- expect(result.current.chainId).toBe("eip155:1");
73
- });
74
-
75
- it("should reflect connecting state", () => {
76
- mockUseWeb3.mockReturnValue(
77
- createMockWeb3({
78
- status: "connecting",
79
- })
80
- );
81
- const { result } = renderHook(() => useWallet());
82
-
83
- expect(result.current.isConnecting).toBe(true);
84
- expect(result.current.isConnected).toBe(false);
85
- });
86
-
87
- it("should reflect reconnecting state", () => {
88
- mockUseWeb3.mockReturnValue(
89
- createMockWeb3({
90
- status: "reconnecting",
91
- })
92
- );
93
- const { result } = renderHook(() => useWallet());
94
-
95
- expect(result.current.isReconnecting).toBe(true);
96
- });
97
-
98
- it("should pass through connect function", () => {
99
- const connect = vi.fn();
100
- mockUseWeb3.mockReturnValue(createMockWeb3({ connect }));
101
- const { result } = renderHook(() => useWallet());
102
-
103
- result.current.connect();
104
- expect(connect).toHaveBeenCalledTimes(1);
105
- });
106
-
107
- it("should pass through disconnect function", () => {
108
- const disconnect = vi.fn();
109
- mockUseWeb3.mockReturnValue(createMockWeb3({ disconnect }));
110
- const { result } = renderHook(() => useWallet());
111
-
112
- result.current.disconnect();
113
- expect(disconnect).toHaveBeenCalledTimes(1);
114
- });
115
-
116
- it("should return null currentAccount when no accounts", () => {
117
- mockUseWeb3.mockReturnValue(createMockWeb3({ accounts: [] }));
118
- const { result } = renderHook(() => useWallet());
119
-
120
- expect(result.current.currentAccount).toBeNull();
121
- });
122
-
123
- it("should use first account as currentAccount", () => {
124
- mockUseWeb3.mockReturnValue(
125
- createMockWeb3({
126
- accounts: ["eip155:1:0xabc", "eip155:137:0xdef"],
127
- })
128
- );
129
- const { result } = renderHook(() => useWallet());
130
-
131
- expect(result.current.currentAccount).toBe("eip155:1:0xabc");
132
- });
133
- });
@@ -1,39 +0,0 @@
1
- import { useWeb3 } from "../provider/Web3ConnectProvider";
2
-
3
- export function useWallet() {
4
- const {
5
- status,
6
- session,
7
- accounts,
8
- chainId,
9
- error,
10
- connect,
11
- disconnect,
12
- reconnect,
13
- switchChain
14
- } = useWeb3();
15
-
16
- const isConnected = status === "connected";
17
- const isConnecting = status === "connecting";
18
- const isReconnecting = status === "reconnecting";
19
-
20
- const currentAccount = accounts[0] ?? null;
21
- const isDisconnected = status === "disconnected";
22
-
23
- return {
24
- status,
25
- session,
26
- accounts,
27
- chainId,
28
- error,
29
- isConnected,
30
- isConnecting,
31
- isReconnecting,
32
- isDisconnected,
33
- currentAccount,
34
- connect,
35
- disconnect,
36
- reconnect,
37
- switchChain
38
- };
39
- }
@@ -1,102 +0,0 @@
1
- "use client";
2
-
3
- import { useCallback, useMemo } from "react";
4
- import { useWeb3 } from "../provider/Web3ConnectProvider";
5
- import {
6
- getUserFriendlyError,
7
- isRetryableError,
8
- } from "../utils/errorMessages";
9
-
10
- export interface UserFriendlyError {
11
- title: string;
12
- description: string;
13
- code?: string;
14
- }
15
-
16
- export interface UseWeb3ErrorHandlerReturn {
17
- /** Current error from the provider */
18
- error: Error | null;
19
- /** User-friendly representation of the current error */
20
- friendlyError: UserFriendlyError | null;
21
- /** Clear the current error */
22
- clearError: () => void;
23
- /** Check if current error is retryable */
24
- isRetryable: boolean;
25
- /** Get a user-friendly version of any error */
26
- formatError: (error: unknown) => UserFriendlyError;
27
- /** Wraps an async function with error formatting */
28
- wrapAsync: <T>(fn: () => Promise<T>) => () => Promise<T>;
29
- }
30
-
31
- /**
32
- * Hook that provides user-friendly error handling for web3 operations.
33
- *
34
- * Features:
35
- * - Maps WalletError codes to human-readable messages
36
- * - Provides retry detection for transient errors
37
- * - Wraps async operations with consistent error formatting
38
- * - Exposes the current error state from Web3ConnectProvider
39
- *
40
- * @example
41
- * ```tsx
42
- * const { friendlyError, clearError, isRetryable, wrapAsync } = useWeb3ErrorHandler();
43
- *
44
- * // Show error in UI
45
- * if (friendlyError) {
46
- * return <ErrorDisplay title={friendlyError.title} message={friendlyError.description} />;
47
- * }
48
- *
49
- * // Wrap an operation
50
- * const safeConnect = wrapAsync(() => connect());
51
- * await safeConnect();
52
- * ```
53
- */
54
- export function useWeb3ErrorHandler(): UseWeb3ErrorHandlerReturn {
55
- const { error, clearError: providerClearError } = useWeb3();
56
-
57
- const friendlyError: UserFriendlyError | null = useMemo(
58
- () => (error ? getUserFriendlyError(error) : null),
59
- [error]
60
- );
61
-
62
- const isRetryable = useMemo(
63
- () => (error ? isRetryableError(error) : false),
64
- [error]
65
- );
66
-
67
- const clearError = useCallback(() => {
68
- providerClearError();
69
- }, [providerClearError]);
70
-
71
- const formatError = useCallback(
72
- (err: unknown): UserFriendlyError => getUserFriendlyError(err),
73
- []
74
- );
75
-
76
- const wrapAsync = useCallback(
77
- <T,>(fn: () => Promise<T>): (() => Promise<T>) => {
78
- return async () => {
79
- try {
80
- return await fn();
81
- } catch (err) {
82
- // Re-throw with user-friendly information attached
83
- const friendly = getUserFriendlyError(err);
84
- const enhanced = new Error(friendly.description) as unknown as Record<string, unknown>;
85
- enhanced.title = friendly.title;
86
- enhanced.code = friendly.code;
87
- throw enhanced;
88
- }
89
- };
90
- },
91
- []
92
- );
93
-
94
- return {
95
- error,
96
- friendlyError,
97
- clearError,
98
- isRetryable,
99
- formatError,
100
- wrapAsync,
101
- };
102
- }