@emblemvault/auth-sdk 2.3.17 → 2.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/emblem-auth.min.js +1 -1
- package/dist/emblem-auth.min.js.map +1 -1
- package/dist/emblem-auth.umd.js +1 -1
- package/dist/emblem-auth.umd.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/signers/index.js +1 -1
- package/dist/signers/index.js.map +1 -1
- package/dist/signers/index.mjs +1 -1
- package/dist/signers/index.mjs.map +1 -1
- package/dist/signers/viem.d.ts.map +1 -1
- package/dist/signers/viem.js +1 -1
- package/dist/signers/viem.js.map +1 -1
- package/dist/signers/viem.mjs +1 -1
- package/dist/signers/viem.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viem.mjs","sources":["../../src/signers/http.ts","../../src/signers/validation.ts","../../src/signers/utils.ts","../../src/signers/viem.ts","../../src/signers/vault.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 } from '../types/signers';\n\n/**\n * Environment detection utilities for warning about unsafe usage patterns\n */\n\n/**\n * Detect if code is running in a browser environment\n */\nexport function isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js server environment\n */\nexport function isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null\n );\n}\n\n/**\n * Validate baseUrl format\n */\nexport function validateBaseUrl(baseUrl?: string): void {\n if (!baseUrl) return; // undefined is ok, will use default\n\n if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n throw new Error('baseUrl must be a valid HTTP(S) URL');\n }\n\n // Warn about http (not https)\n if (\n baseUrl.startsWith('http://') &&\n !baseUrl.includes('localhost') &&\n !baseUrl.includes('127.0.0.1')\n ) {\n console.warn(\n '[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.'\n );\n }\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function validateEthereumAddress(address: string): void {\n if (!address || typeof address !== 'string') {\n throw new Error('Address is required');\n }\n\n if (!address.startsWith('0x')) {\n throw new Error('Address must start with 0x');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {\n throw new Error('Invalid Ethereum address format');\n }\n}\n\n/**\n * Validate vault ID\n */\nexport function validateVaultId(vaultId: string): void {\n if (!vaultId || typeof vaultId !== 'string') {\n throw new Error('vaultId is required');\n }\n\n if (vaultId.trim() === '') {\n throw new Error('vaultId cannot be empty');\n }\n}\n\n/**\n * Safe number conversion with bounds checking\n */\nexport function toSafeNumber(value: unknown, fieldName: string): number {\n const num = Number(value);\n\n if (!Number.isSafeInteger(num)) {\n throw new Error(\n `${fieldName} value ${value} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`\n );\n }\n\n return num;\n}\n\n/**\n * Extended config with security options\n */\nexport interface SignerSecurityConfig extends SignerConfig {\n /**\n * Enable debug logging for security-related checks\n * @default false\n */\n debugSecurity?: boolean;\n}\n\n/**\n * Validate signer configuration\n */\nexport function validateSignerConfig(config: SignerSecurityConfig): void {\n // Validate auth: require at least one method\n const hasJwt = !!config.jwt;\n const hasGetJwt = typeof config.getJwt === 'function';\n const hasHeaders = typeof config.getAuthHeaders === 'function';\n const hasSdk = !!config.sdk && typeof config.sdk.getSession === 'function';\n const hasApiKey = !!config.apiKey;\n\n if (!hasJwt && !hasGetJwt && !hasHeaders && !hasSdk && !hasApiKey) {\n throw new Error('Authentication required: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey');\n }\n\n // Validate baseUrl if provided\n if (config.baseUrl) {\n validateBaseUrl(config.baseUrl);\n }\n\n // Security audit logging\n if (config.debugSecurity) {\n console.log('[Emblem Security Debug]', {\n environment: isBrowserEnvironment() ? 'browser' : 'node',\n hasBaseUrl: !!config.baseUrl,\n timestamp: new Date().toISOString(),\n });\n }\n}\n","import type { Hex } from '../types/signers';\nimport { toSafeNumber } from './validation';\n\nexport function toHexIfBigInt(v: unknown): unknown {\n return typeof v === 'bigint' ? '0x' + v.toString(16) : v;\n}\n\n/**\n * viem txs sometimes have bigint / hex / optional fields. Ethers serializers\n * accept hex strings for numeric fields. Normalize where helpful.\n */\nexport function normalizeTxForEmblem(tx: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...tx };\n\n if (out.value !== undefined) out.value = toHexIfBigInt(out.value);\n if (out.gas !== undefined) {\n out.gasLimit = toHexIfBigInt(out.gas);\n delete out.gas;\n }\n if (out.gasLimit !== undefined) out.gasLimit = toHexIfBigInt(out.gasLimit);\n if (out.gasPrice !== undefined) out.gasPrice = toHexIfBigInt(out.gasPrice);\n if (out.maxFeePerGas !== undefined) out.maxFeePerGas = toHexIfBigInt(out.maxFeePerGas);\n if (out.maxPriorityFeePerGas !== undefined)\n out.maxPriorityFeePerGas = toHexIfBigInt(out.maxPriorityFeePerGas);\n if (out.nonce !== undefined) out.nonce = toSafeNumber(out.nonce, 'nonce');\n if (out.chainId !== undefined) out.chainId = toSafeNumber(out.chainId, 'chainId');\n\n // Some backends only accept legacy fields; fold EIP-1559 into gasPrice and drop unsupported keys\n if (out.maxFeePerGas !== undefined || out.maxPriorityFeePerGas !== undefined) {\n if (out.gasPrice === undefined && out.maxFeePerGas !== undefined) {\n out.gasPrice = out.maxFeePerGas;\n }\n delete out.maxFeePerGas;\n delete out.maxPriorityFeePerGas;\n }\n\n // Remove fields commonly unsupported by legacy serializers\n delete out.type;\n delete out.accessList;\n delete out.account;\n delete out.chain;\n delete out.from;\n\n return out;\n}\n\nexport function isHexString(value: unknown): value is Hex {\n return typeof value === 'string' && /^0x[0-9a-fA-F]*$/.test(value);\n}\n\nexport function bytesToHex(bytes: ArrayLike<number>): Hex {\n let out = '0x';\n for (let i = 0; i < bytes.length; i++) {\n out += (bytes[i] as number).toString(16).padStart(2, '0');\n }\n return out as Hex;\n}\n","import type { Hex, SignerConfig, SignerVaultInfo } from '../types/signers';\nimport { emblemPost } from './http';\nimport { bytesToHex, isHexString, normalizeTxForEmblem } from './utils';\nimport { fetchVaultInfo } from './vault';\n\n// Minimal viem types to avoid hard dependency\ninterface ViemAccount {\n address: Hex;\n signMessage: (args: { message: unknown }) => Promise<Hex>;\n signTypedData: (typedData: unknown) => Promise<Hex>;\n signTransaction: (tx: unknown, opts?: unknown) => Promise<Hex>;\n type: 'local';\n source: 'custom';\n publicKey?: Hex;\n}\n\nexport async function toViemAccount(\n config: SignerConfig,\n infoOverride?: SignerVaultInfo\n): Promise<ViemAccount> {\n const info = infoOverride ?? (await fetchVaultInfo(config));\n const { evmAddress, vaultId } = info;\n\n // Dynamically import viem's toAccount\n // String concatenation prevents bundlers from statically analyzing the import\n // DO NOT CHANGE THIS PATTERN - using a literal import('viem/accounts') breaks Next.js/Webpack builds\n // when viem is not installed. The variable indirection is intentional. - Shannon\n const moduleName = 'viem/accounts';\n const { toAccount } = await import(/* @vite-ignore */ moduleName);\n\n return toAccount({\n address: evmAddress,\n\n async signMessage({ message }: { message: unknown }): Promise<Hex> {\n let payload: string;\n let isRaw = false;\n\n if (typeof message === 'string') {\n payload = message;\n isRaw = false;\n } else if (message && typeof (message as { raw?: unknown }).raw !== 'undefined') {\n const raw = (message as { raw: unknown }).raw;\n payload = typeof raw === 'string' ? raw : bytesToHex(raw as ArrayLike<number>);\n isRaw = true;\n } else if (message instanceof Uint8Array) {\n payload = bytesToHex(message);\n isRaw = false;\n } else if (isHexString(message)) {\n payload = message as string;\n isRaw = false;\n } else {\n // Don't silently convert objects to \"[object Object]\"\n throw new Error(\n `Unsupported message type: ${typeof message}. Expected string, Uint8Array, or hex string.`\n );\n }\n\n const data = await emblemPost<{\n signerAddress: string;\n signature: Hex;\n }>('/sign-eth-message', { vaultId, message: payload, raw: isRaw }, config);\n\n return data.signature;\n },\n\n async signTypedData(typedData: unknown): Promise<Hex> {\n const { domain, types, message } = typedData as {\n domain: unknown;\n types: unknown;\n message: unknown;\n };\n const data = await emblemPost<{\n signerAddress: string;\n signature: Hex;\n }>('/sign-typed-message', { vaultId, domain, types, message }, config);\n\n return data.signature;\n },\n\n async signTransaction(tx: unknown, _opts?: unknown): Promise<Hex> {\n const normalizedTx = normalizeTxForEmblem(tx as Record<string, unknown>);\n\n const data = await emblemPost<{\n signedTransaction: Hex;\n }>('/sign-eth-tx', { vaultId, transaction: normalizedTx }, config);\n\n return data.signedTransaction;\n },\n }) as ViemAccount;\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"],"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","toSafeNumber","fieldName","num","Number","isSafeInteger","MAX_SAFE_INTEGER","toHexIfBigInt","v","bytesToHex","bytes","out","i","length","padStart","toViemAccount","infoOverride","info","data","vaultId","evmAddress","String","startsWith","tokenId","address","created_by","fetchVaultInfo","toAccount","import","signMessage","message","payload","isRaw","raw","Uint8Array","test","signature","signTypedData","typedData","domain","types","signTransaction","tx","_opts","normalizedTx","gas","gasLimit","gasPrice","maxFeePerGas","maxPriorityFeePerGas","nonce","chainId","type","accessList","account","chain","from","normalizeTxForEmblem","transaction","signedTransaction"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"viem.mjs","sources":["../../src/signers/http.ts","../../src/signers/validation.ts","../../src/signers/utils.ts","../../src/signers/viem.ts","../../src/signers/vault.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 } from '../types/signers';\n\n/**\n * Environment detection utilities for warning about unsafe usage patterns\n */\n\n/**\n * Detect if code is running in a browser environment\n */\nexport function isBrowserEnvironment(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're in a Node.js server environment\n */\nexport function isNodeEnvironment(): boolean {\n return (\n typeof process !== 'undefined' && process.versions != null && process.versions.node != null\n );\n}\n\n/**\n * Validate baseUrl format\n */\nexport function validateBaseUrl(baseUrl?: string): void {\n if (!baseUrl) return; // undefined is ok, will use default\n\n if (!baseUrl.startsWith('http://') && !baseUrl.startsWith('https://')) {\n throw new Error('baseUrl must be a valid HTTP(S) URL');\n }\n\n // Warn about http (not https)\n if (\n baseUrl.startsWith('http://') &&\n !baseUrl.includes('localhost') &&\n !baseUrl.includes('127.0.0.1')\n ) {\n console.warn(\n '[Emblem Security Warning] baseUrl uses HTTP instead of HTTPS. This is insecure for production use.'\n );\n }\n}\n\n/**\n * Validate Ethereum address format\n */\nexport function validateEthereumAddress(address: string): void {\n if (!address || typeof address !== 'string') {\n throw new Error('Address is required');\n }\n\n if (!address.startsWith('0x')) {\n throw new Error('Address must start with 0x');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {\n throw new Error('Invalid Ethereum address format');\n }\n}\n\n/**\n * Validate vault ID\n */\nexport function validateVaultId(vaultId: string): void {\n if (!vaultId || typeof vaultId !== 'string') {\n throw new Error('vaultId is required');\n }\n\n if (vaultId.trim() === '') {\n throw new Error('vaultId cannot be empty');\n }\n}\n\n/**\n * Safe number conversion with bounds checking\n */\nexport function toSafeNumber(value: unknown, fieldName: string): number {\n const num = Number(value);\n\n if (!Number.isSafeInteger(num)) {\n throw new Error(\n `${fieldName} value ${value} exceeds safe integer range (max: ${Number.MAX_SAFE_INTEGER})`\n );\n }\n\n return num;\n}\n\n/**\n * Extended config with security options\n */\nexport interface SignerSecurityConfig extends SignerConfig {\n /**\n * Enable debug logging for security-related checks\n * @default false\n */\n debugSecurity?: boolean;\n}\n\n/**\n * Validate signer configuration\n */\nexport function validateSignerConfig(config: SignerSecurityConfig): void {\n // Validate auth: require at least one method\n const hasJwt = !!config.jwt;\n const hasGetJwt = typeof config.getJwt === 'function';\n const hasHeaders = typeof config.getAuthHeaders === 'function';\n const hasSdk = !!config.sdk && typeof config.sdk.getSession === 'function';\n const hasApiKey = !!config.apiKey;\n\n if (!hasJwt && !hasGetJwt && !hasHeaders && !hasSdk && !hasApiKey) {\n throw new Error('Authentication required: provide jwt, getJwt(), getAuthHeaders(), sdk, or apiKey');\n }\n\n // Validate baseUrl if provided\n if (config.baseUrl) {\n validateBaseUrl(config.baseUrl);\n }\n\n // Security audit logging\n if (config.debugSecurity) {\n console.log('[Emblem Security Debug]', {\n environment: isBrowserEnvironment() ? 'browser' : 'node',\n hasBaseUrl: !!config.baseUrl,\n timestamp: new Date().toISOString(),\n });\n }\n}\n","import type { Hex } from '../types/signers';\nimport { toSafeNumber } from './validation';\n\nexport function toHexIfBigInt(v: unknown): unknown {\n return typeof v === 'bigint' ? '0x' + v.toString(16) : v;\n}\n\n/**\n * viem txs sometimes have bigint / hex / optional fields. Ethers serializers\n * accept hex strings for numeric fields. Normalize where helpful.\n */\nexport function normalizeTxForEmblem(tx: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = { ...tx };\n\n if (out.value !== undefined) out.value = toHexIfBigInt(out.value);\n if (out.gas !== undefined) {\n out.gasLimit = toHexIfBigInt(out.gas);\n delete out.gas;\n }\n if (out.gasLimit !== undefined) out.gasLimit = toHexIfBigInt(out.gasLimit);\n if (out.gasPrice !== undefined) out.gasPrice = toHexIfBigInt(out.gasPrice);\n if (out.maxFeePerGas !== undefined) out.maxFeePerGas = toHexIfBigInt(out.maxFeePerGas);\n if (out.maxPriorityFeePerGas !== undefined)\n out.maxPriorityFeePerGas = toHexIfBigInt(out.maxPriorityFeePerGas);\n if (out.nonce !== undefined) out.nonce = toSafeNumber(out.nonce, 'nonce');\n if (out.chainId !== undefined) out.chainId = toSafeNumber(out.chainId, 'chainId');\n\n // Some backends only accept legacy fields; fold EIP-1559 into gasPrice and drop unsupported keys\n if (out.maxFeePerGas !== undefined || out.maxPriorityFeePerGas !== undefined) {\n if (out.gasPrice === undefined && out.maxFeePerGas !== undefined) {\n out.gasPrice = out.maxFeePerGas;\n }\n delete out.maxFeePerGas;\n delete out.maxPriorityFeePerGas;\n }\n\n // Remove fields commonly unsupported by legacy serializers\n delete out.type;\n delete out.accessList;\n delete out.account;\n delete out.chain;\n delete out.from;\n\n return out;\n}\n\nexport function isHexString(value: unknown): value is Hex {\n return typeof value === 'string' && /^0x[0-9a-fA-F]*$/.test(value);\n}\n\nexport function bytesToHex(bytes: ArrayLike<number>): Hex {\n let out = '0x';\n for (let i = 0; i < bytes.length; i++) {\n out += (bytes[i] as number).toString(16).padStart(2, '0');\n }\n return out as Hex;\n}\n","import type { Hex, SignerConfig, SignerVaultInfo } from '../types/signers';\nimport { emblemPost } from './http';\nimport { bytesToHex, isHexString, normalizeTxForEmblem } from './utils';\nimport { fetchVaultInfo } from './vault';\n\n// Minimal viem types to avoid hard dependency\ninterface ViemAccount {\n address: Hex;\n signMessage: (args: { message: unknown }) => Promise<Hex>;\n signTypedData: (typedData: unknown) => Promise<Hex>;\n signTransaction: (tx: unknown, opts?: unknown) => Promise<Hex>;\n type: 'local';\n source: 'custom';\n publicKey?: Hex;\n}\n\nexport async function toViemAccount(\n config: SignerConfig,\n infoOverride?: SignerVaultInfo\n): Promise<ViemAccount> {\n const info = infoOverride ?? (await fetchVaultInfo(config));\n const { evmAddress, vaultId } = info;\n\n // Dynamically import viem's toAccount\n // String concatenation prevents bundlers from statically analyzing the import\n // DO NOT CHANGE THIS PATTERN - using a literal import('viem/accounts') breaks Next.js/Webpack builds\n // when viem is not installed. The variable indirection is intentional. - Shannon\n const moduleName = 'viem/accounts';\n const { toAccount } = await import(/* @vite-ignore */ moduleName);\n\n return toAccount({\n address: evmAddress,\n\n async signMessage({ message }: { message: unknown }): Promise<Hex> {\n let payload: string;\n let isRaw = false;\n\n if (typeof message === 'string') {\n payload = message;\n isRaw = false;\n } else if (message && typeof (message as { raw?: unknown }).raw !== 'undefined') {\n const raw = (message as { raw: unknown }).raw;\n payload = typeof raw === 'string' ? raw : bytesToHex(raw as ArrayLike<number>);\n isRaw = true;\n } else if (message instanceof Uint8Array) {\n payload = bytesToHex(message);\n isRaw = false;\n } else if (isHexString(message)) {\n payload = message as string;\n isRaw = false;\n } else {\n // Don't silently convert objects to \"[object Object]\"\n throw new Error(\n `Unsupported message type: ${typeof message}. Expected string, Uint8Array, or hex string.`\n );\n }\n\n const data = await emblemPost<{\n signerAddress: string;\n signature: Hex;\n }>('/sign-eth-message', { vaultId, message: payload, raw: isRaw }, config);\n\n return data.signature;\n },\n\n async signTypedData(typedData: unknown): Promise<Hex> {\n const { domain, types, primaryType, message } = typedData as {\n domain: unknown;\n types: unknown;\n primaryType?: string;\n message: unknown;\n };\n const data = await emblemPost<{\n signerAddress: string;\n signature: Hex;\n }>('/sign-typed-message', { vaultId, domain, types, primaryType, message }, config);\n\n return data.signature;\n },\n\n async signTransaction(tx: unknown, _opts?: unknown): Promise<Hex> {\n const normalizedTx = normalizeTxForEmblem(tx as Record<string, unknown>);\n\n const data = await emblemPost<{\n signedTransaction: Hex;\n }>('/sign-eth-tx', { vaultId, transaction: normalizedTx }, config);\n\n return data.signedTransaction;\n },\n }) as ViemAccount;\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"],"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","toSafeNumber","fieldName","num","Number","isSafeInteger","MAX_SAFE_INTEGER","toHexIfBigInt","v","bytesToHex","bytes","out","i","length","padStart","toViemAccount","infoOverride","info","data","vaultId","evmAddress","String","startsWith","tokenId","address","created_by","fetchVaultInfo","toAccount","import","signMessage","message","payload","isRaw","raw","Uint8Array","test","signature","signTypedData","typedData","domain","types","primaryType","signTransaction","tx","_opts","normalizedTx","gas","gasLimit","gasPrice","maxFeePerGas","maxPriorityFeePerGas","nonce","chainId","type","accessList","account","chain","from","normalizeTxForEmblem","transaction","signedTransaction"],"mappings":"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"}
|