{"version":3,"sources":["../src/theme.ts","../src/urls.ts","../src/server.ts"],"names":[],"mappings":"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","file":"server.cjs","sourcesContent":["export type EmbedTheme = {\n\tprimary?: string;\n\taccent?: string;\n\tbackground?: string;\n\tforeground?: string;\n\tradius?: string;\n\tfontFamily?: string;\n\tmode?: \"light\" | \"dark\";\n};\n\nconst HEX =\n\t/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\nconst COLOR_FN = /^(?:oklch|rgb|rgba|hsl|hsla)\\([0-9a-zA-Z.\\s%,./-]+\\)$/;\nconst RADIUS = /^\\d+(?:\\.\\d+)?(?:px|rem|em)$/;\nconst FONT = /^[a-zA-Z0-9\\s,\"'-]{1,120}$/;\n\nfunction sanitizeColor(value: unknown): string | undefined {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\tif (HEX.test(trimmed) || COLOR_FN.test(trimmed)) return trimmed;\n\treturn undefined;\n}\n\nexport function sanitizeEmbedTheme(value: unknown): EmbedTheme | null {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\treturn null;\n\t}\n\tconst row = value as Record<string, unknown>;\n\tconst theme: EmbedTheme = {};\n\tconst primary = sanitizeColor(row.primary);\n\tconst accent = sanitizeColor(row.accent);\n\tconst background = sanitizeColor(row.background);\n\tconst foreground = sanitizeColor(row.foreground);\n\tif (typeof row.radius === \"string\" && RADIUS.test(row.radius.trim())) {\n\t\ttheme.radius = row.radius.trim();\n\t}\n\tif (typeof row.fontFamily === \"string\" && FONT.test(row.fontFamily.trim())) {\n\t\ttheme.fontFamily = row.fontFamily.trim();\n\t}\n\tif (primary) theme.primary = primary;\n\tif (accent) theme.accent = accent;\n\tif (background) theme.background = background;\n\tif (foreground) theme.foreground = foreground;\n\tif (row.mode === \"light\" || row.mode === \"dark\") theme.mode = row.mode;\n\treturn Object.keys(theme).length > 0 ? theme : null;\n}\n\nexport function encodeEmbedTheme(theme: EmbedTheme): string {\n\tconst json = JSON.stringify(theme);\n\tconst bytes = new TextEncoder().encode(json);\n\tlet binary = \"\";\n\tfor (const byte of bytes) binary += String.fromCharCode(byte);\n\treturn btoa(binary)\n\t\t.replace(/\\+/g, \"-\")\n\t\t.replace(/\\//g, \"_\")\n\t\t.replace(/=+$/, \"\");\n}\n\nexport function embedThemeCssVars(theme: EmbedTheme): Record<string, string> {\n\tconst vars: Record<string, string> = {};\n\tconst accent = theme.accent ?? theme.primary;\n\tif (theme.primary) {\n\t\tvars[\"--livo-primary\"] = theme.primary;\n\t\tvars[\"--primary\"] = theme.primary;\n\t} else if (accent) {\n\t\tvars[\"--livo-primary\"] = accent;\n\t\tvars[\"--primary\"] = accent;\n\t}\n\tif (accent) {\n\t\tvars[\"--livo-accent\"] = accent;\n\t\tvars[\"--accent\"] = accent;\n\t}\n\tif (theme.background) {\n\t\tvars[\"--livo-background\"] = theme.background;\n\t\tvars[\"--background\"] = theme.background;\n\t}\n\tif (theme.foreground) {\n\t\tvars[\"--livo-foreground\"] = theme.foreground;\n\t\tvars[\"--foreground\"] = theme.foreground;\n\t}\n\tif (theme.radius) {\n\t\tvars[\"--livo-radius\"] = theme.radius;\n\t\tvars[\"--radius\"] = theme.radius;\n\t}\n\tif (theme.fontFamily) vars[\"--font-sans\"] = theme.fontFamily;\n\treturn vars;\n}\n\nexport function decodeEmbedTheme(\n\traw: string | null | undefined,\n): EmbedTheme | null {\n\tif (!raw) return null;\n\ttry {\n\t\tconst padded = raw.replace(/-/g, \"+\").replace(/_/g, \"/\");\n\t\tconst pad =\n\t\t\tpadded.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (padded.length % 4));\n\t\tconst binary = atob(padded + pad);\n\t\tconst bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n\t\treturn sanitizeEmbedTheme(JSON.parse(new TextDecoder().decode(bytes)));\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function resolveEmbedThemeInput(\n\tvalue: EmbedTheme | string | null | undefined,\n): EmbedTheme | null {\n\tif (typeof value === \"string\") return decodeEmbedTheme(value);\n\treturn sanitizeEmbedTheme(value ?? null);\n}\n\nexport function applyEmbedTheme(\n\troot: HTMLElement | null,\n\ttheme: EmbedTheme | null,\n): void {\n\tif (!root || !theme) return;\n\tif (theme.mode === \"dark\") root.classList.add(\"dark\");\n\tif (theme.mode === \"light\") root.classList.remove(\"dark\");\n\tfor (const [key, value] of Object.entries(embedThemeCssVars(theme))) {\n\t\troot.style.setProperty(key, value);\n\t}\n\tif (theme.fontFamily) root.style.fontFamily = theme.fontFamily;\n}\n","import { encodeEmbedTheme, type EmbedTheme } from \"./theme\";\n\nexport type UrlOrigins = {\n\tplayerOrigin?: string;\n\tappOrigin?: string;\n};\n\nexport type PlayerUrlOptions = UrlOrigins & {\n\ttheme?: EmbedTheme;\n\tlocale?: string;\n\tautoplay?: boolean;\n\tname?: string;\n\tavatar?: string;\n\t/** Hosted iframe hides comments/Q&A by default. Pass `true` to set `community=1` (in-player drawers). */\n\tcommunity?: boolean;\n};\n\nconst COMMUNITY_HIDDEN_VALUES = new Set([\"0\", \"false\", \"off\", \"hidden\", \"no\"]);\nconst COMMUNITY_SHOWN_VALUES = new Set([\"1\", \"true\", \"on\", \"show\"]);\n\n/** Hosted iframe hides comments/Q&A unless `community=1` (or `showCommunity=1`). */\nexport function embedShowsCommunity(\n\tsearch: string | Pick<URLSearchParams, \"get\">,\n): boolean {\n\tconst params =\n\t\ttypeof search === \"string\" ? new URLSearchParams(search) : search;\n\tconst raw = params.get(\"community\") ?? params.get(\"showCommunity\");\n\tif (raw == null || raw.trim() === \"\") return false;\n\tconst value = raw.trim().toLowerCase();\n\tif (COMMUNITY_HIDDEN_VALUES.has(value)) return false;\n\treturn COMMUNITY_SHOWN_VALUES.has(value);\n}\n\nfunction trimSlash(value: string): string {\n\treturn value.replace(/\\/$/, \"\");\n}\n\nfunction applyPlayerSearch(url: URL, options: PlayerUrlOptions): void {\n\tif (options.locale) url.searchParams.set(\"lang\", options.locale);\n\tif (options.autoplay) url.searchParams.set(\"autoplay\", \"1\");\n\tif (options.theme)\n\t\turl.searchParams.set(\"theme\", encodeEmbedTheme(options.theme));\n\tconst name = options.name?.trim();\n\tif (name) url.searchParams.set(\"name\", name.slice(0, 80));\n\tconst avatar = options.avatar?.trim();\n\tif (avatar) url.searchParams.set(\"avatar\", avatar);\n\tif (options.community === true) url.searchParams.set(\"community\", \"1\");\n\tif (options.community === false) url.searchParams.set(\"community\", \"0\");\n}\n\nexport function playerUrl(\n\tstreamId: string,\n\toptions: PlayerUrlOptions = {},\n): string {\n\tconst origin = trimSlash(options.playerOrigin ?? \"https://player.livo.tv\");\n\tconst url = new URL(`${origin}/${streamId}`);\n\tapplyPlayerSearch(url, options);\n\treturn url.toString();\n}\n\nexport function vodPlayerUrl(\n\tvodId: string,\n\toptions: PlayerUrlOptions = {},\n): string {\n\tconst origin = trimSlash(options.playerOrigin ?? \"https://player.livo.tv\");\n\tconst url = new URL(`${origin}/vod/${vodId}`);\n\tapplyPlayerSearch(url, options);\n\treturn url.toString();\n}\n\nexport function studioGuestUrl(\n\ttoken: string,\n\toptions: UrlOrigins & { theme?: EmbedTheme; embed?: boolean } = {},\n): string {\n\tconst origin = trimSlash(options.appOrigin ?? \"https://app.livo.tv\");\n\tconst url = new URL(`${origin}/studio/join/${token}`);\n\tif (options.embed !== false) url.searchParams.set(\"embed\", \"1\");\n\tif (options.theme)\n\t\turl.searchParams.set(\"theme\", encodeEmbedTheme(options.theme));\n\treturn url.toString();\n}\n\nexport function studioHostUrl(\n\ttoken: string,\n\toptions: UrlOrigins & { theme?: EmbedTheme; embed?: boolean } = {},\n): string {\n\tconst origin = trimSlash(options.appOrigin ?? \"https://app.livo.tv\");\n\tconst url = new URL(`${origin}/studio/host/${token}`);\n\tif (options.embed !== false) url.searchParams.set(\"embed\", \"1\");\n\tif (options.theme)\n\t\turl.searchParams.set(\"theme\", encodeEmbedTheme(options.theme));\n\treturn url.toString();\n}\n","export type LivoServerClientOptions = {\n\tapiUrl?: string;\n\tapiKey: string;\n\tfetchFn?: typeof fetch;\n};\n\nexport class LivoServerClient {\n\tprivate readonly apiUrl: string;\n\tprivate readonly apiKey: string;\n\tprivate readonly fetchFn: typeof fetch;\n\n\tconstructor(options: LivoServerClientOptions) {\n\t\tthis.apiUrl = (options.apiUrl ?? \"https://media-svc.livo.tv\").replace(\n\t\t\t/\\/$/,\n\t\t\t\"\",\n\t\t);\n\t\tthis.apiKey = options.apiKey;\n\t\tthis.fetchFn = options.fetchFn ?? fetch;\n\t}\n\n\tprivate async request<T>(path: string, init: RequestInit = {}): Promise<T> {\n\t\tconst headers = new Headers(init.headers);\n\t\theaders.set(\"X-Api-Key\", this.apiKey);\n\t\theaders.set(\"accept\", \"application/json\");\n\t\tif (init.body && !headers.has(\"content-type\")) {\n\t\t\theaders.set(\"content-type\", \"application/json\");\n\t\t}\n\t\tconst res = await this.fetchFn(`${this.apiUrl}${path}`, {\n\t\t\t...init,\n\t\t\theaders,\n\t\t});\n\t\tconst body: unknown = await res.json().catch(() => ({}));\n\t\tif (!res.ok) {\n\t\t\tconst error = new Error(`Livo API ${res.status}`);\n\t\t\t(error as Error & { status: number; body: unknown }).status = res.status;\n\t\t\t(error as Error & { status: number; body: unknown }).body = body;\n\t\t\tthrow error;\n\t\t}\n\t\treturn body as T;\n\t}\n\n\tcreateStream(input: {\n\t\ttitle: string;\n\t\tmode?: \"instant\" | \"scheduled\";\n\t\tsource?: \"rtmp\" | \"studio\";\n\t\tkind?: \"stream\" | \"webinar\";\n\t\tstartsAt?: number;\n\t\tdurationSeconds?: number;\n\t\tcurtainId?: string;\n\t\tcaptionsEnabled?: boolean;\n\t\tbroadcastEnabled?: boolean;\n\t\trecordingEnabled?: boolean;\n\t}) {\n\t\treturn this.request<{ stream: { id: string } }>(\"/streams\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify(input),\n\t\t});\n\t}\n\n\tgetStream(id: string) {\n\t\treturn this.request<{ stream: { id: string; status: string } }>(\n\t\t\t`/streams/${encodeURIComponent(id)}`,\n\t\t);\n\t}\n\n\tstartStream(id: string) {\n\t\treturn this.request(`/streams/${encodeURIComponent(id)}/start`, {\n\t\t\tmethod: \"POST\",\n\t\t});\n\t}\n\n\tpublishStream(id: string) {\n\t\treturn this.request(`/streams/${encodeURIComponent(id)}/publish`, {\n\t\t\tmethod: \"POST\",\n\t\t});\n\t}\n\n\tpatchStream(\n\t\tid: string,\n\t\tinput: {\n\t\t\ttitle?: string;\n\t\t\tstartsAt?: number | null;\n\t\t\tdurationSeconds?: number | null;\n\t\t\tcurtainId?: string | null;\n\t\t\tcaptionsEnabled?: boolean;\n\t\t\tcommentsEnabled?: boolean;\n\t\t\tcommentsAfterEnd?: boolean;\n\t\t\tqaEnabled?: boolean;\n\t\t\tbroadcastEnabled?: boolean;\n\t\t\trecordingEnabled?: boolean;\n\t\t},\n\t) {\n\t\treturn this.request(`/streams/${encodeURIComponent(id)}`, {\n\t\t\tmethod: \"PATCH\",\n\t\t\tbody: JSON.stringify(input),\n\t\t});\n\t}\n\n\tstopStream(id: string) {\n\t\treturn this.request(`/streams/${encodeURIComponent(id)}/stop`, {\n\t\t\tmethod: \"POST\",\n\t\t});\n\t}\n\n\tlistStreamOutputs(id: string) {\n\t\treturn this.request<{\n\t\t\toutputs: Array<{ id: string; platform: string; streamKeyHint: string }>;\n\t\t}>(`/streams/${encodeURIComponent(id)}/outputs`);\n\t}\n\n\tcreateStreamOutput(\n\t\tid: string,\n\t\tinput: {\n\t\t\tplatform:\n\t\t\t\t\"facebook\" | \"youtube\" | \"twitch\" | \"instagram\" | \"tiktok\" | \"custom\";\n\t\t\tstreamKey: string;\n\t\t\trtmpUrl?: string;\n\t\t\tenabled?: boolean;\n\t\t},\n\t) {\n\t\treturn this.request<{ output: { id: string } }>(\n\t\t\t`/streams/${encodeURIComponent(id)}/outputs`,\n\t\t\t{ method: \"POST\", body: JSON.stringify(input) },\n\t\t);\n\t}\n\n\tpatchStreamOutput(\n\t\tid: string,\n\t\toutputId: string,\n\t\tinput: { enabled?: boolean; rtmpUrl?: string; streamKey?: string },\n\t) {\n\t\treturn this.request(\n\t\t\t`/streams/${encodeURIComponent(id)}/outputs/${encodeURIComponent(outputId)}`,\n\t\t\t{ method: \"PATCH\", body: JSON.stringify(input) },\n\t\t);\n\t}\n\n\tdeleteStreamOutput(id: string, outputId: string) {\n\t\treturn this.request(\n\t\t\t`/streams/${encodeURIComponent(id)}/outputs/${encodeURIComponent(outputId)}`,\n\t\t\t{ method: \"DELETE\" },\n\t\t);\n\t}\n\n\tlistVods() {\n\t\treturn this.request<{ vods: Array<{ id: string; title: string }> }>(\n\t\t\t\"/vods\",\n\t\t);\n\t}\n\n\tcreateVod(input: {\n\t\tfilename: string;\n\t\tcontentType: string;\n\t\tbyteSize: number;\n\t\tsha256: string;\n\t\ttitle?: string;\n\t\treleaseAt?: number | null;\n\t\tcurtainId?: string | null;\n\t\tcaptionsEnabled?: boolean;\n\t\tcommentsEnabled?: boolean;\n\t}) {\n\t\treturn this.request<{\n\t\t\tvodId: string;\n\t\t\tuploadId: string;\n\t\t\tpartSize: number;\n\t\t}>(\"/vods\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify(input),\n\t\t});\n\t}\n\n\trequestVodPartUrl(vodId: string, partNumber: number) {\n\t\treturn this.request<{ uploadUrl: string }>(\n\t\t\t`/vods/${encodeURIComponent(vodId)}/upload-part`,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: JSON.stringify({ partNumber }),\n\t\t\t},\n\t\t);\n\t}\n\n\tcompleteVodUpload(\n\t\tvodId: string,\n\t\tinput: { parts: Array<{ partNumber: number; etag: string }> },\n\t) {\n\t\treturn this.request(`/vods/${encodeURIComponent(vodId)}/complete-upload`, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify(input),\n\t\t});\n\t}\n\n\ttranscodeVod(vodId: string) {\n\t\treturn this.request(`/vods/${encodeURIComponent(vodId)}/transcode`, {\n\t\t\tmethod: \"POST\",\n\t\t});\n\t}\n\n\tenableVodCaptions(vodId: string) {\n\t\treturn this.request(`/vods/${encodeURIComponent(vodId)}/captions`, {\n\t\t\tmethod: \"POST\",\n\t\t});\n\t}\n\n\tlistCurtains() {\n\t\treturn this.request<{ curtains: Array<{ id: string; title: string }> }>(\n\t\t\t\"/curtains\",\n\t\t);\n\t}\n\n\tcreateCurtain(input: Record<string, unknown>) {\n\t\treturn this.request<{\n\t\t\tcurtain: { id: string };\n\t\t\tuploadId: string;\n\t\t\tpartSize: number;\n\t\t}>(\"/curtains\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify(input),\n\t\t});\n\t}\n\n\tgetOrganizationSettings() {\n\t\treturn this.request<{\n\t\t\tdefaultCurtainId: string | null;\n\t\t\twebhookUrl: string | null;\n\t\t}>(\"/organization/settings\");\n\t}\n\n\tputOrganizationSettings(input: {\n\t\tdefaultCurtainId?: string | null;\n\t\twebhookUrl?: string | null;\n\t\twebhookSecret?: string | null;\n\t}) {\n\t\treturn this.request(\"/organization/settings\", {\n\t\t\tmethod: \"PUT\",\n\t\t\tbody: JSON.stringify(input),\n\t\t});\n\t}\n\n\tmintHostSession(\n\t\tstreamId: string,\n\t\tinput: { displayName: string; picture?: string },\n\t) {\n\t\treturn this.request<{\n\t\t\thostUrl: string;\n\t\t\tguestUrl: string;\n\t\t\thostToken: string;\n\t\t\tguestToken: string;\n\t\t\texpiresAt: number;\n\t\t}>(`/streams/${encodeURIComponent(streamId)}/studio/host-session`, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify(input),\n\t\t});\n\t}\n\n\tlistCommunity(\n\t\tkind: \"stream\" | \"vod\",\n\t\tid: string,\n\t\tquery: { type?: \"comment\" | \"question\"; q?: string; cursor?: string } = {},\n\t) {\n\t\tconst params = new URLSearchParams();\n\t\tif (query.type) params.set(\"type\", query.type);\n\t\tif (query.q) params.set(\"q\", query.q);\n\t\tif (query.cursor) params.set(\"cursor\", query.cursor);\n\t\tconst suffix = params.toString() ? `?${params}` : \"\";\n\t\tconst plural = kind === \"stream\" ? \"streams\" : \"vods\";\n\t\treturn this.request<{ items: unknown[]; nextCursor: string | null }>(\n\t\t\t`/${plural}/${encodeURIComponent(id)}/community${suffix}`,\n\t\t);\n\t}\n\n\tcreateCommunity(\n\t\tkind: \"stream\" | \"vod\",\n\t\tid: string,\n\t\tinput: {\n\t\t\ttype: \"comment\" | \"question\";\n\t\t\tbody: string;\n\t\t\tdisplayName: string;\n\t\t\tpicture?: string | null;\n\t\t\tguestId: string;\n\t\t\tparentId?: string;\n\t\t},\n\t) {\n\t\tconst plural = kind === \"stream\" ? \"streams\" : \"vods\";\n\t\treturn this.request<{ item: unknown }>(\n\t\t\t`/${plural}/${encodeURIComponent(id)}/community`,\n\t\t\t{ method: \"POST\", body: JSON.stringify(input) },\n\t\t);\n\t}\n\n\tpatchCommunity(\n\t\tkind: \"stream\" | \"vod\",\n\t\tid: string,\n\t\titemId: string,\n\t\tinput: Record<string, unknown>,\n\t) {\n\t\tconst plural = kind === \"stream\" ? \"streams\" : \"vods\";\n\t\treturn this.request<{ item: unknown }>(\n\t\t\t`/${plural}/${encodeURIComponent(id)}/community/${encodeURIComponent(itemId)}`,\n\t\t\t{ method: \"PATCH\", body: JSON.stringify(input) },\n\t\t);\n\t}\n}\n\nexport function createLivoServerClient(options: LivoServerClientOptions) {\n\treturn new LivoServerClient(options);\n}\n\nexport { studioGuestUrl as getGuestLink } from \"./urls\";\n"]}