@zerohash-sdk/crypto-account-link-react 1.0.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/.babelrc ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "presets": [
3
+ [
4
+ "@nx/react/babel",
5
+ {
6
+ "runtime": "automatic",
7
+ "useBuiltIns": "usage"
8
+ }
9
+ ]
10
+ ],
11
+ "plugins": []
12
+ }
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # @zerohash-sdk/crypto-account-link-react
2
+
3
+ A React SDK that enables frontend React applications to seamlessly integrate with the Connect Crypto Account Link product.
4
+
5
+ Connect Crypto Account Link provides a secure, customizable flow for linking external crypto accounts (for deposits or payouts) directly within your application.
6
+
7
+ ## Requirements
8
+
9
+ - React 18.0.0 or higher
10
+ - React DOM 18.0.0 or higher
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @zerohash-sdk/crypto-account-link-react
16
+ ```
17
+
18
+ ## Getting Started
19
+
20
+ ### 1. Import the CryptoAccountLink Component
21
+
22
+ ```tsx
23
+ import { CryptoAccountLink } from '@zerohash-sdk/crypto-account-link-react';
24
+ ```
25
+
26
+ ### 2. Add the CryptoAccountLink Component to Your App
27
+
28
+ ```tsx
29
+ function App() {
30
+ const jwt = 'your-jwt-token'; // Obtain this from your backend
31
+
32
+ return (
33
+ <CryptoAccountLink
34
+ jwt={jwt}
35
+ env="prod" // or "cert" for testing
36
+ theme="auto" // 'auto' (default), 'light', or 'dark'
37
+ />
38
+ );
39
+ }
40
+ ```
41
+
42
+ ### 3. Configure Event Callbacks (Optional)
43
+
44
+ ```tsx
45
+ function App() {
46
+ const jwt = 'your-jwt-token';
47
+
48
+ return (
49
+ <CryptoAccountLink
50
+ jwt={jwt}
51
+ env="prod"
52
+ theme="auto"
53
+ isPayouts={false} // true for payouts/withdrawals, false for deposits
54
+ onCompleted={({ externalAccountId, address, nickname, asset, network }) => {
55
+ console.log('Account linked:', externalAccountId, address);
56
+ }}
57
+ onExternalAccountCreated={() => {
58
+ console.log('External account created');
59
+ }}
60
+ onError={({ errorCode, reason }) => {
61
+ console.log('Error:', errorCode, 'Reason:', reason);
62
+ }}
63
+ onClose={() => console.log('Widget closed')}
64
+ onEvent={({ type, data }) => console.log('Event:', type, data)}
65
+ onLoaded={() => console.log('Widget loaded and ready')}
66
+ />
67
+ );
68
+ }
69
+ ```
70
+
71
+ ## Complete Example
72
+
73
+ ```tsx
74
+ import React from 'react';
75
+ import { CryptoAccountLink } from '@zerohash-sdk/crypto-account-link-react';
76
+
77
+ function App() {
78
+ const jwt = 'your-jwt-token';
79
+
80
+ return (
81
+ <div className="App">
82
+ <h1>My App</h1>
83
+
84
+ <CryptoAccountLink
85
+ jwt={jwt}
86
+ env="prod"
87
+ theme="auto"
88
+ isPayouts={false}
89
+ onCompleted={({ externalAccountId, address, nickname, asset, network }) => {
90
+ console.log('Linked:', externalAccountId, address, nickname, asset, network);
91
+ }}
92
+ onExternalAccountCreated={() => console.log('External account created')}
93
+ onError={({ errorCode, reason }) => console.log('Error:', errorCode, reason)}
94
+ onClose={() => console.log('Widget closed')}
95
+ onEvent={({ type, data }) => console.log('Event type:', type, 'Event data:', data)}
96
+ onLoaded={() => console.log('Widget loaded and ready')}
97
+ />
98
+ </div>
99
+ );
100
+ }
101
+
102
+ export default App;
103
+ ```
104
+
105
+ ## API Reference
106
+
107
+ ### CryptoAccountLink Component Props
108
+
109
+ | Prop | Type | Required | Default | Description |
110
+ | -------------------------- | ------------------------------------------------------------------------- | -------- | -------- | ----------------------------------------------------------- |
111
+ | `jwt` | `string` | Yes | - | JWT token for authentication with Connect |
112
+ | `env` | `"prod" \| "cert" \| "dev" \| "local"` | No | `"prod"` | Target environment |
113
+ | `theme` | `"auto" \| "light" \| "dark"` | No | `"auto"` | Theme mode for the interface |
114
+ | `isPayouts` | `boolean` | No | `false` | Set to `true` for payouts/withdrawals, `false` for deposits |
115
+ | `onCompleted` | `({ externalAccountId?, address?, nickname?, asset?, network? }) => void` | No | - | Callback when account linking completes successfully |
116
+ | `onExternalAccountCreated` | `() => void` | No | - | Callback when an external account is created |
117
+ | `onError` | `({ errorCode, reason }) => void` | No | - | Callback for error events |
118
+ | `onClose` | `() => void` | No | - | Callback when the widget is closed |
119
+ | `onEvent` | `({ type, data }) => void` | No | - | Callback for general events |
120
+ | `onLoaded` | `() => void` | No | - | Callback when the widget is loaded and ready |
121
+
122
+ ## More Information & Support
123
+
124
+ For comprehensive documentation or support about Connect, visit our [Documentation Page](https://docs.zerohash.com/).
@@ -0,0 +1,277 @@
1
+ import { default as default_2 } from 'react';
2
+
3
+ /**
4
+ * Generic app event structure
5
+ * @template TType - Event type string
6
+ * @template TData - Event data payload
7
+ */
8
+ declare type AppEvent<TType extends string = string, TData = Record<string, unknown>> = {
9
+ /** The type of event that occurred */
10
+ type: TType;
11
+ /** Data associated with the event */
12
+ data: TData;
13
+ };
14
+
15
+ /**
16
+ * A React wrapper component for the Connect Crypto Account Link product.
17
+ *
18
+ * @param props - Component properties
19
+ * @param jwt - JWT token for authentication (required)
20
+ * @param env - Target environment ("local" | "dev" | "cert" | "prod", defaults to "prod")
21
+ * @param theme - Theme mode ("auto" | "light" | "dark", defaults to "auto")
22
+ * @param isPayouts - Whether this is for payouts (withdrawals) or deposits (defaults to false)
23
+ * @param onCompleted - Callback invoked when the account link flow is successfully completed
24
+ * @param onError - Callback invoked when an error occurs
25
+ * @param onClose - Callback invoked when the user closes the widget
26
+ * @param onLoaded - Callback invoked when the widget has finished loading
27
+ * @param onExternalAccountCreated - Callback invoked when an external account is created
28
+ * @param onEvent - Callback invoked for general application events
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * // Basic usage with production environment (default)
33
+ * <CryptoAccountLink jwt="your-jwt-token" />
34
+ *
35
+ * // Using cert environment for testing
36
+ * <CryptoAccountLink jwt="your-jwt-token" env="cert" />
37
+ *
38
+ * // Force dark theme
39
+ * <CryptoAccountLink jwt="your-jwt-token" theme="dark" />
40
+ *
41
+ * // For payouts/withdrawals
42
+ * <CryptoAccountLink jwt="your-jwt-token" isPayouts={true} />
43
+ *
44
+ * // With callback functions
45
+ * <CryptoAccountLink
46
+ * jwt="your-jwt-token"
47
+ * theme="auto"
48
+ * onLoaded={() => console.log('Crypto account link loaded and ready')}
49
+ * onCompleted={(data) => console.log('Account linked successfully', data)}
50
+ * onClose={() => console.log('Crypto account link closed')}
51
+ * onError={({ errorCode, reason }) => console.error('Error:', errorCode, reason)}
52
+ * onEvent={(event) => console.log('Event:', event)}
53
+ * onExternalAccountCreated={() => console.log('External account created')}
54
+ * />
55
+ * ```
56
+ *
57
+ * @returns React component that renders the Connect Crypto Account Link interface
58
+ */
59
+ export declare const CryptoAccountLink: default_2.FC<CryptoAccountLinkProps>;
60
+
61
+ declare interface CryptoAccountLinkCompletedData {
62
+ externalAccountId?: string;
63
+ address?: string;
64
+ nickname?: string;
65
+ asset?: string;
66
+ network?: string;
67
+ }
68
+
69
+ /**
70
+ * Crypto account link event structure
71
+ */
72
+ declare type CryptoAccountLinkEvent = AppEvent<CryptoAccountLinkEventType>;
73
+
74
+ /**
75
+ * Crypto account link event type literals
76
+ */
77
+ declare type CryptoAccountLinkEventType = string;
78
+
79
+ declare interface CryptoAccountLinkProps {
80
+ /**
81
+ * JWT token used for authentication with the Connect Crypto Account Link service.
82
+ * This token should be obtained from your backend and contain the necessary
83
+ * claims for user identification and authorization.
84
+ *
85
+ * @example "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
86
+ */
87
+ jwt: string;
88
+ /**
89
+ * Target environment for the Connect Crypto Account Link service.
90
+ *
91
+ * @default "prod"
92
+ *
93
+ * Available environments:
94
+ * - `"local"` - Local development environment
95
+ * - `"dev"` - Development environment
96
+ * - `"cert"` - Certificate/staging environment for integration testing
97
+ * - `"prod"` - Live production environment for real applications
98
+ *
99
+ * @example
100
+ * ```tsx
101
+ * // Use production (default)
102
+ * <CryptoAccountLink jwt={token} />
103
+ *
104
+ * // Use cert for testing
105
+ * <CryptoAccountLink jwt={token} env="cert" />
106
+ * ```
107
+ */
108
+ env?: Environment;
109
+ /**
110
+ * Theme mode for the Connect Crypto Account Link interface.
111
+ *
112
+ * @default "auto"
113
+ *
114
+ * Available themes:
115
+ * - `"auto"` - Automatically detect system preference (light/dark mode)
116
+ * - `"light"` - Force light theme
117
+ * - `"dark"` - Force dark theme
118
+ *
119
+ * @example
120
+ * ```tsx
121
+ * // Auto-detect system preference (default)
122
+ * <CryptoAccountLink jwt={token} />
123
+ *
124
+ * // Force dark theme
125
+ * <CryptoAccountLink jwt={token} theme="dark" />
126
+ * ```
127
+ */
128
+ theme?: Theme;
129
+ /**
130
+ * Whether this is for payouts (withdrawals) or deposits.
131
+ *
132
+ * @default false
133
+ *
134
+ * @example
135
+ * ```tsx
136
+ * // For deposits (default)
137
+ * <CryptoAccountLink jwt={token} />
138
+ *
139
+ * // For payouts/withdrawals
140
+ * <CryptoAccountLink jwt={token} isPayouts={true} />
141
+ * ```
142
+ */
143
+ isPayouts?: boolean;
144
+ /**
145
+ * Callback invoked when the crypto account link flow is successfully completed.
146
+ *
147
+ * @param data - Details about the completed account link
148
+ *
149
+ * @example
150
+ * ```tsx
151
+ * <CryptoAccountLink
152
+ * jwt={token}
153
+ * onCompleted={(data) =>
154
+ * console.log('Account linked successfully', data)
155
+ * }
156
+ * />
157
+ * ```
158
+ */
159
+ onCompleted?: (data: CryptoAccountLinkCompletedData) => void;
160
+ /**
161
+ * Callback invoked when an error occurs during the crypto account link flow.
162
+ *
163
+ * @param error - Error details including error code and reason
164
+ *
165
+ * @example
166
+ * ```tsx
167
+ * <CryptoAccountLink
168
+ * jwt={token}
169
+ * onError={({ errorCode, reason }) =>
170
+ * console.error('Crypto account link error:', errorCode, reason)
171
+ * }
172
+ * />
173
+ * ```
174
+ */
175
+ onError?: (error: ErrorPayload) => void;
176
+ /**
177
+ * Callback invoked when the user closes the crypto account link widget.
178
+ *
179
+ * @example
180
+ * ```tsx
181
+ * <CryptoAccountLink
182
+ * jwt={token}
183
+ * onClose={() => setShowCryptoAccountLink(false)}
184
+ * />
185
+ * ```
186
+ */
187
+ onClose?: () => void;
188
+ /**
189
+ * Callback invoked when the crypto account link widget has finished loading and is ready.
190
+ *
191
+ * @example
192
+ * ```tsx
193
+ * <CryptoAccountLink
194
+ * jwt={token}
195
+ * onLoaded={() => setIsLoading(false)}
196
+ * />
197
+ * ```
198
+ */
199
+ onLoaded?: () => void;
200
+ /**
201
+ * Callback invoked when an external account is created.
202
+ *
203
+ * @example
204
+ * ```tsx
205
+ * <CryptoAccountLink
206
+ * jwt={token}
207
+ * onExternalAccountCreated={() => console.log('External account created')}
208
+ * />
209
+ * ```
210
+ */
211
+ onExternalAccountCreated?: () => void;
212
+ /**
213
+ * Callback invoked for general application events during the crypto account link flow.
214
+ *
215
+ * @param event - Event object containing the event type and associated data
216
+ *
217
+ * @example
218
+ * ```tsx
219
+ * <CryptoAccountLink
220
+ * jwt={token}
221
+ * onEvent={(event) => console.log('Crypto account link event:', event)}
222
+ * />
223
+ * ```
224
+ */
225
+ onEvent?: (event: CryptoAccountLinkEvent) => void;
226
+ }
227
+
228
+ /**
229
+ * Available environments for the Connect Crypto Account Link service.
230
+ *
231
+ * - `"local"` - Local development environment (http://localhost:4204)
232
+ * - `"dev"` - Development environment for early-stage testing
233
+ * - `"cert"` - Certificate/staging environment for integration testing
234
+ * - `"prod"` - Live production environment for real applications
235
+ */
236
+ declare type Environment = 'local' | 'dev' | 'cert' | 'prod';
237
+
238
+ /**
239
+ * Generic error codes for all Connect applications
240
+ */
241
+ declare enum ErrorCode {
242
+ /** Network connectivity error */
243
+ NETWORK_ERROR = 'network_error',
244
+ /** Authentication or session expired error */
245
+ AUTH_ERROR = 'auth_error',
246
+ /** Resource not found error */
247
+ NOT_FOUND_ERROR = 'not_found_error',
248
+ /** Validation error from user input */
249
+ VALIDATION_ERROR = 'validation_error',
250
+ /** Server error (5xx) */
251
+ SERVER_ERROR = 'server_error',
252
+ /** Client error (4xx) */
253
+ CLIENT_ERROR = 'client_error',
254
+ /** Unknown or unexpected error */
255
+ UNKNOWN_ERROR = 'unknown_error',
256
+ }
257
+
258
+ /**
259
+ * Generic error payload structure for error callbacks
260
+ */
261
+ declare type ErrorPayload = {
262
+ /** Error code indicating the type of error */
263
+ errorCode: ErrorCode;
264
+ /** Human-readable reason for the error */
265
+ reason: string;
266
+ };
267
+
268
+ /**
269
+ * Theme mode for the Connect Crypto Account Link interface.
270
+ *
271
+ * - `"auto"` - Automatically detect system preference (light/dark mode)
272
+ * - `"light"` - Force light theme
273
+ * - `"dark"` - Force dark theme
274
+ */
275
+ declare type Theme = 'auto' | 'light' | 'dark';
276
+
277
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ import k, { useRef as x, useEffect as a } from "react";
2
+ const b = {
3
+ local: "http://localhost:5173/crypto-account-link-web/index.js",
4
+ dev: "https://connect-sdk.dev.0hash.com/crypto-account-link-web/index.js",
5
+ cert: "https://sdk.sandbox.connect.xyz/crypto-account-link-web/index.js",
6
+ prod: "https://sdk.connect.xyz/crypto-account-link-web/index.js"
7
+ }, I = "zerohash-crypto-account-link-script", f = "zerohash-crypto-account-link", R = (o = "prod") => b[o], w = ({
8
+ jwt: o,
9
+ env: e = "prod",
10
+ theme: h,
11
+ isPayouts: y = !1,
12
+ onCompleted: r,
13
+ onError: n,
14
+ onClose: s,
15
+ onLoaded: i,
16
+ onExternalAccountCreated: p,
17
+ onEvent: d,
18
+ ...m
19
+ }) => {
20
+ const l = x(null);
21
+ return a(() => {
22
+ const t = l.current;
23
+ t && (r && (t.onCompleted = r), n && (t.onError = n), s && (t.onClose = s), i && (t.onLoaded = i), p && (t.onExternalAccountCreated = p), d && (t.onEvent = d));
24
+ }, [r, n, s, i, p, d]), a(() => {
25
+ const t = R(e), u = `${I}-${e}`;
26
+ if (document.getElementById(u))
27
+ return;
28
+ const c = document.createElement("script");
29
+ c.id = u, c.src = t, c.type = "module", c.async = !0, c.onerror = () => {
30
+ console.error(`Failed to load the script for ${f} from ${e} environment.`);
31
+ }, document.head.appendChild(c);
32
+ }, [e]), k.createElement(f, {
33
+ ref: l,
34
+ jwt: o,
35
+ env: e,
36
+ theme: h,
37
+ "is-payouts": y,
38
+ ...m
39
+ });
40
+ };
41
+ export {
42
+ w as CryptoAccountLink
43
+ };
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@zerohash-sdk/crypto-account-link-react",
3
+ "version": "1.0.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ "./package.json": "./package.json",
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "nx": {
18
+ "name": "crypto-account-link-react"
19
+ }
20
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './lib/crypto-account-link-react';
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Replace this with your own classes.
3
+ *
4
+ * Example:
5
+ * .container {
6
+ * }
7
+ */
@@ -0,0 +1,10 @@
1
+ import { render } from '@testing-library/react';
2
+
3
+ import { CryptoAccountLink } from './crypto-account-link-react';
4
+
5
+ describe('CryptoAccountLink', () => {
6
+ it('should render successfully', () => {
7
+ const { baseElement } = render(<CryptoAccountLink jwt="test-token" />);
8
+ expect(baseElement).toBeTruthy();
9
+ });
10
+ });
@@ -0,0 +1,339 @@
1
+ /* eslint-disable @typescript-eslint/no-namespace */ import type {
2
+ CryptoAccountLinkCompletedData,
3
+ CryptoAccountLinkEvent,
4
+ ErrorPayload,
5
+ } from '@zerohash/callbacks';
6
+ import React, { useEffect, useRef } from 'react';
7
+
8
+ const SCRIPT_URLS = {
9
+ local: 'http://localhost:5173/crypto-account-link-web/index.js',
10
+ dev: 'https://connect-sdk.dev.0hash.com/crypto-account-link-web/index.js',
11
+ cert: 'https://sdk.sandbox.connect.xyz/crypto-account-link-web/index.js',
12
+ prod: 'https://sdk.connect.xyz/crypto-account-link-web/index.js',
13
+ } as const;
14
+
15
+ const SCRIPT_ID = 'zerohash-crypto-account-link-script';
16
+ const WEB_COMPONENT_TAG = 'zerohash-crypto-account-link';
17
+
18
+ /**
19
+ * Available environments for the Connect Crypto Account Link service.
20
+ *
21
+ * - `"local"` - Local development environment (http://localhost:4204)
22
+ * - `"dev"` - Development environment for early-stage testing
23
+ * - `"cert"` - Certificate/staging environment for integration testing
24
+ * - `"prod"` - Live production environment for real applications
25
+ */
26
+ type Environment = 'local' | 'dev' | 'cert' | 'prod';
27
+
28
+ /**
29
+ * Theme mode for the Connect Crypto Account Link interface.
30
+ *
31
+ * - `"auto"` - Automatically detect system preference (light/dark mode)
32
+ * - `"light"` - Force light theme
33
+ * - `"dark"` - Force dark theme
34
+ */
35
+ type Theme = 'auto' | 'light' | 'dark';
36
+
37
+ const getScriptUrl = (env: Environment = 'prod'): string => {
38
+ return SCRIPT_URLS[env];
39
+ };
40
+
41
+ interface CryptoAccountLinkProps {
42
+ /**
43
+ * JWT token used for authentication with the Connect Crypto Account Link service.
44
+ * This token should be obtained from your backend and contain the necessary
45
+ * claims for user identification and authorization.
46
+ *
47
+ * @example "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
48
+ */
49
+ jwt: string;
50
+
51
+ /**
52
+ * Target environment for the Connect Crypto Account Link service.
53
+ *
54
+ * @default "prod"
55
+ *
56
+ * Available environments:
57
+ * - `"local"` - Local development environment
58
+ * - `"dev"` - Development environment
59
+ * - `"cert"` - Certificate/staging environment for integration testing
60
+ * - `"prod"` - Live production environment for real applications
61
+ *
62
+ * @example
63
+ * ```tsx
64
+ * // Use production (default)
65
+ * <CryptoAccountLink jwt={token} />
66
+ *
67
+ * // Use cert for testing
68
+ * <CryptoAccountLink jwt={token} env="cert" />
69
+ * ```
70
+ */
71
+ env?: Environment;
72
+
73
+ /**
74
+ * Theme mode for the Connect Crypto Account Link interface.
75
+ *
76
+ * @default "auto"
77
+ *
78
+ * Available themes:
79
+ * - `"auto"` - Automatically detect system preference (light/dark mode)
80
+ * - `"light"` - Force light theme
81
+ * - `"dark"` - Force dark theme
82
+ *
83
+ * @example
84
+ * ```tsx
85
+ * // Auto-detect system preference (default)
86
+ * <CryptoAccountLink jwt={token} />
87
+ *
88
+ * // Force dark theme
89
+ * <CryptoAccountLink jwt={token} theme="dark" />
90
+ * ```
91
+ */
92
+ theme?: Theme;
93
+
94
+ /**
95
+ * Whether this is for payouts (withdrawals) or deposits.
96
+ *
97
+ * @default false
98
+ *
99
+ * @example
100
+ * ```tsx
101
+ * // For deposits (default)
102
+ * <CryptoAccountLink jwt={token} />
103
+ *
104
+ * // For payouts/withdrawals
105
+ * <CryptoAccountLink jwt={token} isPayouts={true} />
106
+ * ```
107
+ */
108
+ isPayouts?: boolean;
109
+
110
+ /**
111
+ * Callback invoked when the crypto account link flow is successfully completed.
112
+ *
113
+ * @param data - Details about the completed account link
114
+ *
115
+ * @example
116
+ * ```tsx
117
+ * <CryptoAccountLink
118
+ * jwt={token}
119
+ * onCompleted={(data) =>
120
+ * console.log('Account linked successfully', data)
121
+ * }
122
+ * />
123
+ * ```
124
+ */
125
+ onCompleted?: (data: CryptoAccountLinkCompletedData) => void;
126
+
127
+ /**
128
+ * Callback invoked when an error occurs during the crypto account link flow.
129
+ *
130
+ * @param error - Error details including error code and reason
131
+ *
132
+ * @example
133
+ * ```tsx
134
+ * <CryptoAccountLink
135
+ * jwt={token}
136
+ * onError={({ errorCode, reason }) =>
137
+ * console.error('Crypto account link error:', errorCode, reason)
138
+ * }
139
+ * />
140
+ * ```
141
+ */
142
+ onError?: (error: ErrorPayload) => void;
143
+
144
+ /**
145
+ * Callback invoked when the user closes the crypto account link widget.
146
+ *
147
+ * @example
148
+ * ```tsx
149
+ * <CryptoAccountLink
150
+ * jwt={token}
151
+ * onClose={() => setShowCryptoAccountLink(false)}
152
+ * />
153
+ * ```
154
+ */
155
+ onClose?: () => void;
156
+
157
+ /**
158
+ * Callback invoked when the crypto account link widget has finished loading and is ready.
159
+ *
160
+ * @example
161
+ * ```tsx
162
+ * <CryptoAccountLink
163
+ * jwt={token}
164
+ * onLoaded={() => setIsLoading(false)}
165
+ * />
166
+ * ```
167
+ */
168
+ onLoaded?: () => void;
169
+
170
+ /**
171
+ * Callback invoked when an external account is created.
172
+ *
173
+ * @example
174
+ * ```tsx
175
+ * <CryptoAccountLink
176
+ * jwt={token}
177
+ * onExternalAccountCreated={() => console.log('External account created')}
178
+ * />
179
+ * ```
180
+ */
181
+ onExternalAccountCreated?: () => void;
182
+
183
+ /**
184
+ * Callback invoked for general application events during the crypto account link flow.
185
+ *
186
+ * @param event - Event object containing the event type and associated data
187
+ *
188
+ * @example
189
+ * ```tsx
190
+ * <CryptoAccountLink
191
+ * jwt={token}
192
+ * onEvent={(event) => console.log('Crypto account link event:', event)}
193
+ * />
194
+ * ```
195
+ */
196
+ onEvent?: (event: CryptoAccountLinkEvent) => void;
197
+ }
198
+
199
+ declare global {
200
+ namespace JSX {
201
+ interface IntrinsicElements {
202
+ /**
203
+ * Connect Crypto Account Link web component element
204
+ */
205
+ [WEB_COMPONENT_TAG]: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
206
+ /**
207
+ * JWT token for authentication
208
+ */
209
+ jwt: string;
210
+ /**
211
+ * Target environment ("local" | "dev" | "cert" | "prod")
212
+ */
213
+ env?: Environment;
214
+ /**
215
+ * Theme mode ("auto" | "light" | "dark")
216
+ */
217
+ theme?: Theme;
218
+ /**
219
+ * Whether this is for payouts (withdrawals) or deposits
220
+ */
221
+ 'is-payouts'?: boolean;
222
+ };
223
+ }
224
+ }
225
+ }
226
+
227
+ interface CryptoAccountLinkElement
228
+ extends HTMLElement,
229
+ Pick<
230
+ CryptoAccountLinkProps,
231
+ 'onCompleted' | 'onError' | 'onClose' | 'onLoaded' | 'onEvent' | 'onExternalAccountCreated'
232
+ > {}
233
+
234
+ /**
235
+ * A React wrapper component for the Connect Crypto Account Link product.
236
+ *
237
+ * @param props - Component properties
238
+ * @param jwt - JWT token for authentication (required)
239
+ * @param env - Target environment ("local" | "dev" | "cert" | "prod", defaults to "prod")
240
+ * @param theme - Theme mode ("auto" | "light" | "dark", defaults to "auto")
241
+ * @param isPayouts - Whether this is for payouts (withdrawals) or deposits (defaults to false)
242
+ * @param onCompleted - Callback invoked when the account link flow is successfully completed
243
+ * @param onError - Callback invoked when an error occurs
244
+ * @param onClose - Callback invoked when the user closes the widget
245
+ * @param onLoaded - Callback invoked when the widget has finished loading
246
+ * @param onExternalAccountCreated - Callback invoked when an external account is created
247
+ * @param onEvent - Callback invoked for general application events
248
+ *
249
+ * @example
250
+ * ```tsx
251
+ * // Basic usage with production environment (default)
252
+ * <CryptoAccountLink jwt="your-jwt-token" />
253
+ *
254
+ * // Using cert environment for testing
255
+ * <CryptoAccountLink jwt="your-jwt-token" env="cert" />
256
+ *
257
+ * // Force dark theme
258
+ * <CryptoAccountLink jwt="your-jwt-token" theme="dark" />
259
+ *
260
+ * // For payouts/withdrawals
261
+ * <CryptoAccountLink jwt="your-jwt-token" isPayouts={true} />
262
+ *
263
+ * // With callback functions
264
+ * <CryptoAccountLink
265
+ * jwt="your-jwt-token"
266
+ * theme="auto"
267
+ * onLoaded={() => console.log('Crypto account link loaded and ready')}
268
+ * onCompleted={(data) => console.log('Account linked successfully', data)}
269
+ * onClose={() => console.log('Crypto account link closed')}
270
+ * onError={({ errorCode, reason }) => console.error('Error:', errorCode, reason)}
271
+ * onEvent={(event) => console.log('Event:', event)}
272
+ * onExternalAccountCreated={() => console.log('External account created')}
273
+ * />
274
+ * ```
275
+ *
276
+ * @returns React component that renders the Connect Crypto Account Link interface
277
+ */
278
+ export const CryptoAccountLink: React.FC<CryptoAccountLinkProps> = ({
279
+ jwt,
280
+ env = 'prod',
281
+ theme,
282
+ isPayouts = false,
283
+ onCompleted,
284
+ onError,
285
+ onClose,
286
+ onLoaded,
287
+ onExternalAccountCreated,
288
+ onEvent,
289
+ ...rest
290
+ }) => {
291
+ const ref = useRef<CryptoAccountLinkElement | null>(null);
292
+
293
+ // Set up callback functions on the web component element
294
+ useEffect(() => {
295
+ const element = ref.current;
296
+ if (!element) return;
297
+
298
+ if (onCompleted) element.onCompleted = onCompleted;
299
+ if (onError) element.onError = onError;
300
+ if (onClose) element.onClose = onClose;
301
+ if (onLoaded) element.onLoaded = onLoaded;
302
+ if (onExternalAccountCreated) element.onExternalAccountCreated = onExternalAccountCreated;
303
+ if (onEvent) element.onEvent = onEvent;
304
+ }, [onCompleted, onError, onClose, onLoaded, onExternalAccountCreated, onEvent]);
305
+
306
+ // Load connect script to render the web component.
307
+ useEffect(() => {
308
+ const scriptUrl = getScriptUrl(env);
309
+ const scriptId = `${SCRIPT_ID}-${env}`;
310
+
311
+ if (document.getElementById(scriptId)) {
312
+ return; // Script already loaded, do nothing.
313
+ }
314
+
315
+ const script = document.createElement('script');
316
+ script.id = scriptId;
317
+ script.src = scriptUrl;
318
+ script.type = 'module';
319
+ script.async = true;
320
+ script.onerror = () => {
321
+ console.error(`Failed to load the script for ${WEB_COMPONENT_TAG} from ${env} environment.`);
322
+ };
323
+
324
+ document.head.appendChild(script);
325
+
326
+ // Note: We don't return a cleanup function to remove the script.
327
+ // The script defines the custom element globally for the entire application,
328
+ // so it should remain even if all component instances are unmounted.
329
+ }, [env]); // Re-run if environment changes
330
+
331
+ return React.createElement(WEB_COMPONENT_TAG, {
332
+ ref,
333
+ jwt,
334
+ env,
335
+ theme,
336
+ 'is-payouts': isPayouts,
337
+ ...rest,
338
+ });
339
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "files": [],
3
+ "include": [],
4
+ "references": [
5
+ {
6
+ "path": "./tsconfig.lib.json"
7
+ },
8
+ {
9
+ "path": "./tsconfig.spec.json"
10
+ }
11
+ ],
12
+ "extends": "../../../../tsconfig.base.json"
13
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "types": ["node", "@nx/react/typings/cssmodule.d.ts", "@nx/react/typings/image.d.ts", "vite/client"],
6
+ "rootDir": "src",
7
+ "jsx": "react-jsx",
8
+ "module": "esnext",
9
+ "moduleResolution": "bundler",
10
+ "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo"
11
+ },
12
+ "exclude": [
13
+ "out-tsc",
14
+ "dist",
15
+ "**/*.spec.ts",
16
+ "**/*.test.ts",
17
+ "**/*.spec.tsx",
18
+ "**/*.test.tsx",
19
+ "**/*.spec.js",
20
+ "**/*.test.js",
21
+ "**/*.spec.jsx",
22
+ "**/*.test.jsx",
23
+ "vite.config.ts",
24
+ "vite.config.mts",
25
+ "vitest.config.ts",
26
+ "vitest.config.mts",
27
+ "src/**/*.test.ts",
28
+ "src/**/*.spec.ts",
29
+ "src/**/*.test.tsx",
30
+ "src/**/*.spec.tsx",
31
+ "src/**/*.test.js",
32
+ "src/**/*.spec.js",
33
+ "src/**/*.test.jsx",
34
+ "src/**/*.spec.jsx"
35
+ ],
36
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"],
37
+ "references": [
38
+ {
39
+ "path": "../../../common/callbacks/tsconfig.lib.json"
40
+ }
41
+ ]
42
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./out-tsc/vitest",
5
+ "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"],
6
+ "jsx": "react-jsx",
7
+ "module": "esnext",
8
+ "moduleResolution": "bundler"
9
+ },
10
+ "include": [
11
+ "vite.config.ts",
12
+ "vite.config.mts",
13
+ "vitest.config.ts",
14
+ "vitest.config.mts",
15
+ "src/**/*.test.ts",
16
+ "src/**/*.spec.ts",
17
+ "src/**/*.test.tsx",
18
+ "src/**/*.spec.tsx",
19
+ "src/**/*.test.js",
20
+ "src/**/*.spec.js",
21
+ "src/**/*.test.jsx",
22
+ "src/**/*.spec.jsx",
23
+ "src/**/*.d.ts"
24
+ ],
25
+ "references": [
26
+ {
27
+ "path": "./tsconfig.lib.json"
28
+ }
29
+ ]
30
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,58 @@
1
+ /// <reference types='vitest' />
2
+ import react from '@vitejs/plugin-react';
3
+ import * as path from 'path';
4
+ import { defineConfig } from 'vite';
5
+ import dts from 'vite-plugin-dts';
6
+
7
+ export default defineConfig(() => ({
8
+ root: __dirname,
9
+ cacheDir: '../../../../node_modules/.vite/src/crypto-account-link/sdks/react',
10
+ plugins: [
11
+ react(),
12
+ dts({
13
+ entryRoot: 'src',
14
+ tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'),
15
+ rollupTypes: true, // Bundle all type dependencies
16
+ bundledPackages: ['@zerohash/callbacks'], // Explicitly bundle callbacks types
17
+ }),
18
+ ],
19
+ // Uncomment this if you are using workers.
20
+ // worker: {
21
+ // plugins: [],
22
+ // },
23
+ // Configuration for building your library.
24
+ // See: https://vitejs.dev/guide/build.html#library-mode
25
+ build: {
26
+ outDir: './dist',
27
+ emptyOutDir: true,
28
+ reportCompressedSize: true,
29
+ commonjsOptions: {
30
+ transformMixedEsModules: true,
31
+ },
32
+ lib: {
33
+ // Could also be a dictionary or array of multiple entry points.
34
+ entry: 'src/index.ts',
35
+ name: '@zerohash-sdk/crypto-account-link-react',
36
+ fileName: 'index',
37
+ // Change this to the formats you want to support.
38
+ // Don't forget to update your package.json as well.
39
+ formats: ['es' as const],
40
+ },
41
+ rollupOptions: {
42
+ // External packages that should not be bundled into your library.
43
+ external: ['react', 'react-dom', 'react/jsx-runtime'],
44
+ },
45
+ },
46
+ test: {
47
+ name: '@zerohash-sdk/crypto-account-link-react',
48
+ watch: false,
49
+ globals: true,
50
+ environment: 'jsdom',
51
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
52
+ reporters: ['default'],
53
+ coverage: {
54
+ reportsDirectory: './test-output/vitest/coverage',
55
+ provider: 'v8' as const,
56
+ },
57
+ },
58
+ }));