npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dynamicore/jumio-sdk

v1.0.3

Published

Librería modular y tipada para la validación de identidad e INE con Jumio en aplicaciones DynamiCore.

Readme

@dynamicore/jumio-sdk

SDK modular, tipado y agnóstico para la validación de identidad mediante Jumio en el ecosistema DynamiCore. Soporta tanto el flujo de Hosted Webflow (Redirección Web) como el de Carga Directa de Documentos (INE API).

TypeScript React Dual ESM/CJS License: MIT

[!IMPORTANT] Para poder utilizar esta librería, la compañía debe tener habilitado el módulo de Jumio desde el backend. Si el módulo no está habilitado para la compañía, la integración no estará disponible aunque el SDK esté instalado y configurado correctamente.


🌟 Modalidades de Verificación Soportadas

| Característica | 🌐 1. Hosted Webflow (Redirección) | 📄 2. Carga Directa (INE API) | | :--- | :--- | :--- | | Experiencia de Usuario | El usuario es redirigido a la interfaz alojada oficial de Jumio para captura biométrica y de documentos. | El usuario permanece en tu app; tu interfaz captura/sube las imágenes de la INE. | | Casos de Uso | Panel web, onboarding sin cámara nativa, verificación biométrica completa + Liveness. | Formularios web/móviles integrados con controles de archivo personalizados. | | Entrada Requerida | clientId, successUrl, errorUrl | clientId, frontImage, backImage | | Hooks de React | useJumioWebflow | useJumioVerification | | Métodos de Core | startWebflow, getWebflowStatus, pollWebflowStatus, parseWebflowReturnParams, buildRedirectUrl | startIneVerification, getIneStatus, verifyIne, pollIneStatus |


📦 Instalación

Desde npm / registro privado:

npm install @dynamicore/jumio-sdk
# o con pnpm / yarn:
pnpm add @dynamicore/jumio-sdk

axios ya viene como dependencia del SDK; no necesitas instalarlo por separado.

En proyectos locales (Monorepo o enlace local):

npm install file:../jumio-sdk

🚀 Guías y Ejemplos de Uso


clientId: global o por llamada

Configura un clientId global al crear JumioClient o un hook (junto a context y authToken) para reutilizarlo en todas las operaciones. También puedes pasarlo en cada llamada a startIneVerification, getIneStatus, pollIneStatus, verifyIne, startWebflow, getWebflowStatus, pollWebflowStatus o sendToPii.

El valor por llamada tiene prioridad sobre el global y solo aplica a esa operación; no modifica la configuración del cliente o hook.

const jumio = new JumioClient({ clientId: "global-123", authToken });

await jumio.startWebflow({
  clientId: "solo-esta-sesion-456", // override temporal
  successUrl,
  errorUrl,
});

🌐 Servicio 1: Hosted Webflow (Redirección Web)

En este flujo, la app solicita una sesión webflow, redirige al cliente a Jumio (href) y consulta el veredicto al regresar.

[!NOTE] Llegar a successUrl solo significa que el usuario completó los pasos en Jumio, no que fue aprobado. Llegar a errorUrl significa que abandonó o falló el flujo. El veredicto real (PASSED / WARNING / REJECTED + extraction) solo se obtiene consultando el estado con accountId + workflowId (getWebflowStatus una vez, o pollWebflowStatus con sondeo). Por eso ambos suelen apuntar a la misma ruta /verify/return.

A. Ejemplo con React / Next.js (useJumioWebflow)

Paso 1: Iniciar la verificación (Pantalla de Inicio)

import React from "react";
import { useJumioWebflow } from "@dynamicore/jumio-sdk/react";

