@solana/connector 0.1.3 → 0.1.5

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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +685 -1071
  3. package/dist/chunk-3STZXVXD.mjs +2185 -0
  4. package/dist/chunk-3STZXVXD.mjs.map +1 -0
  5. package/dist/chunk-I64FD2EH.js +312 -0
  6. package/dist/chunk-I64FD2EH.js.map +1 -0
  7. package/dist/{chunk-TIW3EQPC.js → chunk-JUZVCBAI.js} +127 -104
  8. package/dist/chunk-JUZVCBAI.js.map +1 -0
  9. package/dist/{chunk-7CKCRY25.js → chunk-NQXK7PGX.js} +75 -79
  10. package/dist/chunk-NQXK7PGX.js.map +1 -0
  11. package/dist/{chunk-HPENTIPE.mjs → chunk-QKVL45F6.mjs} +57 -57
  12. package/dist/chunk-QKVL45F6.mjs.map +1 -0
  13. package/dist/chunk-QL3IT3TS.mjs +299 -0
  14. package/dist/chunk-QL3IT3TS.mjs.map +1 -0
  15. package/dist/chunk-ULUYX23Q.js +2213 -0
  16. package/dist/chunk-ULUYX23Q.js.map +1 -0
  17. package/dist/{chunk-TKJSKXSA.mjs → chunk-VMSZJPR5.mjs} +42 -20
  18. package/dist/chunk-VMSZJPR5.mjs.map +1 -0
  19. package/dist/compat.d.mts +4 -2
  20. package/dist/compat.d.ts +4 -2
  21. package/dist/compat.js +3 -3
  22. package/dist/compat.mjs +1 -1
  23. package/dist/headless.d.mts +146 -18
  24. package/dist/headless.d.ts +146 -18
  25. package/dist/headless.js +144 -111
  26. package/dist/headless.mjs +3 -2
  27. package/dist/index.d.mts +6 -5
  28. package/dist/index.d.ts +6 -5
  29. package/dist/index.js +207 -126
  30. package/dist/index.mjs +4 -3
  31. package/dist/react.d.mts +707 -67
  32. package/dist/react.d.ts +707 -67
  33. package/dist/react.js +64 -16
  34. package/dist/react.mjs +2 -2
  35. package/dist/{transaction-signer-D3csM_Mf.d.mts → transaction-signer-D9d8nxwb.d.mts} +3 -1
  36. package/dist/{transaction-signer-D3csM_Mf.d.ts → transaction-signer-D9d8nxwb.d.ts} +3 -1
  37. package/dist/{wallet-standard-shim-Cg0GVGwu.d.mts → wallet-standard-shim--YcrQNRt.d.ts} +216 -6
  38. package/dist/{wallet-standard-shim-C1tisl9S.d.ts → wallet-standard-shim-Dx7H8Ctf.d.mts} +216 -6
  39. package/package.json +16 -12
  40. package/dist/chunk-5ZUVZZWU.mjs +0 -180
  41. package/dist/chunk-5ZUVZZWU.mjs.map +0 -1
  42. package/dist/chunk-7CKCRY25.js.map +0 -1
  43. package/dist/chunk-FTD7F7CS.js +0 -314
  44. package/dist/chunk-FTD7F7CS.js.map +0 -1
  45. package/dist/chunk-HPENTIPE.mjs.map +0 -1
  46. package/dist/chunk-MPZFJEJK.mjs +0 -298
  47. package/dist/chunk-MPZFJEJK.mjs.map +0 -1
  48. package/dist/chunk-SMUUAKC3.js +0 -186
  49. package/dist/chunk-SMUUAKC3.js.map +0 -1
  50. package/dist/chunk-TIW3EQPC.js.map +0 -1
  51. package/dist/chunk-TKJSKXSA.mjs.map +0 -1
@@ -1,9 +1,11 @@
1
- import { c as TransactionActivity, d as TransactionActivityStatus } from './transaction-signer-D3csM_Mf.js';
1
+ import { c as TransactionActivity, d as TransactionActivityStatus } from './transaction-signer-D9d8nxwb.mjs';
2
2
  import { SolanaClusterId, SolanaCluster } from '@wallet-ui/core';
3
3
  import { Wallet, WalletAccount } from '@wallet-standard/base';
4
- import { Address, Signature } from 'gill';
4
+ import { Address } from '@solana/addresses';
5
5
  import React, { ReactNode, Component, ErrorInfo } from 'react';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
+ import { Signature } from '@solana/keys';
8
+ import { DevnetUrl, MainnetUrl, TestnetUrl, Rpc, SolanaRpcApi, RpcSubscriptions, SolanaRpcSubscriptionsApi } from '@solana/kit';
7
9
 
8
10
  /**
9
11
  * Wallet-related types
@@ -21,7 +23,7 @@ type WalletName = string & {
21
23
  * Account address as a branded string for type safety
22
24
  * Represents a Solana address (base58-encoded public key)
23
25
  *
24
- * @deprecated Use `Address` from 'gill' instead for consistent address typing
26
+ * @deprecated Use `Address` from '@solana/addresses' instead for consistent address typing
25
27
  */
