@ncs191655320/live
v0.4.4
Published
Agents CLI (Playwright-based) – chạy không cần .env theo mặc định; global bin: agents
Readme
AGENT-JS
Version: 0.2.6
Package: @ncs191655320/live
CLI Command: agents hoặc agents -mkt
AGENT-JS: Trình điều phối tự động hoá trình duyệt bằng Playwright (khung E2E – điều khiển Chromium/Firefox/WebKit) và kiến trúc mở để cắm Fingerprint Suite (bộ tạo & bộ tiêm fingerprint – hồ sơ trình duyệt).
Yêu cầu hệ thống
- Node.js LTS
- Windows (đường dẫn kiểu
D:\...) - Quyền ghi thư mục dự án
Cài đặt
npm install
npm run pw:installChạy chương trình
Luồng chính (ephemeral profile)
npm start
# hoặc sau khi cài global
agentsLuồng MKT Login (profile manager)
npm run start:mkt
# hoặc sau khi cài global
agents -mktChương trình sẽ hỏi đường dẫn thư mục chứa nhiều cookie.txt (định dạng Netscape cookie file – định dạng lưu cookie truyền thống). Ví dụ: D:\AZ-REFACTOR\LOGIN_LIVE\COOKIES_BULK.
Lưu ý luồng MKT:
- Yêu cầu MKT Login API đang chạy tại
http://127.0.0.1:4980 - Tự động chọn profile đầu tiên từ danh sách
- Không cần nhập workspaceId (sử dụng workspace mặc định)
Luồng xử lý
- Tạo BrowserContext bền vững mới với
userDataDirtạm (tương đương “Delete browsing data – all time”). - Sinh fingerprint profile → áp dụng Context Options +
addInitScript. - Warm-up Google (
waitUntil: networkidle, scroll nhẹ). - Tiêm cookie theo domain (
context.addCookies) và xác nhận trong jar. - Verify UI (login.live.com) + retry reload; Verify storage (portal.azure.com) qua
localStorage/sessionStorage. - Phân loại strict/normal, lưu cookie.txt vào
outputs/.
Lưu ý: Đây là luồng chính (ephemeral). Xem thêm Luồng MKT Login bên dưới.
Luồng MKT Login (v0.2.6+)
- Kết nối MKT Login API (
http://127.0.0.1:4980). - Tự động phát hiện profileId: Lấy danh sách profiles và chọn profile đầu tiên.
- Mở profile và kết nối qua CDP (Chrome DevTools Protocol).
- Tiêm fingerprint Apify: Sinh fingerprint deterministic (seed từ SHA1 của tên file cookie) và inject vào page-level.
- Warm-up → Tiêm cookies → Verify Live → Verify Azure.
- Phân loại và di chuyển file cookie như luồng chính.
- Đóng profile sau khi hoàn tất.
Quy trình phân loại & di chuyển tệp cookie
Đánh giá kết quả
- Chế độ
strict(chuẩn duy nhất): khi cả hai kiểm tra đều vượt qua:uiPassed === truevàapiPassed === true(UI + API). Lưu ý quan trọng: mọi PASS UI bắt buộc phải thu thập được email tài khoản (capturedEmail). UI pass ởverifyLive.ts(strict chain: account → email → portal), API pass ởverifyAzure.ts. - Chế độ
normal: mọi trường hợp còn lại (UI fail hoặc API fail), bao gồm cả trường hợp thiếu email (EMAIL_MISSING), OTP/MFA bắt buộc, hoặc các lỗi URL.
- Chế độ
Xử lý tệp cookie
- Đánh dấu đã xử lý: kết quả của mỗi tệp được push vào mảng
outcomesđể ghi ra báo cáo JSON cuối cùng. - Tổ chức lưu trữ đích:
- Thư mục gốc và các nhánh con được đảm bảo tồn tại khi khởi động:
artifacts/,outputs/,outputs/strict/,outputs/normal/(khởi tạo tạisrc/config.ts, hàmensureDirectories()– xemconfig.ts:237-242). - Chọn thư mục đích theo kết quả:
strictnếuuiPassed && apiPassed.normalnếu không thỏa điều kiện trên (bao gồm UI fail hoặc Azure fail, hoặc bị skip Azure do Live ở trang đăng nhập).
- Di chuyển/sao chép file: chương trình sao chép
cookie.txtvào thư mục tương ứng và lưu lại đường dẫn đích (dest) trong kết quả (thực hiện tạisrc/orchestrator/main.ts– đoạn phân loại & copy, xemmain.ts:299-307).
- Thư mục gốc và các nhánh con được đảm bảo tồn tại khi khởi động:
- Ghi báo cáo: cuối quá trình, toàn bộ
outcomesđược ghi ra file JSON trongartifacts/(xemmain.ts:314-316).
- Đánh dấu đã xử lý: kết quả của mỗi tệp được push vào mảng
Scripts
npm run build— biên dịch TypeScript.npm start— build + chạy orchestrator (luồng chính).npm run start:mkt— build + chạy orchestrator (luồng MKT Login).npm run pw:install— cài đặt trình duyệt Playwright Chromium.npm run test:e2e— chạy kiểm thử E2E cơ bản (Playwright Test).npm publish— publish gói lên npm registry.
Phase 1 – Củng cố nền tảng
- Đã dựng bộ chuẩn ESLint (trình phân tích tĩnh – enforce rule TypeScript/bảo mật) + Prettier (trình định dạng code) với script:
npm run lint/npm run lint:fixnpm run format/npm run format:fix
- Cung cấp hàm
validateEnv()tạisrc/config.tsđể kiểm tra biến môi trường bằng Zod (thư viện validate schema); mọi module có thể gọi lại để đọc cấu hình sạch. - Chuẩn hóa logging với wrapper Pino (logger hiệu năng cao) tại
src/logger.ts; các module sử dụnglogger.info/warn/error(không dùngconsole.log). - Bật các flag TypeScript nghiêm ngặt:
noImplicitAny,exactOptionalPropertyTypes,noUnusedParameters; đã xử lý cảnh báo trong toàn bộ codebase. - Cập nhật
tsconfig.eslint.jsonphục vụ ESLint với Project References. - Bổ sung tài liệu chi tiết trong
docs/de-xuat-toi-uu.mdmô tả roadmap tối ưu theo phase.
Phase 2 – Ổn định trình duyệt và DOM
- Thêm bộ helper DOM tại
src/utils/dom.tsvớigetStableLocator()(locator ổn định + timeout động) vàensureDomStable()(snapshot DOM + retry, log{ step, retryCount, message: "DOM khong on dinh" }). - Các flow (
authFlows.ts,verifyLive.ts) chuyển sang dùng helper thay vì truy cập selector trực tiếp; mọi thao tác quan trọng đều đo ổn định DOM. - Giới thiệu
ContextPool(src/browser/contextPool.ts) giới hạn đồng thời, tái sử dụngBrowserContext, tự độngcontext.clearCookies()giữa job và đóng context incognito khi cần. - Đảm bảo
ephemeralProfilevà profile tạm đều cleanup trongfinally. - Bổ sung biến môi trường điều khiển pool:
CONTEXT_MAX_CONCURRENCY,CONTEXT_REUSE,CONTEXT_CLEAR_COOKIES. - Ghi nhận metric DOM: trung bình thời gian xử lý, số lần retry → phục vụ báo cáo Phase 2.
Phase 3 – Tối ưu API & Dữ liệu
mktlogin-client/core/request.tsdùng p-retry (retry + backoff jitter) vàAbortController; log structured{ event: "api_retry", attempt, status }, timeout mặc định 15s (tùy chỉnh qua biến môi trường).ApiErrormapping giữ nguyên nhưng response được phân loại rõ ràng hơn qua logging chính xác tên lỗi, trạng thái.DataMoverrefactor sang streaming (fs.createReadStream/createWriteStream), kiểm tra checksum SHA-1 sau copy trước khi xoá nguồn.- Biến môi trường hỗ trợ Phase 3:
API_RETRY_ATTEMPTS,API_RETRY_MIN_TIMEOUT_MS,API_REQUEST_TIMEOUT_MS. - Tài liệu Phase 3 cập nhật tại
docs/de-xuat-toi-uu.md; cần chạy thử để thu thập metric retry và mức RAM.
Phase 4 – Quan sát & Kiểm thử
- Logger hỗ trợ
LOG_TRANSPORT_TARGET+LOG_TRANSPORT_OPTIONSđể chuyển log sang hệ thống quan sát (ví dụ Elastic APM) thông quapino.transport. src/utils/dom.tsphát hành metric DOM (dom_metric_snapshot) giúp dashboard hoá retry/delay.- Thêm
npm run bench(Playwright) lưu kết quả vàooutputs/benchmarks/; CI chạy benchmark nhẹ. - CI GitHub Actions (
.github/workflows/ci.yml) chạy lint → test → bench tự động. - Test bổ sung
tests/domHelpers.spec.tsđảm bảo helper DOM hoạt động ổn định. - Lưu ý: SEO lint tạm thời ở chế độ "warning only" cho các thư mục legacy (
src/browser,src/services,src/utils) trong khi dọn dẹp dần; xem runbook để biết kế hoạch làm sạch.
Cấu trúc thư mục
AGENT-JS/
package.json
tsconfig.json
.gitignore
README.md
src/
config.ts
logger.ts
utils/
cookies.ts
browser/
fingerprint.ts
launch.ts
context.ts
services/
warmup.ts
injectCookies.ts
verifyLive.ts
verifyAzure.ts
orchestrator/
main.ts
tests/
e2e.spec.ts
artifacts/
outputs/
strict/
normal/Vận hành an toàn
- Không sử dụng vào mục đích bất chính.
HEADLESScó thể bật/tắt qua biến môi trường.- Thời gian chờ/Retry có thể tinh chỉnh qua
src/config.ts.
Citations (Bằng chứng tài liệu chính thức)
Playwright — BrowserContext.addCookies
https://playwright.dev/docs/api/class-browsercontext#browser-context-add-cookies
Tóm tắt: Thêm nhiều cookie vào BrowserContext; cookie gồm name, value, domain, path, expires, httpOnly, secure, sameSite.Playwright — launchPersistentContext (Chromium)
https://playwright.dev/docs/api/class-browsertype#browser-type-launch-persistent-context
Tóm tắt: Khởi chạy context bền vững dùnguserDataDir; tạo thư mục mới tương đương hồ sơ sạch (xoá dữ liệu cũ).Playwright — page.goto (waitUntil: 'networkidle')
https://playwright.dev/docs/api/class-page#page-goto
Tóm tắt:waitUntilcó thể lànetworkidle(không còn kết nối mạng ≥ 500 ms), phù hợp để chờ trang ổn định trước thao tác.Playwright — addInitScript
https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script
Tóm tắt: Tiêm script chạy trước mọi script của trang; có thể tinh chỉnhnavigator.*ở mức JS.cURL — Netscape cookie file format
https://curl.se/docs/http-cookies.html
Tóm tắt: Định dạng “Netscape HTTP Cookie File”: domain, flag, path, secure, expiration, name, value; dòng#là comment; có tiền tố#HttpOnly_.
Assumptions & Gaps (Giả định & Khoảng trống cần đối chiếu)
- Fingerprint Suite (generator + injector): CHƯA xác minh tên gói và API chính thức trên npm. Cần chỉ định vendor + tài liệu để viết adapter thực thi thật (thay thế
generateFingerprint()và mở rộnginjectFingerprint()). - Heuristics verify login.live.com và portal.azure.com: cần bằng chứng runtime để tối ưu (URL/selector ổn định, key storage phổ biến). Hiện dùng chiến lược phòng thủ, có retry và bằng chứng ảnh.
- Môi trường Python gốc: cần cây thư mục và file nguồn (main.py, nơi xử lý cookie, trình duyệt) để so khớp 1-1.
- Chính sách bảo mật/tốc độ: có thể cần điều chỉnh timeout và
MIN_LS_KEYStheo mạng/tài khoản thực tế.
Kiểm thử
npm run test:e2eGóp ý & mở rộng
- Có thể mở rộng module fingerprint để cắm vendor chính thức khi có tài liệu.
- Bổ sung lưu HAR và thêm báo cáo chi tiết nếu cần.
Cấu hình Azure (verifyAzure)
- Biến môi trường quan trọng (xem ánh xạ trong
src/config.ts):AZURE_REQUIRE_USERID_STRICT(mặc địnhtrue) — siết chặt: bắt buộc cóuserIdhợp lệ kể cả khi cógithub(tham chiếusrc/config.ts:74-76,src/config.ts:243-245).STORAGE_RETRIES(mặc định2) — số lần thử lại khi kiểm tra storage (tham chiếusrc/config.ts:240-241, dùng trongverifyAzure.ts:51-56).STORAGE_BACKOFF_MS(mặc định2000) — thời gian chờ giữa các lần thử (tham chiếusrc/config.ts:240-241, dùng trongverifyAzure.ts:51-56).STORAGE_REQUIRE_LOCAL_ONLY(mặc địnhtrue) — gate readiness ưu tiênlocalStorage(tham chiếusrc/config.ts:239-241, dùng trongverifyAzure.ts:51-76).STORAGE_WAIT_PATTERNS— danh sách pattern chờ key xuất hiện (ví dụ:sessionTracking_,msal.account.keys) (tham chiếusrc/config.ts:219-224, dùng trongverifyAzure.ts:51-76).STORAGE_VERIFY_WRITE— probe ghi thử (none|sessionOnly|localPreferred) (tham chiếusrc/config.ts:226-231, dùng trongverifyAzure.ts:51-76).STORAGE_MIN_KEYS— ngưỡng tối thiểu key để pass về mặt số lượng (tham chiếusrc/config.ts:225-226, dùng trongverifyAzure.tsqua tham sốminLocalStorageKeys).
Quy trình verifyAzure (tóm tắt kỹ thuật)
- Mở
https://portal.azure.comvà ổn định trang:stabilizePage(...)(tham chiếusrc/services/verifyAzure.ts:48-49). - Vòng lặp kiểm tra readiness + refresh/backoff theo config (tham chiếu
src/services/verifyAzure.ts:51-93):checkStorageReady()gate trước khi đọc chi tiết (tham chiếusrc/utils/checkStorageReady.ts:10-21,34-44,146-183).- Trước lượt cuối:
page.reload()để phục hồi nếu cần (tham chiếusrc/services/verifyAzure.ts:83-88).
- Đọc bằng chứng storage:
readAzureStorage()(tham chiếusrc/utils/storage_scripts.ts) và đánh giá tiêu chí pass/fail (tham chiếusrc/services/verifyAzure.ts:95-123). - Ghi ảnh
azure-*.pngvà artifact chi tiếtazure-detail-*.json(tham chiếusrc/services/verifyAzure.ts:126-142).
Tiêu chí pass (điều kiện đầy đủ):
- Số key
localStorage≥STORAGE_MIN_KEYSVÀ - Có đầy đủ nhóm key bắt buộc
userId,displayName,domainName,emailHOẶC có keygithubVÀ userIdhợp lệ theo cấu hình siết chặt (khiAZURE_REQUIRE_USERID_STRICT=true, luôn bắt buộcuserIdhợp lệ; tham chiếusrc/services/verifyAzure.ts:108-112).
Reason codes (Azure)
OK— đạt tiêu chí pass (tham chiếusrc/types/resultCodes.ts:15).STORAGE_UNAVAILABLE— không truy cập được Web Storage (gate readiness fail) (tham chiếusrc/types/resultCodes.ts:16).STORAGE_INSUFFICIENT— đếm không đủ key hoặc thiếu các key bắt buộc (tham chiếusrc/types/resultCodes.ts:17).RETRY_EXCEEDED— hết số lần thử mà vẫn không đạt (tham chiếusrc/types/resultCodes.ts:18).RETRIED_REFRESH_RECOVERED— hồi phục sau khi refresh (tham chiếusrc/types/resultCodes.ts:19).INTERNAL_ERROR— lỗi evaluate/ngoại lệ (tham chiếusrc/types/resultCodes.ts:20).UNKNOWN— dự phòng (tham chiếusrc/types/resultCodes.ts:21).
Artifact chi tiết (azure-detail-*.json)
- Ghi tại thư mục
artifacts/mỗi lần verify Azure (tham chiếusrc/services/verifyAzure.ts:130-142). - Trường dữ liệu chính:
url,attempts,refreshed,ready,reasonCode,apiPassed.evidence: snapshot storage (đã ẩn giá trị PII — xemsampletrongsrc/utils/storage_scripts.ts).
Chuẩn xác thực tài khoản (strict only) – login.live.com → portal.azure.com
- Nguyên tắc bất di bất dịch: PASS UI chỉ hợp lệ khi đã thu thập được email tài khoản (capturedEmail) sau khi vào account.* và trước/đồng thời khi vào portal.
- Sau khi điều hướng đến
login.live.comvà ổn định lần đầu:- Nếu URL vẫn là trang đăng nhập (LOGIN_PAGE) → FAIL sớm.
- Nếu phát hiện OTP/MFA → FAIL với
OTP_REQUIRED/MFA_REQUIRED. - Nếu gặp passkey prompt → cố gắng bỏ qua (handlePasskeyInterrupt) và tiếp tục.
- Chuỗi strict:
- Vào
account.*→ thu thập email (qua/me, JWT cookies, URL param dev, hoặc Web Storage vớicheckStorageReadysiết ổn định tên keys). - Điều hướng/ở
portal.azure.com→ điền email + Next → safe-load → ổn định thích ứng. - Kiểm tra OTP/MFA sau khi nhập email.
- Nếu có
capturedEmailvà không gặp OTP/MFA → PASSOK_STRICT_CHAIN.
- Vào
Tăng cường độ tin cậy thu thập email (Web Storage)
getEmailFromWebStorage(...)chỉ chạy khicheckStorageReady(...)đạt sẵn sàng với ổn định tên keys (names stability):- Bật
requireStableNames=truevà yêu cầuconsistencyPasses ≥ 2(mặc định 2) vớiscanIntervalMshợp lý (mặc định 200 ms). - Nếu readiness không đạt, hàm dừng (return null), KHÔNG quét best‑effort.
- Bật
- Điều này giảm false‑positive và đảm bảo email được lấy khi storage đã “ổn định”.
Adaptive stabilization – Hướng dẫn đọc thống kê & checklist debug
Mục này giúp đọc nhanh thống kê ổn định thích ứng (AdaptiveStat) và xử lý khi ready=false mà không cần tăng timeout.
AdaptiveStat gồm những gì
- label: nhãn của lần đo (ví dụ:
verifyLive-adaptive,verifyLive-portalNav-adaptive,verifyAzure-adaptive). Gán nhãn tạisrc/services/verifyLive.tsquanh các lần push thống kê. - scans: số vòng quét DOM/console trong nhịp; xấp xỉ
durationMs / scanIntervalMs(tham số ởsrc/config.ts– runtime mappingadaptiveScanIntervalMsLive/Azure). - durationMs: thời lượng của nhịp (ms); bị chặn bởi
maxDurationMs(ví dụ Live đặtMath.min(safeWaitMs, 4000)tạisrc/services/verifyLive.ts). - firstStableAtMs: thời điểm lần đầu đạt trạng thái ổn định trong nhịp; có thể rỗng nếu không ổn định.
- ready: true nếu điều kiện ổn định thỏa trong nhịp; false nếu hết thời lượng mà chưa đạt.
- phase: pha nhận diện được (ví dụ
PRE,POST, hoặcNONE). - passes: số lần liên tiếp thỏa điều kiện trong nhịp (chống nhiễu); trần bởi
consecutivePasses(src/config.ts– runtime mappingadaptiveConsecPassesLive/Azure).
Quy tắc quyết định từ SELECTORS (pre/post)
- Any-Of: trong mỗi tập
preSelectorsvàpostSelectors, chỉ cần tìm thấy 1 selector đáng tin là coi như “match” cho nhãn tương ứng; sau đó cần đạt liên tiếpconsecutivePassesđể kết luận “ready”. - Nguồn cấu hình: selector nạp từ
config.livePreSelectorsvàconfig.livePostSelectors(mặc định đã ghim trongsrc/config.ts). Ở runtime được dùng tạisrc/services/verifyLive.ts:392-399. - Ưu tiên: tập POST nên ưu tiên selector shell ổn định của Azure Portal:
div.fxs-portal,#shell-header,#appBar,div.fxs-topbar,nav.fxs-sidebar,div.fxs-avatarmenu,div.fxs-blade-content.
Checklist khi ready=false
- Selector – kiểm tính phù hợp
- Xác nhận selector POST thực sự xuất hiện trên tenant: kiểm nhanh bằng
page.$(selector)hoặc thêm log. - Điều chỉnh danh sách POST (giữ 5–7 selector “nòng cốt”) trong
src/config.tsđể tăng xác suất match sớm, không cần tăng timeout.
- Xác nhận selector POST thực sự xuất hiện trên tenant: kiểm nhanh bằng
- URL guard – đúng đích portal
- Điều hướng HTTPS trực tiếp
https://portal.azure.comvà ép#homekhi cần (xemsrc/services/verifyAzure.ts). - Sau mỗi
goto()/reload()có guard “chrome-error bounce” để phục hồi (xemsrc/services/verifyAzure.tsvàsrc/services/verifyLive.ts).
- Điều hướng HTTPS trực tiếp
- Service Worker/Network – giảm nhiễu
- Bật CDP
Network.enable+Network.setBypassServiceWorker({ bypass: true })ngay sau khi cópage(xemsrc/services/verifyLive.ts,src/services/verifyAzure.ts).
- Bật CDP
- Storage readiness – Azure
- Dùng
checkStorageReady()để gate trước khi đọc chi tiết (gọi trongsrc/services/verifyAzure.ts). - Ngưỡng đếm và yêu cầu keys cấu hình ở
src/config.ts(nhómSTORAGE_*).
- Dùng
- Consecutive passes – chống nhiễu
- Nếu selector đúng nhưng vẫn nhiễu, có thể tăng nhẹ
ADAPTIVE_CONSEC_PASSES_*(không cần tăng timeout) trongsrc/config.ts.
- Nếu selector đúng nhưng vẫn nhiễu, có thể tăng nhẹ
- Ảnh chứng cứ
- Chức năng chụp ảnh đã vô hiệu hóa trong mã; hãy dựa vào log và artifact JSON.
Đoạn kiểm thử nhanh selector (TypeScript)
// Chạy sau khi điều hướng portal để kiểm xem selector shell có xuất hiện hay không
const candidates = [
'div.fxs-portal', '#shell-header', '#appBar',
'div.fxs-topbar', 'nav.fxs-sidebar', 'div.fxs-avatarmenu',
'div.fxs-blade-content'
];
for (const sel of candidates) {
const ok = !!(await page.$(sel));
console.log({ sel, ok });
}Nếu nhiều selector phía trên trả về ok=true, hãy giữ chúng trong LIVE_POST_SELECTORS để adaptive “ready” sớm hơn mà không cần tăng thời gian chờ.
Quy tắc xử lý (STRICT ONLY – account → email → portal):
LOGIN_PAGE hoặc OTP/MFA →
uiPassed=false(failCode:LOGIN_PAGE|OTP_REQUIRED|MFA_REQUIRED|MFA_PUSH_NOTIFICATION_REQUIRED).MFA_PUSH_NOTIFICATION_REQUIRED: Màn hình "Get a code to sign in" + nút "Send notification" yêu cầu xác thực qua push notification đến thiết bị di động → không thể tự động bypass.
ERROR_URL → tiếp tục retry trong giới hạn; nếu vẫn lỗi →
uiPassed=false(ERROR_URL).- Nếu gặp passkey: dùng
handlePasskeyInterruptđể bỏ qua rồi tiếp tục quy trình. - Không dùng
OK_LOGGED_INđể PASS; đây chỉ là trạng thái tham chiếu.
- Nếu gặp passkey: dùng
Ở portal.azure.com và đã nhập email:
- Chỉ FAIL bởi OTP/MFA sau khi nhập email.
- PASS chỉ khi đã thu thập được email (capturedEmail) và không gặp OTP/MFA →
reasonCode = OK_STRICT_CHAIN,uiPassed=true. - Hậu kiểm: nếu
uiPassed=truenhưng thiếu email → ép FAILEMAIL_MISSING.
điều chỉnh thêm trường hợp Ở portal.azure.com và đã nhập email:
- Chỉ FAIL bởi OTP/MFA sau khi nhập email.
- ERROR_URL → sau khi nhập email tiếp tục retry trong giới hạn 2 lần; nếu vẫn lỗi →
uiPassed=false(ERROR_URL). - PASS chỉ khi đã thu thập được email (capturedEmail) và không gặp OTP/MFA →
reasonCode = OK_STRICT_CHAIN,uiPassed=true. - Hậu kiểm: nếu
uiPassed=truenhưng thiếu email → ép FAILEMAIL_MISSING.