export function StartIdentityVerification() {
  const { startWebflow, isStarting, error } = useJumioWebflow({
    clientId: "usr_123", // default para este hook; por llamada hace override
    context: process.env.NEXT_PUBLIC_DYNAMICORE_CONTEXT,
    authToken: () => getAuthTokenFromSession(), // requerido: sin token hay 403
    // La URL base, el endpoint y el proxy de redirección son constantes
    // internas del SDK (ver JUMIO_BASE_URL, JUMIO_ENDPOINT,
    // JUMIO_REDIRECT_PROXY_URL) y no se configuran aquí.
  });

  const handleStart = async () => {
    try {
      const baseUrl = window.location.origin;
      await startWebflow({
        successUrl: `${baseUrl}/verify/return`,
        errorUrl: `${baseUrl}/verify/return`,
        // Las URLs siempre viajan por el proxy interno (Base64 URL-safe).
        // En navegador el SDK redirige a Jumio automáticamente (misma pestaña).
        // clientId aquí haría override del default si se necesita
      });

    } catch (err) {
      console.error("Error al iniciar verificación:", err);
    }
  };

  return (
    <div>
      <h3>Verificación de Identidad</h3>
      {error && <p style={{ color: "red" }}>{error.message}</p>}
      <button onClick={handleStart} disabled={isStarting}>
        {isStarting ? "Cargando..." : "Iniciar Verificación con Jumio"}
      </button>
    </div>
  );
}

Paso 2: Procesar el retorno (Pantalla /verify/return)

import React, { useEffect } from "react";
import { useJumioWebflow } from "@dynamicore/jumio-sdk/react";

export function IdentityReturnPage() {
  const { parseReturnParams, checkResult, cancel, isChecking, result, isValid, isRejected, error } =
    useJumioWebflow({
      clientId: "usr_123",
      context: process.env.NEXT_PUBLIC_DYNAMICORE_CONTEXT,
      authToken: () => getAuthTokenFromSession(), // requerido: sin token hay 403
      onResult: (res) => {
        if (res.valid) {
          console.log("¡Verificación aprobada!", res.extraction);
        }
      },
    });

  useEffect(() => {
    // 1. Extraer accountId y workflowId de los query params de la URL
    const { accountId, workflowId } = parseReturnParams();

    if (accountId && workflowId) {
      // 2. Sondear el resultado final (acepta { maxAttempts, pollingIntervalMs, signal })
      // Para una sola consulta sin sondeo: await client.getWebflowStatus({ accountId, workflowId })
      // Retorna null si aún está pendiente. clientId viene del default del hook
      checkResult({ accountId, workflowId });
    }
    return () => cancel(); // Limpia el sondeo si el componente se desmonta (abort resetea isChecking)
  }, []);

  if (isChecking) {
    return <p>Verificando identidad, por favor espera un momento...</p>;
  }

  if (isValid) {
    return (
      <div>
        <h2>✅ Verificación Completada</h2>
        <p>CURP Extraída: {String(result?.extraction?.curp || "N/A")}</p>
      </div>
    );
  }

  if (isRejected || error) {
    return (
      <div>
        <h2>❌ Verificación No Aprobada</h2>
        <p>{error?.message || "El documento fue rechazado."}</p>
      </div>
    );
  }

  return <p>Cargando información de la sesión...</p>;
}

B. Ejemplo con TypeScript / Node.js (JumioClient)

import { JumioClient } from "@dynamicore/jumio-sdk";

const jumio = new JumioClient({
  clientId: "usr_123",
  context: "MI_CONTEXTO_NEGOCIO",
  authToken: () => getAuthTokenFromSession(),
  // baseUrl, endpoint y proxy de redirección son constantes internas del SDK.
});

// 1. Solicitar la URL de verificación
async function initVerificationSession() {
  const { href, accountId, workflowId } = await jumio.startWebflow({
    successUrl: "https://myapp.com/identity/callback",
    errorUrl: "https://myapp.com/identity/callback",
    // clientId aquí haría override del default si se necesita
  });

  console.log("Redirigir cliente a:", href);
  return { href, accountId, workflowId };
}

