@phantom/react-sdk 1.0.0-beta.0 → 1.0.0-beta.10

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/dist/index.js CHANGED
@@ -52,23 +52,30 @@ var import_browser_sdk = require("@phantom/browser-sdk");
52
52
  var import_jsx_runtime = require("react/jsx-runtime");
53
53
  var PhantomContext = (0, import_react.createContext)(void 0);
54
54
  function PhantomProvider({ children, config, debugConfig }) {
55
+ const memoizedConfig = (0, import_react.useMemo)(() => config, [config]);
56
+ const [sdk, setSdk] = (0, import_react.useState)(null);
57
+ const [isClient, setIsClient] = (0, import_react.useState)(false);
55
58
  const [isConnected, setIsConnected] = (0, import_react.useState)(false);
56
59
  const [isConnecting, setIsConnecting] = (0, import_react.useState)(false);
57
60
  const [connectError, setConnectError] = (0, import_react.useState)(null);
58
61
  const [addresses, setAddresses] = (0, import_react.useState)([]);
59
62
  const [walletId, setWalletId] = (0, import_react.useState)(null);
60
- const [currentProviderType, setCurrentProviderType] = (0, import_react.useState)(config.providerType || null);
63
+ const [currentProviderType, setCurrentProviderType] = (0, import_react.useState)(
64
+ memoizedConfig.providerType || null
65
+ );
61
66
  const [isPhantomAvailable, setIsPhantomAvailable] = (0, import_react.useState)(false);
62
- const [sdk, setSdk] = (0, import_react.useState)(null);
63
- const memoizedConfig = (0, import_react.useMemo)(() => {
64
- return {
65
- ...config,
66
- // Use providerType if provided, default to embedded
67
- providerType: config.providerType || "embedded"
68
- };
69
- }, [config]);
70
67
  (0, import_react.useEffect)(() => {
68
+ setIsClient(true);
69
+ }, []);
70
+ (0, import_react.useEffect)(() => {
71
+ if (!isClient)
72
+ return;
71
73
  const sdkInstance = new import_browser_sdk.BrowserSDK(memoizedConfig);
74
+ setSdk(sdkInstance);
75
+ }, [isClient, memoizedConfig]);
76
+ (0, import_react.useEffect)(() => {
77
+ if (!sdk)
78
+ return;
72
79
  const handleConnectStart = () => {
73
80
  setIsConnecting(true);
74
81
  setConnectError(null);
@@ -77,15 +84,15 @@ function PhantomProvider({ children, config, debugConfig }) {
77
84
  try {
78
85
  setIsConnected(true);
79
86
  setIsConnecting(false);
80
- const providerInfo = sdkInstance.getCurrentProviderInfo();
87
+ const providerInfo = sdk.getCurrentProviderInfo();
81
88
  setCurrentProviderType(providerInfo?.type || null);
82
- const addrs = await sdkInstance.getAddresses();
89
+ const addrs = await sdk.getAddresses();
83
90
  setAddresses(addrs);
84
- setWalletId(sdkInstance.getWalletId());
91
+ setWalletId(sdk.getWalletId());
85
92
  } catch (err) {
86
93
  console.error("Error connecting:", err);
87
94
  try {
88
- await sdkInstance.disconnect();
95
+ await sdk.disconnect();
89
96
  } catch (err2) {
90
97
  console.error("Error disconnecting:", err2);
91
98
  }
@@ -103,41 +110,40 @@ function PhantomProvider({ children, config, debugConfig }) {
103
110
  setAddresses([]);
104
111
  setWalletId(null);
105
112
  };
106
- sdkInstance.on("connect_start", handleConnectStart);
107
- sdkInstance.on("connect", handleConnect);
108
- sdkInstance.on("connect_error", handleConnectError);
109
- sdkInstance.on("disconnect", handleDisconnect);
110
- setSdk(sdkInstance);
113
+ sdk.on("connect_start", handleConnectStart);
114
+ sdk.on("connect", handleConnect);
115
+ sdk.on("connect_error", handleConnectError);
116
+ sdk.on("disconnect", handleDisconnect);
111
117
  return () => {
112
- sdkInstance.off("connect_start", handleConnectStart);
113
- sdkInstance.off("connect", handleConnect);
114
- sdkInstance.off("connect_error", handleConnectError);
115
- sdkInstance.off("disconnect", handleDisconnect);
118
+ sdk.off("connect_start", handleConnectStart);
119
+ sdk.off("connect", handleConnect);
120
+ sdk.off("connect_error", handleConnectError);
121
+ sdk.off("disconnect", handleDisconnect);
116
122
  };
117
- }, [memoizedConfig]);
123
+ }, [sdk]);
118
124
  (0, import_react.useEffect)(() => {
119
- if (!sdk || !debugConfig)
125
+ if (!debugConfig || !sdk)
120
126
  return;
121
127
  sdk.configureDebug(debugConfig);
122
128
  }, [sdk, debugConfig]);
123
129
  (0, import_react.useEffect)(() => {
124
- if (!sdk)
130
+ if (!isClient || !sdk)
125
131
  return;
126
- const initialize = () => {
132
+ const initialize = async () => {
127
133
  try {
128
- const available = import_browser_sdk.BrowserSDK.isPhantomInstalled();
134
+ const available = await import_browser_sdk.BrowserSDK.isPhantomInstalled();
129
135
  setIsPhantomAvailable(available);
130
136
  } catch (err) {
131
137
  console.error("Error checking Phantom extension:", err);
132
138
  setIsPhantomAvailable(false);
133
139
  }
134
- if (config.autoConnect !== false) {
140
+ if (memoizedConfig.autoConnect !== false) {
135
141
  sdk.autoConnect().catch(() => {
136
142
  });
137
143
  }
138
144
  };
139
145
  initialize();
140
- }, [sdk, config.autoConnect]);
146
+ }, [sdk, memoizedConfig.autoConnect, isClient]);
141
147
  const value = (0, import_react.useMemo)(
142
148
  () => ({
143
149
  sdk,
@@ -147,18 +153,10 @@ function PhantomProvider({ children, config, debugConfig }) {
147
153
  addresses,
148
154
  walletId,
149
155
  currentProviderType,
150
- isPhantomAvailable
156
+ isPhantomAvailable,
157
+ isClient
151
158
  }),
152
- [
153
- sdk,
154
- isConnected,
155
- isConnecting,
156
- connectError,
157
- addresses,
158
- walletId,
159
- currentProviderType,
160
- isPhantomAvailable
161
- ]
159
+ [sdk, isConnected, isConnecting, connectError, addresses, walletId, currentProviderType, isPhantomAvailable, isClient]
162
160
  );
163
161
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PhantomContext.Provider, { value, children });
164
162
  }
@@ -235,36 +233,33 @@ function useAccounts() {
235
233
  // src/hooks/useIsExtensionInstalled.ts
236
234
  var React = __toESM(require("react"));
237
235
  var import_browser_sdk2 = require("@phantom/browser-sdk");
238
- var cachedIsInstalled = null;
239
236
  function useIsExtensionInstalled() {
240
- const { sdk } = usePhantom();
241
- const [isLoading, setIsLoading] = React.useState(cachedIsInstalled === null);
242
- const [isInstalled, setIsInstalled] = React.useState(cachedIsInstalled ?? false);
237
+ const [isLoading, setIsLoading] = React.useState(true);
238
+ const [isInstalled, setIsInstalled] = React.useState(false);
243
239
  React.useEffect(() => {
244
- if (!sdk) {
245
- setIsLoading(false);
246
- return;
247
- }
248
- if (cachedIsInstalled !== null) {
249
- setIsInstalled(cachedIsInstalled);
250
- setIsLoading(false);
251
- return;
252
- }
253
- const checkExtension = () => {
240
+ let isMounted = true;
241
+ const checkExtension = async () => {
254
242
  try {
255
243
  setIsLoading(true);
256
- const result = import_browser_sdk2.BrowserSDK.isPhantomInstalled();
257
- cachedIsInstalled = result;
258
- setIsInstalled(result);
244
+ const result = await (0, import_browser_sdk2.waitForPhantomExtension)(3e3);
245
+ if (isMounted) {
246
+ setIsInstalled(result);
247
+ }
259
248
  } catch (error) {
260
- cachedIsInstalled = false;
261
- setIsInstalled(false);
249
+ if (isMounted) {
250
+ setIsInstalled(false);
251
+ }
262
252
  } finally {
263
- setIsLoading(false);
253
+ if (isMounted) {
254
+ setIsLoading(false);
255
+ }
264
256
  }
265
257
  };
266
258
  checkExtension();
267
- }, [sdk]);
259
+ return () => {
260
+ isMounted = false;
261
+ };
262
+ }, []);
268
263
  return { isLoading, isInstalled };
269
264
  }
270
265
 
@@ -301,53 +296,47 @@ function useAutoConfirm() {
301
296
  },
302
297
  [sdk, isInjected]
303
298
  );
