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

@ramiidv/arca-common

v0.2.0

Published

Utilidades compartidas para los SDKs de ARCA (ex AFIP) - WSAA, SOAP client, validadores, tipos comunes

Readme

@ramiidv/arca-common

npm License: MIT Node >= 18

Utilidades compartidas para el ecosistema de SDKs de ARCA (ex AFIP) en TypeScript.

Este paquete es la base sobre la que se construyen los SDKs de dominio:

Instalacion

npm install @ramiidv/arca-common

Requisitos

Que incluye

| Modulo | Descripcion | | --- | --- | | WsaaClient | Cliente WSAA con firma CMS/PKCS#7, cache de tokens y deduplicacion de requests | | SOAP client | soapCall, afipSoapCall, checkServiceErrors — llamadas SOAP con retry, timeout y backoff exponencial | | XML utilities | parseXml, buildXml, ensureArray, getNestedValue — via fast-xml-parser | | Validators | validateCuit, isValidCuit, validateCBU, isValidCBU, formatDate, parseAfipDate, validateFecha, validateFechaRango | | Errors | Jerarquia de errores: ArcaError, ArcaAuthError, ArcaSoapError, ArcaServiceError, ArcaValidationError | | Types | AccessTicket, ArcaBaseConfig, SoapCallOptions, ServerStatus, ArcaEvent | | Constants | WSAA_ENDPOINTS, DocTipo, Provincia |

Uso

WsaaClient — Autenticacion WSAA

import fs from "fs";
import { WsaaClient } from "@ramiidv/arca-common";

const wsaa = new WsaaClient({
  cert: fs.readFileSync("./cert.crt", "utf-8"),
  key: fs.readFileSync("./key.key", "utf-8"),
  production: false,
});

// Obtener ticket de acceso para un servicio
const ticket = await wsaa.getAccessTicket("wsfe");
console.log(ticket.token);
console.log(ticket.sign);
console.log(ticket.expirationTime);

// El ticket se cachea automaticamente. Llamadas subsiguientes
// devuelven el ticket cacheado si no expiro.
const ticket2 = await wsaa.getAccessTicket("wsfe"); // cache hit

// Invalidar cache manualmente
wsaa.clearTicket("wsfe");
wsaa.clearAllTickets();

Validacion de CUIT/CUIL

import { validateCuit, normalizeCuit, formatCuit, isValidCuit } from "@ramiidv/arca-common";

// Valida formato y digito verificador, retorna 11 digitos
const cuit = validateCuit("20-12345678-6"); // "20123456786"
const cuit2 = validateCuit(20123456786);    // "20123456786" (acepta number)

// Check sin lanzar error
if (isValidCuit(cuitDelCliente)) {
  // procesar...
}

// Normalizar (quitar guiones, acepta number)
normalizeCuit("20-12345678-6"); // "20123456786"
normalizeCuit(20123456786);     // "20123456786"

// Formatear
formatCuit("20123456786"); // "20-12345678-6"
formatCuit(20123456786);   // "20-12345678-6"

// Lanza ArcaValidationError si es invalido
try {
  validateCuit("00000000000");
} catch (e) {
  console.error(e.message);  // "CUIT invalido: ..."
  console.error(e.details);  // [{ field: "cuit", message: "...", value: "..." }]
}

Validacion de CBU

import { validateCBU, isValidCBU } from "@ramiidv/arca-common";

// Valida formato de 22 digitos y checksums de ambos bloques
const cbu = validateCBU("0110599140000041817221");

// Check sin lanzar error
if (isValidCBU(cbuDelCliente)) {
  // procesar...
}

Fechas (formato AFIP)

import { formatDate, parseAfipDate } from "@ramiidv/arca-common";

// Formatear a YYYYMMDD (formato AFIP, timezone Argentina)
formatDate(new Date());          // "20260331"
formatDate("20260331");          // "20260331" (passthrough)
formatDate("2026-03-31");        // "20260331" (parsea ISO)

// Parsear YYYYMMDD a Date
const fecha = parseAfipDate("20260331"); // Date(2026, 2, 31)
parseAfipDate("2026-03-31");             // tambien acepta guiones

SOAP client

import { soapCall, afipSoapCall, checkServiceErrors, parseXml, buildXml } from "@ramiidv/arca-common";

