@tiktool/live 2.8.0 → 2.10.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/README.md CHANGED
@@ -65,6 +65,85 @@ await live.connect();
65
65
 
66
66
  ---
67
67
 
68
+ ## Connection Modes
69
+
70
+ There are **two ways** to receive TikTok LIVE events from `tik.tools`. Pick based on scale and IP-exposure tolerance.
71
+
72
+ ### Mode 1 — Direct (default, this SDK)
73
+
74
+ ```
75
+ Your App ──signs URL via──▶ tik.tools ──returns signed URL──▶ Your App
76
+ Your App ───────────────── WS direct to TikTok ───────────────▶ TikTok
77
+ Your App ◀────────────────── live events ────────────────────── TikTok
78
+ ```
79
+
80
+ - **TikTok sees your IP.** Cheapest on our API quota (only the `ws_credentials` call is charged per connection).
81
+ - Good for **up to ~30 concurrent streams** from one container.
82
+ - Above that, TikTok's per-IP rate limit kicks in → frequent `code=1006` closes + reconnect loops.
83
+ - **Solution at scale**: enable the `proxy` option (below) to dial through your own residential pool.
84
+
85
+ ```typescript
86
+ const live = new TikTokLive({
87
+ uniqueId: 'creator_username',
88
+ apiKey: 'YOUR_TIKTOOLS_KEY',
89
+ // Optional: route WS + HTTP through your own proxy (recommended for 30+ streams)
90
+ proxy: 'http://USER:PASS@p.webshare.io:80',
91
+ });
92
+ ```
93
+
94
+ Install `https-proxy-agent` if using `proxy`:
95
+
96
+ ```bash
97
+ npm install https-proxy-agent
98
+ ```
99
+
100
+ ### Mode 2 — Relayed (via our proxy pool, no SDK install)
101
+
102
+ ```
103
+ Your App ◀──── wss://api.tik.tools/?uniqueId=X&apiKey=Y ──── tik.tools
104
+ │
105
+ │ WS via
106
+ │ rotated proxies
107
+ ▼
108
+ TikTok
109
+ ```
110
+
111
+ - **TikTok sees our IPs** (rotated across hundreds of Webshare + residential proxies).
112
+ - We absorb every per-IP rate-limit hit. Survives any block automatically.
113
+ - Best for **30+ concurrent streams**, low-budget setups, or anyone who doesn't want their own IP fingerprinted by TikTok.
114
+ - Costs slightly more per stream-hour (events stream through us, not signed-once direct).
115
+ - No SDK install — plain `WebSocket`. Events arrive pre-parsed as JSON.
116
+
117
+ ```typescript
118
+ import WebSocket from 'ws';
119
+
120
+ const ws = new WebSocket(
121
+ `wss://api.tik.tools/?uniqueId=creator_username&apiKey=YOUR_KEY`
122
+ );
123
+
124
+ ws.on('message', raw => {
125
+ const msg = JSON.parse(raw.toString());
126
+ if (msg.event === 'chat') console.log(msg.data.user.uniqueId, msg.data.comment);
127
+ if (msg.event === 'gift') console.log(msg.data.user.uniqueId, msg.data.giftName, msg.data.diamondCount);
128
+ if (msg.event === 'battleArmies') console.log(msg.data);
129
+ });
130
+ ```
131
+
132
+ Event payloads are identical to Direct-mode `client.on('chat', …)` etc. — only the wrapping changes (`{event, data}` envelope vs the SDK's separate emit).
133
+
134
+ ### Side-by-side
135
+
136
+ | Aspect | Direct (Mode 1) | Relayed (Mode 2) |
137
+ |---|---|---|
138
+ | TikTok sees | Your IP | Our rotated proxy pool |
139
+ | Setup | `new TikTokLive(...)` | `new WebSocket(url)` |
140
+ | Scale limit | ~30 streams / container IP | Thousands |
141
+ | Per-event cost | 1× `ws_credentials` per (re)connect | 1× per event |
142
+ | TikTok rate-limit risk | Yes (mitigated with `proxy`) | None — we handle it |
143
+ | Best for | Hobby / single-creator | Production at scale |
144
+
145
+ ---
146
+
68
147
  ## Events
69
148
 
70
149
  ### Listening
package/dist/index.d.mts CHANGED
@@ -279,6 +279,32 @@ interface TikTokLiveOptions {
279
279
  roomId?: string;
280
280
  /** Pre-resolved ttwid session cookie — skips direct TikTok page fetch when provided with roomId */
281
281
  sessionId?: string;
282
+ /**
283
+ * Optional HTTP/HTTPS proxy URL. When set, the SDK's outbound WebSocket
284
+ * (and HTTP requests) tunnel through this proxy instead of your container's
285
+ * IP. Required when running 50+ concurrent direct connections to avoid
286
+ * TikTok's per-IP rate limiting (manifests as code=1006 abnormal closes).
287
+ *
288
+ * Format: `http://user:pass@host:port` or `http://host:port`.
289
+ *
290
+ * Example (Webshare residential):
291
+ * proxy: 'http://USER:PASS@p.webshare.io:80'
292
+ */
293
+ proxy?: string;
294
+ /**
295
+ * Connection mode.
296
+ * - `'direct'` (default): SDK opens WebSocket directly to TikTok. TikTok
297
+ * sees your IP. Cheapest on API quota. Limited to ~30 concurrent
298
+ * streams per container before TikTok rate-limits.
299
+ * - `'relayed'`: SDK connects to TikTools' managed relay
300
+ * (`wss://api.tik.tools/?...`). We connect to TikTok on your behalf
301
+ * from our rotated proxy pool. TikTok never sees your IP. No rate-
302
+ * limit risk. Scales to thousands of concurrent streams.
303
+ *
304
+ * The decoded events emitted are identical in both modes — code that
305
+ * uses `client.on('chat', e => ...)` works without changes.
306
+ */
307
+ mode?: 'direct' | 'relayed';
282
308
  }
