@blazium/ton-connect-mobile 1.0.0 → 1.0.2

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 CHANGED
@@ -10,6 +10,7 @@ Production-ready TON Connect Mobile SDK for React Native and Expo. This SDK impl
10
10
  - ✅ **Transaction Signing** - Send and sign transactions
11
11
  - ✅ **Signature Verification** - Verifies wallet signatures
12
12
  - ✅ **Cross-Platform** - Works with Expo Managed, Expo Bare, and React Native CLI
13
+ - ⚠️ **Web Limitation** - Deep links (`tonconnect://`) only work on mobile devices (Android/iOS), not in web browsers
13
14
  - ✅ **TypeScript** - Fully typed with TypeScript
14
15
  - ✅ **Production Ready** - No placeholders, no mocks, ready for production use
15
16
 
@@ -125,6 +126,21 @@ try {
125
126
  }
126
127
  ```
127
128
 
129
+ ### Platform Support
130
+
131
+ **⚠️ Important**: TON Connect deep links (`tonconnect://`) only work on **mobile devices** (Android/iOS). They do not work in web browsers.
132
+
133
+ - ✅ **Android**: Full support via Expo or React Native CLI
134
+ - ✅ **iOS**: Full support via Expo or React Native CLI
135
+ - ⚠️ **Web**: Deep links are not supported. The SDK will throw a clear error message if you try to use it in a web browser.
136
+
137
+ **Why?** The `tonconnect://` protocol is a custom URI scheme that requires a mobile app handler. Web browsers cannot handle these custom protocols.
138
+
139
+ **Testing**: To test wallet connections, use:
140
+ - Android device or emulator
141
+ - iOS device or simulator
142
+ - Not web browsers
143
+
128
144
  ### Disconnect
129
145
 
130
146
  ```typescript
@@ -44,15 +44,25 @@ class ExpoAdapter {
44
44
  throw new Error('expo-linking is not available');
45
45
  }
46
46
  try {
47
+ console.log('[ExpoAdapter] Checking if URL can be opened:', url);
47
48
  const canOpen = await Linking.canOpenURL(url);
49
+ console.log('[ExpoAdapter] canOpenURL result:', canOpen);
48
50
  if (!canOpen) {
49
- return false;
51
+ console.error('[ExpoAdapter] Cannot open URL - no app found that handles tonconnect:// protocol');
52
+ throw new Error(`Cannot open URL: ${url}. Make sure a wallet app is installed that supports tonconnect:// protocol.`);
50
53
  }
54
+ console.log('[ExpoAdapter] Opening URL...');
51
55
  await Linking.openURL(url);
56
+ console.log('[ExpoAdapter] URL opened successfully');
52
57
  return true;
53
58
  }
54
59
  catch (error) {
55
- return false;
60
+ console.error('[ExpoAdapter] Error in openURL:', error);
61
+ // Re-throw with more context
62
+ if (error.message && error.message.includes('Cannot open URL')) {
63
+ throw error;
64
+ }
65
+ throw new Error(`Failed to open URL: ${url}. ${error?.message || String(error)}`);
56
66
  }
57
67
  }
58
68
  async getInitialURL() {
@@ -42,15 +42,25 @@ class ReactNativeAdapter {
42
42
  throw new Error('react-native Linking is not available');
43
43
  }
44
44
  try {
45
+ console.log('[ReactNativeAdapter] Checking if URL can be opened:', url);
45
46
  const canOpen = await Linking.canOpenURL(url);
47
+ console.log('[ReactNativeAdapter] canOpenURL result:', canOpen);
46
48
  if (!canOpen) {
47
- return false;
49
+ console.error('[ReactNativeAdapter] Cannot open URL - no app found that handles tonconnect:// protocol');
50
+ throw new Error(`Cannot open URL: ${url}. Make sure a wallet app is installed that supports tonconnect:// protocol.`);
48
51
  }
52
+ console.log('[ReactNativeAdapter] Opening URL...');
49
53
  await Linking.openURL(url);
54
+ console.log('[ReactNativeAdapter] URL opened successfully');
50
55
  return true;
51
56
  }
52
57
  catch (error) {
53
- return false;
58
+ console.error('[ReactNativeAdapter] Error in openURL:', error);
59
+ // Re-throw with more context
60
+ if (error.message && error.message.includes('Cannot open URL')) {
61
+ throw error;
62
+ }
63
+ throw new Error(`Failed to open URL: ${url}. ${error?.message || String(error)}`);
54
64
  }
55
65
  }