// Llamada SOAP de bajo nivel
const bodyXml = '<FEDummy xmlns="http://ar.gov.afip.dif.FEV1/"/>';
const result = await soapCall("https://wswhomo.afip.gov.ar/wsfev1/service.asmx", bodyXml, {
  timeout: 30_000,
  retries: 2,
  retryDelayMs: 1_000,
  soapAction: "",
});

// Llamada SOAP de alto nivel (construye envelope, extrae resultado)
const data = await afipSoapCall(
  "https://wswhomo.afip.gov.ar/wsfev1/service.asmx",
  "http://ar.gov.afip.dif.FEV1/",
  "FEDummy",
  {},
);

// Verificar errores de negocio en la respuesta
checkServiceErrors(data, "WSFE");

// Utilidades XML
const obj = parseXml("<root><item>1</item></root>");
const xml = buildXml({ root: { item: 1 } });

Manejo de errores

import {
  ArcaError,
  ArcaAuthError,
  ArcaSoapError,
  ArcaServiceError,
  ArcaValidationError,
} from "@ramiidv/arca-common";

try {
  const ticket = await wsaa.getAccessTicket("wsfe");
} catch (e) {
  if (e instanceof ArcaAuthError) {
    // Login WSAA fallo (certificado invalido, expirado, etc.)
    console.error("Auth error:", e.message);
  }

  if (e instanceof ArcaSoapError) {
    // Error HTTP/SOAP (timeout, 5xx, SOAP Fault)
    console.error("HTTP status:", e.statusCode);
  }

  if (e instanceof ArcaServiceError) {
    // Error de negocio de ARCA (CUIT invalido, comprobante rechazado, etc.)
    for (const err of e.errors) {
      console.error(`[${err.code}] ${err.msg}`);
    }
  }

  if (e instanceof ArcaValidationError) {
    // Error de validacion de datos de entrada
    console.error("Campo:", e.field);
    for (const detail of e.details) {
      console.error(`  ${detail.field}: ${detail.message}`);
    }
  }

  // Todos extienden ArcaError
  if (e instanceof ArcaError) {
    console.error("ARCA error:", e.message);
  }
}

Constantes

import { WSAA_ENDPOINTS, DocTipo, Provincia } from "@ramiidv/arca-common";

// Endpoints WSAA
console.log(WSAA_ENDPOINTS.testing);    // "https://wsaahomo.afip.gov.ar/ws/services/LoginCms"
console.log(WSAA_ENDPOINTS.production); // "https://wsaa.afip.gov.ar/ws/services/LoginCms"

// Tipos de documento
console.log(DocTipo.CUIT); // 80
console.log(DocTipo.DNI);  // 96

// Provincias
console.log(Provincia.BUENOS_AIRES); // 1
console.log(Provincia.CORDOBA);      // 3

API

new WsaaClient(config)

| Parametro | Tipo | Default | Descripcion | | --- | --- | --- | --- | | cert | string | -- | Certificado X.509 en formato PEM | | key | string | -- | Clave privada RSA en formato PEM | | production | boolean | false | Usar entorno de produccion | | endpoint | string | -- | URL custom del endpoint WSAA (ignora production) | | tokenTTLMinutes | number | 720 | Tiempo de vida del token en minutos (12 horas) | | timeout | number | 30000 | Timeout HTTP en milisegundos | | retries | number | 1 | Reintentos en errores transitorios | | retryDelayMs | number | 1000 | Delay base para backoff exponencial | | onEvent | function | -- | Callback para eventos del SDK |

Metodos de WsaaClient

| Metodo | Retorno | Descripcion | | --- | --- | --- | | getAccessTicket(service) | Promise<AccessTicket> | Obtiene un ticket de acceso (con cache y dedup) | | clearTicket(service) | void | Invalida el ticket cacheado para un servicio | | clearAllTickets() | void | Invalida todos los tickets cacheados |

SOAP client

