@deuriib/dgii-ecf 0.5.1 → 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 +420 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +175 -4
- package/dist/index.d.ts +175 -4
- package/dist/index.js +405 -42
- 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. */
|
|
@@ -76,10 +91,17 @@ interface TrackingStatusResponse {
|
|
|
76
91
|
mensajes?: Mensaje[];
|
|
77
92
|
}
|
|
78
93
|
type InquiryStatusCode = 0 | 1 | 2;
|
|
79
|
-
|
|
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';
|
|
80
100
|
interface InquiryStatusResponse {
|
|
81
101
|
codigo: InquiryStatusCode;
|
|
82
102
|
estado: InquiryStatus;
|
|
103
|
+
/** `true` when the e-NCF sequence is already consumed. */
|
|
104
|
+
secuenciaUtilizada?: boolean;
|
|
83
105
|
rncEmisor?: string;
|
|
84
106
|
ncfElectronico?: string;
|
|
85
107
|
montoTotal?: number;
|
|
@@ -106,9 +128,18 @@ interface InvoiceResponse {
|
|
|
106
128
|
/** Tolerated array form used by the RFCE and status endpoints. */
|
|
107
129
|
mensajes?: Mensaje[];
|
|
108
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";
|
|
109
139
|
interface InvoiceSummaryResponse {
|
|
110
140
|
codigo: number;
|
|
111
|
-
|
|
141
|
+
/** One of the `SUMMARY_*` constants, compared case-insensitively. */
|
|
142
|
+
estado: string;
|
|
112
143
|
mensajes?: Mensaje[];
|
|
113
144
|
encf: string;
|
|
114
145
|
secuenciaUtilizada: boolean;
|
|
@@ -138,7 +169,34 @@ interface VoidNCFResponse {
|
|
|
138
169
|
rnc: string;
|
|
139
170
|
codigo: string;
|
|
140
171
|
nombre: string;
|
|
141
|
-
|
|
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;
|
|
142
200
|
}
|
|
143
201
|
|
|
144
202
|
type DgiiErrorCode = 'INVALID_XML' | 'CERTIFICATE' | 'SIGNING' | 'HTTP' | 'AUTH' | 'TIMEOUT' | 'CIRCUIT_OPEN' | 'IDEMPOTENCY' | 'VALIDATION' | 'UNKNOWN';
|
|
@@ -279,6 +337,8 @@ interface RequestOptions {
|
|
|
279
337
|
resource?: string;
|
|
280
338
|
/** Skip the auth hooks (used by the authentication round-trip itself). */
|
|
281
339
|
skipAuthHooks?: boolean;
|
|
340
|
+
/** Do not attach the bearer token (used by the status service). */
|
|
341
|
+
omitAuth?: boolean;
|
|
282
342
|
}
|
|
283
343
|
/** Thin HTTP client over the native `fetch`, wrapped in resilience policies. */
|
|
284
344
|
declare class HttpClient {
|
|
@@ -370,6 +430,14 @@ declare const validateXMLCertificate: (xml: string) => XmlCertificateValidation;
|
|
|
370
430
|
* Values that are not plain decimals (e.g. `1.0e3`) are returned unchanged.
|
|
371
431
|
*/
|
|
372
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;
|
|
373
441
|
/**
|
|
374
442
|
* Converts between the DGII XML documents and the "compact" JSON shape used by
|
|
375
443
|
* `xml-js` (a dict key is an element, an array is a repeated element, and
|
|
@@ -418,6 +486,66 @@ declare const compareDecimal: (a: string, b: string) => number;
|
|
|
418
486
|
* cannot drift from what is actually being transmitted.
|
|
419
487
|
*/
|
|
420
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;
|
|
421
549
|
|
|
422
550
|
/** First 6 chars of the `<SignatureValue>` (DGII security code). */
|
|
423
551
|
declare const getCodeSixDigitfromSignature: (signedXml: string) => Result<string, DgiiError>;
|
|
@@ -456,6 +584,20 @@ interface EcfOptions {
|
|
|
456
584
|
tokenRefreshSkewMs?: number;
|
|
457
585
|
/** Injectable clock (epoch milliseconds); useful for tests. */
|
|
458
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;
|
|
459
601
|
}
|
|
460
602
|
/**
|
|
461
603
|
* DGII e-CF client. Every method returns a `Result` — no thrown domain errors.
|
|
@@ -468,6 +610,10 @@ declare class ECF {
|
|
|
468
610
|
private readonly inFlight;
|
|
469
611
|
private readonly tokenRefreshSkewMs;
|
|
470
612
|
private readonly now;
|
|
613
|
+
private readonly statusApiKey;
|
|
614
|
+
private readonly enforceB2BRules;
|
|
615
|
+
private readonly validateBeforeSend;
|
|
616
|
+
private readonly xmllintBin;
|
|
471
617
|
private tokenExpiresAt;
|
|
472
618
|
private refreshPromise;
|
|
473
619
|
constructor(credentials: P12ReaderData, environment?: Environment, options?: EcfOptions);
|
|
@@ -494,6 +640,28 @@ declare class ECF {
|
|
|
494
640
|
private reauthenticate;
|
|
495
641
|
/** Authenticate against DGII (or a buyer host) and store the bearer token. */
|
|
496
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>>;
|
|
497
665
|
private getSeed;
|
|
498
666
|
private getAuthToken;
|
|
499
667
|
/**
|
|
@@ -517,6 +685,8 @@ declare class ECF {
|
|
|
517
685
|
trackStatuses(rncEmisor: string, encf: string): Promise<Result<SummaryTrackingStatusResponse[], DgiiError>>;
|
|
518
686
|
/** Normalizes DGII's inconsistent (array | single object) directory payload. */
|
|
519
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>>;
|
|
520
690
|
/** RFCE inquiry — DGII production only. */
|
|
521
691
|
getSummaryInvoiceInquiry(rnc: string, encf: string, codSeguridad: string): Promise<Result<InquiryInvoiceSummary, DgiiError>>;
|
|
522
692
|
/**
|
|
@@ -524,6 +694,7 @@ declare class ECF {
|
|
|
524
694
|
* keyed on `RNC + eNCF + SHA-256(signed XML)`.
|
|
525
695
|
*/
|
|
526
696
|
sendCommercialApproval(signedXml: string, fileName: string): Promise<Result<CommercialApprovalResponse, DgiiError>>;
|
|
697
|
+
sendCommercialApproval(signedXml: string, fileName: string, buyerHost: string): Promise<Result<B2BCommercialApprovalResponse, DgiiError>>;
|
|
527
698
|
/**
|
|
528
699
|
* Submit a signed range-voiding request (ANECF). Idempotent like
|
|
529
700
|
* submissions, keyed on `RNC + RangoNCF + SHA-256(signed XML)`.
|
|
@@ -531,4 +702,4 @@ declare class ECF {
|
|
|
531
702
|
voidENCF(signedXml: string, fileName: string): Promise<Result<VoidNCFResponse, DgiiError>>;
|
|
532
703
|
}
|
|
533
704
|
|
|
534
|
-
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. */
|
|
@@ -76,10 +91,17 @@ interface TrackingStatusResponse {
|
|
|
76
91
|
mensajes?: Mensaje[];
|
|
77
92
|
}
|
|
78
93
|
type InquiryStatusCode = 0 | 1 | 2;
|
|
79
|
-
|
|
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';
|
|
80
100
|
interface InquiryStatusResponse {
|
|
81
101
|
codigo: InquiryStatusCode;
|
|
82
102
|
estado: InquiryStatus;
|
|
103
|
+
/** `true` when the e-NCF sequence is already consumed. */
|
|
104
|
+
secuenciaUtilizada?: boolean;
|
|
83
105
|
rncEmisor?: string;
|
|
84
106
|
ncfElectronico?: string;
|
|
85
107
|
montoTotal?: number;
|
|
@@ -106,9 +128,18 @@ interface InvoiceResponse {
|
|
|
106
128
|
/** Tolerated array form used by the RFCE and status endpoints. */
|
|
107
129
|
mensajes?: Mensaje[];
|
|
108
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";
|
|
109
139
|
interface InvoiceSummaryResponse {
|
|
110
140
|
codigo: number;
|
|
111
|
-
|
|
141
|
+
/** One of the `SUMMARY_*` constants, compared case-insensitively. */
|
|
142
|
+
estado: string;
|
|
112
143
|
mensajes?: Mensaje[];
|
|
113
144
|
encf: string;
|
|
114
145
|
secuenciaUtilizada: boolean;
|
|
@@ -138,7 +169,34 @@ interface VoidNCFResponse {
|
|
|
138
169
|
rnc: string;
|
|
139
170
|
codigo: string;
|
|
140
171
|
nombre: string;
|
|
141
|
-
|
|
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;
|
|
142
200
|
}
|
|
143
201
|
|
|
144
202
|
type DgiiErrorCode = 'INVALID_XML' | 'CERTIFICATE' | 'SIGNING' | 'HTTP' | 'AUTH' | 'TIMEOUT' | 'CIRCUIT_OPEN' | 'IDEMPOTENCY' | 'VALIDATION' | 'UNKNOWN';
|
|
@@ -279,6 +337,8 @@ interface RequestOptions {
|
|
|
279
337
|
resource?: string;
|
|
280
338
|
/** Skip the auth hooks (used by the authentication round-trip itself). */
|
|
281
339
|
skipAuthHooks?: boolean;
|
|
340
|
+
/** Do not attach the bearer token (used by the status service). */
|
|
341
|
+
omitAuth?: boolean;
|
|
282
342
|
}
|
|
283
343
|
/** Thin HTTP client over the native `fetch`, wrapped in resilience policies. */
|
|
284
344
|
declare class HttpClient {
|
|
@@ -370,6 +430,14 @@ declare const validateXMLCertificate: (xml: string) => XmlCertificateValidation;
|
|
|
370
430
|
* Values that are not plain decimals (e.g. `1.0e3`) are returned unchanged.
|
|
371
431
|
*/
|
|
372
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;
|
|
373
441
|
/**
|
|
374
442
|
* Converts between the DGII XML documents and the "compact" JSON shape used by
|
|
375
443
|
* `xml-js` (a dict key is an element, an array is a repeated element, and
|
|
@@ -418,6 +486,66 @@ declare const compareDecimal: (a: string, b: string) => number;
|
|
|
418
486
|
* cannot drift from what is actually being transmitted.
|
|
419
487
|
*/
|
|
420
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;
|
|
421
549
|
|
|
422
550
|
/** First 6 chars of the `<SignatureValue>` (DGII security code). */
|
|
423
551
|
declare const getCodeSixDigitfromSignature: (signedXml: string) => Result<string, DgiiError>;
|
|
@@ -456,6 +584,20 @@ interface EcfOptions {
|
|
|
456
584
|
tokenRefreshSkewMs?: number;
|
|
457
585
|
/** Injectable clock (epoch milliseconds); useful for tests. */
|
|
458
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;
|
|
459
601
|
}
|
|
460
602
|
/**
|
|
461
603
|
* DGII e-CF client. Every method returns a `Result` — no thrown domain errors.
|
|
@@ -468,6 +610,10 @@ declare class ECF {
|
|
|
468
610
|
private readonly inFlight;
|
|
469
611
|
private readonly tokenRefreshSkewMs;
|
|
470
612
|
private readonly now;
|
|
613
|
+
private readonly statusApiKey;
|
|
614
|
+
private readonly enforceB2BRules;
|
|
615
|
+
private readonly validateBeforeSend;
|
|
616
|
+
private readonly xmllintBin;
|
|
471
617
|
private tokenExpiresAt;
|
|
472
618
|
private refreshPromise;
|
|
473
619
|
constructor(credentials: P12ReaderData, environment?: Environment, options?: EcfOptions);
|
|
@@ -494,6 +640,28 @@ declare class ECF {
|
|
|
494
640
|
private reauthenticate;
|
|
495
641
|
/** Authenticate against DGII (or a buyer host) and store the bearer token. */
|
|
496
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>>;
|
|
497
665
|
private getSeed;
|
|
498
666
|
private getAuthToken;
|
|
499
667
|
/**
|
|
@@ -517,6 +685,8 @@ declare class ECF {
|
|
|
517
685
|
trackStatuses(rncEmisor: string, encf: string): Promise<Result<SummaryTrackingStatusResponse[], DgiiError>>;
|
|
518
686
|
/** Normalizes DGII's inconsistent (array | single object) directory payload. */
|
|
519
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>>;
|
|
520
690
|
/** RFCE inquiry — DGII production only. */
|
|
521
691
|
getSummaryInvoiceInquiry(rnc: string, encf: string, codSeguridad: string): Promise<Result<InquiryInvoiceSummary, DgiiError>>;
|
|
522
692
|
/**
|
|
@@ -524,6 +694,7 @@ declare class ECF {
|
|
|
524
694
|
* keyed on `RNC + eNCF + SHA-256(signed XML)`.
|
|
525
695
|
*/
|
|
526
696
|
sendCommercialApproval(signedXml: string, fileName: string): Promise<Result<CommercialApprovalResponse, DgiiError>>;
|
|
697
|
+
sendCommercialApproval(signedXml: string, fileName: string, buyerHost: string): Promise<Result<B2BCommercialApprovalResponse, DgiiError>>;
|
|
527
698
|
/**
|
|
528
699
|
* Submit a signed range-voiding request (ANECF). Idempotent like
|
|
529
700
|
* submissions, keyed on `RNC + RangoNCF + SHA-256(signed XML)`.
|
|
@@ -531,4 +702,4 @@ declare class ECF {
|
|
|
531
702
|
voidENCF(signedXml: string, fileName: string): Promise<Result<VoidNCFResponse, DgiiError>>;
|
|
532
703
|
}
|
|
533
704
|
|
|
534
|
-
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 };
|