Saltar al contenido principal
Version: Guardian v0.1.0

Paquete NPM

@surtai/guardian-web · v0.3.1

El SDK @surtai/guardian-web ejecuta el flujo collect() de Guardian en cualquier navegador moderno. Recopila señales del dispositivo, las cifra localmente y devuelve un payload opaco que tu backend envía al endpoint de evaluación de Surt. El SDK no realiza llamadas de red y no maneja ninguna clave de API, con una excepción: cuando pasas un geolocationJwt opcional, collect() realiza una única llamada GET /geolocation/client-ip en modo best-effort para resolver la IP pública del navegador e incrustarla en el payload. Sin geolocationJwt, collect() realiza cero llamadas de red. El JWT es un token de corta duración generado por tu backend, no una clave de API, así que sigue sin haber ninguna clave de API en el navegador.

npm install @surtai/guardian-web
Web es solo collect

A diferencia de los SDKs nativos (iOS / Android / React Native), el SDK web no expone un método verify(). Todas las decisiones de riesgo ocurren del lado del servidor una vez que tu backend reenvía el payload. Consulta Collect (Servidor a servidor) para el flujo completo del backend.

Uso

TypeScript
import { collect } from '@surtai/guardian-web';

// Variante 1: sin búsqueda de IP, cero llamadas de red.
const { payload } = await collect({ collectLocation: false });

// Variante 2: resuelve la IP pública del navegador dentro del payload.
// Tu backend genera el JWT de corta duración mediante preflight.
const { payload: payloadWithIp } = await collect({
collectLocation: false,
geolocationJwt: jwt,
});

// Reenvía el payload a tu backend.
await fetch('https://your-api.com/verify-device', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId: 'user_123', payload }),
});

Tu backend genera el geolocationJwt llamando a preflight con tu clave sp_live_*; consulta Autenticación. Pasa el JWT a collect() solo cuando quieras resolver la IP pública; de lo contrario, omítelo.

Opciones

OpciónTipoRequeridaPredeterminadoDescripción
collectLocationbooleanNofalseCuando es true, solicita la API de Geolocalización del navegador. Es lo único en collect() que puede activar un aviso de permiso.
geolocationJwtstringNo(ninguno)Cuando se proporciona, collect() resuelve la IP pública del navegador mediante GET /geolocation/client-ip y la incrusta en el payload. Omítelo para saltarte la búsqueda de IP (y todas las llamadas de red).

CollectResult

interface CollectResult {
/** Payload en base64. Pásalo como `payload.data` en la solicitud evaluate mostrada a continuación. */
payload: string;
}

Backend: reenviar a Surt

Tu backend recibe el payload del navegador y lo envía al endpoint de evaluación de Surt:

POST https://api.surt.com/geolocation/transactions/evaluate
Content-Type: application/json
Authorization: Bearer YOUR_SURT_API_KEY
{
"customer_id": "user_123",
"transaction_type": "login",
"transaction_name": "Sign in",
"payload": {
"type": "encrypted",
"data": "<payload de collect()>"
},
"config": {
"response": {
"address": { "type": "include" }
}
}
}

La forma de la solicitud, los valores admitidos de transaction_type, las opciones de config y el esquema de respuesta son idénticos en todos los SDKs de Guardian. Consulta Collect (Servidor a servidor) para la referencia completa, incluyendo ejemplos de Node / Java / Python.

Errores

collect() lanza un único GuardianError en tres condiciones:

import { collect, GuardianError } from '@surtai/guardian-web';

try {
const { payload } = await collect();
} catch (err) {
if (err instanceof GuardianError) {
switch (err.code) {
case 'CRYPTO_UNAVAILABLE': /* no está en un contexto seguro */ break;
case 'ENCRYPTION_FAILED': /* el cifrado falló (raro) */ break;
case 'INVALID_OPTIONS': /* argumentos inválidos */ break;
}
}
}
CódigoSignificado
CRYPTO_UNAVAILABLEFalta window.crypto.subtle. El SDK requiere un contexto seguro (HTTPS o localhost).
ENCRYPTION_FAILEDEl paso de cifrado falló. Trátalo como un bug: captura y reporta.
INVALID_OPTIONSEl argumento de collect() no es un objeto.

Los recolectores individuales (huella digital, batería, geolocalización, red, etc.) nunca lanzan: fallan silenciosamente. Un permiso revocado o una API no compatible solo significa que el campo correspondiente se omite del payload. La búsqueda de IP pública también es best-effort: si la llamada GET /geolocation/client-ip falla o el JWT es rechazado, el campo de IP simplemente se omite y collect() igual devuelve un payload. El backend tolera payloads incompletos.

Compatibilidad de navegadores

  • Cualquier navegador moderno con window.crypto.subtle (Chrome, Edge, Firefox, Safari, Opera).
  • Contexto seguro requerido: HTTPS en producción, localhost para desarrollo. El SDK lanza CRYPTO_UNAVAILABLE fuera de un contexto seguro.
  • Geolocalización, Battery Status, NetworkInformation y otras APIs opcionales degradan con elegancia cuando no están disponibles.

Ejemplos de frameworks

VerifyButton.tsx
import { useState } from 'react';
import { collect } from '@surtai/guardian-web';

export function VerifyButton({ userId }: { userId: string }) {
const [loading, setLoading] = useState(false);

const handleClick = async () => {
setLoading(true);
try {
const { payload } = await collect({ collectLocation: false });
await fetch('/api/verify-device', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userId, payload }),
});
} finally {
setLoading(false);
}
};

return (
<button onClick={handleClick} disabled={loading}>
{loading ? 'Verificando...' : 'Continuar'}
</button>
);
}

Diferencias con los SDKs nativos

@surtai/guardian-web@surtai/guardian-rn / iOS / Android
Método verify()No
Método collect()Sí (única API)
Inicialización a nivel de aplicaciónNingunainitialize(options)
Contexto de cliente / transacciónEstablecido por tu backendIncluido en los claims del JWT generado por el backend
Clave de API en el clienteNoNo (usa un JWT generado por el backend, no una clave de API)
Llamadas de red desde el SDKNinguna (a menos que se pase geolocationJwt)
Verificación de integridad del dispositivoNo (sin equivalente en el navegador)
Estado por cliente persistenteNo (sin estado entre llamadas)No

Web es deliberadamente minimalista: una única función estática que produce un payload cifrado. El vínculo con el cliente, los metadatos de la transacción y las decisiones ocurren todos en tu backend.

Diagnósticos del resultado

El resultado de collect() ahora incluye un objeto opcional diagnostics con lo que observó el SDK durante la transacción: location (collected · denied · unavailable · timeout · not_requested), networkIntel (collected · unavailable) y warnings (lista de { code, signal }).

const { diagnostics } = await collect();
if (diagnostics?.location === 'denied') {
// pide al usuario que active la ubicación
}

Consulta Códigos de error para la referencia completa.