Permisos y ciclo de vida de puertos con Web Serial API
Solicita Web Serial mediante una acción, separa permiso y disponibilidad, limita streams, gestiona desconexiones y conserva una alternativa segura.
BotBrowser Team
Quieres la documentación estructurada de Plataforma?
Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.
Web Serial permite solicitar un puerto elegido por la persona, pero el selector no es una conexión, un periférico confiable ni prueba de propiedad. BotBrowser puede probar las ramas de permiso y alternativa de la página en un contexto controlado; no fabrica un dispositivo serial, concede permiso del sistema fuera del navegador ni demuestra E/S física. El contrato es explícito: pedir tras una acción, abrir solo un puerto compatible, limitar cada trama, cancelar y cerrar streams al desconectar y mantener la tarea útil sin hardware serial.
TL;DR
navigator.serial.requestPort({ filters: [{ usbVendorId: 0x2341 }] })necesita contexto seguro y activación transitoria del usuario.- Un
SerialPortseleccionado es una capacidad del origen; no demuestra que esté abierto, conectado, sea seguro o use el protocolo correcto. - Llama
port.open({ baudRate: 115200 })con configuración revisada y valida tramas decodificadas antes de cambiar el estado. - Los eventos
connectydisconnectmuestran cambios visibles para el navegador; cancela readers, libera locks, cierra el puerto y conserva los borradores. - Guarda
granted,unsupported,invalid-frameodisconnected, no números de serie, buffers crudos ni identidad inferida.
Contenido
- Preguntar en el punto de uso
- Separar permiso y disponibilidad del puerto
- Limitar streams legibles y escribibles
- Coordinar connect y disconnect
- Minimizar metadatos y conservar una alternativa
- Clasificar resultados con una tabla
- Capacidad y límite de BotBrowser
- Conclusión práctica
Preguntar en el punto de uso
Web Serial está limitado a contextos seguros y requestPort() debe ejecutarse durante activación transitoria. Coloca la petición detrás de un control con nombre claro. Detectar navigator.serial solo indica que existe; no abre el selector ni concede acceso. Una política de iframe, configuración administrada, plataforma no compatible o regla del sistema puede impedirla.
async function connectSerial() {
if (!window.isSecureContext || !navigator.serial) return showSerialState('unsupported');
setSerialState('requesting');
try {
const port = await navigator.serial.requestPort({
filters: [{ usbVendorId: 0x2341 }],
});
await openSelectedPort(port);
} catch (error) {
showSerialState(error.name === 'NotFoundError' ? 'cancelled' : 'denied');
}
}
connectButton.addEventListener('click', connectSerial);
No abras el selector al cargar ni repitas tras cancelar. Conserva el borrador y ofrece otro intento después de una acción nueva. Acceso WebUSB: permisos, interfaces y privacidad separa concesión y preparación de sesión. Permisos WebHID y límites de privacidad del dispositivo aplica la misma frontera a los informes. Huella de permisos del navegador explica por qué un estado no concede acceso ni identifica a una persona.
Separar permiso y disponibilidad del puerto
requestPort() devuelve el SerialPort elegido por el navegador. No significa que siga conectado, que acepte la velocidad, que hable el protocolo previsto ni que una escritura llegue a un actuador. Trata selección, apertura, lectura, escritura y cierre como estados distintos.
Antes de open(), decide baudRate, dataBits, stopBits, parity y flowControl soportados. Mantén la tupla documentada y estrecha. Abrir con framing incorrecto puede producir bytes plausibles pero inválidos; la validación debe ocurrir después del decoder.
async function openSelectedPort(port) {
try {
await port.open({ baudRate: 115200, dataBits: 8, stopBits: 1, parity: 'none' });
setSerialState('opened');
await readSerialFrames(port);
} catch (error) {
showSerialState('unsupported');
await closeSerialPort(port);
}
}
navigator.serial.getPorts() puede devolver puertos concedidos antes al origen, pero no es inventario completo ni reemplaza un control de reconexión. Vuelve a comprobar el puerto y el protocolo; no elijas silenciosamente el primero porque un label coincida.
La especificación Web Serial define el modelo de puerto y streams. MDN Web Serial API documenta disponibilidad. Ninguna fuente convierte el puerto en identidad, ubicación, propiedad o prueba de funcionamiento físico.
Limitar streams legibles y escribibles
port.readable y port.writable son streams asíncronos. Trata los bytes como entrada no confiable. Usa decoder con tamaño máximo, delimitador o longitud, checksum cuando el protocolo lo defina y timeout para tramas incompletas. Rechaza antes de cambiar el estado.
const MAX_FRAME_BYTES = 128;
async function readSerialFrames(port) {
const reader = port.readable.getReader();
const decoder = new Uint8Array();
try {
while (true) {
const { value, done } = await reader.read();
if (done) break;
if (value.byteLength > MAX_FRAME_BYTES) {
showSerialState('invalid-frame');
continue;
}
acceptBoundedFrame(value);
}
} finally {
reader.releaseLock();
}
}
El ejemplo mantiene visible el límite; un decoder real debe guardar parciales y limitar el buffer total. No registres cada byte ni envíes una trama arbitraria a un intérprete. Clasifica invalid-length, invalid-checksum o timeout sin retener contenido crudo.
Para escribir, adquiere port.writable.getWriter() solo durante la operación, valida la trama y libera el writer en finally. Un writer.write() resuelto solo prueba que el navegador aceptó bytes; no demuestra que un instrumento se movió o que otra aplicación los recibió. En una escritura incierta, conserva el formulario y exige reintento explícito.
Cancela el reader antes de cerrar el puerto. Si el stream está bloqueado, port.close() puede esperar o rechazar hasta liberar el lock. El dueño de cada tarea debe invalidar su token al navegar o desconectar y evitar que una lectura tardía pinte la alternativa como conectada.
Coordinar connect y disconnect
Escucha navigator.serial.addEventListener('connect', ...) y disconnect. connect significa que el navegador observó un puerto disponible, no que pueda abrir un selector silencioso ni que coincida con la tarea. disconnect confirma retirada observada, no su causa.
Al desconectar, marca la tarea terminal, cancela reader, libera writer, llama port.close() de forma tolerante, quita listeners, conserva datos y muestra reconexión. No reconectes ni reenvíes automáticamente: una orden pudo entregarse parcialmente.
Usa estados idle, requesting, selected, opening, opened, reading, invalid-frame, disconnected, cancelled y fallback. Cada estado necesita mensaje, siguiente acción y regla de retención. Al volver un puerto, exige acción nueva, repite configuración y handshake, y separa label elegido de usbVendorId, usbProductId, serialNumber o getInfo().
Minimizar metadatos y conservar una alternativa
Separa permiso del navegador, sesión serial, consentimiento del protocolo y subida remota. Leer un sensor localmente no autoriza enviar datos. Explica los campos que salen, pide una decisión separada y permite terminar localmente si se rechaza la sincronización.
Un registro necesita normalmente unsupported, denied, cancelled, opened, invalid-frame, disconnected o fallback, más fecha y entorno. Rara vez necesita SerialPort.getInfo(), identificadores USB, fabricante, buffers crudos o historial largo. Un diagnóstico debe ser breve, visible, controlado y eliminado.
Conserva entrada manual, importación, valor simulado o configuración estática. Mantén datos, foco, validación y recuperación sin puerto vivo. No hagas depender login, facturación, recuperación, instrucciones de seguridad ni contenido obligatorio de un dispositivo serial.
Clasificar resultados con una tabla
| Etapa observada | Qué establece | Siguiente acción segura |
|---|---|---|
| API ausente, contexto inseguro o política | Web Serial no puede iniciar aquí | Mantener tarea sin serial y explicar el límite |
| Selector cancelado o permiso denegado | No hay concesión utilizable | Conservar borrador y esperar acción explícita |
Puerto elegido pero open() rechaza | No se obtuvo sesión utilizable | Mostrar ajustes, cerrar y no ampliar acceso |
| Reader informa trama inválida | La entrada falló el protocolo | Descartar, registrar categoría y continuar |
Evento disconnect | El navegador observó retirada | Cancelar streams, cerrar, conservar y ofrecer reintento |
| Trama válida y limitada | Se aceptó un valor | Informar solo ese valor; no inferir efecto físico |
Cada fila debe terminar en estado comprensible. El selector no es conexión, un stream abierto no es protocolo confiable y una trama válida no prueba una acción física.
Capacidad y límite de BotBrowser
Los contextos controlados de BotBrowser pueden verificar el botón, la detección, el resultado del selector, la validación de tramas, la limpieza al desconectar y la alternativa sin serial. La documentación de funciones avanzadas describe capacidades revisables. Sigue siendo evidencia de página: BotBrowser no proporciona periférico serial, no concede permiso del sistema, no garantiza un puerto ni demuestra que bytes cambien hardware. BotBrowser valida estados visibles de navigator.serial y la alternativa en un contexto controlado; no valida una operación eléctrica de un periférico real.
{
"api": "navigator.serial",
"permission": "denied",
"portState": "fallback",
"framesAccepted": 0,
"rawIdentifiersRetained": false,
"physicalDevice": "not-asserted"
}
Repite el fixture al cambiar navegador, política, permiso, configuración, trama simulada o desconexión. Compara la primera divergencia visible sin prometer hardware universal.
Fuentes
Conclusión práctica
Usa una acción explícita, separa permiso de apertura y streams, valida cada trama y cancela readers antes de cerrar tras desconectar. Conserva la tarea sin hardware serial y registra la etapa del fallo, no metadatos del puerto. Repite el fixture tras cambios de navegador, política, driver, firmware o permiso; un resultado de página no promete comportamiento físico.
Este artículo forma parte de la guía: Superficies de la plataforma web: mapa de revisión
Artículos Relacionados
Permisos WebHID y límites de privacidad del dispositivo
PlataformaWeb MIDI API: permisos y privacidad del dispositivo
IdentidadAcceso a dispositivos WebUSB: permisos, interfaces y privacidad
PlataformaWeb Share API: límites de permisos y respaldos seguros
PlataformaWindow Management API: límites entre varias pantallas
PlataformaPresentation API: límites de pantalla y sesión
Lleva BotBrowser de la investigación a producción
Usa estas guías para entender el modelo y después avanzar hacia validación multiplataforma, contextos aislados y despliegue de navegador preparado para escalar.