283
309
 
284
310
  declare class TikTokLive extends EventEmitter {
@@ -302,7 +328,14 @@ declare class TikTokLive extends EventEmitter {
302
328
  private readonly debug;
303
329
  private readonly _presetRoomId;
304
330
  private readonly _presetSessionId;
331
+ private readonly proxyUrl;
332
+ private readonly mode;
305
333
  constructor(options: TikTokLiveOptions);
334
+ /**
335
+ * Build an HttpsProxyAgent when `proxy` option is set, else undefined.
336
+ * Lazy-required so users without proxy don't pay the dependency cost.
337
+ */
338
+ private getProxyAgent;
306
339
  connect(): Promise<void>;
307
340
  disconnect(): void;
308
341
  /**
@@ -349,6 +382,13 @@ declare class TikTokLive extends EventEmitter {
349
382
  private resolveHostUsers;
350
383
  private startHeartbeat;
351
384
  private stopHeartbeat;
385
+ /**
386
+ * Relayed-mode connect. Opens a plain WebSocket to TikTools' managed relay
387
+ * endpoint. Events arrive pre-decoded as `{event, data}` JSON envelopes.
388
+ * The SDK re-emits them on the same event names as Direct mode so user
389
+ * code is identical regardless of mode.
390
+ */
391
+ private _connectRelayed;
352
392
  }
353
393
 
354
394
  export { type BaseEvent, type BattleArmiesEvent, type BattleContributor, type BattleEvent, type BattleHost, type BattleItemCardEvent, type BattleTeam, type BattleTeamUser, type ChatEvent, type ControlEvent, type EmoteChatEvent, type EnvelopeEvent, type GiftEvent, type LikeEvent, type LinkMicEvent, type LiveEvent, type LiveIntroEvent, type MemberEvent, type QuestionEvent, type RankUpdateEvent, type RoomEvent, type RoomInfo, type RoomUserSeqEvent, type SocialEvent, type StreamInfo, type StreamQuality, type StreamUrls, type SubscribeEvent, TikTokLive, type TikTokLiveEvents, type TikTokLiveOptions, type TikTokUser, type UnknownEvent };
package/dist/index.d.ts CHANGED
@@ -279,6 +279,32 @@ interface TikTokLiveOptions {
279
279
  roomId?: string;
280
280
  /** Pre-resolved ttwid session cookie — skips direct TikTok page fetch when provided with roomId */
281
281
  sessionId?: string;
282
+ /**
283
+ * Optional HTTP/HTTPS proxy URL. When set, the SDK's outbound WebSocket
284
+ * (and HTTP requests) tunnel through this proxy instead of your container's
285
+ * IP. Required when running 50+ concurrent direct connections to avoid
286
+ * TikTok's per-IP rate limiting (manifests as code=1006 abnormal closes).
287
+ *
288
+ * Format: `http://user:pass@host:port` or `http://host:port`.
289
+ *
290
+ * Example (Webshare residential):
291
+ * proxy: 'http://USER:PASS@p.webshare.io:80'
292
+ */
293
+ proxy?: string;
294
+ /**
295
+ * Connection mode.
296
+ * - `'direct'` (default): SDK opens WebSocket directly to TikTok. TikTok
297
+ * sees your IP. Cheapest on API quota. Limited to ~30 concurrent
298
+ * streams per container before TikTok rate-limits.
299
+ * - `'relayed'`: SDK connects to TikTools' managed relay
300
+ * (`wss://api.tik.tools/?...`). We connect to TikTok on your behalf
301
+ * from our rotated proxy pool. TikTok never sees your IP. No rate-
302
+ * limit risk. Scales to thousands of concurrent streams.
303
+ *
304
+ * The decoded events emitted are identical in both modes — code that
305
+ * uses `client.on('chat', e => ...)` works without changes.
306
+ */
307
+ mode?: 'direct' | 'relayed';
282
308
  }
283
309
 
284
310
  declare class TikTokLive extends EventEmitter {
@@ -302,7 +328,14 @@ declare class TikTokLive extends EventEmitter {
302
328
  private readonly debug;
303
329
  private readonly _presetRoomId;
304
330
  private readonly _presetSessionId;
331
+ private readonly proxyUrl;
332
+ private readonly mode;
305
333
  constructor(options: TikTokLiveOptions);
334
+ /**
335
+ * Build an HttpsProxyAgent when `proxy` option is set, else undefined.
336
+ * Lazy-required so users without proxy don't pay the dependency cost.
337
+ */
338
+ private getProxyAgent;
306
339
  connect(): Promise<void>;
307
340
  disconnect(): void;
308
341
  /**
@@ -349,6 +382,13 @@ declare class TikTokLive extends EventEmitter {
349
382
  private resolveHostUsers;
350
383
  private startHeartbeat;
351
384
  private stopHeartbeat;
385
+ /**
386
+ * Relayed-mode connect. Opens a plain WebSocket to TikTools' managed relay
387
+ * endpoint. Events arrive pre-decoded as `{event, data}` JSON envelopes.
388
+ * The SDK re-emits them on the same event names as Direct mode so user
389
+ * code is identical regardless of mode.
390
+ */
391
+ private _connectRelayed;
352
392
  }
353
393
 
354
394
  export { type BaseEvent, type BattleArmiesEvent, type BattleContributor, type BattleEvent, type BattleHost, type BattleItemCardEvent, type BattleTeam, type BattleTeamUser, type ChatEvent, type ControlEvent, type EmoteChatEvent, type EnvelopeEvent, type GiftEvent, type LikeEvent, type LinkMicEvent, type LiveEvent, type LiveIntroEvent, type MemberEvent, type QuestionEvent, type RankUpdateEvent, type RoomEvent, type RoomInfo, type RoomUserSeqEvent, type SocialEvent, type StreamInfo, type StreamQuality, type StreamUrls, type SubscribeEvent, TikTokLive, type TikTokLiveEvents, type TikTokLiveOptions, type TikTokUser, type UnknownEvent };