remote-webview-debugger 0.1.0 → 0.2.0
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/CHANGELOG.md +20 -0
- package/CHANGELOG.zh-CN.md +20 -0
- package/README.ar.md +185 -0
- package/README.de.md +169 -0
- package/README.es.md +169 -0
- package/README.fr.md +169 -0
- package/README.ja.md +169 -0
- package/README.ko.md +169 -0
- package/README.md +68 -14
- package/README.pt-BR.md +169 -0
- package/README.ru.md +169 -0
- package/README.zh-CN.md +69 -14
- package/README.zh-TW.md +169 -0
- package/dist/index.d.ts +216 -8
- package/dist/index.mjs +2479 -2873
- package/dist/index.mjs.map +1 -1
- package/dist/locales/ar.d.ts +4 -0
- package/dist/locales/ar.js +2 -0
- package/dist/locales/ar.mjs +150 -0
- package/dist/locales/ar.mjs.map +1 -0
- package/dist/locales/de.d.ts +4 -0
- package/dist/locales/de.js +2 -0
- package/dist/locales/de.mjs +150 -0
- package/dist/locales/de.mjs.map +1 -0
- package/dist/locales/es.d.ts +4 -0
- package/dist/locales/es.js +2 -0
- package/dist/locales/es.mjs +150 -0
- package/dist/locales/es.mjs.map +1 -0
- package/dist/locales/fr.d.ts +4 -0
- package/dist/locales/fr.js +2 -0
- package/dist/locales/fr.mjs +150 -0
- package/dist/locales/fr.mjs.map +1 -0
- package/dist/locales/ja.d.ts +4 -0
- package/dist/locales/ja.js +2 -0
- package/dist/locales/ja.mjs +150 -0
- package/dist/locales/ja.mjs.map +1 -0
- package/dist/locales/ko.d.ts +4 -0
- package/dist/locales/ko.js +2 -0
- package/dist/locales/ko.mjs +156 -0
- package/dist/locales/ko.mjs.map +1 -0
- package/dist/locales/pt.d.ts +4 -0
- package/dist/locales/pt.js +2 -0
- package/dist/locales/pt.mjs +150 -0
- package/dist/locales/pt.mjs.map +1 -0
- package/dist/locales/ru.d.ts +4 -0
- package/dist/locales/ru.js +2 -0
- package/dist/locales/ru.mjs +150 -0
- package/dist/locales/ru.mjs.map +1 -0
- package/dist/locales/zh-TW.d.ts +4 -0
- package/dist/locales/zh-TW.js +2 -0
- package/dist/locales/zh-TW.mjs +150 -0
- package/dist/locales/zh-TW.mjs.map +1 -0
- package/dist/sdk.js +24 -326
- package/dist/sdk.js.map +1 -1
- package/package.json +8 -2
package/README.es.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<!-- i18n-source: d9a31993ea867d3ef7058e7d637886f38a6ee3e1 -->
|
|
2
|
+
[English](README.md) | [简体中文](README.zh-CN.md) | [繁體中文](README.zh-TW.md) | [日本語](README.ja.md) | [한국어](README.ko.md) | Español | [Français](README.fr.md) | [Deutsch](README.de.md) | [Português (Brasil)](README.pt-BR.md) | [Русский](README.ru.md) | [العربية](README.ar.md)
|
|
3
|
+
|
|
4
|
+
# SDK de página de RWD (`sdk/`)
|
|
5
|
+
|
|
6
|
+
Un único archivo JS que carga una WebView de app o una página H5 para que un agente de IA pueda inspeccionar y manejar la página a través del gateway de RWD (`gateway/`) y MCP. Protocolo: [`docs/protocol.es.md`](../docs/protocol.es.md); arquitectura: [`docs/architecture.es.md`](../docs/architecture.es.md).
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/remote-webview-debugger@0.1.0/dist/sdk.js"></script>
|
|
10
|
+
<script>
|
|
11
|
+
RemoteWebviewDebugger.run("https://rwd.example.com/v1", "rwd_pk_xxxxxxxx", {
|
|
12
|
+
userId: "u-42", // opcional
|
|
13
|
+
deviceId: "…", // opcional; lo pasa un host nativo que inyecta el SDK
|
|
14
|
+
helpButton: true, // opcional; muestra el botón "Solicitar asistencia"
|
|
15
|
+
app: { name: "Shop", version: "3.2.0" },
|
|
16
|
+
lang: "en", // opcional; una etiqueta de idioma, por defecto según los idiomas del navegador
|
|
17
|
+
}).then(({ deviceCode, status }) => console.log(deviceCode, status))
|
|
18
|
+
</script>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Cómo obtener el SDK
|
|
22
|
+
|
|
23
|
+
Publicado en npm como [`remote-webview-debugger`](https://www.npmjs.com/package/remote-webview-debugger); versiones y cambios: [CHANGELOG](CHANGELOG.md).
|
|
24
|
+
|
|
25
|
+
| Uso | Dónde |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `<script>` desde un CDN | `https://cdn.jsdelivr.net/npm/remote-webview-debugger@0.1.0/dist/sdk.js` o `https://unpkg.com/remote-webview-debugger@0.1.0/dist/sdk.js` (IIFE minificado, global `RemoteWebviewDebugger`; fija la versión y, si quieres, añade `integrity`) |
|
|
28
|
+
| Un bundler | `npm install remote-webview-debugger` y luego `import { run, status } from 'remote-webview-debugger'` (módulo ES con tipos). Impórtalo antes que tu propio código para que la captura empiece pronto. No cargues además la versión `<script>` en la misma página |
|
|
29
|
+
| Tu gateway | `https://<gateway>/v1/sdk.js`, la copia que integra el gateway (también disponible en una URL direccionada por contenido para SRI, que ofrece la consola web) |
|
|
30
|
+
| Una app nativa | Empaqueta `dist/sdk.js` del paquete o descárgalo de uno de los anteriores; consulta [integración nativa](../docs/native-integration.es.md) |
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
| API | Descripción |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `run(gatewayUrl, appKey, opts?)` | Pone la página en línea (código de dispositivo, píldora). Devuelve `Promise<{deviceCode, status}>`; llamarla de nuevo no tiene efectos negativos. Opciones más abajo. |
|
|
37
|
+
| `status()` | `{deviceCode, status, control, help, label, deviceId, pageId, version, lang, deviceToken, level, config, pending, logSession}`; `status` es `idle / connecting / online / polling / stopped / rejected / quota`, `lang` es el idioma de la interfaz (`null` antes de `run()`), `logSession` es el registro de sesión en el que escribe esta página (`null` cuando no está grabando) |
|
|
38
|
+
| `stop()` | Desconecta y quita la interfaz (la recogida de console / red continúa, de forma acotada) |
|
|
39
|
+
| `setUser(userId)` | Cambia el usuario; vuelve a conectar una vez con un `hello` nuevo |
|
|
40
|
+
| `help(on)` | Solicitar asistencia / cancelar la solicitud |
|
|
41
|
+
| `nativeControl(nativeKey, action)` | «Tomar control» / «Devolver» / «Finalizar» desde la propia interfaz del host nativo |
|
|
42
|
+
| `nativeDecide(nativeKey, requestId, value)` | Con `nativeApproval`, responde a `status().pending`: un nivel o `null` para una solicitud de conexión, `'allow'` o `null` para una confirmación de acción sensible |
|
|
43
|
+
| `setLang(lang?)` | Cambia el idioma de la interfaz en tiempo de ejecución (el ajuste de idioma propio de una app); sin argumento vuelve a los idiomas del navegador. Consulta [Idiomas](#idiomas) |
|
|
44
|
+
| `registerLocale(pack)` | Añade un paquete de idioma o reemplaza el que tenga el mismo `id` (también acepta un array). Consulta [Idiomas](#idiomas) |
|
|
45
|
+
| `builtinLocales` | Los ids de los paquetes integrados |
|
|
46
|
+
|
|
47
|
+
Opciones de `run()`:
|
|
48
|
+
|
|
49
|
+
| Opción | Descripción |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `userId` | El usuario con sesión iniciada, enviado con el `hello` |
|
|
52
|
+
| `deviceId` | Un id de dispositivo estable proporcionado por un host nativo (si no, se guarda uno en localStorage) |
|
|
53
|
+
| `helpButton` | Muestra el botón "Solicitar asistencia" (combinado con OR con la política del proyecto) |
|
|
54
|
+
| `app` | `{ name, version }` de la app anfitriona |
|
|
55
|
+
| `lang` | Idioma de todo lo que ve el usuario del teléfono (píldora, ventana flotante, barra inferior, diálogos, avisos, la pestaña de eruda y la descripción "La IA quiere …" de una acción sensible): una etiqueta de idioma como `'ja'` o `'pt-BR'`. Por defecto: los idiomas del navegador. Consulta [Idiomas](#idiomas) |
|
|
56
|
+
| `locales` | Paquetes de idioma adicionales, registrados antes de elegir el idioma (como `registerLocale`) |
|
|
57
|
+
| `messages` | Mensajes que se sobrescriben, por idioma: `{ en: { ui: { help: 'Contact support' } }, zh: { ui: { help: '联系客服' } } }` |
|
|
58
|
+
| `networkExclude` | Solicitudes con las que el agente no debería tener que lidiar, como fuentes que siempre dan 404 o balizas de analítica: `['.ttf', 'WebTracks', '*beacon*', '/\\/track\\//']`. Cada regla coincide con la URL como subcadena sin distinguir mayúsculas y minúsculas, como patrón con comodín `*` o como expresión regular cuando se escribe `/…/`. Se suman a las reglas de la política del proyecto. Las solicitudes que coinciden quedan fuera de la lista de red y de los eventos `net_fail` de la línea de tiempo; la página las sigue registrando, así que un agente puede pedirlas con `includeExcluded` |
|
|
59
|
+
| `lockScreen` | `false`: no bloquea la página mientras hay un agente conectado (el usuario puede cambiarlo igualmente en la ventana flotante). Por defecto `true` |
|
|
60
|
+
| `theme` | `'auto'` (por defecto, sigue el fondo de la página), `'system'`, `'light'` o `'dark'` |
|
|
61
|
+
| `style` | Colores, fuentes, radios, z-index y posiciones de la interfaz: `{ accent: '#e11d48', radius: 12, zIndex: 1000, pill: { side: 'left' } }`. Consulta [Estilos](#estilos) |
|
|
62
|
+
| `eruda` | `true` o `{ dock, load, src, name }`: muestra Remote Debugger como pestaña dentro de eruda; `load` carga la última versión de eruda cuando la página no tiene ninguna. Desactivado por defecto; la política del proyecto puede activarlo de forma remota, y las opciones locales prevalecen campo a campo |
|
|
63
|
+
| `record` | `false`: esta página no escribe registro de sesión (y no se borra nada de lo ya guardado). Por defecto `true`; la política del proyecto puede desactivar el registro para todas las páginas |
|
|
64
|
+
| `launchId` | A qué arranque de la app pertenece esta página, para que todas las WebViews de un mismo proceso de la app archiven su registro de sesión bajo una sola sesión. Un host nativo pasa aquí su propio id (o define `window.RWDLaunchId` como una cadena o una función que devuelva una); si no, el SDK deduce el arranque a partir de una cookie de sesión más un heartbeat |
|
|
65
|
+
| `nativeKey`, `deviceToken`, `nativeApproval` | Para hosts nativos: el secreto para `nativeControl` / `nativeDecide`, el token de dispositivo que guarda el host y la opción de hacer las preguntas de conexión / confirmación de forma nativa |
|
|
66
|
+
|
|
67
|
+
## Idiomas
|
|
68
|
+
|
|
69
|
+
Integrados: inglés (`en`), chino simplificado (`zh`), chino tradicional (`zh-TW`, que también se usa para `zh-HK`, `zh-MO` y `zh-Hant`), francés (`fr`), español (`es`), ruso (`ru`), árabe (`ar`, con diseño de derecha a izquierda), japonés (`ja`), coreano (`ko`), alemán (`de`) y portugués (`pt`, de Brasil; también se usa para `pt-PT`).
|
|
70
|
+
|
|
71
|
+
**Cómo se elige el idioma.** El idioma del usuario del teléfono es `run({ lang })` si se indica y, si no, cada uno de los `navigator.languages` por orden. Para cada etiqueta, el SDK prueba la etiqueta y luego sus formas más cortas (`pt-BR` → `pt`, `zh-HK` → `zh-TW` → `zh`), se queda con el primer idioma para el que tiene paquete y, si no hay ninguno, usa el inglés. Los mensajes que faltan en un paquete recurren a los idiomas alternativos de la misma forma, así que un paquete parcial no es problema. `setLang('ja')` cambia el idioma en tiempo de ejecución; `status().lang` es el paquete en uso.
|
|
72
|
+
|
|
73
|
+
**Carga.** El inglés y el chino simplificado van dentro de `sdk.js`. Los demás paquetes se cargan bajo demanda, la primera vez que una página los necesita (durante ese instante, la interfaz muestra el idioma alternativo):
|
|
74
|
+
|
|
75
|
+
- Versión `<script>`: desde `locales/<id>.js` junto a `sdk.js` (la ruta del CDN, p. ej. `…/remote-webview-debugger@0.1.0/dist/locales/ja.js`, o `/v1/locales/ja.js` de tu gateway) y, si eso falla, desde el gateway que se pasa a `run()`. Para evitar la solicitud adicional, carga tú mismo el paquete, antes o después de `sdk.js`: `<script src="…/dist/locales/ja.js"></script>`.
|
|
76
|
+
- Versión de módulo ES: un import dinámico, así que tu bundler pone cada idioma en su propio chunk. Para empaquetar uno desde el principio: `import ja from 'remote-webview-debugger/locales/ja'` y luego `run(url, key, { locales: [ja] })`.
|
|
77
|
+
|
|
78
|
+
**Tus propios paquetes y textos.** Un paquete es `{ id, name, dir?, ui?, action?, agent? }`; lo que falte se toma de sus idiomas alternativos:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
RemoteWebviewDebugger.registerLocale({
|
|
82
|
+
id: 'it',
|
|
83
|
+
name: 'Italiano',
|
|
84
|
+
ui: { takeover: 'Prendi il controllo', end: 'Termina', help: 'Richiedi assistenza' /* … */ },
|
|
85
|
+
})
|
|
86
|
+
RemoteWebviewDebugger.run(url, key, {
|
|
87
|
+
messages: { en: { ui: { help: 'Contact support' } } }, // cambia mensajes sueltos de cualquier idioma
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`ui` es el texto de la interfaz, `action` completa "La IA quiere …" en el diálogo de confirmación y `agent` es lo que vuelve al agente. Los tipos de TypeScript (`LocalePack`, `Messages`, `UiMessages`, `ActionMessages`, `AgentMessages`) enumeran todas las claves; `src/locales/en.ts` es la referencia.
|
|
92
|
+
|
|
93
|
+
**Dos públicos.** El usuario del teléfono recibe el idioma descrito arriba. El agente lee los mensajes de error de RPC y los resúmenes de la línea de tiempo (toques, navegación dentro de la página, solicitudes fallidas) en el idioma del gateway, `welcome.agentLang` (`RWD_LANG`), y ese paquete se carga de la misma forma. En inglés hasta que un welcome diga otra cosa; el último valor se guarda en localStorage `rwd:alang`, así que los eventos anteriores al welcome de la siguiente página también lo usan.
|
|
94
|
+
|
|
95
|
+
Así, un usuario que habla chino puede trabajar con un agente que habla inglés: el diálogo pregunta `AI 想要点击「提交订单」,允许吗?` y, si se rechaza, el agente lee `The user denied this action`.
|
|
96
|
+
|
|
97
|
+
## Estilos
|
|
98
|
+
|
|
99
|
+
La interfaz vive en un shadow root sobre `#__rwd` (fuera de `<body>`), así que el CSS de la página no la alcanza salvo a través de estos puntos de enganche:
|
|
100
|
+
|
|
101
|
+
- **Propiedades personalizadas de CSS** en `:root` o `#__rwd`, p. ej. `:root { --rwd-accent-rgb: 225, 29, 72; --rwd-radius: 12px; }`.
|
|
102
|
+
- **`run({ style })`**, que fija esas mismas propiedades en `#__rwd`. Ahí los colores aceptan cualquier color CSS.
|
|
103
|
+
- **`::part()`** para todo lo demás: `#__rwd::part(bar) { … }`. Partes: `pill`, `window`, `bar`, `task`, `dialog`, `toast`, `button`, `cursor`, `glow`, `overlay`. Los nombres de clase internos no son una API estable.
|
|
104
|
+
- **`theme`**: cristal claro u oscuro (por defecto: sigue el fondo de la página).
|
|
105
|
+
|
|
106
|
+
| Propiedad | Campo de `style` | Por defecto | Qué |
|
|
107
|
+
|---|---|---|---|
|
|
108
|
+
| `--rwd-accent-rgb` | `accent` | `59, 130, 246` | Botones, interruptores, el puntero del agente, los resaltados y el brillo de los bordes |
|
|
109
|
+
| `--rwd-danger-rgb` | `danger` | `239, 68, 68` | El botón «Finalizar» |
|
|
110
|
+
| `--rwd-warning-rgb` | `warning` | `245, 158, 11` | «Solicitar asistencia» y «En asistencia»; el estado en que el usuario tiene el control |
|
|
111
|
+
| `--rwd-success-rgb` | `success` | `34, 197, 94` | Punto de en línea; "copiado" |
|
|
112
|
+
| `--rwd-font` | `font` | fuente de interfaz del sistema (por idioma para chino, japonés y coreano) | Todo el texto |
|
|
113
|
+
| `--rwd-font-mono` | `monoFont` | `ui-monospace, "SF Mono", …` | Código de dispositivo y etiquetas |
|
|
114
|
+
| `--rwd-radius` | `radius` | `18px` | Ventana flotante; el diálogo es 2px más redondeado, la tarjeta de tarea y la píldora 2px menos, y los botones del diálogo 6px menos |
|
|
115
|
+
| `--rwd-button-radius` | `buttonRadius` | `999px` | Botones, la barra inferior y los avisos |
|
|
116
|
+
| `--rwd-z-index` | `zIndex` | `2147483647` | Toda la interfaz |
|
|
117
|
+
| `--rwd-bar-bottom` | `barBottom` | `14px` | Barra inferior, por encima del área segura inferior |
|
|
118
|
+
| `--rwd-task-top` | `taskTop` | `10px` | Tarjeta de tarea, por debajo del área segura superior |
|
|
119
|
+
| `--rwd-toast-bottom` | `toastBottom` | `84px` | Avisos, por encima del área segura inferior |
|
|
120
|
+
| — | `pill: { side, top }` | borde derecho (izquierdo en idiomas de derecha a izquierda), `0.62` | Dónde empieza la píldora en reposo hasta que el usuario la arrastra; `top` de 0 (arriba) a 1 (abajo) |
|
|
121
|
+
|
|
122
|
+
Los colores son tripletes `r, g, b` para que los tonos translúcidos los sigan (la misma convención que `--bs-*-rgb` de Bootstrap).
|
|
123
|
+
|
|
124
|
+
## Comportamiento en la página (protocolo §6–§8, §11)
|
|
125
|
+
|
|
126
|
+
- Niveles: las RPC se comprueban contra `welcome.level` / `control.level` (`forbidden`, "Requires the … level"). Un agente sin nivel (un gateway antiguo) recibe `interact`; sin ningún agente conectado no se impone nada adicional.
|
|
127
|
+
- El token de dispositivo se guarda en localStorage `rwd:dtoken` y el token de reanudación en sessionStorage `rwd:resume` (ligado al pageId). Código de cierre 4401: si el token cambió entretanto (otra pestaña del dispositivo acaba de recibirlo), reintenta una vez de inmediato; si no, `rejected` y reintenta al cabo de unos 10 minutos; 4409: vuelve a conectar con un pageId nuevo; 4429: `quota`, reintenta al cabo de unos 5 minutos.
|
|
128
|
+
- `rwd_invite` en la barra de direcciones se retira en `run()` (`history.replaceState`) y se envía con el hello hasta que llega un welcome.
|
|
129
|
+
- `welcome.config`: `helpButton` (combinado con OR con la opción de `run()`), `maskSelectors`, `maskPatterns` (instantánea, console, URLs de red, valores de almacenamiento, resúmenes de la línea de tiempo), `confirmSelectors`, `networkExclude` (se suma a las reglas de la opción de `run()`), `sessionLog`. La última configuración se guarda en localStorage `rwd:cfg` y se usa hasta que llega el welcome; así, un proyecto que desactivó el registro de sesión lo mantiene desactivado desde el primer momento de la siguiente página, antes de cualquier welcome.
|
|
130
|
+
- Las instantáneas terminan con una sección `[Overlays]` que enumera lo que flota sobre la página (el fondo de una ventana emergente, un modal, una hoja inferior) con su etiqueta, un fragmento corto de texto, cuánto del viewport cubre y una ref. Un fondo es un elemento vacío para el que el aria snapshot no tiene nodo, así que recibe una ref `oN` en lugar de `eN`; eso es lo que permite al agente tocarlo para cerrar la ventana emergente.
|
|
131
|
+
- Un clic apunta primero al centro visible del elemento y luego a los demás puntos de una cuadrícula de 3×3 dentro de él, para que una insignia encima de un botón no lo bloquee. Cuando todos los puntos están tapados, la RPC falla con `not_interactable` e indica el elemento que lo tapa y su ref.
|
|
132
|
+
- Los diálogos de conexión y de acciones sensibles (`[data-rwd-confirm]`, `confirmSelectors`, incluido el envío de un formulario con Enter) viven en un Shadow DOM, solo aceptan toques de confianza y se activan 0,4 s después de aparecer. Las pestañas del mismo origen comparten por BroadcastChannel las solicitudes de conexión ya decididas.
|
|
133
|
+
|
|
134
|
+
Cargar el archivo empieza a recoger la console, los errores no capturados y la red (XHR, fetch, WebSocket, sendBeacon, EventSource), con un máximo de 500 entradas de cada tipo; cuando se llena, se descartan primero los logs simples y las solicitudes correctas. Los cuerpos de las respuestas se guardan en caché hasta 5 MB en total, 64 KB cada uno. Por eso conviene cargarlo de forma síncrona y pronto en `<head>`.
|
|
135
|
+
|
|
136
|
+
## Registro de sesión (protocolo §5.4)
|
|
137
|
+
|
|
138
|
+
Esos búferes son la memoria de una sola página. En paralelo, el SDK escribe un **registro de sesión** en IndexedDB (`rwd-log`) en el dispositivo, para que un agente que se conecte después de un bug pueda seguir leyendo todo el camino hasta él:
|
|
139
|
+
|
|
140
|
+
- Una sesión es un arranque de la app, compartido por todas las páginas del origen: `run({ launchId })`; si no, `window.RWDLaunchId`; si no, se deduce de la cookie de sesión `rwd_launch` más un heartbeat (una sesión de cookie que lleva más de una hora en silencio cuenta como un arranque nuevo). `status().logSession` es el id en uso.
|
|
141
|
+
- Qué se graba: apertura de página / navegación dentro de la página / primer plano-segundo plano / salida, los toques del usuario, la entrada de texto, los envíos y las posiciones en las que se detiene el desplazamiento, las llamadas interactivas del agente y `rwd.evaluate`, los cambios de control, la console de todos los niveles y cada solicitud terminada (las fallidas, también con las cabeceras y los cuerpos ocultados, 64 KB cada uno). Funciona tanto si el gateway es accesible como si no. Los campos enmascarados se guardan como `••••`, y los `maskPatterns` se aplican al escribir los registros.
|
|
142
|
+
- Qué se conserva: los 3 últimos arranques, 10 MB cada uno; por encima de eso, se descartan primero los logs simples y las solicitudes correctas. Solo el arranque actual cuando la cuota de almacenamiento es inferior a 64 MB; nada en absoluto sin IndexedDB.
|
|
143
|
+
- El agente lo lee con `rwd.log` (`observe`) y `rwd.logDetail` (`advanced`, para cabeceras y cuerpos). Fuera de eso, nada sale del dispositivo.
|
|
144
|
+
- Se desactiva con `run({ record: false })` para una página, o con `policy.sessionLog: false` para el proyecto, lo que además borra lo que este origen ya había guardado.
|
|
145
|
+
|
|
146
|
+
## Estructura
|
|
147
|
+
|
|
148
|
+
- `src/index.ts`: API pública, sesión, despacho de RPC, estado de control.
|
|
149
|
+
- `src/transport.ts`: el WebSocket de la página (el constructor nativo), tiempo de espera del heartbeat, espera exponencial y, tras 3 intentos fallidos, `POST /v1/presence` cada 60 s.
|
|
150
|
+
- `src/ids.ts`: deviceId / pageId / openerId.
|
|
151
|
+
- `src/launch.ts`: a qué arranque de la app pertenece esta página (`launchId`, `window.RWDLaunchId`, la cookie `rwd_launch`).
|
|
152
|
+
- `src/pageWatch.ts`: mensajes `page` (url, título, visibilidad) y eventos de la línea de tiempo (navegación dentro de la página, toques del usuario).
|
|
153
|
+
- `src/ui.ts`, `src/lock.ts`: la píldora, el botón «Solicitar asistencia», la capa de bloqueo, el brillo, el resaltado de acciones y los diálogos en un Shadow DOM; bloquea la entrada de confianza del usuario mientras hay un agente conectado y muestra cuánto tiempo lleva conectado.
|
|
154
|
+
- `src/approval.ts`: aprobación de conexión y confirmación de acciones sensibles (diálogo en la página, o el host nativo mediante `nativeDecide`).
|
|
155
|
+
- `src/i18n.ts`, `src/locales/`, `src/localeLoader*.ts`: paquetes de idioma (textos de interfaz, de acción y del agente por idioma), elección del idioma y alternativas, carga bajo demanda; `scripts/locales.mjs` genera `dist/locales/<id>.js`.
|
|
156
|
+
- El motor del agente vive junto a chobitsu en `packages/chobitsu/src/engine/rwd/`: instantánea, `rwd.query`, comprobaciones de accionabilidad, entrada sintetizada, teclado, búferes de console / red, capturas de pantalla, `rwd.storage`, el registro de sesión en IndexedDB (`coldlog.ts`), detección de capas superpuestas (`overlays.ts`), niveles y reglas de confirmación (`policy.ts`) y textos dirigidos al agente (`i18n.ts`). Las fuentes de Playwright usadas para las instantáneas están en `packages/chobitsu/src/engine/vendor/playwright/`. La compilación las empaqueta desde el código fuente en `dist/sdk.js`.
|
|
157
|
+
|
|
158
|
+
## Compilación y tests
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
cd sdk
|
|
162
|
+
npm ci
|
|
163
|
+
npm run build # dist/sdk.js (IIFE, global RemoteWebviewDebugger, ES2017), dist/index.mjs + index.d.ts (módulo ES)
|
|
164
|
+
npm run typecheck
|
|
165
|
+
npm test # Playwright: WebKit (iPhone 15) + Chromium (Pixel 7)
|
|
166
|
+
npm run gateway # gateway simulado local: http://localhost:8787/demo/platform/?key=rwd_pk_demo
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Los tests usan `test/mock-gateway.mjs`, que implementa el lado de la página del protocolo (welcome, estado de control, RPC, presencia; tokens, códigos de cierre, niveles, configuración remota, `agentLang`, aprobación de conexión) y sirve `/v1/sdk.js`, los paquetes de idioma bajo `/v1/locales/` y la tienda de demostración. No comprueba los niveles por sí mismo, así que los tests ejercitan la aplicación de niveles de la propia página. Las specs de `test/e2e/` se ejecutan con un navegador en `zh-CN` y `agentLang: 'zh'` salvo que un test indique otra cosa; `i18n.spec.ts` cubre el inglés, y `locales.spec.ts`, los demás paquetes de idioma, las alternativas, los paquetes personalizados, los estilos y el diseño de derecha a izquierda. El test de coexistencia carga eruda 3.4.3 y PageSpy 2.4.0 desde jsdelivr, así que necesita acceso a internet.
|
package/README.fr.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<!-- i18n-source: d9a31993ea867d3ef7058e7d637886f38a6ee3e1 -->
|
|
2
|
+
[English](README.md) | [简体中文](README.zh-CN.md) | [繁體中文](README.zh-TW.md) | [日本語](README.ja.md) | [한국어](README.ko.md) | [Español](README.es.md) | Français | [Deutsch](README.de.md) | [Português (Brasil)](README.pt-BR.md) | [Русский](README.ru.md) | [العربية](README.ar.md)
|
|
3
|
+
|
|
4
|
+
# SDK de page RWD (`sdk/`)
|
|
5
|
+
|
|
6
|
+
Un fichier JS qu'une WebView d'application ou une page H5 charge, pour qu'un agent IA puisse inspecter et piloter la page via la passerelle RWD (`gateway/`) et MCP. Protocole : [`docs/protocol.fr.md`](../docs/protocol.fr.md) ; architecture : [`docs/architecture.fr.md`](../docs/architecture.fr.md).
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/remote-webview-debugger@0.1.0/dist/sdk.js"></script>
|
|
10
|
+
<script>
|
|
11
|
+
RemoteWebviewDebugger.run("https://rwd.example.com/v1", "rwd_pk_xxxxxxxx", {
|
|
12
|
+
userId: "u-42", // facultatif
|
|
13
|
+
deviceId: "…", // facultatif ; fourni par un hôte natif qui injecte le SDK
|
|
14
|
+
helpButton: true, // facultatif ; affiche le bouton « Demander une assistance »
|
|
15
|
+
app: { name: "Shop", version: "3.2.0" },
|
|
16
|
+
lang: "en", // facultatif ; une étiquette de langue, par défaut d'après les langues du navigateur
|
|
17
|
+
}).then(({ deviceCode, status }) => console.log(deviceCode, status))
|
|
18
|
+
</script>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Obtenir le SDK
|
|
22
|
+
|
|
23
|
+
Publié sur npm sous le nom [`remote-webview-debugger`](https://www.npmjs.com/package/remote-webview-debugger) ; versions et modifications : [CHANGELOG](CHANGELOG.md).
|
|
24
|
+
|
|
25
|
+
| Usage | Source |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `<script>` depuis un CDN | `https://cdn.jsdelivr.net/npm/remote-webview-debugger@0.1.0/dist/sdk.js` ou `https://unpkg.com/remote-webview-debugger@0.1.0/dist/sdk.js` (IIFE minifiée, global `RemoteWebviewDebugger` ; épinglez la version, et ajoutez `integrity` si vous le souhaitez) |
|
|
28
|
+
| Un bundler | `npm install remote-webview-debugger`, puis `import { run, status } from 'remote-webview-debugger'` (module ES avec types). Importez-le avant votre propre code pour que la capture démarre tôt. Ne chargez pas en plus la version `<script>` sur la même page |
|
|
29
|
+
| Votre passerelle | `https://<gateway>/v1/sdk.js`, la copie qu'embarque la passerelle (également disponible à une URL adressée par contenu pour SRI, proposée par la console web) |
|
|
30
|
+
| Une application native | Embarquez `dist/sdk.js` du paquet, ou téléchargez-le depuis l'une des sources ci-dessus ; voir [l'intégration native](../docs/native-integration.fr.md) |
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
| API | Description |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `run(gatewayUrl, appKey, opts?)` | Met la page en ligne (code d'appareil, pastille). Renvoie `Promise<{deviceCode, status}>` ; l'appeler une seconde fois est sans effet. Options ci-dessous. |
|
|
37
|
+
| `status()` | `{deviceCode, status, control, help, label, deviceId, pageId, version, lang, deviceToken, level, config, pending, logSession}` ; `status` vaut `idle / connecting / online / polling / stopped / rejected / quota`, `lang` est la langue de l'interface (`null` avant `run()`), `logSession` le journal de session dans lequel écrit cette page (`null` quand rien n'est enregistré) |
|
|
38
|
+
| `stop()` | Se déconnecte et retire l'interface (la collecte de la console / du réseau continue, dans une limite bornée) |
|
|
39
|
+
| `setUser(userId)` | Change d'utilisateur ; se reconnecte une fois avec un nouveau `hello` |
|
|
40
|
+
| `help(on)` | Demande une assistance / annule la demande |
|
|
41
|
+
| `nativeControl(nativeKey, action)` | « Reprendre » / « Rendre » / « Terminer » depuis l'interface propre de l'hôte natif |
|
|
42
|
+
| `nativeDecide(nativeKey, requestId, value)` | Avec `nativeApproval`, répond à `status().pending` : un niveau ou `null` pour une demande de rattachement, `'allow'` ou `null` pour la confirmation d'une action sensible |
|
|
43
|
+
| `setLang(lang?)` | Change la langue de l'interface à l'exécution (le réglage de langue propre à une application) ; sans argument, revient aux langues du navigateur. Voir [Langues](#langues) |
|
|
44
|
+
| `registerLocale(pack)` | Ajoute un pack de langue, ou remplace celui qui a le même `id` (accepte aussi un tableau). Voir [Langues](#langues) |
|
|
45
|
+
| `builtinLocales` | Les identifiants des packs intégrés |
|
|
46
|
+
|
|
47
|
+
Options de `run()` :
|
|
48
|
+
|
|
49
|
+
| Option | Description |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `userId` | L'utilisateur connecté, envoyé avec le `hello` |
|
|
52
|
+
| `deviceId` | Un identifiant d'appareil stable fourni par un hôte natif (sinon, un identifiant est conservé dans le localStorage) |
|
|
53
|
+
| `helpButton` | Affiche le bouton « Demander une assistance » (combiné par OU avec la politique du projet) |
|
|
54
|
+
| `app` | `{ name, version }` de l'application hôte |
|
|
55
|
+
| `lang` | Langue de tout ce que voit l'utilisateur du téléphone (pastille, fenêtre flottante, barre inférieure, boîtes de dialogue, toasts, l'onglet eruda, et la description « AI wants to … » d'une action sensible) : une étiquette de langue comme `'ja'` ou `'pt-BR'`. Par défaut : les langues du navigateur. Voir [Langues](#langues) |
|
|
56
|
+
| `locales` | Packs de langue supplémentaires, enregistrés avant le choix de la langue (comme `registerLocale`) |
|
|
57
|
+
| `messages` | Messages à remplacer, par langue : `{ en: { ui: { help: 'Contact support' } }, zh: { ui: { help: '联系客服' } } }` |
|
|
58
|
+
| `networkExclude` | Les requêtes que l'agent ne devrait pas avoir à éplucher — polices qui renvoient toujours 404, balises d'analytics : `['.ttf', 'WebTracks', '*beacon*', '/\\/track\\//']`. Chaque règle correspond à l'URL en tant que sous-chaîne insensible à la casse, en tant que motif avec joker `*`, ou en tant qu'expression régulière quand elle s'écrit `/…/`. S'ajoute aux règles de la politique du projet. Les requêtes correspondantes restent hors de la liste réseau et des événements `net_fail` de la chronologie ; la page les enregistre quand même, si bien qu'un agent peut les demander avec `includeExcluded` |
|
|
59
|
+
| `lockScreen` | `false` : ne pas verrouiller la page pendant qu'un agent est rattaché (l'utilisateur peut toujours le changer dans la fenêtre flottante). Par défaut `true` |
|
|
60
|
+
| `theme` | `'auto'` (par défaut, suit l'arrière-plan de la page), `'system'`, `'light'` ou `'dark'` |
|
|
61
|
+
| `style` | Couleurs, polices, arrondis, z-index et positions de l'interface : `{ accent: '#e11d48', radius: 12, zIndex: 1000, pill: { side: 'left' } }`. Voir [Apparence](#apparence) |
|
|
62
|
+
| `eruda` | `true` ou `{ dock, load, src, name }` : affiche Remote Debugger dans un onglet d'eruda ; `load` charge la dernière version d'eruda quand la page n'en a pas. Désactivé par défaut ; la politique du projet peut l'activer à distance, les options locales l'emportant champ par champ |
|
|
63
|
+
| `record` | `false` : cette page n'écrit aucun journal de session (et rien de ce qui est déjà stocké n'est supprimé). Par défaut `true` ; la politique du projet peut désactiver le journal pour toutes les pages |
|
|
64
|
+
| `launchId` | Le lancement de l'application auquel appartient cette page, pour que toutes les WebViews d'un même processus d'application rangent leur journal de session sous une seule session. Un hôte natif passe ici son propre identifiant (ou définit `window.RWDLaunchId` comme une chaîne ou une fonction qui en renvoie une) ; sinon, le SDK déduit le lancement d'un cookie de session et d'un battement de cœur |
|
|
65
|
+
| `nativeKey`, `deviceToken`, `nativeApproval` | Pour les hôtes natifs : le secret de `nativeControl` / `nativeDecide`, le jeton d'appareil que conserve l'hôte, et le choix de poser nativement les questions de rattachement / de confirmation |
|
|
66
|
+
|
|
67
|
+
## Langues
|
|
68
|
+
|
|
69
|
+
Intégrées : anglais (`en`), chinois simplifié (`zh`), chinois traditionnel (`zh-TW`, utilisé aussi pour `zh-HK`, `zh-MO` et `zh-Hant`), français (`fr`), espagnol (`es`), russe (`ru`), arabe (`ar`, mis en page de droite à gauche), japonais (`ja`), coréen (`ko`), allemand (`de`) et portugais (`pt`, brésilien ; utilisé aussi pour `pt-PT`).
|
|
70
|
+
|
|
71
|
+
**Choix de la langue.** La langue de l'utilisateur du téléphone est `run({ lang })` si elle est fournie, puis chacune des `navigator.languages` dans l'ordre. Pour chaque étiquette, le SDK essaie l'étiquette puis ses formes plus courtes (`pt-BR` → `pt`, `zh-HK` → `zh-TW` → `zh`), retient la première langue pour laquelle il dispose d'un pack, et se rabat sur l'anglais. Les messages absents d'un pack se rabattent de la même façon : un pack partiel convient donc très bien. `setLang('ja')` change de langue à l'exécution ; `status().lang` est le pack utilisé.
|
|
72
|
+
|
|
73
|
+
**Chargement.** L'anglais et le chinois simplifié sont inclus dans `sdk.js`. Les autres packs se chargent à la demande, la première fois qu'une page en a besoin (l'interface affiche la langue de repli pendant ce court instant) :
|
|
74
|
+
|
|
75
|
+
- Version `<script>` : depuis `locales/<id>.js` à côté de `sdk.js` (le chemin du CDN, par exemple `…/remote-webview-debugger@0.1.0/dist/locales/ja.js`, ou `/v1/locales/ja.js` sur votre passerelle), puis depuis la passerelle passée à `run()` en cas d'échec. Pour éviter la requête supplémentaire, chargez vous-même le pack, avant ou après `sdk.js` : `<script src="…/dist/locales/ja.js"></script>`.
|
|
76
|
+
- Version module ES : un import dynamique, si bien que votre bundler place chaque langue dans son propre chunk. Pour en intégrer une d'emblée au bundle : `import ja from 'remote-webview-debugger/locales/ja'`, puis `run(url, key, { locales: [ja] })`.
|
|
77
|
+
|
|
78
|
+
**Vos propres packs et formulations.** Un pack est `{ id, name, dir?, ui?, action?, agent? }` ; tout ce qui est omis provient de ses langues de repli :
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
RemoteWebviewDebugger.registerLocale({
|
|
82
|
+
id: 'it',
|
|
83
|
+
name: 'Italiano',
|
|
84
|
+
ui: { takeover: 'Prendi il controllo', end: 'Termina', help: 'Richiedi assistenza' /* … */ },
|
|
85
|
+
})
|
|
86
|
+
RemoteWebviewDebugger.run(url, key, {
|
|
87
|
+
messages: { en: { ui: { help: 'Contact support' } } }, // remplace des messages isolés, dans n'importe quelle langue
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`ui` est le texte de l'interface, `action` complète « AI wants to … » dans la boîte de dialogue de confirmation, et `agent` est ce qui est renvoyé à l'agent. Les types TypeScript (`LocalePack`, `Messages`, `UiMessages`, `ActionMessages`, `AgentMessages`) listent toutes les clés ; `src/locales/en.ts` sert de référence.
|
|
92
|
+
|
|
93
|
+
**Deux publics.** L'utilisateur du téléphone reçoit la langue décrite ci-dessus. L'agent lit les messages d'erreur RPC et les résumés de la chronologie (touchers, navigation dans la page, requêtes échouées) dans la langue de la passerelle, `welcome.agentLang` (`RWD_LANG`), dont le pack se charge de la même façon. Anglais tant qu'aucun welcome n'indique autre chose ; la dernière valeur est conservée dans le localStorage `rwd:alang`, si bien que les événements antérieurs au welcome de la page suivante l'utilisent aussi.
|
|
94
|
+
|
|
95
|
+
Un utilisateur sinophone peut donc travailler avec un agent anglophone : la boîte de dialogue demande `AI 想要点击「提交订单」,允许吗?` et, en cas de refus, l'agent lit `The user denied this action`.
|
|
96
|
+
|
|
97
|
+
## Apparence
|
|
98
|
+
|
|
99
|
+
L'interface vit dans une shadow root sur `#__rwd` (en dehors de `<body>`) : le CSS de la page ne l'atteint donc qu'à travers ces points d'accroche :
|
|
100
|
+
|
|
101
|
+
- **Propriétés personnalisées CSS** sur `:root` ou `#__rwd`, par exemple `:root { --rwd-accent-rgb: 225, 29, 72; --rwd-radius: 12px; }`.
|
|
102
|
+
- **`run({ style })`**, qui définit ces mêmes propriétés sur `#__rwd`. Les couleurs y acceptent n'importe quelle couleur CSS.
|
|
103
|
+
- **`::part()`** pour tout le reste : `#__rwd::part(bar) { … }`. Parts : `pill`, `window`, `bar`, `task`, `dialog`, `toast`, `button`, `cursor`, `glow`, `overlay`. Les noms de classes internes ne constituent pas une API stable.
|
|
104
|
+
- **`theme`** : verre clair ou sombre (par défaut : suit l'arrière-plan de la page).
|
|
105
|
+
|
|
106
|
+
| Propriété | Champ de `style` | Par défaut | Rôle |
|
|
107
|
+
|---|---|---|---|
|
|
108
|
+
| `--rwd-accent-rgb` | `accent` | `59, 130, 246` | Boutons, interrupteurs, pointeur de l'agent, mises en surbrillance et lueur des bords |
|
|
109
|
+
| `--rwd-danger-rgb` | `danger` | `239, 68, 68` | Le bouton « Terminer » |
|
|
110
|
+
| `--rwd-warning-rgb` | `warning` | `245, 158, 11` | « Demander une assistance » et « En assistance » ; l'état où l'utilisateur a la main |
|
|
111
|
+
| `--rwd-success-rgb` | `success` | `34, 197, 94` | Point « en ligne » ; « copié » |
|
|
112
|
+
| `--rwd-font` | `font` | police d'interface du système (adaptée à la langue pour le chinois, le japonais et le coréen) | Tout le texte |
|
|
113
|
+
| `--rwd-font-mono` | `monoFont` | `ui-monospace, "SF Mono", …` | Code d'appareil et badges |
|
|
114
|
+
| `--rwd-radius` | `radius` | `18px` | Fenêtre flottante ; la boîte de dialogue est arrondie de 2px de plus, la carte de tâche et la pastille de 2px de moins, les boutons de la boîte de dialogue de 6px de moins |
|
|
115
|
+
| `--rwd-button-radius` | `buttonRadius` | `999px` | Boutons, barre inférieure et toasts |
|
|
116
|
+
| `--rwd-z-index` | `zIndex` | `2147483647` | Toute l'interface |
|
|
117
|
+
| `--rwd-bar-bottom` | `barBottom` | `14px` | Barre inférieure, au-dessus de la zone sûre du bas |
|
|
118
|
+
| `--rwd-task-top` | `taskTop` | `10px` | Carte de tâche, sous la zone sûre du haut |
|
|
119
|
+
| `--rwd-toast-bottom` | `toastBottom` | `84px` | Toasts, au-dessus de la zone sûre du bas |
|
|
120
|
+
| — | `pill: { side, top }` | bord droit (gauche dans les langues de droite à gauche), `0.62` | Position de départ de la pastille au repos, jusqu'à ce que l'utilisateur la déplace ; `top` va de 0 (en haut) à 1 (en bas) |
|
|
121
|
+
|
|
122
|
+
Les couleurs sont des triplets `r, g, b` pour que les nuances translucides suivent (la même convention que les `--bs-*-rgb` de Bootstrap).
|
|
123
|
+
|
|
124
|
+
## Comportement dans la page (protocole §6–§8, §11)
|
|
125
|
+
|
|
126
|
+
- Niveaux : les RPC sont vérifiés par rapport à `welcome.level` / `control.level` (`forbidden`, « Requires the … level »). Un agent sans niveau (passerelle plus ancienne) reçoit `interact` ; sans agent rattaché, rien de plus n'est imposé.
|
|
127
|
+
- Le jeton d'appareil est conservé dans le localStorage `rwd:dtoken`, le jeton de reprise dans le sessionStorage `rwd:resume` (lié au pageId). Code de fermeture 4401 : si le jeton a changé entre-temps (un autre onglet de l'appareil vient de le recevoir), réessayer une fois immédiatement, sinon `rejected` et nouvel essai au bout d'environ 10 minutes ; 4409 : se reconnecter avec un nouveau pageId ; 4429 : `quota`, nouvel essai au bout d'environ 5 minutes.
|
|
128
|
+
- `rwd_invite` dans la barre d'adresse est retiré lors de `run()` (`history.replaceState`) et envoyé avec le hello jusqu'à l'arrivée d'un welcome.
|
|
129
|
+
- `welcome.config` : `helpButton` (combiné par OU avec l'option de `run()`), `maskSelectors`, `maskPatterns` (instantané, console, URL réseau, valeurs du stockage, résumés de la chronologie), `confirmSelectors`, `networkExclude` (ajouté aux règles de l'option de `run()`), `sessionLog`. La dernière configuration est conservée dans le localStorage `rwd:cfg` et utilisée jusqu'à l'arrivée du welcome — ainsi, un projet qui a désactivé le journal de session le garde désactivé dès le premier instant de la page suivante, avant tout welcome.
|
|
130
|
+
- Les instantanés se terminent par une section `[Overlays]` qui liste ce qui flotte au-dessus de la page — le voile d'une popup, une fenêtre modale, un panneau glissant depuis le bas — avec sa balise, un court extrait de texte, la part de la zone d'affichage qu'il couvre et une référence. Un voile est un élément vide pour lequel l'aria snapshot n'a pas de nœud : il reçoit donc une référence `oN` au lieu de `eN` ; c'est ce qui permet à un agent de le toucher pour fermer la popup.
|
|
131
|
+
- Un clic vise d'abord le centre visible de l'élément, puis les autres points d'une grille 3×3 à l'intérieur, si bien qu'un badge posé sur un bouton ne le bloque pas. Quand tous les points sont recouverts, le RPC échoue avec `not_interactable` en nommant l'élément qui masque et sa référence.
|
|
132
|
+
- Les boîtes de dialogue de rattachement et d'action sensible (`[data-rwd-confirm]`, `confirmSelectors`, y compris la touche Entrée qui soumet un formulaire) vivent dans un Shadow DOM, n'acceptent que les touchers de confiance et ne s'activent que 0,4 s après leur apparition. Les onglets de même origine partagent les demandes de rattachement déjà tranchées via BroadcastChannel.
|
|
133
|
+
|
|
134
|
+
Le chargement du fichier lance la collecte de la console, des erreurs non interceptées et du réseau (XHR, fetch, WebSocket, sendBeacon, EventSource), 500 entrées au plus pour chacun ; une fois plein, ce sont les journaux ordinaires et les requêtes réussies qui partent en premier. Les corps de réponse sont mis en cache jusqu'à 5 Mo au total, 64 Ko chacun. Chargez-le donc de façon synchrone et tôt dans le `<head>`.
|
|
135
|
+
|
|
136
|
+
## Journal de session (protocole §5.4)
|
|
137
|
+
|
|
138
|
+
Ces tampons sont la mémoire d'une seule page. En parallèle, le SDK écrit un **journal de session** dans IndexedDB (`rwd-log`) sur l'appareil, pour qu'un agent qui se rattache après un bug puisse quand même lire tout le chemin qui y a mené :
|
|
139
|
+
|
|
140
|
+
- Une session correspond à un lancement de l'application, partagé par toutes les pages de l'origine : `run({ launchId })`, sinon `window.RWDLaunchId`, sinon déduit du cookie de session `rwd_launch` et d'un battement de cœur (une session de cookie restée silencieuse plus d'une heure compte comme un nouveau lancement). `status().logSession` donne l'identifiant utilisé.
|
|
141
|
+
- Enregistré : ouverture de page / navigation dans la page / premier plan-arrière-plan / départ, les touchers, saisies, soumissions et positions de défilement au repos de l'utilisateur, les appels interactifs de l'agent et `rwd.evaluate`, les changements de contrôle, la console à tous les niveaux, et chaque requête terminée — les requêtes échouées aussi avec leurs en-têtes et corps expurgés (64 Ko chacun). Il fonctionne que la passerelle soit joignable ou non. Les champs masqués sont stockés sous la forme `••••`, et les `maskPatterns` sont appliqués au moment où les enregistrements sont écrits.
|
|
142
|
+
- Conservé : les 3 derniers lancements, 10 Mo chacun ; au-delà, les journaux ordinaires et les requêtes réussies sont supprimés en premier. Seul le lancement en cours quand le quota de stockage est inférieur à 64 Mo ; rien du tout sans IndexedDB.
|
|
143
|
+
- Lu par l'agent avec `rwd.log` (`observe`) et `rwd.logDetail` (`advanced`, pour les en-têtes et les corps). Rien ne quitte l'appareil autrement.
|
|
144
|
+
- Désactivé avec `run({ record: false })` pour une page, ou `policy.sessionLog: false` pour le projet — ce qui supprime aussi ce que cette origine a déjà stocké.
|
|
145
|
+
|
|
146
|
+
## Organisation
|
|
147
|
+
|
|
148
|
+
- `src/index.ts` : API publique, session, distribution des RPC, état de contrôle.
|
|
149
|
+
- `src/transport.ts` : le WebSocket de la page (le constructeur natif), délai d'expiration du battement de cœur, backoff exponentiel et, après 3 tentatives échouées, `POST /v1/presence` toutes les 60 s.
|
|
150
|
+
- `src/ids.ts` : deviceId / pageId / openerId.
|
|
151
|
+
- `src/launch.ts` : le lancement de l'application auquel appartient cette page (`launchId`, `window.RWDLaunchId`, le cookie `rwd_launch`).
|
|
152
|
+
- `src/pageWatch.ts` : messages `page` (url, titre, visibilité) et événements de la chronologie (navigation dans la page, touchers de l'utilisateur).
|
|
153
|
+
- `src/ui.ts`, `src/lock.ts` : la pastille, le bouton « Demander une assistance », la surcouche de verrouillage, la lueur, la mise en surbrillance des actions et les boîtes de dialogue dans un Shadow DOM ; bloque les saisies de confiance de l'utilisateur pendant qu'un agent est rattaché, et affiche depuis combien de temps il est connecté.
|
|
154
|
+
- `src/approval.ts` : approbation du rattachement et confirmation des actions sensibles (boîte de dialogue dans la page, ou hôte natif via `nativeDecide`).
|
|
155
|
+
- `src/i18n.ts`, `src/locales/`, `src/localeLoader*.ts` : packs de langue (textes de l'interface, des actions et de l'agent pour chaque langue), choix et repli, chargement à la demande ; `scripts/locales.mjs` construit `dist/locales/<id>.js`.
|
|
156
|
+
- Le moteur de l'agent se trouve à côté de chobitsu dans `packages/chobitsu/src/engine/rwd/` : instantané, `rwd.query`, vérifications d'actionnabilité, saisie synthétisée, clavier, tampons console / réseau, captures d'écran, `rwd.storage`, le journal de session dans IndexedDB (`coldlog.ts`), détection des surcouches (`overlays.ts`), niveaux et règles de confirmation (`policy.ts`), textes destinés à l'agent (`i18n.ts`). Les sources Playwright utilisées pour les instantanés se trouvent dans `packages/chobitsu/src/engine/vendor/playwright/`. Le build les regroupe depuis les sources dans `dist/sdk.js`.
|
|
157
|
+
|
|
158
|
+
## Build et tests
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
cd sdk
|
|
162
|
+
npm ci
|
|
163
|
+
npm run build # dist/sdk.js (IIFE, global RemoteWebviewDebugger, ES2017), dist/index.mjs + index.d.ts (module ES)
|
|
164
|
+
npm run typecheck
|
|
165
|
+
npm test # Playwright : WebKit (iPhone 15) + Chromium (Pixel 7)
|
|
166
|
+
npm run gateway # passerelle simulée locale : http://localhost:8787/demo/platform/?key=rwd_pk_demo
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Les tests utilisent `test/mock-gateway.mjs`, qui implémente le côté page du protocole (welcome, état de contrôle, RPC, présence ; jetons, codes de fermeture, niveaux, configuration distante, `agentLang`, approbation du rattachement) et sert `/v1/sdk.js`, les packs de langue sous `/v1/locales/` ainsi que la boutique de démonstration. Elle ne vérifie pas elle-même les niveaux : les tests mettent donc à l'épreuve le contrôle propre à la page. Les specs de `test/e2e/` s'exécutent avec un navigateur `zh-CN` et `agentLang: 'zh'` sauf indication contraire d'un test ; `i18n.spec.ts` couvre l'anglais, `locales.spec.ts` les autres packs de langue, le repli, les packs personnalisés, l'apparence et la mise en page de droite à gauche. Le test de coexistence charge eruda 3.4.3 et PageSpy 2.4.0 depuis jsdelivr : il nécessite donc un accès à Internet.
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<!-- i18n-source: d9a31993ea867d3ef7058e7d637886f38a6ee3e1 -->
|
|
2
|
+
[English](README.md) | [简体中文](README.zh-CN.md) | [繁體中文](README.zh-TW.md) | 日本語 | [한국어](README.ko.md) | [Español](README.es.md) | [Français](README.fr.md) | [Deutsch](README.de.md) | [Português (Brasil)](README.pt-BR.md) | [Русский](README.ru.md) | [العربية](README.ar.md)
|
|
3
|
+
|
|
4
|
+
# RWD ページ SDK(`sdk/`)
|
|
5
|
+
|
|
6
|
+
App WebView や H5 ページが読み込む 1 つの JS ファイルです。これにより、AI エージェントが RWD ゲートウェイ(`gateway/`)と MCP を通じてページを調べ、操作できるようになります。プロトコル:[`docs/protocol.ja.md`](../docs/protocol.ja.md)、アーキテクチャ:[`docs/architecture.ja.md`](../docs/architecture.ja.md)。
|
|
7
|
+
|
|
8
|
+
```html
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/remote-webview-debugger@0.1.0/dist/sdk.js"></script>
|
|
10
|
+
<script>
|
|
11
|
+
RemoteWebviewDebugger.run("https://rwd.example.com/v1", "rwd_pk_xxxxxxxx", {
|
|
12
|
+
userId: "u-42", // 任意
|
|
13
|
+
deviceId: "…", // 任意。SDK を注入するネイティブホストが渡す
|
|
14
|
+
helpButton: true, // 任意。「サポートを依頼」ボタンを表示する
|
|
15
|
+
app: { name: "Shop", version: "3.2.0" },
|
|
16
|
+
lang: "en", // 任意。言語タグ。デフォルトはブラウザの言語設定から
|
|
17
|
+
}).then(({ deviceCode, status }) => console.log(deviceCode, status))
|
|
18
|
+
</script>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## SDK の入手
|
|
22
|
+
|
|
23
|
+
npm に [`remote-webview-debugger`](https://www.npmjs.com/package/remote-webview-debugger) として公開されています。バージョンと変更点:[CHANGELOG](CHANGELOG.md)。
|
|
24
|
+
|
|
25
|
+
| 用途 | 入手先 |
|
|
26
|
+
|---|---|
|
|
27
|
+
| CDN からの `<script>` | `https://cdn.jsdelivr.net/npm/remote-webview-debugger@0.1.0/dist/sdk.js` または `https://unpkg.com/remote-webview-debugger@0.1.0/dist/sdk.js`(minify 済みの IIFE、グローバル変数 `RemoteWebviewDebugger`。バージョンを固定し、必要なら `integrity` を追加してください) |
|
|
28
|
+
| バンドラー | `npm install remote-webview-debugger` の後、`import { run, status } from 'remote-webview-debugger'`(型付きの ES モジュール)。取得を早く始められるよう、自分のコードより先に import してください。同じページで `<script>` 版を併せて読み込まないでください |
|
|
29
|
+
| 自分のゲートウェイ | `https://<gateway>/v1/sdk.js`。ゲートウェイが埋め込んでいるコピーです(SRI 用のコンテンツアドレス方式の URL もあり、管理コンソールが提示します) |
|
|
30
|
+
| ネイティブアプリ | パッケージの `dist/sdk.js` を同梱するか、上記のいずれかからダウンロードします。[ネイティブ統合](../docs/native-integration.ja.md)を参照してください |
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
| API | 説明 |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `run(gatewayUrl, appKey, opts?)` | ページをオンラインにします(デバイスコード、ピル)。`Promise<{deviceCode, status}>` を返し、再度呼んでも害はありません。オプションは後述します。 |
|
|
37
|
+
| `status()` | `{deviceCode, status, control, help, label, deviceId, pageId, version, lang, deviceToken, level, config, pending, logSession}`。`status` は `idle / connecting / online / polling / stopped / rejected / quota`、`lang` は UI の言語(`run()` の前は `null`)、`logSession` はこのページが書き込むセッションログ(記録していないときは `null`) |
|
|
38
|
+
| `stop()` | 切断して UI を取り除きます(console / ネットワークの収集は上限付きで続きます) |
|
|
39
|
+
| `setUser(userId)` | ユーザーを変更します。新しい `hello` で一度再接続します |
|
|
40
|
+
| `help(on)` | サポートを依頼 / 依頼を取り消す |
|
|
41
|
+
| `nativeControl(nativeKey, action)` | ネイティブホスト独自の UI から引き継ぐ / AI に戻す / 終了を行います |
|
|
42
|
+
| `nativeDecide(nativeKey, requestId, value)` | `nativeApproval` 使用時に `status().pending` に応答します。接続要求にはレベルまたは `null`、センシティブな操作の確認には `'allow'` または `null` |
|
|
43
|
+
| `setLang(lang?)` | 実行時に UI の言語を切り替えます(アプリ独自の言語設定など)。引数なしで呼ぶとブラウザの言語設定に戻ります。[言語](#言語)を参照 |
|
|
44
|
+
| `registerLocale(pack)` | 言語パックを追加するか、同じ `id` の言語パックを置き換えます(配列も渡せます)。[言語](#言語)を参照 |
|
|
45
|
+
| `builtinLocales` | 組み込みの言語パックの ID の一覧 |
|
|
46
|
+
|
|
47
|
+
`run()` のオプション:
|
|
48
|
+
|
|
49
|
+
| オプション | 説明 |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `userId` | サインイン中のユーザー。`hello` と一緒に送られます |
|
|
52
|
+
| `deviceId` | ネイティブホストからの安定したデバイス ID(指定しない場合は localStorage に保持されます) |
|
|
53
|
+
| `helpButton` | 「サポートを依頼」ボタンを表示します(プロジェクトのポリシーと OR を取ります) |
|
|
54
|
+
| `app` | ホストアプリの `{ name, version }` |
|
|
55
|
+
| `lang` | 端末のユーザーが目にするすべて(ピル、フローティングウィンドウ、下部バー、ダイアログ、トースト、eruda のタブ、センシティブな操作の「AI が … しようとしています」という説明)の言語:`'ja'` や `'pt-BR'` などの言語タグ。デフォルトはブラウザの言語設定です。[言語](#言語)を参照 |
|
|
56
|
+
| `locales` | 追加の言語パック。言語を選ぶ前に登録されます(`registerLocale` と同じ) |
|
|
57
|
+
| `messages` | 言語ごとに上書きするメッセージ:`{ en: { ui: { help: 'Contact support' } }, ja: { ui: { help: 'サポートに問い合わせる' } } }` |
|
|
58
|
+
| `networkExclude` | エージェントがかき分けて読まなくて済むようにしたいリクエスト。常に 404 になるフォントや解析用ビーコンなど:`['.ttf', 'WebTracks', '*beacon*', '/\\/track\\//']`。各ルールは URL に対して、大文字小文字を区別しない部分文字列、`*` ワイルドカードのパターン、または `/…/` と書いた場合は正規表現としてマッチします。プロジェクトのポリシーのルールに追加されます。マッチしたリクエストはネットワーク一覧からも `net_fail` タイムラインイベントからも除外されますが、ページは記録を続けるので、エージェントは `includeExcluded` で要求できます |
|
|
59
|
+
| `lockScreen` | `false`:エージェントの接続中もページをロックしません(ユーザーはフローティングウィンドウで変更できます)。デフォルトは `true` |
|
|
60
|
+
| `theme` | `'auto'`(デフォルト、ページの背景に従う)、`'system'`、`'light'`、`'dark'` |
|
|
61
|
+
| `style` | UI の色、フォント、角丸、z-index、位置:`{ accent: '#e11d48', radius: 12, zIndex: 1000, pill: { side: 'left' } }`。[スタイルのカスタマイズ](#スタイルのカスタマイズ)を参照 |
|
|
62
|
+
| `eruda` | `true` または `{ dock, load, src, name }`:Remote Debugger を eruda 内のタブとして表示します。`load` はページに eruda がない場合に最新の eruda を読み込みます。デフォルトはオフです。プロジェクトのポリシーでリモートからオンにでき、ローカルのオプションがフィールド単位で優先されます |
|
|
63
|
+
| `record` | `false`:このページはセッションログを書き込みません(保存済みの内容は削除されません)。デフォルトは `true`。プロジェクトのポリシーで全ページのログをオフにできます |
|
|
64
|
+
| `launchId` | このページがアプリのどの起動に属するか。1 つのアプリプロセスのすべての WebView が、セッションログを 1 つのセッションにまとめるために使います。ネイティブホストはここに独自の ID を渡します(または `window.RWDLaunchId` を文字列か、文字列を返す関数として定義します)。指定がなければ、SDK はセッション Cookie とハートビートから起動を推定します |
|
|
65
|
+
| `nativeKey`、`deviceToken`、`nativeApproval` | ネイティブホスト向け:`nativeControl` / `nativeDecide` 用のシークレット、ホストが保持するデバイストークン、接続 / 確認の問い合わせをネイティブで行うかどうか |
|
|
66
|
+
|
|
67
|
+
## 言語
|
|
68
|
+
|
|
69
|
+
組み込みの言語:英語(`en`)、簡体字中国語(`zh`)、繁体字中国語(`zh-TW`。`zh-HK`、`zh-MO`、`zh-Hant` にも使われます)、フランス語(`fr`)、スペイン語(`es`)、ロシア語(`ru`)、アラビア語(`ar`、右から左へのレイアウト)、日本語(`ja`)、韓国語(`ko`)、ドイツ語(`de`)、ポルトガル語(`pt`、ブラジルポルトガル語。`pt-PT` にも使われます)。
|
|
70
|
+
|
|
71
|
+
**言語の選び方。** 端末のユーザーの言語は、`run({ lang })` が指定されていればそれ、次に `navigator.languages` を順に見ます。SDK は各タグについて、そのタグ自体、次にそれを短くした形(`pt-BR` → `pt`、`zh-HK` → `zh-TW` → `zh`)を試し、言語パックがある最初の言語を使います。どれもなければ英語になります。言語パックに足りないメッセージも同じ順序でフォールバックするため、一部だけの言語パックでも問題ありません。`setLang('ja')` で実行時に切り替えられ、`status().lang` が使用中の言語パックです。
|
|
72
|
+
|
|
73
|
+
**読み込み。** 英語と簡体字中国語は `sdk.js` に含まれています。その他の言語パックは、ページで初めて必要になったときにオンデマンドで読み込まれます(その間、UI はフォールバック先の言語で表示されます):
|
|
74
|
+
|
|
75
|
+
- `<script>` 版:`sdk.js` と同じ場所にある `locales/<id>.js` から読み込みます(CDN のパス、例えば `…/remote-webview-debugger@0.1.0/dist/locales/ja.js`、または自分のゲートウェイの `/v1/locales/ja.js`)。失敗した場合は `run()` に渡したゲートウェイから読み込みます。この追加のリクエストを避けたい場合は、`sdk.js` の前でも後でもよいので言語パックを自分で読み込んでください:`<script src="…/dist/locales/ja.js"></script>`。
|
|
76
|
+
- ES モジュール版:動的 import を使うため、バンドラーは言語ごとに別のチャンクを作ります。最初からバンドルに含めたい場合は、`import ja from 'remote-webview-debugger/locales/ja'` とし、`run(url, key, { locales: [ja] })` に渡します。
|
|
77
|
+
|
|
78
|
+
**独自の言語パックと文言。** 言語パックは `{ id, name, dir?, ui?, action?, agent? }` です。省略した部分はフォールバック先の言語から取られます:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
RemoteWebviewDebugger.registerLocale({
|
|
82
|
+
id: 'it',
|
|
83
|
+
name: 'Italiano',
|
|
84
|
+
ui: { takeover: 'Prendi il controllo', end: 'Termina', help: 'Richiedi assistenza' /* … */ },
|
|
85
|
+
})
|
|
86
|
+
RemoteWebviewDebugger.run(url, key, {
|
|
87
|
+
messages: { ja: { ui: { help: 'サポートに問い合わせる' } } }, // 任意の言語の個別のメッセージを変更
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`ui` は UI のテキスト、`action` は確認ダイアログの「AI が … しようとしています」を補う部分、`agent` はエージェントに返すテキストです。TypeScript の型(`LocalePack`、`Messages`、`UiMessages`、`ActionMessages`、`AgentMessages`)にすべてのキーが列挙されています。基準は `src/locales/en.ts` です。
|
|
92
|
+
|
|
93
|
+
**2 種類の読み手。** 端末のユーザーには上記で選ばれた言語が使われます。エージェントが読む RPC のエラーメッセージとタイムラインの要約(タップ、ページ内遷移、失敗したリクエスト)はゲートウェイの言語 `welcome.agentLang`(`RWD_LANG`)になり、その言語パックも同じ方法で読み込まれます。welcome で指定されるまでは英語です。最後の値は localStorage の `rwd:alang` に保持されるため、次のページで welcome が届く前のイベントにもその値が使われます。
|
|
94
|
+
|
|
95
|
+
そのため、中国語話者のユーザーが英語で動くエージェントと協力できます。ダイアログは `AI 想要点击「提交订单」,允许吗?` と尋ね、拒否されればエージェントは `The user denied this action` を受け取ります。
|
|
96
|
+
|
|
97
|
+
## スタイルのカスタマイズ
|
|
98
|
+
|
|
99
|
+
UI は `#__rwd`(`<body>` の外)の Shadow DOM 内にあるため、ページの CSS は次の入口を通してしか影響しません:
|
|
100
|
+
|
|
101
|
+
- **CSS カスタムプロパティ**:`:root` または `#__rwd` に指定します。例:`:root { --rwd-accent-rgb: 225, 29, 72; --rwd-radius: 12px; }`。
|
|
102
|
+
- **`run({ style })`**:同じプロパティを `#__rwd` に設定します。ここでは色に任意の CSS カラーを使えます。
|
|
103
|
+
- **`::part()`**:それ以外のスタイルに使います:`#__rwd::part(bar) { … }`。パート:`pill`、`window`、`bar`、`task`、`dialog`、`toast`、`button`、`cursor`、`glow`、`overlay`。内部のクラス名は安定した API ではありません。
|
|
104
|
+
- **`theme`**:ライトまたはダークのガラス調(デフォルトはページの背景に従います)。
|
|
105
|
+
|
|
106
|
+
| プロパティ | `style` フィールド | デフォルト | 対象 |
|
|
107
|
+
|---|---|---|---|
|
|
108
|
+
| `--rwd-accent-rgb` | `accent` | `59, 130, 246` | ボタン、スイッチ、エージェントのポインター、ハイライト、縁の光 |
|
|
109
|
+
| `--rwd-danger-rgb` | `danger` | `239, 68, 68` | 「終了」ボタン |
|
|
110
|
+
| `--rwd-warning-rgb` | `warning` | `245, 158, 11` | 「サポートを依頼」と「対応中」、ユーザーが引き継ぎ中の状態 |
|
|
111
|
+
| `--rwd-success-rgb` | `success` | `34, 197, 94` | オンラインを示すドット、「コピー済み」 |
|
|
112
|
+
| `--rwd-font` | `font` | システムの UI フォント(中国語、日本語、韓国語は言語ごと) | すべてのテキスト |
|
|
113
|
+
| `--rwd-font-mono` | `monoFont` | `ui-monospace, "SF Mono", …` | デバイスコードとタグ |
|
|
114
|
+
| `--rwd-radius` | `radius` | `18px` | フローティングウィンドウ。ダイアログはこれより 2px 大きく、タスクカードとピルは 2px 小さく、ダイアログのボタンは 6px 小さくなります |
|
|
115
|
+
| `--rwd-button-radius` | `buttonRadius` | `999px` | ボタン、下部バー、トースト |
|
|
116
|
+
| `--rwd-z-index` | `zIndex` | `2147483647` | UI 全体 |
|
|
117
|
+
| `--rwd-bar-bottom` | `barBottom` | `14px` | 下部バー(下側のセーフエリアからの距離) |
|
|
118
|
+
| `--rwd-task-top` | `taskTop` | `10px` | タスクカード(上側のセーフエリアからの距離) |
|
|
119
|
+
| `--rwd-toast-bottom` | `toastBottom` | `84px` | トースト(下側のセーフエリアからの距離) |
|
|
120
|
+
| — | `pill: { side, top }` | 右端(右から左に書く言語では左端)、`0.62` | ユーザーがドラッグするまでの、待機中のピルの初期位置。`top` は 0(上端)から 1(下端) |
|
|
121
|
+
|
|
122
|
+
色を `r, g, b` の 3 つ組で書くのは、半透明の色合いもそれに合わせて変わるようにするためです(Bootstrap の `--bs-*-rgb` と同じ方式)。
|
|
123
|
+
|
|
124
|
+
## ページ内での動作(プロトコル §6–§8、§11)
|
|
125
|
+
|
|
126
|
+
- レベル:RPC は `welcome.level` / `control.level` に照らしてチェックされます(`forbidden`、「… レベルが必要です」)。レベルを持たないエージェント(古いゲートウェイ)は `interact` として扱われます。エージェントが接続していないときは、追加の制限は何もかかりません。
|
|
127
|
+
- デバイストークンは localStorage の `rwd:dtoken` に、再開トークンは sessionStorage の `rwd:resume`(pageId に紐付く)に保持されます。クローズコード 4401:その間にトークンが変わっていれば(同じデバイスの別のタブがちょうど取得した場合)すぐに一度再試行し、そうでなければ `rejected` となり約 10 分後に再試行します。4409:新しい pageId で再接続します。4429:`quota`、約 5 分後に再試行します。
|
|
128
|
+
- アドレスバーの `rwd_invite` は `run()` の時点で取り除かれ(`history.replaceState`)、welcome が届くまで hello と一緒に送られます。
|
|
129
|
+
- `welcome.config`:`helpButton`(`run()` のオプションと OR を取る)、`maskSelectors`、`maskPatterns`(スナップショット、console、ネットワークの URL、ストレージの値、タイムラインの要約)、`confirmSelectors`、`networkExclude`(`run()` のオプションのルールに追加)、`sessionLog`。最後の設定は localStorage の `rwd:cfg` に保持され、welcome が届くまで使われます。そのため、セッションログをオフにしたプロジェクトでは、次のページでも welcome が届く前の最初の瞬間からオフのままです。
|
|
130
|
+
- スナップショットの末尾には `[Overlays]` セクションがあり、ページの上に浮かぶもの(ポップアップの背景幕、モーダル、ボトムシート)を、タグ、短いテキスト、ビューポートを覆う割合、ref とともに列挙します。背景幕は aria snapshot にノードのない空の要素なので、`eN` ではなく `oN` の ref が付きます。これにより、エージェントは背景幕をタップしてポップアップを閉じられます。
|
|
131
|
+
- クリックはまず要素の見えている中心を狙い、次にその内側の 3×3 グリッドの他の位置を狙います。そのため、ボタンに重なったバッジがクリックを妨げることはありません。すべての位置が覆われている場合、RPC は `not_interactable` で失敗し、覆っている要素とその ref を示します。
|
|
132
|
+
- 接続とセンシティブな操作のダイアログ(`[data-rwd-confirm]`、`confirmSelectors`、Enter によるフォーム送信を含む)は Shadow DOM 内にあり、信頼されたタップだけを受け付け、表示から 0.4 秒後に有効になります。同じオリジンのタブは、決定済みの接続要求を BroadcastChannel で共有します。
|
|
133
|
+
|
|
134
|
+
ファイルを読み込むと、console、捕捉されないエラー、ネットワーク(XHR、fetch、WebSocket、sendBeacon、EventSource)の収集がそれぞれ最大 500 件まで始まります。いっぱいになると、通常のログと成功したリクエストから先に破棄されます。レスポンスボディは合計 5 MB、1 件あたり 64 KB までキャッシュされます。そのため、`<head>` の早い位置で同期的に読み込んでください。
|
|
135
|
+
|
|
136
|
+
## セッションログ(プロトコル §5.4)
|
|
137
|
+
|
|
138
|
+
これらのバッファは 1 つのページのメモリにすぎません。それと並行して、SDK は端末の IndexedDB(`rwd-log`)に**セッションログ**を書き込みます。これにより、バグの後に接続したエージェントも、バグに至るまでの経緯をすべて読めます:
|
|
139
|
+
|
|
140
|
+
- 1 つのセッションはアプリの 1 回の起動で、そのオリジンのすべてのページで共有されます:`run({ launchId })`、なければ `window.RWDLaunchId`、それもなければセッション Cookie `rwd_launch` とハートビートから推定します(Cookie セッションが 1 時間以上沈黙していれば新しい起動とみなします)。`status().logSession` が使用中の ID です。
|
|
141
|
+
- 記録内容:ページのオープン / ページ内遷移 / フォアグラウンドとバックグラウンドの切り替え / 離脱、ユーザーのタップ・入力・送信・スクロールの停止位置、エージェントの操作系の呼び出しと `rwd.evaluate`、制御状態の変化、すべてのレベルの console、そして完了したすべてのリクエスト(失敗したものは伏せ字処理済みのヘッダーとボディも、各 64 KB まで)。ゲートウェイに到達できるかどうかに関係なく動作します。マスク対象のフィールドは `••••` として保存され、`maskPatterns` は記録を書き込む時点で適用されます。
|
|
142
|
+
- 保持:直近 3 回の起動分、各 10 MB まで。それを超えると、通常のログと成功したリクエストから先に破棄されます。ストレージのクォータが 64 MB 未満の場合は現在の起動分のみ、IndexedDB がなければ何も保持しません。
|
|
143
|
+
- エージェントは `rwd.log`(`observe`)と `rwd.logDetail`(ヘッダーとボディ用、`advanced`)で読み取ります。それ以外の方法で端末の外に出ることはありません。
|
|
144
|
+
- 無効化:ページ単位なら `run({ record: false })`、プロジェクト全体なら `policy.sessionLog: false`。後者は、そのオリジンが保存済みの内容も削除します。
|
|
145
|
+
|
|
146
|
+
## 構成
|
|
147
|
+
|
|
148
|
+
- `src/index.ts`:公開 API、セッション、RPC のディスパッチ、制御状態。
|
|
149
|
+
- `src/transport.ts`:ページ WebSocket(ネイティブのコンストラクター)、ハートビートのタイムアウト、指数バックオフ、3 回失敗した後は 60 秒ごとの `POST /v1/presence`。
|
|
150
|
+
- `src/ids.ts`:deviceId / pageId / openerId。
|
|
151
|
+
- `src/launch.ts`:このページがアプリのどの起動に属するか(`launchId`、`window.RWDLaunchId`、`rwd_launch` Cookie)。
|
|
152
|
+
- `src/pageWatch.ts`:`page` メッセージ(URL、タイトル、可視状態)とタイムラインイベント(ページ内遷移、ユーザーのタップ)。
|
|
153
|
+
- `src/ui.ts`、`src/lock.ts`:Shadow DOM 内のピル、「サポートを依頼」ボタン、ロック用オーバーレイ、光る縁、操作のハイライト、ダイアログ。エージェントの接続中はユーザーの信頼された入力をブロックし、接続時間を表示します。
|
|
154
|
+
- `src/approval.ts`:接続承認とセンシティブな操作の確認(ページのダイアログ、または `nativeDecide` 経由のネイティブホスト)。
|
|
155
|
+
- `src/i18n.ts`、`src/locales/`、`src/localeLoader*.ts`:言語パック(言語ごとの UI、操作、エージェント向けのテキスト)、言語の選択とフォールバック、オンデマンドの読み込み。`scripts/locales.mjs` が `dist/locales/<id>.js` をビルドします。
|
|
156
|
+
- エージェント側のエンジンは chobitsu と並んで `packages/chobitsu/src/engine/rwd/` にあります:スナップショット、`rwd.query`、操作可能性のチェック、合成入力、キーボード、console / ネットワークのバッファ、スクリーンショット、`rwd.storage`、IndexedDB 上のセッションログ(`coldlog.ts`)、オーバーレイの検出(`overlays.ts`)、レベルと確認のルール(`policy.ts`)、エージェント向けのテキスト(`i18n.ts`)。スナップショットに使う Playwright のソースは `packages/chobitsu/src/engine/vendor/playwright/` にあります。ビルド時にこれらをソースから `dist/sdk.js` にバンドルします。
|
|
157
|
+
|
|
158
|
+
## ビルドとテスト
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
cd sdk
|
|
162
|
+
npm ci
|
|
163
|
+
npm run build # dist/sdk.js(IIFE、グローバル RemoteWebviewDebugger、ES2017)、dist/index.mjs + index.d.ts(ES モジュール)
|
|
164
|
+
npm run typecheck
|
|
165
|
+
npm test # Playwright:WebKit(iPhone 15)+ Chromium(Pixel 7)
|
|
166
|
+
npm run gateway # ローカルのモックゲートウェイ:http://localhost:8787/demo/platform/?key=rwd_pk_demo
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
テストは `test/mock-gateway.mjs` を使います。これはプロトコルのページ側(welcome、制御状態、RPC、presence、トークン、クローズコード、レベル、リモート設定、`agentLang`、接続承認)を実装し、`/v1/sdk.js`、`/v1/locales/` 以下の言語パック、デモショップを配信します。モック自体はレベルをチェックしないため、テストではページ側の強制が検証されます。`test/e2e/` のスペックは、テストで別途指定しない限り `zh-CN` のブラウザと `agentLang: 'zh'` で実行されます。英語は `i18n.spec.ts` が、その他の言語パック、フォールバック、独自の言語パック、スタイル、右から左へのレイアウトは `locales.spec.ts` がカバーします。共存テストは jsdelivr から eruda 3.4.3 と PageSpy 2.4.0 を読み込むため、インターネット接続が必要です。
|