#!/usr/bin/env node const LOGIN_URL = 'https://api.atuchat.com/e64f27b9ba6b37881120f4584a5444a5c684d8491b703d0af953e5cc6a5f4cec' const account = process.env.ASLAN_ACCOUNT || '6666' const password = process.env.ASLAN_PASSWORD || '123456' const targetUrl = process.env.ASLAN_URL || 'https://h5.atuchat.com/#/admin-center?lang=en' const chromePath = process.env.CHROME_PATH || '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' const headless = process.env.ASLAN_HEADLESS === '1' const exitAfterLoad = process.env.ASLAN_EXIT_AFTER_LOAD === '1' async function loadPlaywright() { try { return await import('playwright') } catch { return await import( '/Users/hy/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright/index.mjs' ) } } function appHeaders(imei = 'aslan-webview-sim') { return { 'req-lang': 'en', 'X-Forwarded-Proto': 'http', 'User-Agent': 'Dart/3.7.2 (dart:io)', 'req-imei': imei, 'req-app-intel': 'version=1.0.0;build=1;model=CodexWebView;sysVersion=1;channel=Google', 'req-client': 'Android', 'req-sys-origin': 'origin=ATYOU;originChild=ATYOU', 'Req-Atyou': 'true', } } function publicUserProfile(profile = {}) { return { id: profile.id || profile.userId, account: profile.account, specialAccount: profile.ownSpecialId?.account, userNickname: profile.userNickname, countryName: profile.countryName, originSys: profile.originSys || profile.sysOrigin, sysOriginChild: profile.sysOriginChild, } } async function login() { const response = await fetch(LOGIN_URL, { method: 'POST', headers: { ...appHeaders('aslan-webview-sim-login'), 'content-type': 'application/json', }, body: JSON.stringify({ account, pwd: password }), }) const data = await response.json() if (!response.ok || !data.status || !data.body?.token) { const error = { httpStatus: response.status, status: data.status, errorCode: data.errorCode, errorMsg: data.errorMsg, } throw new Error(`Aslan login failed: ${JSON.stringify(error)}`) } return data.body } async function main() { const auth = await login() const profile = auth.userProfile || {} const { chromium } = await loadPlaywright() const browser = await chromium.launch({ headless, executablePath: chromePath, args: ['--no-sandbox'], }) const context = await browser.newContext({ viewport: { width: 390, height: 844 }, isMobile: true, hasTouch: true, userAgent: 'Mozilla/5.0 (Linux; Android 12; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36', }) await context.addInitScript( ({ token, profile }) => { window.__aslanWebViewMessages = [] const postBridgeMessage = (message) => { const text = String(message) window.__aslanWebViewMessages.push(text) console.info(`[AslanWebViewSim] FlutterPageControl.postMessage: ${text}`) } window.FlutterPageControl = { postMessage: postBridgeMessage, } window.app = { getAccessOrigin: () => JSON.stringify({ Authorization: `Bearer ${token}`, 'Req-Lang': 'en', 'Req-App-Intel': 'build=1;version=1.0.0;model=CodexWebView;channel=Google;Req-Imei=aslan-webview-sim', 'Req-Sys-Origin': 'origin=ATYOU;originChild=ATYOU', }), closePage: () => postBridgeMessage('close_page'), back: () => history.back(), gotoRoom: (roomId) => postBridgeMessage(`go_to_room:${roomId}`), gotoPrivateChat: (userId) => postBridgeMessage(`private_chat:${userId}`), openUserInfo: (userId) => postBridgeMessage(`view_user_info:${userId}`), gotoAppPage: (pageName) => postBridgeMessage(pageName), goToFlutterPage: (pageName) => postBridgeMessage(pageName), uploadImgFile: () => postBridgeMessage('uploadImgFile'), } try { localStorage.setItem('userProfile', JSON.stringify(profile)) } catch {} }, { token: auth.token, profile }, ) const page = await context.newPage() page.on('console', (msg) => { const text = msg.text() if ( text.includes('[AslanWebViewSim]') || /error|warn|Route|Permission|APP|Failed|identity/i.test(text) ) { console.log(`[browser:${msg.type()}] ${text}`) } }) page.on('pageerror', (error) => { console.log(`[browser:pageerror] ${error.message}`) }) console.log('Aslan WebView simulator started') console.log(`account=${account}`) console.log(`profile=${JSON.stringify(publicUserProfile(profile))}`) console.log(`url=${targetUrl}`) console.log('Close the Chrome window to stop the simulator.') await page.goto(targetUrl, { waitUntil: 'domcontentloaded', timeout: 45_000 }) if (exitAfterLoad) { await page.waitForTimeout(6_000) const state = await page.evaluate(() => ({ href: location.href, text: (document.body?.innerText || '').replace(/\s+/g, ' ').slice(0, 800), bridgeMessages: window.__aslanWebViewMessages || [], })) console.log(`loaded=${JSON.stringify(state)}`) await browser.close() return } await new Promise((resolve) => { browser.on('disconnected', resolve) }) } main().catch((error) => { console.error(error.message || error) process.exit(1) })