// 2. Consultar o sonder el resultado al regresar
async function verifyReturnStatus(returnUrl: string) {
  const { accountId, workflowId } = jumio.parseWebflowReturnParams(returnUrl);

  if (!accountId || !workflowId) {
    throw new Error("No se encontraron parámetros de seguimiento en la URL.");
  }

  const result = await jumio.pollWebflowStatus(
    { accountId, workflowId }, // usa el clientId global del cliente
    { maxAttempts: 15, pollingIntervalMs: 5000 }
  );

  if (result.valid) {
    console.log("Veredicto APROBADO:", result.extraction);
  } else {
    console.warn("Veredicto RECHAZADO:", result.errorMessage);
  }

  return result;
}

📄 Servicio 2: Carga Directa de INE (INE API)

En este flujo, la app captura las imágenes de la INE (frente y reverso) en su propia interfaz y las envía directamente al backend.

A. Ejemplo con React / Next.js (useJumioVerification)

import React, { useState } from "react";
import { useJumioVerification } from "@dynamicore/jumio-sdk/react";

export function DirectIneVerificationStep({ onNext }: { onNext: () => void }) {
  const [frontFile, setFrontFile] = useState<File | null>(null);
  const [backFile, setBackFile] = useState<File | null>(null);

  const { verify, isSubmitting, isPolling, isLoading, stage, progress, error } =
    useJumioVerification({
      clientId: "usr_123", // default para todas las verificaciones de este hook
      context: process.env.NEXT_PUBLIC_DYNAMICORE_CONTEXT,
      authToken: () => getAuthTokenFromSession(), // requerido: sin token hay 403
      onStatusResolved: (res) => {
        if (res.valid) {
          onNext();
        }
      },
    });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!frontFile || !backFile) return;

    await verify({
      frontImage: frontFile,
      backImage: backFile,
      awaitFinalStatus: false, // Sondeo en 2do plano sin bloquear la UI
      // clientId aquí haría override del default si se necesita
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="file" accept="image/*" onChange={(e) => setFrontFile(e.target.files?.[0] || null)} />
      <input type="file" accept="image/*" onChange={(e) => setBackFile(e.target.files?.[0] || null)} />

      {isLoading && <p>Estado: {stage} ({progress}%)</p>}
      {error && <p style={{ color: "red" }}>{error.message}</p>}

      <button type="submit" disabled={isLoading || !frontFile || !backFile}>
        Continuar
      </button>
    </form>
  );
}

B. Ejemplo con TypeScript / Node.js (JumioClient.verifyIne)

import { JumioClient, isJumioError } from "@dynamicore/jumio-sdk";

const jumio = new JumioClient({
  clientId: "usr_987654",
  context: "MI_CONTEXTO_NEGOCIO",
  authToken: () => getAuthTokenFromSession(),
});

async function runDirectVerification() {
  try {
    const result = await jumio.verifyIne({
      frontImage: "https://my-bucket.s3.amazonaws.com/uploads/ine_front.jpg",
      backImage: "https://my-bucket.s3.amazonaws.com/uploads/ine_back.jpg",
      awaitFinalStatus: true,
      // clientId aquí haría override del default si se necesita
    });

    if (result.valid) {
      console.log("INE validada con éxito:", result.data);
    } else {
      console.warn("INE rechazada:", result.errorMessage);
    }
  } catch (error) {
    if (isJumioError(error)) {
      console.error(`Error Jumio [${error.code}]:`, error.message);
    }
  }
}

🛠️ Opciones de Configuración (JumioClientConfig)

