{"version":3,"file":"solana.mjs","sources":["../../src/signers/http.ts","../../src/signers/vault.ts","../../src/signers/solana.ts"],"sourcesContent":["import type { SignerConfig } from '../types/signers';\n\nfunction sanitizeErrorMessage(status: number, text: string): string {\n  // Sanitize error messages to avoid leaking sensitive server information\n  let errorMessage = `Emblem signer error ${status}`;\n\n  if (status >= 500) {\n    errorMessage += ': Internal server error';\n  } else if (status === 401 || status === 403) {\n    errorMessage += ': Authentication failed';\n  } else if (status === 404) {\n    errorMessage += ': Resource not found';\n  } else if (status === 405) {\n    errorMessage += ': Method not allowed';\n  } else if (text) {\n    // For 4xx client errors, include limited error details\n    errorMessage += `: ${text.substring(0, 200)}`; // Limit to 200 chars\n  }\n\n  return errorMessage;\n}\n\nasync function resolveAuthHeaders(config: SignerConfig): Promise<Record<string, string>> {\n  // Priority: custom headers -> jwt/getJwt/sdk -> apiKey (deprecated)\n  if (typeof config.getAuthHeaders === 'function') {\n    const h = await config.getAuthHeaders();\n    if (h && typeof h === 'object') return h;\n  }\n\n  const tok =\n    config.jwt ??\n    (typeof config.getJwt === 'function' ? await config.getJwt() : undefined) ??\n    config.sdk?.getSession()?.authToken ??\n    undefined;\n\n  if (tok) {\n    return { Authorization: `Bearer ${tok}` };\n  }\n\n  // apiKey is deprecated but still supported as fallback\n  if (config.apiKey) {\n    return { 'x-api-key': config.apiKey };\n  }\n\n  throw new Error(\n    'No authentication available: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey'\n  );\n}\n\nexport async function emblemPost<T = unknown>(\n  path: string,\n  body: unknown,\n  config: SignerConfig\n): Promise<T> {\n  const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n  const authHeaders = await resolveAuthHeaders(config);\n  const res = await fetch(`${baseUrl}${path}`, {\n    method: 'POST',\n    headers: {\n      'content-type': 'application/json',\n      ...authHeaders,\n    },\n    body: JSON.stringify(body, (_key: string, value: unknown) =>\n      typeof value === 'bigint' ? value.toString() : value\n    ),\n  });\n\n  if (!res.ok) {\n    const text = await res.text().catch(() => '');\n    throw new Error(sanitizeErrorMessage(res.status, text));\n  }\n\n  return res.json() as Promise<T>;\n}\n\nexport async function emblemGet<T = unknown>(path: string, config: SignerConfig): Promise<T> {\n  const baseUrl = config.baseUrl ?? 'https://api.emblemvault.ai';\n  const authHeaders = await resolveAuthHeaders(config);\n  const res = await fetch(`${baseUrl}${path}`, {\n    method: 'GET',\n    headers: authHeaders,\n  });\n\n  if (!res.ok) {\n    const text = await res.text().catch(() => '');\n    throw new Error(sanitizeErrorMessage(res.status, text));\n  }\n\n  return res.json() as Promise<T>;\n}\n","import type { SignerConfig, SignerVaultInfo, Hex } from '../types/signers';\nimport { emblemPost } from './http';\n\nexport async function fetchVaultInfo(config: SignerConfig): Promise<SignerVaultInfo> {\n  // Note: The server only supports POST for /vault/info\n  const data: Partial<{\n    vaultId: string;\n    address: string;\n    evmAddress: Hex;\n    created_by?: string;\n  }> = await emblemPost('/vault/info', {}, config);\n\n  // Validate required response data (vaultId + evmAddress are required for EVM)\n  if (!data || !data.vaultId || !data.evmAddress) {\n    throw new Error('Invalid vault info response: missing required fields');\n  }\n\n  if (!String(data.evmAddress).startsWith('0x')) {\n    throw new Error('Invalid evmAddress format in response');\n  }\n\n  return {\n    vaultId: data.vaultId,\n    tokenId: data.vaultId,\n    address: data.address || '', // Solana address may be absent; keep optional\n    evmAddress: data.evmAddress as Hex,\n    created_by: data.created_by,\n  };\n}\n","import type { SignerConfig, SignerVaultInfo } from '../types/signers';\nimport { emblemPost } from './http';\nimport { fetchVaultInfo } from './vault';\n\n// @solana/web3.js compatible interfaces\nexport interface SolanaSignerInterface {\n  publicKey: string;\n  signMessage(message: Uint8Array | string): Promise<Uint8Array>;\n  signTransaction(transaction: unknown): Promise<unknown>;\n}\n\n// For Solana Kit compatibility\nexport interface SolanaKitSignerInterface {\n  publicKey: string;\n  signMessage(message: Uint8Array | string): Promise<Uint8Array>;\n  signTransaction(transaction: unknown): Promise<unknown>;\n}\n\nexport class EmblemSolanaSigner implements SolanaSignerInterface, SolanaKitSignerInterface {\n  readonly publicKey: string; // base58 address\n  private readonly config: SignerConfig;\n  private readonly vaultId: string;\n\n  constructor(config: SignerConfig, vaultInfo: SignerVaultInfo) {\n    this.publicKey = vaultInfo.address;\n    this.config = config;\n    this.vaultId = vaultInfo.vaultId;\n  }\n\n  async signMessage(message: Uint8Array | string): Promise<Uint8Array> {\n    // Convert message to bytes if it's a string\n    const messageBytes = typeof message === 'string' ? new TextEncoder().encode(message) : message;\n\n    // Convert to base64 for API transmission\n    const messageBase64 = btoa(String.fromCharCode(...messageBytes));\n\n    const response = await emblemPost<{ signature: string }>(\n      '/sign-solana-message',\n      { vaultId: this.vaultId, message: messageBase64 },\n      this.config\n    );\n\n    // The server returns a signature - could be base64, base58, or hex\n    // Let's check what format we're getting and handle accordingly\n\n    // Try to decode as base58 first (Solana standard)\n    try {\n      // Use @solana/web3.js bs58 decoder if available, otherwise fallback\n      const win = typeof window !== 'undefined' ? (window as unknown as { bs58?: { decode(s: string): Uint8Array } }) : undefined;\n      if (win?.bs58) {\n        return win.bs58.decode(response.signature);\n      }\n      // For Node.js environments or if bs58 is not globally available\n      // The signature might be base64 encoded\n      const signatureBytes = Uint8Array.from(atob(response.signature), (c) => c.charCodeAt(0));\n      return signatureBytes;\n    } catch (e) {\n      // If base64 decode fails, try treating as hex\n      if (response.signature.startsWith('0x')) {\n        const hex = response.signature.slice(2);\n        const bytes = new Uint8Array(hex.length / 2);\n        for (let i = 0; i < hex.length; i += 2) {\n          bytes[i / 2] = parseInt(hex.substr(i, 2), 16);\n        }\n        return bytes;\n      }\n      throw new Error(`Unable to decode signature format: ${e}`);\n    }\n  }\n\n  async signTransaction(transaction: unknown): Promise<unknown> {\n    // Serialize transaction for API transmission\n    const serializedTransaction = this.serializeTransaction(transaction);\n\n    const response = await emblemPost<{\n      serializedSignedTransaction?: string;\n      signedTransaction?: string;\n    }>(\n      '/sign-solana-transaction',\n      {\n        vaultId: this.vaultId,\n        transactionToSign: serializedTransaction, // Pass the base64 string directly\n        broadcast: false, // Don't broadcast, just sign\n        versionedTransaction: true, // Match API test format\n      },\n      this.config\n    );\n\n    // Parse the signed transaction response - handle both response formats\n    const signedTxData = response.serializedSignedTransaction || response.signedTransaction;\n    if (!signedTxData) {\n      throw new Error('No signed transaction data received from server');\n    }\n\n    return this.deserializeTransaction(signedTxData);\n  }\n\n  private serializeTransaction(tx: unknown): string {\n    // Handle different transaction formats from @solana/web3.js\n    if (tx && typeof tx === 'object') {\n      // For VersionedTransaction or Transaction objects\n      if ((tx as { serialize?: () => Uint8Array }).serialize) {\n        // Server expects just the base64 string, not an object\n        const serialized = (tx as { serialize: () => Uint8Array }).serialize();\n        const base64 = btoa(String.fromCharCode(...serialized));\n        return base64;\n      }\n      // For transaction objects with instructions\n      if (\n        (tx as { instructions?: unknown }).instructions ||\n        (tx as { recentBlockhash?: unknown }).recentBlockhash\n      ) {\n        throw new Error(\n          'Cannot serialize unsigned transaction objects. Please use VersionedTransaction.'\n        );\n      }\n    }\n\n    // Fallback: assume it's already a string\n    return tx as string;\n  }\n\n  private deserializeTransaction(signedTxData: unknown): unknown {\n    // If it's already an object (shouldn't happen based on type), handle it\n    if (\n      typeof signedTxData === 'object' &&\n      signedTxData &&\n      (signedTxData as { serializedSignedTransaction?: string }).serializedSignedTransaction\n    ) {\n      signedTxData = (signedTxData as { serializedSignedTransaction: string })\n        .serializedSignedTransaction;\n    }\n\n    // If it's a string, decode from base64\n    if (typeof signedTxData === 'string') {\n      try {\n        // The server returns base64, so decode it\n        const decoded = atob(signedTxData);\n        return new Uint8Array(decoded.split('').map((c) => c.charCodeAt(0)));\n      } catch (e) {\n        console.error('Failed to decode transaction:', e);\n        throw new Error(`Unable to deserialize transaction response: ${e}`);\n      }\n    }\n\n    // If it's already a Uint8Array or other type, return as-is\n    return signedTxData;\n  }\n\n  // Additional utility methods for @solana/web3.js compatibility\n\n  /** Get the vault ID for this signer */\n  getVaultId(): string {\n    return this.vaultId;\n  }\n\n  /** Sign multiple transactions in batch */\n  async signAllTransactions(transactions: unknown[]): Promise<unknown[]> {\n    // Sign each transaction individually for now\n    // Could be optimized with a batch API endpoint in the future\n    const results = [];\n    for (const tx of transactions) {\n      results.push(await this.signTransaction(tx));\n    }\n    return results;\n  }\n\n  /** Check if this signer can sign for a given public key */\n  canSign(publicKey: string): boolean {\n    return publicKey === this.publicKey;\n  }\n\n  /** Sign and optionally broadcast a transaction */\n  async signAndBroadcast(transaction: unknown, broadcast: boolean = true): Promise<string> {\n    // Serialize transaction for API transmission\n    const serializedTransaction = this.serializeTransaction(transaction);\n\n    const response = await emblemPost<{\n      transactionSignature?: string;\n      serializedSignedTransaction?: string;\n    }>(\n      '/sign-solana-transaction',\n      {\n        vaultId: this.vaultId,\n        transactionToSign: serializedTransaction, // Pass the base64 string directly\n        broadcast: broadcast,\n        versionedTransaction: true, // Match API test format\n      },\n      this.config\n    );\n\n    if (broadcast) {\n      // Return the transaction signature\n      if (!response.transactionSignature) {\n        throw new Error('No transaction signature received from broadcast');\n      }\n      return response.transactionSignature;\n    } else {\n      // Return the signed transaction data\n      if (!response.serializedSignedTransaction) {\n        throw new Error('No signed transaction data received from server');\n      }\n      return response.serializedSignedTransaction;\n    }\n  }\n}\n\nexport async function toSolanaWeb3Signer(\n  config: SignerConfig,\n  infoOverride?: SignerVaultInfo\n): Promise<EmblemSolanaSigner> {\n  const info = infoOverride ?? (await fetchVaultInfo(config));\n  return new EmblemSolanaSigner(config, info);\n}\n\nexport async function toSolanaKitSigner(\n  config: SignerConfig,\n  infoOverride?: SignerVaultInfo\n): Promise<EmblemSolanaSigner> {\n  const info = infoOverride ?? (await fetchVaultInfo(config));\n  return new EmblemSolanaSigner(config, info);\n}\n"],"names":["async","emblemPost","path","body","config","baseUrl","authHeaders","getAuthHeaders","h","tok","jwt","getJwt","undefined","sdk","getSession","authToken","Authorization","apiKey","Error","resolveAuthHeaders","res","fetch","method","headers","JSON","stringify","_key","value","toString","ok","text","catch","status","errorMessage","substring","sanitizeErrorMessage","json","fetchVaultInfo","data","vaultId","evmAddress","String","startsWith","tokenId","address","created_by","EmblemSolanaSigner","constructor","vaultInfo","this","publicKey","signMessage","message","messageBytes","TextEncoder","encode","messageBase64","btoa","fromCharCode","response","win","window","bs58","decode","signature","Uint8Array","from","atob","c","charCodeAt","e","hex","slice","bytes","length","i","parseInt","substr","signTransaction","transaction","serializedTransaction","serializeTransaction","transactionToSign","broadcast","versionedTransaction","signedTxData","serializedSignedTransaction","signedTransaction","deserializeTransaction","tx","serialize","serialized","instructions","recentBlockhash","decoded","split","map","console","error","getVaultId","signAllTransactions","transactions","results","push","canSign","signAndBroadcast","transactionSignature","toSolanaWeb3Signer","infoOverride","info","toSolanaKitSigner"],"mappings":"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"}