26
28
  type AccountAddress = string & {
27
29
  readonly __brand: 'AccountAddress';
@@ -33,7 +35,7 @@ declare function isWalletName(value: string): value is WalletName;
33
35
  /**
34
36
  * Type guard to check if a string is a valid account address
35
37
  *
36
- * @deprecated Use `isAddress` from 'gill' instead for proper address validation
38
+ * @deprecated Use `isAddress` from '@solana/addresses' instead for proper address validation
37
39
  */
38
40
  declare function isAccountAddress(value: string): value is AccountAddress;
39
41
  /**
@@ -114,6 +116,48 @@ interface AccountInfo {
114
116
  raw: WalletAccount;
115
117
  }
116
118
 
119
+ /**
120
+ * CoinGecko API configuration for price fetching.
121
+ *
122
+ * Rate Limits (as of 2024):
123
+ * - Free tier (no API key): 10-30 requests/minute (varies by endpoint)
124
+ * - Demo tier (free API key): 30 requests/minute
125
+ * - Paid tiers: Higher limits based on plan
126
+ *
127
+ * @see https://docs.coingecko.com/reference/introduction
128
+ */
129
+ interface CoinGeckoConfig {
130
+ /**
131
+ * CoinGecko API key for higher rate limits.
132
+ * Get a free Demo API key at https://www.coingecko.com/en/api/pricing
133
+ * - Without key: ~10-30 requests/minute (public rate limit)
134
+ * - With Demo key: 30 requests/minute
135
+ */
136
+ apiKey?: string;
137
+ /**
138
+ * Whether the API key is for the Pro API (api.coingecko.com with x-cg-pro-api-key header)
139
+ * or the Demo API (api.coingecko.com with x-cg-demo-api-key header).
140
+ * @default false (uses Demo API header)
141
+ */
142
+ isPro?: boolean;
143
+ /**
144
+ * Maximum number of retry attempts when rate limited (429 response).
145
+ * @default 3
146
+ */
147
+ maxRetries?: number;
148
+ /**
149
+ * Base delay in milliseconds for exponential backoff.
150
+ * Actual delay = baseDelay * 2^attempt + random jitter
151
+ * @default 1000 (1 second)
152
+ */
153
+ baseDelay?: number;
154
+ /**
155
+ * Maximum total timeout in milliseconds for all retry attempts combined.
156
+ * Prevents blocking the caller for too long.
157
+ * @default 30000 (30 seconds)
158
+ */
159
+ maxTimeout?: number;
160
+ }
117
161
  /**
118
162
  * Core connector state
119
163
  */
@@ -149,6 +193,19 @@ interface ConnectorConfig {
149
193
  persistSelection?: boolean;
150
194
  initialCluster?: SolanaClusterId;
151
195
  };
196
+ /**
197
+ * Image proxy URL prefix for token images.
198
+ * When set, token image URLs will be transformed to: `${imageProxy}${encodeURIComponent(originalUrl)}`
199
+ * This prevents direct image fetching which can leak user IPs to untrusted hosts.
200
+ * @example '/_next/image?w=64&q=75&url=' // Next.js Image Optimization
201
+ * @example '/cdn-cgi/image/width=64,quality=75/' // Cloudflare Image Resizing
202
+ */
203
+ imageProxy?: string;
204
+ /**
205
+ * CoinGecko API configuration for token price fetching.
206
+ * Configure API key for higher rate limits and retry behavior for 429 responses.
207
+ */
208
+ coingecko?: CoinGeckoConfig;
152
209
  }
153
210
  /**
154
211
  * Health check information for connector diagnostics
@@ -322,6 +379,10 @@ declare class ConnectorClient {
322
379
  getHealth(): ConnectorHealth;
323
380
  getDebugMetrics(): ConnectorDebugMetrics;
324
381
  getDebugState(): ConnectorDebugState;
382
+ /**
383
+ * Get the current connector configuration
384
+ */
385
+ getConfig(): ConnectorConfig;
325
386
  resetDebugMetrics(): void;
326
387
  destroy(): void;
327
388
  }
@@ -355,6 +416,20 @@ interface DefaultConfigOptions {
355
416
  maxRetries?: number;
356
417
  /** Custom error handler */
357
418
  onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
419
+ /**
420
+ * Image proxy URL prefix for token images.
421
+ * When set, token image URLs will be transformed to: `${imageProxy}${encodeURIComponent(originalUrl)}`
422
+ * This prevents direct image fetching which can leak user IPs to untrusted hosts.
423
+ * @example '/_next/image?w=64&q=75&url=' // Next.js Image Optimization
424
+ * @example '/cdn-cgi/image/width=64,quality=75/' // Cloudflare Image Resizing
425
+ */
426
+ imageProxy?: string;
427
+ /**
428
+ * CoinGecko API configuration for token price fetching.
429
+ * Configure API key for higher rate limits and retry behavior for 429 responses.
430
+ * @see https://docs.coingecko.com/reference/introduction for rate limit details
431
+ */
432
+ coingecko?: CoinGeckoConfig;
358
433
  }
359
434
  /** Extended ConnectorConfig with app metadata */
360
435
  interface ExtendedConnectorConfig extends ConnectorConfig {
@@ -377,6 +452,16 @@ interface ExtendedConnectorConfig extends ConnectorConfig {
377
452
  /** Custom fallback component */
378
453
  fallback?: (error: Error, retry: () => void) => React.ReactNode;
379
454
  };
455
+ /**
456
+ * Image proxy URL prefix for token images.
457
+ * When set, token image URLs will be transformed to: `${imageProxy}${encodeURIComponent(originalUrl)}`
458
+ * This prevents direct image fetching which can leak user IPs to untrusted hosts.
459
+ */
460
+ imageProxy?: string;
461
+ /**
462
+ * CoinGecko API configuration for token price fetching.
463
+ */
464
+ coingecko?: CoinGeckoConfig;
380
465
  }
381
466
  /**
382
467
  * Creates a default connector configuration with sensible defaults for Solana applications
@@ -395,7 +480,7 @@ declare function getDefaultMobileConfig(options: {
395
480
  uri: string;
396
481
  icon: string;
397
482
  };
398
- cluster: "mainnet" | "devnet" | "testnet" | "mainnet-beta";
483
+ cluster: "devnet" | "mainnet" | "testnet" | "mainnet-beta";
399
484
  };
400
485
 
401
486
  declare global {
@@ -912,6 +997,131 @@ declare function copyAddressToClipboard(address: string, options?: Omit<CopyOpti
912
997
  */
