Saltar al contenido
dte-sdk

Contribuir

Las contribuciones son bienvenidas. dte-sdk arma documentos tributarios con valor legal y maneja llaves de firma, así que la corrección, las pruebas y la disciplina con los datos importan más que la velocidad. Esta página te lleva desde un clon hasta un pull request.

El repositorio#

  • Código e issues: github.com/arrowsw/dte-sdk.
  • Rama: el trabajo ocurre en canary. Abre los pull requests contra ella. Fusionar en canary nunca publica nada.
  • Estado: la versión más reciente en npm es la 0.8.0, y canary tiene lo que viene; la 1.0.0 será la primera versión recomendada para producción. Hasta entonces la API puede cambiar en cualquier versión.
  • Licencia: MIT, © Arrow Software. Al contribuir aceptas que tu aporte se publique bajo ella.

Reportar issues#

¿Encontraste un error o tienes una solicitud?

  1. Busca primero entre los issues existentes.
  2. Abre uno nuevo con una descripción clara, los pasos para reproducirlo, el comportamiento esperado y el real, y un ejemplo mínimo de código.

Cuando adjuntes XML, entradas o capturas, tacha los datos: reemplaza RUT, nombres y montos reales por los valores ficticios que usa esta documentación, y nunca adjuntes un CAF, certificado, contraseña, token o sesión del portal reales. Ver Sin datos reales.

Para vulnerabilidades de seguridad, no abras un issue público. Repórtalas en privado como se describe en Seguridad.

Preparar el entorno de desarrollo#

Necesitas Node 22.12 o superior, npm y git. Bajo la 22.12, require() no puede cargar un módulo ES, algo que el paquete soporta para proyectos CommonJS.

Shell
git clone https://github.com/arrowsw/dte-sdk.git
cd dte-sdk
git checkout canary
npm install   # también compila, mediante el script `prepare`
npm test

Comandos#

ComandoQué hace
npm testEjecuta la suite de Jest: pruebas unitarias, basadas en propiedades, de tipos y de humo del paquete compilado.
npm test -- --coverageLo mismo, haciendo cumplir los umbrales de cobertura. Es lo que ejecuta CI.
npm run buildCompila con esbuild (módulos ES, un archivo por entrada más trozos compartidos) y emite las declaraciones con tsc.
npm run lintESLint (configuración flat) con Prettier.
npm run prettierFormatea src y tests.
npm run sizeLa guarda de tamaño del bundle (.size-limit.json): cada entrada tiene un límite en kB, minificada y comprimida.
npm run scanFalla si un archivo versionado contiene un RUT real, una ruta local o un secreto. Ver Sin datos reales.
npm run mutationPruebas de mutación con Stryker. Ver más abajo.
npm run fixtures, npm run fixtures:tlsRegeneran los fixtures sintéticos. Esto cambia todas las llaves, así que regenera tests/__snapshots__/ en el mismo commit.

La prueba de humo del paquete compilado carga los archivos construidos, así que ejecuta npm run build de nuevo después de cambiar las fuentes.

Estilo: Prettier con comillas simples, sin punto y coma, comas finales y 120 columnas; TypeScript en modo estricto; ESLint con las reglas recomendadas (un prefijo de guion bajo marca un argumento o variable que no se usa a propósito). npm run prettier y npm run lint forman parte de la guarda previa a publicar.

La estructura#

Text
src/
  index.ts            entrada `dte-sdk` (documentos, totales, timbres, firmas, sobres, libros, cliente del SII)
  node/index.ts       entrada `dte-sdk/node`
  portal/index.ts     entrada `dte-sdk/portal`
  pdf/index.ts        entrada `dte-sdk/pdf`
  errors.ts           DteError y los códigos estables
  ...                 una carpeta por área: document, totals, ted, signature, envelope, books, sii, portal…
tests/
  <área>/             las pruebas junto al área que cubren
  fixtures/           certificados, CAF, respuestas del SII, XML golden y esquemas oficiales sintéticos
  support/            SII falso, constructores y utilidades (no se recogen como pruebas)
  live/               pruebas de humo opt-in contra el SII real

Dos reglas mantienen honestas las entradas: la entrada raíz no debe evaluar ningún módulo node: al importarse (los adaptadores de Node los cargan en el primer uso), y una función que necesita Node pertenece a dte-sdk/node o a dte-sdk/portal, no a la raíz.

Pruebas#

Todo cambio viene con pruebas. La suite usa Jest con ts-jest y cuatro tipos de prueba:

  • Pruebas unitarias de cada función: el camino feliz, cada código DteError que puede lanzar y los casos límite (redondeos, descuentos, líneas exentas, una respuesta cortada).
  • Pruebas basadas en propiedades (fast-check) para invariantes como totales y codificaciones.
  • Pruebas de tipos (expect-type) para que los tipos públicos no se desvíen.
  • Pruebas golden y de esquemas: el XML de los libros y sobres se compara byte a byte con archivos golden y se valida contra los esquemas oficiales del SII.

El cliente de servicios web del SII se prueba contra un SII falso (tests/support/fake-sii.ts) que sirve respuestas sintéticas desde tests/fixtures/sii/, y el portal contra páginas sintéticas. Es deliberado y honesto: esas pruebas no pueden mostrar cómo responde el SII real. Estado dice qué ha tocado lo real.

El umbral de cobertura del 100 %#

