tca-js 0.4.1 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/api.ts","../src/protocol/constants.ts","../src/protocol/proto.ts","../src/errors.ts","../src/listener/listener.ts","../src/models/message.ts","../src/listener/frame.ts","../src/protocol/lz4.ts","../src/api/account.ts","../src/api/media.ts","../src/api/requests.ts","../src/protocol/context.ts","../src/client.ts","../src/auth/qr-login.ts","../src/auth/cdp.ts","../src/auth/chrome.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { Cmd, MARK_READ_BODY_FIELD, MessageType, WEB } from '../protocol/constants';\nimport type { Context } from '../protocol/context';\nimport { Writer } from '../protocol/proto';\nimport { TikTokError } from '../errors';\nimport { Listener } from '../listener/listener';\nimport { parseConversation, parseMessage } from '../models/message';\nimport type {\n ConversationPage,\n ConversationRef,\n ImageInput,\n MessagePage,\n TikTokAccount,\n TikTokImage,\n TikTokMessage,\n TikTokSticker,\n TikTokUser,\n} from '../models/types';\nimport { avatarLinks, fetchAccount } from './account';\nimport { MediaClient } from './media';\nimport {\n getMessagesBody,\n imageMessageExtra,\n markReadBody,\n reactionOps,\n sendMessageBody,\n setPropertyBody,\n} from './requests';\n\n/** Send result: client-side message id (TikTok echoes it back). The server id arrives via the listener (`isSelf`). */\nexport interface SendResult {\n clientMessageId: string;\n}\n\n/**\n * A logged-in TikTok session — create with `new TikTok().login(credentials)`.\n * All calls go directly over HTTP/WS to TikTok using cookies, no browser needed.\n */\nexport class API {\n readonly listener: Listener;\n private readonly media: MediaClient;\n\n constructor(\n private readonly ctx: Context,\n readonly account: TikTokAccount,\n ) {\n this.listener = new Listener(ctx);\n this.media = new MediaClient(ctx);\n }\n\n getOwnId(): string {\n return this.ctx.ownId;\n }\n\n /** Current cookies — save them so the next `login` needs no QR scan. */\n getCookies(): { name: string; value: string }[] {\n return [...this.ctx.cookies].map(([name, value]) => ({ name, value }));\n }\n\n getContext(): { deviceId: string; userAgent: string } {\n return { deviceId: this.ctx.deviceId, userAgent: this.ctx.userAgent };\n }\n\n /** Whether the session is still alive — call periodically to detect expiry early. */\n async isAlive(): Promise<boolean> {\n return (await fetchAccount(this.ctx).catch(() => null)) !== null;\n }\n\n // ─── Inbox ─────────────────────────────────────────────────────────────────\n\n /** Recent conversations + their latest messages, paginated with `cursor`. */\n async getConversations(cursor = '0'): Promise<ConversationPage> {\n const body = await this.ctx.im(\n '/v2/message/get_by_user_init',\n Cmd.GetMessagesByUserInit,\n new Writer().int(1, BigInt(cursor)).finish(),\n );\n return {\n messages: body.msgs(1).map((m) => parseMessage(m, this.ctx.ownId)),\n conversations: body.msgs(2).map((m) => parseConversation(m, this.ctx.ownId)),\n // Cursor = number of conversations fetched so far (0, 10, 20…) — field 4; field 3 is a timestamp, not used for paging.\n cursor: body.id(4),\n hasMore: body.num(5) === 1,\n };\n }\n\n /** Messages of a conversation, newest first. For older messages: `before = <index of oldest message>`. */\n async getMessages(conv: ConversationRef, opts: { limit?: number; before?: string } = {}): Promise<MessagePage> {\n const limit = Math.min(Math.max(opts.limit ?? 20, 1), 50);\n const body = await this.ctx.im(\n '/v1/message/get_by_conversation',\n Cmd.GetMessagesByConversation,\n getMessagesBody(conv, limit, opts.before),\n );\n const messages = body.msgs(1).map((m) => parseMessage(m, this.ctx.ownId));\n return { messages, hasMore: messages.length >= limit };\n }\n\n /** User profiles by uid (display name, @username, avatar). */\n async getUsers(uids: string[]): Promise<TikTokUser[]> {\n if (uids.length === 0) return [];\n const q = new URLSearchParams({\n aid: '1988',\n app_name: 'tiktok_web',\n device_platform: 'web_pc',\n source: 'im_chat',\n from_page: 'message',\n user_ids: JSON.stringify(uids),\n });\n type Res = {\n status_code?: number;\n users?: {\n im_user_profile?: {\n user_id_str?: string;\n unique_id?: string;\n nick_name?: string;\n avatars?: unknown;\n };\n }[];\n };\n const res = await this.ctx.getJson<Res>(`${WEB}/tiktok/v1/im/user/profile/?${q}`);\n if (res.status_code) throw new TikTokError('IM_ERROR', `user/profile: ${res.status_code}`, res.status_code);\n return (res.users ?? []).map(({ im_user_profile: p = {} }) => ({\n uid: p.user_id_str ?? '',\n uniqueId: p.unique_id ?? '',\n nickname: p.nick_name ?? '',\n ...avatarLinks(p.avatars),\n }));\n }\n\n /**\n * Download an avatar (tries each URL in turn, skips heic). No cookie / Referer sent: the image CDN is cross-origin and\n * URLs are already signed. `null` if no URL could be downloaded.\n */\n async downloadAvatar(user: Pick<TikTokUser, 'avatars'>): Promise<{ data: Buffer; type: string } | null> {\n for (const url of user.avatars) {\n const res = await fetch(url, {\n headers: { 'User-Agent': this.ctx.userAgent },\n referrerPolicy: 'no-referrer',\n signal: AbortSignal.timeout(this.ctx.options.timeoutMs ?? 20_000),\n }).catch(() => null);\n const type = res?.headers.get('content-type') ?? '';\n if (!res?.ok || !/^image\\/(jpeg|png|webp|gif)/.test(type)) continue;\n return { data: Buffer.from(await res.arrayBuffer()), type };\n }\n return null;\n }\n\n /** Mark as read up to message `msg`. */\n async markRead(msg: ConversationRef & { index: string }): Promise<void> {\n await this.ctx.im('/v3/conversation/mark_read', Cmd.MarkRead, markReadBody(msg), MARK_READ_BODY_FIELD);\n }\n\n // ─── Send ─────────────────────────────────────────────────────────────────\n\n /** Send a text message to a conversation (usually the just-received `msg` — it carries the conversation ids). */\n async sendMessage(conv: ConversationRef, text: string): Promise<SendResult> {\n const cid = randomUUID();\n await this.send(conv, cid, MessageType.Text, JSON.stringify({ aweType: 0, text }), null);\n return { clientMessageId: cid };\n }\n\n /** Send an image: upload to the private (encrypted) store, then send an image message. */\n async sendImage(conv: ConversationRef, image: ImageInput): Promise<SendResult> {\n const up = await this.media.upload(image);\n const cid = randomUUID();\n await this.send(conv, cid, MessageType.PrivateImage, '', imageMessageExtra(up));\n return { clientMessageId: cid };\n }\n\n /**\n * Set YOUR reaction on a message — like TikTok Web, one reaction per user: a new `emoji` replaces the old one,\n * `null` = remove. Pass the whole `msg` just read (current `reactions` are needed to know which key to remove).\n * Sends `ModifyMessagePropertyRequestBody` (command 705) — see README.\n */\n async setReaction(msg: TikTokMessage, emoji: string | null): Promise<void> {\n const own = this.ctx.ownId;\n const ops = reactionOps(msg, own, emoji);\n if (ops.length === 0) return;\n const body = await this.ctx.im('/v1/message/set_property', Cmd.SetMessageProperty, setPropertyBody(msg, ops, own));\n // status: 0 success, 1 duplicate (also done); anything else means TikTok rejected it.\n const status = body.num(1);\n if (status > 1) throw new TikTokError('IM_ERROR', `set_property: status ${status}`, status);\n }\n\n // ─── Media ─────────────────────────────────────────────────────────────────\n\n /** Download a sticker image (public CDN, unencrypted, no cookie needed). */\n async downloadSticker(sticker: Pick<TikTokSticker, 'url'>): Promise<{ data: Buffer; type: string }> {\n const res = await fetch(sticker.url, {\n headers: { 'User-Agent': this.ctx.userAgent },\n referrerPolicy: 'no-referrer',\n signal: AbortSignal.timeout(this.ctx.options.timeoutMs ?? 20_000),\n }).catch(() => null);\n if (!res?.ok) throw new TikTokError('DOWNLOAD_FAILED', `Sticker download failed: ${res?.status ?? 'network'}`);\n return { data: Buffer.from(await res.arrayBuffer()), type: res.headers.get('content-type') ?? 'image/webp' };\n }\n\n /** Download + decrypt a message's image (pass the whole `msg` — listener messages lack the URL, this looks it up). */\n async downloadImage(source: TikTokMessage | TikTokImage, which: 'origin' | 'thumb' = 'origin'): Promise<Buffer> {\n let image = 'serverMessageId' in source ? source.image : source;\n // Websocket-pushed messages only have uri + key, no download URL → look up history by message id.\n if ('serverMessageId' in source && image && !image.url) {\n const { messages } = await this.getMessages(source, { limit: 5, before: (BigInt(source.index) + 1n).toString() });\n image = messages.find((m) => m.serverMessageId === source.serverMessageId)?.image ?? image;\n }\n if (!image) throw new TikTokError('DOWNLOAD_FAILED', 'Message has no image');\n return this.media.download(image, which);\n }\n\n private async send(\n conv: ConversationRef,\n cid: string,\n type: number,\n content: string,\n extra: Writer | null,\n ): Promise<void> {\n if (!conv.conversationId || !conv.conversationShortId) {\n throw new TikTokError('IM_ERROR', 'Missing conversationId / conversationShortId');\n }\n await this.ctx.im('/v1/message/send', Cmd.SendMessage, sendMessageBody(conv, cid, type, content, extra));\n }\n}\n","/**\n * TikTok Web IM protocol constants — reconstructed from `tiktok.com/business-suite/messages` traffic\n * (09/11/2026). If TikTok changes things on their side, fix them here; how they were found is in the README.\n */\n\nexport const IM_API = 'https://im-api-sg.tiktok.com';\nexport const IM_WS = 'wss://im-ws-sg.tiktok.com/ws/v2';\nexport const WEB = 'https://www.tiktok.com';\n\nexport const DEFAULT_USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.0.0 Safari/537.36';\n\n/** TikTok Web app id (HTTP IM). */\nexport const AID_WEB = '1988';\n/** \"frontier\" channel app id — websocket pushing new messages. */\nexport const AID_FRONTIER = '1459';\nexport const SDK_VERSION = '1.8.5';\nexport const BUILD_NUMBER = 'feffaa1:master';\n\n/** Websocket `access_key` = md5(FPID + APP_KEY + device_id + SALT). */\nexport const FRONTIER_FPID = '9';\nexport const FRONTIER_APP_KEY = 'e1bd35ec9db7b8d846de66ed140b1ad9';\nexport const FRONTIER_SALT = 'f8a69f1719916z';\n\n/** IM command (`Request.cmd`) — also the body's field number in `RequestBody`. */\nexport const Cmd = {\n SendMessage: 100,\n GetMessagesByUserInit: 203,\n GetMessagesByConversation: 301,\n /** Websocket push of new messages. */\n NewMessage: 500,\n /** Add / remove a reaction (message `property`) — `/v1/message/set_property`. */\n SetMessageProperty: 705,\n GetConversationInfo: 610,\n MarkRead: 2002,\n UploadConfig: 2059,\n} as const;\n\n/** MarkRead's body lives in field 604, not the command number. */\nexport const MARK_READ_BODY_FIELD = 604;\n\n/** `MessageBody.message_type`. */\nexport const MessageType = {\n System: 1,\n Text: 7,\n ShareVideo: 8,\n PrivateImage: 1802,\n /** Sticker — public image on the sticker CDN, not encrypted. */\n Sticker: 1805,\n /** Hidden command (read receipt…) — not shown in the conversation, but still pushed over websocket. */\n Command: 50001,\n} as const;\n\nexport const ConversationType = { OneToOne: 1 } as const;\n\n/** `Response` fields (both HTTP and websocket payload). */\nexport const Resp = { cmd: 1, seq: 2, status: 3, error: 4, body: 6, logId: 7 } as const;\n\n/** `MessageBody` fields. */\nexport const MsgF = {\n conversationId: 1,\n conversationType: 2,\n serverMessageId: 3,\n indexInConversation: 4,\n conversationShortId: 5,\n type: 6,\n sender: 7,\n content: 8,\n ext: 9,\n createTime: 10,\n /** `property_list` — reaction: `{1 key \"e:<emoji>\", 2 {1 PropertyItem[]}}`. */\n propertyList: 15,\n attachments: 20,\n tag: 21,\n} as const;\n\n/** Operation on a message `property` (`ModifyPropertyContent.operation`). */\nexport const PropertyOp = { Add: 0, Remove: 1 } as const;\n\n/** Reaction key = `e:<emoji>`. The mobile app reacting ❤️ also writes the legacy key `e:love` — treated as ❤️. */\nexport const REACTION_PREFIX = 'e:';\nexport const REACTION_LOVE_KEY = 'e:love';\nexport const REACTION_HEART = '\\u2764\\uFE0F';\n\n/** ImageX — image upload endpoint (AWS SigV4-style signing). */\nexport const IMAGEX_REGION = 'cn-north-1';\nexport const IMAGEX_SERVICE = 'imagex';\nexport const IMAGEX_VERSION = '2018-08-01';\n","/**\n * Minimal protobuf, no `.proto` file needed.\n *\n * TikTok doesn't publish its IM `.proto` — field numbers in `constants.ts` were reconstructed from bytes captured\n * in the browser (09/11/2026). Only three wire types are needed: varint (0), length-delimited (2), and skipping 1/5.\n */\n\nexport interface Field {\n n: number;\n wire: number;\n int: bigint;\n bytes: Buffer;\n}\n\nfunction readVarint(b: Buffer, i: number): [bigint, number] {\n let x = 0n;\n let shift = 0n;\n let c: number;\n do {\n if (i >= b.length) throw new Error('varint runs past end of buffer');\n c = b[i++];\n x |= BigInt(c & 127) << shift;\n shift += 7n;\n } while (c & 128);\n return [x, i];\n}\n\n/** Split a message into a list of fields. `null` if the bytes are not valid protobuf. */\nexport function decodeFields(b: Buffer): Field[] | null {\n const out: Field[] = [];\n let i = 0;\n try {\n while (i < b.length) {\n const [key, j] = readVarint(b, i);\n i = j;\n const wire = Number(key & 7n);\n const n = Number(key >> 3n);\n if (n === 0) return null;\n if (wire === 0) {\n const [v, k] = readVarint(b, i);\n out.push({ n, wire, int: v, bytes: Buffer.alloc(0) });\n i = k;\n } else if (wire === 2) {\n const [len, k] = readVarint(b, i);\n const end = k + Number(len);\n if (end > b.length) return null;\n out.push({ n, wire, int: 0n, bytes: b.subarray(k, end) });\n i = end;\n } else if (wire === 1 || wire === 5) {\n const size = wire === 1 ? 8 : 4;\n if (i + size > b.length) return null;\n out.push({ n, wire, int: 0n, bytes: b.subarray(i, i + size) });\n i += size;\n } else {\n return null;\n }\n }\n } catch {\n return null;\n }\n return out;\n}\n\n/** Decoded message — read by field number. */\nexport class Msg {\n private constructor(readonly fields: Field[]) {}\n\n static parse(b: Buffer): Msg {\n const f = decodeFields(b);\n if (!f) throw new Error('Failed to decode protobuf');\n return new Msg(f);\n }\n\n static tryParse(b: Buffer | undefined): Msg | null {\n if (!b) return null;\n const f = decodeFields(b);\n return f ? new Msg(f) : null;\n }\n\n has(n: number): boolean {\n return this.fields.some((f) => f.n === n);\n }\n\n int(n: number): bigint {\n return this.fields.find((f) => f.n === n)?.int ?? 0n;\n }\n\n num(n: number): number {\n return Number(this.int(n));\n }\n\n /** 64-bit integer as a string — uids / message IDs exceed `Number.MAX_SAFE_INTEGER`. */\n id(n: number): string {\n return this.int(n).toString();\n }\n\n bytes(n: number): Buffer {\n return this.fields.find((f) => f.n === n)?.bytes ?? Buffer.alloc(0);\n }\n\n str(n: number): string {\n return this.bytes(n).toString('utf8');\n }\n\n strs(n: number): string[] {\n return this.fields.filter((f) => f.n === n).map((f) => f.bytes.toString('utf8'));\n }\n\n msg(n: number): Msg | null {\n return Msg.tryParse(this.fields.find((f) => f.n === n)?.bytes);\n }\n\n msgs(n: number): Msg[] {\n return this.fields\n .filter((f) => f.n === n)\n .map((f) => Msg.tryParse(f.bytes))\n .filter((m): m is Msg => m !== null);\n }\n\n /** `map<string,string>` — each entry is a message `{1: key, 2: value}`. */\n map(n: number): Record<string, string> {\n const out: Record<string, string> = {};\n for (const m of this.msgs(n)) out[m.str(1)] = m.str(2);\n return out;\n }\n}\n\nfunction varint(x: bigint | number): Buffer {\n let v = BigInt(x);\n if (v < 0n) v = BigInt.asUintN(64, v);\n const out: number[] = [];\n do {\n const c = Number(v & 127n);\n v >>= 7n;\n out.push(v ? c | 128 : c);\n } while (v);\n return Buffer.from(out);\n}\n\nconst key = (n: number, wire: number): Buffer => varint((BigInt(n) << 3n) | BigInt(wire));\n\n/** Build a message in call order. */\nexport class Writer {\n private readonly parts: Buffer[] = [];\n\n int(n: number, v: bigint | number | string): this {\n this.parts.push(key(n, 0), varint(typeof v === 'string' ? BigInt(v) : v));\n return this;\n }\n\n bytes(n: number, v: Buffer | string): this {\n const b = typeof v === 'string' ? Buffer.from(v, 'utf8') : v;\n this.parts.push(key(n, 2), varint(b.length), b);\n return this;\n }\n\n msg(n: number, w: Writer): this {\n return this.bytes(n, w.finish());\n }\n\n /** `map<string,string>` in the object's key order. */\n map(n: number, obj: Record<string, string>): this {\n for (const [k, v] of Object.entries(obj)) this.msg(n, new Writer().bytes(1, k).bytes(2, v));\n return this;\n }\n\n finish(): Buffer {\n return Buffer.concat(this.parts);\n }\n}\n","/** Error from TikTok or from the library itself. `code` lets callers branch (e.g. session expired → rescan). */\nexport class TikTokError extends Error {\n constructor(\n readonly code: TikTokErrorCode,\n message: string,\n /** Original TikTok code (status_code / error_code), if any. */\n readonly upstream?: number | string,\n ) {\n super(message);\n this.name = 'TikTokError';\n }\n}\n\nexport type TikTokErrorCode =\n /** Cookie is no longer logged in — a new session is required. */\n | 'SESSION_EXPIRED'\n /**\n * TikTok's gateway rejects this session for the command (JSON `status_code: 7` instead of protobuf). Seen on\n * `message/send` while reads keep working — log in again to get a fresh session.\n */\n | 'SESSION_BLOCKED'\n | 'HTTP_ERROR'\n /** IM returned a non-zero `status_code`. */\n | 'IM_ERROR'\n | 'UPLOAD_FAILED'\n | 'DOWNLOAD_FAILED'\n | 'BAD_RESPONSE'\n /** QR login failed (Chrome failed to launch, QR expired, no cookie found…). */\n | 'LOGIN_FAILED'\n /** Caller aborted QR login (`signal`). */\n | 'LOGIN_ABORTED';\n","import { EventEmitter } from 'node:events';\nimport WebSocket from 'ws';\nimport { AID_FRONTIER, FRONTIER_FPID, IM_WS, WEB } from '../protocol/constants';\nimport type { Context } from '../protocol/context';\nimport { parseMessage } from '../models/message';\nimport type { TikTokMessage } from '../models/types';\nimport { accessKey, buildAck, newMessageBody, parseFrame } from './frame';\n\n/** The browser sends \"hi\" every 15–30 seconds; use the lower bound. */\nconst HEARTBEAT_MS = 15_000;\n/** If nothing (not even a \"hi\" reply) arrives for this long, treat it as silently dead and reconnect. */\nconst IDLE_TIMEOUT_MS = 75_000;\nconst RECONNECT_MIN_MS = 2_000;\nconst RECONNECT_MAX_MS = 60_000;\n/** The server pushes the same message several times (one frame per device) — remember this many message IDs to dedupe. */\nconst DEDUPE_KEEP = 500;\n\n/** Close code used when we call `stop()` ourselves. */\nexport const MANUAL_CLOSE = 4000;\n\nexport interface ListenerEvents {\n connected: [];\n /** A real message in a conversation (including our own — see `isSelf`). */\n message: [TikTokMessage];\n /** Hidden command: mark as read… (`content.command_type`). */\n command: [TikTokMessage];\n /** Close code + reason. Unless `MANUAL_CLOSE`, the listener reconnects automatically (if enabled). */\n closed: [number, string];\n error: [Error];\n}\n\n/**\n * Listen for new messages via the `im-ws-sg` websocket (aid 1459) — cookies only.\n * Events: `connected`, `message`, `closed`, `error`.\n */\nexport class Listener extends EventEmitter<ListenerEvents> {\n private ws: WebSocket | null = null;\n private heartbeat: NodeJS.Timeout | null = null;\n private idle: NodeJS.Timeout | null = null;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private backoff = RECONNECT_MIN_MS;\n private retry = true;\n private readonly seen = new Set<string>();\n\n constructor(private readonly ctx: Context) {\n super();\n }\n\n get connected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n url(): string {\n const q = new URLSearchParams({\n aid: AID_FRONTIER,\n fpid: FRONTIER_FPID,\n device_platform: 'web',\n version_code: 'fws_1.0.0',\n access_key: accessKey(this.ctx.deviceId),\n device_id: this.ctx.deviceId,\n // Cookie value is already URL-encoded (`1%7C…`) — decode it so URLSearchParams doesn't double-encode.\n ttwid: decodeURIComponent(this.ctx.cookies.get('ttwid') ?? ''),\n xsack: '1',\n xaack: '1',\n xsqos: '0',\n });\n return `${IM_WS}?${q}`;\n }\n\n /** Open the connection. `retryOnClose` (on by default): reconnect on drop, backing off up to 1 minute. */\n start(opts: { retryOnClose?: boolean } = {}): void {\n this.retry = opts.retryOnClose ?? true;\n this.connect();\n }\n\n stop(): void {\n this.retry = false;\n this.clearTimers();\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n const ws = this.ws;\n this.ws = null;\n if (ws && ws.readyState <= WebSocket.OPEN) ws.close(MANUAL_CLOSE, 'manual');\n }\n\n private connect(): void {\n const ws = new WebSocket(this.url(), {\n headers: { Cookie: this.ctx.cookieHeader(), 'User-Agent': this.ctx.userAgent, Origin: WEB },\n });\n this.ws = ws;\n ws.binaryType = 'nodebuffer';\n ws.on('open', () => {\n this.backoff = RECONNECT_MIN_MS;\n this.heartbeat = setInterval(() => ws.readyState === WebSocket.OPEN && ws.send('hi'), HEARTBEAT_MS);\n this.touch();\n this.ctx.log('debug', 'tca: websocket connected');\n this.emit('connected');\n });\n ws.on('message', (data: Buffer, isBinary: boolean) => {\n this.touch();\n if (!isBinary) return; // \"hi\" reply\n try {\n this.onFrame(ws, data);\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n });\n ws.on('error', (err) => this.emit('error', err));\n ws.on('close', (code, reason) => {\n if (this.ws !== ws) return; // old connection was replaced\n this.ws = null;\n this.clearTimers();\n this.emit('closed', code, reason.toString());\n if (!this.retry || code === MANUAL_CLOSE) return;\n const wait = this.backoff;\n this.backoff = Math.min(this.backoff * 2, RECONNECT_MAX_MS);\n this.ctx.log('warn', `tca: websocket closed (${code}) — reconnecting in ${wait / 1000}s`);\n this.reconnectTimer = setTimeout(() => this.connect(), wait);\n });\n }\n\n private touch(): void {\n if (this.idle) clearTimeout(this.idle);\n this.idle = setTimeout(() => {\n this.ctx.log('warn', 'tca: websocket silent too long — reconnecting');\n this.ws?.terminate();\n }, IDLE_TIMEOUT_MS);\n }\n\n private clearTimers(): void {\n if (this.heartbeat) clearInterval(this.heartbeat);\n if (this.idle) clearTimeout(this.idle);\n this.heartbeat = null;\n this.idle = null;\n }\n\n private onFrame(ws: WebSocket, data: Buffer): void {\n const frame = parseFrame(data);\n if (frame.headers.need_ack === '1' && ws.readyState === WebSocket.OPEN) ws.send(buildAck(frame));\n const body = newMessageBody(frame);\n if (!body) return;\n const msg = parseMessage(body, this.ctx.ownId);\n if (!msg.serverMessageId || this.seen.has(msg.serverMessageId)) return;\n this.seen.add(msg.serverMessageId);\n if (this.seen.size > DEDUPE_KEEP) this.seen.delete(this.seen.values().next().value as string);\n if (msg.kind === 'command') this.emit('command', msg);\n else this.emit('message', msg);\n }\n}\n","import { MessageType, MsgF, REACTION_HEART, REACTION_LOVE_KEY, REACTION_PREFIX } from '../protocol/constants';\nimport { Msg } from '../protocol/proto';\nimport type { TikTokConversation, TikTokImage, TikTokMessage, TikTokReaction, TikTokSticker } from './types';\n\nfunction parseJson(s: string): unknown {\n try {\n return JSON.parse(s);\n } catch {\n return s;\n }\n}\n\n/** Image in `attachments` (field 20 → 4): 1 = original, 2 = thumbnail; each {1 uri, 2 url…, 5 {w,h}, 6 key}. */\nfunction parseImage(m: Msg): TikTokImage | null {\n const media = m.msg(MsgF.attachments)?.msg(4);\n const origin = media?.msg(1);\n if (!media || !origin) return null;\n const size = origin.msg(5);\n return {\n uri: origin.str(1),\n url: origin.strs(2)[0] ?? '',\n thumbUrl: media.msg(2)?.strs(2)[0] ?? '',\n width: size?.num(1) ?? 0,\n height: size?.num(2) ?? 0,\n decryptKey: origin.str(6),\n };\n}\n\n/**\n * Sticker (field 20 → 7): `{1 {1 uri, 2 url, 5 {w,h}}, 2 hint, 200 {1 {2 map a:sticker_id, a:sticker_type…}}}`.\n * Links point to the public sticker CDN (`…-dm-sticker-sign-…`) — not encrypted, no cookies needed.\n */\nfunction parseSticker(m: Msg): TikTokSticker | null {\n const st = m.msg(MsgF.attachments)?.msg(7);\n const img = st?.msg(1);\n if (!st || !img) return null;\n const size = img.msg(5);\n const ext = st.msg(200)?.msg(1)?.map(2) ?? {};\n return {\n stickerId: ext['a:sticker_id'] ?? '',\n stickerType: Number(ext['a:sticker_type'] ?? 0),\n url: img.str(2),\n width: size?.num(1) ?? 0,\n height: size?.num(2) ?? 0,\n };\n}\n\n/**\n * Reaction (field 15, `property_list`): each entry `{1 key, 2 {1 PropertyItem[]}}`, key `e:<emoji>`,\n * `PropertyItem {1 uid, 3 sec, 4 idempotent_id, 6 µs}`. The mobile app writes ❤️ as both `e:❤️` and `e:love` → merged.\n */\nfunction parseReactions(m: Msg): TikTokReaction[] {\n const byEmoji = new Map<string, Set<string>>();\n for (const p of m.msgs(MsgF.propertyList)) {\n const key = p.str(1);\n if (!key.startsWith(REACTION_PREFIX)) continue;\n const emoji = key === REACTION_LOVE_KEY ? REACTION_HEART : key.slice(REACTION_PREFIX.length);\n const uids = byEmoji.get(emoji) ?? new Set<string>();\n for (const item of p.msg(2)?.msgs(1) ?? []) uids.add(item.id(1));\n if (uids.size) byEmoji.set(emoji, uids);\n }\n return [...byEmoji].map(([emoji, uids]) => ({ emoji, userIds: [...uids] }));\n}\n\nconst KIND: Record<number, TikTokMessage['kind']> = {\n [MessageType.Text]: 'text',\n [MessageType.PrivateImage]: 'image',\n [MessageType.Sticker]: 'sticker',\n [MessageType.ShareVideo]: 'video',\n [MessageType.System]: 'system',\n [MessageType.Command]: 'command',\n};\n\n/** `MessageBody` → `TikTokMessage`. */\nexport function parseMessage(m: Msg, ownId: string): TikTokMessage {\n const type = m.num(MsgF.type);\n const content = parseJson(m.str(MsgF.content));\n const ext = m.map(MsgF.ext);\n const senderId = m.id(MsgF.sender);\n const text =\n type === MessageType.Text && content && typeof content === 'object' && 'text' in content\n ? String((content as { text: unknown }).text ?? '')\n : '';\n return {\n conversationId: m.str(MsgF.conversationId),\n conversationShortId: m.id(MsgF.conversationShortId),\n serverMessageId: m.id(MsgF.serverMessageId),\n index: m.id(MsgF.indexInConversation),\n type,\n kind: KIND[type] ?? 'other',\n senderId,\n isSelf: senderId === ownId,\n text,\n image: type === MessageType.PrivateImage ? parseImage(m) : null,\n sticker: type === MessageType.Sticker ? parseSticker(m) : null,\n reactions: parseReactions(m),\n content,\n createdAt: m.num(MsgF.createTime),\n clientMessageId: ext['s:client_message_id'] ?? '',\n ext,\n };\n}\n\n/** `ConversationInfo` (field 2 of get_by_user_init): {1 id, 2 shortId, 3 type, 6 {1 {1 uid}}…}. */\nexport function parseConversation(m: Msg, ownId: string): TikTokConversation {\n const participants = (m.msg(6)?.msgs(1) ?? []).map((p) => p.id(1));\n return {\n conversationId: m.str(1),\n conversationShortId: m.id(2),\n participants,\n peerId: participants.find((p) => p !== ownId) ?? '',\n };\n}\n","/**\n * \"Frontier\" websocket framing — pure helpers (no socket), shared by the listener and unit tests.\n */\nimport { createHash } from 'node:crypto';\nimport { Cmd, FRONTIER_APP_KEY, FRONTIER_FPID, FRONTIER_SALT, Resp } from '../protocol/constants';\nimport { lz4Decompress } from '../protocol/lz4';\nimport { Msg, Writer } from '../protocol/proto';\n\n/** \"Frontier\" websocket frame: {1 seqid, 2 logid, 3 service, 4 method, 5 headers, 6 encoding, 7 type, 8 payload}. */\nexport interface Frame {\n seq: bigint;\n logId: bigint;\n headers: Record<string, string>;\n encoding: string;\n payload: Buffer;\n}\n\n/** Websocket `access_key` = md5(FPID + APP_KEY + device_id + SALT). */\nexport function accessKey(deviceId: string): string {\n return createHash('md5')\n .update(FRONTIER_FPID + FRONTIER_APP_KEY + deviceId + FRONTIER_SALT)\n .digest('hex');\n}\n\nexport function parseFrame(data: Buffer): Frame {\n const m = Msg.parse(data);\n return {\n seq: m.int(1),\n logId: m.int(2),\n headers: m.map(5),\n encoding: m.str(6),\n payload: m.bytes(8),\n };\n}\n\n/** The `MessageBody` of a `NewMessage` push inside a frame, or `null` if the frame carries something else. */\nexport function newMessageBody(frame: Frame): Msg | null {\n if (frame.payload.length === 0) return null;\n const payload = frame.encoding === '__lz4' ? lz4Decompress(frame.payload) : frame.payload;\n const resp = Msg.tryParse(payload);\n if (!resp || resp.num(Resp.cmd) !== Cmd.NewMessage) return null;\n // NewMessageNotify: {2 conversationId, 3 type, 4 ?, 5 MessageBody}\n return resp.msg(Resp.body)?.msg(Cmd.NewMessage)?.msg(5) ?? null;\n}\n\n/** Acknowledge receipt — `ack_id = <base36 time>:<x_frontier_traceid>`, echoing the frame's seq/logid. */\nexport function buildAck(f: Frame, now: number = Date.now()): Buffer {\n const ackId = `${now.toString(36)}:${f.headers.x_frontier_traceid ?? ''}`;\n return new Writer()\n .int(1, f.seq)\n .int(2, f.logId)\n .int(3, 5)\n .int(4, 1)\n .map(5, { is_ack: '1', ack_id: ackId, ack_code: '0' })\n .bytes(9, ackId)\n .finish();\n}\n","/**\n * LZ4 block decompression (no frame header) — websocket frames with\n * `payload_encoding = \"__lz4\"` compress their payload this way. No extra dependency for ~30 lines.\n */\nexport function lz4Decompress(src: Buffer): Buffer {\n let out = Buffer.alloc(Math.max(src.length * 4, 1024));\n let o = 0;\n const ensure = (need: number) => {\n if (o + need <= out.length) return;\n let size = out.length * 2;\n while (o + need > size) size *= 2;\n const bigger = Buffer.alloc(size);\n out.copy(bigger, 0, 0, o);\n out = bigger;\n };\n let i = 0;\n while (i < src.length) {\n const token = src[i++];\n let lit = token >> 4;\n if (lit === 15) {\n let b: number;\n do {\n b = src[i++];\n lit += b;\n } while (b === 255);\n }\n ensure(lit);\n src.copy(out, o, i, i + lit);\n i += lit;\n o += lit;\n if (i >= src.length) break;\n const offset = src[i] | (src[i + 1] << 8);\n i += 2;\n if (offset === 0 || offset > o) throw new Error('lz4: invalid offset');\n let len = token & 15;\n if (len === 15) {\n let b: number;\n do {\n b = src[i++];\n len += b;\n } while (b === 255);\n }\n len += 4;\n ensure(len);\n // Copy byte by byte: source and destination ranges may overlap.\n for (let k = 0; k < len; k++, o++) out[o] = out[o - offset];\n }\n return out.subarray(0, o);\n}\n","import { AID_FRONTIER, WEB } from '../protocol/constants';\nimport type { Context } from '../protocol/context';\nimport type { TikTokAccount } from '../models/types';\n\n/** Account for the cookie — `null` if the cookie is no longer logged in. */\nexport async function fetchAccount(ctx: Context): Promise<TikTokAccount | null> {\n type Res = {\n message?: string;\n data?: { user_id_str?: string; username?: string; screen_name?: string; avatar_url?: string; error_code?: number };\n };\n const res = await ctx.getJson<Res>(`${WEB}/passport/web/account/info/?aid=${AID_FRONTIER}`);\n if (res.message !== 'success' || !res.data?.user_id_str) return null;\n return {\n uid: res.data.user_id_str,\n username: res.data.username ?? '',\n screenName: res.data.screen_name ?? '',\n avatar: res.data.avatar_url ?? '',\n };\n}\n\n/** `wid` — device id TikTok issues per `ttwid` cookie; IM + websocket use it as `device_id`. */\nexport async function fetchWebId(ctx: Context): Promise<string> {\n const res = await ctx.fetch(`${WEB}/api/v1/web-cookie-privacy/config?locale=vi-VN&appId=1988&theme=default&tea=1`);\n if (!res.ok) return '';\n return /\"wid\":\"(\\d+)\"/.exec(await res.text())?.[1] ?? '';\n}\n\n/**\n * Avatar URLs from the IM profile `avatars` — collects every `https://…` string (thumb → medium → larger, whatever\n * TikTok returns), then puts browser-readable ones (jpeg/webp/png) first and heic last.\n */\nexport function avatarLinks(avatars: unknown): { avatar: string; avatars: string[] } {\n const urls: string[] = [];\n const walk = (v: unknown) => {\n if (typeof v === 'string') {\n if (/^https?:\\/\\//.test(v) && !urls.includes(v)) urls.push(v);\n } else if (Array.isArray(v)) v.forEach(walk);\n else if (v && typeof v === 'object') Object.values(v).forEach(walk);\n };\n walk(avatars);\n const heic = (u: string) => /\\.heic(\\?|$)/i.test(u.split('?')[0] + '?');\n const ranked = [...urls.filter((u) => !heic(u)), ...urls.filter(heic)];\n return { avatar: ranked[0] ?? '', avatars: ranked };\n}\n","import { createDecipheriv, createHash, createHmac, randomBytes } from 'node:crypto';\nimport { crc32 } from 'node:zlib';\nimport { Cmd, IMAGEX_REGION, IMAGEX_SERVICE, IMAGEX_VERSION } from '../protocol/constants';\nimport type { Context } from '../protocol/context';\nimport { TikTokError } from '../errors';\nimport type { ImageInput, TikTokImage } from '../models/types';\n\n/** Temporary STS credentials for the image store — obtained via IM command `UploadConfig`, valid ~10 minutes. */\ninterface UploadCredential {\n serviceId: string;\n host: string;\n accessKeyId: string;\n sessionToken: string;\n secretAccessKey: string;\n /** ms epoch */\n expiresAt: number;\n}\n\n/** Uploaded image, encrypted by the store — enough to send an image message. */\nexport interface UploadedImage {\n uri: string;\n secretKey: string;\n width: number;\n height: number;\n size: number;\n filename: string;\n}\n\nconst sha256 = (s: string | Buffer) => createHash('sha256').update(s).digest('hex');\nconst hmac = (k: string | Buffer, s: string) => createHmac('sha256', k).update(s).digest();\nconst rfc3986 = (s: string) =>\n encodeURIComponent(s).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);\n\nexport class MediaClient {\n private cred: UploadCredential | null = null;\n\n constructor(private readonly ctx: Context) {}\n\n /** `UploadConfig` returns two credential sets: type 1 = ImageX (images), type 2 = VOD (video). Use type 1. */\n private async credential(): Promise<UploadCredential> {\n if (this.cred && this.cred.expiresAt - Date.now() > 60_000) return this.cred;\n const body = await this.ctx.im('/v1/media/upload_config', Cmd.UploadConfig, Buffer.alloc(0));\n const c = body.msgs(1).find((m) => m.num(1) === 1);\n if (!c) throw new TikTokError('UPLOAD_FAILED', 'upload_config has no ImageX credentials');\n this.cred = {\n serviceId: c.str(2),\n host: c.str(3),\n expiresAt: c.num(4),\n accessKeyId: c.str(6),\n sessionToken: c.str(7),\n secretAccessKey: c.str(8),\n };\n return this.cred;\n }\n\n /** Call ImageX signed with AWS SigV4 (region cn-north-1, service imagex). */\n private async imagex<T>(method: 'GET' | 'POST', params: Record<string, string>, body?: string): Promise<T> {\n const c = await this.credential();\n const amzDate = new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d+/, '');\n const date = amzDate.slice(0, 8);\n const query = Object.keys(params)\n .sort()\n .map((k) => `${rfc3986(k)}=${rfc3986(params[k])}`)\n .join('&');\n const headers: Record<string, string> = { 'x-amz-date': amzDate, 'x-amz-security-token': c.sessionToken };\n if (body !== undefined) headers['x-amz-content-sha256'] = sha256(body);\n const signed = Object.keys(headers).sort();\n const canonical = [\n method,\n '/',\n query,\n signed.map((k) => `${k}:${headers[k]}\\n`).join(''),\n signed.join(';'),\n body !== undefined ? headers['x-amz-content-sha256'] : sha256(''),\n ].join('\\n');\n const scope = `${date}/${IMAGEX_REGION}/${IMAGEX_SERVICE}/aws4_request`;\n const toSign = ['AWS4-HMAC-SHA256', amzDate, scope, sha256(canonical)].join('\\n');\n let k = hmac(`AWS4${c.secretAccessKey}`, date);\n k = hmac(k, IMAGEX_REGION);\n k = hmac(k, IMAGEX_SERVICE);\n k = hmac(k, 'aws4_request');\n const signature = createHmac('sha256', k).update(toSign).digest('hex');\n const res = await fetch(`https://${c.host}/?${query}`, {\n method,\n headers: {\n ...headers,\n Authorization: `AWS4-HMAC-SHA256 Credential=${c.accessKeyId}/${scope}, SignedHeaders=${signed.join(';')}, Signature=${signature}`,\n ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n },\n body,\n signal: AbortSignal.timeout(this.ctx.options.timeoutMs ?? 20_000),\n });\n const json = (await res.json().catch(() => null)) as {\n ResponseMetadata?: { Error?: { Message?: string; CodeN?: number } };\n } | null;\n const err = json?.ResponseMetadata?.Error;\n if (!res.ok || !json || err) {\n throw new TikTokError(\n 'UPLOAD_FAILED',\n `imagex ${params.Action}: ${err?.Message ?? `HTTP ${res.status}`}`,\n err?.CodeN ?? res.status,\n );\n }\n return json as T;\n }\n\n /**\n * Upload an image to the private message store: Apply → POST file → Commit (the store encrypts with AES-GCM\n * and returns the key). Image dimensions come from the Commit result — no need to decode the image.\n */\n async upload(image: ImageInput): Promise<UploadedImage> {\n const c = await this.credential();\n const ext = (/\\.([a-z0-9]{2,5})$/i.exec(image.filename)?.[1] ?? 'jpg').toLowerCase();\n type Apply = {\n Result: {\n UploadAddress: { StoreInfos: { StoreUri: string; Auth: string }[]; UploadHosts: string[]; SessionKey: string };\n };\n };\n const apply = await this.imagex<Apply>('GET', {\n Action: 'ApplyImageUpload',\n Version: IMAGEX_VERSION,\n ServiceId: c.serviceId,\n FileSize: String(image.data.length),\n FileExtension: `.${ext}`,\n s: randomBytes(6).toString('hex').slice(0, 10),\n });\n const addr = apply.Result.UploadAddress;\n const store = addr.StoreInfos[0];\n const host = addr.UploadHosts[0];\n if (!store || !host) throw new TikTokError('UPLOAD_FAILED', 'ApplyImageUpload returned no upload target');\n\n const up = await fetch(`https://${host}/upload/v1/${store.StoreUri}`, {\n method: 'POST',\n headers: {\n Authorization: store.Auth,\n 'Content-CRC32': (crc32(image.data) >>> 0).toString(16).padStart(8, '0'),\n // Without this header the store returns 4004 Not Found.\n 'X-Storage-U': this.ctx.ownId,\n 'Content-Type': 'application/octet-stream',\n 'Content-Disposition': 'attachment; filename=\"undefined\"',\n },\n body: new Uint8Array(image.data),\n signal: AbortSignal.timeout(this.ctx.options.timeoutMs ?? 60_000),\n });\n const upJson = (await up.json().catch(() => null)) as { code?: number; message?: string } | null;\n if (!up.ok || upJson?.code !== 2000) {\n throw new TikTokError(\n 'UPLOAD_FAILED',\n `upload: ${upJson?.message ?? `HTTP ${up.status}`}`,\n upJson?.code ?? up.status,\n );\n }\n\n type Commit = {\n Result: {\n Results: { Encryption?: { Uri: string; SecretKey: string; Extra?: Record<string, string> } }[];\n PluginResult?: { ImageWidth?: number; ImageHeight?: number; ImageSize?: number }[];\n };\n };\n const commit = await this.imagex<Commit>(\n 'POST',\n { Action: 'CommitImageUpload', Version: IMAGEX_VERSION, ServiceId: c.serviceId },\n JSON.stringify({\n SessionKey: addr.SessionKey,\n Functions: [{ name: 'Encryption', input: { Config: { copies: 'cipher_v2' } } }],\n }),\n );\n const enc = commit.Result.Results?.[0]?.Encryption;\n const plugin = commit.Result.PluginResult?.[0];\n if (!enc?.Uri || !enc.SecretKey)\n throw new TikTokError('UPLOAD_FAILED', 'CommitImageUpload returned no encrypted result');\n return {\n uri: enc.Uri,\n secretKey: enc.SecretKey,\n width: plugin?.ImageWidth ?? Number(enc.Extra?.img_width ?? 0),\n height: plugin?.ImageHeight ?? Number(enc.Extra?.img_height ?? 0),\n size: plugin?.ImageSize ?? image.data.length,\n filename: image.filename,\n };\n }\n\n /** Download and decrypt a message image. Layout: 12-byte IV ‖ ciphertext ‖ 16-byte tag. */\n async download(image: TikTokImage, which: 'origin' | 'thumb' = 'origin'): Promise<Buffer> {\n const url = which === 'thumb' && image.thumbUrl ? image.thumbUrl : image.url;\n if (!url) throw new TikTokError('DOWNLOAD_FAILED', 'Image has no URL');\n const res = await this.ctx.fetch(url);\n if (!res.ok) throw new TikTokError('DOWNLOAD_FAILED', `Image download: HTTP ${res.status}`, res.status);\n const enc = Buffer.from(await res.arrayBuffer());\n if (!image.decryptKey) return enc;\n try {\n const d = createDecipheriv('aes-256-gcm', Buffer.from(image.decryptKey, 'hex'), enc.subarray(0, 12));\n d.setAuthTag(enc.subarray(enc.length - 16));\n return Buffer.concat([d.update(enc.subarray(12, enc.length - 16)), d.final()]);\n } catch (err) {\n throw new TikTokError('DOWNLOAD_FAILED', `Image decryption: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n}\n","/**\n * Pure builders for IM request bodies (protobuf) — no I/O, so they can be unit-tested byte for byte.\n */\nimport {\n ConversationType,\n PropertyOp,\n REACTION_HEART,\n REACTION_LOVE_KEY,\n REACTION_PREFIX,\n} from '../protocol/constants';\nimport { Writer } from '../protocol/proto';\nimport type { ConversationRef, TikTokMessage } from '../models/types';\nimport type { UploadedImage } from './media';\n\n/** \"Latest\" cursor for reading history — greater than any `index` (µs). */\nexport const NEWEST = 9_999_999_999_999_999n;\n\n/** `GetMessagesByConversationRequestBody` — messages older than `before` (or the newest ones). */\nexport function getMessagesBody(conv: ConversationRef, limit: number, before?: string): Buffer {\n return new Writer()\n .bytes(1, conv.conversationId)\n .int(2, ConversationType.OneToOne)\n .int(3, BigInt(conv.conversationShortId))\n .int(4, 1) // direction: older than cursor\n .int(5, before ? BigInt(before) : NEWEST)\n .int(6, limit)\n .finish();\n}\n\n/** `MarkConversationReadRequestBody` — read up to message `index`. */\nexport function markReadBody(msg: ConversationRef & { index: string }): Buffer {\n return new Writer()\n .bytes(1, msg.conversationId)\n .int(2, BigInt(msg.conversationShortId))\n .int(3, ConversationType.OneToOne)\n .int(4, BigInt(msg.index))\n .int(11, 4)\n .finish();\n}\n\n/**\n * `SendMessageRequestBody`: {1 convId, 2 conversation type, 3 shortId, 4 content, 5 ext, 6 message type, 7 ticket,\n * 8 client id, …}. `extra` is appended verbatim (image attachments).\n */\nexport function sendMessageBody(\n conv: ConversationRef,\n cid: string,\n type: number,\n content: string,\n extra: Writer | null,\n): Buffer {\n const w = new Writer()\n .bytes(1, conv.conversationId)\n .int(2, ConversationType.OneToOne)\n .int(3, BigInt(conv.conversationShortId))\n .bytes(4, content)\n .map(5, { 's:mentioned_users': '', 's:client_message_id': cid })\n .int(6, type)\n .bytes(7, 'deprecated')\n .bytes(8, cid);\n return extra ? Buffer.concat([w.finish(), extra.finish()]) : w.finish();\n}\n\n/** Extra `SendMessageRequestBody` fields (13, 14, 17) describing an uploaded private image. */\nexport function imageMessageExtra(up: UploadedImage): Writer {\n const w = String(up.width);\n const h = String(up.height);\n const media = new Writer()\n .msg(\n 1,\n new Writer()\n .bytes(1, up.uri)\n .msg(5, new Writer().int(1, up.width).int(2, up.height))\n .bytes(6, up.secretKey)\n .int(7, 0),\n )\n .msg(\n 3,\n new Writer()\n .msg(1, new Writer().bytes(1, 'You sent a 📷'))\n .msg(2, new Writer().bytes(1, 'sent a 📷'))\n .msg(3, new Writer().bytes(1, '[Photo]')),\n )\n .msg(\n 200,\n new Writer().msg(\n 1,\n new Writer().bytes(1, up.uri).map(2, {\n image_width: w,\n image_height: h,\n decrypt_key: up.secretKey,\n quote_preview: 'dm_cam_preview_photo',\n sender_preview: 'sender_preview',\n }),\n ),\n );\n return new Writer()\n .msg(13, new Writer().msg(4, media))\n .bytes(14, 'private_image')\n .msg(\n 17,\n new Writer()\n .int(1, 1)\n .bytes(2, up.uri)\n .bytes(3, up.secretKey)\n .msg(10, new Writer().int(1, up.width).int(2, up.height).int(4, up.size).bytes(5, up.filename)),\n );\n}\n\nexport interface PropertyChange {\n op: number;\n key: string;\n}\n\n/**\n * Property operations that make `own`'s reaction on `msg` equal `emoji` (one reaction per user; `null` = remove).\n * Empty when nothing needs to change.\n */\nexport function reactionOps(\n msg: Pick<TikTokMessage, 'reactions'>,\n own: string,\n emoji: string | null,\n): PropertyChange[] {\n const mine = msg.reactions.filter((r) => r.userIds.includes(own)).map((r) => r.emoji);\n const ops: PropertyChange[] = [];\n if (emoji && !mine.includes(emoji)) ops.push({ op: PropertyOp.Add, key: REACTION_PREFIX + emoji });\n for (const e of mine) {\n if (e === emoji) continue;\n ops.push({ op: PropertyOp.Remove, key: REACTION_PREFIX + e });\n // ❤️ sent from the mobile app still uses the legacy key `e:love` — remove it too or the app keeps showing the heart.\n if (e === REACTION_HEART) ops.push({ op: PropertyOp.Remove, key: REACTION_LOVE_KEY });\n }\n return ops;\n}\n\n/** `ModifyMessagePropertyRequestBody` (command 705) applying `ops` to `msg` as user `own`. */\nexport function setPropertyBody(msg: TikTokMessage, ops: PropertyChange[], own: string): Buffer {\n const target = new Writer()\n .bytes(1, msg.conversationId)\n .int(2, ConversationType.OneToOne)\n .int(3, BigInt(msg.conversationShortId))\n .int(4, BigInt(msg.serverMessageId))\n .bytes(5, msg.clientMessageId);\n for (const o of ops) target.msg(6, new Writer().int(1, o.op).bytes(2, o.key).bytes(4, own));\n return new Writer().msg(1, target).bytes(2, 'deprecated').finish();\n}\n","import { AID_WEB, BUILD_NUMBER, DEFAULT_USER_AGENT, IM_API, Resp, SDK_VERSION, WEB } from './constants';\nimport { TikTokError } from '../errors';\nimport { Msg, Writer } from './proto';\nimport type { CookieInput, Credentials, TikTokOptions } from '../models/types';\n\n/** `name → value` cookies from any input shape of `Credentials.cookies`. */\nexport function normalizeCookies(input: Credentials['cookies']): Map<string, string> {\n const jar = new Map<string, string>();\n if (typeof input === 'string') {\n for (const part of input.split(';')) {\n const i = part.indexOf('=');\n if (i > 0) jar.set(part.slice(0, i).trim(), part.slice(i + 1).trim());\n }\n } else if (Array.isArray(input)) {\n for (const c of input as CookieInput[]) if (c?.name) jar.set(c.name, String(c.value ?? ''));\n } else {\n for (const [k, v] of Object.entries(input ?? {})) jar.set(k, String(v));\n }\n return jar;\n}\n\n/** Shared state of a session: cookies, device id, uid, HTTP calls. */\nexport class Context {\n readonly cookies: Map<string, string>;\n /**\n * IM device id = the `wid` TikTok issues for the `ttwid` cookie (`login` fetches it). The websocket only\n * accepts this id — a made-up id gets 400 (HTTP IM isn't picky).\n */\n deviceId: string;\n readonly userAgent: string;\n ownId = '';\n private seq = 10_000;\n\n constructor(\n creds: Credentials,\n readonly options: TikTokOptions = {},\n ) {\n this.cookies = normalizeCookies(creds.cookies);\n this.deviceId = creds.deviceId ?? '';\n this.userAgent = creds.userAgent || DEFAULT_USER_AGENT;\n }\n\n cookieHeader(): string {\n return [...this.cookies].map(([k, v]) => `${k}=${v}`).join('; ');\n }\n\n log(level: 'debug' | 'warn', msg: string): void {\n this.options.logger?.(level, msg);\n }\n\n /** `fetch` with cookies + UA + timeout. */\n async fetch(url: string, init: RequestInit & { headers?: Record<string, string> } = {}): Promise<Response> {\n try {\n return await fetch(url, {\n ...init,\n headers: {\n 'User-Agent': this.userAgent,\n Referer: `${WEB}/`,\n Origin: WEB,\n Cookie: this.cookieHeader(),\n ...init.headers,\n },\n signal: AbortSignal.timeout(this.options.timeoutMs ?? 20_000),\n });\n } catch (err) {\n throw new TikTokError('HTTP_ERROR', `${url.split('?')[0]}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n async getJson<T>(url: string): Promise<T> {\n const res = await this.fetch(url);\n if (!res.ok) throw new TikTokError('HTTP_ERROR', `${url.split('?')[0]}: HTTP ${res.status}`, res.status);\n return (await res.json()) as T;\n }\n\n /** IM `Request` envelope: command + body + common headers. */\n buildRequest(cmd: number, bodyField: number, body: Buffer): Buffer {\n return new Writer()\n .int(1, cmd)\n .int(2, this.seq++)\n .bytes(3, SDK_VERSION)\n .bytes(4, '')\n .int(5, 3)\n .int(6, 0)\n .bytes(7, BUILD_NUMBER)\n .msg(8, new Writer().bytes(bodyField, body))\n .bytes(9, this.deviceId)\n .bytes(11, 'web')\n .map(15, {\n aid: AID_WEB,\n app_name: 'tiktok_web',\n channel: 'web',\n device_platform: 'web_pc',\n device_id: this.deviceId,\n user_is_login: 'true',\n user_agent: this.userAgent,\n })\n .int(18, 1)\n .finish();\n }\n\n /**\n * Call an IM command over HTTP. Returns the unwrapped body (`ResponseBody[cmd]`).\n * NO X-Gnarly/X-Bogus/msToken signature needed — the IM server only checks cookies (tested 09/11/2026).\n */\n async im(path: string, cmd: number, body: Buffer, bodyField: number = cmd): Promise<Msg> {\n const url = `${IM_API}${path}?aid=${AID_WEB}&version_code=1.0.0&app_name=tiktok_web&device_platform=web_pc`;\n const res = await this.fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-protobuf', Accept: 'application/x-protobuf' },\n body: new Uint8Array(this.buildRequest(cmd, bodyField, body)),\n });\n if (!res.ok) throw new TikTokError('HTTP_ERROR', `${path}: HTTP ${res.status}`, res.status);\n const raw = Buffer.from(await res.arrayBuffer());\n if (/json/i.test(res.headers.get('content-type') ?? '')) throw gatewayError(path, raw);\n const resp = Msg.tryParse(raw);\n if (!resp) throw new TikTokError('BAD_RESPONSE', `${path}: response is not protobuf`);\n const status = resp.num(Resp.status);\n if (status !== 0) {\n const desc = resp.str(Resp.error);\n // Not logged in: 200005 (tested with a cookieless request).\n const code = status === 200005 ? 'SESSION_EXPIRED' : 'IM_ERROR';\n throw new TikTokError(code, `${path}: ${status} ${desc}`.trim(), status);\n }\n return resp.msg(Resp.body)?.msg(cmd) ?? resp.msg(Resp.body)?.msg(bodyField) ?? Msg.parse(Buffer.alloc(0));\n }\n}\n\n/**\n * The gateway in front of the IM server answers with JSON (`{\"status_code\": 7, …}`) when it refuses a request before it\n * reaches IM. Observed 12/11/2026: one stored session got 7 on every `message/send` (even a garbage body) while\n * `mark_read` / `get_by_conversation` kept working; a freshly logged-in session passed — hence `SESSION_BLOCKED`.\n */\nfunction gatewayError(path: string, raw: Buffer): TikTokError {\n let status: unknown;\n try {\n status = (JSON.parse(raw.toString('utf8')) as { status_code?: unknown }).status_code;\n } catch {\n // not JSON after all\n }\n if (status === 7) return new TikTokError('SESSION_BLOCKED', `${path}: gateway status_code 7 — session blocked`, 7);\n return new TikTokError(\n 'BAD_RESPONSE',\n `${path}: gateway JSON status_code ${String(status)}`,\n typeof status === 'number' ? status : undefined,\n );\n}\n","import { API } from './api/api';\nimport { fetchAccount, fetchWebId } from './api/account';\nimport { Context } from './protocol/context';\nimport { TikTokError } from './errors';\nimport type { Credentials, TikTokOptions } from './models/types';\n\nexport class TikTok {\n constructor(private readonly options: TikTokOptions = {}) {}\n\n /** Log in with existing cookies. Expired cookies → `TikTokError('SESSION_EXPIRED')`. */\n async login(credentials: Credentials): Promise<API> {\n const ctx = new Context(credentials, this.options);\n if (!ctx.cookies.get('sessionid') && !ctx.cookies.get('sid_tt')) {\n throw new TikTokError('SESSION_EXPIRED', 'Cookie has no sessionid');\n }\n const account = await fetchAccount(ctx);\n if (!account) throw new TikTokError('SESSION_EXPIRED', 'TikTok cookie is no longer logged in');\n ctx.ownId = account.uid;\n ctx.deviceId = (await fetchWebId(ctx).catch(() => '')) || ctx.deviceId;\n if (!ctx.deviceId) throw new TikTokError('BAD_RESPONSE', 'Could not get wid (device_id) — cookie missing ttwid?');\n return new API(ctx, account);\n }\n}\n","import { rm } from 'node:fs/promises';\nimport { DEFAULT_USER_AGENT, WEB } from '../protocol/constants';\nimport { TikTokError } from '../errors';\nimport type { CookieInput, Credentials } from '../models/types';\nimport { openTab, type Cdp } from './cdp';\nimport { launchChrome, resolveChromePath } from './chrome';\n\n/**\n * QR login via headless Chrome.\n *\n * Why a browser: TikTok's QR API (`passport/web/check_qrconnect`) requires a JS signature\n * (X-Gnarly / msToken) — calling it bare from Node yields `error_code 7`. So we open the real\n * `tiktok.com/login/qrcode` page in headless Chrome and let it sign itself; we only LISTEN to\n * responses via CDP: the QR image from the `get_qrcode` body, the status from `check_qrconnect`.\n * After login we grab the cookies and close Chrome — everything after (`login`, chat) needs no browser.\n */\n\nexport type QrLoginEvent =\n /** New QR image (`data:image/png;base64,…`) — show it to the user to scan. A new one comes on expiry. */\n | { type: 'qr'; image: string; expiresAt: number }\n /** Scanned, waiting for confirmation on the phone. */\n | { type: 'scanned' }\n /** Confirmed — fetching cookies. */\n | { type: 'confirmed' };\n\nexport interface QrLoginOptions {\n /**\n * Path to Chrome / Chromium (e.g. `/usr/bin/chromium-browser`). Optional — when omitted, `CHROME_PATH` and the\n * usual install locations are searched.\n */\n chromePath?: string;\n onEvent?: (e: QrLoginEvent) => void;\n signal?: AbortSignal;\n /** Total time to wait for a scan (ms) — default 5 minutes. */\n timeoutMs?: number;\n /** When the QR expires (~1 minute), regenerate it at most this many times. */\n maxRefresh?: number;\n userAgent?: string;\n}\n\n/**\n * Log in to TikTok via QR. Returns `Credentials` (`.tiktok.com` cookies + UA) — pass them to\n * `new TikTok().login(creds)` and SAVE them so you don't need to scan next time.\n */\nexport async function loginQR(opts: QrLoginOptions): Promise<Credentials> {\n const userAgent = opts.userAgent || DEFAULT_USER_AGENT;\n const maxRefresh = opts.maxRefresh ?? 3;\n const { proc, ws, dir } = await launchChrome(resolveChromePath(opts.chromePath), userAgent);\n let cdp: Cdp | null = null;\n try {\n cdp = await openTab(ws);\n const tab = cdp;\n await tab.send('Network.enable');\n await tab.send('Page.enable');\n\n const result = new Promise<Credentials>((resolve, reject) => {\n const urlById = new Map<string, string>();\n let refreshes = 0;\n let scanned = false;\n let done = false;\n const finish = (err: Error | null, creds?: Credentials) => {\n if (done) return;\n done = true;\n clearTimeout(timer);\n opts.signal?.removeEventListener('abort', onAbort);\n if (err) reject(err);\n else resolve(creds!);\n };\n const timer = setTimeout(\n () => finish(new TikTokError('LOGIN_FAILED', 'Timed out waiting for QR scan')),\n opts.timeoutMs ?? 5 * 60_000,\n );\n const onAbort = () => finish(new TikTokError('LOGIN_ABORTED', 'QR login aborted'));\n opts.signal?.addEventListener('abort', onAbort);\n\n const body = async (requestId: string): Promise<{ data?: Record<string, unknown> } | null> => {\n const r = await tab\n .send<{ body: string; base64Encoded: boolean }>('Network.getResponseBody', { requestId })\n .catch(() => null);\n if (!r) return null;\n try {\n return JSON.parse(r.base64Encoded ? Buffer.from(r.body, 'base64').toString() : r.body) as {\n data?: Record<string, unknown>;\n };\n } catch {\n return null;\n }\n };\n\n /** After `confirmed`: the page redirects and sets session cookies — wait for `sessionid`. */\n const collectCookies = async () => {\n for (let i = 0; i < 30 && !done; i++) {\n const { cookies } = await tab.send<{ cookies: (CookieInput & { domain: string })[] }>(\n 'Network.getAllCookies',\n );\n const mine = cookies.filter((c) => c.domain.endsWith('tiktok.com'));\n if (mine.some((c) => c.name === 'sessionid' && c.value) && mine.some((c) => c.name === 'ttwid')) {\n // Same name on `.tiktok.com` and `www.tiktok.com` → keep the `.tiktok.com` one.\n const byName = new Map<string, CookieInput>();\n for (const c of mine.sort(\n (a, b) => (a.domain === '.tiktok.com' ? 1 : 0) - (b.domain === '.tiktok.com' ? 1 : 0),\n )) {\n byName.set(c.name, { name: c.name, value: c.value });\n }\n return finish(null, { cookies: [...byName.values()], userAgent });\n }\n await new Promise((r) => setTimeout(r, 1000));\n }\n finish(new TikTokError('LOGIN_FAILED', 'Confirmed but no sessionid cookie found'));\n };\n\n tab.on((method, p) => {\n if (done) return;\n if (method === 'Network.responseReceived') {\n const res = p.response as { url: string };\n urlById.set(p.requestId as string, res.url);\n return;\n }\n if (method !== 'Network.loadingFinished') return;\n const url = urlById.get(p.requestId as string) ?? '';\n if (url.includes('/passport/web/get_qrcode/')) {\n void body(p.requestId as string).then((j) => {\n const qr = j?.data?.qrcode;\n if (typeof qr === 'string' && qr) {\n opts.onEvent?.({\n type: 'qr',\n image: `data:image/png;base64,${qr}`,\n expiresAt: Number(j?.data?.expire_time ?? 0) * 1000 || Date.now() + 60_000,\n });\n }\n });\n } else if (url.includes('/passport/web/check_qrconnect/')) {\n // The page polls 3 regions in parallel (sg/us/eu) — only the account's region changes status, the rest stay \"new\".\n void body(p.requestId as string).then((j) => {\n const status = String(j?.data?.status ?? '');\n if (status === 'scanned' && !scanned) {\n scanned = true;\n opts.onEvent?.({ type: 'scanned' });\n } else if (status === 'confirmed') {\n opts.onEvent?.({ type: 'confirmed' });\n void collectCookies();\n } else if (status === 'expired' && !scanned) {\n if (refreshes++ >= maxRefresh)\n finish(new TikTokError('LOGIN_FAILED', 'QR expired without being scanned'));\n else void tab.send('Page.reload');\n }\n });\n }\n });\n });\n\n await tab.send('Page.navigate', { url: `${WEB}/login/qrcode` });\n return await result;\n } finally {\n cdp?.close();\n proc.kill('SIGKILL');\n await rm(dir, { recursive: true, force: true }).catch(() => undefined);\n }\n}\n","import WebSocket from 'ws';\n\n/** Minimal Chrome DevTools Protocol client bound to one tab. */\nexport interface Cdp {\n send<T = Record<string, unknown>>(method: string, params?: object): Promise<T>;\n on(handler: (method: string, params: Record<string, unknown>) => void): void;\n close(): void;\n}\n\n/** Attach CDP to a new tab (a flat session on the browser websocket). */\nexport async function openTab(browserWs: string): Promise<Cdp> {\n const ws = new WebSocket(browserWs, { perMessageDeflate: false });\n await new Promise<void>((resolve, reject) => {\n ws.once('open', () => resolve());\n ws.once('error', reject);\n });\n let id = 0;\n // eslint-disable-next-line prefer-const -- the ws message handler reads it before Target.attachToTarget assigns it\n let sessionId: string | undefined;\n const pending = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n const handlers: ((m: string, p: Record<string, unknown>) => void)[] = [];\n ws.on('message', (raw: Buffer) => {\n const m = JSON.parse(raw.toString()) as {\n id?: number;\n method?: string;\n params?: Record<string, unknown>;\n result?: unknown;\n error?: { message: string };\n sessionId?: string;\n };\n if (m.id !== undefined && pending.has(m.id)) {\n const p = pending.get(m.id)!;\n pending.delete(m.id);\n if (m.error) p.reject(new Error(m.error.message));\n else p.resolve(m.result ?? {});\n return;\n }\n if (m.method && (!m.sessionId || m.sessionId === sessionId)) for (const h of handlers) h(m.method, m.params ?? {});\n });\n const raw = <T>(method: string, params: object = {}, sid?: string): Promise<T> =>\n new Promise((resolve, reject) => {\n const i = ++id;\n pending.set(i, { resolve: resolve as (v: unknown) => void, reject });\n ws.send(JSON.stringify({ id: i, method, params, ...(sid ? { sessionId: sid } : {}) }));\n });\n const target = await raw<{ targetId: string }>('Target.createTarget', { url: 'about:blank' });\n sessionId = (await raw<{ sessionId: string }>('Target.attachToTarget', { targetId: target.targetId, flatten: true }))\n .sessionId;\n return {\n send: (method, params) => raw(method, params, sessionId),\n on: (h) => handlers.push(h),\n close: () => ws.close(),\n };\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdtemp, rm } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { delimiter, join } from 'node:path';\nimport { TikTokError } from '../errors';\n\n/** Executable names looked up on `PATH` (Linux / BSD). */\nconst PATH_NAMES = ['google-chrome', 'google-chrome-stable', 'chromium', 'chromium-browser', 'chrome'];\n\n/** Well-known install locations per platform. */\nfunction knownPaths(platform: NodeJS.Platform, env: NodeJS.ProcessEnv): string[] {\n if (platform === 'darwin') {\n const apps = [\n 'Google Chrome.app/Contents/MacOS/Google Chrome',\n 'Chromium.app/Contents/MacOS/Chromium',\n 'Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',\n ];\n const roots = ['/Applications', ...(env.HOME ? [join(env.HOME, 'Applications')] : [])];\n return roots.flatMap((r) => apps.map((a) => join(r, a)));\n }\n if (platform === 'win32') {\n const roots = [env.PROGRAMFILES, env['PROGRAMFILES(X86)'], env.LOCALAPPDATA].filter((r): r is string => !!r);\n return roots.flatMap((r) => [\n join(r, 'Google', 'Chrome', 'Application', 'chrome.exe'),\n join(r, 'Chromium', 'Application', 'chrome.exe'),\n ]);\n }\n return [\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium',\n '/usr/bin/chromium-browser',\n '/snap/bin/chromium',\n '/opt/google/chrome/chrome',\n ];\n}\n\n/**\n * Locate a Chrome / Chromium executable: `CHROME_PATH` env, then well-known install paths for the platform, then\n * `PATH`. Returns `null` when none is found.\n */\nexport function findChrome(\n env: NodeJS.ProcessEnv = process.env,\n platform: NodeJS.Platform = process.platform,\n exists: (path: string) => boolean = existsSync,\n): string | null {\n if (env.CHROME_PATH && exists(env.CHROME_PATH)) return env.CHROME_PATH;\n for (const p of knownPaths(platform, env)) if (exists(p)) return p;\n if (platform !== 'win32') {\n for (const dir of (env.PATH ?? '').split(delimiter).filter(Boolean)) {\n for (const name of PATH_NAMES) if (exists(join(dir, name))) return join(dir, name);\n }\n }\n return null;\n}\n\n/** `chromePath` if given, otherwise auto-detect — throws `LOGIN_FAILED` when nothing is found. */\nexport function resolveChromePath(chromePath?: string): string {\n if (chromePath) return chromePath;\n const found = findChrome();\n if (!found) {\n throw new TikTokError(\n 'LOGIN_FAILED',\n 'Chrome / Chromium not found — install it, set the CHROME_PATH environment variable, or pass `chromePath`',\n );\n }\n return found;\n}\n\n/** Launch headless Chrome and wait for the \"DevTools listening on ws://…\" line. */\nexport async function launchChrome(\n chromePath: string,\n userAgent: string,\n): Promise<{ proc: ChildProcess; ws: string; dir: string }> {\n const dir = await mkdtemp(join(tmpdir(), 'tca-chrome-'));\n const proc = spawn(\n chromePath,\n [\n '--headless=new',\n '--remote-debugging-port=0',\n `--user-data-dir=${dir}`,\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-gpu',\n '--disable-dev-shm-usage',\n // Containers run as root — Chromium requires disabling the sandbox.\n '--no-sandbox',\n '--window-size=1280,900',\n '--lang=vi-VN',\n // The default headless UA contains \"HeadlessChrome\" — replace it with a normal UA.\n `--user-agent=${userAgent}`,\n 'about:blank',\n ],\n { stdio: ['ignore', 'ignore', 'pipe'] },\n );\n const ws = await new Promise<string>((resolve, reject) => {\n let buf = '';\n const timer = setTimeout(() => reject(new Error('Chrome did not start within 20s')), 20_000);\n proc.stderr!.on('data', (d: Buffer) => {\n buf += d.toString();\n const m = /DevTools listening on (ws:\\/\\/\\S+)/.exec(buf);\n if (m) {\n clearTimeout(timer);\n resolve(m[1]);\n }\n });\n proc.once('error', (e) => {\n clearTimeout(timer);\n reject(e);\n });\n proc.once('exit', (code) => {\n clearTimeout(timer);\n reject(new Error(`Chrome exited (${code}) before it was ready`));\n });\n }).catch(async (err: unknown) => {\n proc.kill('SIGKILL');\n await rm(dir, { recursive: true, force: true });\n throw new TikTokError(\n 'LOGIN_FAILED',\n `Failed to launch Chrome: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n return { proc, ws, dir };\n}\n"],"mappings":"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","names":["key","key","createHash","createHash","k","rm","WebSocket","raw","rm"]}
1
+ {"version":3,"sources":["../src/api/api.ts","../src/protocol/constants.ts","../src/protocol/proto.ts","../src/errors.ts","../src/listener/listener.ts","../src/models/message.ts","../src/listener/frame.ts","../src/protocol/lz4.ts","../src/api/account.ts","../src/api/media.ts","../src/api/requests.ts","../src/protocol/ticket-guard.ts","../src/protocol/context.ts","../src/client.ts","../src/auth/qr-login.ts","../src/auth/cdp.ts","../src/auth/chrome.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { Cmd, MARK_READ_BODY_FIELD, MessageType, WEB } from '../protocol/constants';\nimport type { Context } from '../protocol/context';\nimport { Writer } from '../protocol/proto';\nimport { TikTokError } from '../errors';\nimport { Listener } from '../listener/listener';\nimport { parseConversation, parseMessage } from '../models/message';\nimport type {\n ConversationPage,\n ConversationRef,\n ImageInput,\n MessagePage,\n TikTokAccount,\n TikTokImage,\n TikTokMessage,\n TikTokSticker,\n TikTokUser,\n TicketGuard,\n} from '../models/types';\nimport { avatarLinks, fetchAccount } from './account';\nimport { MediaClient } from './media';\nimport {\n getMessagesBody,\n imageMessageExtra,\n markReadBody,\n reactionOps,\n sendMessageBody,\n setPropertyBody,\n} from './requests';\n\n/** Send result: client-side message id (TikTok echoes it back). The server id arrives via the listener (`isSelf`). */\nexport interface SendResult {\n clientMessageId: string;\n}\n\n/**\n * A logged-in TikTok session — create with `new TikTok().login(credentials)`.\n * All calls go directly over HTTP/WS to TikTok using cookies, no browser needed.\n */\nexport class API {\n readonly listener: Listener;\n private readonly media: MediaClient;\n\n constructor(\n private readonly ctx: Context,\n readonly account: TikTokAccount,\n ) {\n this.listener = new Listener(ctx);\n this.media = new MediaClient(ctx);\n }\n\n getOwnId(): string {\n return this.ctx.ownId;\n }\n\n /** Current cookies — save them so the next `login` needs no QR scan. */\n getCookies(): { name: string; value: string }[] {\n return [...this.ctx.cookies].map(([name, value]) => ({ name, value }));\n }\n\n /** Non-cookie session state to save alongside the cookies (pass back into `login`). */\n getContext(): { deviceId: string; userAgent: string; ticketGuard?: TicketGuard } {\n return { deviceId: this.ctx.deviceId, userAgent: this.ctx.userAgent, ticketGuard: this.ctx.ticketGuard };\n }\n\n /** Whether the session is still alive — call periodically to detect expiry early. */\n async isAlive(): Promise<boolean> {\n return (await fetchAccount(this.ctx).catch(() => null)) !== null;\n }\n\n // ─── Inbox ─────────────────────────────────────────────────────────────────\n\n /** Recent conversations + their latest messages, paginated with `cursor`. */\n async getConversations(cursor = '0'): Promise<ConversationPage> {\n const body = await this.ctx.im(\n '/v2/message/get_by_user_init',\n Cmd.GetMessagesByUserInit,\n new Writer().int(1, BigInt(cursor)).finish(),\n );\n return {\n messages: body.msgs(1).map((m) => parseMessage(m, this.ctx.ownId)),\n conversations: body.msgs(2).map((m) => parseConversation(m, this.ctx.ownId)),\n // Cursor = number of conversations fetched so far (0, 10, 20…) — field 4; field 3 is a timestamp, not used for paging.\n cursor: body.id(4),\n hasMore: body.num(5) === 1,\n };\n }\n\n /** Messages of a conversation, newest first. For older messages: `before = <index of oldest message>`. */\n async getMessages(conv: ConversationRef, opts: { limit?: number; before?: string } = {}): Promise<MessagePage> {\n const limit = Math.min(Math.max(opts.limit ?? 20, 1), 50);\n const body = await this.ctx.im(\n '/v1/message/get_by_conversation',\n Cmd.GetMessagesByConversation,\n getMessagesBody(conv, limit, opts.before),\n );\n const messages = body.msgs(1).map((m) => parseMessage(m, this.ctx.ownId));\n return { messages, hasMore: messages.length >= limit };\n }\n\n /** User profiles by uid (display name, @username, avatar). */\n async getUsers(uids: string[]): Promise<TikTokUser[]> {\n if (uids.length === 0) return [];\n const q = new URLSearchParams({\n aid: '1988',\n app_name: 'tiktok_web',\n device_platform: 'web_pc',\n source: 'im_chat',\n from_page: 'message',\n user_ids: JSON.stringify(uids),\n });\n type Res = {\n status_code?: number;\n users?: {\n im_user_profile?: {\n user_id_str?: string;\n unique_id?: string;\n nick_name?: string;\n avatars?: unknown;\n };\n }[];\n };\n const res = await this.ctx.getJson<Res>(`${WEB}/tiktok/v1/im/user/profile/?${q}`);\n if (res.status_code) throw new TikTokError('IM_ERROR', `user/profile: ${res.status_code}`, res.status_code);\n return (res.users ?? []).map(({ im_user_profile: p = {} }) => ({\n uid: p.user_id_str ?? '',\n uniqueId: p.unique_id ?? '',\n nickname: p.nick_name ?? '',\n ...avatarLinks(p.avatars),\n }));\n }\n\n /**\n * Download an avatar (tries each URL in turn, skips heic). No cookie / Referer sent: the image CDN is cross-origin and\n * URLs are already signed. `null` if no URL could be downloaded.\n */\n async downloadAvatar(user: Pick<TikTokUser, 'avatars'>): Promise<{ data: Buffer; type: string } | null> {\n for (const url of user.avatars) {\n const res = await fetch(url, {\n headers: { 'User-Agent': this.ctx.userAgent },\n referrerPolicy: 'no-referrer',\n signal: AbortSignal.timeout(this.ctx.options.timeoutMs ?? 20_000),\n }).catch(() => null);\n const type = res?.headers.get('content-type') ?? '';\n if (!res?.ok || !/^image\\/(jpeg|png|webp|gif)/.test(type)) continue;\n return { data: Buffer.from(await res.arrayBuffer()), type };\n }\n return null;\n }\n\n /** Mark as read up to message `msg`. */\n async markRead(msg: ConversationRef & { index: string }): Promise<void> {\n await this.ctx.im('/v3/conversation/mark_read', Cmd.MarkRead, markReadBody(msg), MARK_READ_BODY_FIELD);\n }\n\n // ─── Send ─────────────────────────────────────────────────────────────────\n\n /** Send a text message to a conversation (usually the just-received `msg` — it carries the conversation ids). */\n async sendMessage(conv: ConversationRef, text: string): Promise<SendResult> {\n const cid = randomUUID();\n await this.send(conv, cid, MessageType.Text, JSON.stringify({ aweType: 0, text }), null);\n return { clientMessageId: cid };\n }\n\n /** Send an image: upload to the private (encrypted) store, then send an image message. */\n async sendImage(conv: ConversationRef, image: ImageInput): Promise<SendResult> {\n const up = await this.media.upload(image);\n const cid = randomUUID();\n await this.send(conv, cid, MessageType.PrivateImage, '', imageMessageExtra(up));\n return { clientMessageId: cid };\n }\n\n /**\n * Set YOUR reaction on a message — like TikTok Web, one reaction per user: a new `emoji` replaces the old one,\n * `null` = remove. Pass the whole `msg` just read (current `reactions` are needed to know which key to remove).\n * Sends `ModifyMessagePropertyRequestBody` (command 705) — see README.\n */\n async setReaction(msg: TikTokMessage, emoji: string | null): Promise<void> {\n const own = this.ctx.ownId;\n const ops = reactionOps(msg, own, emoji);\n if (ops.length === 0) return;\n const body = await this.ctx.im('/v1/message/set_property', Cmd.SetMessageProperty, setPropertyBody(msg, ops, own));\n // status: 0 success, 1 duplicate (also done); anything else means TikTok rejected it.\n const status = body.num(1);\n if (status > 1) throw new TikTokError('IM_ERROR', `set_property: status ${status}`, status);\n }\n\n // ─── Media ─────────────────────────────────────────────────────────────────\n\n /** Download a sticker image (public CDN, unencrypted, no cookie needed). */\n async downloadSticker(sticker: Pick<TikTokSticker, 'url'>): Promise<{ data: Buffer; type: string }> {\n const res = await fetch(sticker.url, {\n headers: { 'User-Agent': this.ctx.userAgent },\n referrerPolicy: 'no-referrer',\n signal: AbortSignal.timeout(this.ctx.options.timeoutMs ?? 20_000),\n }).catch(() => null);\n if (!res?.ok) throw new TikTokError('DOWNLOAD_FAILED', `Sticker download failed: ${res?.status ?? 'network'}`);\n return { data: Buffer.from(await res.arrayBuffer()), type: res.headers.get('content-type') ?? 'image/webp' };\n }\n\n /** Download + decrypt a message's image (pass the whole `msg` — listener messages lack the URL, this looks it up). */\n async downloadImage(source: TikTokMessage | TikTokImage, which: 'origin' | 'thumb' = 'origin'): Promise<Buffer> {\n let image = 'serverMessageId' in source ? source.image : source;\n // Websocket-pushed messages only have uri + key, no download URL → look up history by message id.\n if ('serverMessageId' in source && image && !image.url) {\n const { messages } = await this.getMessages(source, { limit: 5, before: (BigInt(source.index) + 1n).toString() });\n image = messages.find((m) => m.serverMessageId === source.serverMessageId)?.image ?? image;\n }\n if (!image) throw new TikTokError('DOWNLOAD_FAILED', 'Message has no image');\n return this.media.download(image, which);\n }\n\n private async send(\n conv: ConversationRef,\n cid: string,\n type: number,\n content: string,\n extra: Writer | null,\n ): Promise<void> {\n if (!conv.conversationId || !conv.conversationShortId) {\n throw new TikTokError('IM_ERROR', 'Missing conversationId / conversationShortId');\n }\n await this.ctx.im('/v1/message/send', Cmd.SendMessage, sendMessageBody(conv, cid, type, content, extra));\n }\n}\n","/**\n * TikTok Web IM protocol constants — reconstructed from `tiktok.com/business-suite/messages` traffic\n * (09/11/2026). If TikTok changes things on their side, fix them here; how they were found is in the README.\n */\n\nexport const IM_API = 'https://im-api-sg.tiktok.com';\nexport const IM_WS = 'wss://im-ws-sg.tiktok.com/ws/v2';\nexport const WEB = 'https://www.tiktok.com';\n\nexport const DEFAULT_USER_AGENT =\n 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.0.0 Safari/537.36';\n\n/** TikTok Web app id (HTTP IM). */\nexport const AID_WEB = '1988';\n/** \"frontier\" channel app id — websocket pushing new messages. */\nexport const AID_FRONTIER = '1459';\nexport const SDK_VERSION = '1.8.5';\nexport const BUILD_NUMBER = 'feffaa1:master';\n\n/** Websocket `access_key` = md5(FPID + APP_KEY + device_id + SALT). */\nexport const FRONTIER_FPID = '9';\nexport const FRONTIER_APP_KEY = 'e1bd35ec9db7b8d846de66ed140b1ad9';\nexport const FRONTIER_SALT = 'f8a69f1719916z';\n\n/** IM command (`Request.cmd`) — also the body's field number in `RequestBody`. */\nexport const Cmd = {\n SendMessage: 100,\n GetMessagesByUserInit: 203,\n GetMessagesByConversation: 301,\n /** Websocket push of new messages. */\n NewMessage: 500,\n /** Add / remove a reaction (message `property`) — `/v1/message/set_property`. */\n SetMessageProperty: 705,\n GetConversationInfo: 610,\n MarkRead: 2002,\n UploadConfig: 2059,\n} as const;\n\n/** MarkRead's body lives in field 604, not the command number. */\nexport const MARK_READ_BODY_FIELD = 604;\n\n/** `MessageBody.message_type`. */\nexport const MessageType = {\n System: 1,\n Text: 7,\n ShareVideo: 8,\n PrivateImage: 1802,\n /** Sticker — public image on the sticker CDN, not encrypted. */\n Sticker: 1805,\n /** Hidden command (read receipt…) — not shown in the conversation, but still pushed over websocket. */\n Command: 50001,\n} as const;\n\nexport const ConversationType = { OneToOne: 1 } as const;\n\n/** `Response` fields (both HTTP and websocket payload). */\nexport const Resp = { cmd: 1, seq: 2, status: 3, error: 4, body: 6, logId: 7 } as const;\n\n/** `MessageBody` fields. */\nexport const MsgF = {\n conversationId: 1,\n conversationType: 2,\n serverMessageId: 3,\n indexInConversation: 4,\n conversationShortId: 5,\n type: 6,\n sender: 7,\n content: 8,\n ext: 9,\n createTime: 10,\n /** `property_list` — reaction: `{1 key \"e:<emoji>\", 2 {1 PropertyItem[]}}`. */\n propertyList: 15,\n attachments: 20,\n tag: 21,\n} as const;\n\n/** Operation on a message `property` (`ModifyPropertyContent.operation`). */\nexport const PropertyOp = { Add: 0, Remove: 1 } as const;\n\n/** Reaction key = `e:<emoji>`. The mobile app reacting ❤️ also writes the legacy key `e:love` — treated as ❤️. */\nexport const REACTION_PREFIX = 'e:';\nexport const REACTION_LOVE_KEY = 'e:love';\nexport const REACTION_HEART = '\\u2764\\uFE0F';\n\n/** ImageX — image upload endpoint (AWS SigV4-style signing). */\nexport const IMAGEX_REGION = 'cn-north-1';\nexport const IMAGEX_SERVICE = 'imagex';\nexport const IMAGEX_VERSION = '2018-08-01';\n","/**\n * Minimal protobuf, no `.proto` file needed.\n *\n * TikTok doesn't publish its IM `.proto` — field numbers in `constants.ts` were reconstructed from bytes captured\n * in the browser (09/11/2026). Only three wire types are needed: varint (0), length-delimited (2), and skipping 1/5.\n */\n\nexport interface Field {\n n: number;\n wire: number;\n int: bigint;\n bytes: Buffer;\n}\n\nfunction readVarint(b: Buffer, i: number): [bigint, number] {\n let x = 0n;\n let shift = 0n;\n let c: number;\n do {\n if (i >= b.length) throw new Error('varint runs past end of buffer');\n c = b[i++];\n x |= BigInt(c & 127) << shift;\n shift += 7n;\n } while (c & 128);\n return [x, i];\n}\n\n/** Split a message into a list of fields. `null` if the bytes are not valid protobuf. */\nexport function decodeFields(b: Buffer): Field[] | null {\n const out: Field[] = [];\n let i = 0;\n try {\n while (i < b.length) {\n const [key, j] = readVarint(b, i);\n i = j;\n const wire = Number(key & 7n);\n const n = Number(key >> 3n);\n if (n === 0) return null;\n if (wire === 0) {\n const [v, k] = readVarint(b, i);\n out.push({ n, wire, int: v, bytes: Buffer.alloc(0) });\n i = k;\n } else if (wire === 2) {\n const [len, k] = readVarint(b, i);\n const end = k + Number(len);\n if (end > b.length) return null;\n out.push({ n, wire, int: 0n, bytes: b.subarray(k, end) });\n i = end;\n } else if (wire === 1 || wire === 5) {\n const size = wire === 1 ? 8 : 4;\n if (i + size > b.length) return null;\n out.push({ n, wire, int: 0n, bytes: b.subarray(i, i + size) });\n i += size;\n } else {\n return null;\n }\n }\n } catch {\n return null;\n }\n return out;\n}\n\n/** Decoded message — read by field number. */\nexport class Msg {\n private constructor(readonly fields: Field[]) {}\n\n static parse(b: Buffer): Msg {\n const f = decodeFields(b);\n if (!f) throw new Error('Failed to decode protobuf');\n return new Msg(f);\n }\n\n static tryParse(b: Buffer | undefined): Msg | null {\n if (!b) return null;\n const f = decodeFields(b);\n return f ? new Msg(f) : null;\n }\n\n has(n: number): boolean {\n return this.fields.some((f) => f.n === n);\n }\n\n int(n: number): bigint {\n return this.fields.find((f) => f.n === n)?.int ?? 0n;\n }\n\n num(n: number): number {\n return Number(this.int(n));\n }\n\n /** 64-bit integer as a string — uids / message IDs exceed `Number.MAX_SAFE_INTEGER`. */\n id(n: number): string {\n return this.int(n).toString();\n }\n\n bytes(n: number): Buffer {\n return this.fields.find((f) => f.n === n)?.bytes ?? Buffer.alloc(0);\n }\n\n str(n: number): string {\n return this.bytes(n).toString('utf8');\n }\n\n strs(n: number): string[] {\n return this.fields.filter((f) => f.n === n).map((f) => f.bytes.toString('utf8'));\n }\n\n msg(n: number): Msg | null {\n return Msg.tryParse(this.fields.find((f) => f.n === n)?.bytes);\n }\n\n msgs(n: number): Msg[] {\n return this.fields\n .filter((f) => f.n === n)\n .map((f) => Msg.tryParse(f.bytes))\n .filter((m): m is Msg => m !== null);\n }\n\n /** `map<string,string>` — each entry is a message `{1: key, 2: value}`. */\n map(n: number): Record<string, string> {\n const out: Record<string, string> = {};\n for (const m of this.msgs(n)) out[m.str(1)] = m.str(2);\n return out;\n }\n}\n\nfunction varint(x: bigint | number): Buffer {\n let v = BigInt(x);\n if (v < 0n) v = BigInt.asUintN(64, v);\n const out: number[] = [];\n do {\n const c = Number(v & 127n);\n v >>= 7n;\n out.push(v ? c | 128 : c);\n } while (v);\n return Buffer.from(out);\n}\n\nconst key = (n: number, wire: number): Buffer => varint((BigInt(n) << 3n) | BigInt(wire));\n\n/** Build a message in call order. */\nexport class Writer {\n private readonly parts: Buffer[] = [];\n\n int(n: number, v: bigint | number | string): this {\n this.parts.push(key(n, 0), varint(typeof v === 'string' ? BigInt(v) : v));\n return this;\n }\n\n bytes(n: number, v: Buffer | string): this {\n const b = typeof v === 'string' ? Buffer.from(v, 'utf8') : v;\n this.parts.push(key(n, 2), varint(b.length), b);\n return this;\n }\n\n msg(n: number, w: Writer): this {\n return this.bytes(n, w.finish());\n }\n\n /** `map<string,string>` in the object's key order. */\n map(n: number, obj: Record<string, string>): this {\n for (const [k, v] of Object.entries(obj)) this.msg(n, new Writer().bytes(1, k).bytes(2, v));\n return this;\n }\n\n finish(): Buffer {\n return Buffer.concat(this.parts);\n }\n}\n","/** Error from TikTok or from the library itself. `code` lets callers branch (e.g. session expired → rescan). */\nexport class TikTokError extends Error {\n constructor(\n readonly code: TikTokErrorCode,\n message: string,\n /** Original TikTok code (status_code / error_code), if any. */\n readonly upstream?: number | string,\n ) {\n super(message);\n this.name = 'TikTokError';\n }\n}\n\nexport type TikTokErrorCode =\n /** Cookie is no longer logged in — a new session is required. */\n | 'SESSION_EXPIRED'\n /**\n * TikTok's gateway rejects this session for the command (JSON `status_code: 7` instead of protobuf). Seen on\n * `message/send` while reads keep working — log in again to get a fresh session.\n */\n | 'SESSION_BLOCKED'\n | 'HTTP_ERROR'\n /** IM returned a non-zero `status_code`. */\n | 'IM_ERROR'\n | 'UPLOAD_FAILED'\n | 'DOWNLOAD_FAILED'\n | 'BAD_RESPONSE'\n /** QR login failed (Chrome failed to launch, QR expired, no cookie found…). */\n | 'LOGIN_FAILED'\n /** Caller aborted QR login (`signal`). */\n | 'LOGIN_ABORTED';\n","import { EventEmitter } from 'node:events';\nimport WebSocket from 'ws';\nimport { AID_FRONTIER, FRONTIER_FPID, IM_WS, WEB } from '../protocol/constants';\nimport type { Context } from '../protocol/context';\nimport { parseMessage } from '../models/message';\nimport type { TikTokMessage } from '../models/types';\nimport { accessKey, buildAck, newMessageBody, parseFrame } from './frame';\n\n/** The browser sends \"hi\" every 15–30 seconds; use the lower bound. */\nconst HEARTBEAT_MS = 15_000;\n/** If nothing (not even a \"hi\" reply) arrives for this long, treat it as silently dead and reconnect. */\nconst IDLE_TIMEOUT_MS = 75_000;\nconst RECONNECT_MIN_MS = 2_000;\nconst RECONNECT_MAX_MS = 60_000;\n/** The server pushes the same message several times (one frame per device) — remember this many message IDs to dedupe. */\nconst DEDUPE_KEEP = 500;\n\n/** Close code used when we call `stop()` ourselves. */\nexport const MANUAL_CLOSE = 4000;\n\nexport interface ListenerEvents {\n connected: [];\n /** A real message in a conversation (including our own — see `isSelf`). */\n message: [TikTokMessage];\n /** Hidden command: mark as read… (`content.command_type`). */\n command: [TikTokMessage];\n /** Close code + reason. Unless `MANUAL_CLOSE`, the listener reconnects automatically (if enabled). */\n closed: [number, string];\n error: [Error];\n}\n\n/**\n * Listen for new messages via the `im-ws-sg` websocket (aid 1459) — cookies only.\n * Events: `connected`, `message`, `closed`, `error`.\n */\nexport class Listener extends EventEmitter<ListenerEvents> {\n private ws: WebSocket | null = null;\n private heartbeat: NodeJS.Timeout | null = null;\n private idle: NodeJS.Timeout | null = null;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private backoff = RECONNECT_MIN_MS;\n private retry = true;\n private readonly seen = new Set<string>();\n\n constructor(private readonly ctx: Context) {\n super();\n }\n\n get connected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n url(): string {\n const q = new URLSearchParams({\n aid: AID_FRONTIER,\n fpid: FRONTIER_FPID,\n device_platform: 'web',\n version_code: 'fws_1.0.0',\n access_key: accessKey(this.ctx.deviceId),\n device_id: this.ctx.deviceId,\n // Cookie value is already URL-encoded (`1%7C…`) — decode it so URLSearchParams doesn't double-encode.\n ttwid: decodeURIComponent(this.ctx.cookies.get('ttwid') ?? ''),\n xsack: '1',\n xaack: '1',\n xsqos: '0',\n });\n return `${IM_WS}?${q}`;\n }\n\n /** Open the connection. `retryOnClose` (on by default): reconnect on drop, backing off up to 1 minute. */\n start(opts: { retryOnClose?: boolean } = {}): void {\n this.retry = opts.retryOnClose ?? true;\n this.connect();\n }\n\n stop(): void {\n this.retry = false;\n this.clearTimers();\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n const ws = this.ws;\n this.ws = null;\n if (ws && ws.readyState <= WebSocket.OPEN) ws.close(MANUAL_CLOSE, 'manual');\n }\n\n private connect(): void {\n const ws = new WebSocket(this.url(), {\n headers: { Cookie: this.ctx.cookieHeader(), 'User-Agent': this.ctx.userAgent, Origin: WEB },\n });\n this.ws = ws;\n ws.binaryType = 'nodebuffer';\n ws.on('open', () => {\n this.backoff = RECONNECT_MIN_MS;\n this.heartbeat = setInterval(() => ws.readyState === WebSocket.OPEN && ws.send('hi'), HEARTBEAT_MS);\n this.touch();\n this.ctx.log('debug', 'tca: websocket connected');\n this.emit('connected');\n });\n ws.on('message', (data: Buffer, isBinary: boolean) => {\n this.touch();\n if (!isBinary) return; // \"hi\" reply\n try {\n this.onFrame(ws, data);\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n });\n ws.on('error', (err) => this.emit('error', err));\n ws.on('close', (code, reason) => {\n if (this.ws !== ws) return; // old connection was replaced\n this.ws = null;\n this.clearTimers();\n this.emit('closed', code, reason.toString());\n if (!this.retry || code === MANUAL_CLOSE) return;\n const wait = this.backoff;\n this.backoff = Math.min(this.backoff * 2, RECONNECT_MAX_MS);\n this.ctx.log('warn', `tca: websocket closed (${code}) — reconnecting in ${wait / 1000}s`);\n this.reconnectTimer = setTimeout(() => this.connect(), wait);\n });\n }\n\n private touch(): void {\n if (this.idle) clearTimeout(this.idle);\n this.idle = setTimeout(() => {\n this.ctx.log('warn', 'tca: websocket silent too long — reconnecting');\n this.ws?.terminate();\n }, IDLE_TIMEOUT_MS);\n }\n\n private clearTimers(): void {\n if (this.heartbeat) clearInterval(this.heartbeat);\n if (this.idle) clearTimeout(this.idle);\n this.heartbeat = null;\n this.idle = null;\n }\n\n private onFrame(ws: WebSocket, data: Buffer): void {\n const frame = parseFrame(data);\n if (frame.headers.need_ack === '1' && ws.readyState === WebSocket.OPEN) ws.send(buildAck(frame));\n const body = newMessageBody(frame);\n if (!body) return;\n const msg = parseMessage(body, this.ctx.ownId);\n if (!msg.serverMessageId || this.seen.has(msg.serverMessageId)) return;\n this.seen.add(msg.serverMessageId);\n if (this.seen.size > DEDUPE_KEEP) this.seen.delete(this.seen.values().next().value as string);\n if (msg.kind === 'command') this.emit('command', msg);\n else this.emit('message', msg);\n }\n}\n","import { MessageType, MsgF, REACTION_HEART, REACTION_LOVE_KEY, REACTION_PREFIX } from '../protocol/constants';\nimport { Msg } from '../protocol/proto';\nimport type { TikTokConversation, TikTokImage, TikTokMessage, TikTokReaction, TikTokSticker } from './types';\n\nfunction parseJson(s: string): unknown {\n try {\n return JSON.parse(s);\n } catch {\n return s;\n }\n}\n\n/** Image in `attachments` (field 20 → 4): 1 = original, 2 = thumbnail; each {1 uri, 2 url…, 5 {w,h}, 6 key}. */\nfunction parseImage(m: Msg): TikTokImage | null {\n const media = m.msg(MsgF.attachments)?.msg(4);\n const origin = media?.msg(1);\n if (!media || !origin) return null;\n const size = origin.msg(5);\n return {\n uri: origin.str(1),\n url: origin.strs(2)[0] ?? '',\n thumbUrl: media.msg(2)?.strs(2)[0] ?? '',\n width: size?.num(1) ?? 0,\n height: size?.num(2) ?? 0,\n decryptKey: origin.str(6),\n };\n}\n\n/**\n * Sticker (field 20 → 7): `{1 {1 uri, 2 url, 5 {w,h}}, 2 hint, 200 {1 {2 map a:sticker_id, a:sticker_type…}}}`.\n * Links point to the public sticker CDN (`…-dm-sticker-sign-…`) — not encrypted, no cookies needed.\n */\nfunction parseSticker(m: Msg): TikTokSticker | null {\n const st = m.msg(MsgF.attachments)?.msg(7);\n const img = st?.msg(1);\n if (!st || !img) return null;\n const size = img.msg(5);\n const ext = st.msg(200)?.msg(1)?.map(2) ?? {};\n return {\n stickerId: ext['a:sticker_id'] ?? '',\n stickerType: Number(ext['a:sticker_type'] ?? 0),\n url: img.str(2),\n width: size?.num(1) ?? 0,\n height: size?.num(2) ?? 0,\n };\n}\n\n/**\n * Reaction (field 15, `property_list`): each entry `{1 key, 2 {1 PropertyItem[]}}`, key `e:<emoji>`,\n * `PropertyItem {1 uid, 3 sec, 4 idempotent_id, 6 µs}`. The mobile app writes ❤️ as both `e:❤️` and `e:love` → merged.\n */\nfunction parseReactions(m: Msg): TikTokReaction[] {\n const byEmoji = new Map<string, Set<string>>();\n for (const p of m.msgs(MsgF.propertyList)) {\n const key = p.str(1);\n if (!key.startsWith(REACTION_PREFIX)) continue;\n const emoji = key === REACTION_LOVE_KEY ? REACTION_HEART : key.slice(REACTION_PREFIX.length);\n const uids = byEmoji.get(emoji) ?? new Set<string>();\n for (const item of p.msg(2)?.msgs(1) ?? []) uids.add(item.id(1));\n if (uids.size) byEmoji.set(emoji, uids);\n }\n return [...byEmoji].map(([emoji, uids]) => ({ emoji, userIds: [...uids] }));\n}\n\nconst KIND: Record<number, TikTokMessage['kind']> = {\n [MessageType.Text]: 'text',\n [MessageType.PrivateImage]: 'image',\n [MessageType.Sticker]: 'sticker',\n [MessageType.ShareVideo]: 'video',\n [MessageType.System]: 'system',\n [MessageType.Command]: 'command',\n};\n\n/** `MessageBody` → `TikTokMessage`. */\nexport function parseMessage(m: Msg, ownId: string): TikTokMessage {\n const type = m.num(MsgF.type);\n const content = parseJson(m.str(MsgF.content));\n const ext = m.map(MsgF.ext);\n const senderId = m.id(MsgF.sender);\n const text =\n type === MessageType.Text && content && typeof content === 'object' && 'text' in content\n ? String((content as { text: unknown }).text ?? '')\n : '';\n return {\n conversationId: m.str(MsgF.conversationId),\n conversationShortId: m.id(MsgF.conversationShortId),\n serverMessageId: m.id(MsgF.serverMessageId),\n index: m.id(MsgF.indexInConversation),\n type,\n kind: KIND[type] ?? 'other',\n senderId,\n isSelf: senderId === ownId,\n text,\n image: type === MessageType.PrivateImage ? parseImage(m) : null,\n sticker: type === MessageType.Sticker ? parseSticker(m) : null,\n reactions: parseReactions(m),\n content,\n createdAt: m.num(MsgF.createTime),\n clientMessageId: ext['s:client_message_id'] ?? '',\n ext,\n };\n}\n\n/** `ConversationInfo` (field 2 of get_by_user_init): {1 id, 2 shortId, 3 type, 6 {1 {1 uid}}…}. */\nexport function parseConversation(m: Msg, ownId: string): TikTokConversation {\n const participants = (m.msg(6)?.msgs(1) ?? []).map((p) => p.id(1));\n return {\n conversationId: m.str(1),\n conversationShortId: m.id(2),\n participants,\n peerId: participants.find((p) => p !== ownId) ?? '',\n };\n}\n","/**\n * \"Frontier\" websocket framing — pure helpers (no socket), shared by the listener and unit tests.\n */\nimport { createHash } from 'node:crypto';\nimport { Cmd, FRONTIER_APP_KEY, FRONTIER_FPID, FRONTIER_SALT, Resp } from '../protocol/constants';\nimport { lz4Decompress } from '../protocol/lz4';\nimport { Msg, Writer } from '../protocol/proto';\n\n/** \"Frontier\" websocket frame: {1 seqid, 2 logid, 3 service, 4 method, 5 headers, 6 encoding, 7 type, 8 payload}. */\nexport interface Frame {\n seq: bigint;\n logId: bigint;\n headers: Record<string, string>;\n encoding: string;\n payload: Buffer;\n}\n\n/** Websocket `access_key` = md5(FPID + APP_KEY + device_id + SALT). */\nexport function accessKey(deviceId: string): string {\n return createHash('md5')\n .update(FRONTIER_FPID + FRONTIER_APP_KEY + deviceId + FRONTIER_SALT)\n .digest('hex');\n}\n\nexport function parseFrame(data: Buffer): Frame {\n const m = Msg.parse(data);\n return {\n seq: m.int(1),\n logId: m.int(2),\n headers: m.map(5),\n encoding: m.str(6),\n payload: m.bytes(8),\n };\n}\n\n/** The `MessageBody` of a `NewMessage` push inside a frame, or `null` if the frame carries something else. */\nexport function newMessageBody(frame: Frame): Msg | null {\n if (frame.payload.length === 0) return null;\n const payload = frame.encoding === '__lz4' ? lz4Decompress(frame.payload) : frame.payload;\n const resp = Msg.tryParse(payload);\n if (!resp || resp.num(Resp.cmd) !== Cmd.NewMessage) return null;\n // NewMessageNotify: {2 conversationId, 3 type, 4 ?, 5 MessageBody}\n return resp.msg(Resp.body)?.msg(Cmd.NewMessage)?.msg(5) ?? null;\n}\n\n/** Acknowledge receipt — `ack_id = <base36 time>:<x_frontier_traceid>`, echoing the frame's seq/logid. */\nexport function buildAck(f: Frame, now: number = Date.now()): Buffer {\n const ackId = `${now.toString(36)}:${f.headers.x_frontier_traceid ?? ''}`;\n return new Writer()\n .int(1, f.seq)\n .int(2, f.logId)\n .int(3, 5)\n .int(4, 1)\n .map(5, { is_ack: '1', ack_id: ackId, ack_code: '0' })\n .bytes(9, ackId)\n .finish();\n}\n","/**\n * LZ4 block decompression (no frame header) — websocket frames with\n * `payload_encoding = \"__lz4\"` compress their payload this way. No extra dependency for ~30 lines.\n */\nexport function lz4Decompress(src: Buffer): Buffer {\n let out = Buffer.alloc(Math.max(src.length * 4, 1024));\n let o = 0;\n const ensure = (need: number) => {\n if (o + need <= out.length) return;\n let size = out.length * 2;\n while (o + need > size) size *= 2;\n const bigger = Buffer.alloc(size);\n out.copy(bigger, 0, 0, o);\n out = bigger;\n };\n let i = 0;\n while (i < src.length) {\n const token = src[i++];\n let lit = token >> 4;\n if (lit === 15) {\n let b: number;\n do {\n b = src[i++];\n lit += b;\n } while (b === 255);\n }\n ensure(lit);\n src.copy(out, o, i, i + lit);\n i += lit;\n o += lit;\n if (i >= src.length) break;\n const offset = src[i] | (src[i + 1] << 8);\n i += 2;\n if (offset === 0 || offset > o) throw new Error('lz4: invalid offset');\n let len = token & 15;\n if (len === 15) {\n let b: number;\n do {\n b = src[i++];\n len += b;\n } while (b === 255);\n }\n len += 4;\n ensure(len);\n // Copy byte by byte: source and destination ranges may overlap.\n for (let k = 0; k < len; k++, o++) out[o] = out[o - offset];\n }\n return out.subarray(0, o);\n}\n","import { AID_FRONTIER, WEB } from '../protocol/constants';\nimport type { Context } from '../protocol/context';\nimport type { TikTokAccount } from '../models/types';\n\n/** Account for the cookie — `null` if the cookie is no longer logged in. */\nexport async function fetchAccount(ctx: Context): Promise<TikTokAccount | null> {\n type Res = {\n message?: string;\n data?: { user_id_str?: string; username?: string; screen_name?: string; avatar_url?: string; error_code?: number };\n };\n const res = await ctx.getJson<Res>(`${WEB}/passport/web/account/info/?aid=${AID_FRONTIER}`);\n if (res.message !== 'success' || !res.data?.user_id_str) return null;\n return {\n uid: res.data.user_id_str,\n username: res.data.username ?? '',\n screenName: res.data.screen_name ?? '',\n avatar: res.data.avatar_url ?? '',\n };\n}\n\n/** `wid` — device id TikTok issues per `ttwid` cookie; IM + websocket use it as `device_id`. */\nexport async function fetchWebId(ctx: Context): Promise<string> {\n const res = await ctx.fetch(`${WEB}/api/v1/web-cookie-privacy/config?locale=vi-VN&appId=1988&theme=default&tea=1`);\n if (!res.ok) return '';\n return /\"wid\":\"(\\d+)\"/.exec(await res.text())?.[1] ?? '';\n}\n\n/**\n * Avatar URLs from the IM profile `avatars` — collects every `https://…` string (thumb → medium → larger, whatever\n * TikTok returns), then puts browser-readable ones (jpeg/webp/png) first and heic last.\n */\nexport function avatarLinks(avatars: unknown): { avatar: string; avatars: string[] } {\n const urls: string[] = [];\n const walk = (v: unknown) => {\n if (typeof v === 'string') {\n if (/^https?:\\/\\//.test(v) && !urls.includes(v)) urls.push(v);\n } else if (Array.isArray(v)) v.forEach(walk);\n else if (v && typeof v === 'object') Object.values(v).forEach(walk);\n };\n walk(avatars);\n const heic = (u: string) => /\\.heic(\\?|$)/i.test(u.split('?')[0] + '?');\n const ranked = [...urls.filter((u) => !heic(u)), ...urls.filter(heic)];\n return { avatar: ranked[0] ?? '', avatars: ranked };\n}\n","import { createDecipheriv, createHash, createHmac, randomBytes } from 'node:crypto';\nimport { crc32 } from 'node:zlib';\nimport { Cmd, IMAGEX_REGION, IMAGEX_SERVICE, IMAGEX_VERSION } from '../protocol/constants';\nimport type { Context } from '../protocol/context';\nimport { TikTokError } from '../errors';\nimport type { ImageInput, TikTokImage } from '../models/types';\n\n/** Temporary STS credentials for the image store — obtained via IM command `UploadConfig`, valid ~10 minutes. */\ninterface UploadCredential {\n serviceId: string;\n host: string;\n accessKeyId: string;\n sessionToken: string;\n secretAccessKey: string;\n /** ms epoch */\n expiresAt: number;\n}\n\n/** Uploaded image, encrypted by the store — enough to send an image message. */\nexport interface UploadedImage {\n uri: string;\n secretKey: string;\n width: number;\n height: number;\n size: number;\n filename: string;\n}\n\nconst sha256 = (s: string | Buffer) => createHash('sha256').update(s).digest('hex');\nconst hmac = (k: string | Buffer, s: string) => createHmac('sha256', k).update(s).digest();\nconst rfc3986 = (s: string) =>\n encodeURIComponent(s).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);\n\nexport class MediaClient {\n private cred: UploadCredential | null = null;\n\n constructor(private readonly ctx: Context) {}\n\n /** `UploadConfig` returns two credential sets: type 1 = ImageX (images), type 2 = VOD (video). Use type 1. */\n private async credential(): Promise<UploadCredential> {\n if (this.cred && this.cred.expiresAt - Date.now() > 60_000) return this.cred;\n const body = await this.ctx.im('/v1/media/upload_config', Cmd.UploadConfig, Buffer.alloc(0));\n const c = body.msgs(1).find((m) => m.num(1) === 1);\n if (!c) throw new TikTokError('UPLOAD_FAILED', 'upload_config has no ImageX credentials');\n this.cred = {\n serviceId: c.str(2),\n host: c.str(3),\n expiresAt: c.num(4),\n accessKeyId: c.str(6),\n sessionToken: c.str(7),\n secretAccessKey: c.str(8),\n };\n return this.cred;\n }\n\n /** Call ImageX signed with AWS SigV4 (region cn-north-1, service imagex). */\n private async imagex<T>(method: 'GET' | 'POST', params: Record<string, string>, body?: string): Promise<T> {\n const c = await this.credential();\n const amzDate = new Date().toISOString().replace(/[-:]/g, '').replace(/\\.\\d+/, '');\n const date = amzDate.slice(0, 8);\n const query = Object.keys(params)\n .sort()\n .map((k) => `${rfc3986(k)}=${rfc3986(params[k])}`)\n .join('&');\n const headers: Record<string, string> = { 'x-amz-date': amzDate, 'x-amz-security-token': c.sessionToken };\n if (body !== undefined) headers['x-amz-content-sha256'] = sha256(body);\n const signed = Object.keys(headers).sort();\n const canonical = [\n method,\n '/',\n query,\n signed.map((k) => `${k}:${headers[k]}\\n`).join(''),\n signed.join(';'),\n body !== undefined ? headers['x-amz-content-sha256'] : sha256(''),\n ].join('\\n');\n const scope = `${date}/${IMAGEX_REGION}/${IMAGEX_SERVICE}/aws4_request`;\n const toSign = ['AWS4-HMAC-SHA256', amzDate, scope, sha256(canonical)].join('\\n');\n let k = hmac(`AWS4${c.secretAccessKey}`, date);\n k = hmac(k, IMAGEX_REGION);\n k = hmac(k, IMAGEX_SERVICE);\n k = hmac(k, 'aws4_request');\n const signature = createHmac('sha256', k).update(toSign).digest('hex');\n const res = await fetch(`https://${c.host}/?${query}`, {\n method,\n headers: {\n ...headers,\n Authorization: `AWS4-HMAC-SHA256 Credential=${c.accessKeyId}/${scope}, SignedHeaders=${signed.join(';')}, Signature=${signature}`,\n ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n },\n body,\n signal: AbortSignal.timeout(this.ctx.options.timeoutMs ?? 20_000),\n });\n const json = (await res.json().catch(() => null)) as {\n ResponseMetadata?: { Error?: { Message?: string; CodeN?: number } };\n } | null;\n const err = json?.ResponseMetadata?.Error;\n if (!res.ok || !json || err) {\n throw new TikTokError(\n 'UPLOAD_FAILED',\n `imagex ${params.Action}: ${err?.Message ?? `HTTP ${res.status}`}`,\n err?.CodeN ?? res.status,\n );\n }\n return json as T;\n }\n\n /**\n * Upload an image to the private message store: Apply → POST file → Commit (the store encrypts with AES-GCM\n * and returns the key). Image dimensions come from the Commit result — no need to decode the image.\n */\n async upload(image: ImageInput): Promise<UploadedImage> {\n const c = await this.credential();\n const ext = (/\\.([a-z0-9]{2,5})$/i.exec(image.filename)?.[1] ?? 'jpg').toLowerCase();\n type Apply = {\n Result: {\n UploadAddress: { StoreInfos: { StoreUri: string; Auth: string }[]; UploadHosts: string[]; SessionKey: string };\n };\n };\n const apply = await this.imagex<Apply>('GET', {\n Action: 'ApplyImageUpload',\n Version: IMAGEX_VERSION,\n ServiceId: c.serviceId,\n FileSize: String(image.data.length),\n FileExtension: `.${ext}`,\n s: randomBytes(6).toString('hex').slice(0, 10),\n });\n const addr = apply.Result.UploadAddress;\n const store = addr.StoreInfos[0];\n const host = addr.UploadHosts[0];\n if (!store || !host) throw new TikTokError('UPLOAD_FAILED', 'ApplyImageUpload returned no upload target');\n\n const up = await fetch(`https://${host}/upload/v1/${store.StoreUri}`, {\n method: 'POST',\n headers: {\n Authorization: store.Auth,\n 'Content-CRC32': (crc32(image.data) >>> 0).toString(16).padStart(8, '0'),\n // Without this header the store returns 4004 Not Found.\n 'X-Storage-U': this.ctx.ownId,\n 'Content-Type': 'application/octet-stream',\n 'Content-Disposition': 'attachment; filename=\"undefined\"',\n },\n body: new Uint8Array(image.data),\n signal: AbortSignal.timeout(this.ctx.options.timeoutMs ?? 60_000),\n });\n const upJson = (await up.json().catch(() => null)) as { code?: number; message?: string } | null;\n if (!up.ok || upJson?.code !== 2000) {\n throw new TikTokError(\n 'UPLOAD_FAILED',\n `upload: ${upJson?.message ?? `HTTP ${up.status}`}`,\n upJson?.code ?? up.status,\n );\n }\n\n type Commit = {\n Result: {\n Results: { Encryption?: { Uri: string; SecretKey: string; Extra?: Record<string, string> } }[];\n PluginResult?: { ImageWidth?: number; ImageHeight?: number; ImageSize?: number }[];\n };\n };\n const commit = await this.imagex<Commit>(\n 'POST',\n { Action: 'CommitImageUpload', Version: IMAGEX_VERSION, ServiceId: c.serviceId },\n JSON.stringify({\n SessionKey: addr.SessionKey,\n Functions: [{ name: 'Encryption', input: { Config: { copies: 'cipher_v2' } } }],\n }),\n );\n const enc = commit.Result.Results?.[0]?.Encryption;\n const plugin = commit.Result.PluginResult?.[0];\n if (!enc?.Uri || !enc.SecretKey)\n throw new TikTokError('UPLOAD_FAILED', 'CommitImageUpload returned no encrypted result');\n return {\n uri: enc.Uri,\n secretKey: enc.SecretKey,\n width: plugin?.ImageWidth ?? Number(enc.Extra?.img_width ?? 0),\n height: plugin?.ImageHeight ?? Number(enc.Extra?.img_height ?? 0),\n size: plugin?.ImageSize ?? image.data.length,\n filename: image.filename,\n };\n }\n\n /** Download and decrypt a message image. Layout: 12-byte IV ‖ ciphertext ‖ 16-byte tag. */\n async download(image: TikTokImage, which: 'origin' | 'thumb' = 'origin'): Promise<Buffer> {\n const url = which === 'thumb' && image.thumbUrl ? image.thumbUrl : image.url;\n if (!url) throw new TikTokError('DOWNLOAD_FAILED', 'Image has no URL');\n const res = await this.ctx.fetch(url);\n if (!res.ok) throw new TikTokError('DOWNLOAD_FAILED', `Image download: HTTP ${res.status}`, res.status);\n const enc = Buffer.from(await res.arrayBuffer());\n if (!image.decryptKey) return enc;\n try {\n const d = createDecipheriv('aes-256-gcm', Buffer.from(image.decryptKey, 'hex'), enc.subarray(0, 12));\n d.setAuthTag(enc.subarray(enc.length - 16));\n return Buffer.concat([d.update(enc.subarray(12, enc.length - 16)), d.final()]);\n } catch (err) {\n throw new TikTokError('DOWNLOAD_FAILED', `Image decryption: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n}\n","/**\n * Pure builders for IM request bodies (protobuf) — no I/O, so they can be unit-tested byte for byte.\n */\nimport {\n ConversationType,\n PropertyOp,\n REACTION_HEART,\n REACTION_LOVE_KEY,\n REACTION_PREFIX,\n} from '../protocol/constants';\nimport { Writer } from '../protocol/proto';\nimport type { ConversationRef, TikTokMessage } from '../models/types';\nimport type { UploadedImage } from './media';\n\n/** \"Latest\" cursor for reading history — greater than any `index` (µs). */\nexport const NEWEST = 9_999_999_999_999_999n;\n\n/** `GetMessagesByConversationRequestBody` — messages older than `before` (or the newest ones). */\nexport function getMessagesBody(conv: ConversationRef, limit: number, before?: string): Buffer {\n return new Writer()\n .bytes(1, conv.conversationId)\n .int(2, ConversationType.OneToOne)\n .int(3, BigInt(conv.conversationShortId))\n .int(4, 1) // direction: older than cursor\n .int(5, before ? BigInt(before) : NEWEST)\n .int(6, limit)\n .finish();\n}\n\n/** `MarkConversationReadRequestBody` — read up to message `index`. */\nexport function markReadBody(msg: ConversationRef & { index: string }): Buffer {\n return new Writer()\n .bytes(1, msg.conversationId)\n .int(2, BigInt(msg.conversationShortId))\n .int(3, ConversationType.OneToOne)\n .int(4, BigInt(msg.index))\n .int(11, 4)\n .finish();\n}\n\n/**\n * `SendMessageRequestBody`: {1 convId, 2 conversation type, 3 shortId, 4 content, 5 ext, 6 message type, 7 ticket,\n * 8 client id, …}. `extra` is appended verbatim (image attachments).\n */\nexport function sendMessageBody(\n conv: ConversationRef,\n cid: string,\n type: number,\n content: string,\n extra: Writer | null,\n): Buffer {\n const w = new Writer()\n .bytes(1, conv.conversationId)\n .int(2, ConversationType.OneToOne)\n .int(3, BigInt(conv.conversationShortId))\n .bytes(4, content)\n .map(5, { 's:mentioned_users': '', 's:client_message_id': cid })\n .int(6, type)\n .bytes(7, 'deprecated')\n .bytes(8, cid);\n return extra ? Buffer.concat([w.finish(), extra.finish()]) : w.finish();\n}\n\n/** Extra `SendMessageRequestBody` fields (13, 14, 17) describing an uploaded private image. */\nexport function imageMessageExtra(up: UploadedImage): Writer {\n const w = String(up.width);\n const h = String(up.height);\n const media = new Writer()\n .msg(\n 1,\n new Writer()\n .bytes(1, up.uri)\n .msg(5, new Writer().int(1, up.width).int(2, up.height))\n .bytes(6, up.secretKey)\n .int(7, 0),\n )\n .msg(\n 3,\n new Writer()\n .msg(1, new Writer().bytes(1, 'You sent a 📷'))\n .msg(2, new Writer().bytes(1, 'sent a 📷'))\n .msg(3, new Writer().bytes(1, '[Photo]')),\n )\n .msg(\n 200,\n new Writer().msg(\n 1,\n new Writer().bytes(1, up.uri).map(2, {\n image_width: w,\n image_height: h,\n decrypt_key: up.secretKey,\n quote_preview: 'dm_cam_preview_photo',\n sender_preview: 'sender_preview',\n }),\n ),\n );\n return new Writer()\n .msg(13, new Writer().msg(4, media))\n .bytes(14, 'private_image')\n .msg(\n 17,\n new Writer()\n .int(1, 1)\n .bytes(2, up.uri)\n .bytes(3, up.secretKey)\n .msg(10, new Writer().int(1, up.width).int(2, up.height).int(4, up.size).bytes(5, up.filename)),\n );\n}\n\nexport interface PropertyChange {\n op: number;\n key: string;\n}\n\n/**\n * Property operations that make `own`'s reaction on `msg` equal `emoji` (one reaction per user; `null` = remove).\n * Empty when nothing needs to change.\n */\nexport function reactionOps(\n msg: Pick<TikTokMessage, 'reactions'>,\n own: string,\n emoji: string | null,\n): PropertyChange[] {\n const mine = msg.reactions.filter((r) => r.userIds.includes(own)).map((r) => r.emoji);\n const ops: PropertyChange[] = [];\n if (emoji && !mine.includes(emoji)) ops.push({ op: PropertyOp.Add, key: REACTION_PREFIX + emoji });\n for (const e of mine) {\n if (e === emoji) continue;\n ops.push({ op: PropertyOp.Remove, key: REACTION_PREFIX + e });\n // ❤️ sent from the mobile app still uses the legacy key `e:love` — remove it too or the app keeps showing the heart.\n if (e === REACTION_HEART) ops.push({ op: PropertyOp.Remove, key: REACTION_LOVE_KEY });\n }\n return ops;\n}\n\n/** `ModifyMessagePropertyRequestBody` (command 705) applying `ops` to `msg` as user `own`. */\nexport function setPropertyBody(msg: TikTokMessage, ops: PropertyChange[], own: string): Buffer {\n const target = new Writer()\n .bytes(1, msg.conversationId)\n .int(2, ConversationType.OneToOne)\n .int(3, BigInt(msg.conversationShortId))\n .int(4, BigInt(msg.serverMessageId))\n .bytes(5, msg.clientMessageId);\n for (const o of ops) target.msg(6, new Writer().int(1, o.op).bytes(2, o.key).bytes(4, own));\n return new Writer().msg(1, target).bytes(2, 'deprecated').finish();\n}\n","import { createPrivateKey, createPublicKey, sign } from 'node:crypto';\nimport type { TicketGuard } from '../models/types';\n\n/**\n * TikTok \"ticket guard\" — request signing the web client applies to `message/send` (enforced since 12/11/2026: a\n * session that sends unsigned gets its sends blocked after the first one, gateway JSON `status_code: 7`).\n *\n * At login the page generates an EC P-256 key pair, registers the public key, and the server hands back a `ticket` +\n * `ts_sign` (response header `tt-ticket-guard-server-data`). Each signed request then carries:\n *\n * req_sign = base64(DER(ECDSA-SHA256(privateKey, \"ticket=<ticket>&path=<path>&timestamp=<unix s>\")))\n * tt-ticket-guard-client-data = base64(JSON {ts_sign, req_content: \"ticket,path,timestamp\", req_sign, timestamp})\n * tt-ticket-guard-public-key = base64(uncompressed public point, 65 bytes)\n *\n * X-Gnarly / X-Dynosaur (also sent by the web client) are not required — tested 12/11/2026.\n */\n\n/** IM paths the web client signs. */\nexport const SIGNED_PATHS = new Set(['/v1/message/send']);\n\n/** Headers for one signed request. */\nexport function ticketGuardHeaders(guard: TicketGuard, path: string, now: number = Date.now()): Record<string, string> {\n const timestamp = Math.floor(now / 1000);\n const message = `ticket=${guard.ticket}&path=${path}&timestamp=${timestamp}`;\n const reqSign = sign('sha256', Buffer.from(message), createPrivateKey(guard.privateKey)).toString('base64');\n const clientData = { ts_sign: guard.tsSign, req_content: 'ticket,path,timestamp', req_sign: reqSign, timestamp };\n return {\n 'tt-ticket-guard-client-data': Buffer.from(JSON.stringify(clientData)).toString('base64'),\n 'tt-ticket-guard-public-key': publicPoint(guard.publicKey),\n 'tt-ticket-guard-version': '2',\n 'tt-ticket-guard-web-version': '1',\n 'tt-ticket-guard-iteration-version': '0',\n };\n}\n\n/** PEM public key → base64 of the uncompressed point (`04 || x || y`). */\nfunction publicPoint(pem: string): string {\n const jwk = createPublicKey(pem).export({ format: 'jwk' });\n return Buffer.concat([\n Buffer.from([4]),\n Buffer.from(jwk.x ?? '', 'base64url'),\n Buffer.from(jwk.y ?? '', 'base64url'),\n ]).toString('base64');\n}\n\n/**\n * Evaluated in a logged-in tiktok.com page: reads the security SDK's IndexedDB store (`secure-store`). The key pair is\n * stored as plain PEM; the ticket is AES-GCM encrypted with a key PBKDF2-derived from a constant\n * (`\"tt-ticket-guard-iv\"`, salt `\"secure-salt\"`). Resolves `null` until the SDK has stored a ticket.\n */\nexport const READ_TICKET_GUARD_JS = `(async () => {\n try {\n const db = await new Promise((ok, ko) => { const r = indexedDB.open('secure-store'); r.onsuccess = () => ok(r.result); r.onerror = ko; });\n if (!db.objectStoreNames.contains('cryptvalues')) return null;\n const get = (k) => new Promise((ok) => { const q = db.transaction('cryptvalues').objectStore('cryptvalues').get(k); q.onsuccess = () => ok(q.result); q.onerror = () => ok(null); });\n const keysRaw = await get('security-sdk/s_sdk_crypt_sdk');\n const signRaw = await get('security-sdk/s_sdk_sign_data_key/tt_fetch');\n if (!keysRaw || !signRaw) return null;\n const keys = JSON.parse(JSON.parse(keysRaw).data);\n const signData = JSON.parse(JSON.parse(signRaw).data);\n if (!keys.ec_privateKey || !keys.ec_publicKey || !signData.ts_sign || !signData.encrypt_ticket) return null;\n const te = new TextEncoder();\n const base = await crypto.subtle.importKey('raw', te.encode('tt-ticket-guard-iv'), 'PBKDF2', false, ['deriveKey']);\n const aes = await crypto.subtle.deriveKey({ name: 'PBKDF2', salt: te.encode('secure-salt'), iterations: 1000, hash: 'SHA-256' }, base, { name: 'AES-GCM', length: 128 }, false, ['decrypt']);\n const enc = Uint8Array.from(atob(signData.encrypt_ticket), (c) => c.charCodeAt(0));\n const ticket = new TextDecoder().decode(await crypto.subtle.decrypt({ name: 'AES-GCM', iv: enc.slice(0, 12) }, aes, enc.slice(12)));\n return { privateKey: keys.ec_privateKey, publicKey: keys.ec_publicKey, tsSign: signData.ts_sign, ticket };\n } catch (e) {\n return null;\n }\n})()`;\n\n/** Shape check for a value read back from storage / the page. */\nexport function isTicketGuard(v: unknown): v is TicketGuard {\n const g = v as Partial<TicketGuard> | null;\n return (\n !!g &&\n typeof g.privateKey === 'string' &&\n typeof g.publicKey === 'string' &&\n typeof g.tsSign === 'string' &&\n typeof g.ticket === 'string' &&\n g.ticket.length > 0\n );\n}\n","import { AID_WEB, BUILD_NUMBER, DEFAULT_USER_AGENT, IM_API, Resp, SDK_VERSION, WEB } from './constants';\nimport { TikTokError } from '../errors';\nimport { Msg, Writer } from './proto';\nimport type { CookieInput, Credentials, TicketGuard, TikTokOptions } from '../models/types';\nimport { isTicketGuard, SIGNED_PATHS, ticketGuardHeaders } from './ticket-guard';\n\n/** `name → value` cookies from any input shape of `Credentials.cookies`. */\nexport function normalizeCookies(input: Credentials['cookies']): Map<string, string> {\n const jar = new Map<string, string>();\n if (typeof input === 'string') {\n for (const part of input.split(';')) {\n const i = part.indexOf('=');\n if (i > 0) jar.set(part.slice(0, i).trim(), part.slice(i + 1).trim());\n }\n } else if (Array.isArray(input)) {\n for (const c of input as CookieInput[]) if (c?.name) jar.set(c.name, String(c.value ?? ''));\n } else {\n for (const [k, v] of Object.entries(input ?? {})) jar.set(k, String(v));\n }\n return jar;\n}\n\n/** Shared state of a session: cookies, device id, uid, HTTP calls. */\nexport class Context {\n readonly cookies: Map<string, string>;\n /**\n * IM device id = the `wid` TikTok issues for the `ttwid` cookie (`login` fetches it). The websocket only\n * accepts this id — a made-up id gets 400 (HTTP IM isn't picky).\n */\n deviceId: string;\n readonly userAgent: string;\n /** Signing material for `SIGNED_PATHS` — absent for sessions saved before 0.5.0 (sends then go unsigned). */\n readonly ticketGuard?: TicketGuard;\n ownId = '';\n private seq = 10_000;\n\n constructor(\n creds: Credentials,\n readonly options: TikTokOptions = {},\n ) {\n this.cookies = normalizeCookies(creds.cookies);\n this.deviceId = creds.deviceId ?? '';\n this.userAgent = creds.userAgent || DEFAULT_USER_AGENT;\n if (isTicketGuard(creds.ticketGuard)) this.ticketGuard = creds.ticketGuard;\n }\n\n cookieHeader(): string {\n return [...this.cookies].map(([k, v]) => `${k}=${v}`).join('; ');\n }\n\n log(level: 'debug' | 'warn', msg: string): void {\n this.options.logger?.(level, msg);\n }\n\n /** `fetch` with cookies + UA + timeout. */\n async fetch(url: string, init: RequestInit & { headers?: Record<string, string> } = {}): Promise<Response> {\n try {\n return await fetch(url, {\n ...init,\n headers: {\n 'User-Agent': this.userAgent,\n Referer: `${WEB}/`,\n Origin: WEB,\n Cookie: this.cookieHeader(),\n ...init.headers,\n },\n signal: AbortSignal.timeout(this.options.timeoutMs ?? 20_000),\n });\n } catch (err) {\n throw new TikTokError('HTTP_ERROR', `${url.split('?')[0]}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n async getJson<T>(url: string): Promise<T> {\n const res = await this.fetch(url);\n if (!res.ok) throw new TikTokError('HTTP_ERROR', `${url.split('?')[0]}: HTTP ${res.status}`, res.status);\n return (await res.json()) as T;\n }\n\n /** IM `Request` envelope: command + body + common headers. */\n buildRequest(cmd: number, bodyField: number, body: Buffer): Buffer {\n return new Writer()\n .int(1, cmd)\n .int(2, this.seq++)\n .bytes(3, SDK_VERSION)\n .bytes(4, '')\n .int(5, 3)\n .int(6, 0)\n .bytes(7, BUILD_NUMBER)\n .msg(8, new Writer().bytes(bodyField, body))\n .bytes(9, this.deviceId)\n .bytes(11, 'web')\n .map(15, {\n aid: AID_WEB,\n app_name: 'tiktok_web',\n channel: 'web',\n device_platform: 'web_pc',\n device_id: this.deviceId,\n user_is_login: 'true',\n user_agent: this.userAgent,\n })\n .int(18, 1)\n .finish();\n }\n\n /**\n * Call an IM command over HTTP. Returns the unwrapped body (`ResponseBody[cmd]`).\n * NO X-Gnarly/X-Bogus/msToken signature needed. `message/send` additionally needs the ticket-guard headers\n * (enforced 12/11/2026) — added from `ticketGuard` when present.\n */\n async im(path: string, cmd: number, body: Buffer, bodyField: number = cmd): Promise<Msg> {\n const url = `${IM_API}${path}?aid=${AID_WEB}&version_code=1.0.0&app_name=tiktok_web&device_platform=web_pc`;\n const res = await this.fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-protobuf',\n Accept: 'application/x-protobuf',\n ...(this.ticketGuard && SIGNED_PATHS.has(path) ? ticketGuardHeaders(this.ticketGuard, path) : {}),\n },\n body: new Uint8Array(this.buildRequest(cmd, bodyField, body)),\n });\n if (!res.ok) throw new TikTokError('HTTP_ERROR', `${path}: HTTP ${res.status}`, res.status);\n const raw = Buffer.from(await res.arrayBuffer());\n if (/json/i.test(res.headers.get('content-type') ?? '')) throw gatewayError(path, raw);\n const resp = Msg.tryParse(raw);\n if (!resp) throw new TikTokError('BAD_RESPONSE', `${path}: response is not protobuf`);\n const status = resp.num(Resp.status);\n if (status !== 0) {\n const desc = resp.str(Resp.error);\n // Not logged in: 200005 (tested with a cookieless request).\n const code = status === 200005 ? 'SESSION_EXPIRED' : 'IM_ERROR';\n throw new TikTokError(code, `${path}: ${status} ${desc}`.trim(), status);\n }\n return resp.msg(Resp.body)?.msg(cmd) ?? resp.msg(Resp.body)?.msg(bodyField) ?? Msg.parse(Buffer.alloc(0));\n }\n}\n\n/**\n * The gateway in front of the IM server answers with JSON (`{\"status_code\": 7, …}`) when it refuses a request before it\n * reaches IM. Observed 12/11/2026: one stored session got 7 on every `message/send` (even a garbage body) while\n * `mark_read` / `get_by_conversation` kept working; a freshly logged-in session passed — hence `SESSION_BLOCKED`.\n */\nfunction gatewayError(path: string, raw: Buffer): TikTokError {\n let status: unknown;\n try {\n status = (JSON.parse(raw.toString('utf8')) as { status_code?: unknown }).status_code;\n } catch {\n // not JSON after all\n }\n if (status === 7) return new TikTokError('SESSION_BLOCKED', `${path}: gateway status_code 7 — session blocked`, 7);\n return new TikTokError(\n 'BAD_RESPONSE',\n `${path}: gateway JSON status_code ${String(status)}`,\n typeof status === 'number' ? status : undefined,\n );\n}\n","import { API } from './api/api';\nimport { fetchAccount, fetchWebId } from './api/account';\nimport { Context } from './protocol/context';\nimport { TikTokError } from './errors';\nimport type { Credentials, TikTokOptions } from './models/types';\n\nexport class TikTok {\n constructor(private readonly options: TikTokOptions = {}) {}\n\n /** Log in with existing cookies. Expired cookies → `TikTokError('SESSION_EXPIRED')`. */\n async login(credentials: Credentials): Promise<API> {\n const ctx = new Context(credentials, this.options);\n if (!ctx.cookies.get('sessionid') && !ctx.cookies.get('sid_tt')) {\n throw new TikTokError('SESSION_EXPIRED', 'Cookie has no sessionid');\n }\n const account = await fetchAccount(ctx);\n if (!account) throw new TikTokError('SESSION_EXPIRED', 'TikTok cookie is no longer logged in');\n ctx.ownId = account.uid;\n ctx.deviceId = (await fetchWebId(ctx).catch(() => '')) || ctx.deviceId;\n if (!ctx.deviceId) throw new TikTokError('BAD_RESPONSE', 'Could not get wid (device_id) — cookie missing ttwid?');\n return new API(ctx, account);\n }\n}\n","import { rm } from 'node:fs/promises';\nimport { DEFAULT_USER_AGENT, WEB } from '../protocol/constants';\nimport { TikTokError } from '../errors';\nimport type { CookieInput, Credentials, TicketGuard } from '../models/types';\nimport { isTicketGuard, READ_TICKET_GUARD_JS } from '../protocol/ticket-guard';\nimport { openTab, type Cdp } from './cdp';\nimport { launchChrome, resolveChromePath } from './chrome';\n\n/**\n * QR login via headless Chrome.\n *\n * Why a browser: TikTok's QR API (`passport/web/check_qrconnect`) requires a JS signature\n * (X-Gnarly / msToken) — calling it bare from Node yields `error_code 7`. So we open the real\n * `tiktok.com/login/qrcode` page in headless Chrome and let it sign itself; we only LISTEN to\n * responses via CDP: the QR image from the `get_qrcode` body, the status from `check_qrconnect`.\n * After login we grab the cookies and close Chrome — everything after (`login`, chat) needs no browser.\n */\n\nexport type QrLoginEvent =\n /** New QR image (`data:image/png;base64,…`) — show it to the user to scan. A new one comes on expiry. */\n | { type: 'qr'; image: string; expiresAt: number }\n /** Scanned, waiting for confirmation on the phone. */\n | { type: 'scanned' }\n /** Confirmed — fetching cookies. */\n | { type: 'confirmed' };\n\nexport interface QrLoginOptions {\n /**\n * Path to Chrome / Chromium (e.g. `/usr/bin/chromium-browser`). Optional — when omitted, `CHROME_PATH` and the\n * usual install locations are searched.\n */\n chromePath?: string;\n onEvent?: (e: QrLoginEvent) => void;\n signal?: AbortSignal;\n /** Total time to wait for a scan (ms) — default 5 minutes. */\n timeoutMs?: number;\n /** When the QR expires (~1 minute), regenerate it at most this many times. */\n maxRefresh?: number;\n userAgent?: string;\n}\n\n/**\n * Log in to TikTok via QR. Returns `Credentials` (`.tiktok.com` cookies + UA) — pass them to\n * `new TikTok().login(creds)` and SAVE them so you don't need to scan next time.\n */\nexport async function loginQR(opts: QrLoginOptions): Promise<Credentials> {\n const userAgent = opts.userAgent || DEFAULT_USER_AGENT;\n const maxRefresh = opts.maxRefresh ?? 3;\n const { proc, ws, dir } = await launchChrome(resolveChromePath(opts.chromePath), userAgent);\n let cdp: Cdp | null = null;\n try {\n cdp = await openTab(ws);\n const tab = cdp;\n await tab.send('Network.enable');\n await tab.send('Page.enable');\n\n const result = new Promise<Credentials>((resolve, reject) => {\n const urlById = new Map<string, string>();\n let refreshes = 0;\n let scanned = false;\n let done = false;\n const finish = (err: Error | null, creds?: Credentials) => {\n if (done) return;\n done = true;\n clearTimeout(timer);\n opts.signal?.removeEventListener('abort', onAbort);\n if (err) reject(err);\n else resolve(creds!);\n };\n const timer = setTimeout(\n () => finish(new TikTokError('LOGIN_FAILED', 'Timed out waiting for QR scan')),\n opts.timeoutMs ?? 5 * 60_000,\n );\n const onAbort = () => finish(new TikTokError('LOGIN_ABORTED', 'QR login aborted'));\n opts.signal?.addEventListener('abort', onAbort);\n\n const body = async (requestId: string): Promise<{ data?: Record<string, unknown> } | null> => {\n const r = await tab\n .send<{ body: string; base64Encoded: boolean }>('Network.getResponseBody', { requestId })\n .catch(() => null);\n if (!r) return null;\n try {\n return JSON.parse(r.base64Encoded ? Buffer.from(r.body, 'base64').toString() : r.body) as {\n data?: Record<string, unknown>;\n };\n } catch {\n return null;\n }\n };\n\n /**\n * Ticket-guard signing material (needed to send since 12/11/2026). The security SDK stores it right after login;\n * if the post-login page didn't, open /messages (it signs `message/send`) and wait. `undefined` if never found.\n */\n const readTicketGuard = async (): Promise<TicketGuard | undefined> => {\n const read = async () => {\n const r = await tab\n .send<{ result?: { value?: unknown } }>('Runtime.evaluate', {\n expression: READ_TICKET_GUARD_JS,\n awaitPromise: true,\n returnByValue: true,\n })\n .catch(() => null);\n return isTicketGuard(r?.result?.value) ? r.result.value : undefined;\n };\n for (let i = 0; i < 8 && !done; i++) {\n const g = await read();\n if (g) return g;\n await new Promise((r) => setTimeout(r, 1000));\n }\n await tab.send('Page.navigate', { url: `${WEB}/messages` }).catch(() => undefined);\n for (let i = 0; i < 20 && !done; i++) {\n await new Promise((r) => setTimeout(r, 1000));\n const g = await read();\n if (g) return g;\n }\n return undefined;\n };\n\n /** After `confirmed`: the page redirects and sets session cookies — wait for `sessionid`. */\n const collectCookies = async () => {\n for (let i = 0; i < 30 && !done; i++) {\n const { cookies } = await tab.send<{ cookies: (CookieInput & { domain: string })[] }>(\n 'Network.getAllCookies',\n );\n const mine = cookies.filter((c) => c.domain.endsWith('tiktok.com'));\n if (mine.some((c) => c.name === 'sessionid' && c.value) && mine.some((c) => c.name === 'ttwid')) {\n // Same name on `.tiktok.com` and `www.tiktok.com` → keep the `.tiktok.com` one.\n const byName = new Map<string, CookieInput>();\n for (const c of mine.sort(\n (a, b) => (a.domain === '.tiktok.com' ? 1 : 0) - (b.domain === '.tiktok.com' ? 1 : 0),\n )) {\n byName.set(c.name, { name: c.name, value: c.value });\n }\n const ticketGuard = await readTicketGuard();\n return finish(null, { cookies: [...byName.values()], userAgent, ...(ticketGuard ? { ticketGuard } : {}) });\n }\n await new Promise((r) => setTimeout(r, 1000));\n }\n finish(new TikTokError('LOGIN_FAILED', 'Confirmed but no sessionid cookie found'));\n };\n\n tab.on((method, p) => {\n if (done) return;\n if (method === 'Network.responseReceived') {\n const res = p.response as { url: string };\n urlById.set(p.requestId as string, res.url);\n return;\n }\n if (method !== 'Network.loadingFinished') return;\n const url = urlById.get(p.requestId as string) ?? '';\n if (url.includes('/passport/web/get_qrcode/')) {\n void body(p.requestId as string).then((j) => {\n const qr = j?.data?.qrcode;\n if (typeof qr === 'string' && qr) {\n opts.onEvent?.({\n type: 'qr',\n image: `data:image/png;base64,${qr}`,\n expiresAt: Number(j?.data?.expire_time ?? 0) * 1000 || Date.now() + 60_000,\n });\n }\n });\n } else if (url.includes('/passport/web/check_qrconnect/')) {\n // The page polls 3 regions in parallel (sg/us/eu) — only the account's region changes status, the rest stay \"new\".\n void body(p.requestId as string).then((j) => {\n const status = String(j?.data?.status ?? '');\n if (status === 'scanned' && !scanned) {\n scanned = true;\n opts.onEvent?.({ type: 'scanned' });\n } else if (status === 'confirmed') {\n opts.onEvent?.({ type: 'confirmed' });\n void collectCookies();\n } else if (status === 'expired' && !scanned) {\n if (refreshes++ >= maxRefresh)\n finish(new TikTokError('LOGIN_FAILED', 'QR expired without being scanned'));\n else void tab.send('Page.reload');\n }\n });\n }\n });\n });\n\n await tab.send('Page.navigate', { url: `${WEB}/login/qrcode` });\n return await result;\n } finally {\n cdp?.close();\n proc.kill('SIGKILL');\n await rm(dir, { recursive: true, force: true }).catch(() => undefined);\n }\n}\n","import WebSocket from 'ws';\n\n/** Minimal Chrome DevTools Protocol client bound to one tab. */\nexport interface Cdp {\n send<T = Record<string, unknown>>(method: string, params?: object): Promise<T>;\n on(handler: (method: string, params: Record<string, unknown>) => void): void;\n close(): void;\n}\n\n/** Attach CDP to a new tab (a flat session on the browser websocket). */\nexport async function openTab(browserWs: string): Promise<Cdp> {\n const ws = new WebSocket(browserWs, { perMessageDeflate: false });\n await new Promise<void>((resolve, reject) => {\n ws.once('open', () => resolve());\n ws.once('error', reject);\n });\n let id = 0;\n // eslint-disable-next-line prefer-const -- the ws message handler reads it before Target.attachToTarget assigns it\n let sessionId: string | undefined;\n const pending = new Map<number, { resolve: (v: unknown) => void; reject: (e: Error) => void }>();\n const handlers: ((m: string, p: Record<string, unknown>) => void)[] = [];\n ws.on('message', (raw: Buffer) => {\n const m = JSON.parse(raw.toString()) as {\n id?: number;\n method?: string;\n params?: Record<string, unknown>;\n result?: unknown;\n error?: { message: string };\n sessionId?: string;\n };\n if (m.id !== undefined && pending.has(m.id)) {\n const p = pending.get(m.id)!;\n pending.delete(m.id);\n if (m.error) p.reject(new Error(m.error.message));\n else p.resolve(m.result ?? {});\n return;\n }\n if (m.method && (!m.sessionId || m.sessionId === sessionId)) for (const h of handlers) h(m.method, m.params ?? {});\n });\n const raw = <T>(method: string, params: object = {}, sid?: string): Promise<T> =>\n new Promise((resolve, reject) => {\n const i = ++id;\n pending.set(i, { resolve: resolve as (v: unknown) => void, reject });\n ws.send(JSON.stringify({ id: i, method, params, ...(sid ? { sessionId: sid } : {}) }));\n });\n const target = await raw<{ targetId: string }>('Target.createTarget', { url: 'about:blank' });\n sessionId = (await raw<{ sessionId: string }>('Target.attachToTarget', { targetId: target.targetId, flatten: true }))\n .sessionId;\n return {\n send: (method, params) => raw(method, params, sessionId),\n on: (h) => handlers.push(h),\n close: () => ws.close(),\n };\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { mkdtemp, rm } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { delimiter, join } from 'node:path';\nimport { TikTokError } from '../errors';\n\n/** Executable names looked up on `PATH` (Linux / BSD). */\nconst PATH_NAMES = ['google-chrome', 'google-chrome-stable', 'chromium', 'chromium-browser', 'chrome'];\n\n/** Well-known install locations per platform. */\nfunction knownPaths(platform: NodeJS.Platform, env: NodeJS.ProcessEnv): string[] {\n if (platform === 'darwin') {\n const apps = [\n 'Google Chrome.app/Contents/MacOS/Google Chrome',\n 'Chromium.app/Contents/MacOS/Chromium',\n 'Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',\n ];\n const roots = ['/Applications', ...(env.HOME ? [join(env.HOME, 'Applications')] : [])];\n return roots.flatMap((r) => apps.map((a) => join(r, a)));\n }\n if (platform === 'win32') {\n const roots = [env.PROGRAMFILES, env['PROGRAMFILES(X86)'], env.LOCALAPPDATA].filter((r): r is string => !!r);\n return roots.flatMap((r) => [\n join(r, 'Google', 'Chrome', 'Application', 'chrome.exe'),\n join(r, 'Chromium', 'Application', 'chrome.exe'),\n ]);\n }\n return [\n '/usr/bin/google-chrome',\n '/usr/bin/google-chrome-stable',\n '/usr/bin/chromium',\n '/usr/bin/chromium-browser',\n '/snap/bin/chromium',\n '/opt/google/chrome/chrome',\n ];\n}\n\n/**\n * Locate a Chrome / Chromium executable: `CHROME_PATH` env, then well-known install paths for the platform, then\n * `PATH`. Returns `null` when none is found.\n */\nexport function findChrome(\n env: NodeJS.ProcessEnv = process.env,\n platform: NodeJS.Platform = process.platform,\n exists: (path: string) => boolean = existsSync,\n): string | null {\n if (env.CHROME_PATH && exists(env.CHROME_PATH)) return env.CHROME_PATH;\n for (const p of knownPaths(platform, env)) if (exists(p)) return p;\n if (platform !== 'win32') {\n for (const dir of (env.PATH ?? '').split(delimiter).filter(Boolean)) {\n for (const name of PATH_NAMES) if (exists(join(dir, name))) return join(dir, name);\n }\n }\n return null;\n}\n\n/** `chromePath` if given, otherwise auto-detect — throws `LOGIN_FAILED` when nothing is found. */\nexport function resolveChromePath(chromePath?: string): string {\n if (chromePath) return chromePath;\n const found = findChrome();\n if (!found) {\n throw new TikTokError(\n 'LOGIN_FAILED',\n 'Chrome / Chromium not found — install it, set the CHROME_PATH environment variable, or pass `chromePath`',\n );\n }\n return found;\n}\n\n/** Launch headless Chrome and wait for the \"DevTools listening on ws://…\" line. */\nexport async function launchChrome(\n chromePath: string,\n userAgent: string,\n): Promise<{ proc: ChildProcess; ws: string; dir: string }> {\n const dir = await mkdtemp(join(tmpdir(), 'tca-chrome-'));\n const proc = spawn(\n chromePath,\n [\n '--headless=new',\n '--remote-debugging-port=0',\n `--user-data-dir=${dir}`,\n '--no-first-run',\n '--no-default-browser-check',\n '--disable-gpu',\n '--disable-dev-shm-usage',\n // Containers run as root — Chromium requires disabling the sandbox.\n '--no-sandbox',\n '--window-size=1280,900',\n '--lang=vi-VN',\n // The default headless UA contains \"HeadlessChrome\" — replace it with a normal UA.\n `--user-agent=${userAgent}`,\n 'about:blank',\n ],\n { stdio: ['ignore', 'ignore', 'pipe'] },\n );\n const ws = await new Promise<string>((resolve, reject) => {\n let buf = '';\n const timer = setTimeout(() => reject(new Error('Chrome did not start within 20s')), 20_000);\n proc.stderr!.on('data', (d: Buffer) => {\n buf += d.toString();\n const m = /DevTools listening on (ws:\\/\\/\\S+)/.exec(buf);\n if (m) {\n clearTimeout(timer);\n resolve(m[1]);\n }\n });\n proc.once('error', (e) => {\n clearTimeout(timer);\n reject(e);\n });\n proc.once('exit', (code) => {\n clearTimeout(timer);\n reject(new Error(`Chrome exited (${code}) before it was ready`));\n });\n }).catch(async (err: unknown) => {\n proc.kill('SIGKILL');\n await rm(dir, { recursive: true, force: true });\n throw new TikTokError(\n 'LOGIN_FAILED',\n `Failed to launch Chrome: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n return { proc, ws, dir };\n}\n"],"mappings":"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","names":["key","key","createHash","createHash","k","rm","WebSocket","raw","rm"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tca-js",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Unofficial TikTok Chat API for JavaScript — read/send TikTok direct messages (text, images, reactions) and listen over websocket using session cookies, no browser needed.",
5
5
  "license": "MIT",
6
6
  "author": "rice2411",