56
66
  async getInitialURL() {
@@ -45,18 +45,26 @@ class WebAdapter {
45
45
  async openURL(url) {
46
46
  try {
47
47
  if (typeof window !== 'undefined') {
48
- // For web, we can use window.open or window.location
49
- // For deep links to mobile wallets, we'll use window.location
48
+ // For web, tonconnect:// deep links don't work
49
+ // They only work on mobile devices (Android/iOS)
50
50
  if (url.startsWith('tonconnect://')) {
51
- // Try to open in new window/tab, fallback to current window
52
- const opened = window.open(url, '_blank');
53
- if (!opened) {
54
- // Popup blocked, try current window
55
- window.location.href = url;
51
+ // Show user-friendly error message
52
+ const errorMessage = 'TON Connect deep links only work on mobile devices (Android/iOS).\n\n' +
53
+ 'Please test this on a mobile device or use the mobile app.\n\n' +
54
+ 'Deep link: ' + url.substring(0, 100) + '...';
55
+ // Try to show alert (if available)
56
+ if (typeof window.alert !== 'undefined') {
57
+ window.alert(errorMessage);
56
58
  }
57
- return true;
59
+ else {
60
+ console.error('TON Connect Web Error:', errorMessage);
61
+ }
62
+ // Throw error so SDK can handle it properly
63
+ throw new Error('TON Connect deep links are not supported in web browsers. ' +
64
+ 'Please use this SDK on a mobile device (Android/iOS) or test with a mobile app.');
58
65
  }
59
66
  else {
67
+ // Regular HTTP/HTTPS URLs work fine
60
68
  window.location.href = url;
61
69
  return true;
62
70
  }
@@ -64,7 +72,8 @@ class WebAdapter {
64
72
  return false;
65
73
  }
66
74
  catch (error) {
67
- return false;
75
+ // Re-throw the error so SDK can handle it
76
+ throw error;
68
77
  }
69
78
  }
70
79
  async getInitialURL() {
package/dist/index.js CHANGED
@@ -108,6 +108,7 @@ class TonConnectMobile {
108
108
  // eslint-disable-next-line no-undef
109
109
  if (typeof globalThis !== 'undefined' && globalThis.window && globalThis.document) {
110
110
  // Web platform
111
+ console.log('[TON Connect] Using WebAdapter');
111
112
  return new web_1.WebAdapter();
112
113
  }
113
114
  // Try to detect Expo environment
@@ -116,15 +117,18 @@ class TonConnectMobile {
116
117
  if (typeof require !== 'undefined') {
117
118
  const expoLinking = require('expo-linking');
118
119
  if (expoLinking) {
120
+ console.log('[TON Connect] Using ExpoAdapter');
119
121
  return new expo_1.ExpoAdapter();
120
122
  }
121
123
  }
122
124
  }
123
- catch {
125
+ catch (error) {
126
+ console.log('[TON Connect] ExpoAdapter not available:', error);
124
127
  // expo-linking not available, continue to React Native adapter
125
128
  }
126
129
  // Fall back to React Native adapter
127
130
  // This will work for both React Native CLI and Expo (since Expo also has react-native)
131
+ console.log('[TON Connect] Using ReactNativeAdapter');
128
132
  return new react_native_1.ReactNativeAdapter();
129
133
  }
130
134
  /**
@@ -260,6 +264,10 @@ class TonConnectMobile {
260
264
  }
261
265
  // Build connection request URL
262
266
  const url = (0, protocol_1.buildConnectionRequest)(this.config.manifestUrl, this.config.scheme);
267
+ // DEBUG: Log the URL being opened
268
+ console.log('[TON Connect] Opening URL:', url);
269
+ console.log('[TON Connect] Manifest URL:', this.config.manifestUrl);
270
+ console.log('[TON Connect] Return scheme:', this.config.scheme);
263
271
  // Create promise for connection
264
272
  return new Promise((resolve, reject) => {
265
273
  let timeout = null;
@@ -283,12 +291,27 @@ class TonConnectMobile {
283
291
  // Set timeout
284
292
  timeout = setTimeout(() => {
285
293
  if (this.connectionPromise) {
294
+ console.log('[TON Connect] Connection timeout after', this.config.connectionTimeout, 'ms');
286
295
  this.connectionPromise.reject(new ConnectionTimeoutError());
287
296
  }
288
297
  }, this.config.connectionTimeout);
289
298
  this.connectionPromise.timeout = timeout;
290
299
  // Open wallet app
291
- this.adapter.openURL(url).catch((error) => {
300
+ console.log('[TON Connect] Attempting to open wallet app...');
301
+ this.adapter.openURL(url).then((success) => {
302
+ console.log('[TON Connect] openURL result:', success);
303
+ // URL opened successfully, wait for callback
304
+ // If success is false, it should have thrown an error
305
+ if (!success && this.connectionPromise) {
306
+ console.log('[TON Connect] openURL returned false, rejecting promise');
307
+ this.connectionPromise.reject(new TonConnectError('Failed to open wallet app. Please make sure a TON wallet is installed.'));
308
+ }
309
+ else {
310
+ console.log('[TON Connect] URL opened successfully, waiting for wallet callback...');
311
+ }
312
+ }).catch((error) => {
313
+ // Error opening URL - reject the promise
314
+ console.error('[TON Connect] Error opening URL:', error);
292
315
  if (this.connectionPromise) {
293
316
  this.connectionPromise.reject(new TonConnectError(`Failed to open wallet: ${error?.message || String(error)}`));
294
317
  }
@@ -342,7 +365,14 @@ class TonConnectMobile {
342
365
  }, this.config.transactionTimeout);
343
366
  this.transactionPromise.timeout = timeout;
344
367
  // Open wallet app
345
- this.adapter.openURL(url).catch((error) => {
368
+ this.adapter.openURL(url).then((success) => {
369
+ // URL opened successfully, wait for callback
370
+ // If success is false, it should have thrown an error
371
+ if (!success && this.transactionPromise) {
372
+ this.transactionPromise.reject(new TonConnectError('Failed to open wallet app. Please make sure a TON wallet is installed.'));
373
+ }
374
+ }).catch((error) => {
375
+ // Error opening URL - reject the promise
346
376
  if (this.transactionPromise) {
347
377
  this.transactionPromise.reject(new TonConnectError(`Failed to open wallet: ${error?.message || String(error)}`));
348
378
  }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@blazium/ton-connect-mobile",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Production-ready TON Connect Mobile SDK for React Native and Expo. Implements the real TonConnect protocol for mobile applications using deep links and callbacks.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/blaziumdev/ton-connect-mobile.git"
9
+ "url": "git+https://github.com/blaziumdev/ton-connect-mobile.git"
10
10
  },
11
11
  "scripts": {
12
12
  "build": "tsc",
@@ -53,14 +53,24 @@ export class ExpoAdapter implements PlatformAdapter {
53
53
  throw new Error('expo-linking is not available');
54
54
  }
55
55
  try {
56
+ console.log('[ExpoAdapter] Checking if URL can be opened:', url);
56
57
  const canOpen = await Linking.canOpenURL(url);
58
+ console.log('[ExpoAdapter] canOpenURL result:', canOpen);
57
59
  if (!canOpen) {
58
- return false;
60
+ console.error('[ExpoAdapter] Cannot open URL - no app found that handles tonconnect:// protocol');
61
+ throw new Error(`Cannot open URL: ${url}. Make sure a wallet app is installed that supports tonconnect:// protocol.`);
59
62
  }
63
+ console.log('[ExpoAdapter] Opening URL...');
60
64
  await Linking.openURL(url);
65
+ console.log('[ExpoAdapter] URL opened successfully');
61
66
  return true;
62
- } catch (error) {
63
- return false;
67
+ } catch (error: any) {
68
+ console.error('[ExpoAdapter] Error in openURL:', error);
69
+ // Re-throw with more context
70
+ if (error.message && error.message.includes('Cannot open URL')) {
71
+ throw error;
72
+ }
73
+ throw new Error(`Failed to open URL: ${url}. ${error?.message || String(error)}`);
64
74
  }
65
75
  }
66
76
 
@@ -51,14 +51,24 @@ export class ReactNativeAdapter implements PlatformAdapter {
51
51
  throw new Error('react-native Linking is not available');
52
52
  }
53
53
  try {
54
+ console.log('[ReactNativeAdapter] Checking if URL can be opened:', url);
54
55
  const canOpen = await Linking.canOpenURL(url);
56
+ console.log('[ReactNativeAdapter] canOpenURL result:', canOpen);
55
57
  if (!canOpen) {
56
- return false;
58
+ console.error('[ReactNativeAdapter] Cannot open URL - no app found that handles tonconnect:// protocol');
59
+ throw new Error(`Cannot open URL: ${url}. Make sure a wallet app is installed that supports tonconnect:// protocol.`);
57
60
  }
61
+ console.log('[ReactNativeAdapter] Opening URL...');
58
62
  await Linking.openURL(url);
63
+ console.log('[ReactNativeAdapter] URL opened successfully');
59
64
  return true;
60
- } catch (error) {
61
- return false;
65
+ } catch (error: any) {
66
+ console.error('[ReactNativeAdapter] Error in openURL:', error);
67
+ // Re-throw with more context
68
+ if (error.message && error.message.includes('Cannot open URL')) {
69
+ throw error;
70
+ }
71
+ throw new Error(`Failed to open URL: ${url}. ${error?.message || String(error)}`);
62
72
  }
63
73
  }
64
74
 
@@ -11,6 +11,7 @@ declare const window: {
11
11
  open(url: string, target?: string): any;
12
12
  addEventListener(type: string, listener: () => void): void;
13
13
  removeEventListener(type: string, listener: () => void): void;
14
+ alert(message: string): void;
14
15
  localStorage: {
15
16
  setItem(key: string, value: string): void;
16
17
  getItem(key: string): string | null;
@@ -68,24 +69,37 @@ export class WebAdapter implements PlatformAdapter {
68
69
  async openURL(url: string): Promise<boolean> {
69
70
  try {
70
71
  if (typeof window !== 'undefined') {
71
- // For web, we can use window.open or window.location
72
- // For deep links to mobile wallets, we'll use window.location
72
+ // For web, tonconnect:// deep links don't work
73
+ // They only work on mobile devices (Android/iOS)
73
74
  if (url.startsWith('tonconnect://')) {
74
- // Try to open in new window/tab, fallback to current window
75
- const opened = window.open(url, '_blank');
76
- if (!opened) {
77
- // Popup blocked, try current window
78
- window.location.href = url;
75
+ // Show user-friendly error message
76
+ const errorMessage =
77
+ 'TON Connect deep links only work on mobile devices (Android/iOS).\n\n' +
78
+ 'Please test this on a mobile device or use the mobile app.\n\n' +
79
+ 'Deep link: ' + url.substring(0, 100) + '...';
80
+
81
+ // Try to show alert (if available)
82
+ if (typeof window.alert !== 'undefined') {
83
+ window.alert(errorMessage);
84
+ } else {
85
+ console.error('TON Connect Web Error:', errorMessage);
79
86
  }
80
- return true;
87
+
88
+ // Throw error so SDK can handle it properly
89
+ throw new Error(
90
+ 'TON Connect deep links are not supported in web browsers. ' +
91
+ 'Please use this SDK on a mobile device (Android/iOS) or test with a mobile app.'
92
+ );
81
93
  } else {
94
+ // Regular HTTP/HTTPS URLs work fine
82
95
  window.location.href = url;
83
96
  return true;
84
97
  }
85
98
  }
86
99
  return false;
87
100
  } catch (error) {
88
- return false;
101
+ // Re-throw the error so SDK can handle it
102
+ throw error;
89
103
  }
90
104
  }
91
105
 
package/src/index.ts CHANGED
@@ -132,6 +132,7 @@ export class TonConnectMobile {
132
132
  // eslint-disable-next-line no-undef
133
133
  if (typeof globalThis !== 'undefined' && (globalThis as any).window && (globalThis as any).document) {
134
134
  // Web platform
135
+ console.log('[TON Connect] Using WebAdapter');
135
136
  return new WebAdapter();
136
137
  }
137
138
 
@@ -141,15 +142,18 @@ export class TonConnectMobile {
141
142
  if (typeof require !== 'undefined') {
142
143
  const expoLinking = require('expo-linking');
143
144
  if (expoLinking) {
145
+ console.log('[TON Connect] Using ExpoAdapter');
144
146
  return new ExpoAdapter();
145
147
  }
146
148
  }
147
- } catch {
149
+ } catch (error) {
150
+ console.log('[TON Connect] ExpoAdapter not available:', error);
148
151
  // expo-linking not available, continue to React Native adapter
149
152
  }
150
153
 
151
154
  // Fall back to React Native adapter
152
155
  // This will work for both React Native CLI and Expo (since Expo also has react-native)
156
+ console.log('[TON Connect] Using ReactNativeAdapter');
153
157
  return new ReactNativeAdapter();
154
158
  }
155
159
 
@@ -300,6 +304,11 @@ export class TonConnectMobile {
300
304
 
301
305
  // Build connection request URL
302
306
  const url = buildConnectionRequest(this.config.manifestUrl, this.config.scheme);
307
+
308
+ // DEBUG: Log the URL being opened
309
+ console.log('[TON Connect] Opening URL:', url);
310
+ console.log('[TON Connect] Manifest URL:', this.config.manifestUrl);
311
+ console.log('[TON Connect] Return scheme:', this.config.scheme);
303
312
 
304
313
  // Create promise for connection
305
314
  return new Promise<WalletInfo>((resolve, reject) => {
@@ -326,6 +335,7 @@ export class TonConnectMobile {
326
335
  // Set timeout
327
336
  timeout = setTimeout(() => {
328
337
  if (this.connectionPromise) {
338
+ console.log('[TON Connect] Connection timeout after', this.config.connectionTimeout, 'ms');
329
339
  this.connectionPromise.reject(new ConnectionTimeoutError());
330
340
  }
331
341
  }, this.config.connectionTimeout) as unknown as number;
@@ -333,7 +343,22 @@ export class TonConnectMobile {
333
343
  this.connectionPromise.timeout = timeout;
334
344
 
335
345
  // Open wallet app
336
- this.adapter.openURL(url).catch((error) => {
346
+ console.log('[TON Connect] Attempting to open wallet app...');
347
+ this.adapter.openURL(url).then((success) => {
348
+ console.log('[TON Connect] openURL result:', success);
349
+ // URL opened successfully, wait for callback
350
+ // If success is false, it should have thrown an error
351
+ if (!success && this.connectionPromise) {
352
+ console.log('[TON Connect] openURL returned false, rejecting promise');
353
+ this.connectionPromise.reject(
354
+ new TonConnectError('Failed to open wallet app. Please make sure a TON wallet is installed.')
355
+ );
356
+ } else {
357
+ console.log('[TON Connect] URL opened successfully, waiting for wallet callback...');
358
+ }
359
+ }).catch((error) => {
360
+ // Error opening URL - reject the promise
361
+ console.error('[TON Connect] Error opening URL:', error);
337
362
  if (this.connectionPromise) {
338
363
  this.connectionPromise.reject(
339
364
  new TonConnectError(`Failed to open wallet: ${error?.message || String(error)}`)
@@ -398,7 +423,16 @@ export class TonConnectMobile {
398
423
  this.transactionPromise.timeout = timeout;
399
424
 
400
425
  // Open wallet app
401
- this.adapter.openURL(url).catch((error) => {
426
+ this.adapter.openURL(url).then((success) => {
427
+ // URL opened successfully, wait for callback
428
+ // If success is false, it should have thrown an error
429
+ if (!success && this.transactionPromise) {
430
+ this.transactionPromise.reject(
431
+ new TonConnectError('Failed to open wallet app. Please make sure a TON wallet is installed.')
432
+ );
433
+ }
434
+ }).catch((error) => {
435
+ // Error opening URL - reject the promise
402
436
  if (this.transactionPromise) {
403
437
  this.transactionPromise.reject(
404
438
  new TonConnectError(`Failed to open wallet: ${error?.message || String(error)}`)