@voyage_ai/v402-web-ts 0.1.0 → 0.1.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.
@@ -30,7 +30,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/react/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- PaymentButton: () => PaymentButton,
34
33
  WalletConnect: () => WalletConnect,
35
34
  usePayment: () => usePayment,
36
35
  usePaymentInfo: () => usePaymentInfo,
@@ -45,7 +44,7 @@ var import_react = require("react");
45
44
  var import_types3 = require("x402/types");
46
45
 
47
46
  // src/types/common.ts
48
- var PROD_BACK_URL = "https://v402.onvoyage.ai/api";
47
+ var PROD_BACK_URL = "https://v402.onvoyage.ai/api/pay";
49
48
 
50
49
  // src/types/svm.ts
51
50
  var import_zod = require("zod");
@@ -234,300 +233,48 @@ function onAccountsChanged(callback) {
234
233
  ethereum.removeListener?.("accountsChanged", handler);
235
234
  };
236
235
  }
237
-
238
- // src/services/svm/payment-header.ts
239
- var import_web3 = require("@solana/web3.js");
240
- var import_spl_token = require("@solana/spl-token");
241
- async function createSvmPaymentHeader(params) {
242
- const { wallet, paymentRequirements, x402Version, rpcUrl } = params;
243
- const connection = new import_web3.Connection(rpcUrl, "confirmed");
244
- const feePayer = paymentRequirements?.extra?.feePayer;
245
- if (typeof feePayer !== "string" || !feePayer) {
246
- throw new Error("Missing facilitator feePayer in payment requirements (extra.feePayer).");
247
- }
248
- const feePayerPubkey = new import_web3.PublicKey(feePayer);
249
- const walletAddress = wallet?.publicKey?.toString() || wallet?.address;
250
- if (!walletAddress) {
251
- throw new Error("Missing connected Solana wallet address or publicKey");
252
- }
253
- const userPubkey = new import_web3.PublicKey(walletAddress);
254
- if (!paymentRequirements?.payTo) {
255
- throw new Error("Missing payTo in payment requirements");
256
- }
257
- const destination = new import_web3.PublicKey(paymentRequirements.payTo);
258
- const instructions = [];
259
- instructions.push(
260
- import_web3.ComputeBudgetProgram.setComputeUnitLimit({
261
- units: 7e3
262
- // Sufficient for SPL token transfer
263
- })
264
- );
265
- instructions.push(
266
- import_web3.ComputeBudgetProgram.setComputeUnitPrice({
267
- microLamports: 1
268
- // Minimal price
269
- })
270
- );
271
- if (!paymentRequirements.asset) {
272
- throw new Error("Missing token mint for SPL transfer");
273
- }
274
- const mintPubkey = new import_web3.PublicKey(paymentRequirements.asset);
275
- const mintInfo = await connection.getAccountInfo(mintPubkey, "confirmed");
276
- const programId = mintInfo?.owner?.toBase58() === import_spl_token.TOKEN_2022_PROGRAM_ID.toBase58() ? import_spl_token.TOKEN_2022_PROGRAM_ID : import_spl_token.TOKEN_PROGRAM_ID;
277
- const mint = await (0, import_spl_token.getMint)(connection, mintPubkey, void 0, programId);
278
- const sourceAta = await (0, import_spl_token.getAssociatedTokenAddress)(
279
- mintPubkey,
280
- userPubkey,
281
- false,
282
- programId
283
- );
284
- const destinationAta = await (0, import_spl_token.getAssociatedTokenAddress)(
285
- mintPubkey,
286
- destination,
287
- false,
288
- programId
289
- );
290
- const sourceAtaInfo = await connection.getAccountInfo(sourceAta, "confirmed");
291
- if (!sourceAtaInfo) {
292
- throw new Error(
293
- `User does not have an Associated Token Account for ${paymentRequirements.asset}. Please create one first or ensure you have the required token.`
294
- );
295
- }
296
- const destAtaInfo = await connection.getAccountInfo(destinationAta, "confirmed");
297
- if (!destAtaInfo) {
298
- throw new Error(
299
- `Destination does not have an Associated Token Account for ${paymentRequirements.asset}. The receiver must create their token account before receiving payments.`
300
- );
301
- }
302
- const amount = BigInt(paymentRequirements.maxAmountRequired);
303
- instructions.push(
304
- (0, import_spl_token.createTransferCheckedInstruction)(
305
- sourceAta,
306
- mintPubkey,
307
- destinationAta,
308
- userPubkey,
309
- amount,
310
- mint.decimals,
311
- [],
312
- programId
313
- )
314
- );
315
- const { blockhash } = await connection.getLatestBlockhash("confirmed");
316
- const message = new import_web3.TransactionMessage({
317
- payerKey: feePayerPubkey,
318
- recentBlockhash: blockhash,
319
- instructions
320
- }).compileToV0Message();
321
- const transaction = new import_web3.VersionedTransaction(message);
322
- if (typeof wallet?.signTransaction !== "function") {
323
- throw new Error("Connected wallet does not support signTransaction");
324
- }
325
- const userSignedTx = await wallet.signTransaction(transaction);
326
- const serializedTransaction = Buffer.from(userSignedTx.serialize()).toString("base64");
327
- const paymentPayload = {
328
- x402Version,
329
- scheme: paymentRequirements.scheme,
330
- network: paymentRequirements.network,
331
- payload: {
332
- transaction: serializedTransaction
333
- }
334
- };
335
- const paymentHeader = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
336
- return paymentHeader;
337
- }
338
- function getDefaultSolanaRpcUrl(network) {
339
- const normalized = network.toLowerCase();
340
- if (normalized === "solana" || normalized === "solana-mainnet") {
341
- return "https://api.mainnet-beta.solana.com";
342
- } else if (normalized === "solana-devnet") {
343
- return "https://api.devnet.solana.com";
344
- }
345
- throw new Error(`Unsupported Solana network: ${network}`);
346
- }
347
-
348
- // src/services/svm/payment-handler.ts
349
- async function handleSvmPayment(endpoint, config, requestInit) {
350
- const { wallet, network, rpcUrl, maxPaymentAmount } = config;
351
- const initialResponse = await fetch(endpoint, {
352
- ...requestInit,
353
- method: requestInit?.method || "POST"
354
- });
355
- if (initialResponse.status !== 402) {
356
- return initialResponse;
357
- }
358
- const rawResponse = await initialResponse.json();
359
- const x402Version = rawResponse.x402Version;
360
- const parsedPaymentRequirements = rawResponse.accepts || [];
361
- const selectedRequirements = parsedPaymentRequirements.find(
362
- (req) => req.scheme === "exact" && SolanaNetworkSchema.safeParse(req.network.toLowerCase()).success
363
- );
364
- if (!selectedRequirements) {
365
- console.error(
366
- "\u274C No suitable Solana payment requirements found. Available networks:",
367
- parsedPaymentRequirements.map((req) => req.network)
368
- );
369
- throw new Error("No suitable Solana payment requirements found");
370
- }
371
- if (maxPaymentAmount && maxPaymentAmount > BigInt(0)) {
372
- if (BigInt(selectedRequirements.maxAmountRequired) > maxPaymentAmount) {
373
- throw new Error(
374
- `Payment amount ${selectedRequirements.maxAmountRequired} exceeds maximum allowed ${maxPaymentAmount}`
375
- );
376
- }
236
+ function onChainChanged(callback) {
237
+ if (typeof window === "undefined" || !window.ethereum) {
238
+ return () => {
239
+ };
377
240
  }
378
- const effectiveRpcUrl = rpcUrl || getDefaultSolanaRpcUrl(network);
379
- const paymentHeader = await createSvmPaymentHeader({
380
- wallet,
381
- paymentRequirements: selectedRequirements,
382
- x402Version,
383
- rpcUrl: effectiveRpcUrl
384
- });
385
- const newInit = {
386
- ...requestInit,
387
- method: requestInit?.method || "POST",
388
- headers: {
389
- ...requestInit?.headers || {},
390
- "X-PAYMENT": paymentHeader,
391
- "Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE"
392
- }
393
- };
394
- return await fetch(endpoint, newInit);
395
- }
396
-
397
- // src/services/evm/payment-header.ts
398
- var import_ethers = require("ethers");
399
- async function createEvmPaymentHeader(params) {
400
- const { wallet, paymentRequirements, x402Version, chainId } = params;
401
- if (!paymentRequirements?.payTo) {
402
- throw new Error("Missing payTo in payment requirements");
403
- }
404
- if (!paymentRequirements?.asset) {
405
- throw new Error("Missing asset (token contract) in payment requirements");
406
- }
407
- const now = Math.floor(Date.now() / 1e3);
408
- const nonceBytes = import_ethers.ethers.randomBytes(32);
409
- const nonceBytes32 = import_ethers.ethers.hexlify(nonceBytes);
410
- const domain = {
411
- name: paymentRequirements.extra?.name || "USDC",
412
- version: paymentRequirements.extra?.version || "2",
413
- chainId,
414
- verifyingContract: paymentRequirements.asset
415
- };
416
- const types = {
417
- TransferWithAuthorization: [
418
- { name: "from", type: "address" },
419
- { name: "to", type: "address" },
420
- { name: "value", type: "uint256" },
421
- { name: "validAfter", type: "uint256" },
422
- { name: "validBefore", type: "uint256" },
423
- { name: "nonce", type: "bytes32" }
424
- ]
425
- };
426
- const authorization = {
427
- from: wallet.address,
428
- to: paymentRequirements.payTo,
429
- value: paymentRequirements.maxAmountRequired,
430
- validAfter: "0",
431
- // Effective immediately
432
- validBefore: String(now + (paymentRequirements.maxTimeoutSeconds || 3600)),
433
- nonce: nonceBytes32
434
- };
435
- const signature = await wallet.signTypedData(domain, types, authorization);
436
- const headerPayload = {
437
- x402_version: x402Version,
438
- x402Version,
439
- scheme: paymentRequirements.scheme,
440
- network: paymentRequirements.network,
441
- payload: {
442
- signature,
443
- authorization: {
444
- from: authorization.from,
445
- to: authorization.to,
446
- value: String(authorization.value),
447
- valid_after: authorization.validAfter,
448
- validAfter: authorization.validAfter,
449
- valid_before: authorization.validBefore,
450
- validBefore: authorization.validBefore,
451
- nonce: authorization.nonce
452
- }
453
- }
241
+ const ethereum = window.ethereum;
242
+ const handler = (chainId) => {
243
+ console.log("\u{1F504} Chain changed to:", chainId);
244
+ callback(chainId);
454
245
  };
455
- const paymentHeader = btoa(JSON.stringify(headerPayload));
456
- return paymentHeader;
457
- }
458
- function getChainIdFromNetwork(network) {
459
- const chainIdMap = {
460
- "ethereum": 1,
461
- "sepolia": 11155111,
462
- "base": 8453,
463
- "base-sepolia": 84532,
464
- "polygon": 137,
465
- "arbitrum": 42161,
466
- "optimism": 10
246
+ ethereum.on("chainChanged", handler);
247
+ return () => {
248
+ ethereum.removeListener?.("chainChanged", handler);
467
249
  };
468
- const chainId = chainIdMap[network.toLowerCase()];
469
- if (!chainId) {
470
- throw new Error(`Unknown network: ${network}`);
471
- }
472
- return chainId;
473
250
  }
474
-
475
- // src/services/evm/payment-handler.ts
476
- async function handleEvmPayment(endpoint, config, requestInit) {
477
- const { wallet, network, maxPaymentAmount } = config;
478
- const initialResponse = await fetch(endpoint, {
479
- ...requestInit,
480
- method: requestInit?.method || "POST"
481
- });
482
- if (initialResponse.status !== 402) {
483
- return initialResponse;
484
- }
485
- const rawResponse = await initialResponse.json();
486
- const x402Version = rawResponse.x402Version;
487
- const parsedPaymentRequirements = rawResponse.accepts || [];
488
- const selectedRequirements = parsedPaymentRequirements.find(
489
- (req) => req.scheme === "exact" && EvmNetworkSchema.safeParse(req.network.toLowerCase()).success
490
- );
491
- if (!selectedRequirements) {
492
- console.error(
493
- "\u274C No suitable EVM payment requirements found. Available networks:",
494
- parsedPaymentRequirements.map((req) => req.network)
495
- );
496
- throw new Error("No suitable EVM payment requirements found");
497
- }
498
- if (maxPaymentAmount && maxPaymentAmount > BigInt(0)) {
499
- if (BigInt(selectedRequirements.maxAmountRequired) > maxPaymentAmount) {
500
- throw new Error(
501
- `Payment amount ${selectedRequirements.maxAmountRequired} exceeds maximum allowed ${maxPaymentAmount}`
502
- );
503
- }
251
+ function onWalletDisconnect(callback) {
252
+ if (typeof window === "undefined") {
253
+ return () => {
254
+ };
504
255
  }
505
- const targetChainId = getChainIdFromNetwork(selectedRequirements.network);
506
- if (wallet.switchChain) {
507
- try {
508
- await wallet.switchChain(`0x${targetChainId.toString(16)}`);
509
- } catch (error) {
510
- console.warn("Failed to switch chain:", error);
511
- }
256
+ const solana = window.solana;
257
+ if (!solana) {
258
+ return () => {
259
+ };
512
260
  }
513
- const paymentHeader = await createEvmPaymentHeader({
514
- wallet,
515
- paymentRequirements: selectedRequirements,
516
- x402Version,
517
- chainId: targetChainId
518
- });
519
- const newInit = {
520
- ...requestInit,
521
- method: requestInit?.method || "POST",
522
- headers: {
523
- ...requestInit?.headers || {},
524
- "X-PAYMENT": paymentHeader,
525
- "Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE"
526
- }
261
+ const handler = () => {
262
+ console.log("\u{1F50C} Solana wallet disconnected");
263
+ callback();
264
+ };
265
+ solana.on("disconnect", handler);
266
+ return () => {
267
+ solana.removeListener?.("disconnect", handler);
527
268
  };
528
- return await fetch(endpoint, newInit);
529
269
  }
530
270
 
271
+ // src/services/svm/payment-header.ts
272
+ var import_web3 = require("@solana/web3.js");
273
+ var import_spl_token = require("@solana/spl-token");
274
+
275
+ // src/services/evm/payment-header.ts
276
+ var import_ethers = require("ethers");
277
+
531
278
  // src/utils/payment-helpers.ts
532
279
  var import_ethers2 = require("ethers");
533
280
  function parsePaymentRequired(response) {
@@ -553,62 +300,6 @@ function getSupportedNetworkTypes(paymentRequirements) {
553
300
  });
554
301
  return Array.from(networkTypes);
555
302
  }
556
- async function makePayment(networkType, merchantId, endpoint = PROD_BACK_URL) {
557
- endpoint = `${endpoint}/${merchantId}`;
558
- let response;
559
- if (networkType === "solana" /* SOLANA */ || networkType === "svm" /* SVM */) {
560
- const solana = window.solana;
561
- if (!solana) {
562
- throw new Error("\u8BF7\u5B89\u88C5 Phantom \u94B1\u5305");
563
- }
564
- if (!solana.isConnected) {
565
- await solana.connect();
566
- }
567
- response = await handleSvmPayment(endpoint, {
568
- wallet: solana,
569
- network: "solana-devnet"
570
- });
571
- } else if (networkType === "evm" /* EVM */) {
572
- if (!window.ethereum) {
573
- throw new Error("\u8BF7\u5B89\u88C5 MetaMask \u94B1\u5305");
574
- }
575
- const provider = new import_ethers2.ethers.BrowserProvider(window.ethereum);
576
- const signer = await provider.getSigner();
577
- const wallet = {
578
- address: await signer.getAddress(),
579
- signTypedData: async (domain, types, message) => {
580
- return await signer.signTypedData(domain, types, message);
581
- }
582
- };
583
- const network = endpoint.includes("sepolia") ? "base-sepolia" : "base";
584
- response = await handleEvmPayment(endpoint, {
585
- wallet,
586
- network
587
- });
588
- } else {
589
- throw new Error(`\u4E0D\u652F\u6301\u7684\u7F51\u7EDC\u7C7B\u578B: ${networkType}`);
590
- }
591
- return response;
592
- }
593
- async function handlePayment(endpoint, networkType, callbacks) {
594
- try {
595
- callbacks?.onStart?.();
596
- const response = await makePayment(networkType, "", endpoint);
597
- if (!response.ok) {
598
- const errorText = await response.text();
599
- throw new Error(`\u8BF7\u6C42\u5931\u8D25 (${response.status}): ${errorText}`);
600
- }
601
- const result = await response.json();
602
- callbacks?.onSuccess?.(result);
603
- return result;
604
- } catch (err) {
605
- const errorMessage = err.message || "\u652F\u4ED8\u5931\u8D25";
606
- callbacks?.onError?.(errorMessage);
607
- throw err;
608
- } finally {
609
- callbacks?.onFinish?.();
610
- }
611
- }
612
303
 
613
304
  // src/utils/network.ts
614
305
  var NETWORK_TYPE_MAP = {
@@ -632,6 +323,7 @@ var NETWORK_TYPE_MAP = {
632
323
  };
633
324
  function getNetworkDisplayName(network) {
634
325
  const displayNames = {
326
+ "evm": "EVM",
635
327
  "ethereum": "Ethereum",
636
328
  "sepolia": "Sepolia Testnet",
637
329
  "base": "Base",
@@ -677,6 +369,29 @@ var WalletStore = class {
677
369
  }
678
370
  }
679
371
  });
372
+ onChainChanged(() => {
373
+ const connectedType = getConnectedNetworkType();
374
+ if (connectedType === "evm" /* EVM */) {
375
+ console.log("\u26A0\uFE0F Network changed detected - disconnecting wallet");
376
+ disconnectWallet();
377
+ this.setState({
378
+ address: null,
379
+ networkType: null,
380
+ error: "Network changed. Please reconnect your wallet."
381
+ });
382
+ }
383
+ });
384
+ onWalletDisconnect(() => {
385
+ const connectedType = getConnectedNetworkType();
386
+ if (connectedType === "solana" /* SOLANA */ || connectedType === "svm" /* SVM */) {
387
+ console.log("\u26A0\uFE0F Solana wallet disconnected");
388
+ disconnectWallet();
389
+ this.setState({
390
+ address: null,
391
+ networkType: null
392
+ });
393
+ }
394
+ });
680
395
  }
681
396
  async autoReconnect() {
682
397
  if (!isWalletManuallyDisconnected()) {
@@ -801,7 +516,7 @@ function usePayment() {
801
516
 
802
517
  // src/react/hooks/usePaymentInfo.ts
803
518
  var import_react3 = require("react");
804
- function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL) {
519
+ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL, additionalParams) {
805
520
  const [paymentInfo, setPaymentInfo] = (0, import_react3.useState)(null);
806
521
  const [supportedNetworks, setSupportedNetworks] = (0, import_react3.useState)([]);
807
522
  const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
@@ -810,8 +525,17 @@ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL) {
810
525
  setIsLoading(true);
811
526
  setError(null);
812
527
  try {
813
- endpoint = `${endpoint}/${merchantId}`;
814
- const response = await fetch(endpoint, { method: "POST" });
528
+ const fullEndpoint = `${endpoint}/${merchantId}`;
529
+ const requestInit = {
530
+ method: "POST",
531
+ ...additionalParams && Object.keys(additionalParams).length > 0 ? {
532
+ body: JSON.stringify(additionalParams),
533
+ headers: {
534
+ "Content-Type": "application/json"
535
+ }
536
+ } : {}
537
+ };
538
+ const response = await fetch(fullEndpoint, requestInit);
815
539
  if (response.status === 402) {
816
540
  const body = await response.json();
817
541
  const payment = parsePaymentRequired(body);
@@ -832,7 +556,7 @@ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL) {
832
556
  };
833
557
  (0, import_react3.useEffect)(() => {
834
558
  fetchPaymentInfo();
835
- }, [endpoint]);
559
+ }, [endpoint, merchantId]);
836
560
  return {
837
561
  paymentInfo,
838
562
  supportedNetworks,
@@ -844,6 +568,187 @@ function usePaymentInfo(merchantId, endpoint = PROD_BACK_URL) {
844
568
 
845
569
  // src/react/components/WalletConnect.tsx
846
570
  var import_react4 = __toESM(require("react"));
571
+
572
+ // src/react/styles/inline-styles.ts
573
+ var isDarkMode = () => {
574
+ if (typeof window === "undefined") return false;
575
+ return window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false;
576
+ };
577
+ var colors = {
578
+ // Light mode
579
+ light: {
580
+ background: "#fafafa",
581
+ cardBg: "#ffffff",
582
+ text: "#0a0a0a",
583
+ textSecondary: "#737373",
584
+ primary: "#000000",
585
+ primaryHover: "#262626",
586
+ danger: "#ef4444",
587
+ dangerHover: "#dc2626",
588
+ success: "#10b981",
589
+ successHover: "#059669",
590
+ disabled: "#e5e5e5",
591
+ disabledText: "#a3a3a3",
592
+ errorBg: "#fef2f2",
593
+ errorText: "#dc2626"
594
+ },
595
+ // Dark mode
596
+ dark: {
597
+ background: "#0a0a0a",
598
+ cardBg: "#171717",
599
+ text: "#fafafa",
600
+ textSecondary: "#a3a3a3",
601
+ primary: "#ffffff",
602
+ primaryHover: "#e5e5e5",
603
+ danger: "#f87171",
604
+ dangerHover: "#ef4444",
605
+ success: "#34d399",
606
+ successHover: "#10b981",
607
+ disabled: "#262626",
608
+ disabledText: "#525252",
609
+ errorBg: "#1c1917",
610
+ errorText: "#f87171"
611
+ }
612
+ };
613
+ var getColors = () => {
614
+ return isDarkMode() ? colors.dark : colors.light;
615
+ };
616
+ var containerStyle = {
617
+ width: "100%",
618
+ maxWidth: "420px",
619
+ margin: "0 auto"
620
+ };
621
+ var getSectionStyle = () => {
622
+ const c = getColors();
623
+ return {
624
+ padding: "1.5rem",
625
+ background: c.cardBg,
626
+ borderRadius: "12px"
627
+ };
628
+ };
629
+ var getTitleStyle = () => {
630
+ const c = getColors();
631
+ return {
632
+ margin: "0 0 1.25rem 0",
633
+ fontSize: "1.125rem",
634
+ fontWeight: 600,
635
+ color: c.text,
636
+ letterSpacing: "-0.01em"
637
+ };
638
+ };
639
+ var buttonsContainerStyle = {
640
+ display: "flex",
641
+ flexDirection: "column",
642
+ gap: "0.75rem"
643
+ };
644
+ var walletOptionStyle = {
645
+ display: "flex",
646
+ flexDirection: "column",
647
+ gap: "0.5rem"
648
+ };
649
+ var baseButtonStyle = {
650
+ padding: "0.875rem 1.25rem",
651
+ fontSize: "0.9375rem",
652
+ fontWeight: 500,
653
+ border: "none",
654
+ borderRadius: "8px",
655
+ cursor: "pointer",
656
+ transition: "background-color 0.15s ease, opacity 0.15s ease",
657
+ outline: "none",
658
+ letterSpacing: "-0.01em"
659
+ };
660
+ var getConnectButtonStyle = (isDisabled, isHovered) => {
661
+ const c = getColors();
662
+ const darkMode = isDarkMode();
663
+ if (isDisabled) {
664
+ return {
665
+ ...baseButtonStyle,
666
+ background: c.disabled,
667
+ color: c.disabledText,
668
+ cursor: "not-allowed",
669
+ border: darkMode ? "1px solid #404040" : "1px solid #d4d4d4"
670
+ };
671
+ }
672
+ return {
673
+ ...baseButtonStyle,
674
+ background: isHovered ? c.primaryHover : c.primary,
675
+ color: darkMode ? "#000000" : "#ffffff",
676
+ cursor: "pointer"
677
+ };
678
+ };
679
+ var getDisconnectButtonStyle = (isHovered) => {
680
+ const c = getColors();
681
+ return {
682
+ ...baseButtonStyle,
683
+ background: isHovered ? c.dangerHover : c.danger,
684
+ color: "#ffffff"
685
+ };
686
+ };
687
+ var getInstallLinkStyle = (isHovered) => {
688
+ const c = getColors();
689
+ return {
690
+ display: "inline-block",
691
+ padding: "0.5rem",
692
+ fontSize: "0.8125rem",
693
+ color: c.textSecondary,
694
+ textDecoration: isHovered ? "underline" : "none",
695
+ textAlign: "center",
696
+ fontWeight: 500
697
+ };
698
+ };
699
+ var walletAddressStyle = {
700
+ display: "flex",
701
+ flexDirection: "column",
702
+ gap: "0.5rem",
703
+ marginBottom: "1rem"
704
+ };
705
+ var getLabelStyle = () => {
706
+ const c = getColors();
707
+ return {
708
+ fontSize: "0.8125rem",
709
+ color: c.textSecondary,
710
+ fontWeight: 500,
711
+ textTransform: "uppercase",
712
+ letterSpacing: "0.05em"
713
+ };
714
+ };
715
+ var getAddressStyle = () => {
716
+ const c = getColors();
717
+ return {
718
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
719
+ fontSize: "0.9375rem",
720
+ fontWeight: 500,
721
+ color: c.text,
722
+ letterSpacing: "-0.01em"
723
+ };
724
+ };
725
+ var walletActionsStyle = {
726
+ margin: "1rem 0"
727
+ };
728
+ var getHintStyle = () => {
729
+ const c = getColors();
730
+ return {
731
+ marginTop: "1rem",
732
+ fontSize: "0.8125rem",
733
+ color: c.textSecondary,
734
+ textAlign: "center",
735
+ lineHeight: "1.5"
736
+ };
737
+ };
738
+ var getErrorStyle = () => {
739
+ const c = getColors();
740
+ return {
741
+ marginTop: "1rem",
742
+ padding: "0.75rem 1rem",
743
+ background: c.errorBg,
744
+ color: c.errorText,
745
+ borderRadius: "8px",
746
+ fontSize: "0.8125rem",
747
+ fontWeight: 500
748
+ };
749
+ };
750
+
751
+ // src/react/components/WalletConnect.tsx
847
752
  function WalletConnect({
848
753
  supportedNetworks = ["solana" /* SOLANA */, "evm" /* EVM */],
849
754
  className = "",
@@ -851,6 +756,8 @@ function WalletConnect({
851
756
  onDisconnect
852
757
  }) {
853
758
  const { address, networkType, isConnecting, error, connect, disconnect } = useWallet();
759
+ const [hoveredButton, setHoveredButton] = (0, import_react4.useState)(null);
760
+ const [hoveredLink, setHoveredLink] = (0, import_react4.useState)(null);
854
761
  const handleConnect = async (network) => {
855
762
  try {
856
763
  await connect(network);
@@ -861,14 +768,16 @@ function WalletConnect({
861
768
  disconnect();
862
769
  onDisconnect?.();
863
770
  };
864
- return /* @__PURE__ */ import_react4.default.createElement("div", { className: `x402-wallet-connect ${className}` }, !address ? /* @__PURE__ */ import_react4.default.createElement("div", { className: "x402-wallet-section" }, /* @__PURE__ */ import_react4.default.createElement("h3", { className: "x402-section-title" }, "Choose Your Wallet"), supportedNetworks.length === 0 ? /* @__PURE__ */ import_react4.default.createElement("p", { className: "x402-hint" }, "No payment required") : /* @__PURE__ */ import_react4.default.createElement("div", { className: "x402-wallet-buttons" }, supportedNetworks.map((network) => {
771
+ return /* @__PURE__ */ import_react4.default.createElement("div", { style: { ...containerStyle, ...className ? {} : {} }, className }, !address ? /* @__PURE__ */ import_react4.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react4.default.createElement("h3", { style: getTitleStyle() }, "Connect Wallet"), supportedNetworks.length === 0 ? /* @__PURE__ */ import_react4.default.createElement("p", { style: getHintStyle() }, "Please install a supported wallet extension") : /* @__PURE__ */ import_react4.default.createElement("div", { style: buttonsContainerStyle }, supportedNetworks.map((network) => {
865
772
  const installed = isWalletInstalled(network);
866
- return /* @__PURE__ */ import_react4.default.createElement("div", { key: network, className: "x402-wallet-option" }, /* @__PURE__ */ import_react4.default.createElement(
773
+ return /* @__PURE__ */ import_react4.default.createElement("div", { key: network, style: walletOptionStyle }, /* @__PURE__ */ import_react4.default.createElement(
867
774
  "button",
868
775
  {
869
- className: "x402-connect-button",
776
+ style: getConnectButtonStyle(isConnecting || !installed, hoveredButton === network),
870
777
  onClick: () => handleConnect(network),
871
- disabled: isConnecting || !installed
778
+ disabled: isConnecting || !installed,
779
+ onMouseEnter: () => setHoveredButton(network),
780
+ onMouseLeave: () => setHoveredButton(null)
872
781
  },
873
782
  isConnecting ? "Connecting..." : getNetworkDisplayName(network)
874
783
  ), !installed && /* @__PURE__ */ import_react4.default.createElement(
@@ -877,63 +786,25 @@ function WalletConnect({
877
786
  href: getWalletInstallUrl(network),
878
787
  target: "_blank",
879
788
  rel: "noopener noreferrer",
880
- className: "x402-install-link"
789
+ style: getInstallLinkStyle(hoveredLink === network),
790
+ onMouseEnter: () => setHoveredLink(network),
791
+ onMouseLeave: () => setHoveredLink(null)
881
792
  },
882
793
  "Install Wallet"
883
794
  ));
884
- })), error && /* @__PURE__ */ import_react4.default.createElement("p", { className: "x402-error" }, error), /* @__PURE__ */ import_react4.default.createElement("p", { className: "x402-hint" }, "To switch accounts, please change it in your wallet extension")) : /* @__PURE__ */ import_react4.default.createElement("div", { className: "x402-wallet-info" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "x402-wallet-address" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "x402-wallet-label" }, "Connected ", networkType && `(${getNetworkDisplayName(networkType)})`, ":"), /* @__PURE__ */ import_react4.default.createElement("span", { className: "x402-address" }, formatAddress(address))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "x402-wallet-actions" }, /* @__PURE__ */ import_react4.default.createElement("button", { className: "x402-disconnect-button", onClick: handleDisconnect }, "Disconnect")), /* @__PURE__ */ import_react4.default.createElement("p", { className: "x402-hint" }, "Switch account in your wallet to change address")));
885
- }
886
-
887
- // src/react/components/PaymentButton.tsx
888
- var import_react5 = __toESM(require("react"));
889
- function PaymentButton({
890
- endpoint,
891
- className = "",
892
- disabled = false,
893
- onSuccess,
894
- onError,
895
- onStart,
896
- onFinish,
897
- children = "Pay Now"
898
- }) {
899
- const { networkType } = useWallet();
900
- const { isProcessing, setIsProcessing, setResult, setError, error } = usePayment();
901
- const handleClick = async () => {
902
- if (!networkType) {
903
- const errorMsg = "Please connect wallet first";
904
- setError(errorMsg);
905
- onError?.(errorMsg);
906
- return;
907
- }
908
- try {
909
- onStart?.();
910
- setIsProcessing(true);
911
- setError(null);
912
- const result = await handlePayment(endpoint, networkType);
913
- setResult(result);
914
- onSuccess?.(result);
915
- } catch (err) {
916
- const errorMsg = err.message || "Payment failed";
917
- setError(errorMsg);
918
- onError?.(errorMsg);
919
- } finally {
920
- setIsProcessing(false);
921
- onFinish?.();
922
- }
923
- };
924
- return /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(
795
+ })), error && /* @__PURE__ */ import_react4.default.createElement("p", { style: getErrorStyle() }, error), /* @__PURE__ */ import_react4.default.createElement("p", { style: getHintStyle() }, "To switch accounts, please change it in your wallet extension")) : /* @__PURE__ */ import_react4.default.createElement("div", { style: getSectionStyle() }, /* @__PURE__ */ import_react4.default.createElement("div", { style: walletAddressStyle }, /* @__PURE__ */ import_react4.default.createElement("span", { style: getLabelStyle() }, "Connected ", networkType && `(${getNetworkDisplayName(networkType)})`), /* @__PURE__ */ import_react4.default.createElement("span", { style: getAddressStyle() }, formatAddress(address))), /* @__PURE__ */ import_react4.default.createElement("div", { style: walletActionsStyle }, /* @__PURE__ */ import_react4.default.createElement(
925
796
  "button",
926
797
  {
927
- className: `x402-pay-button ${className}`,
928
- onClick: handleClick,
929
- disabled: disabled || isProcessing || !networkType
798
+ style: getDisconnectButtonStyle(hoveredButton === "disconnect"),
799
+ onClick: handleDisconnect,
800
+ onMouseEnter: () => setHoveredButton("disconnect"),
801
+ onMouseLeave: () => setHoveredButton(null)
930
802
  },
931
- isProcessing ? "Processing..." : children
932
- ), error && /* @__PURE__ */ import_react5.default.createElement("p", { className: "x402-error" }, error));
803
+ "Disconnect"
804
+ )), /* @__PURE__ */ import_react4.default.createElement("p", { style: getHintStyle() }, "Switch account in your wallet to change address")));
933
805
  }
934
806
  // Annotate the CommonJS export names for ESM import in node:
935
807
  0 && (module.exports = {
936
- PaymentButton,
937
808
  WalletConnect,
938
809
  usePayment,
939
810
  usePaymentInfo,