55 lines
1.8 KiB
JavaScript
55 lines
1.8 KiB
JavaScript
/**
|
|
* Validates a single feed object shape (pure function).
|
|
* @param {unknown} item
|
|
* @returns {boolean} True if item has id, name, lat, lng with correct types.
|
|
*/
|
|
export function isValidFeed(item) {
|
|
if (!item || typeof item !== 'object') return false
|
|
const o = /** @type {Record<string, unknown>} */ (item)
|
|
return (
|
|
typeof o.id === 'string'
|
|
&& typeof o.name === 'string'
|
|
&& typeof o.lat === 'number'
|
|
&& typeof o.lng === 'number'
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Returns a safe stream URL (http/https only) or empty string. Prevents javascript:, data:, etc.
|
|
* @param {unknown} url
|
|
* @returns {string} Safe http(s) URL or empty string.
|
|
*/
|
|
export function sanitizeStreamUrl(url) {
|
|
if (typeof url !== 'string' || !url.trim()) return ''
|
|
const u = url.trim()
|
|
if (u.startsWith('https://') || u.startsWith('http://')) return u
|
|
return ''
|
|
}
|
|
|
|
/**
|
|
* Sanitizes a validated feed for API response: safe streamUrl and sourceType only.
|
|
* @param {{ id: string, name: string, lat: number, lng: number, [key: string]: unknown }} feed
|
|
* @returns {{ id: string, name: string, lat: number, lng: number, streamUrl: string, sourceType: string, description?: string }} Sanitized feed for API.
|
|
*/
|
|
export function sanitizeFeedForResponse(feed) {
|
|
return {
|
|
id: feed.id,
|
|
name: feed.name,
|
|
lat: feed.lat,
|
|
lng: feed.lng,
|
|
streamUrl: sanitizeStreamUrl(feed.streamUrl),
|
|
sourceType: feed.sourceType === 'hls' ? 'hls' : 'mjpeg',
|
|
...(typeof feed.description === 'string' ? { description: feed.description } : {}),
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filters and returns only valid feeds from an array (pure function).
|
|
* @param {unknown[]} list
|
|
* @returns {Array<{ id: string, name: string, lat: number, lng: number }>} Array of valid feed objects.
|
|
*/
|
|
export function getValidFeeds(list) {
|
|
if (!Array.isArray(list)) return []
|
|
return list.filter(isValidFeed)
|
|
}
|