@livo-tv/sdk 1.0.0

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/server.js ADDED
@@ -0,0 +1,90 @@
1
+ // src/theme.ts
2
+ function encodeEmbedTheme(theme) {
3
+ const json = JSON.stringify(theme);
4
+ const bytes = new TextEncoder().encode(json);
5
+ let binary = "";
6
+ for (const byte of bytes) binary += String.fromCharCode(byte);
7
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
8
+ }
9
+
10
+ // src/urls.ts
11
+ function trimSlash(value) {
12
+ return value.replace(/\/$/, "");
13
+ }
14
+ function studioGuestUrl(token, options = {}) {
15
+ const origin = trimSlash(options.appOrigin ?? "https://app.livo.tv");
16
+ const url = new URL(`${origin}/studio/join/${token}`);
17
+ if (options.embed !== false) url.searchParams.set("embed", "1");
18
+ if (options.theme)
19
+ url.searchParams.set("theme", encodeEmbedTheme(options.theme));
20
+ return url.toString();
21
+ }
22
+
23
+ // src/server.ts
24
+ var LivoServerClient = class {
25
+ apiUrl;
26
+ apiKey;
27
+ fetchFn;
28
+ constructor(options) {
29
+ this.apiUrl = (options.apiUrl ?? "https://media-svc.livo.tv").replace(
30
+ /\/$/,
31
+ ""
32
+ );
33
+ this.apiKey = options.apiKey;
34
+ this.fetchFn = options.fetchFn ?? fetch;
35
+ }
36
+ async request(path, init = {}) {
37
+ const headers = new Headers(init.headers);
38
+ headers.set("X-Api-Key", this.apiKey);
39
+ headers.set("accept", "application/json");
40
+ if (init.body && !headers.has("content-type")) {
41
+ headers.set("content-type", "application/json");
42
+ }
43
+ const res = await this.fetchFn(`${this.apiUrl}${path}`, {
44
+ ...init,
45
+ headers
46
+ });
47
+ const body = await res.json().catch(() => ({}));
48
+ if (!res.ok) {
49
+ const error = new Error(`Livo API ${res.status}`);
50
+ error.status = res.status;
51
+ error.body = body;
52
+ throw error;
53
+ }
54
+ return body;
55
+ }
56
+ createStream(input) {
57
+ return this.request("/streams", {
58
+ method: "POST",
59
+ body: JSON.stringify(input)
60
+ });
61
+ }
62
+ getStream(id) {
63
+ return this.request(
64
+ `/streams/${encodeURIComponent(id)}`
65
+ );
66
+ }
67
+ stopStream(id) {
68
+ return this.request(`/streams/${encodeURIComponent(id)}/stop`, {
69
+ method: "POST"
70
+ });
71
+ }
72
+ listVods() {
73
+ return this.request(
74
+ "/vods"
75
+ );
76
+ }
77
+ mintHostSession(streamId, input) {
78
+ return this.request(`/streams/${encodeURIComponent(streamId)}/studio/host-session`, {
79
+ method: "POST",
80
+ body: JSON.stringify(input)
81
+ });
82
+ }
83
+ };
84
+ function createLivoServerClient(options) {
85
+ return new LivoServerClient(options);
86
+ }
87
+
88
+ export { LivoServerClient, createLivoServerClient, studioGuestUrl as getGuestLink };
89
+ //# sourceMappingURL=server.js.map
90
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme.ts","../src/urls.ts","../src/server.ts"],"names":[],"mappings":"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","file":"server.js","sourcesContent":["export type EmbedTheme = {\n\tprimary?: 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 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 (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\tif (theme.primary) {\n\t\tvars[\"--livo-primary\"] = theme.primary;\n\t\tvars[\"--primary\"] = theme.primary;\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","import { encodeEmbedTheme, type EmbedTheme } from \"./theme\";\n\nexport type UrlOrigins = {\n\tplayerOrigin?: string;\n\tappOrigin?: string;\n};\n\nfunction trimSlash(value: string): string {\n\treturn value.replace(/\\/$/, \"\");\n}\n\nexport function playerUrl(\n\tstreamId: string,\n\toptions: UrlOrigins & { theme?: EmbedTheme; locale?: string } = {},\n): string {\n\tconst origin = trimSlash(options.playerOrigin ?? \"https://player.livo.tv\");\n\tconst url = new URL(`${origin}/${streamId}`);\n\tif (options.locale) url.searchParams.set(\"lang\", options.locale);\n\tif (options.theme)\n\t\turl.searchParams.set(\"theme\", encodeEmbedTheme(options.theme));\n\treturn url.toString();\n}\n\nexport function vodPlayerUrl(\n\tvodId: string,\n\toptions: UrlOrigins & { theme?: EmbedTheme; locale?: string } = {},\n): string {\n\tconst origin = trimSlash(options.playerOrigin ?? \"https://player.livo.tv\");\n\tconst url = new URL(`${origin}/vod/${vodId}`);\n\tif (options.locale) url.searchParams.set(\"lang\", options.locale);\n\tif (options.theme)\n\t\turl.searchParams.set(\"theme\", encodeEmbedTheme(options.theme));\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: { title: string; mode?: \"instant\" | \"scheduled\" }) {\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\tstopStream(id: string) {\n\t\treturn this.request(`/streams/${encodeURIComponent(id)}/stop`, {\n\t\t\tmethod: \"POST\",\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\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\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\nexport function createLivoServerClient(options: LivoServerClientOptions) {\n\treturn new LivoServerClient(options);\n}\n\nexport { studioGuestUrl as getGuestLink } from \"./urls\";\n"]}
@@ -0,0 +1,13 @@
1
+ .livo-sdk {
2
+ --livo-primary: #2563eb;
3
+ --livo-background: #0c121c;
4
+ --livo-foreground: #f8fafc;
5
+ --livo-radius: 0.625rem;
6
+ --primary: var(--livo-primary);
7
+ --background: var(--livo-background);
8
+ --foreground: var(--livo-foreground);
9
+ --radius: var(--livo-radius);
10
+ color: var(--livo-foreground);
11
+ background: var(--livo-background);
12
+ font-family: var(--font-sans, Inter, system-ui, sans-serif);
13
+ }
@@ -0,0 +1,33 @@
1
+ type EmbedTheme = {
2
+ primary?: string;
3
+ background?: string;
4
+ foreground?: string;
5
+ radius?: string;
6
+ fontFamily?: string;
7
+ mode?: "light" | "dark";
8
+ };
9
+ declare function sanitizeEmbedTheme(value: unknown): EmbedTheme | null;
10
+ declare function encodeEmbedTheme(theme: EmbedTheme): string;
11
+
12
+ type UrlOrigins = {
13
+ playerOrigin?: string;
14
+ appOrigin?: string;
15
+ };
16
+ declare function playerUrl(streamId: string, options?: UrlOrigins & {
17
+ theme?: EmbedTheme;
18
+ locale?: string;
19
+ }): string;
20
+ declare function vodPlayerUrl(vodId: string, options?: UrlOrigins & {
21
+ theme?: EmbedTheme;
22
+ locale?: string;
23
+ }): string;
24
+ declare function studioGuestUrl(token: string, options?: UrlOrigins & {
25
+ theme?: EmbedTheme;
26
+ embed?: boolean;
27
+ }): string;
28
+ declare function studioHostUrl(token: string, options?: UrlOrigins & {
29
+ theme?: EmbedTheme;
30
+ embed?: boolean;
31
+ }): string;
32
+
33
+ export { type EmbedTheme as E, type UrlOrigins as U, studioGuestUrl as a, studioHostUrl as b, encodeEmbedTheme as e, playerUrl as p, sanitizeEmbedTheme as s, vodPlayerUrl as v };
@@ -0,0 +1,33 @@
1
+ type EmbedTheme = {
2
+ primary?: string;
3
+ background?: string;
4
+ foreground?: string;
5
+ radius?: string;
6
+ fontFamily?: string;
7
+ mode?: "light" | "dark";
8
+ };
9
+ declare function sanitizeEmbedTheme(value: unknown): EmbedTheme | null;
10
+ declare function encodeEmbedTheme(theme: EmbedTheme): string;
11
+
12
+ type UrlOrigins = {
13
+ playerOrigin?: string;
14
+ appOrigin?: string;
15
+ };
16
+ declare function playerUrl(streamId: string, options?: UrlOrigins & {
17
+ theme?: EmbedTheme;
18
+ locale?: string;
19
+ }): string;
20
+ declare function vodPlayerUrl(vodId: string, options?: UrlOrigins & {
21
+ theme?: EmbedTheme;
22
+ locale?: string;
23
+ }): string;
24
+ declare function studioGuestUrl(token: string, options?: UrlOrigins & {
25
+ theme?: EmbedTheme;
26
+ embed?: boolean;
27
+ }): string;
28
+ declare function studioHostUrl(token: string, options?: UrlOrigins & {
29
+ theme?: EmbedTheme;
30
+ embed?: boolean;
31
+ }): string;
32
+
33
+ export { type EmbedTheme as E, type UrlOrigins as U, studioGuestUrl as a, studioHostUrl as b, encodeEmbedTheme as e, playerUrl as p, sanitizeEmbedTheme as s, vodPlayerUrl as v };
package/package.json ADDED
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "@livo-tv/sdk",
3
+ "version": "1.0.0",
4
+ "description": "Embed the Livo player and studio in a third-party app",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "./server": {
21
+ "import": {
22
+ "types": "./dist/server.d.ts",
23
+ "default": "./dist/server.js"
24
+ },
25
+ "require": {
26
+ "types": "./dist/server.d.cts",
27
+ "default": "./dist/server.cjs"
28
+ }
29
+ },
30
+ "./styles.css": "./dist/styles.css"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "sideEffects": [
37
+ "**/*.css"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsup && node scripts/copy-css.mjs",
41
+ "typecheck": "tsc --noEmit",
42
+ "lint": "eslint . --max-warnings=0",
43
+ "format": "prettier --write .",
44
+ "format:check": "prettier --check .",
45
+ "test": "vitest run --coverage",
46
+ "prepublishOnly": "pnpm build",
47
+ "release": "semantic-release",
48
+ "ci:check": "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm run test && pnpm run build"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/livo-tv/sdk.git"
53
+ },
54
+ "keywords": [
55
+ "livo",
56
+ "player",
57
+ "studio",
58
+ "hls",
59
+ "embed"
60
+ ],
61
+ "author": "Livo",
62
+ "license": "MIT",
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "peerDependencies": {
67
+ "hls.js": ">=1.5.0",
68
+ "react": ">=18.0.0",
69
+ "react-dom": ">=18.0.0"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "hls.js": {
73
+ "optional": true
74
+ }
75
+ },
76
+ "dependencies": {
77
+ "@livo-tv/blocks": "^1.20.0"
78
+ },
79
+ "devDependencies": {
80
+ "@eslint/js": "^9.26.0",
81
+ "@semantic-release/changelog": "^6.0.3",
82
+ "@semantic-release/git": "^10.0.1",
83
+ "@semantic-release/github": "^11.0.1",
84
+ "@semantic-release/npm": "^13.1.3",
85
+ "@testing-library/react": "^16.3.0",
86
+ "@types/react": "^19.1.3",
87
+ "@types/react-dom": "^19.1.3",
88
+ "@vitest/coverage-istanbul": "^4.0.0",
89
+ "eslint": "^9.26.0",
90
+ "eslint-config-prettier": "^10.1.3",
91
+ "jsdom": "^26.1.0",
92
+ "prettier": "^3.5.3",
93
+ "react": "^19.1.0",
94
+ "react-dom": "^19.1.0",
95
+ "semantic-release": "^25.0.2",
96
+ "tsup": "^8.5.0",
97
+ "typescript": "^5.9.3",
98
+ "typescript-eslint": "^8.32.1",
99
+ "vitest": "^4.0.0"
100
+ },
101
+ "packageManager": "pnpm@10.23.0",
102
+ "pnpm": {
103
+ "onlyBuiltDependencies": [
104
+ "esbuild"
105
+ ]
106
+ }
107
+ }