@solana/connector 0.2.1 → 0.2.3

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 (79) hide show
  1. package/README.md +17 -0
  2. package/dist/{chunk-UCISIAOG.mjs → chunk-A7WQ3K75.mjs} +3 -3
  3. package/dist/{chunk-UCISIAOG.mjs.map → chunk-A7WQ3K75.mjs.map} +1 -1
  4. package/dist/{chunk-4Z2F6ERB.js → chunk-B6YBZB6H.js} +49 -48
  5. package/dist/chunk-B6YBZB6H.js.map +1 -0
  6. package/dist/{chunk-SITQ4JWM.js → chunk-BF67LVVM.js} +17 -21
  7. package/dist/chunk-BF67LVVM.js.map +1 -0
  8. package/dist/{chunk-IDTUFDNB.mjs → chunk-DFKGCW7K.mjs} +98 -12
  9. package/dist/chunk-DFKGCW7K.mjs.map +1 -0
  10. package/dist/chunk-E3DAIOYS.mjs +22 -0
  11. package/dist/chunk-E3DAIOYS.mjs.map +1 -0
  12. package/dist/chunk-FG7HTQTV.mjs +7 -0
  13. package/dist/chunk-FG7HTQTV.mjs.map +1 -0
  14. package/dist/chunk-L5FWMNWO.js +9 -0
  15. package/dist/chunk-L5FWMNWO.js.map +1 -0
  16. package/dist/{chunk-HN5AJF7F.js → chunk-NLPEO5GT.js} +5 -5
  17. package/dist/{chunk-HN5AJF7F.js.map → chunk-NLPEO5GT.js.map} +1 -1
  18. package/dist/chunk-QST7XLMB.js +26 -0
  19. package/dist/chunk-QST7XLMB.js.map +1 -0
  20. package/dist/{chunk-ZZTY3O4N.mjs → chunk-SJCQ3KZE.mjs} +4 -7
  21. package/dist/chunk-SJCQ3KZE.mjs.map +1 -0
  22. package/dist/{chunk-BZ2VBJCZ.js → chunk-ULEPN4NL.js} +181 -95
  23. package/dist/chunk-ULEPN4NL.js.map +1 -0
  24. package/dist/{chunk-HPQ5T32K.mjs → chunk-UOML5ULB.mjs} +4 -4
  25. package/dist/{chunk-HPQ5T32K.mjs.map → chunk-UOML5ULB.mjs.map} +1 -1
  26. package/dist/{chunk-MDR4Y37Z.mjs → chunk-WPDCSFX2.mjs} +5 -4
  27. package/dist/chunk-WPDCSFX2.mjs.map +1 -0
  28. package/dist/{chunk-BJAVJQLK.js → chunk-X2X5TFXS.js} +6 -6
  29. package/dist/{chunk-BJAVJQLK.js.map → chunk-X2X5TFXS.js.map} +1 -1
  30. package/dist/compat.js +2 -2
  31. package/dist/compat.mjs +1 -1
  32. package/dist/fireblocks-FLKRTJU3.js +67 -0
  33. package/dist/fireblocks-FLKRTJU3.js.map +1 -0
  34. package/dist/fireblocks-KCJV3GEK.mjs +65 -0
  35. package/dist/fireblocks-KCJV3GEK.mjs.map +1 -0
  36. package/dist/headless.d.mts +11 -11
  37. package/dist/headless.d.ts +11 -11
  38. package/dist/headless.js +147 -147
  39. package/dist/headless.mjs +4 -4
  40. package/dist/index.d.mts +1 -1
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.js +188 -188
  43. package/dist/index.mjs +5 -5
  44. package/dist/privy-6LYDE24Z.mjs +64 -0
  45. package/dist/privy-6LYDE24Z.mjs.map +1 -0
  46. package/dist/privy-ID4YFTKR.js +66 -0
  47. package/dist/privy-ID4YFTKR.js.map +1 -0
  48. package/dist/protocol-G-z1lRqo.d.mts +166 -0
  49. package/dist/protocol-G-z1lRqo.d.ts +166 -0
  50. package/dist/react.d.mts +3 -3
  51. package/dist/react.d.ts +3 -3
  52. package/dist/react.js +49 -49
  53. package/dist/react.mjs +2 -2
  54. package/dist/remote.d.mts +46 -0
  55. package/dist/remote.d.ts +46 -0
  56. package/dist/remote.js +212 -0
  57. package/dist/remote.js.map +1 -0
  58. package/dist/remote.mjs +198 -0
  59. package/dist/remote.mjs.map +1 -0
  60. package/dist/server.d.mts +141 -0
  61. package/dist/server.d.ts +141 -0
  62. package/dist/server.js +189 -0
  63. package/dist/server.js.map +1 -0
  64. package/dist/server.mjs +187 -0
  65. package/dist/server.mjs.map +1 -0
  66. package/dist/{standard-shim-tmnQelaJ.d.ts → standard-shim-BB0Lkg_C.d.ts} +44 -1
  67. package/dist/{standard-shim-CGB88PPO.d.mts → standard-shim-n5phZB1d.d.mts} +44 -1
  68. package/dist/{walletconnect-447EY3OJ.js → walletconnect-F2M3PAAN.js} +8 -8
  69. package/dist/{walletconnect-447EY3OJ.js.map → walletconnect-F2M3PAAN.js.map} +1 -1
  70. package/dist/walletconnect-Z6LPGALR.mjs +3 -0
  71. package/dist/{walletconnect-U455PO4I.mjs.map → walletconnect-Z6LPGALR.mjs.map} +1 -1
  72. package/package.json +27 -2
  73. package/dist/chunk-4Z2F6ERB.js.map +0 -1
  74. package/dist/chunk-BZ2VBJCZ.js.map +0 -1
  75. package/dist/chunk-IDTUFDNB.mjs.map +0 -1
  76. package/dist/chunk-MDR4Y37Z.mjs.map +0 -1
  77. package/dist/chunk-SITQ4JWM.js.map +0 -1
  78. package/dist/chunk-ZZTY3O4N.mjs.map +0 -1
  79. package/dist/walletconnect-U455PO4I.mjs +0 -3
