Covers every API-surface break introduced after the 2.1.1-beta1 snapshot of 2025-12-12 (commits eee8383..HEAD). Anything older is unaffected; anything in this window is new.
The headline release is 2.2.0-beta1 / 2.3.0-alpha1, which lands a near-total rewrite of the connection, web/ws clients, routes layer, configuration, and packaging.
- The package is now ESM-only (
"type": "module"inpackage.json). CommonJS consumers must switch toimport/ dynamicimport(). The CJSrequire('tiktok-live-connector')path no longer works. exportsfield replaces the implicit single entry. Two public entry points are exposed; nothing else underdist/is importable:tiktok-live-connector→ modernTikTokLiveConnectionAPI.tiktok-live-connector/legacy→ the deprecatedWebcastPushConnectionshim. PreviouslyWebcastPushConnectionwas re-exported from the root entry; now it must be imported from/legacy.
- Build pipeline migrated from
tsc+tsc-aliastotsdown(tsdown.config.ts).dist/is emitted as ES2022 ESM. Anyone consuming the old CJSdist/shape will break. - TypeScript bumped from ^4.8.2 to ^5.6.0,
tsconfignow targetsES2022,module: ESNext,moduleResolution: Bundler,strictNullChecks: true,allowJs: false. Downstream type imports may now fail under stricter null checks. - Node engine is unchanged at
>=20, but Node 18 (which still works in some setups under the old build) is no longer practical due to ESM + got requirements.
- HTTP transport: axios →
got^15. All HTTP types (AxiosRequestConfig,AxiosInstance,AxiosResponse, interceptors) are gone from the public API. Custom request options now use got'sOptionsInitshape (and the project's narrowerWebcastGotHttpConfig). - Protobuf schema externalised:
tiktok-live-proto. All message types previously exported from@/types/tiktok-schema(~41k lines deleted) now live in thetiktok-live-protopackage and are re-exported fromtiktok-live-proto/v2. Module-augmentation consumers must updatedeclare module '@/types/tiktok-schema'todeclare module 'tiktok-live-proto/v2'. - Removed runtime dependencies:
axios,callable-instance,protobufjs,https-proxy-agent.axiosis still kept as adevDependencyfor tests only;callable-instancewas the base for the old class-style routes. - Added runtime dependencies:
got@^15,tiktok-live-proto@0.1.1. (hpagentwas added for proxying, then removed in favour of consumer-supplied agents — supply your own proxy agent viawebClientOptions.agent/wsClientOptions.agent.) @eulerstream/euler-api-sdkbumped from0.1.7to0.3.0— its API surface (notablySignTikTokUrlBodyMethodEnum,SignWebcastUrl200Response) has shifted; consumers that imported from@eulerstream/euler-api-sdk/dist/sdk/apishould now import from the package root.
src/lib/index.tsre-exports collapsed. Previous:client,utilities,web,ws,_legacy,config. Now only:client,ws/lib/proto-utils,ws/lib/ws-client. Deep imports viatiktok-live-connector/lib/...were never supported, but anything that pulledWebcastConfig,Config,EulerSigner,TikTokWebClient,WebcastPushConnection, etc. from the package root no longer resolves.src/types/index.tsdrops./routeand./tiktok-schemaexports; instead re-exportstiktok-live-proto/v2. TheRouteabstract class andtiktok-schemasymbols are no longer in the barrel.src/lib/_legacy/is gone.WebcastPushConnectionandsimplifyObjectmoved tosrc/lib/client/legacy/. The class still exists, but you import it viatiktok-live-connector/legacy, not via the root barrel.src/lib/client.tsis gone.TikTokLiveConnectionlives atsrc/lib/client/index.ts.src/lib/config.tsis gone. Its contents are split intosrc/lib/web/defaults.ts,src/lib/web/config.ts,src/lib/web/lib/device-presets.ts,src/lib/ws/defaults.ts,src/lib/ws/config.ts. TheConfigdefault export and theWebcastConfiginterface are removed.src/lib/utilities.tsis gone. Proto helpers moved tosrc/lib/ws/lib/proto-utils.ts;randomLongStringis gone (see §10); device-preset helpers moved tosrc/lib/web/lib/device-presets.ts.src/lib/web/index.tsis empty. TheTikTokWebClientwrapper class is removed (see §5).src/lib/web/lib/tiktok-signer.tsis removed. TheEulerSignerstandalone class is gone; signing now goes throughRouteConfig.fetchWebcastSignatureFromProvider.src/lib/web/routes/reorganised from a flat folder intobase/,euler/,composite/subfolders (see §6). The flat module paths (@/lib/web/routes/fetch-room-info, etc.) no longer exist.src/types/general.tsremoved along with itsWebSocketStatusCodeenum.src/types/web.tsandsrc/types/ws.tsare new.
The constructor signature (uniqueId, options) is unchanged, but the shape of options is fundamentally different.
Before:
new TikTokLiveConnection(uniqueId, {
sessionId: '...',
ttTargetIdc: 'useast1a',
oauthToken: '...'
});After:
new TikTokLiveConnection(uniqueId, {
session: {
cookie: { type: 'cookie', value: { sessionId: '...', ttTargetIdc: 'useast1a' } },
oAuthToken: { type: 'oAuthToken', value: '...' },
},
});Notes:
CookieSessionBundleandOAuthTokenSessionBundleare discriminated unions tagged withtype. The discriminator on the OAuth bundle is'oAuthToken'(capital A) — earlier in this development cycle it was briefly'oauthToken'; if you wrote against an interim version, update the tag.useMobile: truenow requiressession.cookieandauthenticateWs: trueat the type level.authenticateWs: true(without mobile) also requiressession.cookie.
| Removed | Replacement |
|---|---|
enableRequestPolling, requestPollingIntervalMs |
Polling fallback dropped entirely; the connection is WebSocket-only. |
connectWithUniqueId |
connect() always uses uniqueId to resolve a roomId if one is not supplied/cached; there is no separate flag. |
disableEulerFallbacks |
Replace with per-route toggles on IsLiveRouteConfig / by overriding handlers on RouteConfig (see §6). |
signedWebSocketProvider |
Replace by overriding RouteConfig.fetchSignedWebSocketFromProvider globally (or via your own eulerApiInstance). |
webClientHeaders, webClientParams |
Folded into webClientOptions.headers / webClientOptions.searchParams, or globally via webConfigOverrides.DEFAULT_HTTP_CLIENT_HEADERS / .DEFAULT_HTTP_CLIENT_PARAMS. |
wsClientHeaders, wsClientParams |
Folded into wsClientOptions.headers and wsConfigOverrides.DEFAULT_WS_CLIENT_PARAMS. |
webClientOptions: AxiosRequestConfig |
Now webClientOptions: WebcastGotHttpConfig (got's OptionsInit minus url / prefixUrl / searchParams / cookieJar). Axios-shaped options will not type-check or behave correctly. |
wsClientOptions: ClientOptions |
Same ws.ClientOptions type, but the surrounding wiring changed (see §5). |
clientPresets?: GetWebConfigParams— supply fixeddevice/screen/locationpresets. If omitted, random presets are picked per connection (was hard-coded inside the oldConfigmodule).webConfigOverrides?: Partial<WebcastWebConfigDefaults>— patch the static web defaults (host, default headers/params, cookie names, IDC name).wsConfigOverrides?: Partial<WebcastWebSocketConfigDefaults>— patch the static ws defaults (host, params, headers, ping interval, version-code suffix).eulerApiInstance?: EulerStreamApiClient— inject a pre-built Euler SDK client; if omitted, one is created fromsignApiKey(orSIGN_API_KEYenv).
TikTokLiveConnectionState gains an isConnecting: boolean field. Anything destructuring or asserting on the previous 4-field shape (isConnected, roomId, roomInfo, availableGifts) needs to be updated.
apiClientgetter (returns the underlyingEulerStreamApiClient) is new;webClient.webSigneris gone.webClientgetter still returns aWebcastHttpClient, but it is the rewritten got-based one, not the axios wrapper (see §5).wsClientgetter now returnsWebcastWebSocketClient | null(renamed fromTikTokWsClient).- The
state.isConnectingproperty is observable while aconnect()call is in flight. - The
clientParamsgetter still proxies towebClient.clientParams, but that object is now read-only at the top level and merged per-call (see §5).
- Constructor signature changed:
- Was
new WebcastHttpClient(config: WebcastHttpClientConfig, webSigner?: EulerSigner). - Now
new WebcastHttpClient(webcastWebConfig: WebcastWebConfigDefaults, eulerApiInstance?: EulerStreamApiClient, gotHttpConfig?: WebcastGotHttpConfig).
- Was
- The
WebcastHttpClientConfigtype is removed. ItscustomHeaders/axiosOptions/clientParams/signApiKey/oauthTokenfields no longer exist. axiosInstancefield is removed;_gotInstanceis the new transport (and isprotected).webSignerfield is removed. URL signing flows throughRouteConfig.fetchWebcastSignatureFromProvider.clientParamsis now areadonlyobject filled fromwebcastWebConfig.DEFAULT_HTTP_CLIENT_PARAMS. Mutating it after the fact is no longer the supported way to add params; pass them per-call viarequest({ searchParams }), or overridewebConfigOverrides.clientHeadersis new (was implicit onaxiosInstance.defaults.headers).oAuthSessionBundleis new (a typedOAuthTokenSessionBundle | nullslot).request({ params })→request({ searchParams }). The argument shape (WebcastHttpClientRequestParams) is nowOmit<OptionsInit, 'url' | 'prefixUrl' | 'searchParams' | 'cookieJar' | 'headers'> & { host, path, headers?, searchParams?, signRequest, ... }. Axios-styleparamswill silently fail.
CookieJar→WebcastCookieJar(default export fromsrc/lib/web/lib/cookie-jar.ts). ImplementsAbstractWebcastCookieJar(extends got'sPromiseCookieJar).- Constructor:
new WebcastCookieJar(webConfig: WebcastWebConfigDefaults)(wasnew CookieJar(axiosInstance, cookies?)). - The internal
cookiesrecord is renamedstore. The Proxy that exposed cookies as direct properties of the jar is gone — read/write viastore[name]orgetCookie/setCookie. - Direct getters/setters removed:
sessionId,ttTargetIdc,setSession(sessionId, ttTargetIdc),buildSessionCookieHeader(...). Replaced by:await jar.getSessionBundle(): Promise<CookieSessionBundle | null>await jar.setSessionBundle(session: CookieSessionBundle): Promise<void>WebcastCookieJar.serializeCookieSessionBundle(webConfig, bundle)(static helper)
processSetCookieHeaderis nowasyncand takesunknown(got passes header arrays).readCookies/appendCookies(axios interceptor methods) are gone; the integration is via got'scookieJaroption, set automatically byWebcastHttpClient.
- Class renamed and moved off of the manual constructor pattern onto a provider factory.
- Old:
new TikTokWsClient(wsUrl, cookieJar, webSocketParams, webSocketHeaders, webSocketOptions, pingIntervalMs). - New: produced by
createWebSocketProvider(webcastWebSocketConfig, wsClientOptions?), which returns(dynamicParams: WebSocketDynamicParams) => WebcastWebSocketClient. Direct construction isnew WebcastWebSocketClient(mergedConfig, wsClientOptions?). WebSocketDynamicParams={ roomId, baseUrl, wsParams, wsHeaders }. Anyone instantiating the WS client directly must provide these.
- Old:
- The standalone
pingIntervalMsconstructor argument is gone — it's nowwebcastWebSocketConfig.DEFAULT_WS_PING_INTERVAL. - The cookie jar is no longer passed to the WS client; the connection serialises cookies from the cookie jar into
wsHeaders.Cookiebefore constructing the client. - Heartbeat now uses the running
seqIdinstead of a constant'1'forsendPacketSeqId. Mock servers / sniffers that pinned to'1'will see new values. - Heartbeat / ACK frames now also fire when
protoMessageFetchResult?.internalExtis missing they are skipped (with aconsole.errorwarning suppressible viaDISABLE_ACK_LOG_WARNING=1). Previously this would crash with aTypeError. Behaviour change for anyone catching that error. - The typed
EventMapwas inlined in the file; it now lives insrc/types/ws.tsasWebcastWebSocketEventMap/WebcastTypedWebSocket.
The TikTokWebClient wrapper class (which exposed fetchRoomInfo / fetchRoomIdFromEuler / sendRoomChatFromEuler / etc. as instance fields) is deleted. Use the route functions or the RouteConfig registry instead (§6), passing a webClient: WebcastHttpClient and (for Euler routes) apiClient: EulerStreamApiClient.
The flat Route class hierarchy is replaced with a function-based architecture and a runtime-overridable global registry.
-
abstract class Route<Args, Response> extends CallableInstance<...>is removed. -
All
FetchXxxRouteclasses (FetchRoomInfoRoute,FetchRoomInfoFromHtmlRoute,FetchRoomInfoFromApiLiveRoute,FetchSignedWebSocketFromEulerRoute,FetchRoomIdFromEulerRoute,FetchRoomInfoFromEulerRoute,SendRoomChatFromEulerRoute) are removed. -
Each route is now a plain async function created by the
createRoute(routeId, handler)wrapper from@/lib/web/lib/route-wrapper. They take an args object and return a Promise.Old:
const route = new FetchRoomInfoFromEulerRoute(webClient); const info = await route({ roomId });
New:
import { fetchRoomInfoFromEulerRoute } from 'tiktok-live-connector'; const info = await fetchRoomInfoFromEulerRoute({ webClient, apiClient, roomId });
The src/lib/web/routes/*.ts flat layout is gone. Routes now live under:
| Group | Path | Members |
|---|---|---|
base/ |
src/lib/web/routes/base/ |
fetchRoomInfoRoute, fetchRoomInfoFromHtmlRoute, fetchRoomInfoFromApiLiveRoute, fetchRoomGiftsRoute |
euler/ |
src/lib/web/routes/euler/ |
fetchRoomIdFromEulerRoute, fetchRoomInfoFromEulerRoute, fetchSignedWebSocketFromEulerRoute, sendRoomChatFromEulerRoute, fetchWebcastSignatureFromEulerRoute (new) |
composite/ |
src/lib/web/routes/composite/ |
fetchRoomIdComposite, fetchIsLiveComposite |
Imports from the old paths (@/lib/web/routes/fetch-room-info, etc.) no longer resolve.
A new global mutable registry lives at src/lib/web/config.ts:
import { RouteConfig } from 'tiktok-live-connector';
RouteConfig.fetchRoomInfo = async ({ webClient, roomId }) => { /* override */ };
RouteConfig.fetchSignedWebSocketFromProvider = async (params) => { /* swap Euler for your own */ };TikTokLiveConnection and WebcastHttpClient now read all overridable handlers from this registry. The signedWebSocketProvider connection option (§4) is replaced by overriding RouteConfig.fetchSignedWebSocketFromProvider globally.
RoomGiftsResponseis a new dedicated type for the room-gifts response;RoomGiftInfois still re-exported but isany.IsLiveRouteConfig(boolean toggles for skipping each fallback method) is exported fromsrc/lib/web/routes/composite/fetch-is-live.tsand replaces the olddisableEulerFallbacksconnection option.- New per-route ID enums in
src/lib/web/routes/routes.ts(BaseFetchRoute,EulerFetchRoute,CompositeFetchRoute) used as therouteIdthread for error context.
src/types/errors.ts was rewritten:
| Removed | Notes |
|---|---|
FetchIsLiveError |
Replaced by InvalidResponseCompositeError. |
MissingRoomIdError |
No replacement; absent room IDs now surface as InvalidResponseError from the composite room-id route. |
FetchSignedWebSocketIdentityParameterError |
No replacement. |
| Changed | Notes |
|---|---|
InvalidResponseError |
Constructor was (message: string, requestErr?: Error). Now (config: { routeId: string, requestErr?: Error }, ...args: string[]). The first argument is a config object, not a string. The name field is no longer manually set. |
SignAPIError |
Varargs accept string | Error | undefined; Error values are unwrapped to .message when assembling the rendered string. |
| Added | Notes |
|---|---|
InvalidRequestError |
(config: { routeId }, ...args: string[]). |
InvalidResponseCompositeError |
(config: { routeId, requestErrs?: Error[] }, ...args: string[]). Aggregates per-source errors from composite fallback flows. |
ConnectTimeoutError extends ConnectError |
Thrown when the websocket fails to open within WS_CONNECT_TIMEOUT_MS (default 20000). |
WebcastEvent.SUPER_FAN_BOX = 'superFanBox'added (commitb609a02,2026-02-28).ClientEventMapgained the matchingEventHandler<WebcastEnvelopeMessage>entry. The duplicateSUPER_FANentry that used to live in the map was removed (no behaviour change, but the prior duplicate is gone if you grepped for it).WebcastEvent.SUPER_FAN_JOIN = 'superFanJoin'added (commit35501c7,2026-04-22). Distinguishes "an existing super fan joined the live" (SUPER_FAN_JOIN) from "someone became a super fan" (SUPER_FAN). Listeners that were treating everyttlive_superfan*barrage asSUPER_FANwill now receive only the "became super fan" subset; the "joined" subset routes toSUPER_FAN_JOINand should be subscribed to separately.- The
[WebcastEvent.SUPER_FAN]handler payload is unchanged (WebcastBarrageMessage). [ControlEvent.WEBSOCKET_CONNECTED]payload type renamedTikTokWsClient→WebcastWebSocketClient(same shape, new name).WebcastTypedClient(new () => TypedEventEmitter<ClientEventMap>) is now exported fromsrc/types/events.ts.
The monolithic Config default export is gone; configuration is now domain-scoped and value-keyed.
| Old | New |
|---|---|
Config.TIKTOK_HOST_WEB, Config.TIKTOK_HOST_WEBCAST, Config.TIKTOK_HTTP_ORIGIN, Config.DEFAULT_HTTP_CLIENT_* |
WebcastWebConfigDefaults (object) in src/lib/web/defaults.ts |
Config.DEFAULT_WS_CLIENT_* |
WebSocketConfigDefaults (object) and the WebcastWebSocketConfigDefaults type in src/lib/ws/defaults.ts |
| Implicit static defaults | getWebConfig({ device, screen, location }) returns a freshly-cloned config with templated values resolved |
| Implicit static defaults | getWebSocketConfigDefaults({ device, screen, location }) for the WS counterpart |
| Implicit static random selection | getRandomPresets() returns { device, screen, location }; expose them on the connection via clientPresets if you want to lock them. |
Config.DEFAULT_HTTP_CLIENT_COOKIES |
Removed; default cookies are seeded from WebcastWebConfigDefaults.DEFAULT_HTTP_CLIENT_HEADERS.Cookie and parsed into the cookie-jar store. |
WebcastConfig interface |
Removed. Use typeof WebcastWebConfigDefaults (exported as a type alias). |
EulerSigner class |
Removed. Use RouteConfig.fetchWebcastSignatureFromProvider or createEulerClient() from src/lib/web/routes/euler/config.ts. |
SignConfig (process-wide config from the SDK) |
Still global, but now imported from @eulerstream/euler-api-sdk via src/lib/web/routes/euler/config.ts. The connection writes SignConfig.apiKey = options.signApiKey if a key is supplied. |
New config-related public types in src/types/web.ts: LocationPreset, DevicePreset, ScreenPreset, GetWebConfigParams, GetWebSocketConfigParams, WebSocketDynamicParams, AbstractWebcastCookieJar, WebcastGotHttpConfig.
randomLongString()→generateUniqId()(moved tosrc/lib/ws/lib/ws-utils.ts). Same algorithm; renamed for clarity. Imports ofrandomLongStringfrom@/lib/utilitieswill fail.generateDeviceId()anduserAgentToDevicePreset()moved from@/lib/utilitiesto@/lib/web/lib/device-presets.ts.validateAndNormalizeUniqueId(uniqueId)now takesunknownand returnsstring(was loosely typed); throwsInvalidUniqueIdErrorfor non-strings.createBaseWebcastPushFramenow defaults the payload toBuffer.from([])instead ofnew Uint8Array()(matches got/ws expectations on Node).- The
EulerSignerre-export from@/libis gone (see §9).
Still ships, but with significant churn:
- Import path moved. Was importable from
tiktok-live-connector; now only viatiktok-live-connector/legacy. - Constructor signature changed transitively — it inherits from the new
TikTokLiveConnection, so the session-bundle changes from §4 apply equally here. - The class is typed against a stricter
WebcastPushConnectionBasecast; the old(...args: any[])escape hatch is gone. Subclassers that relied on the loose cast must adopt the(uniqueId, options)signature. WebcastControlMessage.actionis now guarded againstundefinedbefore the[3, 4].includes(action)check; theaction == nullcase used to throw, now it's a no-op.- The fire-and-forget
this.disconnect()on stream-end is nowvoid this.disconnect().catch(() => {})— unhandled rejections from a stream-end disconnect no longer surface. WebcastEvent.SUPER_FAN_JOINis also routed inside the legacy flow (viaresolveLegacySuperFanBarrageEvent), so legacy listeners forSUPER_FANwill likewise see only the "became super fan" subset (see §8).
| Var | Effect | Status |
|---|---|---|
TIKTOK_CLIENT_TIMEOUT |
Per-request got timeout (ms). Default 10000. |
Same name, now applied to got's timeout.request instead of axios's timeout. |
WS_CONNECT_TIMEOUT_MS |
New. Connect timeout in ms (default 20000) before ConnectTimeoutError is thrown. |
New. |
DISABLE_ACK_LOG_WARNING |
New. Suppresses the console.error warning when an ACK frame is skipped due to a missing internalExt. |
New. |
SIGN_API_KEY |
Picked up by the Euler SDK if signApiKey isn't passed. |
Unchanged. |
- Rewrite
require('tiktok-live-connector')asimport { TikTokLiveConnection } from 'tiktok-live-connector'. If you usedWebcastPushConnection, switch toimport { WebcastPushConnection } from 'tiktok-live-connector/legacy'. - Replace
sessionId/ttTargetIdc/oauthTokenconstructor options with thesession: { cookie, oAuthToken }bundle shape (note the capitalAinoAuthToken). - Replace
webClientHeaders/webClientParams/wsClientHeaders/wsClientParamswithwebClientOptions/wsClientOptions(got-shaped) orwebConfigOverrides/wsConfigOverrides. - Replace
signedWebSocketProviderwith aRouteConfig.fetchSignedWebSocketFromProvideroverride. - Replace any
new FetchXxxRoute(...)andnew TikTokWebClient(...)usage with the new functional routes (fetchXxxRoute({ webClient, apiClient, ... })orRouteConfig.xxx(...)). - Replace any
axios-shaped request options withgot-shaped equivalents. - Update protobuf imports from
@/types/tiktok-schema(or the package barrel) totiktok-live-proto/v2. Updatedeclare moduleaugmentations accordingly. - Update direct cookie-jar access (
jar.sessionId,jar.setSession(...)) tojar.getSessionBundle()/jar.setSessionBundle(...). - Update
InvalidResponseErrorconstructor calls to pass{ routeId }as the first argument instead of a string message. - Subscribe to
WebcastEvent.SUPER_FAN_JOINif you previously relied onSUPER_FANcovering the "joined" sub-case. - Consume
state.isConnectingif you destructureTikTokLiveConnectionState. - Bump TS to 5.x and ensure your tsconfig is ESM-friendly (
module: ESNext/moduleResolution: BundlerorNodeNext).