304
- const disable = (0, import_react4.useCallback)(
305
- async () => {
306
- if (!sdk) {
307
- throw new Error("SDK not initialized");
308
- }
309
- if (!isInjected) {
310
- throw new Error("Auto-confirm is only available for injected (extension) providers");
311
- }
312
- try {
313
- setIsLoading(true);
314
- setError(null);
315
- await sdk.disableAutoConfirm();
316
- const newStatus = await sdk.getAutoConfirmStatus();
317
- setStatus(newStatus);
318
- } catch (err) {
319
- const error2 = err instanceof Error ? err : new Error("Unknown error occurred");
320
- setError(error2);
321
- throw error2;
322
- } finally {
323
- setIsLoading(false);
324
- }
325
- },
326
- [sdk, isInjected]
327
- );
328
- const refetch = (0, import_react4.useCallback)(
329
- async () => {
330
- if (!sdk || !isInjected) {
331
- return;
332
- }
333
- try {
334
- setIsLoading(true);
335
- setError(null);
336
- const [statusResult, supportedResult] = await Promise.all([
337
- sdk.getAutoConfirmStatus(),
338
- sdk.getSupportedAutoConfirmChains()
339
- ]);
340
- setStatus(statusResult);
341
- setSupportedChains(supportedResult);
342
- } catch (err) {
343
- const error2 = err instanceof Error ? err : new Error("Failed to fetch auto-confirm data");
344
- setError(error2);
345
- } finally {
346
- setIsLoading(false);
347
- }
348
- },
349
- [sdk, isInjected]
350
- );
299
+ const disable = (0, import_react4.useCallback)(async () => {
300
+ if (!sdk) {
301
+ throw new Error("SDK not initialized");
302
+ }
303
+ if (!isInjected) {
304
+ throw new Error("Auto-confirm is only available for injected (extension) providers");
305
+ }
306
+ try {
307
+ setIsLoading(true);
308
+ setError(null);
309
+ await sdk.disableAutoConfirm();
310
+ const newStatus = await sdk.getAutoConfirmStatus();
311
+ setStatus(newStatus);
312
+ } catch (err) {
313
+ const error2 = err instanceof Error ? err : new Error("Unknown error occurred");
314
+ setError(error2);
315
+ throw error2;
316
+ } finally {
317
+ setIsLoading(false);
318
+ }
319
+ }, [sdk, isInjected]);
320
+ const refetch = (0, import_react4.useCallback)(async () => {
321
+ if (!sdk || !isInjected) {
322
+ return;
323
+ }
324
+ try {
325
+ setIsLoading(true);
326
+ setError(null);
327
+ const [statusResult, supportedResult] = await Promise.all([
328
+ sdk.getAutoConfirmStatus(),
329
+ sdk.getSupportedAutoConfirmChains()
330
+ ]);
331
+ setStatus(statusResult);
332
+ setSupportedChains(supportedResult);
333
+ } catch (err) {
334
+ const error2 = err instanceof Error ? err : new Error("Failed to fetch auto-confirm data");
335
+ setError(error2);
336
+ } finally {
337
+ setIsLoading(false);
338
+ }
339
+ }, [sdk, isInjected]);
351
340
  (0, import_react4.useEffect)(() => {
352
341
  if (sdk && isInjected) {
353
342
  refetch();
@@ -369,143 +358,38 @@ function useAutoConfirm() {
369
358
  }
370
359
 
371
360
  // src/hooks/useSolana.ts
372
- var import_react5 = require("react");
373
361
  function useSolana() {
374
- const { sdk, isConnected } = usePhantom();
375
- const solanaChain = (0, import_react5.useMemo)(() => {
376
- if (!sdk || !isConnected)
377
- return null;
378
- try {
379
- return sdk.solana;
380
- } catch {
381
- return null;
382
- }
383
- }, [sdk, isConnected]);
384
- const signMessage = (0, import_react5.useCallback)(async (message) => {
385
- if (!solanaChain)
386
- throw new Error("Solana chain not available. Ensure SDK is connected.");
387
- return solanaChain.signMessage(message);
388
- }, [solanaChain]);
389
- const signTransaction = (0, import_react5.useCallback)(async (transaction) => {
390
- if (!solanaChain)
391
- throw new Error("Solana chain not available. Ensure SDK is connected.");
392
- return solanaChain.signTransaction(transaction);
393
- }, [solanaChain]);
394
- const signAndSendTransaction = (0, import_react5.useCallback)(async (transaction) => {
395
- if (!solanaChain)
396
- throw new Error("Solana chain not available. Ensure SDK is connected.");
397
- return solanaChain.signAndSendTransaction(transaction);
398
- }, [solanaChain]);
399
- const connect = (0, import_react5.useCallback)(async (options) => {
400
- if (!solanaChain)
401
- throw new Error("Solana chain not available. Ensure SDK is connected.");
402
- return solanaChain.connect(options);
403
- }, [solanaChain]);
404
- const disconnect = (0, import_react5.useCallback)(async () => {
405
- if (!solanaChain)
406
- throw new Error("Solana chain not available. Ensure SDK is connected.");
407
- return solanaChain.disconnect();
408
- }, [solanaChain]);
409
- const switchNetwork = (0, import_react5.useCallback)(async (network) => {
410
- if (!solanaChain)
411
- throw new Error("Solana chain not available. Ensure SDK is connected.");
412
- return solanaChain.switchNetwork(network);
413
- }, [solanaChain]);
414
- const getPublicKey = (0, import_react5.useCallback)(async () => {
415
- if (!solanaChain)
416
- return null;
417
- return solanaChain.getPublicKey();
418
- }, [solanaChain]);
362
+ const { sdk, isConnected, isClient } = usePhantom();
363
+ if (!isClient || !sdk) {
364
+ return {
365
+ solana: {},
366
+ // This will be replaced when SDK is ready
367
+ isAvailable: false
368
+ };
369
+ }
419
370
  return {
420
- // Chain instance for advanced usage
421
- solana: solanaChain,
422
- // Convenient methods
423
- signMessage,
424
- signTransaction,
425
- signAndSendTransaction,
426
- connect,
427
- disconnect,
428
- switchNetwork,
429
- getPublicKey,
371
+ // Chain instance with connection enforcement for signing methods
372
+ solana: sdk.solana,
430
373
  // State
431
- isAvailable: !!solanaChain,
432
- isConnected: solanaChain?.isConnected() ?? false
374
+ isAvailable: !!isConnected
433
375
  };
434
376
  }
435
377
 
436
378
  // src/hooks/useEthereum.ts
437
- var import_react6 = require("react");
438
379
  function useEthereum() {
439
- const { sdk, isConnected } = usePhantom();
440
- const ethereumChain = (0, import_react6.useMemo)(() => {
441
- if (!sdk || !isConnected)
442
- return null;
443
- try {
444
- return sdk.ethereum;
445
- } catch {
446
- return null;
447
- }
448
- }, [sdk, isConnected]);
449
- const request = (0, import_react6.useCallback)(async (args) => {
450
- if (!ethereumChain)
451
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
452
- return ethereumChain.request(args);
453
- }, [ethereumChain]);
454
- const signPersonalMessage = (0, import_react6.useCallback)(async (message, address) => {
455
- return request({
456
- method: "personal_sign",
457
- params: [message, address]
458
- });
459
- }, [request]);
460
- const sendTransaction = (0, import_react6.useCallback)(async (transaction) => {
461
- if (!ethereumChain)
462
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
463
- return ethereumChain.sendTransaction(transaction);
464
- }, [ethereumChain]);
465
- const switchChain = (0, import_react6.useCallback)(async (chainId) => {
466
- if (!ethereumChain)
467
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
468
- return ethereumChain.switchChain(chainId);
469
- }, [ethereumChain]);
470
- const getChainId = (0, import_react6.useCallback)(async () => {
471
- if (!ethereumChain)
472
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
473
- return ethereumChain.getChainId();
474
- }, [ethereumChain]);
475
- const getAccounts = (0, import_react6.useCallback)(async () => {
476
- if (!ethereumChain)
477
- throw new Error("Ethereum chain not available. Ensure SDK is connected.");
478
- return ethereumChain.getAccounts();
479
- }, [ethereumChain]);
480
- const signMessage = (0, import_react6.useCallback)(async (message) => {
481
- return request({
482
- method: "eth_sign",
483
- params: [await getAccounts().then((accounts) => accounts[0]), message]
484
- });
485
- }, [request, getAccounts]);
486
- const signTypedData = (0, import_react6.useCallback)(async (typedData) => {
487
- const accounts = await getAccounts();
488
- return request({
489
- method: "eth_signTypedData_v4",
490
- params: [accounts[0], JSON.stringify(typedData)]
491
- });
492
- }, [request, getAccounts]);
380
+ const { sdk, isConnected, isClient } = usePhantom();
381
+ if (!isClient || !sdk) {
382
+ return {
383
+ ethereum: {},
384
+ // This will be replaced when SDK is ready
385
+ isAvailable: false
386
+ };
387
+ }
493
388
  return {
494
- // Chain instance for advanced usage
495
- ethereum: ethereumChain,
496
- // Standard EIP-1193 interface
497
- request,
498
- // Convenient methods
499
- signPersonalMessage,
500
- signMessage,
501
- signTypedData,
502
- sendTransaction,
503
- switchChain,
504
- getChainId,
505
- getAccounts,
389
+ // Chain instance with connection enforcement for signing methods
390
+ ethereum: sdk.ethereum,
506
391
  // State
507
- isAvailable: !!ethereumChain,
508
- isConnected: ethereumChain?.isConnected() ?? false
392
+ isAvailable: !!isConnected
509
393
  };
510
394
  }
511
395