@deuriib/dgii-ecf 0.5.0 → 0.6.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/dist/MANIFEST.json +122 -0
- package/dist/README.md +44 -0
- package/dist/anecf.xsd +134 -0
- package/dist/arecf.xsd +69 -0
- package/dist/e-cf-32.xsd +1707 -0
- package/dist/e-cf-33.xsd +1724 -0
- package/dist/e-cf-34.xsd +1668 -0
- package/dist/e-cf-41.xsd +1543 -0
- package/dist/e-cf-43.xsd +1345 -0
- package/dist/e-cf-44.xsd +1618 -0
- package/dist/e-cf-45.xsd +1682 -0
- package/dist/e-cf-46.xsd +1642 -0
- package/dist/e-cf-47.xsd +1463 -0
- package/dist/index.cjs +422 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +180 -5
- package/dist/index.d.ts +180 -5
- package/dist/index.js +407 -43
- package/dist/index.js.map +1 -1
- package/dist/semilla.xsd +12 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -30,6 +30,7 @@ declare enum Endpoint {
|
|
|
30
30
|
InquiryStatus = "consultaestado/api/Consultas/Estado",
|
|
31
31
|
AllTrackingEcf = "ConsultaTrackIds/api/TrackIds/Consulta",
|
|
32
32
|
Directory = "consultadirectorio/api/consultas/obtenerdirectorioporrnc",
|
|
33
|
+
DirectoryList = "consultadirectorio/api/consultas/listado",
|
|
33
34
|
Void = "anulacionrangos/api/operaciones/anularrango"
|
|
34
35
|
}
|
|
35
36
|
/** Endpoints used when talking to a buyer's Sender↔Receiver host. */
|
|
@@ -39,6 +40,20 @@ declare enum SenderReceiverEndpoint {
|
|
|
39
40
|
SendInvoice = "fe/recepcion/api/ecf",
|
|
40
41
|
CommercialApproval = "fe/aprobacioncomercial/api/ecf"
|
|
41
42
|
}
|
|
43
|
+
/** Service-status endpoints. They carry no environment segment. */
|
|
44
|
+
declare enum StatusEndpoint {
|
|
45
|
+
Services = "api/estatusservicios/obtenerestatus",
|
|
46
|
+
MaintenanceWindows = "api/estatusservicios/obtenerventanasmantenimiento",
|
|
47
|
+
Check = "api/estatusservicios/verificarestado"
|
|
48
|
+
}
|
|
49
|
+
/** Numeric `ambiente` codes accepted by the status service. */
|
|
50
|
+
declare enum StatusEnvironment {
|
|
51
|
+
PreCertification = 1,
|
|
52
|
+
Production = 2,
|
|
53
|
+
Certification = 3
|
|
54
|
+
}
|
|
55
|
+
/** Build an absolute status-service URL (no environment segment). */
|
|
56
|
+
declare const buildStatusUrl: (endpoint: StatusEndpoint, baseUrl?: string) => string;
|
|
42
57
|
/** Build an absolute DGII URL: `${baseUrl}/${environment}/${endpoint}`. */
|
|
43
58
|
declare const buildUrl: (environment: Environment, endpoint: Endpoint, baseUrl?: string) => string;
|
|
44
59
|
/** Build an absolute Sender↔Receiver URL against a buyer host. */
|
|
@@ -46,7 +61,11 @@ declare const buildSenderReceiverUrl: (host: string, endpoint: SenderReceiverEnd
|
|
|
46
61
|
|
|
47
62
|
interface Mensaje {
|
|
48
63
|
valor: string;
|
|
49
|
-
|
|
64
|
+
/**
|
|
65
|
+
* DGII message code. Numeric on the status endpoints, a string on the RFCE
|
|
66
|
+
* response, so both shapes are preserved instead of coerced.
|
|
67
|
+
*/
|
|
68
|
+
codigo: number | string;
|
|
50
69
|
}
|
|
51
70
|
interface AuthToken {
|
|
52
71
|
token: string;
|
|
@@ -72,10 +91,17 @@ interface TrackingStatusResponse {
|
|
|
72
91
|
mensajes?: Mensaje[];
|
|
73
92
|
}
|
|
74
93
|
type InquiryStatusCode = 0 | 1 | 2;
|
|
75
|
-
|
|
94
|
+
/**
|
|
95
|
+
* eNCF inquiry states. "Aceptado Condicional" is observable for an E32 below
|
|
96
|
+
* RD$250,000 even though the tracking service reports it with a different
|
|
97
|
+
* code, so it belongs in the union.
|
|
98
|
+
*/
|
|
99
|
+
type InquiryStatus = 'No encontrado' | 'Aceptado' | 'Rechazado' | 'Aceptado Condicional';
|
|
76
100
|
interface InquiryStatusResponse {
|
|
77
101
|
codigo: InquiryStatusCode;
|
|
78
102
|
estado: InquiryStatus;
|
|
103
|
+
/** `true` when the e-NCF sequence is already consumed. */
|
|
104
|
+
secuenciaUtilizada?: boolean;
|
|
79
105
|
rncEmisor?: string;
|
|
80
106
|
ncfElectronico?: string;
|
|
81
107
|
montoTotal?: number;
|
|
@@ -102,9 +128,18 @@ interface InvoiceResponse {
|
|
|
102
128
|
/** Tolerated array form used by the RFCE and status endpoints. */
|
|
103
129
|
mensajes?: Mensaje[];
|
|
104
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Documented states of an RFCE reception. DGII is not consistent about casing
|
|
133
|
+
* between services (the tracking service reports "Aceptado Condicional"), so
|
|
134
|
+
* `estado` stays a `string` and these constants are the documented values.
|
|
135
|
+
*/
|
|
136
|
+
declare const SUMMARY_ACCEPTED = "Aceptado";
|
|
137
|
+
declare const SUMMARY_CONDITIONAL_ACCEPTED = "Aceptado condicional";
|
|
138
|
+
declare const SUMMARY_REJECTED = "Rechazado";
|
|
105
139
|
interface InvoiceSummaryResponse {
|
|
106
140
|
codigo: number;
|
|
107
|
-
|
|
141
|
+
/** One of the `SUMMARY_*` constants, compared case-insensitively. */
|
|
142
|
+
estado: string;
|
|
108
143
|
mensajes?: Mensaje[];
|
|
109
144
|
encf: string;
|
|
110
145
|
secuenciaUtilizada: boolean;
|
|
@@ -134,7 +169,34 @@ interface VoidNCFResponse {
|
|
|
134
169
|
rnc: string;
|
|
135
170
|
codigo: string;
|
|
136
171
|
nombre: string;
|
|
137
|
-
|
|
172
|
+
/** DGII returns objects on some services and bare strings on others. */
|
|
173
|
+
mensajes: Mensaje[];
|
|
174
|
+
}
|
|
175
|
+
/** Operational state reported by the DGII status service. */
|
|
176
|
+
type ServiceAvailability = 'Disponible' | 'No Disponible';
|
|
177
|
+
/** One entry of `getServiceStatus` (`estatusservicios/obtenerestatus`). */
|
|
178
|
+
interface ServiceStatusEntry {
|
|
179
|
+
servicio: string;
|
|
180
|
+
estatus: ServiceAvailability;
|
|
181
|
+
ambiente: string;
|
|
182
|
+
}
|
|
183
|
+
/** One maintenance window of `getMaintenanceWindows`. */
|
|
184
|
+
interface MaintenanceWindow {
|
|
185
|
+
ambiente: string;
|
|
186
|
+
horaInicio: string;
|
|
187
|
+
horaFin: string;
|
|
188
|
+
dias: string[];
|
|
189
|
+
}
|
|
190
|
+
/** Result of `checkServiceAvailability` (`estatusservicios/verificarestado`). */
|
|
191
|
+
interface ServiceAvailabilityResponse {
|
|
192
|
+
estado: ServiceAvailability;
|
|
193
|
+
}
|
|
194
|
+
/** Outcome of a direct ACECF delivery to a buyer host (Emisor↔Receptor). */
|
|
195
|
+
interface B2BCommercialApprovalResponse {
|
|
196
|
+
/** HTTP status returned by the buyer host: 200 satisfactory, 400 unsatisfactory. */
|
|
197
|
+
status: 200 | 400;
|
|
198
|
+
/** `true` for HTTP 200, `false` for HTTP 400. */
|
|
199
|
+
accepted: boolean;
|
|
138
200
|
}
|
|
139
201
|
|
|
140
202
|
type DgiiErrorCode = 'INVALID_XML' | 'CERTIFICATE' | 'SIGNING' | 'HTTP' | 'AUTH' | 'TIMEOUT' | 'CIRCUIT_OPEN' | 'IDEMPOTENCY' | 'VALIDATION' | 'UNKNOWN';
|
|
@@ -275,6 +337,8 @@ interface RequestOptions {
|
|
|
275
337
|
resource?: string;
|
|
276
338
|
/** Skip the auth hooks (used by the authentication round-trip itself). */
|
|
277
339
|
skipAuthHooks?: boolean;
|
|
340
|
+
/** Do not attach the bearer token (used by the status service). */
|
|
341
|
+
omitAuth?: boolean;
|
|
278
342
|
}
|
|
279
343
|
/** Thin HTTP client over the native `fetch`, wrapped in resilience policies. */
|
|
280
344
|
declare class HttpClient {
|
|
@@ -366,6 +430,14 @@ declare const validateXMLCertificate: (xml: string) => XmlCertificateValidation;
|
|
|
366
430
|
* Values that are not plain decimals (e.g. `1.0e3`) are returned unchanged.
|
|
367
431
|
*/
|
|
368
432
|
declare const roundHalfUpToCents: (value: string) => string;
|
|
433
|
+
/**
|
|
434
|
+
* Drop empty leaves and the containers they leave behind.
|
|
435
|
+
*
|
|
436
|
+
* DGII forbids empty tags: any element without a value must be omitted
|
|
437
|
+
* entirely instead of being serialized as `<Tag/>` or `<Tag></Tag>`. An object
|
|
438
|
+
* that only carries `_attributes` is *not* empty — it still renders an element.
|
|
439
|
+
*/
|
|
440
|
+
declare const pruneEmptyValues: (input: unknown) => unknown;
|
|
369
441
|
/**
|
|
370
442
|
* Converts between the DGII XML documents and the "compact" JSON shape used by
|
|
371
443
|
* `xml-js` (a dict key is an element, an array is a repeated element, and
|
|
@@ -414,6 +486,66 @@ declare const compareDecimal: (a: string, b: string) => number;
|
|
|
414
486
|
* cannot drift from what is actually being transmitted.
|
|
415
487
|
*/
|
|
416
488
|
declare const resolveReceptionRoute: (signedXml: string) => Result<ReceptionRoute, DgiiError>;
|
|
489
|
+
/**
|
|
490
|
+
* Whether a signed document may be delivered directly to a buyer host.
|
|
491
|
+
*
|
|
492
|
+
* DGII excludes E32 below RD$250,000 (only the RFCE summary applies) plus
|
|
493
|
+
* E41, E43, E45, E46 and E47. E31, E33, E34, E44 and an E32 at or above the
|
|
494
|
+
* threshold can go peer-to-peer.
|
|
495
|
+
*/
|
|
496
|
+
declare const checkB2BApplicability: (signedXml: string) => Result<void, DgiiError>;
|
|
497
|
+
|
|
498
|
+
/** Message returned when a submission with the same key is already in flight. */
|
|
499
|
+
declare const PENDING_SUBMISSION_MESSAGE = "A submission with this key is already pending; call reconcileSubmission() before retrying";
|
|
500
|
+
/** Outcome of reconciling a pending submission against DGII. */
|
|
501
|
+
interface ReconciliationResult {
|
|
502
|
+
/** DGII's answer for the e-NCF. */
|
|
503
|
+
inquiry: InquiryStatusResponse;
|
|
504
|
+
/** `true` when DGII already has a record of the document. */
|
|
505
|
+
delivered: boolean;
|
|
506
|
+
/** `true` when the e-NCF sequence may be reused. */
|
|
507
|
+
canReuseSequence: boolean;
|
|
508
|
+
/** `true` when the pending marker was cleared and a retry is safe. */
|
|
509
|
+
cleared: boolean;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Whether a rejected e-NCF sequence may be reused.
|
|
513
|
+
*
|
|
514
|
+
* DGII sets `secuenciaUtilizada` to `true` when the sequence is consumed and
|
|
515
|
+
* `false` when the rejection leaves it reusable: invalid certificate or
|
|
516
|
+
* signature, invalid XML, non-delegated signer, unauthorized or expired e-NCF,
|
|
517
|
+
* non-electronic issuer, unknown or inactive RNC.
|
|
518
|
+
*
|
|
519
|
+
* An absent flag is treated as "not reusable" — the conservative answer.
|
|
520
|
+
*/
|
|
521
|
+
declare const canReuseSequence: (response: {
|
|
522
|
+
secuenciaUtilizada?: boolean | null;
|
|
523
|
+
}) => boolean;
|
|
524
|
+
|
|
525
|
+
declare const SCHEMA_DIR: string;
|
|
526
|
+
/** Schemas DGII publishes but that do not compile, with the reason. */
|
|
527
|
+
declare const UNAVAILABLE_SCHEMAS: Record<string, string>;
|
|
528
|
+
/** One schema violation, with the element DGII would complain about. */
|
|
529
|
+
interface SchemaViolation {
|
|
530
|
+
path: string;
|
|
531
|
+
message: string;
|
|
532
|
+
}
|
|
533
|
+
interface ValidationOptions {
|
|
534
|
+
/**
|
|
535
|
+
* `xmllint` binary to use. Defaults to `DGII_XMLLINT_BIN` or `xmllint` on
|
|
536
|
+
* `PATH`. There is no bundled engine: validation shells out.
|
|
537
|
+
*/
|
|
538
|
+
bin?: string;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Validate a DGII document against its bundled XML Schema.
|
|
542
|
+
*
|
|
543
|
+
* Requires `xmllint` (libxml2-utils) on `PATH`, or `DGII_XMLLINT_BIN` pointing
|
|
544
|
+
* at it. A missing binary is an error — never a silent pass.
|
|
545
|
+
*/
|
|
546
|
+
declare const validateDocument: (xml: string, options?: ValidationOptions) => Result<SchemaViolation[], DgiiError>;
|
|
547
|
+
/** One-line summary of the first violations, for an error message. */
|
|
548
|
+
declare const formatViolations: (violations: readonly SchemaViolation[]) => string;
|
|
417
549
|
|
|
418
550
|
/** First 6 chars of the `<SignatureValue>` (DGII security code). */
|
|
419
551
|
declare const getCodeSixDigitfromSignature: (signedXml: string) => Result<string, DgiiError>;
|
|
@@ -452,6 +584,20 @@ interface EcfOptions {
|
|
|
452
584
|
tokenRefreshSkewMs?: number;
|
|
453
585
|
/** Injectable clock (epoch milliseconds); useful for tests. */
|
|
454
586
|
now?: () => number;
|
|
587
|
+
/** API key for the `statusecf` service (`Authorization: Apikey …`). */
|
|
588
|
+
statusApiKey?: string;
|
|
589
|
+
/**
|
|
590
|
+
* Reject a direct buyer-host delivery for the e-CF types DGII excludes
|
|
591
|
+
* (E32 below RD$250,000, E41, E43, E45, E46, E47). Defaults to `true`.
|
|
592
|
+
*/
|
|
593
|
+
enforceB2BRules?: boolean;
|
|
594
|
+
/**
|
|
595
|
+
* Validate a general e-CF against its bundled XML Schema before sending.
|
|
596
|
+
* Requires `xmllint` (or `DGII_XMLLINT_BIN`). Defaults to `false`.
|
|
597
|
+
*/
|
|
598
|
+
validateBeforeSend?: boolean;
|
|
599
|
+
/** `xmllint` binary used by `validateBeforeSend`. */
|
|
600
|
+
xmllintBin?: string;
|
|
455
601
|
}
|
|
456
602
|
/**
|
|
457
603
|
* DGII e-CF client. Every method returns a `Result` — no thrown domain errors.
|
|
@@ -464,6 +610,10 @@ declare class ECF {
|
|
|
464
610
|
private readonly inFlight;
|
|
465
611
|
private readonly tokenRefreshSkewMs;
|
|
466
612
|
private readonly now;
|
|
613
|
+
private readonly statusApiKey;
|
|
614
|
+
private readonly enforceB2BRules;
|
|
615
|
+
private readonly validateBeforeSend;
|
|
616
|
+
private readonly xmllintBin;
|
|
467
617
|
private tokenExpiresAt;
|
|
468
618
|
private refreshPromise;
|
|
469
619
|
constructor(credentials: P12ReaderData, environment?: Environment, options?: EcfOptions);
|
|
@@ -490,6 +640,28 @@ declare class ECF {
|
|
|
490
640
|
private reauthenticate;
|
|
491
641
|
/** Authenticate against DGII (or a buyer host) and store the bearer token. */
|
|
492
642
|
authenticate(buyerHost?: string): Promise<Result<AuthToken, DgiiError>>;
|
|
643
|
+
/**
|
|
644
|
+
* Query the operational status of every DGII service.
|
|
645
|
+
*
|
|
646
|
+
* The status host takes an API key instead of a bearer token, so this call
|
|
647
|
+
* neither needs `authenticate()` nor triggers a token refresh.
|
|
648
|
+
*/
|
|
649
|
+
getServiceStatus(): Promise<Result<ServiceStatusEntry[], DgiiError>>;
|
|
650
|
+
/** Scheduled maintenance windows, one entry per environment. */
|
|
651
|
+
getMaintenanceWindows(): Promise<Result<MaintenanceWindow[], DgiiError>>;
|
|
652
|
+
/** Whether an environment is currently inside a maintenance window. */
|
|
653
|
+
checkServiceAvailability(ambiente: StatusEnvironment): Promise<Result<ServiceAvailabilityResponse, DgiiError>>;
|
|
654
|
+
private statusRequest;
|
|
655
|
+
/**
|
|
656
|
+
* Resolve what happened to a submission whose idempotency marker is pending.
|
|
657
|
+
*
|
|
658
|
+
* Queries DGII by e-NCF. When DGII has no record of the document the marker
|
|
659
|
+
* is cleared, because re-submitting cannot double-issue. When DGII does have
|
|
660
|
+
* a record the marker stays in place — it is the lock that prevents a second
|
|
661
|
+
* submission of a document that already exists — and `delivered` tells the
|
|
662
|
+
* caller to stop retrying.
|
|
663
|
+
*/
|
|
664
|
+
reconcileSubmission(signedXml: string): Promise<Result<ReconciliationResult, DgiiError>>;
|
|
493
665
|
private getSeed;
|
|
494
666
|
private getAuthToken;
|
|
495
667
|
/**
|
|
@@ -513,6 +685,8 @@ declare class ECF {
|
|
|
513
685
|
trackStatuses(rncEmisor: string, encf: string): Promise<Result<SummaryTrackingStatusResponse[], DgiiError>>;
|
|
514
686
|
/** Normalizes DGII's inconsistent (array | single object) directory payload. */
|
|
515
687
|
getCustomerDirectory(rnc: string): Promise<Result<ServiceDirectoryResponse[] | undefined, DgiiError>>;
|
|
688
|
+
/** General directory listing — every receiver that publishes service URLs. */
|
|
689
|
+
getDirectoryListing(): Promise<Result<ServiceDirectoryResponse[], DgiiError>>;
|
|
516
690
|
/** RFCE inquiry — DGII production only. */
|
|
517
691
|
getSummaryInvoiceInquiry(rnc: string, encf: string, codSeguridad: string): Promise<Result<InquiryInvoiceSummary, DgiiError>>;
|
|
518
692
|
/**
|
|
@@ -520,6 +694,7 @@ declare class ECF {
|
|
|
520
694
|
* keyed on `RNC + eNCF + SHA-256(signed XML)`.
|
|
521
695
|
*/
|
|
522
696
|
sendCommercialApproval(signedXml: string, fileName: string): Promise<Result<CommercialApprovalResponse, DgiiError>>;
|
|
697
|
+
sendCommercialApproval(signedXml: string, fileName: string, buyerHost: string): Promise<Result<B2BCommercialApprovalResponse, DgiiError>>;
|
|
523
698
|
/**
|
|
524
699
|
* Submit a signed range-voiding request (ANECF). Idempotent like
|
|
525
700
|
* submissions, keyed on `RNC + RangoNCF + SHA-256(signed XML)`.
|
|
@@ -527,4 +702,4 @@ declare class ECF {
|
|
|
527
702
|
voidENCF(signedXml: string, fileName: string): Promise<Result<VoidNCFResponse, DgiiError>>;
|
|
528
703
|
}
|
|
529
704
|
|
|
530
|
-
export { type AuthToken, BaseUrl, type BaseUrlKey, CONSUMPTION_SUMMARY_THRESHOLD, type CertificateInfo, type CommercialApprovalResponse, type DgiiDocumentType, DgiiError, type DgiiErrorCode, type DgiiErrorContext, type DgiiErrorOptions, type DgiiResult, ECF, ECF_TYPE_CODES, type EcfOptions, type EcfTypeCode, Endpoint, Environment, type GeneralReceptionRoute, HttpClient, type HttpClientOptions, type IdempotencyStore, InMemoryIdempotencyStore, type InMemoryIdempotencyStoreOptions, type InquiryInvoiceSummary, type InquiryStatus, type InquiryStatusCode, type InquiryStatusResponse, type InvoiceResponse, type InvoiceSummaryResponse, type Mensaje, P12Reader, type P12ReaderData, type ReceptionRoute, type RequestOptions, type ResilienceOptions, type ResiliencePolicies, SenderReceiverEndpoint, type ServiceDirectoryResponse, Signature, type SummaryReceptionRoute, type SummaryTrackingStatusResponse, type TrackStatusCode, TrackStatusEnum, type TrackingStatusResponse, Transformer, type VoidNCFResponse, type XmlCertificateValidation, buildSenderReceiverUrl, buildUrl, compareDecimal, convertECF32ToRFCE, createResiliencePolicies, defaultResilienceOptions, extractDgiiErrorMessage, generateEcfQRCodeURL, generateFcQRCodeURL, getCodeSixDigitfromSignature, getCurrentFormattedDate, getCurrentFormattedDateTime, getXmlFromBodyResponse, isEcfTypeCode, isRetryableError, isRetryableStatus, resolveReceptionRoute, roundHalfUpToCents, toDgiiError, validateXMLCertificate };
|
|
705
|
+
export { type AuthToken, type B2BCommercialApprovalResponse, BaseUrl, type BaseUrlKey, CONSUMPTION_SUMMARY_THRESHOLD, type CertificateInfo, type CommercialApprovalResponse, type DgiiDocumentType, DgiiError, type DgiiErrorCode, type DgiiErrorContext, type DgiiErrorOptions, type DgiiResult, ECF, ECF_TYPE_CODES, type EcfOptions, type EcfTypeCode, Endpoint, Environment, type GeneralReceptionRoute, HttpClient, type HttpClientOptions, type IdempotencyStore, InMemoryIdempotencyStore, type InMemoryIdempotencyStoreOptions, type InquiryInvoiceSummary, type InquiryStatus, type InquiryStatusCode, type InquiryStatusResponse, type InvoiceResponse, type InvoiceSummaryResponse, type MaintenanceWindow, type Mensaje, P12Reader, type P12ReaderData, PENDING_SUBMISSION_MESSAGE, type ReceptionRoute, type ReconciliationResult, type RequestOptions, type ResilienceOptions, type ResiliencePolicies, SCHEMA_DIR, SUMMARY_ACCEPTED, SUMMARY_CONDITIONAL_ACCEPTED, SUMMARY_REJECTED, type SchemaViolation, SenderReceiverEndpoint, type ServiceAvailability, type ServiceAvailabilityResponse, type ServiceDirectoryResponse, type ServiceStatusEntry, Signature, StatusEndpoint, StatusEnvironment, type SummaryReceptionRoute, type SummaryTrackingStatusResponse, type TrackStatusCode, TrackStatusEnum, type TrackingStatusResponse, Transformer, UNAVAILABLE_SCHEMAS, type ValidationOptions, type VoidNCFResponse, type XmlCertificateValidation, buildSenderReceiverUrl, buildStatusUrl, buildUrl, canReuseSequence, checkB2BApplicability, compareDecimal, convertECF32ToRFCE, createResiliencePolicies, defaultResilienceOptions, extractDgiiErrorMessage, formatViolations, generateEcfQRCodeURL, generateFcQRCodeURL, getCodeSixDigitfromSignature, getCurrentFormattedDate, getCurrentFormattedDateTime, getXmlFromBodyResponse, isEcfTypeCode, isRetryableError, isRetryableStatus, pruneEmptyValues, resolveReceptionRoute, roundHalfUpToCents, toDgiiError, validateDocument, validateXMLCertificate };
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ declare enum Endpoint {
|
|
|
30
30
|
InquiryStatus = "consultaestado/api/Consultas/Estado",
|
|
31
31
|
AllTrackingEcf = "ConsultaTrackIds/api/TrackIds/Consulta",
|
|
32
32
|
Directory = "consultadirectorio/api/consultas/obtenerdirectorioporrnc",
|
|
33
|
+
DirectoryList = "consultadirectorio/api/consultas/listado",
|
|
33
34
|
Void = "anulacionrangos/api/operaciones/anularrango"
|
|
34
35
|
}
|
|
35
36
|
/** Endpoints used when talking to a buyer's Sender↔Receiver host. */
|
|
@@ -39,6 +40,20 @@ declare enum SenderReceiverEndpoint {
|
|
|
39
40
|
SendInvoice = "fe/recepcion/api/ecf",
|
|
40
41
|
CommercialApproval = "fe/aprobacioncomercial/api/ecf"
|
|
41
42
|
}
|
|
43
|
+
/** Service-status endpoints. They carry no environment segment. */
|
|
44
|
+
declare enum StatusEndpoint {
|
|
45
|
+
Services = "api/estatusservicios/obtenerestatus",
|
|
46
|
+
MaintenanceWindows = "api/estatusservicios/obtenerventanasmantenimiento",
|
|
47
|
+
Check = "api/estatusservicios/verificarestado"
|
|
48
|
+
}
|
|
49
|
+
/** Numeric `ambiente` codes accepted by the status service. */
|
|
50
|
+
declare enum StatusEnvironment {
|
|
51
|
+
PreCertification = 1,
|
|
52
|
+
Production = 2,
|
|
53
|
+
Certification = 3
|
|
54
|
+
}
|
|
55
|
+
/** Build an absolute status-service URL (no environment segment). */
|
|
56
|
+
declare const buildStatusUrl: (endpoint: StatusEndpoint, baseUrl?: string) => string;
|
|
42
57
|
/** Build an absolute DGII URL: `${baseUrl}/${environment}/${endpoint}`. */
|
|
43
58
|
declare const buildUrl: (environment: Environment, endpoint: Endpoint, baseUrl?: string) => string;
|
|
44
59
|
/** Build an absolute Sender↔Receiver URL against a buyer host. */
|
|
@@ -46,7 +61,11 @@ declare const buildSenderReceiverUrl: (host: string, endpoint: SenderReceiverEnd
|
|
|
46
61
|
|
|
47
62
|
interface Mensaje {
|
|
48
63
|
valor: string;
|
|
49
|
-
|
|
64
|
+
/**
|
|
65
|
+
* DGII message code. Numeric on the status endpoints, a string on the RFCE
|
|
66
|
+
* response, so both shapes are preserved instead of coerced.
|
|
67
|
+
*/
|
|
68
|
+
codigo: number | string;
|
|
50
69
|
}
|
|
51
70
|
interface AuthToken {
|
|
52
71
|
token: string;
|
|
@@ -72,10 +91,17 @@ interface TrackingStatusResponse {
|
|
|
72
91
|
mensajes?: Mensaje[];
|
|
73
92
|
}
|
|
74
93
|
type InquiryStatusCode = 0 | 1 | 2;
|
|
75
|
-
|
|
94
|
+
/**
|
|
95
|
+
* eNCF inquiry states. "Aceptado Condicional" is observable for an E32 below
|
|
96
|
+
* RD$250,000 even though the tracking service reports it with a different
|
|
97
|
+
* code, so it belongs in the union.
|
|
98
|
+
*/
|
|
99
|
+
type InquiryStatus = 'No encontrado' | 'Aceptado' | 'Rechazado' | 'Aceptado Condicional';
|
|
76
100
|
interface InquiryStatusResponse {
|
|
77
101
|
codigo: InquiryStatusCode;
|
|
78
102
|
estado: InquiryStatus;
|
|
103
|
+
/** `true` when the e-NCF sequence is already consumed. */
|
|
104
|
+
secuenciaUtilizada?: boolean;
|
|
79
105
|
rncEmisor?: string;
|
|
80
106
|
ncfElectronico?: string;
|
|
81
107
|
montoTotal?: number;
|
|
@@ -102,9 +128,18 @@ interface InvoiceResponse {
|
|
|
102
128
|
/** Tolerated array form used by the RFCE and status endpoints. */
|
|
103
129
|
mensajes?: Mensaje[];
|
|
104
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Documented states of an RFCE reception. DGII is not consistent about casing
|
|
133
|
+
* between services (the tracking service reports "Aceptado Condicional"), so
|
|
134
|
+
* `estado` stays a `string` and these constants are the documented values.
|
|
135
|
+
*/
|
|
136
|
+
declare const SUMMARY_ACCEPTED = "Aceptado";
|
|
137
|
+
declare const SUMMARY_CONDITIONAL_ACCEPTED = "Aceptado condicional";
|
|
138
|
+
declare const SUMMARY_REJECTED = "Rechazado";
|
|
105
139
|
interface InvoiceSummaryResponse {
|
|
106
140
|
codigo: number;
|
|
107
|
-
|
|
141
|
+
/** One of the `SUMMARY_*` constants, compared case-insensitively. */
|
|
142
|
+
estado: string;
|
|
108
143
|
mensajes?: Mensaje[];
|
|
109
144
|
encf: string;
|
|
110
145
|
secuenciaUtilizada: boolean;
|
|
@@ -134,7 +169,34 @@ interface VoidNCFResponse {
|
|
|
134
169
|
rnc: string;
|
|
135
170
|
codigo: string;
|
|
136
171
|
nombre: string;
|
|
137
|
-
|
|
172
|
+
/** DGII returns objects on some services and bare strings on others. */
|
|
173
|
+
mensajes: Mensaje[];
|
|
174
|
+
}
|
|
175
|
+
/** Operational state reported by the DGII status service. */
|
|
176
|
+
type ServiceAvailability = 'Disponible' | 'No Disponible';
|
|
177
|
+
/** One entry of `getServiceStatus` (`estatusservicios/obtenerestatus`). */
|
|
178
|
+
interface ServiceStatusEntry {
|
|
179
|
+
servicio: string;
|
|
180
|
+
estatus: ServiceAvailability;
|
|
181
|
+
ambiente: string;
|
|
182
|
+
}
|
|
183
|
+
/** One maintenance window of `getMaintenanceWindows`. */
|
|
184
|
+
interface MaintenanceWindow {
|
|
185
|
+
ambiente: string;
|
|
186
|
+
horaInicio: string;
|
|
187
|
+
horaFin: string;
|
|
188
|
+
dias: string[];
|
|
189
|
+
}
|
|
190
|
+
/** Result of `checkServiceAvailability` (`estatusservicios/verificarestado`). */
|
|
191
|
+
interface ServiceAvailabilityResponse {
|
|
192
|
+
estado: ServiceAvailability;
|
|
193
|
+
}
|
|
194
|
+
/** Outcome of a direct ACECF delivery to a buyer host (Emisor↔Receptor). */
|
|
195
|
+
interface B2BCommercialApprovalResponse {
|
|
196
|
+
/** HTTP status returned by the buyer host: 200 satisfactory, 400 unsatisfactory. */
|
|
197
|
+
status: 200 | 400;
|
|
198
|
+
/** `true` for HTTP 200, `false` for HTTP 400. */
|
|
199
|
+
accepted: boolean;
|
|
138
200
|
}
|
|
139
201
|
|
|
140
202
|
type DgiiErrorCode = 'INVALID_XML' | 'CERTIFICATE' | 'SIGNING' | 'HTTP' | 'AUTH' | 'TIMEOUT' | 'CIRCUIT_OPEN' | 'IDEMPOTENCY' | 'VALIDATION' | 'UNKNOWN';
|
|
@@ -275,6 +337,8 @@ interface RequestOptions {
|
|
|
275
337
|
resource?: string;
|
|
276
338
|
/** Skip the auth hooks (used by the authentication round-trip itself). */
|
|
277
339
|
skipAuthHooks?: boolean;
|
|
340
|
+
/** Do not attach the bearer token (used by the status service). */
|
|
341
|
+
omitAuth?: boolean;
|
|
278
342
|
}
|
|
279
343
|
/** Thin HTTP client over the native `fetch`, wrapped in resilience policies. */
|
|
280
344
|
declare class HttpClient {
|
|
@@ -366,6 +430,14 @@ declare const validateXMLCertificate: (xml: string) => XmlCertificateValidation;
|
|
|
366
430
|
* Values that are not plain decimals (e.g. `1.0e3`) are returned unchanged.
|
|
367
431
|
*/
|
|
368
432
|
declare const roundHalfUpToCents: (value: string) => string;
|
|
433
|
+
/**
|
|
434
|
+
* Drop empty leaves and the containers they leave behind.
|
|
435
|
+
*
|
|
436
|
+
* DGII forbids empty tags: any element without a value must be omitted
|
|
437
|
+
* entirely instead of being serialized as `<Tag/>` or `<Tag></Tag>`. An object
|
|
438
|
+
* that only carries `_attributes` is *not* empty — it still renders an element.
|
|
439
|
+
*/
|
|
440
|
+
declare const pruneEmptyValues: (input: unknown) => unknown;
|
|
369
441
|
/**
|
|
370
442
|
* Converts between the DGII XML documents and the "compact" JSON shape used by
|
|
371
443
|
* `xml-js` (a dict key is an element, an array is a repeated element, and
|
|
@@ -414,6 +486,66 @@ declare const compareDecimal: (a: string, b: string) => number;
|
|
|
414
486
|
* cannot drift from what is actually being transmitted.
|
|
415
487
|
*/
|
|
416
488
|
declare const resolveReceptionRoute: (signedXml: string) => Result<ReceptionRoute, DgiiError>;
|
|
489
|
+
/**
|
|
490
|
+
* Whether a signed document may be delivered directly to a buyer host.
|
|
491
|
+
*
|
|
492
|
+
* DGII excludes E32 below RD$250,000 (only the RFCE summary applies) plus
|
|
493
|
+
* E41, E43, E45, E46 and E47. E31, E33, E34, E44 and an E32 at or above the
|
|
494
|
+
* threshold can go peer-to-peer.
|
|
495
|
+
*/
|
|
496
|
+
declare const checkB2BApplicability: (signedXml: string) => Result<void, DgiiError>;
|
|
497
|
+
|
|
498
|
+
/** Message returned when a submission with the same key is already in flight. */
|
|
499
|
+
declare const PENDING_SUBMISSION_MESSAGE = "A submission with this key is already pending; call reconcileSubmission() before retrying";
|
|
500
|
+
/** Outcome of reconciling a pending submission against DGII. */
|
|
501
|
+
interface ReconciliationResult {
|
|
502
|
+
/** DGII's answer for the e-NCF. */
|
|
503
|
+
inquiry: InquiryStatusResponse;
|
|
504
|
+
/** `true` when DGII already has a record of the document. */
|
|
505
|
+
delivered: boolean;
|
|
506
|
+
/** `true` when the e-NCF sequence may be reused. */
|
|
507
|
+
canReuseSequence: boolean;
|
|
508
|
+
/** `true` when the pending marker was cleared and a retry is safe. */
|
|
509
|
+
cleared: boolean;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Whether a rejected e-NCF sequence may be reused.
|
|
513
|
+
*
|
|
514
|
+
* DGII sets `secuenciaUtilizada` to `true` when the sequence is consumed and
|
|
515
|
+
* `false` when the rejection leaves it reusable: invalid certificate or
|
|
516
|
+
* signature, invalid XML, non-delegated signer, unauthorized or expired e-NCF,
|
|
517
|
+
* non-electronic issuer, unknown or inactive RNC.
|
|
518
|
+
*
|
|
519
|
+
* An absent flag is treated as "not reusable" — the conservative answer.
|
|
520
|
+
*/
|
|
521
|
+
declare const canReuseSequence: (response: {
|
|
522
|
+
secuenciaUtilizada?: boolean | null;
|
|
523
|
+
}) => boolean;
|
|
524
|
+
|
|
525
|
+
declare const SCHEMA_DIR: string;
|
|
526
|
+
/** Schemas DGII publishes but that do not compile, with the reason. */
|
|
527
|
+
declare const UNAVAILABLE_SCHEMAS: Record<string, string>;
|
|
528
|
+
/** One schema violation, with the element DGII would complain about. */
|
|
529
|
+
interface SchemaViolation {
|
|
530
|
+
path: string;
|
|
531
|
+
message: string;
|
|
532
|
+
}
|
|
533
|
+
interface ValidationOptions {
|
|
534
|
+
/**
|
|
535
|
+
* `xmllint` binary to use. Defaults to `DGII_XMLLINT_BIN` or `xmllint` on
|
|
536
|
+
* `PATH`. There is no bundled engine: validation shells out.
|
|
537
|
+
*/
|
|
538
|
+
bin?: string;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Validate a DGII document against its bundled XML Schema.
|
|
542
|
+
*
|
|
543
|
+
* Requires `xmllint` (libxml2-utils) on `PATH`, or `DGII_XMLLINT_BIN` pointing
|
|
544
|
+
* at it. A missing binary is an error — never a silent pass.
|
|
545
|
+
*/
|
|
546
|
+
declare const validateDocument: (xml: string, options?: ValidationOptions) => Result<SchemaViolation[], DgiiError>;
|
|
547
|
+
/** One-line summary of the first violations, for an error message. */
|
|
548
|
+
declare const formatViolations: (violations: readonly SchemaViolation[]) => string;
|
|
417
549
|
|
|
418
550
|
/** First 6 chars of the `<SignatureValue>` (DGII security code). */
|
|
419
551
|
declare const getCodeSixDigitfromSignature: (signedXml: string) => Result<string, DgiiError>;
|
|
@@ -452,6 +584,20 @@ interface EcfOptions {
|
|
|
452
584
|
tokenRefreshSkewMs?: number;
|
|
453
585
|
/** Injectable clock (epoch milliseconds); useful for tests. */
|
|
454
586
|
now?: () => number;
|
|
587
|
+
/** API key for the `statusecf` service (`Authorization: Apikey …`). */
|
|
588
|
+
statusApiKey?: string;
|
|
589
|
+
/**
|
|
590
|
+
* Reject a direct buyer-host delivery for the e-CF types DGII excludes
|
|
591
|
+
* (E32 below RD$250,000, E41, E43, E45, E46, E47). Defaults to `true`.
|
|
592
|
+
*/
|
|
593
|
+
enforceB2BRules?: boolean;
|
|
594
|
+
/**
|
|
595
|
+
* Validate a general e-CF against its bundled XML Schema before sending.
|
|
596
|
+
* Requires `xmllint` (or `DGII_XMLLINT_BIN`). Defaults to `false`.
|
|
597
|
+
*/
|
|
598
|
+
validateBeforeSend?: boolean;
|
|
599
|
+
/** `xmllint` binary used by `validateBeforeSend`. */
|
|
600
|
+
xmllintBin?: string;
|
|
455
601
|
}
|
|
456
602
|
/**
|
|
457
603
|
* DGII e-CF client. Every method returns a `Result` — no thrown domain errors.
|
|
@@ -464,6 +610,10 @@ declare class ECF {
|
|
|
464
610
|
private readonly inFlight;
|
|
465
611
|
private readonly tokenRefreshSkewMs;
|
|
466
612
|
private readonly now;
|
|
613
|
+
private readonly statusApiKey;
|
|
614
|
+
private readonly enforceB2BRules;
|
|
615
|
+
private readonly validateBeforeSend;
|
|
616
|
+
private readonly xmllintBin;
|
|
467
617
|
private tokenExpiresAt;
|
|
468
618
|
private refreshPromise;
|
|
469
619
|
constructor(credentials: P12ReaderData, environment?: Environment, options?: EcfOptions);
|
|
@@ -490,6 +640,28 @@ declare class ECF {
|
|
|
490
640
|
private reauthenticate;
|
|
491
641
|
/** Authenticate against DGII (or a buyer host) and store the bearer token. */
|
|
492
642
|
authenticate(buyerHost?: string): Promise<Result<AuthToken, DgiiError>>;
|
|
643
|
+
/**
|
|
644
|
+
* Query the operational status of every DGII service.
|
|
645
|
+
*
|
|
646
|
+
* The status host takes an API key instead of a bearer token, so this call
|
|
647
|
+
* neither needs `authenticate()` nor triggers a token refresh.
|
|
648
|
+
*/
|
|
649
|
+
getServiceStatus(): Promise<Result<ServiceStatusEntry[], DgiiError>>;
|
|
650
|
+
/** Scheduled maintenance windows, one entry per environment. */
|
|
651
|
+
getMaintenanceWindows(): Promise<Result<MaintenanceWindow[], DgiiError>>;
|
|
652
|
+
/** Whether an environment is currently inside a maintenance window. */
|
|
653
|
+
checkServiceAvailability(ambiente: StatusEnvironment): Promise<Result<ServiceAvailabilityResponse, DgiiError>>;
|
|
654
|
+
private statusRequest;
|
|
655
|
+
/**
|
|
656
|
+
* Resolve what happened to a submission whose idempotency marker is pending.
|
|
657
|
+
*
|
|
658
|
+
* Queries DGII by e-NCF. When DGII has no record of the document the marker
|
|
659
|
+
* is cleared, because re-submitting cannot double-issue. When DGII does have
|
|
660
|
+
* a record the marker stays in place — it is the lock that prevents a second
|
|
661
|
+
* submission of a document that already exists — and `delivered` tells the
|
|
662
|
+
* caller to stop retrying.
|
|
663
|
+
*/
|
|
664
|
+
reconcileSubmission(signedXml: string): Promise<Result<ReconciliationResult, DgiiError>>;
|
|
493
665
|
private getSeed;
|
|
494
666
|
private getAuthToken;
|
|
495
667
|
/**
|
|
@@ -513,6 +685,8 @@ declare class ECF {
|
|
|
513
685
|
trackStatuses(rncEmisor: string, encf: string): Promise<Result<SummaryTrackingStatusResponse[], DgiiError>>;
|
|
514
686
|
/** Normalizes DGII's inconsistent (array | single object) directory payload. */
|
|
515
687
|
getCustomerDirectory(rnc: string): Promise<Result<ServiceDirectoryResponse[] | undefined, DgiiError>>;
|
|
688
|
+
/** General directory listing — every receiver that publishes service URLs. */
|
|
689
|
+
getDirectoryListing(): Promise<Result<ServiceDirectoryResponse[], DgiiError>>;
|
|
516
690
|
/** RFCE inquiry — DGII production only. */
|
|
517
691
|
getSummaryInvoiceInquiry(rnc: string, encf: string, codSeguridad: string): Promise<Result<InquiryInvoiceSummary, DgiiError>>;
|
|
518
692
|
/**
|
|
@@ -520,6 +694,7 @@ declare class ECF {
|
|
|
520
694
|
* keyed on `RNC + eNCF + SHA-256(signed XML)`.
|
|
521
695
|
*/
|
|
522
696
|
sendCommercialApproval(signedXml: string, fileName: string): Promise<Result<CommercialApprovalResponse, DgiiError>>;
|
|
697
|
+
sendCommercialApproval(signedXml: string, fileName: string, buyerHost: string): Promise<Result<B2BCommercialApprovalResponse, DgiiError>>;
|
|
523
698
|
/**
|
|
524
699
|
* Submit a signed range-voiding request (ANECF). Idempotent like
|
|
525
700
|
* submissions, keyed on `RNC + RangoNCF + SHA-256(signed XML)`.
|
|
@@ -527,4 +702,4 @@ declare class ECF {
|
|
|
527
702
|
voidENCF(signedXml: string, fileName: string): Promise<Result<VoidNCFResponse, DgiiError>>;
|
|
528
703
|
}
|
|
529
704
|
|
|
530
|
-
export { type AuthToken, BaseUrl, type BaseUrlKey, CONSUMPTION_SUMMARY_THRESHOLD, type CertificateInfo, type CommercialApprovalResponse, type DgiiDocumentType, DgiiError, type DgiiErrorCode, type DgiiErrorContext, type DgiiErrorOptions, type DgiiResult, ECF, ECF_TYPE_CODES, type EcfOptions, type EcfTypeCode, Endpoint, Environment, type GeneralReceptionRoute, HttpClient, type HttpClientOptions, type IdempotencyStore, InMemoryIdempotencyStore, type InMemoryIdempotencyStoreOptions, type InquiryInvoiceSummary, type InquiryStatus, type InquiryStatusCode, type InquiryStatusResponse, type InvoiceResponse, type InvoiceSummaryResponse, type Mensaje, P12Reader, type P12ReaderData, type ReceptionRoute, type RequestOptions, type ResilienceOptions, type ResiliencePolicies, SenderReceiverEndpoint, type ServiceDirectoryResponse, Signature, type SummaryReceptionRoute, type SummaryTrackingStatusResponse, type TrackStatusCode, TrackStatusEnum, type TrackingStatusResponse, Transformer, type VoidNCFResponse, type XmlCertificateValidation, buildSenderReceiverUrl, buildUrl, compareDecimal, convertECF32ToRFCE, createResiliencePolicies, defaultResilienceOptions, extractDgiiErrorMessage, generateEcfQRCodeURL, generateFcQRCodeURL, getCodeSixDigitfromSignature, getCurrentFormattedDate, getCurrentFormattedDateTime, getXmlFromBodyResponse, isEcfTypeCode, isRetryableError, isRetryableStatus, resolveReceptionRoute, roundHalfUpToCents, toDgiiError, validateXMLCertificate };
|
|
705
|
+
export { type AuthToken, type B2BCommercialApprovalResponse, BaseUrl, type BaseUrlKey, CONSUMPTION_SUMMARY_THRESHOLD, type CertificateInfo, type CommercialApprovalResponse, type DgiiDocumentType, DgiiError, type DgiiErrorCode, type DgiiErrorContext, type DgiiErrorOptions, type DgiiResult, ECF, ECF_TYPE_CODES, type EcfOptions, type EcfTypeCode, Endpoint, Environment, type GeneralReceptionRoute, HttpClient, type HttpClientOptions, type IdempotencyStore, InMemoryIdempotencyStore, type InMemoryIdempotencyStoreOptions, type InquiryInvoiceSummary, type InquiryStatus, type InquiryStatusCode, type InquiryStatusResponse, type InvoiceResponse, type InvoiceSummaryResponse, type MaintenanceWindow, type Mensaje, P12Reader, type P12ReaderData, PENDING_SUBMISSION_MESSAGE, type ReceptionRoute, type ReconciliationResult, type RequestOptions, type ResilienceOptions, type ResiliencePolicies, SCHEMA_DIR, SUMMARY_ACCEPTED, SUMMARY_CONDITIONAL_ACCEPTED, SUMMARY_REJECTED, type SchemaViolation, SenderReceiverEndpoint, type ServiceAvailability, type ServiceAvailabilityResponse, type ServiceDirectoryResponse, type ServiceStatusEntry, Signature, StatusEndpoint, StatusEnvironment, type SummaryReceptionRoute, type SummaryTrackingStatusResponse, type TrackStatusCode, TrackStatusEnum, type TrackingStatusResponse, Transformer, UNAVAILABLE_SCHEMAS, type ValidationOptions, type VoidNCFResponse, type XmlCertificateValidation, buildSenderReceiverUrl, buildStatusUrl, buildUrl, canReuseSequence, checkB2BApplicability, compareDecimal, convertECF32ToRFCE, createResiliencePolicies, defaultResilienceOptions, extractDgiiErrorMessage, formatViolations, generateEcfQRCodeURL, generateFcQRCodeURL, getCodeSixDigitfromSignature, getCurrentFormattedDate, getCurrentFormattedDateTime, getXmlFromBodyResponse, isEcfTypeCode, isRetryableError, isRetryableStatus, pruneEmptyValues, resolveReceptionRoute, roundHalfUpToCents, toDgiiError, validateDocument, validateXMLCertificate };
|