tca-js 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/qr-login.js CHANGED
@@ -11,7 +11,7 @@ const node_path_1 = require("node:path");
11
11
  const ws_1 = __importDefault(require("ws"));
12
12
  const constants_1 = require("./constants");
13
13
  const errors_1 = require("./errors");
14
- /** Nối CDP vào một tab mới (một session phẳng trên websocket của trình duyệt). */
14
+ /** Attach CDP to a new tab (a flat session on the browser websocket). */
15
15
  async function openTab(browserWs) {
16
16
  const ws = new ws_1.default(browserWs, { perMessageDeflate: false });
17
17
  await new Promise((resolve, reject) => {
@@ -50,7 +50,7 @@ async function openTab(browserWs) {
50
50
  close: () => ws.close(),
51
51
  };
52
52
  }
53
- /** Chạy Chrome headless, chờ dòng "DevTools listening on ws://…". */
53
+ /** Launch headless Chrome and wait for the "DevTools listening on ws://…" line. */
54
54
  async function launchChrome(chromePath, userAgent) {
55
55
  const dir = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'tca-chrome-'));
56
56
  const proc = (0, node_child_process_1.spawn)(chromePath, [
@@ -61,17 +61,17 @@ async function launchChrome(chromePath, userAgent) {
61
61
  '--no-default-browser-check',
62
62
  '--disable-gpu',
63
63
  '--disable-dev-shm-usage',
64
- // Trong container chạy root — Chromium đòi tắt sandbox.
64
+ // Containers run as root — Chromium requires disabling the sandbox.
65
65
  '--no-sandbox',
66
66
  '--window-size=1280,900',
67
67
  '--lang=vi-VN',
68
- // UA mặc định của headless có chữ "HeadlessChrome" — thay bằng UA thường.
68
+ // The default headless UA contains "HeadlessChrome" — replace it with a normal UA.
69
69
  `--user-agent=${userAgent}`,
70
70
  'about:blank',
71
71
  ], { stdio: ['ignore', 'ignore', 'pipe'] });
72
72
  const ws = await new Promise((resolve, reject) => {
73
73
  let buf = '';
74
- const timer = setTimeout(() => reject(new Error('Chrome không khởi động sau 20s')), 20_000);
74
+ const timer = setTimeout(() => reject(new Error('Chrome did not start within 20s')), 20_000);
75
75
  proc.stderr.on('data', (d) => {
76
76
  buf += d.toString();
77
77
  const m = /DevTools listening on (ws:\/\/\S+)/.exec(buf);
@@ -86,18 +86,18 @@ async function launchChrome(chromePath, userAgent) {
86
86
  });
87
87
  proc.once('exit', (code) => {
88
88
  clearTimeout(timer);
89
- reject(new Error(`Chrome thoát (${code}) trước khi sẵn sàng`));
89
+ reject(new Error(`Chrome exited (${code}) before it was ready`));
90
90
  });
91
91
  }).catch(async (err) => {
92
92
  proc.kill('SIGKILL');
93
93
  await (0, promises_1.rm)(dir, { recursive: true, force: true });
94
- throw new errors_1.TikTokError('LOGIN_FAILED', `Không mở được Chrome: ${err instanceof Error ? err.message : String(err)}`);
94
+ throw new errors_1.TikTokError('LOGIN_FAILED', `Failed to launch Chrome: ${err instanceof Error ? err.message : String(err)}`);
95
95
  });
96
96
  return { proc, ws, dir };
97
97
  }
98
98
  /**
99
- * Đăng nhập TikTok bằng QR. Trả `Credentials` (cookie `.tiktok.com` + UA) — đưa vào
100
- * `new TikTok().login(creds)` và LƯU LẠI để lần sau khỏi quét.
99
+ * Log in to TikTok via QR. Returns `Credentials` (`.tiktok.com` cookies + UA) — pass them to
100
+ * `new TikTok().login(creds)` and SAVE them so you don't need to scan next time.
101
101
  */
102
102
  async function loginQR(opts) {
103
103
  const userAgent = opts.userAgent || constants_1.DEFAULT_USER_AGENT;
@@ -125,8 +125,8 @@ async function loginQR(opts) {
125
125
  else
126
126
  resolve(creds);
127
127
  };
128
- const timer = setTimeout(() => finish(new errors_1.TikTokError('LOGIN_FAILED', 'Hết thời gian chờ quét QR')), opts.timeoutMs ?? 5 * 60_000);
129
- const onAbort = () => finish(new errors_1.TikTokError('LOGIN_ABORTED', 'Đã huỷ đăng nhập QR'));
128
+ const timer = setTimeout(() => finish(new errors_1.TikTokError('LOGIN_FAILED', 'Timed out waiting for QR scan')), opts.timeoutMs ?? 5 * 60_000);
129
+ const onAbort = () => finish(new errors_1.TikTokError('LOGIN_ABORTED', 'QR login aborted'));
130
130
  opts.signal?.addEventListener('abort', onAbort);
131
131
  const body = async (requestId) => {
132
132
  const r = await tab.send('Network.getResponseBody', { requestId }).catch(() => null);
@@ -139,13 +139,13 @@ async function loginQR(opts) {
139
139
  return null;
140
140
  }
141
141
  };
142
- /** Sau `confirmed`: trang tự chuyển hướng + đặt cookie phiên — chờ có `sessionid`. */
142
+ /** After `confirmed`: the page redirects and sets session cookies — wait for `sessionid`. */
143
143
  const collectCookies = async () => {
144
144
  for (let i = 0; i < 30 && !done; i++) {
145
145
  const { cookies } = await tab.send('Network.getAllCookies');
146
146
  const mine = cookies.filter((c) => c.domain.endsWith('tiktok.com'));
147
147
  if (mine.some((c) => c.name === 'sessionid' && c.value) && mine.some((c) => c.name === 'ttwid')) {
148
- // Trùng tên ở `.tiktok.com` và `www.tiktok.com` → giữ bản `.tiktok.com`.
148
+ // Same name on `.tiktok.com` and `www.tiktok.com` → keep the `.tiktok.com` one.
149
149
  const byName = new Map();
150
150
  for (const c of mine.sort((a, b) => (a.domain === '.tiktok.com' ? 1 : 0) - (b.domain === '.tiktok.com' ? 1 : 0))) {
151
151
  byName.set(c.name, { name: c.name, value: c.value });
@@ -154,7 +154,7 @@ async function loginQR(opts) {
154
154
  }
155
155
  await new Promise((r) => setTimeout(r, 1000));
156
156
  }
157
- finish(new errors_1.TikTokError('LOGIN_FAILED', 'Đã xác nhận nhưng không thấy cookie sessionid'));
157
+ finish(new errors_1.TikTokError('LOGIN_FAILED', 'Confirmed but no sessionid cookie found'));
158
158
  };
159
159
  tab.on((method, p) => {
160
160
  if (done)
@@ -180,7 +180,7 @@ async function loginQR(opts) {
180
180
  });
181
181
  }
182
182
  else if (url.includes('/passport/web/check_qrconnect/')) {
183
- // Trang hỏi song song 3 vùng (sg/us/eu) — chỉ vùng của tài khoản đổi trạng thái, còn lại vẫn "new".
183
+ // The page polls 3 regions in parallel (sg/us/eu) — only the account's region changes status, the rest stay "new".
184
184
  void body(p.requestId).then((j) => {
185
185
  const status = String(j?.data?.status ?? '');
186
186
  if (status === 'scanned' && !scanned) {
@@ -193,7 +193,7 @@ async function loginQR(opts) {
193
193
  }
194
194
  else if (status === 'expired' && !scanned) {
195
195
  if (refreshes++ >= maxRefresh)
196
- finish(new errors_1.TikTokError('LOGIN_FAILED', 'QR hết hạn, không ai quét'));
196
+ finish(new errors_1.TikTokError('LOGIN_FAILED', 'QR expired without being scanned'));
197
197
  else
198
198
  void tab.send('Page.reload');
199
199
  }
package/dist/types.d.ts CHANGED
@@ -1,87 +1,87 @@
1
- /** Một cookie — đúng dạng `chrome.cookies.getAll` / CDP `Storage.getCookies` trả về (thừa trường không sao). */
1
+ /** A cookie — same shape as `chrome.cookies.getAll` / CDP `Storage.getCookies` returns (extra fields are fine). */
2
2
  export interface CookieInput {
3
3
  name: string;
4
4
  value: string;
5
5
  }
6
- /** Thứ cần để đăng nhập lại — lưu lại sau mỗi lần đăng nhập, như `{cookie, imei, userAgent}` của zca-js. */
6
+ /** What you need to log in again — save it after each login. */
7
7
  export interface Credentials {
8
- /** Cookie của `.tiktok.com`: mảng `{name, value}`, object `{name: value}`, hoặc chuỗi `a=b; c=d`. */
8
+ /** `.tiktok.com` cookies: array of `{name, value}`, object `{name: value}`, or string `a=b; c=d`. */
9
9
  cookies: CookieInput[] | Record<string, string> | string;
10
- /** Mã máy IM (`wid`) — bỏ trống thì `login` hỏi TikTok theo `ttwid`. Chỉ dùng khi không hỏi được. */
10
+ /** IM device id (`wid`) — leave empty and `login` asks TikTok using `ttwid`. Only used when that fails. */
11
11
  deviceId?: string;
12
12
  userAgent?: string;
13
13
  }
14
14
  export interface TikTokOptions {
15
- /** Ghi log gỡ lỗi — mặc định im lặng. */
15
+ /** Debug logging — silent by default. */
16
16
  logger?: (level: 'debug' | 'warn', msg: string) => void;
17
- /** Hạn chờ mỗi request HTTP (ms). */
17
+ /** Timeout per HTTP request (ms). */
18
18
  timeoutMs?: number;
19
19
  }
20
- /** Đủ để nhắm một hội thoại: gửi tin, đọc tin, đánh dấu đã đọc. Mọi `TikTokMessage` đều thoả. */
20
+ /** Enough to target a conversation: send, read, mark as read. Every `TikTokMessage` satisfies it. */
21
21
  export interface ConversationRef {
22
22
  conversationId: string;
23
23
  conversationShortId: string;
24
24
  }
25
25
  export interface TikTokImage {
26
- /** Mã ảnh trên kho TikTok (đã mã hoá). */
26
+ /** Image id in TikTok storage (encrypted). */
27
27
  uri: string;
28
- /** Link tải bản gốc — cần cookie, nội dung là AES-256-GCM. */
28
+ /** Original download link — needs cookies, content is AES-256-GCM. */
29
29
  url: string;
30
30
  thumbUrl: string;
31
31
  width: number;
32
32
  height: number;
33
- /** Khoá AES-256-GCM (hex) để giải `url` — `api.downloadImage` lo việc này. */
33
+ /** AES-256-GCM key (hex) to decrypt `url` — `api.downloadImage` handles this. */
34
34
  decryptKey: string;
35
35
  }
36
- /** Sticker (nhãn dán) — kể cả sticker khách tự tạo (`stickerType` 15). Link CDN công khai, có chữ ký + hạn vài ngày. */
36
+ /** Sticker — including user-made stickers (`stickerType` 15). Public CDN link, signed + expires in a few days. */
37
37
  export interface TikTokSticker {
38
38
  stickerId: string;
39
- /** 14 = sticker có sẵn của TikTok, 15 = sticker người dùng tự tạo (ảnh chế, AI…). */
39
+ /** 14 = built-in TikTok sticker, 15 = user-made sticker (memes, AI…). */
40
40
  stickerType: number;
41
41
  url: string;
42
42
  width: number;
43
43
  height: number;
44
44
  }
45
- /** Một reaction trên tin: emoji + những người đã thả (uid). `e:love` của app điện thoại đã gộp vào ❤️. */
45
+ /** A reaction on a message: emoji + users who reacted (uid). The mobile app's `e:love` is merged into ❤️. */
46
46
  export interface TikTokReaction {
47
47
  emoji: string;
48
48
  userIds: string[];
49
49
  }
50
50
  export interface TikTokMessage extends ConversationRef {
51
51
  serverMessageId: string;
52
- /** Vị trí trong hội thoại (µs) — làm mốc đọc tiếp tin cũ hơn. */
52
+ /** Position in the conversation (µs) — cursor for paging older messages. */
53
53
  index: string;
54
- /** `MessageType` — 7 chữ, 1802 ảnh, 1805 sticker, 8 chia sẻ video, 1 hệ thống. */
54
+ /** `MessageType` — 7 text, 1802 image, 1805 sticker, 8 video share, 1 system. */
55
55
  type: number;
56
- /** `command` = lệnh ẩn (đã đọc…) — listener phát qua sự kiện `command`, không qua `message`. */
56
+ /** `command` = hidden command (read receipt…) — listener emits it via the `command` event, not `message`. */
57
57
  kind: 'text' | 'image' | 'sticker' | 'video' | 'system' | 'command' | 'other';
58
58
  senderId: string;
59
59
  isSelf: boolean;
60
- /** Nội dung chữ (`kind = text`), rỗng với loại khác. */
60
+ /** Text content (`kind = text`), empty for other kinds. */
61
61
  text: string;
62
62
  image: TikTokImage | null;
63
63
  sticker: TikTokSticker | null;
64
64
  reactions: TikTokReaction[];
65
- /** JSON thô của nội dung (`{"aweType":0,"text":"…"}`…). */
65
+ /** Raw JSON content (`{"aweType":0,"text":"…"}`…). */
66
66
  content: unknown;
67
- /** Giờ gửi, ms epoch. */
67
+ /** Send time, ms epoch. */
68
68
  createdAt: number;
69
69
  clientMessageId: string;
70
70
  ext: Record<string, string>;
71
71
  }
72
72
  export interface TikTokConversation extends ConversationRef {
73
73
  participants: string[];
74
- /** Người còn lại trong hội thoại 1-1. */
74
+ /** The other participant in a 1-1 conversation. */
75
75
  peerId: string;
76
76
  }
77
77
  export interface TikTokUser {
78
78
  uid: string;
79
- /** `@username` (không có @). */
79
+ /** `@username` (without @). */
80
80
  uniqueId: string;
81
81
  nickname: string;
82
- /** Ảnh đại diện tốt nhất (ưu tiên jpeg/webp/png, tránh heic trình duyệt không đọc). */
82
+ /** Best avatar (prefers jpeg/webp/png, avoids heic which browsers can't read). */
83
83
  avatar: string;
84
- /** Mọi link ảnh đại diện TikTok trả, xếp theo ưu tiên — link có chữ ký, có hạn; `downloadAvatar` thử lần lượt. */
84
+ /** All avatar links TikTok returns, by priority — signed, expiring links; `downloadAvatar` tries them in order. */
85
85
  avatars: string[];
86
86
  }
87
87
  export interface TikTokAccount {
@@ -90,10 +90,10 @@ export interface TikTokAccount {
90
90
  screenName: string;
91
91
  avatar: string;
92
92
  }
93
- /** File đính kèm — giống `attachments` của zca-js. */
93
+ /** Image attachment. */
94
94
  export interface ImageInput {
95
95
  data: Buffer;
96
- /** Chỉ cần đuôi để TikTok biết định dạng: `anh.jpg`, `bill.png`. */
96
+ /** Only the extension matters so TikTok knows the format: `photo.jpg`, `bill.png`. */
97
97
  filename: string;
98
98
  }
99
99
  export interface MessagePage {
@@ -102,7 +102,7 @@ export interface MessagePage {
102
102
  }
103
103
  export interface ConversationPage {
104
104
  conversations: TikTokConversation[];
105
- /** Tin mới nhất kèm theo — tiện dựng danh sách hộp thư. */
105
+ /** Latest messages included — handy for building an inbox list. */
106
106
  messages: TikTokMessage[];
107
107
  cursor: string;
108
108
  hasMore: boolean;
package/package.json CHANGED
@@ -1,17 +1,35 @@
1
1
  {
2
2
  "name": "tca-js",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
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",
7
- "repository": { "type": "git", "url": "git+https://github.com/rice2411/tca-js.git" },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/rice2411/tca-js.git"
10
+ },
8
11
  "homepage": "https://github.com/rice2411/tca-js#readme",
9
- "bugs": { "url": "https://github.com/rice2411/tca-js/issues" },
10
- "keywords": ["tiktok", "tiktok-api", "tiktok-dm", "tiktok-chat", "direct-message", "unofficial", "chat", "websocket", "zca-js"],
12
+ "bugs": {
13
+ "url": "https://github.com/rice2411/tca-js/issues"
14
+ },
15
+ "keywords": [
16
+ "tiktok",
17
+ "tiktok-api",
18
+ "tiktok-dm",
19
+ "tiktok-chat",
20
+ "direct-message",
21
+ "unofficial",
22
+ "chat",
23
+ "websocket"
24
+ ],
11
25
  "main": "./dist/index.js",
12
26
  "types": "./dist/index.d.ts",
13
- "files": ["dist"],
14
- "engines": { "node": ">=22" },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "engines": {
31
+ "node": ">=22"
32
+ },
15
33
  "scripts": {
16
34
  "build": "rm -rf dist && tsc -p tsconfig.json",
17
35
  "prepublishOnly": "npm run build",