| Funcion | Descripcion | | --- | --- | | soapCall(endpoint, bodyContent, opts?) | Llamada SOAP de bajo nivel con retry y timeout | | afipSoapCall(endpoint, namespace, method, params, opts?) | Llamada SOAP de alto nivel para WS de ARCA | | checkServiceErrors(result, serviceName) | Lanza ArcaServiceError si hay errores de negocio | | parseXml(xml) | Parsea XML a objeto JS | | buildXml(obj) | Construye XML desde objeto JS | | ensureArray(val) | Normaliza valor/array/null a array | | getNestedValue(obj, ...keys) | Busca valor probando multiples keys (para namespaces SOAP) |

Validators

| Funcion | Retorno | Descripcion | | --- | --- | --- | | validateCuit(cuit) | string | Valida CUIT/CUIL (formato + checksum), retorna 11 digitos. Acepta string \| number | | isValidCuit(cuit) | boolean | Verifica si un CUIT es valido sin lanzar error | | normalizeCuit(cuit) | string | Elimina guiones, acepta string \| number | | formatCuit(cuit) | string | Formatea como XX-XXXXXXXX-X, acepta string \| number | | validateCBU(cbu) | string | Valida CBU (22 digitos + checksums de bloques) | | isValidCBU(cbu) | boolean | Verifica si un CBU es valido sin lanzar error | | formatDate(date) | string | Formatea Date \| string a YYYYMMDD (timezone Argentina) | | parseAfipDate(str) | Date | Parsea YYYYMMDD o YYYY-MM-DD a Date | | validateFecha(date, fieldName) | void | Valida que sea un Date valido | | validateFechaRango(inicio, fin) | void | Valida que fin sea posterior a inicio | | collectErrors(fn, errors) | void | Ejecuta validacion y recolecta errores sin lanzar | | collectErrorsWithPrefix(fn, errors, prefix) | void | Como collectErrors pero prefija el campo |

Errores

| Clase | Cuando se lanza | Propiedades extra | | --- | --- | --- | | ArcaError | Clase base para todos los errores | -- | | ArcaAuthError | Login WSAA fallo, certificado invalido, respuesta inesperada | -- | | ArcaSoapError | Error HTTP, timeout, SOAP Fault | statusCode?: number | | ArcaServiceError | Error de negocio de ARCA (codigos funcionales) | errors: { code, msg }[] | | ArcaValidationError | Datos de entrada invalidos | field?: string, details: ValidationErrorDetail[] |

Types

| Tipo | Descripcion | | --- | --- | | AccessTicket | Token + sign + expirationTime | | ArcaBaseConfig | Config base: cert, key, production, timeout, retries, onEvent | | SoapCallOptions | Opciones para llamadas SOAP: timeout, retries, soapAction, onEvent | | ServerStatus | Estado de servidores: appserver, dbserver, authserver | | ArcaEvent | Union discriminada de eventos del SDK | | WsaaClientConfig | Config del constructor de WsaaClient | | ValidationErrorDetail | Detalle de error: field, message, value |

Constants

| Constante | Tipo | Descripcion | | --- | --- | --- | | WSAA_ENDPOINTS | { testing, production } | URLs de los endpoints WSAA | | WSAA_NAMESPACE | string | Namespace XML del WSAA | | DocTipo | enum | Tipos de documento (CUIT=80, CUIL=86, DNI=96, etc.) | | Provincia | enum | Provincias argentinas (0-23) |

Eventos

El SDK emite eventos via el callback onEvent para debugging y monitoreo.

| Evento | Cuando | Datos | | --- | --- | --- | | auth:login | Nuevo token obtenido | service, durationMs | | auth:cache-hit | Token cacheado reutilizado | service | | request:start | Antes de una llamada SOAP | method, endpoint | | request:end | Llamada SOAP completada | method, endpoint, durationMs | | request:retry | Reintentando tras error | method, endpoint, attempt, error | | request:error | Llamada SOAP fallo | method, endpoint, error |

Retry automatico

Habilitado por defecto (retries: 1). Solo reintenta en errores transitorios (timeout, HTTP 5xx, errores de red). No reintenta en errores de negocio. Backoff exponencial: retryDelayMs * 2^attempt.

// Configurar retries
const wsaa = new WsaaClient({
  ...config,
  retries: 2,          // 2 reintentos (3 intentos totales)
  retryDelayMs: 2000,  // 2s, 4s
});

Ejemplos

Ver la carpeta examples/ para ejemplos completos:

Licencia

MIT