@oobit/react-native-sdk 1.0.6 → 1.1.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.
- package/README.md +177 -377
- package/dist/WidgetSDK.d.ts +3 -0
- package/dist/WidgetSDK.d.ts.map +1 -1
- package/dist/WidgetSDK.js +58 -75
- package/dist/WidgetSDK.js.map +1 -1
- package/dist/index.d.ts +8 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -13
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +59 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -1
- package/src/WidgetSDK.tsx +65 -108
- package/src/index.ts +30 -38
- package/src/types.ts +66 -19
- package/src/biometricUtils.ts +0 -183
package/src/WidgetSDK.tsx
CHANGED
|
@@ -20,19 +20,16 @@ import {
|
|
|
20
20
|
View,
|
|
21
21
|
} from "react-native";
|
|
22
22
|
import { WebView, WebViewMessageEvent } from "react-native-webview";
|
|
23
|
-
import { authenticateWithBiometrics } from "./biometricUtils";
|
|
24
23
|
import { getWidgetUrl } from "./config";
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
NativeBiometricFailedMessage,
|
|
28
|
-
NativeCardDetailsSessionMessage,
|
|
29
|
-
WidgetMessage,
|
|
30
|
-
WidgetSDKConfig,
|
|
31
|
-
} from "./types";
|
|
24
|
+
import { CopyToClipboardMessage, WidgetMessage, WidgetSDKConfig } from "./types";
|
|
32
25
|
import { isWalletAvailable, openNativeWallet } from "./walletUtils";
|
|
26
|
+
import * as Clipboard from "expo-clipboard";
|
|
33
27
|
|
|
34
28
|
export interface WidgetSDKRef {
|
|
29
|
+
/** Navigate back within the widget */
|
|
35
30
|
navigateBack: () => void;
|
|
31
|
+
/** Reload the widget */
|
|
32
|
+
reload: () => void;
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
@@ -42,13 +39,25 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
42
39
|
userWalletAddress,
|
|
43
40
|
environment,
|
|
44
41
|
onReady,
|
|
45
|
-
onCardCreated,
|
|
46
42
|
onError,
|
|
47
43
|
onClose,
|
|
48
44
|
onTransactionRequested,
|
|
45
|
+
onLoadingChange,
|
|
46
|
+
debug = false,
|
|
47
|
+
loadingIndicatorColor = "#007AFF",
|
|
49
48
|
},
|
|
50
49
|
ref
|
|
51
50
|
) => {
|
|
51
|
+
// Debug logger - only logs when debug is enabled
|
|
52
|
+
const log = debug
|
|
53
|
+
? (...args: unknown[]) => console.log("[WidgetSDK]", ...args)
|
|
54
|
+
: () => {};
|
|
55
|
+
const logError = debug
|
|
56
|
+
? (...args: unknown[]) => console.error("[WidgetSDK]", ...args)
|
|
57
|
+
: () => {};
|
|
58
|
+
const logWarn = debug
|
|
59
|
+
? (...args: unknown[]) => console.warn("[WidgetSDK]", ...args)
|
|
60
|
+
: () => {};
|
|
52
61
|
const webViewRef = useRef<WebView>(null);
|
|
53
62
|
const [walletAvailable, setWalletAvailable] = useState(false);
|
|
54
63
|
const [isLoading, setIsLoading] = useState(true);
|
|
@@ -77,7 +86,7 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
77
86
|
return () => backHandler.remove();
|
|
78
87
|
}, []);
|
|
79
88
|
|
|
80
|
-
// Expose
|
|
89
|
+
// Expose methods via ref
|
|
81
90
|
useImperativeHandle(ref, () => ({
|
|
82
91
|
navigateBack: () => {
|
|
83
92
|
sendMessageToWidget({
|
|
@@ -85,8 +94,19 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
85
94
|
timestamp: Date.now(),
|
|
86
95
|
});
|
|
87
96
|
},
|
|
97
|
+
reload: () => {
|
|
98
|
+
log("Reloading widget");
|
|
99
|
+
setIsLoading(true);
|
|
100
|
+
hasLoadedOnce.current = false;
|
|
101
|
+
webViewRef.current?.reload();
|
|
102
|
+
},
|
|
88
103
|
}));
|
|
89
104
|
|
|
105
|
+
// Notify parent of loading state changes
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
onLoadingChange?.(isLoading);
|
|
108
|
+
}, [isLoading, onLoadingChange]);
|
|
109
|
+
|
|
90
110
|
const checkWalletAvailability = async () => {
|
|
91
111
|
const available = await isWalletAvailable();
|
|
92
112
|
setWalletAvailable(available);
|
|
@@ -99,7 +119,7 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
99
119
|
try {
|
|
100
120
|
const message: WidgetMessage = JSON.parse(event.nativeEvent.data);
|
|
101
121
|
|
|
102
|
-
|
|
122
|
+
log("Received message:", message.type);
|
|
103
123
|
|
|
104
124
|
switch (message.type) {
|
|
105
125
|
case "widget:ready":
|
|
@@ -110,10 +130,6 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
110
130
|
handleOpenWallet();
|
|
111
131
|
break;
|
|
112
132
|
|
|
113
|
-
case "widget:card-created":
|
|
114
|
-
handleCardCreated(message);
|
|
115
|
-
break;
|
|
116
|
-
|
|
117
133
|
case "widget:error":
|
|
118
134
|
handleError(message);
|
|
119
135
|
break;
|
|
@@ -127,25 +143,25 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
127
143
|
break;
|
|
128
144
|
|
|
129
145
|
case "widget:token-expired":
|
|
130
|
-
|
|
146
|
+
logError("Access token expired");
|
|
131
147
|
onError?.("TOKEN_EXPIRED", "Access token has expired");
|
|
132
148
|
break;
|
|
133
149
|
|
|
134
|
-
case "widget:
|
|
135
|
-
|
|
150
|
+
case "widget:copy-to-clipboard":
|
|
151
|
+
handleCopyToClipboard(message as CopyToClipboardMessage);
|
|
136
152
|
break;
|
|
137
153
|
|
|
138
154
|
default:
|
|
139
|
-
|
|
155
|
+
logWarn("Unknown message type:", message);
|
|
140
156
|
}
|
|
141
157
|
} catch (error) {
|
|
142
|
-
|
|
158
|
+
logError("Failed to parse message:", error);
|
|
143
159
|
onError?.("PARSE_ERROR", "Failed to parse widget message");
|
|
144
160
|
}
|
|
145
161
|
};
|
|
146
162
|
|
|
147
163
|
const handleReady = () => {
|
|
148
|
-
|
|
164
|
+
log("Widget ready");
|
|
149
165
|
onReady?.();
|
|
150
166
|
|
|
151
167
|
// Send platform info to widget
|
|
@@ -159,7 +175,7 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
159
175
|
};
|
|
160
176
|
|
|
161
177
|
const handleOpenWallet = async () => {
|
|
162
|
-
|
|
178
|
+
log("Opening native wallet...");
|
|
163
179
|
|
|
164
180
|
const success = await openNativeWallet();
|
|
165
181
|
|
|
@@ -170,26 +186,17 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
170
186
|
});
|
|
171
187
|
};
|
|
172
188
|
|
|
173
|
-
const handleCardCreated = (message: WidgetMessage) => {
|
|
174
|
-
if (message.type !== "widget:card-created") return;
|
|
175
|
-
|
|
176
|
-
const { cardId, cardType, last4 } = message.payload;
|
|
177
|
-
console.log("[WidgetSDK] Card created:", cardId);
|
|
178
|
-
|
|
179
|
-
onCardCreated?.(cardId, cardType, last4);
|
|
180
|
-
};
|
|
181
|
-
|
|
182
189
|
const handleError = (message: WidgetMessage) => {
|
|
183
190
|
if (message.type !== "widget:error") return;
|
|
184
191
|
|
|
185
192
|
const { code, message: errorMessage } = message.payload;
|
|
186
|
-
|
|
193
|
+
logError("Widget error:", code, errorMessage);
|
|
187
194
|
|
|
188
195
|
onError?.(code, errorMessage);
|
|
189
196
|
};
|
|
190
197
|
|
|
191
198
|
const handleClose = () => {
|
|
192
|
-
|
|
199
|
+
log("Widget closed");
|
|
193
200
|
onClose?.();
|
|
194
201
|
};
|
|
195
202
|
|
|
@@ -198,11 +205,10 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
198
205
|
|
|
199
206
|
const { token, cryptoAmount, depositAddress, depositAddressTag } =
|
|
200
207
|
message.payload;
|
|
201
|
-
|
|
202
|
-
token,
|
|
208
|
+
log("Transaction requested:", {
|
|
209
|
+
token: token.symbol,
|
|
203
210
|
cryptoAmount,
|
|
204
211
|
depositAddress,
|
|
205
|
-
depositAddressTag,
|
|
206
212
|
});
|
|
207
213
|
|
|
208
214
|
onTransactionRequested?.(
|
|
@@ -214,79 +220,30 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
214
220
|
};
|
|
215
221
|
|
|
216
222
|
/**
|
|
217
|
-
* Handle
|
|
218
|
-
*
|
|
219
|
-
* 2. Generate cryptographically linked sessionId + secretKey pair
|
|
220
|
-
* 3. Send credentials back to widget for API call and decryption
|
|
223
|
+
* Handle clipboard copy request from widget
|
|
224
|
+
* Copies text to device clipboard and sends result back to widget
|
|
221
225
|
*/
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
console.log(
|
|
227
|
-
"[WidgetSDK] Card details requested, initiating biometric auth..."
|
|
228
|
-
);
|
|
226
|
+
const handleCopyToClipboard = async (message: CopyToClipboardMessage) => {
|
|
227
|
+
const { text, label } = message.payload;
|
|
228
|
+
// Log only the label, never the actual text content (security)
|
|
229
|
+
log("Copy to clipboard requested:", label || "unlabeled");
|
|
229
230
|
|
|
230
|
-
// Step 1: Authenticate with biometrics
|
|
231
|
-
const biometricResult = await authenticateWithBiometrics(
|
|
232
|
-
"Authenticate to view card details"
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
if (!biometricResult.success) {
|
|
236
|
-
console.log(
|
|
237
|
-
"[WidgetSDK] Biometric auth failed:",
|
|
238
|
-
biometricResult.error
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
const failedMessage: NativeBiometricFailedMessage = {
|
|
242
|
-
type: "native:biometric-failed",
|
|
243
|
-
payload: {
|
|
244
|
-
reason: biometricResult.error?.reason || "failed",
|
|
245
|
-
message: biometricResult.error?.message,
|
|
246
|
-
},
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
sendMessageToWidget(failedMessage);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Step 2: Generate session credentials
|
|
254
231
|
try {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
publicKey
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
console.log("[WidgetSDK] Session credentials generated successfully");
|
|
264
|
-
|
|
265
|
-
// Step 3: Send credentials to widget
|
|
266
|
-
const sessionMessage: NativeCardDetailsSessionMessage = {
|
|
267
|
-
type: "native:card-details-session",
|
|
268
|
-
payload: {
|
|
269
|
-
sessionId,
|
|
270
|
-
secretKey: secretKeyHex,
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
sendMessageToWidget(sessionMessage);
|
|
232
|
+
await Clipboard.setStringAsync(text);
|
|
233
|
+
sendMessageToWidget({
|
|
234
|
+
type: "native:clipboard-result",
|
|
235
|
+
payload: { success: true, label },
|
|
236
|
+
});
|
|
275
237
|
} catch (error) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
const failedMessage: NativeBiometricFailedMessage = {
|
|
282
|
-
type: "native:biometric-failed",
|
|
238
|
+
logError("Clipboard copy failed:", error);
|
|
239
|
+
sendMessageToWidget({
|
|
240
|
+
type: "native:clipboard-result",
|
|
283
241
|
payload: {
|
|
284
|
-
|
|
285
|
-
|
|
242
|
+
success: false,
|
|
243
|
+
label,
|
|
244
|
+
error: "Clipboard operation failed",
|
|
286
245
|
},
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
sendMessageToWidget(failedMessage);
|
|
246
|
+
});
|
|
290
247
|
}
|
|
291
248
|
};
|
|
292
249
|
|
|
@@ -314,7 +271,7 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
314
271
|
});
|
|
315
272
|
|
|
316
273
|
const url = `${baseUrl}?${params.toString()}`;
|
|
317
|
-
|
|
274
|
+
log("Widget URL:", url.substring(0, 100) + "...");
|
|
318
275
|
return url;
|
|
319
276
|
}, [accessToken, userWalletAddress, environment]);
|
|
320
277
|
|
|
@@ -333,7 +290,7 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
333
290
|
}}
|
|
334
291
|
onError={(syntheticEvent) => {
|
|
335
292
|
const { nativeEvent } = syntheticEvent;
|
|
336
|
-
|
|
293
|
+
logError("WebView error:", nativeEvent);
|
|
337
294
|
setIsLoading(false);
|
|
338
295
|
onError?.("WEBVIEW_ERROR", "Failed to load widget");
|
|
339
296
|
}}
|
|
@@ -348,9 +305,9 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
348
305
|
url.includes("wallet.google.com") ||
|
|
349
306
|
url.includes("wallet.apple.com")
|
|
350
307
|
) {
|
|
351
|
-
|
|
308
|
+
log("Opening external URL:", url);
|
|
352
309
|
Linking.openURL(url).catch((err) => {
|
|
353
|
-
|
|
310
|
+
logError("Failed to open URL:", err);
|
|
354
311
|
});
|
|
355
312
|
return false; // Don't load in WebView
|
|
356
313
|
}
|
|
@@ -370,7 +327,7 @@ export const WidgetSDK = forwardRef<WidgetSDKRef, WidgetSDKConfig>(
|
|
|
370
327
|
/>
|
|
371
328
|
{isLoading && (
|
|
372
329
|
<View style={styles.loadingOverlay}>
|
|
373
|
-
<ActivityIndicator size="large" color=
|
|
330
|
+
<ActivityIndicator size="large" color={loadingIndicatorColor} />
|
|
374
331
|
</View>
|
|
375
332
|
)}
|
|
376
333
|
</View>
|
package/src/index.ts
CHANGED
|
@@ -3,59 +3,51 @@
|
|
|
3
3
|
* Export all public components, types, and utilities
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export { WidgetSDK } from
|
|
7
|
-
export type { WidgetSDKRef } from
|
|
6
|
+
export { WidgetSDK } from "./WidgetSDK";
|
|
7
|
+
export type { WidgetSDKRef } from "./WidgetSDK";
|
|
8
8
|
|
|
9
9
|
// Export all message types for clients to use
|
|
10
10
|
export type {
|
|
11
|
-
// Configuration
|
|
12
|
-
WidgetSDKConfig,
|
|
13
|
-
WidgetEnvironment,
|
|
14
|
-
DepositToken,
|
|
15
|
-
|
|
16
|
-
// Widget → Native message types
|
|
17
|
-
WidgetMessageType,
|
|
18
11
|
BaseWidgetMessage,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
TransactionRequestedMessage,
|
|
26
|
-
RequestCardDetailsSessionMessage,
|
|
27
|
-
|
|
12
|
+
CopyToClipboardMessage,
|
|
13
|
+
DepositToken,
|
|
14
|
+
NativeBackPressedMessage,
|
|
15
|
+
NativeBiometricFailedMessage,
|
|
16
|
+
NativeCardDetailsSessionMessage,
|
|
17
|
+
NativeMessage,
|
|
28
18
|
// Native → Widget message types
|
|
29
19
|
NativeMessageType,
|
|
30
|
-
NativeMessage,
|
|
31
|
-
NativeBackPressedMessage,
|
|
32
20
|
NativeNavigateBackMessage,
|
|
33
21
|
NativePlatformInfoMessage,
|
|
34
22
|
NativeWalletOpenedMessage,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
OpenWalletMessage,
|
|
24
|
+
RequestCardDetailsSessionMessage,
|
|
25
|
+
TokenExpiredMessage,
|
|
26
|
+
TransactionRequestedMessage,
|
|
27
|
+
WidgetCloseMessage,
|
|
28
|
+
WidgetEnvironment,
|
|
29
|
+
WidgetErrorMessage,
|
|
30
|
+
WidgetMessage,
|
|
31
|
+
// Widget → Native message types
|
|
32
|
+
WidgetMessageType,
|
|
33
|
+
WidgetReadyMessage,
|
|
34
|
+
// Configuration
|
|
35
|
+
WidgetSDKConfig,
|
|
36
|
+
// Error codes
|
|
37
|
+
SDKErrorCode,
|
|
38
|
+
} from "./types";
|
|
38
39
|
|
|
39
40
|
// Export constants
|
|
40
|
-
export {
|
|
41
|
-
export {
|
|
41
|
+
export { getWidgetUrl, WIDGET_URLS } from "./config";
|
|
42
|
+
export { MessageTypes, WALLET_URLS } from "./types";
|
|
42
43
|
|
|
43
44
|
// Export wallet utilities
|
|
44
|
-
export {
|
|
45
|
-
|
|
46
|
-
// Export biometric utilities
|
|
47
|
-
export {
|
|
48
|
-
authenticateWithBiometrics,
|
|
49
|
-
isBiometricAvailable,
|
|
50
|
-
getBiometryTypeLabel,
|
|
51
|
-
AuthenticationType,
|
|
52
|
-
} from './biometricUtils';
|
|
53
|
-
export type { BiometricResult, BiometricAvailability } from './biometricUtils';
|
|
45
|
+
export { isWalletAvailable, openNativeWallet } from "./walletUtils";
|
|
54
46
|
|
|
55
47
|
// Export crypto utilities (for advanced usage)
|
|
56
48
|
export {
|
|
57
|
-
generateSessionCredentials,
|
|
58
49
|
generateRandomHexKey,
|
|
50
|
+
generateSessionCredentials,
|
|
59
51
|
hexToBase64,
|
|
60
|
-
} from
|
|
61
|
-
export type { SessionCredentials } from
|
|
52
|
+
} from "./cryptoUtils";
|
|
53
|
+
export type { SessionCredentials } from "./cryptoUtils";
|
package/src/types.ts
CHANGED
|
@@ -17,12 +17,12 @@ export interface DepositToken {
|
|
|
17
17
|
export type WidgetMessageType =
|
|
18
18
|
| "widget:ready"
|
|
19
19
|
| "widget:open-wallet"
|
|
20
|
-
| "widget:card-created"
|
|
21
20
|
| "widget:error"
|
|
22
21
|
| "widget:close"
|
|
23
22
|
| "widget:transaction-requested"
|
|
24
23
|
| "widget:token-expired"
|
|
25
|
-
| "widget:request-card-details-session"
|
|
24
|
+
| "widget:request-card-details-session"
|
|
25
|
+
| "widget:copy-to-clipboard";
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Native Message Types
|
|
@@ -34,7 +34,8 @@ export type NativeMessageType =
|
|
|
34
34
|
| "native:back-pressed"
|
|
35
35
|
| "native:navigate-back"
|
|
36
36
|
| "native:card-details-session"
|
|
37
|
-
| "native:biometric-failed"
|
|
37
|
+
| "native:biometric-failed"
|
|
38
|
+
| "native:clipboard-result";
|
|
38
39
|
|
|
39
40
|
export interface NativeBackPressedMessage {
|
|
40
41
|
type: "native:back-pressed";
|
|
@@ -49,7 +50,7 @@ export interface NativeNavigateBackMessage {
|
|
|
49
50
|
export interface NativePlatformInfoMessage {
|
|
50
51
|
type: "native:platform-info";
|
|
51
52
|
payload: {
|
|
52
|
-
platform:
|
|
53
|
+
platform: "ios" | "android";
|
|
53
54
|
walletAvailable: boolean;
|
|
54
55
|
};
|
|
55
56
|
}
|
|
@@ -77,13 +78,23 @@ export interface NativeBiometricFailedMessage {
|
|
|
77
78
|
};
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
export interface NativeClipboardResultMessage {
|
|
82
|
+
type: "native:clipboard-result";
|
|
83
|
+
payload: {
|
|
84
|
+
success: boolean;
|
|
85
|
+
label?: string; // Echo back the label for correlation
|
|
86
|
+
error?: string;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
80
90
|
export type NativeMessage =
|
|
81
91
|
| NativeBackPressedMessage
|
|
82
92
|
| NativeNavigateBackMessage
|
|
83
93
|
| NativePlatformInfoMessage
|
|
84
94
|
| NativeWalletOpenedMessage
|
|
85
95
|
| NativeCardDetailsSessionMessage
|
|
86
|
-
| NativeBiometricFailedMessage
|
|
96
|
+
| NativeBiometricFailedMessage
|
|
97
|
+
| NativeClipboardResultMessage;
|
|
87
98
|
|
|
88
99
|
export interface BaseWidgetMessage {
|
|
89
100
|
type: WidgetMessageType;
|
|
@@ -101,15 +112,6 @@ export interface OpenWalletMessage extends BaseWidgetMessage {
|
|
|
101
112
|
};
|
|
102
113
|
}
|
|
103
114
|
|
|
104
|
-
export interface CardCreatedMessage extends BaseWidgetMessage {
|
|
105
|
-
type: "widget:card-created";
|
|
106
|
-
payload: {
|
|
107
|
-
cardId: string;
|
|
108
|
-
cardType: "virtual" | "physical";
|
|
109
|
-
last4: string;
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
115
|
export interface WidgetErrorMessage extends BaseWidgetMessage {
|
|
114
116
|
type: "widget:error";
|
|
115
117
|
payload: {
|
|
@@ -146,15 +148,23 @@ export interface RequestCardDetailsSessionMessage extends BaseWidgetMessage {
|
|
|
146
148
|
};
|
|
147
149
|
}
|
|
148
150
|
|
|
151
|
+
export interface CopyToClipboardMessage extends BaseWidgetMessage {
|
|
152
|
+
type: "widget:copy-to-clipboard";
|
|
153
|
+
payload: {
|
|
154
|
+
text: string;
|
|
155
|
+
label?: string; // Optional: human-readable label for analytics/logging (e.g., "Card Number", "Deposit Address")
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
149
159
|
export type WidgetMessage =
|
|
150
160
|
| WidgetReadyMessage
|
|
151
161
|
| OpenWalletMessage
|
|
152
|
-
| CardCreatedMessage
|
|
153
162
|
| WidgetErrorMessage
|
|
154
163
|
| WidgetCloseMessage
|
|
155
164
|
| TransactionRequestedMessage
|
|
156
165
|
| TokenExpiredMessage
|
|
157
|
-
| RequestCardDetailsSessionMessage
|
|
166
|
+
| RequestCardDetailsSessionMessage
|
|
167
|
+
| CopyToClipboardMessage;
|
|
158
168
|
|
|
159
169
|
/**
|
|
160
170
|
* Widget environment configuration
|
|
@@ -163,6 +173,14 @@ export type WidgetMessage =
|
|
|
163
173
|
*/
|
|
164
174
|
export type WidgetEnvironment = "development" | "production";
|
|
165
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Known SDK error codes
|
|
178
|
+
* - TOKEN_EXPIRED: The access token has expired
|
|
179
|
+
* - PARSE_ERROR: Failed to parse a message from the widget
|
|
180
|
+
* - WEBVIEW_ERROR: The WebView failed to load
|
|
181
|
+
*/
|
|
182
|
+
export type SDKErrorCode = "TOKEN_EXPIRED" | "PARSE_ERROR" | "WEBVIEW_ERROR";
|
|
183
|
+
|
|
166
184
|
/**
|
|
167
185
|
* SDK Configuration
|
|
168
186
|
*/
|
|
@@ -176,16 +194,44 @@ export interface WidgetSDKConfig {
|
|
|
176
194
|
* @default 'production'
|
|
177
195
|
*/
|
|
178
196
|
environment?: WidgetEnvironment;
|
|
197
|
+
/**
|
|
198
|
+
* Called when the widget is ready and loaded
|
|
199
|
+
*/
|
|
179
200
|
onReady?: () => void;
|
|
180
|
-
|
|
181
|
-
|
|
201
|
+
/**
|
|
202
|
+
* Called when an error occurs
|
|
203
|
+
* @param code - Error code (SDKErrorCode or custom widget error code)
|
|
204
|
+
* @param message - Human-readable error message
|
|
205
|
+
*/
|
|
206
|
+
onError?: (code: SDKErrorCode | string, message: string) => void;
|
|
207
|
+
/**
|
|
208
|
+
* Called when the widget requests to close
|
|
209
|
+
*/
|
|
182
210
|
onClose?: () => void;
|
|
211
|
+
/**
|
|
212
|
+
* Called when a crypto transaction is requested
|
|
213
|
+
*/
|
|
183
214
|
onTransactionRequested?: (
|
|
184
215
|
token: DepositToken,
|
|
185
216
|
cryptoAmount: string,
|
|
186
217
|
depositAddress: string,
|
|
187
218
|
depositAddressTag: string | null
|
|
188
219
|
) => void;
|
|
220
|
+
/**
|
|
221
|
+
* Called when the loading state changes
|
|
222
|
+
* @param isLoading - Whether the widget is currently loading
|
|
223
|
+
*/
|
|
224
|
+
onLoadingChange?: (isLoading: boolean) => void;
|
|
225
|
+
/**
|
|
226
|
+
* Enable debug logging to console
|
|
227
|
+
* @default false
|
|
228
|
+
*/
|
|
229
|
+
debug?: boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Custom color for the loading indicator
|
|
232
|
+
* @default "#007AFF"
|
|
233
|
+
*/
|
|
234
|
+
loadingIndicatorColor?: string;
|
|
189
235
|
}
|
|
190
236
|
|
|
191
237
|
/**
|
|
@@ -213,12 +259,12 @@ export const MessageTypes = {
|
|
|
213
259
|
// Widget → Native
|
|
214
260
|
READY: "widget:ready",
|
|
215
261
|
OPEN_WALLET: "widget:open-wallet",
|
|
216
|
-
CARD_CREATED: "widget:card-created",
|
|
217
262
|
ERROR: "widget:error",
|
|
218
263
|
CLOSE: "widget:close",
|
|
219
264
|
TRANSACTION_REQUESTED: "widget:transaction-requested",
|
|
220
265
|
TOKEN_EXPIRED: "widget:token-expired",
|
|
221
266
|
REQUEST_CARD_DETAILS_SESSION: "widget:request-card-details-session",
|
|
267
|
+
COPY_TO_CLIPBOARD: "widget:copy-to-clipboard",
|
|
222
268
|
// Native → Widget
|
|
223
269
|
PLATFORM_INFO: "native:platform-info",
|
|
224
270
|
WALLET_OPENED: "native:wallet-opened",
|
|
@@ -226,4 +272,5 @@ export const MessageTypes = {
|
|
|
226
272
|
NAVIGATE_BACK: "native:navigate-back",
|
|
227
273
|
CARD_DETAILS_SESSION: "native:card-details-session",
|
|
228
274
|
BIOMETRIC_FAILED: "native:biometric-failed",
|
|
275
|
+
CLIPBOARD_RESULT: "native:clipboard-result",
|
|
229
276
|
} as const;
|