913
998
  declare function copySignatureToClipboard(signature: string, options?: Omit<CopyOptions, 'validateType'>): Promise<ClipboardResult>;
914
999
 
1000
+ /**
1001
+ * @solana/connector - Kit RPC Utilities
1002
+ *
1003
+ * RPC URL helpers for Solana clusters.
1004
+ */
1005
+
1006
+ /** Solana cluster moniker */
1007
+ type SolanaClusterMoniker = 'devnet' | 'localnet' | 'mainnet' | 'testnet';
1008
+ /** Localnet URL type */
1009
+ type LocalnetUrl = string & {
1010
+ '~cluster': 'localnet';
1011
+ };
1012
+ /** Generic URL type */
1013
+ type GenericUrl = string & {};
1014
+ /** Union of all cluster URL types */
1015
+ type ModifiedClusterUrl = DevnetUrl | GenericUrl | LocalnetUrl | MainnetUrl | TestnetUrl;
1016
+ /** URL or moniker that can be used to create a Solana client */
1017
+ type SolanaClientUrlOrMoniker = ModifiedClusterUrl | SolanaClusterMoniker | URL;
1018
+ /**
1019
+ * Get a public Solana RPC endpoint for a cluster based on its moniker
1020
+ *
1021
+ * Note: These RPC URLs are rate limited and not suitable for production applications.
1022
+ * For production, use a dedicated RPC provider like Triton, Helius, QuickNode, or Alchemy.
1023
+ *
1024
+ * @param cluster - Cluster moniker
1025
+ * @returns Public RPC URL for the cluster
1026
+ */
1027
+ declare function getPublicSolanaRpcUrl(cluster: SolanaClusterMoniker | 'mainnet-beta' | 'localhost'): ModifiedClusterUrl;
1028
+
1029
+ /**
1030
+ * @solana/connector - Kit Client Factory
1031
+ *
1032
+ * Creates a Solana RPC and WebSocket subscriptions client.
1033
+ * Replaces gill's createSolanaClient with a kit-based implementation.
1034
+ */
1035
+
1036
+ /**
1037
+ * Configuration for creating a Solana RPC client
1038
+ */
1039
+ interface CreateSolanaClientRpcConfig {
1040
+ /** Custom port for the RPC endpoint */
1041
+ port?: number;
1042
+ }
1043
+ /**
1044
+ * Configuration for creating a Solana RPC subscriptions client
1045
+ */
1046
+ interface CreateSolanaClientRpcSubscriptionsConfig {
1047
+ /** Custom port for the WebSocket endpoint */
1048
+ port?: number;
1049
+ }
1050
+ /**
1051
+ * Arguments for creating a Solana client
1052
+ */
1053
+ interface CreateSolanaClientArgs<TClusterUrl extends SolanaClientUrlOrMoniker = string> {
1054
+ /** Full RPC URL (for a private RPC endpoint) or the Solana moniker (for a public RPC endpoint) */
1055
+ urlOrMoniker: SolanaClientUrlOrMoniker | TClusterUrl;
1056
+ /** Configuration used to create the `rpc` client */
1057
+ rpcConfig?: CreateSolanaClientRpcConfig;
1058
+ /** Configuration used to create the `rpcSubscriptions` client */
1059
+ rpcSubscriptionsConfig?: CreateSolanaClientRpcSubscriptionsConfig;
1060
+ }
1061
+ /**
1062
+ * A Solana client with RPC and WebSocket subscription capabilities
1063
+ */
1064
+ interface SolanaClient<TClusterUrl extends ModifiedClusterUrl | string = string> {
1065
+ /** Used to make RPC calls to your RPC provider */
1066
+ rpc: Rpc<SolanaRpcApi>;
1067
+ /** Used to make RPC websocket calls to your RPC provider */
1068
+ rpcSubscriptions: RpcSubscriptions<SolanaRpcSubscriptionsApi>;
1069
+ /** Full RPC URL that was used to create this client */
1070
+ urlOrMoniker: SolanaClientUrlOrMoniker | TClusterUrl;
1071
+ }
1072
+ /**
1073
+ * Create a Solana `rpc` and `rpcSubscriptions` client
1074
+ *
1075
+ * @param props - Configuration for the client
1076
+ * @returns Solana client with RPC and WebSocket subscription capabilities
1077
+ *
1078
+ * @example
1079
+ * ```ts
1080
+ * // Using a cluster moniker
1081
+ * const client = createSolanaClient({ urlOrMoniker: 'devnet' });
1082
+ *
1083
+ * // Using a custom RPC URL
1084
+ * const client = createSolanaClient({ urlOrMoniker: 'https://my-rpc.example.com' });
1085
+ *
1086
+ * // Making RPC calls
1087
+ * const balance = await client.rpc.getBalance(address).send();
1088
+ * ```
1089
+ */
1090
+ declare function createSolanaClient(props: Omit<CreateSolanaClientArgs<MainnetUrl | 'mainnet'>, 'urlOrMoniker'> & {
1091
+ urlOrMoniker: 'mainnet';
1092
+ }): SolanaClient<MainnetUrl>;
1093
+ declare function createSolanaClient(props: Omit<CreateSolanaClientArgs<DevnetUrl | 'devnet'>, 'urlOrMoniker'> & {
1094
+ urlOrMoniker: 'devnet';
1095
+ }): SolanaClient<DevnetUrl>;
1096
+ declare function createSolanaClient(props: Omit<CreateSolanaClientArgs<TestnetUrl | 'testnet'>, 'urlOrMoniker'> & {
1097
+ urlOrMoniker: 'testnet';
1098
+ }): SolanaClient<TestnetUrl>;
1099
+ declare function createSolanaClient(props: Omit<CreateSolanaClientArgs<LocalnetUrl | 'localnet'>, 'urlOrMoniker'> & {
1100
+ urlOrMoniker: 'localnet';
1101
+ }): SolanaClient<LocalnetUrl>;
1102
+ declare function createSolanaClient<TClusterUrl extends ModifiedClusterUrl>(props: CreateSolanaClientArgs<TClusterUrl>): SolanaClient<TClusterUrl>;
1103
+
1104
+ /**
1105
+ * @solana/connector - Kit Debug Utilities
1106
+ *
1107
+ * Simplified debug logging utilities for the connector.
1108
+ * Replaces gill's debug system with a connector-specific implementation.
1109
+ */
1110
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
1111
+ declare global {
1112
+ /**
1113
+ * Whether or not to enable debug mode. When enabled, default log level of `info`
1114
+ */
1115
+ var __CONNECTOR_DEBUG__: boolean | undefined;
1116
+ /**
1117
+ * Set the a desired level of logs to be output in the application
1118
+ *
1119
+ * - Default: `info`
1120
+ * - Options: `debug` | `info` | `warn` | `error`
1121
+ */
1122
+ var __CONNECTOR_DEBUG_LEVEL__: LogLevel | undefined;
1123
+ }
1124
+
915
1125
  interface WalletsRegistry {
916
1126
  get(): readonly Wallet[];
917
1127
  on(event: 'register' | 'unregister', callback: (wallet: Wallet) => void): () => void;
@@ -923,4 +1133,4 @@ type WalletStandardAccount = WalletAccount;
923
1133
  */
924
1134
  declare function getWalletsRegistry(): WalletsRegistry;
925
1135
 
926
- export { getBlockUrl as $, type AccountInfo as A, type StorageOptions as B, ConnectorProvider as C, type DefaultConfigOptions as D, type ExtendedConnectorConfig as E, type EnhancedStorageAccountOptions as F, type EnhancedStorageClusterOptions as G, type EnhancedStorageWalletOptions as H, WalletErrorType as I, type WalletError as J, ClipboardErrorType as K, type Listener as L, type MobileWalletAdapterConfig as M, type ClipboardResult as N, type CopyOptions as O, isClipboardAvailable as P, copyToClipboard as Q, copyAddressToClipboard as R, type StorageAdapter as S, copySignatureToClipboard as T, type UnifiedConfigOptions as U, getClusterRpcUrl as V, type WalletInfo as W, getClusterExplorerUrl as X, getTransactionUrl as Y, getAddressUrl as Z, getTokenUrl as _, useConnectorClient as a, isMainnetCluster as a0, isDevnetCluster as a1, isTestnetCluster as a2, isLocalCluster as a3, getClusterName as a4, getClusterType as a5, getClusterChainId as a6, getChainIdForWalletStandard as a7, type SolanaNetwork as a8, PUBLIC_RPC_ENDPOINTS as a9, normalizeNetwork as aa, toClusterId as ab, getDefaultRpcUrl as ac, isMainnet as ad, isDevnet as ae, isTestnet as af, isLocalnet as ag, getNetworkDisplayName as ah, ConnectorErrorBoundary as b, type ConnectorSnapshot as c, type ConnectorConfig as d, type ConnectorState as e, type WalletStandardWallet as f, type WalletStandardAccount as g, type UnifiedConfig as h, type ClusterType as i, ConnectorClient as j, getWalletsRegistry as k, getDefaultConfig as l, getDefaultMobileConfig as m, createConfig as n, isUnifiedConfig as o, type WalletName as p, type AccountAddress as q, isWalletName as r, isAccountAddress as s, type ConnectorHealth as t, useConnector as u, type ConnectorDebugMetrics as v, withErrorBoundary as w, type ConnectorDebugState as x, type ConnectorEvent as y, type ConnectorEventListener as z };
1136
+ export { copySignatureToClipboard as $, type AccountInfo as A, type StorageOptions as B, ConnectorProvider as C, type DefaultConfigOptions as D, type ExtendedConnectorConfig as E, type EnhancedStorageAccountOptions as F, type EnhancedStorageClusterOptions as G, type EnhancedStorageWalletOptions as H, WalletErrorType as I, type WalletError as J, getPublicSolanaRpcUrl as K, type Listener as L, type MobileWalletAdapterConfig as M, createSolanaClient as N, type SolanaClusterMoniker as O, type ModifiedClusterUrl as P, type SolanaClient as Q, type CreateSolanaClientArgs as R, type StorageAdapter as S, ClipboardErrorType as T, type UnifiedConfigOptions as U, type ClipboardResult as V, type WalletInfo as W, type CopyOptions as X, isClipboardAvailable as Y, copyToClipboard as Z, copyAddressToClipboard as _, useConnectorClient as a, getClusterRpcUrl as a0, getClusterExplorerUrl as a1, getTransactionUrl as a2, getAddressUrl as a3, getTokenUrl as a4, getBlockUrl as a5, isMainnetCluster as a6, isDevnetCluster as a7, isTestnetCluster as a8, isLocalCluster as a9, getClusterName as aa, getClusterType as ab, getClusterChainId as ac, getChainIdForWalletStandard as ad, type SolanaNetwork as ae, PUBLIC_RPC_ENDPOINTS as af, normalizeNetwork as ag, toClusterId as ah, getDefaultRpcUrl as ai, isMainnet as aj, isDevnet as ak, isTestnet as al, isLocalnet as am, getNetworkDisplayName as an, ConnectorErrorBoundary as b, type ConnectorSnapshot as c, type ConnectorConfig as d, type ConnectorState as e, type WalletStandardWallet as f, type WalletStandardAccount as g, type UnifiedConfig as h, type ClusterType as i, ConnectorClient as j, getWalletsRegistry as k, getDefaultConfig as l, getDefaultMobileConfig as m, createConfig as n, isUnifiedConfig as o, type WalletName as p, type AccountAddress as q, isWalletName as r, isAccountAddress as s, type ConnectorHealth as t, useConnector as u, type ConnectorDebugMetrics as v, withErrorBoundary as w, type ConnectorDebugState as x, type ConnectorEvent as y, type ConnectorEventListener as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/connector",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Headless wallet connector client and React provider built on Wallet Standard",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -65,17 +65,17 @@
65
65
  "@nanostores/persistent": "^1.1.0",
66
66
  "@solana-mobile/wallet-standard-mobile": "^0.4.3",
67
67
  "@solana/webcrypto-ed25519-polyfill": "^4.0.0",
68
- "@solana/addresses": "^3.0.0",
69
- "@solana/keys": "^3.0.0",
70
- "@solana/kit": "^3.0.0",
71
- "@solana/signers": "^3.0.0",
72
- "@solana/transactions": "^3.0.0",
68
+ "@solana/addresses": "^5.0.0",
69
+ "@solana/codecs": "^5.0.0",
70
+ "@solana/keys": "^5.0.0",
71
+ "@solana/kit": "^5.0.0",
72
+ "@solana/signers": "^5.0.0",
73
+ "@solana/transaction-messages": "^5.0.0",
74
+ "@solana/transactions": "^5.0.0",
73
75
  "@wallet-standard/app": "^1.1.0",
74
76
  "@wallet-standard/base": "^1.1.0",
75
77
  "@wallet-standard/features": "^1.1.0",
76
- "@wallet-ui/core": "^2.0.0",
77
- "bs58": "^6.0.0",
78
- "gill": "^0.12.0"
78
+ "@wallet-ui/core": "^2.1.0"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@testing-library/jest-dom": "^6.9.1",
@@ -85,11 +85,15 @@
85
85
  "@vitest/coverage-v8": "^3.2.4",
86
86
  "@vitest/ui": "^3.2.4",
87
87
  "happy-dom": "^20.0.7",
88
- "react": "19.2.0",
89
- "react-dom": "19.2.0",
88
+ "react": "^19.2.1",
89
+ "react-dom": "^19.2.1",
90
90
  "tsup": "^8.5.0",
91
91
  "typescript": "^5.9.3",
92
92
  "vitest": "^3.2.4"
93
93
  },
94
- "license": "MIT"
94
+ "license": "MIT",
95
+ "repository": {
96
+ "type": "git",
97
+ "url": "https://github.com/solana-foundation/connectorkit"
98
+ }
95
99
  }
