""" Diagnostic probes against the live WebView. Consolidates what inspect_amplitude / inspect_bridge / inspect_window / inspect_vue_app / read_amplitude_events / debug_cdp used to do separately. All of them shared the same three defects: they assumed an adb forward already existed, they grabbed targets[0] without checking its type, and they read one WebSocket frame after Page.enable and treated whatever arrived as the command reply. The shared core fixes all three. py tools/inspect_page.py # everything py tools/inspect_page.py amplitude bridge """ import argparse import json import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) import telecom_cdp as T PROBES = { "page": """ (() => ({ url: location.href, route: location.pathname, title: document.title, innerWidth: window.innerWidth, innerHeight: window.innerHeight, devicePixelRatio: window.devicePixelRatio, scrollHeight: document.documentElement.scrollHeight, scrollY: window.scrollY, readyState: document.readyState }))() """, "amplitude": """ (() => { const connectors = window.analyticsConnectorInstances || {}; return { hasAmplitudeGlobal: typeof window.amplitude !== 'undefined', connectorInstances: Object.keys(connectors), connectorShape: Object.keys(connectors).reduce((acc, k) => { const inst = connectors[k] || {}; acc[k] = { keys: Object.keys(inst).slice(0, 20), hasEventBridge: !!inst.eventBridge, hasSetEventReceiver: !!(inst.eventBridge && typeof inst.eventBridge.setEventReceiver === 'function') }; return acc; }, {}), hasYandexMetrika: typeof window.ym === 'function', hasGtag: typeof window.gtag === 'function' }; })() """, "bridge": """ (() => { const out = {}; ['AndroidBridge', 'Android', 'Aitu', 'NativeBridge', 'webkit'].forEach(name => { const obj = window[name]; if (!obj) return; const methods = []; for (const k in obj) { try { if (typeof obj[k] === 'function') methods.push(k); } catch (e) { /* guarded getter */ } } out[name] = methods.slice(0, 60); }); return out; })() """, "window": """ (() => { const builtin = new Set(Object.getOwnPropertyNames(Object.getPrototypeOf(window))); const custom = Object.keys(window).filter(k => !builtin.has(k) && !k.startsWith('webkit')); return { customGlobals: custom.slice(0, 120), total: custom.length }; })() """, "vue": """ (() => { const root = document.querySelector('#app') || document.body; const vue = root && (root.__vue_app__ || root.__vue__); return { hasVueApp: !!(root && root.__vue_app__), hasVueInstance: !!(root && root.__vue__), version: (window.Vue && window.Vue.version) || (vue && vue.version) || null, rootId: root ? root.id : null, routerPath: (window.$nuxt && window.$nuxt.$route && window.$nuxt.$route.path) || location.pathname, componentClasses: [...new Set([...document.querySelectorAll('[class]')] .map(e => String(e.className).split(' ')[0]).filter(Boolean))].slice(0, 60) }; })() """, "storage": """ (() => { const pick = store => { const out = {}; for (let i = 0; i < store.length; i++) { const k = store.key(i); if (!/amplitude|analytics|event|session|device/i.test(k)) continue; const v = store.getItem(k) || ''; out[k] = v.length > 400 ? v.slice(0, 400) + '...(truncated)' : v; } return out; }; return { localStorage: pick(window.localStorage), sessionStorage: pick(window.sessionStorage) }; })() """, } def main(): parser = argparse.ArgumentParser(description="Probe the TelecomKz WebView.") parser.add_argument("probes", nargs="*", choices=list(PROBES) + [], default=None) args = parser.parse_args() names = args.probes or list(PROBES) try: device, target = T.connect() except T.DeviceError as exc: print("Error: " + str(exc)) return 1 print("Device: " + device) print("Target: " + str(target.get("title")) + " " + str(target.get("url"))) with T.CdpSession(target["webSocketDebuggerUrl"]) as session: for name in names: print("\n=== " + name + " ===") try: value = session.evaluate("JSON.stringify(" + PROBES[name] + ")") print(json.dumps(json.loads(value), ensure_ascii=False, indent=2)) except Exception as exc: print("probe failed: " + str(exc)) return 0 if __name__ == "__main__": sys.exit(main())