tiktok-live-api 1.2.4 → 1.2.5
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/bin/demo.mjs +157 -58
- package/package.json +1 -1
package/bin/demo.mjs
CHANGED
|
@@ -10,36 +10,72 @@ import path from 'path';
|
|
|
10
10
|
|
|
11
11
|
const REACT_TEMPLATE = [
|
|
12
12
|
'"use client";',
|
|
13
|
-
"import React, { useEffect, useState } from 'react';",
|
|
13
|
+
"import React, { useEffect, useState, useRef } from 'react';",
|
|
14
14
|
"import { TikTokLive } from 'tiktok-live-api';",
|
|
15
15
|
"",
|
|
16
16
|
"export default function TikTokLiveComponent() {",
|
|
17
17
|
" const [events, setEvents] = useState([]);",
|
|
18
18
|
" const [username, setUsername] = useState('aljazeeraenglish');",
|
|
19
|
+
" const [apiKey, setApiKey] = useState('demo_tiktokliveapi_public_2026');",
|
|
20
|
+
" const [inputUsername, setInputUsername] = useState('aljazeeraenglish');",
|
|
19
21
|
" const [connected, setConnected] = useState(false);",
|
|
20
|
-
" ",
|
|
22
|
+
" const clientRef = useRef(null);",
|
|
23
|
+
"",
|
|
21
24
|
" useEffect(() => {",
|
|
22
|
-
"
|
|
25
|
+
" if (!username) return;",
|
|
26
|
+
" if (clientRef.current) { clientRef.current.disconnect(); }",
|
|
27
|
+
" setEvents([]);",
|
|
28
|
+
" setConnected(false);",
|
|
23
29
|
" ",
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
" const client = new TikTokLive(username, { apiKey });",
|
|
31
|
+
" clientRef.current = client;",
|
|
32
|
+
" ",
|
|
33
|
+
" client.on('chat', (e) => setEvents(prev => [...prev.slice(-40), \"💬 \" + e.user.uniqueId + \": \" + e.comment]));",
|
|
34
|
+
" client.on('gift', (e) => setEvents(prev => [...prev.slice(-40), \"🎁 \" + e.user.uniqueId + \" sent \" + e.giftName]));",
|
|
35
|
+
" client.on('member', (e) => setEvents(prev => [...prev.slice(-40), \"👋 \" + e.user.uniqueId + \" joined\"]));",
|
|
36
|
+
" client.on('like', (e) => setEvents(prev => [...prev.slice(-40), \"❤️ \" + e.user.uniqueId + \" liked\"]));",
|
|
26
37
|
" client.on('connected', () => setConnected(true));",
|
|
27
38
|
" client.on('disconnected', () => setConnected(false));",
|
|
28
39
|
" ",
|
|
29
|
-
" client.connect();",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
40
|
+
" client.connect().catch(() => setConnected(false));",
|
|
41
|
+
" ",
|
|
42
|
+
" return () => { if (clientRef.current) { clientRef.current.disconnect(); } };",
|
|
43
|
+
" }, [username, apiKey]);",
|
|
44
|
+
"",
|
|
45
|
+
" const handleConnect = (e) => {",
|
|
46
|
+
" e.preventDefault();",
|
|
47
|
+
" setUsername(inputUsername);",
|
|
48
|
+
" };",
|
|
32
49
|
"",
|
|
33
50
|
" return (",
|
|
34
|
-
" <div style={{ fontFamily: 'sans-serif', maxWidth:
|
|
35
|
-
" <
|
|
36
|
-
"
|
|
37
|
-
" <
|
|
38
|
-
"
|
|
51
|
+
" <div style={{ fontFamily: 'system-ui, sans-serif', maxWidth: 600, margin: '40px auto', border: '1px solid #e5e7eb', borderRadius: '12px', boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)', background: '#fff' }}>",
|
|
52
|
+
" <div style={{ padding: '24px', borderBottom: '1px solid #e5e7eb' }}>",
|
|
53
|
+
" <h2 style={{ margin: '0 0 8px 0', fontSize: '1.5rem', fontWeight: 600 }}>TikTok Live SDK</h2>",
|
|
54
|
+
" <p style={{ margin: 0, fontSize: '0.875rem', color: '#6b7280' }}>",
|
|
55
|
+
" Get your own API key and unlock unlimited connections at <a href=\"https://tik.tools\" target=\"_blank\" style={{ color: '#3b82f6', textDecoration: 'none' }}>tik.tools</a>",
|
|
56
|
+
" </p>",
|
|
39
57
|
" </div>",
|
|
40
|
-
" <div style={{
|
|
41
|
-
"
|
|
42
|
-
"
|
|
58
|
+
" <div style={{ padding: '24px' }}>",
|
|
59
|
+
" <form onSubmit={handleConnect} style={{ display: 'flex', flexDirection: 'column', gap: '16px', marginBottom: '24px' }}>",
|
|
60
|
+
" <div>",
|
|
61
|
+
" <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: 500, marginBottom: '6px' }}>TikTok Username</label>",
|
|
62
|
+
" <input type=\"text\" value={inputUsername} onChange={(e) => setInputUsername(e.target.value)} style={{ width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid #d1d5db', boxSizing: 'border-box' }} placeholder=\"e.g. aljazeeraenglish\" />",
|
|
63
|
+
" </div>",
|
|
64
|
+
" <div>",
|
|
65
|
+
" <label style={{ display: 'block', fontSize: '0.875rem', fontWeight: 500, marginBottom: '6px' }}>API Key</label>",
|
|
66
|
+
" <input type=\"text\" value={apiKey} onChange={(e) => setApiKey(e.target.value)} style={{ width: '100%', padding: '8px 12px', borderRadius: '6px', border: '1px solid #d1d5db', boxSizing: 'border-box', fontFamily: 'monospace' }} />",
|
|
67
|
+
" <p style={{ margin: '4px 0 0 0', fontSize: '0.75rem', color: '#9ca3af' }}>The demo key is rate-limited. Replace with your own key for production.</p>",
|
|
68
|
+
" </div>",
|
|
69
|
+
" <button type=\"submit\" style={{ background: '#000', color: '#fff', padding: '10px 16px', borderRadius: '6px', border: 'none', fontWeight: 500, cursor: 'pointer' }}>Connect Stream</button>",
|
|
70
|
+
" </form>",
|
|
71
|
+
" <div style={{ marginBottom: '16px', display: 'flex', alignItems: 'center', gap: '8px' }}>",
|
|
72
|
+
" <div style={{ width: 10, height: 10, borderRadius: '50%', background: connected ? '#10b981' : '#ef4444', transition: 'background 0.3s' }}></div>",
|
|
73
|
+
" <span style={{ fontSize: '0.875rem', color: '#374151', fontWeight: 500 }}>{connected ? 'Connected to @' + username : 'Disconnected'}</span>",
|
|
74
|
+
" </div>",
|
|
75
|
+
" <div style={{ height: 350, overflowY: 'auto', background: '#f9fafb', padding: '12px', borderRadius: '8px', border: '1px solid #e5e7eb', fontSize: '0.875rem', display: 'flex', flexDirection: 'column' }}>",
|
|
76
|
+
" {events.map((e, i) => <div key={i} style={{ padding: '6px 0', borderBottom: '1px solid #f3f4f6', wordBreak: 'break-word' }}>{e}</div>)}",
|
|
77
|
+
" {events.length === 0 && <div style={{ color: '#9ca3af', textAlign: 'center', margin: 'auto 0' }}>{connected ? 'Waiting for events...' : 'Connect to a valid stream to see events'}</div>}",
|
|
78
|
+
" </div>",
|
|
43
79
|
" </div>",
|
|
44
80
|
" </div>",
|
|
45
81
|
" );",
|
|
@@ -48,17 +84,36 @@ const REACT_TEMPLATE = [
|
|
|
48
84
|
|
|
49
85
|
const VUE_TEMPLATE = [
|
|
50
86
|
"<template>",
|
|
51
|
-
' <div style="font-family: sans-serif; max-width:
|
|
52
|
-
' <
|
|
53
|
-
'
|
|
54
|
-
|
|
55
|
-
|
|
87
|
+
' <div style="font-family: system-ui, sans-serif; max-width: 600px; margin: 40px auto; border: 1px solid #e5e7eb; border-radius: 12px; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); background: #fff">',
|
|
88
|
+
' <div style="padding: 24px; border-bottom: 1px solid #e5e7eb">',
|
|
89
|
+
' <h2 style="margin: 0 0 8px 0; font-size: 1.5rem; font-weight: 600">TikTok Live SDK</h2>',
|
|
90
|
+
' <p style="margin: 0; font-size: 0.875rem; color: #6b7280">',
|
|
91
|
+
' Get your own API key and unlock unlimited connections at <a href="https://tik.tools" target="_blank" style="color: #3b82f6; text-decoration: none">tik.tools</a>',
|
|
92
|
+
" </p>",
|
|
56
93
|
" </div>",
|
|
57
|
-
' <div style="
|
|
58
|
-
' <
|
|
59
|
-
"
|
|
94
|
+
' <div style="padding: 24px">',
|
|
95
|
+
' <form @submit.prevent="handleConnect" style="display: flex; flex-direction: column; gap: 16px; margin-bottom: 24px">',
|
|
96
|
+
" <div>",
|
|
97
|
+
' <label style="display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 6px">TikTok Username</label>',
|
|
98
|
+
' <input type="text" v-model="inputUsername" style="width: 100%; padding: 8px 12px; border-radius: 6px; border: 1px solid #d1d5db; box-sizing: border-box" placeholder="e.g. aljazeeraenglish" />',
|
|
99
|
+
" </div>",
|
|
100
|
+
" <div>",
|
|
101
|
+
' <label style="display: block; font-size: 0.875rem; font-weight: 500; margin-bottom: 6px">API Key</label>',
|
|
102
|
+
' <input type="text" v-model="apiKey" style="width: 100%; padding: 8px 12px; border-radius: 6px; border: 1px solid #d1d5db; box-sizing: border-box; font-family: monospace" />',
|
|
103
|
+
' <p style="margin: 4px 0 0 0; font-size: 0.75rem; color: #9ca3af">The demo key is rate-limited. Replace with your own key for production.</p>',
|
|
104
|
+
" </div>",
|
|
105
|
+
' <button type="submit" style="background: #000; color: #fff; padding: 10px 16px; border-radius: 6px; border: none; font-weight: 500; cursor: pointer">Connect Stream</button>',
|
|
106
|
+
" </form>",
|
|
107
|
+
' <div style="margin-bottom: 16px; display: flex; align-items: center; gap: 8px">',
|
|
108
|
+
" <div :style=\"{ width: '10px', height: '10px', borderRadius: '50%', background: connected ? '#10b981' : '#ef4444', transition: 'background 0.3s' }\"></div>",
|
|
109
|
+
" <span style=\"font-size: 0.875rem; color: '#374151'; font-weight: 500\">{{ connected ? 'Connected to @' + activeUsername : 'Disconnected' }}</span>",
|
|
110
|
+
" </div>",
|
|
111
|
+
' <div style="height: 350px; overflow-y: auto; background: #f9fafb; padding: 12px; border-radius: 8px; border: 1px solid #e5e7eb; font-size: 0.875rem; display: flex; flex-direction: column">',
|
|
112
|
+
' <div v-for="(e, i) in events" :key="i" style="padding: 6px 0; border-bottom: 1px solid #f3f4f6; word-break: break-word">',
|
|
113
|
+
" {{ e }}",
|
|
114
|
+
" </div>",
|
|
115
|
+
' <div v-if="events.length === 0" style="color: #9ca3af; text-align: center; margin: auto 0">{{ connected ? "Waiting for events..." : "Connect to a valid stream to see events" }}</div>',
|
|
60
116
|
" </div>",
|
|
61
|
-
' <div v-if="events.length === 0" style="color: #9ca3af; text-align: center; margin-top: 120px">Waiting for events...</div>',
|
|
62
117
|
" </div>",
|
|
63
118
|
" </div>",
|
|
64
119
|
"</template>",
|
|
@@ -67,28 +122,55 @@ const VUE_TEMPLATE = [
|
|
|
67
122
|
"import { ref, onMounted, onUnmounted } from 'vue'",
|
|
68
123
|
"import { TikTokLive } from 'tiktok-live-api'",
|
|
69
124
|
"",
|
|
70
|
-
"const
|
|
125
|
+
"const inputUsername = ref('aljazeeraenglish')",
|
|
126
|
+
"const activeUsername = ref('aljazeeraenglish')",
|
|
127
|
+
"const apiKey = ref('demo_tiktokliveapi_public_2026')",
|
|
71
128
|
"const connected = ref(false)",
|
|
72
129
|
"const events = ref([])",
|
|
73
130
|
"let client = null",
|
|
74
131
|
"",
|
|
75
|
-
"
|
|
76
|
-
" client
|
|
132
|
+
"const connectClient = () => {",
|
|
133
|
+
" if (client) client.disconnect()",
|
|
134
|
+
" events.value = []",
|
|
135
|
+
" connected.value = false",
|
|
136
|
+
" activeUsername.value = inputUsername.value",
|
|
137
|
+
" ",
|
|
138
|
+
" if (!activeUsername.value) return",
|
|
139
|
+
" ",
|
|
140
|
+
" client = new TikTokLive(activeUsername.value, { apiKey: apiKey.value })",
|
|
77
141
|
" ",
|
|
78
142
|
" client.on('chat', (e) => {",
|
|
79
143
|
' events.value.push("💬 " + e.user.uniqueId + ": " + e.comment)',
|
|
80
|
-
" if (events.value.length >
|
|
144
|
+
" if (events.value.length > 40) events.value.shift()",
|
|
81
145
|
" })",
|
|
82
146
|
" ",
|
|
83
147
|
" client.on('gift', (e) => {",
|
|
84
148
|
' events.value.push("🎁 " + e.user.uniqueId + " sent " + e.giftName)',
|
|
85
|
-
" if (events.value.length >
|
|
149
|
+
" if (events.value.length > 40) events.value.shift()",
|
|
150
|
+
" })",
|
|
151
|
+
"",
|
|
152
|
+
" client.on('member', (e) => {",
|
|
153
|
+
' events.value.push("👋 " + e.user.uniqueId + " joined")',
|
|
154
|
+
" if (events.value.length > 40) events.value.shift()",
|
|
155
|
+
" })",
|
|
156
|
+
" ",
|
|
157
|
+
" client.on('like', (e) => {",
|
|
158
|
+
' events.value.push("❤️ " + e.user.uniqueId + " liked")',
|
|
159
|
+
" if (events.value.length > 40) events.value.shift()",
|
|
86
160
|
" })",
|
|
87
161
|
"",
|
|
88
162
|
" client.on('connected', () => connected.value = true)",
|
|
89
163
|
" client.on('disconnected', () => connected.value = false)",
|
|
90
164
|
" ",
|
|
91
|
-
" client.connect()",
|
|
165
|
+
" client.connect().catch(() => connected.value = false)",
|
|
166
|
+
"}",
|
|
167
|
+
"",
|
|
168
|
+
"const handleConnect = () => {",
|
|
169
|
+
" connectClient()",
|
|
170
|
+
"}",
|
|
171
|
+
"",
|
|
172
|
+
"onMounted(() => {",
|
|
173
|
+
" connectClient()",
|
|
92
174
|
"})",
|
|
93
175
|
"",
|
|
94
176
|
"onUnmounted(() => {",
|
|
@@ -119,21 +201,16 @@ if (!isInteractive) {
|
|
|
119
201
|
|
|
120
202
|
console.log("\n " + B + "tiktok-live-api" + R + "\n Unofficial TikTok LIVE SDK by TikTool\n");
|
|
121
203
|
console.log(" What would you like to do?");
|
|
122
|
-
console.log(" 1) " + C.cyan + "Watch Live Terminal Demo" + R
|
|
204
|
+
console.log(" 1) " + C.cyan + "Watch Live Terminal Demo" + R);
|
|
123
205
|
console.log(" 2) " + C.green + "Scaffold a Nuxt 3 (Vue) App" + R);
|
|
124
206
|
console.log(" 3) " + C.blue + "Scaffold a Next.js (React) App" + R);
|
|
125
207
|
console.log(" 4) " + C.yellow + "Scaffold a Vite (React) App" + R + "\n");
|
|
126
208
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
rl.question(" Choose [1-4]: ", (answer) => {
|
|
134
|
-
clearTimeout(timeoutId);
|
|
135
|
-
handleMenu(answer.trim() || '1');
|
|
136
|
-
});
|
|
209
|
+
function promptAction() {
|
|
210
|
+
rl.question(" Choose [1-4]: ", (answer) => {
|
|
211
|
+
handleMenu(answer.trim());
|
|
212
|
+
});
|
|
213
|
+
}
|
|
137
214
|
|
|
138
215
|
function handleMenu(choice) {
|
|
139
216
|
if (choice === '1') {
|
|
@@ -143,39 +220,58 @@ if (!isInteractive) {
|
|
|
143
220
|
|
|
144
221
|
if (!['2', '3', '4'].includes(choice)) {
|
|
145
222
|
console.log(" " + C.red + "Invalid choice." + R);
|
|
146
|
-
|
|
147
|
-
process.exit(1);
|
|
223
|
+
return promptAction();
|
|
148
224
|
}
|
|
149
225
|
|
|
150
226
|
rl.question("\n Target directory (e.g. ./my-app) [./tiktok-live-project]: ", (dir) => {
|
|
151
227
|
dir = dir.trim() || './tiktok-live-project';
|
|
152
|
-
|
|
153
|
-
|
|
228
|
+
|
|
229
|
+
console.log("\n Select Package Manager:");
|
|
230
|
+
console.log(" 1) npm " + D + "(Default)" + R);
|
|
231
|
+
console.log(" 2) yarn");
|
|
232
|
+
console.log(" 3) pnpm");
|
|
233
|
+
console.log(" 4) bun");
|
|
234
|
+
|
|
235
|
+
rl.question("\n Choose [1-4]: ", (pmAnswer) => {
|
|
236
|
+
const pmChoice = pmAnswer.trim() || '1';
|
|
237
|
+
const pmMap = { '1': 'npm', '2': 'yarn', '3': 'pnpm', '4': 'bun' };
|
|
238
|
+
const pm = pmMap[pmChoice] || 'npm';
|
|
239
|
+
|
|
240
|
+
rl.close();
|
|
241
|
+
runScaffold(choice, dir, pm);
|
|
242
|
+
});
|
|
154
243
|
});
|
|
155
244
|
}
|
|
245
|
+
|
|
246
|
+
promptAction();
|
|
156
247
|
}
|
|
157
248
|
|
|
158
249
|
// ── Scaffolding Logic ───────────────────────────────────────────────────
|
|
159
250
|
|
|
160
|
-
function runScaffold(choice, targetDir) {
|
|
251
|
+
function runScaffold(choice, targetDir, pm) {
|
|
161
252
|
const isNuxt = choice === '2';
|
|
162
253
|
const isNext = choice === '3';
|
|
163
254
|
const isVite = choice === '4';
|
|
164
255
|
const fullPath = path.resolve(process.cwd(), targetDir);
|
|
165
256
|
|
|
166
|
-
|
|
257
|
+
const npxCmd = pm === 'bun' ? 'bunx' : (pm === 'pnpm' ? 'pnpm dlx' : 'npx');
|
|
258
|
+
const installCmd = pm === 'npm' ? 'npm install tiktok-live-api' : pm === 'yarn' ? 'yarn add tiktok-live-api' : pm === 'pnpm' ? 'pnpm add tiktok-live-api' : 'bun add tiktok-live-api';
|
|
259
|
+
const devCmd = pm === 'npm' ? 'npm run dev' : pm === 'yarn' ? 'yarn dev' : pm === 'pnpm' ? 'pnpm dev' : 'bun run dev';
|
|
260
|
+
|
|
261
|
+
console.log("\n " + B + "🚀 Scaffolding project into " + targetDir + " using " + pm + "..." + R + "\n");
|
|
167
262
|
|
|
168
263
|
try {
|
|
169
264
|
if (isNuxt) {
|
|
170
|
-
execSync('
|
|
265
|
+
execSync(npxCmd + ' nuxi@latest init "' + targetDir + '" --packageManager ' + pm, { stdio: 'inherit' });
|
|
171
266
|
} else if (isNext) {
|
|
172
|
-
execSync('
|
|
267
|
+
execSync(npxCmd + ' create-next-app@latest "' + targetDir + '" --js --eslint --tailwind --app --src-dir --import-alias "@/*" --use-' + pm, { stdio: 'inherit' });
|
|
173
268
|
} else if (isVite) {
|
|
174
|
-
|
|
269
|
+
const createCmd = pm === 'npm' ? 'npm create vite@latest' : pm === 'yarn' ? 'yarn create vite' : pm === 'pnpm' ? 'pnpm create vite' : 'bun create vite';
|
|
270
|
+
execSync(createCmd + ' "' + targetDir + '" -- --template react', { stdio: 'inherit' });
|
|
175
271
|
}
|
|
176
272
|
|
|
177
273
|
console.log("\n " + B + "📦 Installing " + C.cyan + "tiktok-live-api" + B + " SDK..." + R + "\n");
|
|
178
|
-
execSync(
|
|
274
|
+
execSync(installCmd, { cwd: fullPath, stdio: 'inherit' });
|
|
179
275
|
|
|
180
276
|
if (isNuxt) {
|
|
181
277
|
const compDir = path.join(fullPath, 'components');
|
|
@@ -186,9 +282,9 @@ function runScaffold(choice, targetDir) {
|
|
|
186
282
|
if (fs.existsSync(appVue)) {
|
|
187
283
|
fs.writeFileSync(appVue, [
|
|
188
284
|
'<template>',
|
|
189
|
-
' <
|
|
285
|
+
' <main style="min-height: 100vh; background: #f9fafb; padding-top: 40px;">',
|
|
190
286
|
' <TikTokLive />',
|
|
191
|
-
' </
|
|
287
|
+
' </main>',
|
|
192
288
|
'</template>'
|
|
193
289
|
].join('\n') + '\n');
|
|
194
290
|
}
|
|
@@ -204,7 +300,7 @@ function runScaffold(choice, targetDir) {
|
|
|
204
300
|
"",
|
|
205
301
|
"export default function Home() {",
|
|
206
302
|
" return (",
|
|
207
|
-
' <main
|
|
303
|
+
' <main style={{ minHeight: "100vh", background: "#f9fafb", paddingTop: "40px" }}>',
|
|
208
304
|
" <TikTokLive />",
|
|
209
305
|
" </main>",
|
|
210
306
|
" );",
|
|
@@ -223,9 +319,9 @@ function runScaffold(choice, targetDir) {
|
|
|
223
319
|
"",
|
|
224
320
|
"export default function App() {",
|
|
225
321
|
" return (",
|
|
226
|
-
|
|
322
|
+
' <main style={{ minHeight: "100vh", background: "#f9fafb", paddingTop: "40px" }}>',
|
|
227
323
|
" <TikTokLive />",
|
|
228
|
-
" </
|
|
324
|
+
" </main>",
|
|
229
325
|
" );",
|
|
230
326
|
"}"
|
|
231
327
|
].join('\n') + '\n');
|
|
@@ -235,7 +331,10 @@ function runScaffold(choice, targetDir) {
|
|
|
235
331
|
console.log("\n " + C.green + "✔ Project successfully scaffolded!" + R + "\n");
|
|
236
332
|
console.log(" " + B + "Next steps:" + R);
|
|
237
333
|
console.log(" cd " + targetDir);
|
|
238
|
-
|
|
334
|
+
if (isVite && pm !== 'bun') {
|
|
335
|
+
console.log(" " + pm + " install");
|
|
336
|
+
}
|
|
337
|
+
console.log(" " + devCmd + "\n");
|
|
239
338
|
|
|
240
339
|
} catch (err) {
|
|
241
340
|
console.error("\n " + C.red + "Error during scaffolding:" + R, err.message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiktok-live-api",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Unofficial TikTok LIVE API Client — Real-time chat, gifts, viewers, battles, and AI live captions from any TikTok livestream. Managed WebSocket API with 99.9% uptime.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|