@@ -1,180 +0,0 @@
1
- import { isDebugEnabled, debug } from 'gill';
2
-
3
- var __defProp = Object.defineProperty;
4
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value);
6
- var SENSITIVE_KEYS = [
7
- "address",
8
- "publickey",
9
- "signature",
10
- "account",
11
- "rpcurl",
12
- "url",
13
- "apikey",
14
- "api_key",
15
- "token",
16
- "secret",
17
- "password",
18
- "private",
19
- "seed",
20
- "mnemonic"
21
- ], LOG_LEVELS = {
22
- debug: 0,
23
- info: 1,
24
- warn: 2,
25
- error: 3
26
- }, SecureLogger = class {
27
- constructor(config = {}) {
28
- __publicField(this, "config");
29
- let isDevelopment = typeof process < "u" && process.env?.NODE_ENV === "development";
30
- this.config = {
31
- enabled: config.enabled ?? isDevelopment,
32
- level: config.level ?? "debug",
33
- redactSensitive: config.redactSensitive ?? !isDevelopment,
34
- prefix: config.prefix ?? "Connector",
35
- useGillDebug: config.useGillDebug ?? true
36
- // Default to using gill's debug system
37
- };
38
- }
39
- /**
40
- * Log debug information (lowest priority)
41
- */
42
- debug(message, data) {
43
- this.log("debug", message, data);
44
- }
45
- /**
46
- * Log general information
47
- */
48
- info(message, data) {
49
- this.log("info", message, data);
50
- }
51
- /**
52
- * Log warnings
53
- */
54
- warn(message, data) {
55
- this.log("warn", message, data);
56
- }
57
- /**
58
- * Log errors (highest priority)
59
- */
60
- error(message, data) {
61
- this.log("error", message, data);
62
- }
63
- /**
64
- * Internal log method that handles level filtering and redaction
65
- * Integrates with gill's debug system when enabled
66
- */
67
- log(level, message, data) {
68
- let gillDebugEnabled = this.config.useGillDebug ? isDebugEnabled() : false;
69
- if (!this.config.enabled && !gillDebugEnabled) return;
70
- let effectiveLevel = this.config.level;
71
- if (this.config.useGillDebug && typeof globalThis < "u") {
72
- let gillLevel = globalThis.__GILL_DEBUG_LEVEL__;
73
- gillLevel && ["debug", "info", "warn", "error"].includes(gillLevel) && (effectiveLevel = gillLevel);
74
- }
75
- if (LOG_LEVELS[level] < LOG_LEVELS[effectiveLevel])
76
- return;
77
- let processedData = this.config.redactSensitive ? this.redact(data) : data, fullMessage = processedData !== void 0 ? `${message} ${typeof processedData == "object" ? JSON.stringify(processedData, null, 2) : processedData}` : message;
78
- if (this.config.useGillDebug && gillDebugEnabled)
79
- debug(fullMessage, level, this.config.prefix);
80
- else {
81
- let prefix = `[${this.config.prefix}]`;
82
- switch (level) {
83
- case "debug":
84
- console.debug(prefix, message, processedData !== void 0 ? processedData : "");
85
- break;
86
- case "info":
87
- console.info(prefix, message, processedData !== void 0 ? processedData : "");
88
- break;
89
- case "warn":
90
- console.warn(prefix, message, processedData !== void 0 ? processedData : "");
91
- break;
92
- case "error":
93
- console.error(prefix, message, processedData !== void 0 ? processedData : "");
94
- break;
95
- }
96
- }
97
- }
98
- /**
99
- * Recursively redact sensitive information from data
100
- */
101
- redact(data) {
102
- if (data == null || typeof data != "object")
103
- return data;
104
- if (Array.isArray(data))
105
- return data.map((item) => this.redact(item));
106
- let redacted = {};
107
- for (let [key, value] of Object.entries(data)) {
108
- let keyLower = key.toLowerCase();
109
- SENSITIVE_KEYS.some((sensitiveKey) => keyLower.includes(sensitiveKey)) ? redacted[key] = this.maskValue(value) : typeof value == "object" && value !== null ? redacted[key] = this.redact(value) : redacted[key] = value;
110
- }
111
- return redacted;
112
- }
113
- /**
114
- * Mask a sensitive value for logging
115
- * Shows first 4 and last 4 characters for strings longer than 8 chars
116
- */
117
- maskValue(value) {
118
- if (value == null)
119
- return "***";
120
- let str = String(value);
121
- return str.length <= 8 ? "***" : `${str.slice(0, 4)}...${str.slice(-4)}`;
122
- }
123
- /**
124
- * Update logger configuration at runtime
125
- */
126
- updateConfig(config) {
127
- this.config = { ...this.config, ...config };
128
- }
129
- /**
130
- * Get current configuration
131
- */
132
- getConfig() {
133
- return { ...this.config };
134
- }
135
- }; new SecureLogger({
136
- prefix: "Connector"
137
- });
138
- function createLogger(prefix, config) {
139
- return new SecureLogger({ ...config, prefix });
140
- }
141
-
142
- // src/utils/transaction-format.ts
143
- function isWeb3jsTransaction(tx) {
144
- return tx !== null && typeof tx == "object" && "serialize" in tx && typeof tx.serialize == "function";
145
- }
146
- function serializeTransaction(tx) {
147
- if (isWeb3jsTransaction(tx))
148
- return tx.serialize({
149
- requireAllSignatures: false,
150
- verifySignatures: false
151
- });
152
- if (tx instanceof Uint8Array)
153
- return tx;
154
- if (ArrayBuffer.isView(tx))
155
- return new Uint8Array(tx.buffer, tx.byteOffset, tx.byteLength);
156
- throw new Error("Unsupported transaction format - must be Transaction, VersionedTransaction, or Uint8Array");
157
- }
158
- function isLegacyTransaction(bytes) {
159
- return bytes.length === 0 ? false : (bytes[0] & 128) === 0;
160
- }
161
- async function deserializeToWeb3jsTransaction(bytes) {
162
- if (isLegacyTransaction(bytes)) {
163
- let { Transaction } = await import('@solana/web3.js');
164
- return Transaction.from(bytes);
165
- } else {
166
- let { VersionedTransaction } = await import('@solana/web3.js');
167
- return VersionedTransaction.deserialize(bytes);
168
- }
169
- }
170
- function prepareTransactionForWallet(tx) {
171
- let wasWeb3js = isWeb3jsTransaction(tx);
172
- return { serialized: serializeTransaction(tx), wasWeb3js };
173
- }
174
- async function convertSignedTransaction(signedBytes, wasWeb3js) {
175
- return wasWeb3js ? await deserializeToWeb3jsTransaction(signedBytes) : signedBytes;
176
- }
177
-
178
- export { __publicField, convertSignedTransaction, createLogger, isWeb3jsTransaction, prepareTransactionForWallet };
179
- //# sourceMappingURL=chunk-5ZUVZZWU.mjs.map
180
- //# sourceMappingURL=chunk-5ZUVZZWU.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/utils/secure-logger.ts","../src/utils/transaction-format.ts"],"names":["gillDebug"],"mappings":"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","file":"chunk-5ZUVZZWU.mjs","sourcesContent":["/**\n * @solana/connector - Secure Logger\n *\n * Production-safe logger that redacts sensitive information\n * Prevents accidental exposure of addresses, keys, and other PII in logs\n *\n * Integrates with gill's debug system:\n * - Respects `__GILL_DEBUG__` flag (enable/disable logging globally)\n * - Respects `__GILL_DEBUG_LEVEL__` (set minimum log level)\n * - Extends gill's debug with sensitive data redaction\n * - Provides unified logging API across connector and gill\n *\n * Enable gill debug:\n * ```ts\n * window.__GILL_DEBUG__ = true\n * window.__GILL_DEBUG_LEVEL__ = 'debug' // or 'info', 'warn', 'error'\n * ```\n */\n\nimport { isDebugEnabled, debug as gillDebug } from 'gill';\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface SecureLoggerConfig {\n /** Enable logging (defaults to true in development, false in production) */\n enabled?: boolean;\n /** Minimum log level to output */\n level?: LogLevel;\n /** Redact sensitive information in logs (defaults to true in production) */\n redactSensitive?: boolean;\n /** Custom prefix for all log messages */\n prefix?: string;\n /** Use gill's debug system for logging (respects __GILL_DEBUG__ flags) */\n useGillDebug?: boolean;\n}\n\n/**\n * Keys that contain sensitive information that should be redacted\n */\nconst SENSITIVE_KEYS = [\n 'address',\n 'publickey',\n 'signature',\n 'account',\n 'rpcurl',\n 'url',\n 'apikey',\n 'api_key',\n 'token',\n 'secret',\n 'password',\n 'private',\n 'seed',\n 'mnemonic',\n];\n\n/**\n * Log levels in order of severity\n */\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * SecureLogger - Production-safe logging with automatic redaction\n *\n * Features:\n * - Integrates with gill's debug system (respects __GILL_DEBUG__ flags)\n * - Automatic redaction of sensitive data (addresses, keys, URLs)\n * - Configurable log levels (respects __GILL_DEBUG_LEVEL__)\n * - Environment-aware defaults\n * - Deep object traversal for nested sensitive data\n *\n * @example\n * ```ts\n * // Enable gill debug (affects all logging across connector + gill)\n * window.__GILL_DEBUG__ = true\n * window.__GILL_DEBUG_LEVEL__ = 'info' // Optional: filter by level\n *\n * const logger = new SecureLogger({ prefix: 'Connector' });\n *\n * logger.debug('User connected', {\n * address: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU', // Auto-redacted in prod\n * wallet: 'Phantom'\n * });\n * // Development: \"User connected { address: '7xKX...gAsU', wallet: 'Phantom' }\"\n * // Production: \"User connected { address: '***', wallet: 'Phantom' }\"\n * ```\n */\nexport class SecureLogger {\n private config: Required<SecureLoggerConfig>;\n\n constructor(config: SecureLoggerConfig = {}) {\n const isDevelopment = typeof process !== 'undefined' && process.env?.NODE_ENV === 'development';\n\n this.config = {\n enabled: config.enabled ?? isDevelopment,\n level: config.level ?? 'debug',\n redactSensitive: config.redactSensitive ?? !isDevelopment,\n prefix: config.prefix ?? 'Connector',\n useGillDebug: config.useGillDebug ?? true, // Default to using gill's debug system\n };\n }\n\n /**\n * Log debug information (lowest priority)\n */\n debug(message: string, data?: unknown): void {\n this.log('debug', message, data);\n }\n\n /**\n * Log general information\n */\n info(message: string, data?: unknown): void {\n this.log('info', message, data);\n }\n\n /**\n * Log warnings\n */\n warn(message: string, data?: unknown): void {\n this.log('warn', message, data);\n }\n\n /**\n * Log errors (highest priority)\n */\n error(message: string, data?: unknown): void {\n this.log('error', message, data);\n }\n\n /**\n * Internal log method that handles level filtering and redaction\n * Integrates with gill's debug system when enabled\n */\n private log(level: LogLevel, message: string, data?: unknown): void {\n // Check if logging is enabled (either via config or gill's debug system)\n const gillDebugEnabled = this.config.useGillDebug ? isDebugEnabled() : false;\n if (!this.config.enabled && !gillDebugEnabled) return;\n\n // Get effective log level (prefer gill's debug level if set)\n let effectiveLevel = this.config.level;\n if (this.config.useGillDebug && typeof globalThis !== 'undefined') {\n const gillLevel = (globalThis as { __GILL_DEBUG_LEVEL__?: string }).__GILL_DEBUG_LEVEL__;\n if (gillLevel && ['debug', 'info', 'warn', 'error'].includes(gillLevel)) {\n effectiveLevel = gillLevel as LogLevel;\n }\n }\n\n // Check if this log level should be output\n if (LOG_LEVELS[level] < LOG_LEVELS[effectiveLevel]) {\n return;\n }\n\n // Process data (redact if enabled)\n const processedData = this.config.redactSensitive ? this.redact(data) : data;\n\n // Format message with data\n const fullMessage =\n processedData !== undefined\n ? `${message} ${typeof processedData === 'object' ? JSON.stringify(processedData, null, 2) : processedData}`\n : message;\n\n // Use gill's debug system if enabled, otherwise fall back to console.*\n if (this.config.useGillDebug && gillDebugEnabled) {\n gillDebug(fullMessage, level as any, this.config.prefix);\n } else {\n const prefix = `[${this.config.prefix}]`;\n switch (level) {\n case 'debug':\n console.debug(prefix, message, processedData !== undefined ? processedData : '');\n break;\n case 'info':\n console.info(prefix, message, processedData !== undefined ? processedData : '');\n break;\n case 'warn':\n console.warn(prefix, message, processedData !== undefined ? processedData : '');\n break;\n case 'error':\n console.error(prefix, message, processedData !== undefined ? processedData : '');\n break;\n }\n }\n }\n\n /**\n * Recursively redact sensitive information from data\n */\n private redact(data: unknown): unknown {\n if (data === null || data === undefined) {\n return data;\n }\n\n // Handle primitives\n if (typeof data !== 'object') {\n return data;\n }\n\n // Handle arrays\n if (Array.isArray(data)) {\n return data.map(item => this.redact(item));\n }\n\n // Handle objects\n const redacted: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n const keyLower = key.toLowerCase();\n\n // Check if this key contains sensitive information\n const isSensitive = SENSITIVE_KEYS.some(sensitiveKey => keyLower.includes(sensitiveKey));\n\n if (isSensitive) {\n redacted[key] = this.maskValue(value);\n } else if (typeof value === 'object' && value !== null) {\n redacted[key] = this.redact(value);\n } else {\n redacted[key] = value;\n }\n }\n\n return redacted;\n }\n\n /**\n * Mask a sensitive value for logging\n * Shows first 4 and last 4 characters for strings longer than 8 chars\n */\n private maskValue(value: unknown): string {\n if (value === null || value === undefined) {\n return '***';\n }\n\n const str = String(value);\n\n // For very short strings, just mask completely\n if (str.length <= 8) {\n return '***';\n }\n\n // For longer strings, show first and last 4 characters\n return `${str.slice(0, 4)}...${str.slice(-4)}`;\n }\n\n /**\n * Update logger configuration at runtime\n */\n updateConfig(config: Partial<SecureLoggerConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Get current configuration\n */\n getConfig(): Required<SecureLoggerConfig> {\n return { ...this.config };\n }\n}\n\n/**\n * Default logger instance for the connector\n * Automatically configured based on NODE_ENV\n */\nexport const logger = new SecureLogger({\n prefix: 'Connector',\n});\n\n/**\n * Create a logger with a custom prefix\n *\n * @example\n * ```ts\n * const walletLogger = createLogger('WalletDetector');\n * walletLogger.debug('Scanning for wallets...');\n * // Output: [WalletDetector] Scanning for wallets...\n * ```\n */\nexport function createLogger(prefix: string, config?: Omit<SecureLoggerConfig, 'prefix'>): SecureLogger {\n return new SecureLogger({ ...config, prefix });\n}\n","/**\n * Transaction Format Utilities\n *\n * Utilities for detecting and converting between different transaction formats:\n * - web3.js Transaction/VersionedTransaction objects\n * - Serialized Uint8Array (Wallet Standard format)\n * - Other TypedArray formats\n *\n * Note: Uses dynamic imports for @solana/web3.js to avoid bundling it\n * since it's only needed for the compat layer.\n */\n\nimport type { Transaction, VersionedTransaction } from '@solana/web3.js';\nimport type { SolanaTransaction } from '../types/transactions';\n\n/**\n * Check if a value is a web3.js Transaction or VersionedTransaction object\n *\n * @param tx - Value to check\n * @returns True if it's a web3.js transaction object\n */\nexport function isWeb3jsTransaction(tx: unknown): tx is Transaction | VersionedTransaction {\n // Duck-typing: if it has a serialize method, it's likely a web3.js transaction\n return tx !== null && typeof tx === 'object' && 'serialize' in tx && typeof tx.serialize === 'function';\n}\n\n/**\n * Serialize a transaction to Uint8Array format (required for Wallet Standard)\n *\n * @param tx - Transaction to serialize (web3.js object, Uint8Array, or TypedArray)\n * @returns Serialized transaction bytes\n * @throws Error if transaction format is unsupported\n */\nexport function serializeTransaction(tx: SolanaTransaction): Uint8Array {\n // web3.js Transaction/VersionedTransaction object\n if (isWeb3jsTransaction(tx)) {\n return tx.serialize({\n requireAllSignatures: false,\n verifySignatures: false,\n });\n }\n\n // Already serialized as Uint8Array\n if (tx instanceof Uint8Array) {\n return tx;\n }\n\n // Other TypedArray format\n if (ArrayBuffer.isView(tx)) {\n return new Uint8Array(tx.buffer, tx.byteOffset, tx.byteLength);\n }\n\n throw new Error('Unsupported transaction format - must be Transaction, VersionedTransaction, or Uint8Array');\n}\n\n/**\n * Check if transaction bytes represent a legacy transaction\n * Legacy transactions have high bit = 0, versioned have high bit = 1\n *\n * @param bytes - Serialized transaction bytes\n * @returns True if legacy transaction\n */\nfunction isLegacyTransaction(bytes: Uint8Array): boolean {\n if (bytes.length === 0) return false;\n // High bit of first byte: 0 = legacy, 1 = versioned\n return (bytes[0] & 0x80) === 0;\n}\n\n/**\n * Deserialize bytes to a web3.js Transaction or VersionedTransaction object\n * Uses dynamic import to avoid bundling @solana/web3.js\n * Automatically detects legacy vs versioned format\n *\n * @param bytes - Serialized transaction bytes\n * @returns Transaction or VersionedTransaction object\n */\nexport async function deserializeToWeb3jsTransaction(bytes: Uint8Array): Promise<Transaction | VersionedTransaction> {\n if (isLegacyTransaction(bytes)) {\n // Legacy transaction - use Transaction.deserialize to preserve legacy-only fields\n const { Transaction } = await import('@solana/web3.js');\n return Transaction.from(bytes);\n } else {\n // Versioned transaction\n const { VersionedTransaction } = await import('@solana/web3.js');\n return VersionedTransaction.deserialize(bytes);\n }\n}\n\n/**\n * Smart converter that preserves the original format\n * Converts to Wallet Standard format (Uint8Array) and tracks original type\n *\n * @param tx - Transaction in any supported format\n * @returns Object with serialized bytes and format flag\n */\nexport function prepareTransactionForWallet(tx: SolanaTransaction): { serialized: Uint8Array; wasWeb3js: boolean } {\n const wasWeb3js = isWeb3jsTransaction(tx);\n const serialized = serializeTransaction(tx);\n return { serialized, wasWeb3js };\n}\n\n/**\n * Convert signed transaction bytes back to original format if needed\n *\n * @param signedBytes - Signed transaction as Uint8Array\n * @param wasWeb3js - Whether the original was a web3.js object\n * @returns Transaction in appropriate format (async if conversion needed)\n * Returns Transaction for legacy, VersionedTransaction for versioned, or Uint8Array if not web3js\n */\nexport async function convertSignedTransaction(\n signedBytes: Uint8Array,\n wasWeb3js: boolean,\n): Promise<Transaction | VersionedTransaction | Uint8Array> {\n if (wasWeb3js) {\n return await deserializeToWeb3jsTransaction(signedBytes);\n }\n return signedBytes;\n}\n"]}