| Parámetro | Tipo | Por defecto | Descripción | | :--- | :--- | :--- | :--- | | clientId | string | undefined | Identificador por defecto del cliente a verificar. Si se define aquí, verifyIne, startIneVerification, getIneStatus, pollIneStatus, startWebflow, getWebflowStatus, pollWebflowStatus y sendToPii pueden omitir clientId (fallback). Un clientId por llamada hace override. | | context | string | undefined | Header de contexto enviado en las peticiones. | | authToken | string \| Provider | — (requerido) | Token Bearer o función proveedora dinámica. Sin token el backend responde 403 (el SDK lanza JumioValidationError antes de la petición). | | authTokenPrefix | string | "" | Prefijo del header Authorization (ej. "Bearer"). | | requestTimeout | number | 180000 (3 min) | Timeout para peticiones POST. | | statusTimeout | number | 120000 (2 min) | Timeout para peticiones GET de estado. | | maxRetries | number | 3 | Número de reintentos ante caídas de red. | | retryDelayMs | number | 800 | Delay base del backoff exponencial entre reintentos. | | pollingIntervalMs | number | 10000 (10s) | Intervalo entre consultas de sondeo. | | maxPollingAttempts | number | 20 | Máximo de consultas de sondeo antes de timeout. | | s3Signer | S3SignerFunction | undefined | Función para firmar rutas privadas de S3. | | customHeaders | Record<string,string> | undefined | Headers adicionales en cada petición. | | axiosInstance | AxiosInstance | undefined | Instancia propia de Axios (opcional). |

🔒 Constantes internas (no configurables)

La URL base, el endpoint y el proxy de redirección siempre apuntan a la infraestructura de DynamiCore y no forman parte de JumioClientConfig a propósito. Se exportan solo como referencia:

import {
  JUMIO_BASE_URL,           // "https://front.dynamicore.io"
  JUMIO_ENDPOINT,           // "/marketplace/apps/jumio"
  JUMIO_REDIRECT_PROXY_URL, // "https://inllhuznm2.execute-api.us-west-2.amazonaws.com/prod/jumio/redirect/"
} from "@dynamicore/jumio-sdk";

startWebflow siempre envía las URLs de retorno por el proxy interno (JUMIO_REDIRECT_PROXY_URL, Base64 URL-safe).


🧰 Helpers y notas del flujo Webflow

  • client.buildRedirectUrl(returnUrl) / buildRedirectUrl(url, proxy) — construye la URL de retorno codificada en Base64 URL-safe contra el proxy interno (JUMIO_REDIRECT_PROXY_URL). La función pura acepta un proxy custom como 2do argumento.
  • client.getWebflowStatus({ accountId, workflowId, clientId }) — una sola consulta GET ?type=ine&accountId&workflowId&clientId; retorna WebflowResult | null (null = pendiente).
  • client.pollWebflowStatus(params, { maxAttempts, pollingIntervalMs, signal, onAttempt }) — sondeo hasta veredicto o JumioPollingTimeoutError.
  • client.sendToPii({ accountId, workflowId, clientId, signal? }) — OPCIONAL: tras un veredicto valid: true, envía los datos al PII del cliente. Replica el curl de producción: GET a JUMIO_ENDPOINT con accountId/workflowId/clientId en query y headers Authorization + context. Usa la misma infra constante (JUMIO_BASE_URL/JUMIO_ENDPOINT). Lanza JumioPiiError (code: "PII_SYNC_FAILED") distinguible de un rechazo de Jumio — el hook guarda el fallo en piiError sin sobrescribir el veredicto válido.
  • Hooks exponen cancel() / reset(); un abort (desmontaje, cancel, StrictMode) baja isChecking/isStarting/isSendingPii/isLoading sin marcar error. useJumioWebflow expone isSendingPii, piiResult, piiError y sendToPii().
  • El backend puede responder con envelope { data } o { values } y datos anidados; el SDK los desempaqueta. parseWebflowReturnParams acepta workflowExecutionId / workflowId y params anidados en ?status=.

🧪 Pruebas y Construcción

# Instalar dependencias
npm install

# Ejecutar suite completa de pruebas unitarias (65 tests)
npm test

# Verificación de tipos TypeScript
npm run typecheck

# Compilar para producción (ESM, CJS y .d.ts)
npm run build

📄 Licencia

MIT © DynamiCore