package/dist/server.js ADDED
@@ -0,0 +1,189 @@
1
+ 'use strict';
2
+
3
+ var chunkQST7XLMB_js = require('./chunk-QST7XLMB.js');
4
+
5
+ // src/server/route-handlers.ts
6
+ function jsonResponse(data, status = 200) {
7
+ return new Response(JSON.stringify(data), {
8
+ status,
9
+ headers: { "Content-Type": "application/json" }
10
+ });
11
+ }
12
+ function errorResponse(code, message, status = 400, details) {
13
+ return jsonResponse({
14
+ error: { code, message, details }
15
+ }, status);
16
+ }
17
+ function defaultAuthorize(request) {
18
+ let token = process.env.CONNECTOR_SIGNER_TOKEN;
19
+ if (!token)
20
+ return console.warn("[connector/server] CONNECTOR_SIGNER_TOKEN not set - rejecting all requests"), false;
21
+ let authHeader = request.headers.get("Authorization");
22
+ if (!authHeader)
23
+ return false;
24
+ let parts = authHeader.split(" ");
25
+ return (parts.length === 2 && parts[0].toLowerCase() === "bearer" ? parts[1] : authHeader) === token;
26
+ }
27
+ async function sendTransaction(rpc, signedTxBytes) {
28
+ let base64Tx = chunkQST7XLMB_js.encodeBase64(signedTxBytes), result = await (await fetch(rpc.url, {
29
+ method: "POST",
30
+ headers: { "Content-Type": "application/json" },
31
+ body: JSON.stringify({
32
+ jsonrpc: "2.0",
33
+ id: 1,
34
+ method: "sendTransaction",
35
+ params: [
36
+ base64Tx,
37
+ {
38
+ encoding: "base64",
39
+ skipPreflight: false,
40
+ preflightCommitment: rpc.commitment || "confirmed"
41
+ }
42
+ ]
43
+ })
44
+ })).json();
45
+ if (result.error)
46
+ throw new Error(result.error.message || "RPC error");
47
+ return result.result;
48
+ }
49
+ var cachedSigner = null;
50
+ async function loadSigner(config) {
51
+ if (cachedSigner)
52
+ return cachedSigner;
53
+ if (config.type === "custom")
54
+ return cachedSigner = config.signer, cachedSigner;
55
+ if (config.type === "fireblocks") {
56
+ let { loadFireblocksSigner } = await import('./fireblocks-FLKRTJU3.js');
57
+ return cachedSigner = await loadFireblocksSigner(config), cachedSigner;
58
+ }
59
+ if (config.type === "privy") {
60
+ let { loadPrivySigner } = await import('./privy-ID4YFTKR.js');
61
+ return cachedSigner = await loadPrivySigner(config), cachedSigner;
62
+ }
63
+ throw new Error(`Unknown provider type: ${config.type}`);
64
+ }
65
+ function createRemoteSignerRouteHandlers(config) {
66
+ let {
67
+ provider,
68
+ authorize = defaultAuthorize,
69
+ policy,
70
+ rpc,
71
+ chains = ["solana:mainnet", "solana:devnet"],
72
+ name = "Remote Signer",
73
+ icon
74
+ } = config;
75
+ async function GET(request) {
76
+ try {
77
+ if (!await authorize(request))
78
+ return errorResponse("UNAUTHORIZED", "Unauthorized", 401);
79
+ let signer = await loadSigner(provider);
80
+ if (!await signer.isAvailable())
81
+ return errorResponse("PROVIDER_ERROR", "Signer not available", 503);
82
+ let capabilities = {
83
+ signTransaction: true,
84
+ signAllTransactions: true,
85
+ signMessage: true,
86
+ signAndSendTransaction: !!rpc
87
+ }, metadata = {
88
+ address: signer.address,
89
+ chains,
90
+ capabilities,
91
+ name,
92
+ icon
93
+ };
94
+ return jsonResponse(metadata);
95
+ } catch (error) {
96
+ return console.error("[connector/server] GET error:", error), errorResponse(
97
+ "INTERNAL_ERROR",
98
+ error instanceof Error ? error.message : "Internal server error",
99
+ 500
100
+ );
101
+ }
102
+ }
103
+ async function POST(request) {
104
+ try {
105
+ if (!await authorize(request))
106
+ return errorResponse("UNAUTHORIZED", "Unauthorized", 401);
107
+ let body;
108
+ try {
109
+ body = await request.json();
110
+ } catch {
111
+ return errorResponse("INVALID_REQUEST", "Invalid JSON body", 400);
112
+ }
113
+ if (!body.operation)
114
+ return errorResponse("INVALID_REQUEST", "Missing operation field", 400);
115
+ let signer = await loadSigner(provider);
116
+ switch (body.operation) {
117
+ case "signTransaction": {
118
+ if (!body.transaction)
119
+ return errorResponse("INVALID_REQUEST", "Missing transaction field", 400);
120
+ let txBytes = chunkQST7XLMB_js.decodeBase64(body.transaction);
121
+ if (policy?.validateTransaction && !await policy.validateTransaction(txBytes, request))
122
+ return errorResponse("POLICY_VIOLATION", "Transaction rejected by policy", 403);
123
+ let signedTx = await signer.signTransaction(txBytes), response = {
124
+ signedTransaction: chunkQST7XLMB_js.encodeBase64(signedTx)
125
+ };
126
+ return jsonResponse(response);
127
+ }
128
+ case "signAllTransactions": {
129
+ if (!body.transactions || !Array.isArray(body.transactions))
130
+ return errorResponse("INVALID_REQUEST", "Missing transactions array", 400);
131
+ let txBytesArray = body.transactions.map((tx) => chunkQST7XLMB_js.decodeBase64(tx));
132
+ if (policy?.validateTransaction) {
133
+ for (let txBytes of txBytesArray)
134
+ if (!await policy.validateTransaction(txBytes, request))
135
+ return errorResponse("POLICY_VIOLATION", "Transaction rejected by policy", 403);
136
+ }
137
+ let response = {
138
+ signedTransactions: (await signer.signAllTransactions(txBytesArray)).map((tx) => chunkQST7XLMB_js.encodeBase64(tx))
139
+ };
140
+ return jsonResponse(response);
141
+ }
142
+ case "signMessage": {
143
+ if (!body.message)
144
+ return errorResponse("INVALID_REQUEST", "Missing message field", 400);
145
+ let messageBytes = chunkQST7XLMB_js.decodeBase64(body.message);
146
+ if (policy?.validateMessage && !await policy.validateMessage(messageBytes, request))
147
+ return errorResponse("POLICY_VIOLATION", "Message rejected by policy", 403);
148
+ let signature = await signer.signMessage(messageBytes), response = {
149
+ signature: chunkQST7XLMB_js.encodeBase64(signature)
150
+ };
151
+ return jsonResponse(response);
152
+ }
153
+ case "signAndSendTransaction": {
154
+ if (!rpc)
155
+ return errorResponse("INVALID_OPERATION", "signAndSendTransaction not enabled", 400);
156
+ if (!body.transaction)
157
+ return errorResponse("INVALID_REQUEST", "Missing transaction field", 400);
158
+ let txBytes = chunkQST7XLMB_js.decodeBase64(body.transaction);
159
+ if (policy?.validateTransaction && !await policy.validateTransaction(txBytes, request))
160
+ return errorResponse("POLICY_VIOLATION", "Transaction rejected by policy", 403);
161
+ let signedTx = await signer.signTransaction(txBytes);
162
+ try {
163
+ let response = { signature: await sendTransaction(rpc, signedTx) };
164
+ return jsonResponse(response);
165
+ } catch (error) {
166
+ return errorResponse(
167
+ "SEND_FAILED",
168
+ error instanceof Error ? error.message : "Failed to send transaction",
169
+ 500
170
+ );
171
+ }
172
+ }
173
+ default:
174
+ return errorResponse(
175
+ "INVALID_OPERATION",
176
+ `Unknown operation: ${body.operation}`,
177
+ 400
178
+ );
179
+ }
180
+ } catch (error) {
181
+ return console.error("[connector/server] POST error:", error), error instanceof Error && (error.message.includes("rate limit") || error.message.includes("429")) ? errorResponse("PROVIDER_ERROR", "Rate limited, please retry", 429) : errorResponse("SIGNING_FAILED", error instanceof Error ? error.message : "Signing failed", 500);
182
+ }
183
+ }
184
+ return { GET, POST };
185
+ }
186
+
187
+ exports.createRemoteSignerRouteHandlers = createRemoteSignerRouteHandlers;
188
+ //# sourceMappingURL=server.js.map
189
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/route-handlers.ts"],"names":["encodeBase64","decodeBase64"],"mappings":"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","file":"server.js","sourcesContent":["/**\n * @solana/connector/server - Route Handlers\n *\n * Creates Next.js Route Handler compatible GET/POST handlers for remote signing.\n * Designed for Node.js runtime (not Edge) to support crypto operations.\n */\n\nimport type {\n RemoteSignerMetadata,\n RemoteSignerCapabilities,\n RemoteSignerRequest,\n SignTransactionResponse,\n SignAllTransactionsResponse,\n SignMessageResponse,\n SignAndSendTransactionResponse,\n RemoteSignerErrorCode,\n RemoteSignerErrorResponse,\n} from '../remote/protocol';\nimport { decodeBase64, encodeBase64 } from '../remote/protocol';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Signer interface that providers must implement\n */\nexport interface RemoteSigner {\n /** Signer's Solana address (base58) */\n readonly address: string;\n\n /** Sign transaction bytes, return signed transaction bytes */\n signTransaction(transactionBytes: Uint8Array): Promise<Uint8Array>;\n\n /** Sign multiple transactions */\n signAllTransactions(transactions: Uint8Array[]): Promise<Uint8Array[]>;\n\n /** Sign a message, return 64-byte signature */\n signMessage(message: Uint8Array): Promise<Uint8Array>;\n\n /** Check if signer is available/healthy */\n isAvailable(): Promise<boolean>;\n}\n\n/**\n * Provider configuration\n */\nexport type ProviderType = 'fireblocks' | 'privy' | 'custom';\n\nexport interface FireblocksProviderConfig {\n type: 'fireblocks';\n /** Fireblocks API key */\n apiKey: string;\n /** RSA private key PEM for JWT signing */\n privateKeyPem: string;\n /** Vault account ID */\n vaultAccountId: string;\n /** Asset ID (default: 'SOL') */\n assetId?: string;\n /** API base URL (default: https://api.fireblocks.io) */\n apiBaseUrl?: string;\n}\n\nexport interface PrivyProviderConfig {\n type: 'privy';\n /** Privy app ID */\n appId: string;\n /** Privy app secret */\n appSecret: string;\n /** Privy wallet ID */\n walletId: string;\n /** API base URL (default: https://api.privy.io/v1) */\n apiBaseUrl?: string;\n}\n\nexport interface CustomProviderConfig {\n type: 'custom';\n /** Custom signer implementation */\n signer: RemoteSigner;\n}\n\nexport type ProviderConfig = FireblocksProviderConfig | PrivyProviderConfig | CustomProviderConfig;\n\n/**\n * Authorization callback\n */\nexport type AuthorizeCallback = (request: Request) => Promise<boolean> | boolean;\n\n/**\n * Policy validation callback\n */\nexport interface PolicyHooks {\n /** Validate a transaction before signing (return false to reject) */\n validateTransaction?: (transactionBytes: Uint8Array, request: Request) => Promise<boolean> | boolean;\n /** Validate a message before signing (return false to reject) */\n validateMessage?: (messageBytes: Uint8Array, request: Request) => Promise<boolean> | boolean;\n}\n\n/**\n * RPC configuration for sign+send operations\n */\nexport interface RpcConfig {\n /** Solana RPC endpoint URL */\n url: string;\n /** Commitment level for confirmations */\n commitment?: 'processed' | 'confirmed' | 'finalized';\n}\n\n/**\n * Route handler configuration\n */\nexport interface RemoteSignerRouteHandlersConfig {\n /** Provider configuration */\n provider: ProviderConfig;\n /**\n * Authorization callback. Default: checks for Authorization header matching CONNECTOR_SIGNER_TOKEN env var.\n * Return true to allow, false to reject.\n */\n authorize?: AuthorizeCallback;\n /** Policy hooks for transaction/message validation */\n policy?: PolicyHooks;\n /** RPC configuration (required for signAndSendTransaction) */\n rpc?: RpcConfig;\n /** Supported chains (default: ['solana:mainnet', 'solana:devnet']) */\n chains?: string[];\n /** Wallet name shown in metadata */\n name?: string;\n /** Wallet icon URL */\n icon?: string;\n}\n\n/**\n * Next.js compatible request/response types\n */\nexport interface NextRequest extends Request {\n // Next.js adds extra properties, but we only need standard Request\n}\n\nexport type NextResponse = Response;\n\n/**\n * Route handlers object returned by the factory\n */\nexport interface RouteHandlers {\n GET: (request: NextRequest) => Promise<NextResponse>;\n POST: (request: NextRequest) => Promise<NextResponse>;\n}\n\n// ============================================================================\n// Helper functions\n// ============================================================================\n\nfunction jsonResponse(data: unknown, status = 200): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\nfunction errorResponse(code: RemoteSignerErrorCode, message: string, status = 400, details?: unknown): Response {\n const body: RemoteSignerErrorResponse = {\n error: { code, message, details },\n };\n return jsonResponse(body, status);\n}\n\n/**\n * Default authorization: check Authorization header against CONNECTOR_SIGNER_TOKEN env var\n */\nfunction defaultAuthorize(request: Request): boolean {\n const token = process.env.CONNECTOR_SIGNER_TOKEN;\n if (!token) {\n // No token configured = reject all (safe default)\n console.warn('[connector/server] CONNECTOR_SIGNER_TOKEN not set - rejecting all requests');\n return false;\n }\n\n const authHeader = request.headers.get('Authorization');\n if (!authHeader) {\n return false;\n }\n\n // Support \"Bearer <token>\" format\n const parts = authHeader.split(' ');\n const providedToken = parts.length === 2 && parts[0].toLowerCase() === 'bearer' ? parts[1] : authHeader;\n\n return providedToken === token;\n}\n\n/**\n * Send a signed transaction to Solana RPC\n */\nasync function sendTransaction(rpc: RpcConfig, signedTxBytes: Uint8Array): Promise<string> {\n const base64Tx = encodeBase64(signedTxBytes);\n\n const response = await fetch(rpc.url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'sendTransaction',\n params: [\n base64Tx,\n {\n encoding: 'base64',\n skipPreflight: false,\n preflightCommitment: rpc.commitment || 'confirmed',\n },\n ],\n }),\n });\n\n const result = await response.json();\n\n if (result.error) {\n throw new Error(result.error.message || 'RPC error');\n }\n\n return result.result as string;\n}\n\n// ============================================================================\n// Provider loader\n// ============================================================================\n\nlet cachedSigner: RemoteSigner | null = null;\n\nasync function loadSigner(config: ProviderConfig): Promise<RemoteSigner> {\n if (cachedSigner) {\n return cachedSigner;\n }\n\n if (config.type === 'custom') {\n cachedSigner = config.signer;\n return cachedSigner;\n }\n\n if (config.type === 'fireblocks') {\n const { loadFireblocksSigner } = await import('./providers/fireblocks');\n cachedSigner = await loadFireblocksSigner(config);\n return cachedSigner;\n }\n\n if (config.type === 'privy') {\n const { loadPrivySigner } = await import('./providers/privy');\n cachedSigner = await loadPrivySigner(config);\n return cachedSigner;\n }\n\n throw new Error(`Unknown provider type: ${(config as ProviderConfig).type}`);\n}\n\n// ============================================================================\n// Route Handler Factory\n// ============================================================================\n\n/**\n * Create Next.js Route Handlers for remote signing\n *\n * @example\n * ```typescript\n * // app/api/connector-signer/route.ts\n * import { createRemoteSignerRouteHandlers } from '@solana/connector/server';\n *\n * const { GET, POST } = createRemoteSignerRouteHandlers({\n * provider: {\n * type: 'fireblocks',\n * apiKey: process.env.FIREBLOCKS_API_KEY!,\n * privateKeyPem: process.env.FIREBLOCKS_PRIVATE_KEY!,\n * vaultAccountId: process.env.FIREBLOCKS_VAULT_ID!,\n * },\n * rpc: {\n * url: process.env.SOLANA_RPC_URL!,\n * },\n * });\n *\n * export { GET, POST };\n * export const runtime = 'nodejs';\n * ```\n */\nexport function createRemoteSignerRouteHandlers(config: RemoteSignerRouteHandlersConfig): RouteHandlers {\n const {\n provider,\n authorize = defaultAuthorize,\n policy,\n rpc,\n chains = ['solana:mainnet', 'solana:devnet'],\n name = 'Remote Signer',\n icon,\n } = config;\n\n // GET handler: return signer metadata\n async function GET(request: NextRequest): Promise<NextResponse> {\n try {\n // Check authorization\n const authorized = await authorize(request);\n if (!authorized) {\n return errorResponse('UNAUTHORIZED', 'Unauthorized', 401);\n }\n\n // Load signer\n const signer = await loadSigner(provider);\n\n // Check availability\n const available = await signer.isAvailable();\n if (!available) {\n return errorResponse('PROVIDER_ERROR', 'Signer not available', 503);\n }\n\n // Build capabilities\n const capabilities: RemoteSignerCapabilities = {\n signTransaction: true,\n signAllTransactions: true,\n signMessage: true,\n signAndSendTransaction: Boolean(rpc),\n };\n\n // Build metadata response\n const metadata: RemoteSignerMetadata = {\n address: signer.address,\n chains,\n capabilities,\n name,\n icon,\n };\n\n return jsonResponse(metadata);\n } catch (error) {\n console.error('[connector/server] GET error:', error);\n return errorResponse(\n 'INTERNAL_ERROR',\n error instanceof Error ? error.message : 'Internal server error',\n 500,\n );\n }\n }\n\n // POST handler: handle signing operations\n async function POST(request: NextRequest): Promise<NextResponse> {\n try {\n // Check authorization\n const authorized = await authorize(request);\n if (!authorized) {\n return errorResponse('UNAUTHORIZED', 'Unauthorized', 401);\n }\n\n // Parse request body\n let body: RemoteSignerRequest;\n try {\n body = await request.json();\n } catch {\n return errorResponse('INVALID_REQUEST', 'Invalid JSON body', 400);\n }\n\n if (!body.operation) {\n return errorResponse('INVALID_REQUEST', 'Missing operation field', 400);\n }\n\n // Load signer\n const signer = await loadSigner(provider);\n\n // Handle operations\n switch (body.operation) {\n case 'signTransaction': {\n if (!body.transaction) {\n return errorResponse('INVALID_REQUEST', 'Missing transaction field', 400);\n }\n\n const txBytes = decodeBase64(body.transaction);\n\n // Policy check\n if (policy?.validateTransaction) {\n const allowed = await policy.validateTransaction(txBytes, request);\n if (!allowed) {\n return errorResponse('POLICY_VIOLATION', 'Transaction rejected by policy', 403);\n }\n }\n\n const signedTx = await signer.signTransaction(txBytes);\n const response: SignTransactionResponse = {\n signedTransaction: encodeBase64(signedTx),\n };\n return jsonResponse(response);\n }\n\n case 'signAllTransactions': {\n if (!body.transactions || !Array.isArray(body.transactions)) {\n return errorResponse('INVALID_REQUEST', 'Missing transactions array', 400);\n }\n\n const txBytesArray = body.transactions.map(tx => decodeBase64(tx));\n\n // Policy check for each transaction\n if (policy?.validateTransaction) {\n for (const txBytes of txBytesArray) {\n const allowed = await policy.validateTransaction(txBytes, request);\n if (!allowed) {\n return errorResponse('POLICY_VIOLATION', 'Transaction rejected by policy', 403);\n }\n }\n }\n\n const signedTxs = await signer.signAllTransactions(txBytesArray);\n const response: SignAllTransactionsResponse = {\n signedTransactions: signedTxs.map(tx => encodeBase64(tx)),\n };\n return jsonResponse(response);\n }\n\n case 'signMessage': {\n if (!body.message) {\n return errorResponse('INVALID_REQUEST', 'Missing message field', 400);\n }\n\n const messageBytes = decodeBase64(body.message);\n\n // Policy check\n if (policy?.validateMessage) {\n const allowed = await policy.validateMessage(messageBytes, request);\n if (!allowed) {\n return errorResponse('POLICY_VIOLATION', 'Message rejected by policy', 403);\n }\n }\n\n const signature = await signer.signMessage(messageBytes);\n const response: SignMessageResponse = {\n signature: encodeBase64(signature),\n };\n return jsonResponse(response);\n }\n\n case 'signAndSendTransaction': {\n if (!rpc) {\n return errorResponse('INVALID_OPERATION', 'signAndSendTransaction not enabled', 400);\n }\n\n if (!body.transaction) {\n return errorResponse('INVALID_REQUEST', 'Missing transaction field', 400);\n }\n\n const txBytes = decodeBase64(body.transaction);\n\n // Policy check\n if (policy?.validateTransaction) {\n const allowed = await policy.validateTransaction(txBytes, request);\n if (!allowed) {\n return errorResponse('POLICY_VIOLATION', 'Transaction rejected by policy', 403);\n }\n }\n\n // Sign\n const signedTx = await signer.signTransaction(txBytes);\n\n // Send\n try {\n const signature = await sendTransaction(rpc, signedTx);\n const response: SignAndSendTransactionResponse = { signature };\n return jsonResponse(response);\n } catch (error) {\n return errorResponse(\n 'SEND_FAILED',\n error instanceof Error ? error.message : 'Failed to send transaction',\n 500,\n );\n }\n }\n\n default:\n return errorResponse(\n 'INVALID_OPERATION',\n `Unknown operation: ${(body as { operation: string }).operation}`,\n 400,\n );\n }\n } catch (error) {\n console.error('[connector/server] POST error:', error);\n\n // Check for known signer errors\n if (error instanceof Error) {\n if (error.message.includes('rate limit') || error.message.includes('429')) {\n return errorResponse('PROVIDER_ERROR', 'Rate limited, please retry', 429);\n }\n }\n\n return errorResponse('SIGNING_FAILED', error instanceof Error ? error.message : 'Signing failed', 500);\n }\n }\n\n return { GET, POST };\n}\n"]}
@@ -0,0 +1,187 @@
1
+ import { decodeBase64, encodeBase64 } from './chunk-E3DAIOYS.mjs';
2
+
3
+ // src/server/route-handlers.ts
4
+ function jsonResponse(data, status = 200) {
5
+ return new Response(JSON.stringify(data), {
6
+ status,
7
+ headers: { "Content-Type": "application/json" }
8
+ });
9
+ }
10
+ function errorResponse(code, message, status = 400, details) {
11
+ return jsonResponse({
12
+ error: { code, message, details }
13
+ }, status);
14
+ }
15
+ function defaultAuthorize(request) {
16
+ let token = process.env.CONNECTOR_SIGNER_TOKEN;
17
+ if (!token)
18
+ return console.warn("[connector/server] CONNECTOR_SIGNER_TOKEN not set - rejecting all requests"), false;
19
+ let authHeader = request.headers.get("Authorization");
20
+ if (!authHeader)
21
+ return false;
22
+ let parts = authHeader.split(" ");
23
+ return (parts.length === 2 && parts[0].toLowerCase() === "bearer" ? parts[1] : authHeader) === token;
24
+ }
25
+ async function sendTransaction(rpc, signedTxBytes) {
26
+ let base64Tx = encodeBase64(signedTxBytes), result = await (await fetch(rpc.url, {
27
+ method: "POST",
28
+ headers: { "Content-Type": "application/json" },
29
+ body: JSON.stringify({
30
+ jsonrpc: "2.0",
31
+ id: 1,
32
+ method: "sendTransaction",
33
+ params: [
34
+ base64Tx,
35
+ {
36
+ encoding: "base64",
37
+ skipPreflight: false,
38
+ preflightCommitment: rpc.commitment || "confirmed"
39
+ }
40
+ ]
41
+ })
42
+ })).json();
43
+ if (result.error)
44
+ throw new Error(result.error.message || "RPC error");
45
+ return result.result;
46
+ }
47
+ var cachedSigner = null;
48
+ async function loadSigner(config) {
49
+ if (cachedSigner)
50
+ return cachedSigner;
51
+ if (config.type === "custom")
52
+ return cachedSigner = config.signer, cachedSigner;
53
+ if (config.type === "fireblocks") {
54
+ let { loadFireblocksSigner } = await import('./fireblocks-KCJV3GEK.mjs');
55
+ return cachedSigner = await loadFireblocksSigner(config), cachedSigner;
56
+ }
57
+ if (config.type === "privy") {
58
+ let { loadPrivySigner } = await import('./privy-6LYDE24Z.mjs');
59
+ return cachedSigner = await loadPrivySigner(config), cachedSigner;
60
+ }
61
+ throw new Error(`Unknown provider type: ${config.type}`);
62
+ }
63
+ function createRemoteSignerRouteHandlers(config) {
64
+ let {
65
+ provider,
66
+ authorize = defaultAuthorize,
67
+ policy,
68
+ rpc,
69
+ chains = ["solana:mainnet", "solana:devnet"],
70
+ name = "Remote Signer",
71
+ icon
72
+ } = config;
73
+ async function GET(request) {
74
+ try {
75
+ if (!await authorize(request))
76
+ return errorResponse("UNAUTHORIZED", "Unauthorized", 401);
77
+ let signer = await loadSigner(provider);
78
+ if (!await signer.isAvailable())
79
+ return errorResponse("PROVIDER_ERROR", "Signer not available", 503);
80
+ let capabilities = {
81
+ signTransaction: true,
82
+ signAllTransactions: true,
83
+ signMessage: true,
84
+ signAndSendTransaction: !!rpc
85
+ }, metadata = {
86
+ address: signer.address,
87
+ chains,
88
+ capabilities,
89
+ name,
90
+ icon
91
+ };
92
+ return jsonResponse(metadata);
93
+ } catch (error) {
94
+ return console.error("[connector/server] GET error:", error), errorResponse(
95
+ "INTERNAL_ERROR",
96
+ error instanceof Error ? error.message : "Internal server error",
97
+ 500
98
+ );
99
+ }
100
+ }
101
+ async function POST(request) {
102
+ try {
103
+ if (!await authorize(request))
104
+ return errorResponse("UNAUTHORIZED", "Unauthorized", 401);
105
+ let body;
106
+ try {
107
+ body = await request.json();
108
+ } catch {
109
+ return errorResponse("INVALID_REQUEST", "Invalid JSON body", 400);
110
+ }
111
+ if (!body.operation)
112
+ return errorResponse("INVALID_REQUEST", "Missing operation field", 400);
113
+ let signer = await loadSigner(provider);
114
+ switch (body.operation) {
115
+ case "signTransaction": {
116
+ if (!body.transaction)
117
+ return errorResponse("INVALID_REQUEST", "Missing transaction field", 400);
118
+ let txBytes = decodeBase64(body.transaction);
119
+ if (policy?.validateTransaction && !await policy.validateTransaction(txBytes, request))
120
+ return errorResponse("POLICY_VIOLATION", "Transaction rejected by policy", 403);
121
+ let signedTx = await signer.signTransaction(txBytes), response = {
122
+ signedTransaction: encodeBase64(signedTx)
123
+ };
124
+ return jsonResponse(response);
125
+ }
126
+ case "signAllTransactions": {
127
+ if (!body.transactions || !Array.isArray(body.transactions))
128
+ return errorResponse("INVALID_REQUEST", "Missing transactions array", 400);
129
+ let txBytesArray = body.transactions.map((tx) => decodeBase64(tx));
130
+ if (policy?.validateTransaction) {
131
+ for (let txBytes of txBytesArray)
132
+ if (!await policy.validateTransaction(txBytes, request))
133
+ return errorResponse("POLICY_VIOLATION", "Transaction rejected by policy", 403);
134
+ }
135
+ let response = {
136
+ signedTransactions: (await signer.signAllTransactions(txBytesArray)).map((tx) => encodeBase64(tx))
137
+ };
138
+ return jsonResponse(response);
139
+ }
140
+ case "signMessage": {
141
+ if (!body.message)
142
+ return errorResponse("INVALID_REQUEST", "Missing message field", 400);
143
+ let messageBytes = decodeBase64(body.message);
144
+ if (policy?.validateMessage && !await policy.validateMessage(messageBytes, request))
145
+ return errorResponse("POLICY_VIOLATION", "Message rejected by policy", 403);
146
+ let signature = await signer.signMessage(messageBytes), response = {
147
+ signature: encodeBase64(signature)
148
+ };
149
+ return jsonResponse(response);
150
+ }
151
+ case "signAndSendTransaction": {
152
+ if (!rpc)
153
+ return errorResponse("INVALID_OPERATION", "signAndSendTransaction not enabled", 400);
154
+ if (!body.transaction)
155
+ return errorResponse("INVALID_REQUEST", "Missing transaction field", 400);
156
+ let txBytes = decodeBase64(body.transaction);
157
+ if (policy?.validateTransaction && !await policy.validateTransaction(txBytes, request))
158
+ return errorResponse("POLICY_VIOLATION", "Transaction rejected by policy", 403);
159
+ let signedTx = await signer.signTransaction(txBytes);
160
+ try {
161
+ let response = { signature: await sendTransaction(rpc, signedTx) };
162
+ return jsonResponse(response);
163
+ } catch (error) {
164
+ return errorResponse(
165
+ "SEND_FAILED",
166
+ error instanceof Error ? error.message : "Failed to send transaction",
167
+ 500
168
+ );
169
+ }
170
+ }
171
+ default:
172
+ return errorResponse(
173
+ "INVALID_OPERATION",
174
+ `Unknown operation: ${body.operation}`,
175
+ 400
176
+ );
177
+ }
178
+ } catch (error) {
179
+ return console.error("[connector/server] POST error:", error), error instanceof Error && (error.message.includes("rate limit") || error.message.includes("429")) ? errorResponse("PROVIDER_ERROR", "Rate limited, please retry", 429) : errorResponse("SIGNING_FAILED", error instanceof Error ? error.message : "Signing failed", 500);
180
+ }
181
+ }
182
+ return { GET, POST };
183
+ }
184
+
185
+ export { createRemoteSignerRouteHandlers };
186
+ //# sourceMappingURL=server.mjs.map
187
+ //# sourceMappingURL=server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/route-handlers.ts"],"names":[],"mappings":";;;AAwJA,SAAS,YAAA,CAAa,IAAA,EAAe,MAAA,GAAS,GAAA,EAAe;AACzD,EAAA,OAAO,IAAI,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG;AAAA,IACtC,MAAA;AAAA,IACA,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAAmB,GACjD,CAAA;AACL;AAEA,SAAS,aAAA,CAAc,IAAA,EAA6B,OAAA,EAAiB,MAAA,GAAS,KAAK,OAAA,EAA6B;AAI5G,EAAA,OAAO,YAAA,CAHiC;AAAA,IACpC,KAAA,EAAO,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA;AAAQ,KAEV,MAAM,CAAA;AACpC;AAKA,SAAS,iBAAiB,OAAA,EAA2B;AACjD,EAAA,IAAM,KAAA,GAAQ,QAAQ,GAAA,CAAI,sBAAA;AAC1B,EAAA,IAAI,CAAC,KAAA;AAED,IAAA,OAAA,OAAA,CAAQ,IAAA,CAAK,4EAA4E,CAAA,EAClF,KAAA;AAGX,EAAA,IAAM,UAAA,GAAa,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,eAAe,CAAA;AACtD,EAAA,IAAI,CAAC,UAAA;AACD,IAAA,OAAO,KAAA;AAIX,EAAA,IAAM,KAAA,GAAQ,UAAA,CAAW,KAAA,CAAM,GAAG,CAAA;AAGlC,EAAA,OAAA,CAFsB,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,KAAA,CAAM,CAAC,CAAA,CAAE,WAAA,EAAY,KAAM,QAAA,GAAW,KAAA,CAAM,CAAC,CAAA,GAAI,UAAA,MAEpE,KAAA;AAC7B;AAKA,eAAe,eAAA,CAAgB,KAAgB,aAAA,EAA4C;AACvF,EAAA,IAAM,QAAA,GAAW,aAAa,aAAa,CAAA,EAoBrC,SAAS,MAAA,CAlBE,MAAM,KAAA,CAAM,GAAA,CAAI,GAAA,EAAK;AAAA,IAClC,MAAA,EAAQ,MAAA;AAAA,IACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,MACjB,OAAA,EAAS,KAAA;AAAA,MACT,EAAA,EAAI,CAAA;AAAA,MACJ,MAAA,EAAQ,iBAAA;AAAA,MACR,MAAA,EAAQ;AAAA,QACJ,QAAA;AAAA,QACA;AAAA,UACI,QAAA,EAAU,QAAA;AAAA,UACV,aAAA,EAAe,KAAA;AAAA,UACf,mBAAA,EAAqB,IAAI,UAAA,IAAc;AAAA;AAC3C;AACJ,KACH;AAAA,GACJ,GAE6B,IAAA,EAAK;AAEnC,EAAA,IAAI,MAAA,CAAO,KAAA;AACP,IAAA,MAAM,IAAI,KAAA,CAAM,MAAA,CAAO,KAAA,CAAM,WAAW,WAAW,CAAA;AAGvD,EAAA,OAAO,MAAA,CAAO,MAAA;AAClB;AAMA,IAAI,YAAA,GAAoC,IAAA;AAExC,eAAe,WAAW,MAAA,EAA+C;AACrE,EAAA,IAAI,YAAA;AACA,IAAA,OAAO,YAAA;AAGX,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA;AAChB,IAAA,OAAA,YAAA,GAAe,OAAO,MAAA,EACf,YAAA;AAGX,EAAA,IAAI,MAAA,CAAO,SAAS,YAAA,EAAc;AAC9B,IAAA,IAAM,EAAE,oBAAA,EAAqB,GAAI,MAAM,OAAO,2BAAwB,CAAA;AACtE,IAAA,OAAA,YAAA,GAAe,MAAM,oBAAA,CAAqB,MAAM,CAAA,EACzC,YAAA;AAAA,EACX;AAEA,EAAA,IAAI,MAAA,CAAO,SAAS,OAAA,EAAS;AACzB,IAAA,IAAM,EAAE,eAAA,EAAgB,GAAI,MAAM,OAAO,sBAAmB,CAAA;AAC5D,IAAA,OAAA,YAAA,GAAe,MAAM,eAAA,CAAgB,MAAM,CAAA,EACpC,YAAA;AAAA,EACX;AAEA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA2B,MAAA,CAA0B,IAAI,CAAA,CAAE,CAAA;AAC/E;AA8BO,SAAS,gCAAgC,MAAA,EAAwD;AACpG,EAAA,IAAM;AAAA,IACF,QAAA;AAAA,IACA,SAAA,GAAY,gBAAA;AAAA,IACZ,MAAA;AAAA,IACA,GAAA;AAAA,IACA,MAAA,GAAS,CAAC,gBAAA,EAAkB,eAAe,CAAA;AAAA,IAC3C,IAAA,GAAO,eAAA;AAAA,IACP;AAAA,GACJ,GAAI,MAAA;AAGJ,EAAA,eAAe,IAAI,OAAA,EAA6C;AAC5D,IAAA,IAAI;AAGA,MAAA,IAAI,CADe,MAAM,SAAA,CAAU,OAAO,CAAA;AAEtC,QAAA,OAAO,aAAA,CAAc,cAAA,EAAgB,cAAA,EAAgB,GAAG,CAAA;AAI5D,MAAA,IAAM,MAAA,GAAS,MAAM,UAAA,CAAW,QAAQ,CAAA;AAIxC,MAAA,IAAI,CADc,MAAM,MAAA,CAAO,WAAA,EAAY;AAEvC,QAAA,OAAO,aAAA,CAAc,gBAAA,EAAkB,sBAAA,EAAwB,GAAG,CAAA;AAItE,MAAA,IAAM,YAAA,GAAyC;AAAA,QAC3C,eAAA,EAAiB,IAAA;AAAA,QACjB,mBAAA,EAAqB,IAAA;AAAA,QACrB,WAAA,EAAa,IAAA;AAAA,QACb,wBAAwB,CAAA,CAAQ;AAAA,SAI9B,QAAA,GAAiC;AAAA,QACnC,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,MAAA;AAAA,QACA,YAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA,OACJ;AAEA,MAAA,OAAO,aAAa,QAAQ,CAAA;AAAA,IAChC,SAAS,KAAA,EAAO;AACZ,MAAA,OAAA,OAAA,CAAQ,KAAA,CAAM,+BAAA,EAAiC,KAAK,CAAA,EAC7C,aAAA;AAAA,QACH,gBAAA;AAAA,QACA,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,uBAAA;AAAA,QACzC;AAAA,OACJ;AAAA,IACJ;AAAA,EACJ;AAGA,EAAA,eAAe,KAAK,OAAA,EAA6C;AAC7D,IAAA,IAAI;AAGA,MAAA,IAAI,CADe,MAAM,SAAA,CAAU,OAAO,CAAA;AAEtC,QAAA,OAAO,aAAA,CAAc,cAAA,EAAgB,cAAA,EAAgB,GAAG,CAAA;AAI5D,MAAA,IAAI,IAAA;AACJ,MAAA,IAAI;AACA,QAAA,IAAA,GAAO,MAAM,QAAQ,IAAA,EAAK;AAAA,MAC9B,CAAA,CAAA,MAAQ;AACJ,QAAA,OAAO,aAAA,CAAc,iBAAA,EAAmB,mBAAA,EAAqB,GAAG,CAAA;AAAA,MACpE;AAEA,MAAA,IAAI,CAAC,IAAA,CAAK,SAAA;AACN,QAAA,OAAO,aAAA,CAAc,iBAAA,EAAmB,yBAAA,EAA2B,GAAG,CAAA;AAI1E,MAAA,IAAM,MAAA,GAAS,MAAM,UAAA,CAAW,QAAQ,CAAA;AAGxC,MAAA,QAAQ,KAAK,SAAA;AAAW,QACpB,KAAK,iBAAA,EAAmB;AACpB,UAAA,IAAI,CAAC,IAAA,CAAK,WAAA;AACN,YAAA,OAAO,aAAA,CAAc,iBAAA,EAAmB,2BAAA,EAA6B,GAAG,CAAA;AAG5E,UAAA,IAAM,OAAA,GAAU,YAAA,CAAa,IAAA,CAAK,WAAW,CAAA;AAG7C,UAAA,IAAI,QAAQ,mBAAA,IAEJ,CADY,MAAM,MAAA,CAAO,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAE7D,YAAA,OAAO,aAAA,CAAc,kBAAA,EAAoB,gCAAA,EAAkC,GAAG,CAAA;AAItF,UAAA,IAAM,WAAW,MAAM,MAAA,CAAO,eAAA,CAAgB,OAAO,GAC/C,QAAA,GAAoC;AAAA,YACtC,iBAAA,EAAmB,aAAa,QAAQ;AAAA,WAC5C;AACA,UAAA,OAAO,aAAa,QAAQ,CAAA;AAAA,QAChC;AAAA,QAEA,KAAK,qBAAA,EAAuB;AACxB,UAAA,IAAI,CAAC,IAAA,CAAK,YAAA,IAAgB,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,YAAY,CAAA;AACtD,YAAA,OAAO,aAAA,CAAc,iBAAA,EAAmB,4BAAA,EAA8B,GAAG,CAAA;AAG7E,UAAA,IAAM,eAAe,IAAA,CAAK,YAAA,CAAa,IAAI,CAAA,EAAA,KAAM,YAAA,CAAa,EAAE,CAAC,CAAA;AAGjE,UAAA,IAAI,MAAA,EAAQ,mBAAA,EAAA;AACR,YAAA,KAAA,IAAW,OAAA,IAAW,YAAA;AAElB,cAAA,IAAI,CADY,MAAM,MAAA,CAAO,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAE7D,gBAAA,OAAO,aAAA,CAAc,kBAAA,EAAoB,gCAAA,EAAkC,GAAG,CAAA;AAAA,UAAA;AAM1F,UAAA,IAAM,QAAA,GAAwC;AAAA,YAC1C,kBAAA,EAAA,CAFc,MAAM,MAAA,CAAO,mBAAA,CAAoB,YAAY,GAE7B,GAAA,CAAI,CAAA,EAAA,KAAM,YAAA,CAAa,EAAE,CAAC;AAAA,WAC5D;AACA,UAAA,OAAO,aAAa,QAAQ,CAAA;AAAA,QAChC;AAAA,QAEA,KAAK,aAAA,EAAe;AAChB,UAAA,IAAI,CAAC,IAAA,CAAK,OAAA;AACN,YAAA,OAAO,aAAA,CAAc,iBAAA,EAAmB,uBAAA,EAAyB,GAAG,CAAA;AAGxE,UAAA,IAAM,YAAA,GAAe,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA;AAG9C,UAAA,IAAI,QAAQ,eAAA,IAEJ,CADY,MAAM,MAAA,CAAO,eAAA,CAAgB,cAAc,OAAO,CAAA;AAE9D,YAAA,OAAO,aAAA,CAAc,kBAAA,EAAoB,4BAAA,EAA8B,GAAG,CAAA;AAIlF,UAAA,IAAM,YAAY,MAAM,MAAA,CAAO,WAAA,CAAY,YAAY,GACjD,QAAA,GAAgC;AAAA,YAClC,SAAA,EAAW,aAAa,SAAS;AAAA,WACrC;AACA,UAAA,OAAO,aAAa,QAAQ,CAAA;AAAA,QAChC;AAAA,QAEA,KAAK,wBAAA,EAA0B;AAC3B,UAAA,IAAI,CAAC,GAAA;AACD,YAAA,OAAO,aAAA,CAAc,mBAAA,EAAqB,oCAAA,EAAsC,GAAG,CAAA;AAGvF,UAAA,IAAI,CAAC,IAAA,CAAK,WAAA;AACN,YAAA,OAAO,aAAA,CAAc,iBAAA,EAAmB,2BAAA,EAA6B,GAAG,CAAA;AAG5E,UAAA,IAAM,OAAA,GAAU,YAAA,CAAa,IAAA,CAAK,WAAW,CAAA;AAG7C,UAAA,IAAI,QAAQ,mBAAA,IAEJ,CADY,MAAM,MAAA,CAAO,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAE7D,YAAA,OAAO,aAAA,CAAc,kBAAA,EAAoB,gCAAA,EAAkC,GAAG,CAAA;AAKtF,UAAA,IAAM,QAAA,GAAW,MAAM,MAAA,CAAO,eAAA,CAAgB,OAAO,CAAA;AAGrD,UAAA,IAAI;AAEA,YAAA,IAAM,WAA2C,EAAE,SAAA,EADjC,MAAM,eAAA,CAAgB,GAAA,EAAK,QAAQ,CAAA,EACQ;AAC7D,YAAA,OAAO,aAAa,QAAQ,CAAA;AAAA,UAChC,SAAS,KAAA,EAAO;AACZ,YAAA,OAAO,aAAA;AAAA,cACH,aAAA;AAAA,cACA,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,4BAAA;AAAA,cACzC;AAAA,aACJ;AAAA,UACJ;AAAA,QACJ;AAAA,QAEA;AACI,UAAA,OAAO,aAAA;AAAA,YACH,mBAAA;AAAA,YACA,CAAA,mBAAA,EAAuB,KAA+B,SAAS,CAAA,CAAA;AAAA,YAC/D;AAAA,WACJ;AAAA;AACR,IACJ,SAAS,KAAA,EAAO;AAIZ,MAAA,OAHA,OAAA,CAAQ,KAAA,CAAM,gCAAA,EAAkC,KAAK,CAAA,EAGjD,KAAA,YAAiB,KAAA,KACb,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA,IAAK,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,CAAA,GAC7D,aAAA,CAAc,gBAAA,EAAkB,4BAAA,EAA8B,GAAG,CAAA,GAIzE,aAAA,CAAc,gBAAA,EAAkB,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,kBAAkB,GAAG,CAAA;AAAA,IACzG;AAAA,EACJ;AAEA,EAAA,OAAO,EAAE,KAAK,IAAA,EAAK;AACvB","file":"server.mjs","sourcesContent":["/**\n * @solana/connector/server - Route Handlers\n *\n * Creates Next.js Route Handler compatible GET/POST handlers for remote signing.\n * Designed for Node.js runtime (not Edge) to support crypto operations.\n */\n\nimport type {\n RemoteSignerMetadata,\n RemoteSignerCapabilities,\n RemoteSignerRequest,\n SignTransactionResponse,\n SignAllTransactionsResponse,\n SignMessageResponse,\n SignAndSendTransactionResponse,\n RemoteSignerErrorCode,\n RemoteSignerErrorResponse,\n} from '../remote/protocol';\nimport { decodeBase64, encodeBase64 } from '../remote/protocol';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Signer interface that providers must implement\n */\nexport interface RemoteSigner {\n /** Signer's Solana address (base58) */\n readonly address: string;\n\n /** Sign transaction bytes, return signed transaction bytes */\n signTransaction(transactionBytes: Uint8Array): Promise<Uint8Array>;\n\n /** Sign multiple transactions */\n signAllTransactions(transactions: Uint8Array[]): Promise<Uint8Array[]>;\n\n /** Sign a message, return 64-byte signature */\n signMessage(message: Uint8Array): Promise<Uint8Array>;\n\n /** Check if signer is available/healthy */\n isAvailable(): Promise<boolean>;\n}\n\n/**\n * Provider configuration\n */\nexport type ProviderType = 'fireblocks' | 'privy' | 'custom';\n\nexport interface FireblocksProviderConfig {\n type: 'fireblocks';\n /** Fireblocks API key */\n apiKey: string;\n /** RSA private key PEM for JWT signing */\n privateKeyPem: string;\n /** Vault account ID */\n vaultAccountId: string;\n /** Asset ID (default: 'SOL') */\n assetId?: string;\n /** API base URL (default: https://api.fireblocks.io) */\n apiBaseUrl?: string;\n}\n\nexport interface PrivyProviderConfig {\n type: 'privy';\n /** Privy app ID */\n appId: string;\n /** Privy app secret */\n appSecret: string;\n /** Privy wallet ID */\n walletId: string;\n /** API base URL (default: https://api.privy.io/v1) */\n apiBaseUrl?: string;\n}\n\nexport interface CustomProviderConfig {\n type: 'custom';\n /** Custom signer implementation */\n signer: RemoteSigner;\n}\n\nexport type ProviderConfig = FireblocksProviderConfig | PrivyProviderConfig | CustomProviderConfig;\n\n/**\n * Authorization callback\n */\nexport type AuthorizeCallback = (request: Request) => Promise<boolean> | boolean;\n\n/**\n * Policy validation callback\n */\nexport interface PolicyHooks {\n /** Validate a transaction before signing (return false to reject) */\n validateTransaction?: (transactionBytes: Uint8Array, request: Request) => Promise<boolean> | boolean;\n /** Validate a message before signing (return false to reject) */\n validateMessage?: (messageBytes: Uint8Array, request: Request) => Promise<boolean> | boolean;\n}\n\n/**\n * RPC configuration for sign+send operations\n */\nexport interface RpcConfig {\n /** Solana RPC endpoint URL */\n url: string;\n /** Commitment level for confirmations */\n commitment?: 'processed' | 'confirmed' | 'finalized';\n}\n\n/**\n * Route handler configuration\n */\nexport interface RemoteSignerRouteHandlersConfig {\n /** Provider configuration */\n provider: ProviderConfig;\n /**\n * Authorization callback. Default: checks for Authorization header matching CONNECTOR_SIGNER_TOKEN env var.\n * Return true to allow, false to reject.\n */\n authorize?: AuthorizeCallback;\n /** Policy hooks for transaction/message validation */\n policy?: PolicyHooks;\n /** RPC configuration (required for signAndSendTransaction) */\n rpc?: RpcConfig;\n /** Supported chains (default: ['solana:mainnet', 'solana:devnet']) */\n chains?: string[];\n /** Wallet name shown in metadata */\n name?: string;\n /** Wallet icon URL */\n icon?: string;\n}\n\n/**\n * Next.js compatible request/response types\n */\nexport interface NextRequest extends Request {\n // Next.js adds extra properties, but we only need standard Request\n}\n\nexport type NextResponse = Response;\n\n/**\n * Route handlers object returned by the factory\n */\nexport interface RouteHandlers {\n GET: (request: NextRequest) => Promise<NextResponse>;\n POST: (request: NextRequest) => Promise<NextResponse>;\n}\n\n// ============================================================================\n// Helper functions\n// ============================================================================\n\nfunction jsonResponse(data: unknown, status = 200): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n\nfunction errorResponse(code: RemoteSignerErrorCode, message: string, status = 400, details?: unknown): Response {\n const body: RemoteSignerErrorResponse = {\n error: { code, message, details },\n };\n return jsonResponse(body, status);\n}\n\n/**\n * Default authorization: check Authorization header against CONNECTOR_SIGNER_TOKEN env var\n */\nfunction defaultAuthorize(request: Request): boolean {\n const token = process.env.CONNECTOR_SIGNER_TOKEN;\n if (!token) {\n // No token configured = reject all (safe default)\n console.warn('[connector/server] CONNECTOR_SIGNER_TOKEN not set - rejecting all requests');\n return false;\n }\n\n const authHeader = request.headers.get('Authorization');\n if (!authHeader) {\n return false;\n }\n\n // Support \"Bearer <token>\" format\n const parts = authHeader.split(' ');\n const providedToken = parts.length === 2 && parts[0].toLowerCase() === 'bearer' ? parts[1] : authHeader;\n\n return providedToken === token;\n}\n\n/**\n * Send a signed transaction to Solana RPC\n */\nasync function sendTransaction(rpc: RpcConfig, signedTxBytes: Uint8Array): Promise<string> {\n const base64Tx = encodeBase64(signedTxBytes);\n\n const response = await fetch(rpc.url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'sendTransaction',\n params: [\n base64Tx,\n {\n encoding: 'base64',\n skipPreflight: false,\n preflightCommitment: rpc.commitment || 'confirmed',\n },\n ],\n }),\n });\n\n const result = await response.json();\n\n if (result.error) {\n throw new Error(result.error.message || 'RPC error');\n }\n\n return result.result as string;\n}\n\n// ============================================================================\n// Provider loader\n// ============================================================================\n\nlet cachedSigner: RemoteSigner | null = null;\n\nasync function loadSigner(config: ProviderConfig): Promise<RemoteSigner> {\n if (cachedSigner) {\n return cachedSigner;\n }\n\n if (config.type === 'custom') {\n cachedSigner = config.signer;\n return cachedSigner;\n }\n\n if (config.type === 'fireblocks') {\n const { loadFireblocksSigner } = await import('./providers/fireblocks');\n cachedSigner = await loadFireblocksSigner(config);\n return cachedSigner;\n }\n\n if (config.type === 'privy') {\n const { loadPrivySigner } = await import('./providers/privy');\n cachedSigner = await loadPrivySigner(config);\n return cachedSigner;\n }\n\n throw new Error(`Unknown provider type: ${(config as ProviderConfig).type}`);\n}\n\n// ============================================================================\n// Route Handler Factory\n// ============================================================================\n\n/**\n * Create Next.js Route Handlers for remote signing\n *\n * @example\n * ```typescript\n * // app/api/connector-signer/route.ts\n * import { createRemoteSignerRouteHandlers } from '@solana/connector/server';\n *\n * const { GET, POST } = createRemoteSignerRouteHandlers({\n * provider: {\n * type: 'fireblocks',\n * apiKey: process.env.FIREBLOCKS_API_KEY!,\n * privateKeyPem: process.env.FIREBLOCKS_PRIVATE_KEY!,\n * vaultAccountId: process.env.FIREBLOCKS_VAULT_ID!,\n * },\n * rpc: {\n * url: process.env.SOLANA_RPC_URL!,\n * },\n * });\n *\n * export { GET, POST };\n * export const runtime = 'nodejs';\n * ```\n */\nexport function createRemoteSignerRouteHandlers(config: RemoteSignerRouteHandlersConfig): RouteHandlers {\n const {\n provider,\n authorize = defaultAuthorize,\n policy,\n rpc,\n chains = ['solana:mainnet', 'solana:devnet'],\n name = 'Remote Signer',\n icon,\n } = config;\n\n // GET handler: return signer metadata\n async function GET(request: NextRequest): Promise<NextResponse> {\n try {\n // Check authorization\n const authorized = await authorize(request);\n if (!authorized) {\n return errorResponse('UNAUTHORIZED', 'Unauthorized', 401);\n }\n\n // Load signer\n const signer = await loadSigner(provider);\n\n // Check availability\n const available = await signer.isAvailable();\n if (!available) {\n return errorResponse('PROVIDER_ERROR', 'Signer not available', 503);\n }\n\n // Build capabilities\n const capabilities: RemoteSignerCapabilities = {\n signTransaction: true,\n signAllTransactions: true,\n signMessage: true,\n signAndSendTransaction: Boolean(rpc),\n };\n\n // Build metadata response\n const metadata: RemoteSignerMetadata = {\n address: signer.address,\n chains,\n capabilities,\n name,\n icon,\n };\n\n return jsonResponse(metadata);\n } catch (error) {\n console.error('[connector/server] GET error:', error);\n return errorResponse(\n 'INTERNAL_ERROR',\n error instanceof Error ? error.message : 'Internal server error',\n 500,\n );\n }\n }\n\n // POST handler: handle signing operations\n async function POST(request: NextRequest): Promise<NextResponse> {\n try {\n // Check authorization\n const authorized = await authorize(request);\n if (!authorized) {\n return errorResponse('UNAUTHORIZED', 'Unauthorized', 401);\n }\n\n // Parse request body\n let body: RemoteSignerRequest;\n try {\n body = await request.json();\n } catch {\n return errorResponse('INVALID_REQUEST', 'Invalid JSON body', 400);\n }\n\n if (!body.operation) {\n return errorResponse('INVALID_REQUEST', 'Missing operation field', 400);\n }\n\n // Load signer\n const signer = await loadSigner(provider);\n\n // Handle operations\n switch (body.operation) {\n case 'signTransaction': {\n if (!body.transaction) {\n return errorResponse('INVALID_REQUEST', 'Missing transaction field', 400);\n }\n\n const txBytes = decodeBase64(body.transaction);\n\n // Policy check\n if (policy?.validateTransaction) {\n const allowed = await policy.validateTransaction(txBytes, request);\n if (!allowed) {\n return errorResponse('POLICY_VIOLATION', 'Transaction rejected by policy', 403);\n }\n }\n\n const signedTx = await signer.signTransaction(txBytes);\n const response: SignTransactionResponse = {\n signedTransaction: encodeBase64(signedTx),\n };\n return jsonResponse(response);\n }\n\n case 'signAllTransactions': {\n if (!body.transactions || !Array.isArray(body.transactions)) {\n return errorResponse('INVALID_REQUEST', 'Missing transactions array', 400);\n }\n\n const txBytesArray = body.transactions.map(tx => decodeBase64(tx));\n\n // Policy check for each transaction\n if (policy?.validateTransaction) {\n for (const txBytes of txBytesArray) {\n const allowed = await policy.validateTransaction(txBytes, request);\n if (!allowed) {\n return errorResponse('POLICY_VIOLATION', 'Transaction rejected by policy', 403);\n }\n }\n }\n\n const signedTxs = await signer.signAllTransactions(txBytesArray);\n const response: SignAllTransactionsResponse = {\n signedTransactions: signedTxs.map(tx => encodeBase64(tx)),\n };\n return jsonResponse(response);\n }\n\n case 'signMessage': {\n if (!body.message) {\n return errorResponse('INVALID_REQUEST', 'Missing message field', 400);\n }\n\n const messageBytes = decodeBase64(body.message);\n\n // Policy check\n if (policy?.validateMessage) {\n const allowed = await policy.validateMessage(messageBytes, request);\n if (!allowed) {\n return errorResponse('POLICY_VIOLATION', 'Message rejected by policy', 403);\n }\n }\n\n const signature = await signer.signMessage(messageBytes);\n const response: SignMessageResponse = {\n signature: encodeBase64(signature),\n };\n return jsonResponse(response);\n }\n\n case 'signAndSendTransaction': {\n if (!rpc) {\n return errorResponse('INVALID_OPERATION', 'signAndSendTransaction not enabled', 400);\n }\n\n if (!body.transaction) {\n return errorResponse('INVALID_REQUEST', 'Missing transaction field', 400);\n }\n\n const txBytes = decodeBase64(body.transaction);\n\n // Policy check\n if (policy?.validateTransaction) {\n const allowed = await policy.validateTransaction(txBytes, request);\n if (!allowed) {\n return errorResponse('POLICY_VIOLATION', 'Transaction rejected by policy', 403);\n }\n }\n\n // Sign\n const signedTx = await signer.signTransaction(txBytes);\n\n // Send\n try {\n const signature = await sendTransaction(rpc, signedTx);\n const response: SignAndSendTransactionResponse = { signature };\n return jsonResponse(response);\n } catch (error) {\n return errorResponse(\n 'SEND_FAILED',\n error instanceof Error ? error.message : 'Failed to send transaction',\n 500,\n );\n }\n }\n\n default:\n return errorResponse(\n 'INVALID_OPERATION',\n `Unknown operation: ${(body as { operation: string }).operation}`,\n 400,\n );\n }\n } catch (error) {\n console.error('[connector/server] POST error:', error);\n\n // Check for known signer errors\n if (error instanceof Error) {\n if (error.message.includes('rate limit') || error.message.includes('429')) {\n return errorResponse('PROVIDER_ERROR', 'Rate limited, please retry', 429);\n }\n }\n\n return errorResponse('SIGNING_FAILED', error instanceof Error ? error.message : 'Signing failed', 500);\n }\n }\n\n return { GET, POST };\n}\n"]}
@@ -661,9 +661,37 @@ type Listener = (s: ConnectorState) => void;
661
661
  /**
662
662
  * Connector configuration options
663
663
  */
664
+ interface WalletDisplayConfig {
665
+ /**
666
+ * Explicit allowlist of wallet display names to expose as connectors.
667
+ *
668
+ * - Matching is case-insensitive and uses exact name equality (after trimming).
669
+ * - When provided and non-empty, only wallets in this list are shown/available.
670
+ */
671
+ allowList?: string[];
672
+ /**
673
+ * Denylist of wallet display names to hide/remove.
674
+ *
675
+ * - Matching is case-insensitive and uses exact name equality (after trimming).
676
+ * - Deny wins over allow/featured when the same wallet appears in multiple lists.
677
+ */
678
+ denyList?: string[];
679
+ /**
680
+ * Wallets to prioritize to the top of the list (in the provided order).
681
+ *
682
+ * - Matching is case-insensitive and uses exact name equality (after trimming).
683
+ * - Does not filter wallets by itself; it only reorders remaining wallets.
684
+ */
685
+ featured?: string[];
686
+ }
664
687
  interface ConnectorConfig {
665
688
  autoConnect?: boolean;
666
689
  debug?: boolean;
690
+ /**
691
+ * Wallet list controls for Wallet Standard auto-discovery.
692
+ * This affects which detected wallets are exposed as connectors (and therefore selectable / autoConnect-able).
693
+ */
694
+ wallets?: WalletDisplayConfig;
667
695
  /** Storage configuration using enhanced storage adapters */
668
696
  storage?: {
669
697
  account: StorageAdapter<string | undefined>;
@@ -700,6 +728,11 @@ interface ConnectorConfig {
700
728
  * @see https://docs.walletconnect.network/wallet-sdk/chain-support/solana
701
729
  */
702
730
  walletConnect?: WalletConnectConfig;
731
+ /**
732
+ * Additional wallets to include alongside Wallet Standard wallets.
733
+ * Use this to add remote/server-backed signers created via `createRemoteSignerWallet()`.
734
+ */
735
+ additionalWallets?: Wallet[];
703
736
  }
704
737
  /**
705
738
  * Health check information for connector diagnostics
@@ -991,6 +1024,16 @@ interface DefaultConfigOptions {
991
1024
  * @see https://docs.walletconnect.network/wallet-sdk/chain-support/solana
992
1025
  */
993
1026
  walletConnect?: boolean | SimplifiedWalletConnectConfig;
1027
+ /**
1028
+ * Additional wallets to include alongside Wallet Standard wallets.
1029
+ * Use this to add remote/server-backed signers created via `createRemoteSignerWallet()`.
1030
+ */
1031
+ additionalWallets?: Wallet[];
1032
+ /**
1033
+ * Optional wallet display controls for Wallet Standard auto-discovery.
1034
+ * Use this to filter/prioritize which detected wallets are exposed as connectors.
1035
+ */
1036
+ wallets?: WalletDisplayConfig;
994
1037
  }
995
1038
  /**
996
1039
  * Simplified WalletConnect configuration
@@ -1574,4 +1617,4 @@ declare const ready: Promise<void>;
1574
1617
  */
1575
1618
  declare function getWalletsRegistry(): WalletsRegistry;
1576
1619
 
1577
- export { type WalletConnectMetadata as $, type AccountInfo as A, isWalletStatusError as B, ConnectorProvider as C, type DefaultConfigOptions as D, type ExtendedConnectorConfig as E, toLegacyWalletState as F, type WalletConnector as G, type WalletStatusDisconnected as H, INITIAL_WALLET_STATUS as I, type WalletStatusConnecting as J, type WalletStatusConnected as K, type WalletStatusError as L, type MobileWalletAdapterConfig as M, WalletErrorType as N, isWalletError as O, createWalletError as P, type WalletError as Q, type RegisterMwaConfig as R, type SimplifiedWalletConnectConfig as S, getPublicSolanaRpcUrl as T, createSolanaClient as U, type SolanaClusterMoniker as V, type WalletInfo as W, type ModifiedClusterUrl as X, type SolanaClient as Y, type CreateSolanaClientArgs as Z, type WalletConnectConfig as _, useConnectorClient as a, type WalletConnectTransport as a0, type WalletName as a1, type AccountAddress as a2, isWalletName as a3, isAccountAddress as a4, type CoinGeckoConfig as a5, type ConnectorHealth as a6, type ConnectorDebugMetrics as a7, type ConnectorDebugState as a8, type Listener as a9, getClusterExplorerUrl as aA, getTransactionUrl as aB, getAddressUrl as aC, getTokenUrl as aD, getBlockUrl as aE, isMainnetCluster as aF, isDevnetCluster as aG, isTestnetCluster as aH, isLocalCluster as aI, getClusterName as aJ, getClusterType as aK, getClusterChainId as aL, getChainIdForWalletStandard as aM, type ConnectorEvent as aa, type ConnectorEventListener as ab, type StorageAdapter as ac, type StorageOptions as ad, type EnhancedStorageAccountOptions as ae, type EnhancedStorageClusterOptions as af, type EnhancedStorageWalletOptions as ag, type EnhancedStorageWalletStateOptions as ah, type PersistedWalletState as ai, type WalletConnectSolanaAccount as aj, type WalletConnectSignMessageParams as ak, type WalletConnectSignMessageResult as al, type WalletConnectSignTransactionParams as am, type WalletConnectSignTransactionResult as an, type WalletConnectSignAllTransactionsParams as ao, type WalletConnectSignAllTransactionsResult as ap, type WalletConnectSignAndSendTransactionParams as aq, type WalletConnectSignAndSendTransactionResult as ar, ClipboardErrorType as as, type ClipboardResult as at, type CopyOptions as au, isClipboardAvailable as av, copyToClipboard as aw, copyAddressToClipboard as ax, copySignatureToClipboard as ay, getClusterRpcUrl as az, getDefaultMobileConfig as b, type ConnectorSnapshot as c, type ConnectorConfig as d, type ConnectorState as e, type WalletStandardWallet as f, getDefaultConfig as g, type WalletStandardAccount as h, type WalletConnectorId as i, type WalletConnectorMetadata as j, type WalletSession as k, type WalletStatus as l, type SessionAccount as m, type ConnectOptions as n, createConnectorId as o, isWalletConnectorId as p, isConnected as q, isConnecting as r, isDisconnected as s, type ClusterType as t, useConnector as u, ConnectorClient as v, getWalletsRegistry as w, ready as x, getWalletNameFromConnectorId as y, isStatusError as z };
1620
+ export { type WalletConnectConfig as $, type AccountInfo as A, isStatusError as B, ConnectorProvider as C, type DefaultConfigOptions as D, type ExtendedConnectorConfig as E, isWalletStatusError as F, toLegacyWalletState as G, type WalletConnector as H, INITIAL_WALLET_STATUS as I, type WalletStatusDisconnected as J, type WalletStatusConnecting as K, type WalletStatusConnected as L, type MobileWalletAdapterConfig as M, type WalletStatusError as N, WalletErrorType as O, isWalletError as P, createWalletError as Q, type RegisterMwaConfig as R, type SimplifiedWalletConnectConfig as S, type WalletError as T, getPublicSolanaRpcUrl as U, createSolanaClient as V, type WalletInfo as W, type SolanaClusterMoniker as X, type ModifiedClusterUrl as Y, type SolanaClient as Z, type CreateSolanaClientArgs as _, useConnectorClient as a, type WalletConnectMetadata as a0, type WalletConnectTransport as a1, type WalletName as a2, type AccountAddress as a3, isWalletName as a4, isAccountAddress as a5, type CoinGeckoConfig as a6, type ConnectorHealth as a7, type ConnectorDebugMetrics as a8, type ConnectorDebugState as a9, getClusterRpcUrl as aA, getClusterExplorerUrl as aB, getTransactionUrl as aC, getAddressUrl as aD, getTokenUrl as aE, getBlockUrl as aF, isMainnetCluster as aG, isDevnetCluster as aH, isTestnetCluster as aI, isLocalCluster as aJ, getClusterName as aK, getClusterType as aL, getClusterChainId as aM, getChainIdForWalletStandard as aN, type Listener as aa, type ConnectorEvent as ab, type ConnectorEventListener as ac, type StorageAdapter as ad, type StorageOptions as ae, type EnhancedStorageAccountOptions as af, type EnhancedStorageClusterOptions as ag, type EnhancedStorageWalletOptions as ah, type EnhancedStorageWalletStateOptions as ai, type PersistedWalletState as aj, type WalletConnectSolanaAccount as ak, type WalletConnectSignMessageParams as al, type WalletConnectSignMessageResult as am, type WalletConnectSignTransactionParams as an, type WalletConnectSignTransactionResult as ao, type WalletConnectSignAllTransactionsParams as ap, type WalletConnectSignAllTransactionsResult as aq, type WalletConnectSignAndSendTransactionParams as ar, type WalletConnectSignAndSendTransactionResult as as, ClipboardErrorType as at, type ClipboardResult as au, type CopyOptions as av, isClipboardAvailable as aw, copyToClipboard as ax, copyAddressToClipboard as ay, copySignatureToClipboard as az, getDefaultMobileConfig as b, type ConnectorSnapshot as c, type ConnectorConfig as d, type ConnectorState as e, type WalletDisplayConfig as f, getDefaultConfig as g, type WalletStandardWallet as h, type WalletStandardAccount as i, type WalletConnectorId as j, type WalletConnectorMetadata as k, type WalletSession as l, type WalletStatus as m, type SessionAccount as n, type ConnectOptions as o, createConnectorId as p, isWalletConnectorId as q, isConnected as r, isConnecting as s, isDisconnected as t, useConnector as u, type ClusterType as v, ConnectorClient as w, getWalletsRegistry as x, ready as y, getWalletNameFromConnectorId as z };