/** * Request tracing for Portal API calls. * * Propagation in the Web SDK: * - Browser: High-level methods (backup, recover, sendAsset, provider.request) accept optional * traceId or generate one. They pass it to handleRequestToIframeAndPost (postMessage) or * to fetch headers (X-Portal-Trace-Id). * - Iframe: On each portal:* message, the iframe reads traceId from the message (top-level or * data.traceId), calls setRequestTraceId(traceId), which sets it on Api, Mpc, ZeroX, etc. * All REST and MPC calls made during that request then use the same trace ID (header or reqId). * - After the request completes, clearRequestTraceId() is called so the next message gets a * fresh or caller-provided trace ID. */ /** * HTTP header name for request tracing. * Used by connect-api (client + custodian APIs) in the Web SDK. * Note: Other internal services may use different header names. */ export const X_PORTAL_TRACE_ID_HEADER = 'X-Portal-Trace-Id' /** * Generates a UUID v4 trace ID for request correlation. * Uses crypto.randomUUID() when available; otherwise crypto.getRandomValues() for better * quality than Math.random(); falls back to Math.random() only when no crypto API exists. */ export function generateTraceId(): string { if ( typeof crypto !== 'undefined' && typeof (crypto as Crypto).randomUUID === 'function' ) { return (crypto as Crypto).randomUUID() } if ( typeof crypto !== 'undefined' && typeof (crypto as Crypto).getRandomValues === 'function' ) { return fallbackUuidV4WithCrypto(crypto as Crypto) } return fallbackUuidV4WithMathRandom() } function fallbackUuidV4WithCrypto(crypto: Crypto): string { const bytes = new Uint8Array(16) crypto.getRandomValues(bytes) bytes[6] = (bytes[6]! & 0x0f) | 0x40 bytes[8] = (bytes[8]! & 0x3f) | 0x80 const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('') return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}` } function fallbackUuidV4WithMathRandom(): string { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0 const v = c === 'x' ? r : (r & 0x3) | 0x8 return v.toString(16) }) }