borsa / nextjs-app /src /lib /api-utils.ts
veteroner's picture
feat: live position monitoring with charts + trading system production ready
656ac31
/**
* Shared API route utility functions.
* Eliminates duplication across stocks, trading-signals, and analysis routes.
*/
/**
* Safely converts an unknown value to a finite number, or returns null.
*/
export function toNumber(value: unknown): number | null {
const n = typeof value === 'number' ? value : Number(value)
return Number.isFinite(n) ? n : null
}
/**
* Picks the first present key from an object.
* Useful when upstream APIs return data under varying field names.
*/
export function pick<T extends Record<string, unknown>>(
obj: T | null | undefined,
keys: string[]
): unknown {
if (!obj) return undefined
for (const k of keys) {
if (k in obj) return obj[k]
}
return undefined
}
/**
* Extracts and validates a stock symbol from Next.js dynamic route params.
* Returns uppercase sanitized symbol or null if invalid.
*/
export async function getSymbolFromParams(
params: Promise<{ symbol: string }> | { symbol: string }
): Promise<string | null> {
const resolved = await params
const raw = resolved?.symbol
if (!raw || typeof raw !== 'string') return null
const symbol = raw.toUpperCase().trim()
// Only allow alphanumeric + dot (e.g. "THYAO", "XU100.IS")
if (!/^[A-Z0-9.]{1,20}$/.test(symbol)) return null
return symbol
}
/**
* Sanitizes upstream error messages to prevent leaking internal details.
* Strips file paths, stack traces, and internal URLs.
*/
export function sanitizeErrorMessage(error: unknown): string {
if (!error) return 'Bilinmeyen hata'
const message = error instanceof Error ? error.message : String(error)
// Strip file paths (unix/windows)
let sanitized = message.replace(/\/[\w./\\-]+\.(ts|js|tsx|jsx|py|json)/gi, '[path]')
// Strip stack traces
sanitized = sanitized.replace(/at\s+\w+.*\(.*\)/g, '')
// Strip internal URLs (keep only the error context)
sanitized = sanitized.replace(/https?:\/\/[^\s"')]+/g, '[url]')
// Truncate to 200 chars
if (sanitized.length > 200) {
sanitized = sanitized.slice(0, 200) + '...'
}
return sanitized.trim() || 'Bilinmeyen hata'
}