UNPKG

@huolala-tech/page-spy-lynx

Version:

An SDK of PageSpy for debugging Lynx app

191 lines (138 loc) 6.71 kB
[npm-image]: https://img.shields.io/npm/v/@huolala-tech/page-spy-lynx?logo=npm&label=version [npm-url]: https://www.npmjs.com/package/@huolala-tech/page-spy-lynx [minified-image]: https://img.shields.io/bundlephobia/min/@huolala-tech/page-spy-lynx [minified-url]: https://unpkg.com/browse/@huolala-tech/page-spy-lynx/dist/esm/index.min.js [English](./README.md) | [Chinese](./README_ZH.md) # `@huolala-tech/page-spy-lynx` [![SDK version][npm-image]][npm-url] [![SDK size][minified-image]][minified-url] > PageSpy SDK for Lynx apps. Lynx does not provide browser `window` or `document` objects. This SDK does not depend on DOM APIs, and its built-in plugins enable themselves only when the Lynx runtime exposes the corresponding global capability. ## Usage Initialize PageSpy from background-only code, such as an entry module imported only by background logic or inside a Lynx `useEffect`. ```ts import PageSpy from '@huolala-tech/page-spy-lynx'; const pageSpy = new PageSpy({ api: 'example.com', }); ``` ## `InitConfig` The `api` option is required. Other options follow the shared PageSpy SDK config. ```ts const pageSpy = new PageSpy(config); interface InitConfig { api: string; project?: string; title?: string; enableSSL?: boolean | null; disabledPlugins?: (InternalPlugins | string)[]; } type InternalPlugins = | 'ConsolePlugin' | 'ErrorPlugin' | 'NetworkPlugin' | 'SystemPlugin' | 'WebSocketPlugin'; ``` ## Built-in plugins - `ConsolePlugin`: proxies `console.log/info/error/warn/debug`. - `SystemPlugin`: reports PageSpy client and available Lynx system information. - `NetworkPlugin`: proxies `fetch` first, and proxies `XMLHttpRequest` only when the runtime exposes a compatible implementation. - `WebSocketPlugin`: proxies WebSocket traffic only when `globalThis.WebSocket` is constructable. - `ErrorPlugin`: listens to global error and unhandled rejection hooks when the runtime exposes them. Use `disabledPlugins` to turn off any built-in plugin. ## Native WebSocket module PageSpy prefers Lynx `NativeModules.LynxNativeWebSocketModule` for its own WebSocket connection. Host apps should register this native module before initializing PageSpy in real Lynx native runtimes. In web preview runtimes, the SDK falls back to a constructable `globalThis.WebSocket`; if neither capability exists, initialization throws a clear error. The JavaScript contract is: ```ts declare let NativeModules: { LynxNativeWebSocketModule: { connect(socketId: string, url: string): void; send(socketId: string, data: string): void; close(socketId: string): void; drainEvents( socketId: string, callback: (events: NativeWebSocketEvent[]) => void, ): void; }; }; type NativeWebSocketEvent = | { type: 'open'; socketId: string } | { type: 'message'; socketId: string; data: string } | { type: 'close'; socketId: string; code?: number; reason?: string } | { type: 'error'; socketId: string; message?: string }; ``` Native implementations should enqueue `open/message/close/error` events and return them through `drainEvents`. Do not depend on invoking the same NativeModule callback multiple times. Native examples are included in `native-examples/android`, `native-examples/ios`, and `native-examples/harmony`. Android registration: ```java LynxEnv.inst().registerModule( "LynxNativeWebSocketModule", LynxNativeWebSocketModule.class ); ``` The Android example uses OkHttp's `WebSocketListener`; add OkHttp to the host app or adapt the sample to the app's existing WebSocket client. iOS registration: ```objc [globalConfig registerModule:LynxNativeWebSocketModule.class]; ``` Harmony registration: ```ts import { LynxNativeWebSocketModule } from './module/LynxNativeWebSocketModule'; this.modules.set('LynxNativeWebSocketModule', { moduleClass: LynxNativeWebSocketModule, }); ``` The Harmony example uses NetworkKit's WebSocket API. If your Harmony SDK uses a different WebSocket import path, adapt only the import and keep the NativeModule contract unchanged. `WebSocketPlugin` is separate from this module. It still proxies app WebSocket traffic only when the Lynx runtime exposes a constructable `globalThis.WebSocket`. ## Native Console module In Lynx native runtimes, `console` messages are routed through the Lynx DevTool inspector pipeline and cannot be reliably intercepted by overwriting `console.log` in JavaScript. PageSpy automatically detects `NativeModules.PageSpyConsoleModule` and polls `drainMessages` for JSON strings received by `LynxInspectorConsoleDelegate.onConsoleMessage(msg)`. The JavaScript contract is: ```ts declare let NativeModules: { PageSpyConsoleModule: { drainMessages(callback: (messages: string[]) => void): void; }; }; ``` Native examples are included in `native-examples/android`, `native-examples/ios`, and `native-examples/harmony`: - `PageSpyConsoleModule`: stores console messages and returns them to JS via `drainMessages`. - `PageSpyConsoleDelegate`: implements `LynxInspectorConsoleDelegate` and queues messages from `onConsoleMessage(msg)`. Android registration and setup: ```java LynxEnv.inst().registerModule( "PageSpyConsoleModule", PageSpyConsoleModule.class ); LynxBaseInspectorOwner owner = lynxView.getBaseInspectorOwner(); if (owner != null) { owner.setLynxInspectorConsoleDelegate(new PageSpyConsoleDelegate()); } ``` iOS registration and setup: ```objc [globalConfig registerModule:PageSpyConsoleModule.class]; id<LynxBaseInspectorOwner> owner = lynxView.baseInspectorOwner; if (owner) { [PageSpyConsoleDelegate installWithInspectorOwner:owner]; } ``` Harmony registration and setup: ```ts import { LynxView, LynxContext } from '@lynx/lynx'; import { PageSpyConsoleModule } from './module/PageSpyConsoleModule'; import { PageSpyConsoleDelegate } from './module/PageSpyConsoleDelegate'; this.modules.set('PageSpyConsoleModule', { moduleClass: PageSpyConsoleModule, }); LynxView({ onCreate: (context: LynxContext) => { const owner = context.getBaseInspectorOwner(); if (owner) { PageSpyConsoleDelegate.installWithInspectorOwner(owner); } }, }); ``` Without this delegate integration, PageSpy still works in Web or JS-overwritable console environments, but iOS/Android/Harmony native console messages may not be captured because they stay inside Lynx's native inspector pipeline. Troubleshooting: if iOS logs only show `LynxNativeWebSocketModule.drainEvents` and never show `PageSpyConsoleModule.drainMessages`, the current LynxView does not expose `NativeModules.PageSpyConsoleModule`. Registering only the WebSocket module makes the PageSpy connection work, but it does not capture native console messages.