@oobit/react-native-sdk 1.0.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/src/types.ts ADDED
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Widget SDK Types
3
+ * Messages that can be sent between the web widget and React Native
4
+ */
5
+
6
+ /**
7
+ * Token information for transaction confirmation
8
+ * Minimal fields needed to display a send transaction confirmation page
9
+ */
10
+ export interface DepositToken {
11
+ symbol: string;
12
+ name: string;
13
+ iconUrl: string | null;
14
+ networkName: string;
15
+ }
16
+
17
+ export type WidgetMessageType =
18
+ | 'widget:ready'
19
+ | 'widget:open-wallet'
20
+ | 'widget:card-created'
21
+ | 'widget:error'
22
+ | 'widget:close'
23
+ | 'widget:transaction-requested'
24
+ | 'widget:token-expired';
25
+
26
+ /**
27
+ * Native Message Types
28
+ * Messages sent from the native app to the web widget
29
+ */
30
+ export type NativeMessageType =
31
+ | 'native:platform-info'
32
+ | 'native:wallet-opened'
33
+ | 'native:back-pressed'
34
+ | 'native:navigate-back';
35
+
36
+ export interface NativeBackPressedMessage {
37
+ type: 'native:back-pressed';
38
+ timestamp: number;
39
+ }
40
+
41
+ export interface NativeNavigateBackMessage {
42
+ type: 'native:navigate-back';
43
+ timestamp: number;
44
+ }
45
+
46
+ export interface NativePlatformInfoMessage {
47
+ type: 'native:platform-info';
48
+ payload: {
49
+ platform: string;
50
+ walletAvailable: boolean;
51
+ };
52
+ }
53
+
54
+ export interface NativeWalletOpenedMessage {
55
+ type: 'native:wallet-opened';
56
+ payload: {
57
+ success: boolean;
58
+ };
59
+ }
60
+
61
+ export type NativeMessage =
62
+ | NativeBackPressedMessage
63
+ | NativeNavigateBackMessage
64
+ | NativePlatformInfoMessage
65
+ | NativeWalletOpenedMessage;
66
+
67
+ export interface BaseWidgetMessage {
68
+ type: WidgetMessageType;
69
+ timestamp: number;
70
+ }
71
+
72
+ export interface WidgetReadyMessage extends BaseWidgetMessage {
73
+ type: 'widget:ready';
74
+ }
75
+
76
+ export interface OpenWalletMessage extends BaseWidgetMessage {
77
+ type: 'widget:open-wallet';
78
+ payload: {
79
+ platform: 'ios' | 'android';
80
+ };
81
+ }
82
+
83
+ export interface CardCreatedMessage extends BaseWidgetMessage {
84
+ type: 'widget:card-created';
85
+ payload: {
86
+ cardId: string;
87
+ cardType: 'virtual' | 'physical';
88
+ last4: string;
89
+ };
90
+ }
91
+
92
+ export interface WidgetErrorMessage extends BaseWidgetMessage {
93
+ type: 'widget:error';
94
+ payload: {
95
+ code: string;
96
+ message: string;
97
+ };
98
+ }
99
+
100
+ export interface WidgetCloseMessage extends BaseWidgetMessage {
101
+ type: 'widget:close';
102
+ }
103
+
104
+ export interface TransactionRequestedMessage extends BaseWidgetMessage {
105
+ type: 'widget:transaction-requested';
106
+ payload: {
107
+ token: DepositToken;
108
+ cryptoAmount: string;
109
+ depositAddress: string;
110
+ depositAddressTag: string | null;
111
+ };
112
+ }
113
+
114
+ export interface TokenExpiredMessage extends BaseWidgetMessage {
115
+ type: 'widget:token-expired';
116
+ payload?: {
117
+ reason?: string;
118
+ };
119
+ }
120
+
121
+ export type WidgetMessage =
122
+ | WidgetReadyMessage
123
+ | OpenWalletMessage
124
+ | CardCreatedMessage
125
+ | WidgetErrorMessage
126
+ | WidgetCloseMessage
127
+ | TransactionRequestedMessage
128
+ | TokenExpiredMessage;
129
+
130
+ /**
131
+ * SDK Configuration
132
+ */
133
+ export interface WidgetSDKConfig {
134
+ accessToken: string; // Required: Access token from backend
135
+ userWalletAddress: string; // Required: User's external wallet address for crypto deposits
136
+ onReady?: () => void;
137
+ onCardCreated?: (cardId: string, cardType: string, last4: string) => void;
138
+ onError?: (code: string, message: string) => void;
139
+ onClose?: () => void;
140
+ onTransactionRequested?: (token: DepositToken, cryptoAmount: string, depositAddress: string, depositAddressTag: string | null) => void;
141
+ }
142
+
143
+ /**
144
+ * Platform-specific wallet URLs
145
+ */
146
+ export const WALLET_URLS = {
147
+ ios: {
148
+ passkit: 'shoebox://', // Apple Wallet deep link
149
+ fallback: 'https://wallet.apple.com',
150
+ },
151
+ android: {
152
+ googlePay: 'https://pay.google.com/gp/w/home/wallet',
153
+ fallback: 'https://wallet.google.com',
154
+ },
155
+ } as const;
156
+
157
+ /**
158
+ * Message type constants that clients can use
159
+ * @example
160
+ * if (message.type === MessageTypes.READY) {
161
+ * // Handle ready
162
+ * }
163
+ */
164
+ export const MessageTypes = {
165
+ // Widget → Native
166
+ READY: 'widget:ready',
167
+ OPEN_WALLET: 'widget:open-wallet',
168
+ CARD_CREATED: 'widget:card-created',
169
+ ERROR: 'widget:error',
170
+ CLOSE: 'widget:close',
171
+ TRANSACTION_REQUESTED: 'widget:transaction-requested',
172
+ TOKEN_EXPIRED: 'widget:token-expired',
173
+ // Native → Widget
174
+ PLATFORM_INFO: 'native:platform-info',
175
+ WALLET_OPENED: 'native:wallet-opened',
176
+ BACK_PRESSED: 'native:back-pressed',
177
+ NAVIGATE_BACK: 'native:navigate-back',
178
+ } as const;
179
+
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Wallet Integration Utilities
3
+ * Handles opening Apple Wallet (iOS) and Google Wallet (Android)
4
+ */
5
+
6
+ import * as IntentLauncher from "expo-intent-launcher";
7
+ import { Alert, Linking, Platform } from "react-native";
8
+ import { WALLET_URLS } from "./types";
9
+
10
+ /**
11
+ * Opens the native wallet app based on platform
12
+ * @returns Promise that resolves when wallet opens successfully
13
+ */
14
+ export const openNativeWallet = async (): Promise<boolean> => {
15
+ try {
16
+ if (Platform.OS === "ios") {
17
+ return await openAppleWallet();
18
+ } else if (Platform.OS === "android") {
19
+ return await openGoogleWallet();
20
+ } else {
21
+ console.warn("Wallet opening not supported on this platform");
22
+ return false;
23
+ }
24
+ } catch (error) {
25
+ console.error("Failed to open wallet:", error);
26
+ Alert.alert(
27
+ "Error",
28
+ "Could not open wallet. Please check if the app is installed."
29
+ );
30
+ return false;
31
+ }
32
+ };
33
+
34
+ /**
35
+ * Opens Apple Wallet on iOS
36
+ * Uses multiple URL schemes in order of reliability
37
+ */
38
+ const openAppleWallet = async (): Promise<boolean> => {
39
+ const { passkit, fallback } = WALLET_URLS.ios;
40
+
41
+ try {
42
+ console.log("Attempting to open Apple Wallet...");
43
+
44
+ // Method 1: Try wallet:// scheme (documented as working in recent iOS)
45
+ try {
46
+ const canOpenWallet = await Linking.canOpenURL("wallet://");
47
+ if (canOpenWallet) {
48
+ await Linking.openURL("wallet://");
49
+ console.log("Successfully opened Apple Wallet via wallet:// scheme");
50
+ return true;
51
+ }
52
+ } catch (walletError) {
53
+ console.log("wallet:// scheme failed, trying shoebox://:", walletError);
54
+ }
55
+
56
+ // Method 2: Try shoebox:// scheme (undocumented but widely used)
57
+ // Note: This is unofficial and could potentially cause App Store rejection
58
+ try {
59
+ const canOpenShoebox = await Linking.canOpenURL(passkit);
60
+ if (canOpenShoebox) {
61
+ await Linking.openURL(passkit);
62
+ console.log("Successfully opened Apple Wallet via shoebox:// scheme");
63
+ return true;
64
+ }
65
+ } catch (shoeboxError) {
66
+ console.log("shoebox:// scheme failed:", shoeboxError);
67
+ }
68
+
69
+ // Method 3: Fallback to wallet.apple.com (opens in browser)
70
+ console.log("Direct schemes failed, falling back to web URL");
71
+ const canOpenFallback = await Linking.canOpenURL(fallback);
72
+ if (canOpenFallback) {
73
+ await Linking.openURL(fallback);
74
+ console.log("Opened wallet.apple.com in browser");
75
+ return true;
76
+ }
77
+
78
+ throw new Error("Apple Wallet not available");
79
+ } catch (error) {
80
+ console.error("Failed to open Apple Wallet:", error);
81
+ throw error;
82
+ }
83
+ };
84
+
85
+ /**
86
+ * Opens Google Wallet on Android
87
+ * Matches the proven Android native implementation from LinksUtils.kt
88
+ */
89
+ const openGoogleWallet = async (): Promise<boolean> => {
90
+ const GOOGLE_WALLET_PACKAGE = "com.google.android.apps.walletnfcrel";
91
+
92
+ try {
93
+ console.log("Attempting to open Google Wallet...");
94
+
95
+ // First, try using the market:// scheme to just launch the app if it's installed
96
+ // This is the most reliable way to open an installed app without knowing the exact activity
97
+ try {
98
+ const canOpen = await Linking.canOpenURL(`market://launch?id=${GOOGLE_WALLET_PACKAGE}`);
99
+ console.log("Can open market launch URL:", canOpen);
100
+
101
+ if (canOpen) {
102
+ await Linking.openURL(`market://launch?id=${GOOGLE_WALLET_PACKAGE}`);
103
+ console.log("Successfully opened Google Wallet via market:// scheme");
104
+ return true;
105
+ }
106
+ } catch (marketLaunchError) {
107
+ console.log("Market launch failed, trying intent launcher:", marketLaunchError);
108
+ }
109
+
110
+ // Fallback: Try intent launcher with ACTION_VIEW (no explicit className)
111
+ // This should open the app if it handles the VIEW action
112
+ try {
113
+ await IntentLauncher.startActivityAsync("android.intent.action.VIEW", {
114
+ packageName: GOOGLE_WALLET_PACKAGE,
115
+ flags: 268435456, // FLAG_ACTIVITY_NEW_TASK (0x10000000)
116
+ });
117
+ console.log("Successfully opened Google Wallet with VIEW intent");
118
+ return true;
119
+ } catch (intentError) {
120
+ console.log("Intent launcher failed:", intentError);
121
+
122
+ // App is not installed, open Play Store
123
+ console.log("App appears to not be installed, opening Play Store");
124
+ try {
125
+ // Try native Play Store app first
126
+ const playStoreUrl = `market://details?id=${GOOGLE_WALLET_PACKAGE}`;
127
+ await Linking.openURL(playStoreUrl);
128
+
129
+ Alert.alert(
130
+ "Google Wallet",
131
+ "Google Wallet is not installed. Opening Play Store to install the app."
132
+ );
133
+ return false;
134
+ } catch (marketError) {
135
+ console.log("Market URL failed, trying web Play Store:", marketError);
136
+
137
+ // Fallback to web Play Store
138
+ await Linking.openURL(
139
+ `https://play.google.com/store/apps/details?id=${GOOGLE_WALLET_PACKAGE}`
140
+ );
141
+
142
+ Alert.alert(
143
+ "Google Wallet",
144
+ "Google Wallet is not installed. Opening Play Store to install the app."
145
+ );
146
+ return false;
147
+ }
148
+ }
149
+ } catch (error) {
150
+ console.error("Failed to open Google Wallet:", error);
151
+ throw error;
152
+ }
153
+ };
154
+
155
+ /**
156
+ * Check if wallet is available on the current platform
157
+ */
158
+ export const isWalletAvailable = async (): Promise<boolean> => {
159
+ try {
160
+ if (Platform.OS === "ios") {
161
+ return await Linking.canOpenURL(WALLET_URLS.ios.passkit);
162
+ } else if (Platform.OS === "android") {
163
+ return await Linking.canOpenURL(WALLET_URLS.android.googlePay);
164
+ }
165
+ return false;
166
+ } catch (error) {
167
+ console.error("Error checking wallet availability:", error);
168
+ return false;
169
+ }
170
+ };