jest.config.cjs fija un umbral global de 100 % en sentencias, ramas, funciones y líneas, medido contra src/**/*.ts (nunca contra el dist compilado). CI falla ante cualquier caída. Si código real introduce una rama realmente inalcanzable, baja el umbral de forma deliberada y documenta el porqué en el mismo pull request; no dejes una rama sin probar ni agregues un comentario para esconderla.

Pruebas de mutación#

npm run mutation ejecuta Stryker sobre src/**/*.ts con el runner de Jest. Es lento, así que es un chequeo de profundidad periódico y no una guarda por commit. Sus umbrales son 90 (alto), 80 (bajo) y 70 (corte).

Pruebas de humo en vivo#

Las pruebas de tests/live hablan con el ambiente de certificación del SII con un certificado real. Nunca corren en CI y se omiten salvo que las actives:

Shell
SII_LIVE=1 SII_CERT_PFX=/path/to/firma.pfx SII_CERT_PASSWORD="$PFX_PASSWORD" \
  [SII_COMPANY_RUT=… SII_LIVE_TRACK_ID=…] npx jest tests/live

Nada de una ejecución en vivo se sube al repositorio: ni salidas, ni directorios de captura, ni RUT. Si las ejecutas, usas tu propio certificado contra el SII; lee antes Seguridad.

La convención de JSDoc bilingüe#

La documentación de la API vive en el código, en inglés y en español. Toda función, tipo y campo exportado tiene un bloque JSDoc con una línea EN: y una línea ES:, y lo mismo las etiquetas @param, @returns y @throws {DteError} (una línea @throws lista los códigos de error que puede lanzar la función, en ambos idiomas):

TypeScript
/**
 * EN: Type guard for `DteError`.
 * ES: Guarda de tipo para `DteError`.
 * @param value EN: anything. ES: cualquier valor.
 * @returns EN: true when `value` is a `DteError`. ES: true cuando `value` es un `DteError`.
 */

En los campos del modelo de dominio, la línea ES: nombra la etiqueta del SII que produce el campo, para que quien conoce el formato del SII encuentre el camino de vuelta:

TypeScript
/** EN: Folio. ES: `NroDoc` — Folio del documento. */
readonly folio: number

El modelo se nombra en inglés; las etiquetas y el vocabulario propios del SII aparecen en la línea ES: y en el XML. Un pull request que agrega un export sin ambos idiomas está incompleto.

Sin datos reales#

El repositorio es público y nunca debe contener a un contribuyente real. Esto cubre código, pruebas, fixtures, documentación, mensajes de commit, issues y pull requests.

  • Usa datos ficticios. Los RUT de los ejemplos y las pruebas son valores de documentación, como 76543210-3, 12345678-5 y 66666666-6 (el RUT genérico del propio SII). Los certificados, CAF y llaves TLS de tests/fixtures se generan localmente y son sintéticos. Las contraseñas de los ejemplos vienen de process.env.
  • npm run scan lo hace cumplir. Falla cuando un archivo versionado bajo src/, tests/, scripts/, docs/, README.md, llms.txt o CHANGELOG.md contiene un RUT fuera de una lista corta permitida, una ruta local de una máquina o un archivo que parece un secreto (.pfx, .p12, .pem, .key, .env; los fixtures son la única excepción). Corre en CI y antes de cada publicación. Agregar un RUT a la lista es una decisión deliberada: pregunta primero de quién es.
  • Nunca subas un CAF, certificado, token o sesión del portal reales, ni una captura de un intercambio real. Una captura tacha los secretos pero conserva los RUT y el XML.

Commits y pull requests#

1

Crea una rama desde canary

Shell
git checkout canary && git pull
git checkout -b fix/short-description
2

Implementa con pruebas

Agrega pruebas para el nuevo comportamiento, teniendo presente el umbral de cobertura, y escribe el JSDoc en ambos idiomas.

3

Verifica en local

Shell
npm test -- --coverage
npm run lint
npm run scan
npm run build && npm run size
4

Actualiza el changelog

Agrega una línea bajo [Unreleased] en CHANGELOG.md, que sigue Keep a Changelog. Si cambias la API pública, actualiza también el README.

5

Abre el pull request

Contra canary, con un título en el estilo convencional que usa el historial: feat: …, fix: …, docs: …, feat!: … para un cambio incompatible. Di qué cambió y por qué, y qué probaste. Los pull requests se fusionan con squash.

Los pull requests de funcionalidades nunca suben la versión. Ningún pull request que cambie el comportamiento toca version en package.json ni en package-lock.json.

Publicaciones#

Las versiones las publican los mantenedores, siguiendo RELEASING.md:

  • Una versión es su propio pull request (rama release/X.Y.Z, commit chore(release): X.Y.Z) que contiene solo el cambio de versión y la sección finalizada del CHANGELOG.
  • Publicar solo se dispara con un tag. Subir un tag vX.Y.Z ejecuta en CI el workflow de publicación: npm ci, la guarda previa a publicar (scan, pruebas, Prettier y lint), una verificación de que el tag coincide con la versión de package.json, y npm publish --provenance.
  • Sin token y con procedencia. El workflow se autentica con npm Trusted Publishing (GitHub OIDC), así que no existe un NPM_TOKEN que filtrar, y cada tarball lleva una atestación de procedencia que lo enlaza con su commit y su build de origen.

Licencia#

dte-sdk se publica bajo la licencia MIT.