dgii-ts 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +33 -9
- package/README.md +34 -9
- package/dist/{chunk-D6DU6PD3.cjs → chunk-6REHWG3R.cjs} +1 -1
- package/dist/{chunk-QWP5FSCN.cjs → chunk-DUKBAJTM.cjs} +8 -4
- package/dist/{chunk-KMSKQH4U.js → chunk-LRPZFX62.js} +1 -1
- package/dist/{chunk-ABNHQAWP.js → chunk-YV4IPACJ.js} +7 -3
- package/dist/client.cjs +3 -3
- package/dist/client.d.cts +8 -3
- package/dist/client.d.ts +8 -3
- package/dist/client.js +2 -2
- package/dist/index.cjs +3 -3
- package/dist/index.js +2 -2
- package/dist/scraping.cjs +2 -2
- package/dist/scraping.js +1 -1
- package/package.json +3 -2
- package/skills/dgii-ts/SKILL.md +273 -0
package/README.en.md
CHANGED
|
@@ -40,8 +40,9 @@ that pass validation despite failing the check-digit algorithm.
|
|
|
40
40
|
### Resilient client (DgiiClient)
|
|
41
41
|
|
|
42
42
|
`DgiiClient` is the recommended entry point for real-time queries. It uses
|
|
43
|
-
web scraping
|
|
44
|
-
|
|
43
|
+
web scraping with a circuit breaker to prevent cascading failures and retry
|
|
44
|
+
with exponential backoff. The SOAP fallback is opt-in (`soapFallback: true`)
|
|
45
|
+
and off by default since version 0.3.0.
|
|
45
46
|
|
|
46
47
|
### Web scraping
|
|
47
48
|
|
|
@@ -52,8 +53,8 @@ endpoint in January 2025.
|
|
|
52
53
|
### SOAP client (WSMovilDGII) — deprecated
|
|
53
54
|
|
|
54
55
|
Typed wrapper around DGII's SOAP service. **Permanently blocked by DGII
|
|
55
|
-
since January 2025.** Kept as an
|
|
56
|
-
for direct use.
|
|
56
|
+
since January 2025.** Kept as an opt-in `DgiiClient` fallback (off by
|
|
57
|
+
default) and not recommended for direct use.
|
|
57
58
|
|
|
58
59
|
### Bulk data importer
|
|
59
60
|
|
|
@@ -74,6 +75,29 @@ pnpm add dgii-ts
|
|
|
74
75
|
yarn add dgii-ts
|
|
75
76
|
```
|
|
76
77
|
|
|
78
|
+
## Agent skill
|
|
79
|
+
|
|
80
|
+
dgii-ts ships a skill ([`skills/dgii-ts/SKILL.md`](./skills/dgii-ts/SKILL.md))
|
|
81
|
+
that teaches coding agents (Claude Code, Cursor, Codex, Copilot, and others
|
|
82
|
+
that support [Agent Skills](https://agentskills.io)) to use the library
|
|
83
|
+
correctly: what each validator checks, how to handle `DgiiClient` errors,
|
|
84
|
+
and how to avoid hammering DGII.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Any supported agent
|
|
88
|
+
npx skills add franklinmdev/dgii-ts --skill dgii-ts
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
In Claude Code you can also install it as a plugin:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
/plugin marketplace add franklinmdev/dgii-ts
|
|
95
|
+
/plugin install dgii-ts@dgii-ts
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The skill is also included in the npm package, under
|
|
99
|
+
`node_modules/dgii-ts/skills/`.
|
|
100
|
+
|
|
77
101
|
## Quick start
|
|
78
102
|
|
|
79
103
|
### Validate an RNC
|
|
@@ -144,7 +168,8 @@ For an e-NCF (E-series) DGII requires the buyer's RNC. Without it DGII
|
|
|
144
168
|
answers with a required-field message: `ScrapingClient.getNCF` throws
|
|
145
169
|
`DgiiServiceError` and `DgiiClient.getNCF` wraps it in
|
|
146
170
|
`AllStrategiesFailedError` after exhausting retries and the fallback
|
|
147
|
-
(the message keeps DGII's text). The
|
|
171
|
+
(the message keeps DGII's text). The same happens without the
|
|
172
|
+
security code: DGII requires it too (verified with an E31 e-NCF).
|
|
148
173
|
|
|
149
174
|
```typescript
|
|
150
175
|
const ecfResult = await client.getNCF('101010632', 'E310125217173', {
|
|
@@ -187,7 +212,7 @@ ignored for a B-series NCF.
|
|
|
187
212
|
|
|
188
213
|
| Class/Method | Description |
|
|
189
214
|
| --- | --- |
|
|
190
|
-
| `DgiiClient` | Scraping
|
|
215
|
+
| `DgiiClient` | Scraping, circuit breaker, retry (optional SOAP fallback) |
|
|
191
216
|
| `client.getContribuyente(rnc)` | Looks up taxpayer data by RNC |
|
|
192
217
|
| `client.getNCF(rnc, ncf, options?)` | Validates a fiscal receipt against DGII (`options` for e-NCF) |
|
|
193
218
|
|
|
@@ -229,7 +254,7 @@ accepts an `encoding` option (defaults to `latin1`).
|
|
|
229
254
|
├─────────────────────────────────────────────────┤
|
|
230
255
|
│ Layer 2: DgiiClient (resilient) │
|
|
231
256
|
│ ✓ Web scraping (primary) │
|
|
232
|
-
│ ✓
|
|
257
|
+
│ ✓ Circuit breaker ✓ Retry │
|
|
233
258
|
├─────────────────────────────────────────────────┤
|
|
234
259
|
│ Layer 3: Bulk data (DGII_RNC.zip) │
|
|
235
260
|
│ ✓ Daily download ✓ TXT parsing │
|
|
@@ -237,8 +262,7 @@ accepts an `encoding` option (defaults to `latin1`).
|
|
|
237
262
|
```
|
|
238
263
|
|
|
239
264
|
**Layer 1** is instant and works offline. **Layer 2** provides real-time data
|
|
240
|
-
using web scraping
|
|
241
|
-
breaker, and retry with exponential backoff. **Layer 3** is ideal for batch
|
|
265
|
+
using web scraping, a circuit breaker, and retry with exponential backoff. **Layer 3** is ideal for batch
|
|
242
266
|
operations where you need to look up thousands of RNCs quickly.
|
|
243
267
|
|
|
244
268
|
## Project status
|
package/README.md
CHANGED
|
@@ -43,8 +43,9 @@ pasan validación aunque no cumplan el algoritmo de dígito verificador.
|
|
|
43
43
|
### Cliente resiliente (DgiiClient)
|
|
44
44
|
|
|
45
45
|
`DgiiClient` es el punto de entrada recomendado para consultas en tiempo real.
|
|
46
|
-
Usa web scraping
|
|
47
|
-
|
|
46
|
+
Usa web scraping con circuit breaker para evitar cascadas de errores y retry
|
|
47
|
+
con backoff exponencial. El fallback a SOAP es opcional (`soapFallback: true`)
|
|
48
|
+
y está apagado por defecto desde la versión 0.3.0.
|
|
48
49
|
|
|
49
50
|
### Web scraping
|
|
50
51
|
|
|
@@ -56,7 +57,8 @@ bloqueó el endpoint SOAP en enero 2025.
|
|
|
56
57
|
|
|
57
58
|
Wrapper tipado alrededor del servicio SOAP de la DGII. **Bloqueado
|
|
58
59
|
permanentemente por la DGII en enero 2025.** Se mantiene como fallback
|
|
59
|
-
|
|
60
|
+
opcional de `DgiiClient` (apagado por defecto) y no se recomienda su uso
|
|
61
|
+
directo.
|
|
60
62
|
|
|
61
63
|
### Importador de datos masivos
|
|
62
64
|
|
|
@@ -77,6 +79,29 @@ pnpm add dgii-ts
|
|
|
77
79
|
yarn add dgii-ts
|
|
78
80
|
```
|
|
79
81
|
|
|
82
|
+
## Skill para agentes de IA
|
|
83
|
+
|
|
84
|
+
dgii-ts incluye un skill ([`skills/dgii-ts/SKILL.md`](./skills/dgii-ts/SKILL.md))
|
|
85
|
+
que enseña a los agentes de código (Claude Code, Cursor, Codex, Copilot y
|
|
86
|
+
otros compatibles con [Agent Skills](https://agentskills.io)) a usar la
|
|
87
|
+
librería correctamente: qué valida cada validador, cómo manejar los
|
|
88
|
+
errores de `DgiiClient` y cómo no saturar a la DGII.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Cualquier agente compatible
|
|
92
|
+
npx skills add franklinmdev/dgii-ts --skill dgii-ts
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
En Claude Code también se puede instalar como plugin:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
/plugin marketplace add franklinmdev/dgii-ts
|
|
99
|
+
/plugin install dgii-ts@dgii-ts
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
El skill viene además dentro del paquete de npm, en
|
|
103
|
+
`node_modules/dgii-ts/skills/`.
|
|
104
|
+
|
|
80
105
|
## Uso rápido
|
|
81
106
|
|
|
82
107
|
### Validar un RNC
|
|
@@ -147,8 +172,8 @@ Para un e-NCF (serie E) la DGII exige el RNC del comprador. Sin él
|
|
|
147
172
|
responde con un mensaje de campo requerido: `ScrapingClient.getNCF`
|
|
148
173
|
lanza `DgiiServiceError` y `DgiiClient.getNCF` lo envuelve en
|
|
149
174
|
`AllStrategiesFailedError` tras agotar reintentos y fallback (el
|
|
150
|
-
mensaje conserva el texto de la DGII).
|
|
151
|
-
|
|
175
|
+
mensaje conserva el texto de la DGII). Lo mismo pasa sin el código
|
|
176
|
+
de seguridad: la DGII también lo exige (verificado con un e-NCF E31).
|
|
152
177
|
|
|
153
178
|
```typescript
|
|
154
179
|
const ecfResult = await client.getNCF('101010632', 'E310125217173', {
|
|
@@ -192,7 +217,7 @@ serie B.
|
|
|
192
217
|
|
|
193
218
|
| Clase/Método | Descripción |
|
|
194
219
|
| --- | --- |
|
|
195
|
-
| `DgiiClient` | Cliente con scraping
|
|
220
|
+
| `DgiiClient` | Cliente con scraping, circuit breaker y retry (SOAP fallback opcional) |
|
|
196
221
|
| `client.getContribuyente(rnc)` | Consulta datos de un contribuyente por RNC |
|
|
197
222
|
| `client.getNCF(rnc, ncf, options?)` | Valida un comprobante fiscal contra la DGII (`options` para e-NCF) |
|
|
198
223
|
|
|
@@ -234,7 +259,7 @@ Acepta `encoding` en las opciones (`latin1` por defecto).
|
|
|
234
259
|
├─────────────────────────────────────────────────┤
|
|
235
260
|
│ Capa 2: DgiiClient (resiliente) │
|
|
236
261
|
│ ✓ Web scraping (primario) │
|
|
237
|
-
│ ✓
|
|
262
|
+
│ ✓ Circuit breaker ✓ Retry │
|
|
238
263
|
├─────────────────────────────────────────────────┤
|
|
239
264
|
│ Capa 3: Datos masivos (DGII_RNC.zip) │
|
|
240
265
|
│ ✓ Descarga diaria ✓ Parseo TXT │
|
|
@@ -242,8 +267,8 @@ Acepta `encoding` en las opciones (`latin1` por defecto).
|
|
|
242
267
|
```
|
|
243
268
|
|
|
244
269
|
La **capa 1** es instantánea y funciona sin conexión. La **capa 2** ofrece
|
|
245
|
-
datos en tiempo real con web scraping
|
|
246
|
-
|
|
270
|
+
datos en tiempo real con web scraping, circuit breaker y retry con backoff
|
|
271
|
+
exponencial. La **capa 3** es
|
|
247
272
|
ideal para operaciones en lote donde necesitas buscar miles de RNC rápidamente.
|
|
248
273
|
|
|
249
274
|
## Estado del proyecto
|
|
@@ -94,7 +94,7 @@ function parseContribuyenteHtml(html) {
|
|
|
94
94
|
rnc: _chunkQH4BK5X3cjs.stripNonDigits.call(void 0, rnc),
|
|
95
95
|
nombre: _chunkQH4BK5X3cjs.collapseSpaces.call(void 0, nombre),
|
|
96
96
|
nombreComercial: _chunkQH4BK5X3cjs.collapseSpaces.call(void 0, nombreComercial),
|
|
97
|
-
estado: rawEstado.toUpperCase()
|
|
97
|
+
estado: _chunkQH4BK5X3cjs.collapseSpaces.call(void 0, rawEstado).toUpperCase() === "ACTIVO" ? "ACTIVO" : "INACTIVO",
|
|
98
98
|
categoria: _chunkQH4BK5X3cjs.collapseSpaces.call(void 0, categoria),
|
|
99
99
|
esFacturadorElectronico: rawFacturadorElectronico.trim().toUpperCase().replace(/[ÍI]/g, "I").startsWith("SI"),
|
|
100
100
|
actividadEconomica: actividadEconomica ? _chunkQH4BK5X3cjs.collapseSpaces.call(void 0, actividadEconomica) : void 0,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var _chunkDLB5RJ7Ecjs = require('./chunk-DLB5RJ7E.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunk6REHWG3Rcjs = require('./chunk-6REHWG3R.cjs');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
@@ -52,7 +52,11 @@ var ConsecutiveBreaker = class {
|
|
|
52
52
|
this._onSuccess();
|
|
53
53
|
return result;
|
|
54
54
|
} catch (error) {
|
|
55
|
-
|
|
55
|
+
if (error instanceof _chunkNASWEFHNcjs.DgiiNotFoundError) {
|
|
56
|
+
this._onSuccess();
|
|
57
|
+
} else {
|
|
58
|
+
this._onFailure();
|
|
59
|
+
}
|
|
56
60
|
throw error;
|
|
57
61
|
}
|
|
58
62
|
}
|
|
@@ -123,7 +127,7 @@ async function withRetry(fn, options = DEFAULT_RETRY_OPTIONS) {
|
|
|
123
127
|
var DgiiClient = class {
|
|
124
128
|
constructor(options) {
|
|
125
129
|
const timeout = _optionalChain([options, 'optionalAccess', _ => _.timeout]);
|
|
126
|
-
this._scraping = new (0,
|
|
130
|
+
this._scraping = new (0, _chunk6REHWG3Rcjs.ScrapingClient)(
|
|
127
131
|
timeout ? { timeout } : void 0
|
|
128
132
|
);
|
|
129
133
|
this._soap = new (0, _chunkDLB5RJ7Ecjs.DgiiSoapClient)(
|
|
@@ -139,7 +143,7 @@ var DgiiClient = class {
|
|
|
139
143
|
...DEFAULT_RETRY_OPTIONS,
|
|
140
144
|
..._optionalChain([options, 'optionalAccess', _4 => _4.retry])
|
|
141
145
|
};
|
|
142
|
-
this._soapFallback = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _5 => _5.soapFallback]), () => (
|
|
146
|
+
this._soapFallback = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _5 => _5.soapFallback]), () => ( false));
|
|
143
147
|
}
|
|
144
148
|
/**
|
|
145
149
|
* Consulta datos de un contribuyente por RNC o cédula.
|
|
@@ -94,7 +94,7 @@ function parseContribuyenteHtml(html) {
|
|
|
94
94
|
rnc: stripNonDigits(rnc),
|
|
95
95
|
nombre: collapseSpaces(nombre),
|
|
96
96
|
nombreComercial: collapseSpaces(nombreComercial),
|
|
97
|
-
estado: rawEstado.toUpperCase()
|
|
97
|
+
estado: collapseSpaces(rawEstado).toUpperCase() === "ACTIVO" ? "ACTIVO" : "INACTIVO",
|
|
98
98
|
categoria: collapseSpaces(categoria),
|
|
99
99
|
esFacturadorElectronico: rawFacturadorElectronico.trim().toUpperCase().replace(/[ÍI]/g, "I").startsWith("SI"),
|
|
100
100
|
actividadEconomica: actividadEconomica ? collapseSpaces(actividadEconomica) : void 0,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-QTN5ZT4P.js";
|
|
4
4
|
import {
|
|
5
5
|
ScrapingClient
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LRPZFX62.js";
|
|
7
7
|
import {
|
|
8
8
|
AllStrategiesFailedError,
|
|
9
9
|
DgiiConnectionError,
|
|
@@ -52,7 +52,11 @@ var ConsecutiveBreaker = class {
|
|
|
52
52
|
this._onSuccess();
|
|
53
53
|
return result;
|
|
54
54
|
} catch (error) {
|
|
55
|
-
|
|
55
|
+
if (error instanceof DgiiNotFoundError) {
|
|
56
|
+
this._onSuccess();
|
|
57
|
+
} else {
|
|
58
|
+
this._onFailure();
|
|
59
|
+
}
|
|
56
60
|
throw error;
|
|
57
61
|
}
|
|
58
62
|
}
|
|
@@ -139,7 +143,7 @@ var DgiiClient = class {
|
|
|
139
143
|
...DEFAULT_RETRY_OPTIONS,
|
|
140
144
|
...options?.retry
|
|
141
145
|
};
|
|
142
|
-
this._soapFallback = options?.soapFallback ??
|
|
146
|
+
this._soapFallback = options?.soapFallback ?? false;
|
|
143
147
|
}
|
|
144
148
|
/**
|
|
145
149
|
* Consulta datos de un contribuyente por RNC o cédula.
|
package/dist/client.cjs
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkDUKBAJTMcjs = require('./chunk-DUKBAJTM.cjs');
|
|
7
7
|
require('./chunk-DLB5RJ7E.cjs');
|
|
8
|
-
require('./chunk-
|
|
8
|
+
require('./chunk-6REHWG3R.cjs');
|
|
9
9
|
require('./chunk-OSGHCQFA.cjs');
|
|
10
10
|
require('./chunk-WMFHPNFP.cjs');
|
|
11
11
|
require('./chunk-QH4BK5X3.cjs');
|
|
@@ -15,4 +15,4 @@ require('./chunk-NASWEFHN.cjs');
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
exports.ConsecutiveBreaker =
|
|
18
|
+
exports.ConsecutiveBreaker = _chunkDUKBAJTMcjs.ConsecutiveBreaker; exports.DgiiClient = _chunkDUKBAJTMcjs.DgiiClient; exports.isRetryableError = _chunkDUKBAJTMcjs.isRetryableError; exports.withRetry = _chunkDUKBAJTMcjs.withRetry;
|
package/dist/client.d.cts
CHANGED
|
@@ -59,7 +59,11 @@ declare class ConsecutiveBreaker {
|
|
|
59
59
|
interface ClientOptions {
|
|
60
60
|
/** Tiempo de espera en milisegundos (por defecto: 15000) */
|
|
61
61
|
timeout?: number;
|
|
62
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Habilitar fallback a SOAP (por defecto: false). La DGII bloqueó el
|
|
64
|
+
* endpoint SOAP en enero 2025; activarlo solo agrega una petición
|
|
65
|
+
* inútil tras cada falla del scraping.
|
|
66
|
+
*/
|
|
63
67
|
soapFallback?: boolean;
|
|
64
68
|
/** Opciones de reintentos */
|
|
65
69
|
retry?: Partial<RetryOptions>;
|
|
@@ -70,8 +74,9 @@ interface ClientOptions {
|
|
|
70
74
|
/**
|
|
71
75
|
* Cliente resiliente para consultas a la DGII.
|
|
72
76
|
*
|
|
73
|
-
* Usa web scraping
|
|
74
|
-
* fallback (
|
|
77
|
+
* Usa web scraping con circuit breaker y reintentos automáticos. El
|
|
78
|
+
* fallback a SOAP es opcional (`soapFallback: true`) y está apagado por
|
|
79
|
+
* defecto: la DGII bloqueó ese endpoint en enero 2025.
|
|
75
80
|
*/
|
|
76
81
|
declare class DgiiClient {
|
|
77
82
|
private readonly _scraping;
|
package/dist/client.d.ts
CHANGED
|
@@ -59,7 +59,11 @@ declare class ConsecutiveBreaker {
|
|
|
59
59
|
interface ClientOptions {
|
|
60
60
|
/** Tiempo de espera en milisegundos (por defecto: 15000) */
|
|
61
61
|
timeout?: number;
|
|
62
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Habilitar fallback a SOAP (por defecto: false). La DGII bloqueó el
|
|
64
|
+
* endpoint SOAP en enero 2025; activarlo solo agrega una petición
|
|
65
|
+
* inútil tras cada falla del scraping.
|
|
66
|
+
*/
|
|
63
67
|
soapFallback?: boolean;
|
|
64
68
|
/** Opciones de reintentos */
|
|
65
69
|
retry?: Partial<RetryOptions>;
|
|
@@ -70,8 +74,9 @@ interface ClientOptions {
|
|
|
70
74
|
/**
|
|
71
75
|
* Cliente resiliente para consultas a la DGII.
|
|
72
76
|
*
|
|
73
|
-
* Usa web scraping
|
|
74
|
-
* fallback (
|
|
77
|
+
* Usa web scraping con circuit breaker y reintentos automáticos. El
|
|
78
|
+
* fallback a SOAP es opcional (`soapFallback: true`) y está apagado por
|
|
79
|
+
* defecto: la DGII bloqueó ese endpoint en enero 2025.
|
|
75
80
|
*/
|
|
76
81
|
declare class DgiiClient {
|
|
77
82
|
private readonly _scraping;
|
package/dist/client.js
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
DgiiClient,
|
|
4
4
|
isRetryableError,
|
|
5
5
|
withRetry
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YV4IPACJ.js";
|
|
7
7
|
import "./chunk-QTN5ZT4P.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-LRPZFX62.js";
|
|
9
9
|
import "./chunk-H42U4GI5.js";
|
|
10
10
|
import "./chunk-KW4ZV6FJ.js";
|
|
11
11
|
import "./chunk-D26S6EXD.js";
|
package/dist/index.cjs
CHANGED
|
@@ -17,7 +17,7 @@ require('./chunk-2ST6QKHA.cjs');
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
var
|
|
20
|
+
var _chunkDUKBAJTMcjs = require('./chunk-DUKBAJTM.cjs');
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
@@ -27,7 +27,7 @@ var _chunkDLB5RJ7Ecjs = require('./chunk-DLB5RJ7E.cjs');
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
var
|
|
30
|
+
var _chunk6REHWG3Rcjs = require('./chunk-6REHWG3R.cjs');
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
|
|
@@ -69,4 +69,4 @@ var _chunkNASWEFHNcjs = require('./chunk-NASWEFHN.cjs');
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
exports.AllStrategiesFailedError = _chunkNASWEFHNcjs.AllStrategiesFailedError; exports.BulkFormatError = _chunkNASWEFHNcjs.BulkFormatError; exports.ConsecutiveBreaker =
|
|
72
|
+
exports.AllStrategiesFailedError = _chunkNASWEFHNcjs.AllStrategiesFailedError; exports.BulkFormatError = _chunkNASWEFHNcjs.BulkFormatError; exports.ConsecutiveBreaker = _chunkDUKBAJTMcjs.ConsecutiveBreaker; exports.DGII_BULK_URL = _chunkVIZWYFHPcjs.DGII_BULK_URL; exports.DGII_ESTADOS = _chunkVIZWYFHPcjs.DGII_ESTADOS; exports.DGII_NCF_URL = _chunk6REHWG3Rcjs.DGII_NCF_URL; exports.DGII_RNC_URL = _chunk6REHWG3Rcjs.DGII_RNC_URL; exports.DGII_SOAP_BASE_URL = _chunkDLB5RJ7Ecjs.DGII_SOAP_BASE_URL; exports.DgiiClient = _chunkDUKBAJTMcjs.DgiiClient; exports.DgiiConnectionError = _chunkNASWEFHNcjs.DgiiConnectionError; exports.DgiiError = _chunkNASWEFHNcjs.DgiiError; exports.DgiiNotFoundError = _chunkNASWEFHNcjs.DgiiNotFoundError; exports.DgiiServiceError = _chunkNASWEFHNcjs.DgiiServiceError; exports.DgiiSoapClient = _chunkDLB5RJ7Ecjs.DgiiSoapClient; exports.ECF_TYPE_NAMES = _chunkOSGHCQFAcjs.ECF_TYPE_NAMES; exports.NCF_TYPE_NAMES = _chunkUW6W2JHWcjs.NCF_TYPE_NAMES; exports.SOAP_ACTIONS = _chunkDLB5RJ7Ecjs.SOAP_ACTIONS; exports.ScrapingClient = _chunk6REHWG3Rcjs.ScrapingClient; exports.downloadBulkFile = _chunkVIZWYFHPcjs.downloadBulkFile; exports.isRetryableError = _chunkDUKBAJTMcjs.isRetryableError; exports.parseBulkFile = _chunkVIZWYFHPcjs.parseBulkFile; exports.validateCedula = _chunkUW6W2JHWcjs.validateCedula; exports.validateEcf = _chunkOSGHCQFAcjs.validateEcf; exports.validateNcf = _chunkUW6W2JHWcjs.validateNcf; exports.validateRnc = _chunkUW6W2JHWcjs.validateRnc; exports.withRetry = _chunkDUKBAJTMcjs.withRetry;
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
DgiiClient,
|
|
18
18
|
isRetryableError,
|
|
19
19
|
withRetry
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-YV4IPACJ.js";
|
|
21
21
|
import {
|
|
22
22
|
DGII_SOAP_BASE_URL,
|
|
23
23
|
DgiiSoapClient,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
DGII_NCF_URL,
|
|
28
28
|
DGII_RNC_URL,
|
|
29
29
|
ScrapingClient
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-LRPZFX62.js";
|
|
31
31
|
import {
|
|
32
32
|
ECF_TYPE_NAMES,
|
|
33
33
|
validateEcf
|
package/dist/scraping.cjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunk6REHWG3Rcjs = require('./chunk-6REHWG3R.cjs');
|
|
8
8
|
require('./chunk-OSGHCQFA.cjs');
|
|
9
9
|
require('./chunk-WMFHPNFP.cjs');
|
|
10
10
|
require('./chunk-QH4BK5X3.cjs');
|
|
@@ -14,4 +14,4 @@ require('./chunk-NASWEFHN.cjs');
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
exports.DGII_NCF_URL =
|
|
17
|
+
exports.DGII_NCF_URL = _chunk6REHWG3Rcjs.DGII_NCF_URL; exports.DGII_RNC_URL = _chunk6REHWG3Rcjs.DGII_RNC_URL; exports.FORM_FIELDS = _chunk6REHWG3Rcjs.FORM_FIELDS; exports.ScrapingClient = _chunk6REHWG3Rcjs.ScrapingClient;
|
package/dist/scraping.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dgii-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Librería TypeScript para validación e integración con la DGII de República Dominicana — RNC, Cédula, NCF, e-NCF",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -80,7 +80,8 @@
|
|
|
80
80
|
},
|
|
81
81
|
"sideEffects": false,
|
|
82
82
|
"files": [
|
|
83
|
-
"dist"
|
|
83
|
+
"dist",
|
|
84
|
+
"skills"
|
|
84
85
|
],
|
|
85
86
|
"scripts": {
|
|
86
87
|
"build": "tsup",
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dgii-ts
|
|
3
|
+
description: Write correct TypeScript or JavaScript with the dgii-ts library for Dominican Republic tax data from the DGII (Dirección General de Impuestos Internos). Covers validating RNC and cédula numbers, checking NCF and e-NCF (e-CF) invoice numbers, looking up taxpayers (contribuyentes) live, verifying an e-NCF's status, and importing the DGII_RNC.zip taxpayer registry. Use this whenever code touches RNC, cédula, NCF, e-NCF, comprobantes fiscales, facturación electrónica, or Dominican tax IDs, even if the user never names dgii-ts, and before writing any mod-11 or Luhn check or any DGII scraper by hand.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dgii-ts
|
|
7
|
+
|
|
8
|
+
dgii-ts validates Dominican tax identifiers offline and queries the DGII
|
|
9
|
+
online. Most mistakes with it come from three misunderstandings: treating
|
|
10
|
+
an offline `valid: true` as "DGII confirmed this", using the wrong entry
|
|
11
|
+
point for live queries, and handling errors in a way that either hides
|
|
12
|
+
real outages or hammers DGII's servers. This skill exists to prevent
|
|
13
|
+
those.
|
|
14
|
+
|
|
15
|
+
If the project does not depend on it yet: `npm install dgii-ts`
|
|
16
|
+
(Node 18 or later).
|
|
17
|
+
|
|
18
|
+
## Pick the entry point
|
|
19
|
+
|
|
20
|
+
| Need | Use | Network |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| Is this RNC, cédula, NCF or e-NCF well formed? (forms, imports, and always before a live lookup) | `validateRnc`, `validateCedula`, `validateNcf`, `validateEcf` from `dgii-ts/validators` | none |
|
|
23
|
+
| Does DGII know this taxpayer, what is its name and status? Is this invoice number real? | one shared `DgiiClient` from `dgii-ts/client` | DGII web pages |
|
|
24
|
+
| Many RNCs at once, an offline copy of the registry, search by name | `downloadBulkFile` and `parseBulkFile` from `dgii-ts/bulk` | one ~23 MB download |
|
|
25
|
+
|
|
26
|
+
Three things the library also exports that you should not reach for:
|
|
27
|
+
|
|
28
|
+
- `DgiiSoapClient` (`dgii-ts/soap`) is deprecated. DGII shut the SOAP
|
|
29
|
+
service off in January 2025 and it currently answers without data.
|
|
30
|
+
- `ScrapingClient` (`dgii-ts/scraping`) is the low-level layer that
|
|
31
|
+
`DgiiClient` wraps. Used directly it has no retries and no circuit
|
|
32
|
+
breaker.
|
|
33
|
+
- Hand-written check digits or regexes. DGII has real identifiers that
|
|
34
|
+
fail the checksum; the validators carry a whitelist of them, so a
|
|
35
|
+
hand-rolled mod-11 or Luhn rejects real taxpayers.
|
|
36
|
+
|
|
37
|
+
## Offline validators
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { validateRnc, validateCedula, validateNcf, validateEcf } from 'dgii-ts/validators';
|
|
41
|
+
|
|
42
|
+
validateRnc('131-09819-3'); // { valid: true, formatted: '1-31-09819-3' }
|
|
43
|
+
validateCedula('00114272360'); // { valid: true, formatted: '001-1427236-0' }
|
|
44
|
+
validateNcf('b0100000001'); // { valid: true, type: 'CREDITO_FISCAL', serie: 'B01' }
|
|
45
|
+
validateEcf('E310000000001'); // { valid: true, type: 'CREDITO_FISCAL_ELECTRONICA', serie: 'E31' }
|
|
46
|
+
validateRnc('131098194'); // { valid: false }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- **`valid: true` only means well formed.** It does not mean the RNC is
|
|
50
|
+
registered or active, or that the NCF was ever issued or belongs to that
|
|
51
|
+
issuer. Only `DgiiClient` can say that. Word UI messages accordingly
|
|
52
|
+
("invalid format" vs "not registered with DGII").
|
|
53
|
+
- RNC and cédula: every non-digit is stripped first, so dashes and spaces
|
|
54
|
+
are fine. RNC is 9 digits (mod-11), cédula is 11 digits (Luhn).
|
|
55
|
+
`formatted` is `X-XX-XXXXX-X` or `XXX-XXXXXXX-X`.
|
|
56
|
+
- NCF and e-NCF: only uppercased and trimmed; separators are **not**
|
|
57
|
+
stripped, so `B01-00000001` is invalid. NCF is `B` + 2-digit type + 8
|
|
58
|
+
digits (11 chars). e-NCF is `E` + 2-digit type + 10 digits (13 chars).
|
|
59
|
+
Unknown type codes are invalid. Valid NCF types: 01, 02, 03, 04, 11,
|
|
60
|
+
12, 13, 14, 15, 16, 17. Valid e-NCF types: 31, 32, 33, 34, 41, 43, 44,
|
|
61
|
+
45, 46, 47. `NCF_TYPE_NAMES` and `ECF_TYPE_NAMES` (exported from the
|
|
62
|
+
same subpath, keyed by the 2-digit code) give Spanish display names.
|
|
63
|
+
- Non-string input returns `{ valid: false }` and never throws, so the
|
|
64
|
+
validators are safe on raw form data.
|
|
65
|
+
- The result is a discriminated union: check `valid` before reading
|
|
66
|
+
`formatted`, `type` or `serie`.
|
|
67
|
+
- A Dominican taxpayer ID is either an RNC (companies, 9 digits) or a
|
|
68
|
+
cédula (people, 11 digits). A field that accepts "RNC o cédula" should
|
|
69
|
+
accept either validator's `valid: true`. `getContribuyente` accepts
|
|
70
|
+
both.
|
|
71
|
+
- Store the digits (`value.replace(/\D/g, '')`) and use `formatted` for
|
|
72
|
+
display.
|
|
73
|
+
|
|
74
|
+
## Live lookups with DgiiClient
|
|
75
|
+
|
|
76
|
+
Run it on the server. DGII's pages send no CORS headers, so a browser
|
|
77
|
+
cannot call them; use an API route, server action or backend job.
|
|
78
|
+
|
|
79
|
+
Create **one** client and reuse it:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// dgii.ts
|
|
83
|
+
import { DgiiClient } from 'dgii-ts/client';
|
|
84
|
+
|
|
85
|
+
export const dgii = new DgiiClient({ soapFallback: false });
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Retry and circuit-breaker state live inside the instance. A new client per
|
|
89
|
+
request never trips its breaker, so during a DGII outage every request
|
|
90
|
+
keeps hitting DGII. `soapFallback` is `false` by default from dgii-ts
|
|
91
|
+
0.3.0; older versions default to `true`, so pass `false` explicitly. The
|
|
92
|
+
SOAP service is shut off: the fallback only adds a wasted request after
|
|
93
|
+
every failed lookup, and an empty SOAP reply would be reported as
|
|
94
|
+
`DgiiNotFoundError`, making an outage look like "not registered". Do not
|
|
95
|
+
turn it on.
|
|
96
|
+
|
|
97
|
+
Options and defaults: `timeout` 15000 ms (clamped to 1 to 120 s);
|
|
98
|
+
`retry: { maxRetries: 2, baseDelayMs: 500, maxDelayMs: 10000 }`
|
|
99
|
+
(exponential backoff with jitter); `circuitBreaker: { failureThreshold: 5,
|
|
100
|
+
recoveryTimeoutMs: 60000, successThreshold: 2 }`. Pass partial objects;
|
|
101
|
+
the rest keeps its default.
|
|
102
|
+
|
|
103
|
+
### Taxpayer: `getContribuyente(rncOrCedula)`
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import type { Contribuyente } from 'dgii-ts';
|
|
107
|
+
import { DgiiNotFoundError } from 'dgii-ts/errors';
|
|
108
|
+
|
|
109
|
+
async function findTaxpayer(digits: string): Promise<Contribuyente | null> {
|
|
110
|
+
try {
|
|
111
|
+
return await dgii.getContribuyente(digits);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
// Not registered with DGII: a normal answer, not an outage
|
|
114
|
+
if (err instanceof DgiiNotFoundError) return null;
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
A `Contribuyente` has `rnc` (digits only), `nombre`, `nombreComercial`,
|
|
121
|
+
`estado`, `categoria`, `esFacturadorElectronico`, and the optional
|
|
122
|
+
`actividadEconomica`, `regimenDePagos` and `administracionLocal`.
|
|
123
|
+
|
|
124
|
+
- `estado` is `'ACTIVO'` or `'INACTIVO'`. Every other DGII status
|
|
125
|
+
(suspended, cancelled, and so on) is reported as `'INACTIVO'`.
|
|
126
|
+
- An unregistered RNC or cédula **throws** `DgiiNotFoundError`. It is not
|
|
127
|
+
retried and does not count against the circuit breaker.
|
|
128
|
+
- Pass the digits you validated, not user input as typed.
|
|
129
|
+
|
|
130
|
+
### Invoice number: `getNCF(rncEmisor, ncf, options?)`
|
|
131
|
+
|
|
132
|
+
For a B-series NCF:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const r = await dgii.getNCF('131098193', 'B0100000001');
|
|
136
|
+
// found: { valid: true, rnc, ncf, nombreComercial? }
|
|
137
|
+
// not found: { valid: false, rnc: '', ncf: '' } (other fields undefined)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Unlike `getContribuyente`, a missing or invalid NCF does **not** throw; it
|
|
141
|
+
returns `valid: false`.
|
|
142
|
+
|
|
143
|
+
For an e-NCF (E-series), DGII needs the buyer's RNC **and** the 6-character
|
|
144
|
+
security code printed on the invoice. The types mark both optional because
|
|
145
|
+
B-series lookups ignore them, but without either one DGII refuses to answer
|
|
146
|
+
and `DgiiClient` throws `AllStrategiesFailedError` whose message contains
|
|
147
|
+
DGII's "es necesario completar el campo..." text.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const e = await dgii.getNCF('101010632', 'E310125217173', {
|
|
151
|
+
rncComprador: '131262414',
|
|
152
|
+
codigoSeguridad: 'KrOLI0',
|
|
153
|
+
});
|
|
154
|
+
// { valid: true, rnc: '101010632', ncf: 'E310125217173',
|
|
155
|
+
// rncComprador: '131262414', codigoSeguridad: 'KrOLI0',
|
|
156
|
+
// estado: 'Aceptado', montoTotal: 230677.74, totalItbis: 35188.13,
|
|
157
|
+
// fechaEmision: '2026-02-11', fechaFirma: '2026-02-11' }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
- For an e-NCF, `valid: true` means DGII **found** it, not that it is
|
|
161
|
+
accepted. Check `estado`.
|
|
162
|
+
- A wrong security code gives `valid: false`.
|
|
163
|
+
- `montoTotal` and `totalItbis` are numbers; `fechaEmision` and
|
|
164
|
+
`fechaFirma` are strings exactly as DGII shows them.
|
|
165
|
+
- The library decides "e-NCF or not" with `validateEcf`, so run the
|
|
166
|
+
offline validator first and only pass the options for an e-NCF.
|
|
167
|
+
- DGII also accepts a foreign ID in place of the buyer's RNC, but the
|
|
168
|
+
library has no option for it.
|
|
169
|
+
|
|
170
|
+
## Errors
|
|
171
|
+
|
|
172
|
+
`DgiiClient` only ever throws two things:
|
|
173
|
+
|
|
174
|
+
| Error (`code`) | Meaning | What to do |
|
|
175
|
+
| --- | --- | --- |
|
|
176
|
+
| `DgiiNotFoundError` (`DGII_NOT_FOUND`) | `getContribuyente`: DGII has no such RNC or cédula | Tell the user it is not registered. Do not retry. |
|
|
177
|
+
| `AllStrategiesFailedError` (`DGII_ALL_STRATEGIES_FAILED`) | Everything else, after the built-in retries: network down, timeout, DGII HTTP error, circuit open, DGII page changed, missing e-NCF fields, empty input | Report "DGII is unavailable, try later" and log `err.errors` (one error per strategy tried; `err.cause` is the first). |
|
|
178
|
+
|
|
179
|
+
The underlying `DgiiConnectionError` (`DGII_CONNECTION_ERROR`) and
|
|
180
|
+
`DgiiServiceError` (`DGII_SERVICE_ERROR`, with optional `statusCode`) are
|
|
181
|
+
inside `err.errors`; they are only thrown directly by the low-level
|
|
182
|
+
clients. `BulkFormatError` (`DGII_BULK_FORMAT_ERROR`) comes from
|
|
183
|
+
`parseBulkFile`. All of them extend `DgiiError` and are exported from
|
|
184
|
+
`dgii-ts/errors` (and the root). Matching on `err.code` also works when
|
|
185
|
+
`instanceof` cannot, for example when an app loads the package both as
|
|
186
|
+
ESM and as CommonJS.
|
|
187
|
+
|
|
188
|
+
Do not wrap calls in your own retry loop. The client already retries
|
|
189
|
+
connection errors and HTTP 5xx with backoff, and deliberately does not
|
|
190
|
+
retry 4xx or unexpected pages, because repeating those will not help.
|
|
191
|
+
|
|
192
|
+
Because empty input and missing e-NCF fields also surface as
|
|
193
|
+
`AllStrategiesFailedError`, validate before calling. Otherwise a
|
|
194
|
+
programming error looks like a DGII outage.
|
|
195
|
+
|
|
196
|
+
## Be gentle with DGII
|
|
197
|
+
|
|
198
|
+
DGII publishes no rate limit and these are its public web pages. Each
|
|
199
|
+
lookup is two HTTP requests (load the form, submit it).
|
|
200
|
+
|
|
201
|
+
- Validate offline first. Never send DGII an identifier that fails the
|
|
202
|
+
validator.
|
|
203
|
+
- Share one client (above).
|
|
204
|
+
- Cache results. Taxpayer names and statuses rarely change within a day.
|
|
205
|
+
- For batches, go one at a time or with very low concurrency. For more
|
|
206
|
+
than a few dozen RNCs, use the bulk file instead of live lookups.
|
|
207
|
+
- Keep the default retry and circuit-breaker settings unless you have a
|
|
208
|
+
measured reason; raising retries multiplies load during an outage.
|
|
209
|
+
|
|
210
|
+
## Bulk registry: DGII_RNC.zip
|
|
211
|
+
|
|
212
|
+
Node only (it uses `node:https` and `node:fs`).
|
|
213
|
+
|
|
214
|
+
The library downloads the ZIP but does not unzip it, and it has no zip
|
|
215
|
+
dependency. Extract the single entry `TMP/DGII_RNC.TXT` with the zip tool
|
|
216
|
+
the project already uses, or `adm-zip` (`npm install adm-zip`, plus
|
|
217
|
+
`@types/adm-zip` for TypeScript):
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import { writeFile } from 'node:fs/promises';
|
|
221
|
+
import AdmZip from 'adm-zip';
|
|
222
|
+
import { downloadBulkFile, parseBulkFile } from 'dgii-ts/bulk';
|
|
223
|
+
|
|
224
|
+
const zipPath = await downloadBulkFile({ outputDir: '/var/data/dgii' });
|
|
225
|
+
|
|
226
|
+
const entry = new AdmZip(zipPath).getEntry('TMP/DGII_RNC.TXT');
|
|
227
|
+
if (!entry) throw new Error('DGII_RNC.zip no longer contains TMP/DGII_RNC.TXT');
|
|
228
|
+
const txtPath = '/var/data/dgii/DGII_RNC.TXT';
|
|
229
|
+
await writeFile(txtPath, entry.getData());
|
|
230
|
+
|
|
231
|
+
const rows = await parseBulkFile({ filePath: txtPath });
|
|
232
|
+
const byRnc = new Map(rows.map((row) => [row.rnc, row]));
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- `downloadBulkFile` writes `<outputDir>/DGII_RNC.zip` (overwriting it) and
|
|
236
|
+
returns that path, relative if `outputDir` was relative. `timeout`
|
|
237
|
+
defaults to 60 s (clamped 5 s to 10 min). It rejects with a plain
|
|
238
|
+
`Error`, not a `DgiiError`.
|
|
239
|
+
- The ZIP holds one file, `TMP/DGII_RNC.TXT`: about 90 MB, pipe-delimited,
|
|
240
|
+
latin-1. The parser defaults to `latin1`; do not pass `utf8` or names
|
|
241
|
+
like MUÑOZ get corrupted.
|
|
242
|
+
- `parseBulkFile` returns the whole registry as one array (about 790,000
|
|
243
|
+
rows in September 2026, roughly 0.5 GB of memory at peak). Load it in a
|
|
244
|
+
scheduled job and write it to a database or index; do not parse it per
|
|
245
|
+
request.
|
|
246
|
+
- To check a list (suppliers, customers), validate each ID with
|
|
247
|
+
`validateRnc` **or** `validateCedula` (people appear by cédula), report
|
|
248
|
+
the ones that fail as bad format rather than "not registered", and look
|
|
249
|
+
the rest up by their digits.
|
|
250
|
+
- Each row: `rnc` (bare digits: 9 for an RNC, 11 for a cédula), `nombre`,
|
|
251
|
+
`nombreComercial`, `actividad` (DGII truncates it), `estado`, `regimen`,
|
|
252
|
+
`fechaConstitucion` (`dd/mm/yyyy` or empty).
|
|
253
|
+
- Bulk `estado` is DGII's full vocabulary, `DGII_ESTADOS`: `ACTIVO`,
|
|
254
|
+
`SUSPENDIDO`, `DADO DE BAJA`, `CESE TEMPORAL`, `ANULADO`, `RECHAZADO`.
|
|
255
|
+
That is not comparable with `getContribuyente`'s `ACTIVO`/`INACTIVO`.
|
|
256
|
+
- Rows without exactly 11 columns are skipped. If most sampled rows have
|
|
257
|
+
an unknown `estado`, it throws `BulkFormatError`: DGII changed the
|
|
258
|
+
layout, so fail loudly rather than import garbage.
|
|
259
|
+
|
|
260
|
+
## Imports
|
|
261
|
+
|
|
262
|
+
| Subpath | Contents | Runs in |
|
|
263
|
+
| --- | --- | --- |
|
|
264
|
+
| `dgii-ts/validators` | the four validators, `NCF_TYPE_NAMES`, `ECF_TYPE_NAMES` | anywhere, including the browser |
|
|
265
|
+
| `dgii-ts/client` | `DgiiClient` | server (Node 18+) |
|
|
266
|
+
| `dgii-ts/errors` | the error classes | anywhere |
|
|
267
|
+
| `dgii-ts/bulk` | `downloadBulkFile`, `parseBulkFile`, `DGII_ESTADOS`, `DGII_BULK_URL` | Node |
|
|
268
|
+
| `dgii-ts` | everything above plus the low-level clients | server |
|
|
269
|
+
|
|
270
|
+
Types (`ValidationResult`, `NcfValidationResult`, `Contribuyente`,
|
|
271
|
+
`NcfQueryOptions`, `NcfQueryResult`, `BulkContribuyente`, `ClientOptions`)
|
|
272
|
+
are exported from the root. Both ESM `import` and CommonJS `require` work.
|
|
273
|
+
In client-side bundles import from `dgii-ts/validators` only.
|