@deuriib/dgii-ecf 0.2.0 → 0.2.2
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/index.cjs +33 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +34 -18
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -634,25 +634,17 @@ var C14N_INCLUSIVE = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
|
|
|
634
634
|
var RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
|
635
635
|
var SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256";
|
|
636
636
|
var ENVELOPED = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
|
|
637
|
-
var CUSTOM_DIGEST_URI = "http://dgii.gov.do/digest/sha256-
|
|
638
|
-
var DgiiDigest = class
|
|
639
|
-
static sortAttributes(attributes) {
|
|
640
|
-
return Array.from(attributes).sort((a, b) => {
|
|
641
|
-
const left = `${a.name}="${a.value}"`;
|
|
642
|
-
const right = `${b.name}="${b.value}"`;
|
|
643
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
644
|
-
});
|
|
645
|
-
}
|
|
637
|
+
var CUSTOM_DIGEST_URI = "http://dgii.gov.do/digest/sha256-c14n";
|
|
638
|
+
var DgiiDigest = class {
|
|
646
639
|
getHash(xml) {
|
|
647
640
|
const doc = new import_xmldom.DOMParser().parseFromString(
|
|
648
641
|
xml
|
|
649
642
|
);
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
return import_node_crypto.default.createHash("sha256").update(doc.toString(), "utf8").digest("base64");
|
|
643
|
+
const canonical = new import_xml_crypto.C14nCanonicalization().process(
|
|
644
|
+
doc,
|
|
645
|
+
{}
|
|
646
|
+
);
|
|
647
|
+
return import_node_crypto.default.createHash("sha256").update(canonical, "utf8").digest("base64");
|
|
656
648
|
}
|
|
657
649
|
getAlgorithmName() {
|
|
658
650
|
return SHA256;
|
|
@@ -975,6 +967,8 @@ var convertECF32ToRFCE = (ecf32Xml) => {
|
|
|
975
967
|
|
|
976
968
|
// src/client.ts
|
|
977
969
|
var import_node_crypto2 = require("crypto");
|
|
970
|
+
var PENDING_SUBMISSION = { pending: true };
|
|
971
|
+
var isPendingSubmission = (value) => typeof value === "object" && value !== null && value.pending === true;
|
|
978
972
|
var sha256Hex = (value) => (0, import_node_crypto2.createHash)("sha256").update(value, "utf8").digest("hex");
|
|
979
973
|
var extractTag = (xml, tag) => {
|
|
980
974
|
const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));
|
|
@@ -1075,10 +1069,19 @@ var ECF = class {
|
|
|
1075
1069
|
async sendElectronicDocument(signedXml, fileName, buyerHost) {
|
|
1076
1070
|
const key = this.buildIdempotencyKey(signedXml);
|
|
1077
1071
|
const cached = await this.idempotency.get(key);
|
|
1078
|
-
if (cached) {
|
|
1072
|
+
if (cached !== void 0) {
|
|
1073
|
+
if (isPendingSubmission(cached)) {
|
|
1074
|
+
return (0, import_neverthrow.err)(
|
|
1075
|
+
new DgiiError(
|
|
1076
|
+
"A submission with this key is already pending; reconcile via a status lookup before retrying",
|
|
1077
|
+
{ code: "IDEMPOTENCY" }
|
|
1078
|
+
)
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1079
1081
|
return (0, import_neverthrow.ok)(cached);
|
|
1080
1082
|
}
|
|
1081
1083
|
return this.singleFlight(key, async () => {
|
|
1084
|
+
await this.idempotency.set(key, PENDING_SUBMISSION);
|
|
1082
1085
|
const url = buyerHost ? buildSenderReceiverUrl(buyerHost, "fe/recepcion/api/ecf" /* SendInvoice */) : buildUrl(this.environment, "recepcion/api/FacturasElectronicas" /* SendInvoice */);
|
|
1083
1086
|
const result = await this.http.postMultipart(
|
|
1084
1087
|
url,
|
|
@@ -1088,6 +1091,8 @@ var ECF = class {
|
|
|
1088
1091
|
);
|
|
1089
1092
|
if (result.isOk()) {
|
|
1090
1093
|
await this.idempotency.set(key, result.value);
|
|
1094
|
+
} else {
|
|
1095
|
+
await this.idempotency.delete(key);
|
|
1091
1096
|
}
|
|
1092
1097
|
return result;
|
|
1093
1098
|
});
|
|
@@ -1096,10 +1101,19 @@ var ECF = class {
|
|
|
1096
1101
|
async sendSummary(signedXml, fileName) {
|
|
1097
1102
|
const key = this.buildIdempotencyKey(signedXml);
|
|
1098
1103
|
const cached = await this.idempotency.get(key);
|
|
1099
|
-
if (cached) {
|
|
1104
|
+
if (cached !== void 0) {
|
|
1105
|
+
if (isPendingSubmission(cached)) {
|
|
1106
|
+
return (0, import_neverthrow.err)(
|
|
1107
|
+
new DgiiError(
|
|
1108
|
+
"A submission with this key is already pending; reconcile via a status lookup before retrying",
|
|
1109
|
+
{ code: "IDEMPOTENCY" }
|
|
1110
|
+
)
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1100
1113
|
return (0, import_neverthrow.ok)(cached);
|
|
1101
1114
|
}
|
|
1102
1115
|
return this.singleFlight(key, async () => {
|
|
1116
|
+
await this.idempotency.set(key, PENDING_SUBMISSION);
|
|
1103
1117
|
const url = buildUrl(this.environment, "recepcionfc/api/recepcion/ecf" /* SendSummary */, BaseUrl.CF);
|
|
1104
1118
|
const result = await this.http.postMultipart(
|
|
1105
1119
|
url,
|
|
@@ -1109,6 +1123,8 @@ var ECF = class {
|
|
|
1109
1123
|
);
|
|
1110
1124
|
if (result.isOk()) {
|
|
1111
1125
|
await this.idempotency.set(key, result.value);
|
|
1126
|
+
} else {
|
|
1127
|
+
await this.idempotency.delete(key);
|
|
1112
1128
|
}
|
|
1113
1129
|
return result;
|
|
1114
1130
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/types.ts","../src/errors.ts","../src/result.ts","../src/resilience.ts","../src/http.ts","../src/certificate.ts","../src/signing.ts","../src/transformer.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["export * from './environment.js';\nexport * from './types.js';\nexport * from './errors.js';\nexport * from './result.js';\nexport * from './resilience.js';\nexport * from './http.js';\nexport * from './certificate.js';\nexport * from './signing.js';\nexport * from './transformer.js';\nexport * from './utils.js';\nexport * from './client.js';\n","export enum Environment {\n /** DGII test environment */\n Dev = 'TesteCF',\n /** DGII certification environment */\n Cert = 'CerteCF',\n /** DGII production environment */\n Prod = 'eCF',\n}\n\nexport const BaseUrl = {\n /** Crédito fiscal / general e-CF services */\n ECF: 'https://ecf.dgii.gov.do',\n /** Factura de consumo (< DOP 250,000) */\n CF: 'https://fc.dgii.gov.do',\n /** DGII service status */\n STATUS: 'https://statusecf.dgii.gov.do',\n} as const;\n\nexport type BaseUrlKey = keyof typeof BaseUrl;\n\nexport enum Endpoint {\n Seed = 'Autenticacion/api/Autenticacion/Semilla',\n ValidateSeed = 'autenticacion/api/Autenticacion/ValidarSemilla',\n SendInvoice = 'recepcion/api/FacturasElectronicas',\n SendSummary = 'recepcionfc/api/recepcion/ecf',\n InquiryInvoiceSummary = 'consultarfce/api/Consultas/Consulta',\n CommercialApproval = 'aprobacionComercial/api/AprobacionComercial',\n TrackResultStatus = 'consultaresultado/api/Consultas/Estado',\n InquiryStatus = 'consultaestado/api/Consultas/Estado',\n AllTrackingEcf = 'ConsultaTrackIds/api/TrackIds/Consulta',\n Directory = 'consultadirectorio/api/consultas/obtenerdirectorioporrnc',\n Void = 'anulacionrangos/api/operaciones/anularrango',\n}\n\n/** Endpoints used when talking to a buyer's Sender↔Receiver host. */\nexport enum SenderReceiverEndpoint {\n Seed = 'fe/autenticacion/api/semilla',\n ValidateSeed = 'fe/autenticacion/api/validacioncertificado',\n SendInvoice = 'fe/recepcion/api/ecf',\n CommercialApproval = 'fe/aprobacioncomercial/api/ecf',\n}\n\n/** Build an absolute DGII URL: `${baseUrl}/${environment}/${endpoint}`. */\nexport const buildUrl = (\n environment: Environment,\n endpoint: Endpoint,\n baseUrl: string = BaseUrl.ECF,\n): string => `${baseUrl.replace(/\\/+$/, '')}/${environment}/${endpoint}`;\n\n/** Build an absolute Sender↔Receiver URL against a buyer host. */\nexport const buildSenderReceiverUrl = (\n host: string,\n endpoint: SenderReceiverEndpoint,\n): string => `${host.replace(/\\/+$/, '')}/${endpoint}`;\n","export interface Mensaje {\n valor: string;\n codigo: number;\n}\n\nexport interface AuthToken {\n token: string;\n expira: string;\n expedido: string;\n}\n\nexport enum TrackStatusEnum {\n NotFound = 'No encontrado',\n Accepted = 'Aceptado',\n Rejected = 'Rechazado',\n InProcess = 'En Proceso',\n ConditionalAccepted = 'Aceptado Condicional',\n}\n\nexport type TrackStatusCode = 0 | 1 | 2 | 3 | 4;\n\nexport interface TrackingStatusResponse {\n trackId: string;\n codigo: TrackStatusCode;\n estado: TrackStatusEnum;\n rnc: string;\n encf: string;\n secuenciaUtilizada: boolean;\n fechaRecepcion: string;\n mensajes?: Mensaje[];\n}\n\nexport type InquiryStatusCode = 0 | 1 | 2;\n\nexport type InquiryStatus = 'No encontrado' | 'Aceptado' | 'Rechazado';\n\nexport interface InquiryStatusResponse {\n codigo: InquiryStatusCode;\n estado: InquiryStatus;\n rncEmisor?: string;\n ncfElectronico?: string;\n montoTotal?: number;\n totalITBIS?: number;\n fechaEmision?: string;\n fechaFirma?: string;\n rncComprador?: string;\n codigoSeguridad?: string;\n idExtranjero?: string;\n}\n\nexport interface SummaryTrackingStatusResponse {\n trackId: string;\n estado: string;\n fechaRecepcion: string;\n}\n\nexport interface InvoiceResponse {\n trackId?: string;\n error?: string;\n mensajes?: Mensaje[];\n}\n\nexport interface InvoiceSummaryResponse {\n codigo: number;\n estado: 'Aceptado' | 'Rechazado' | 'Aceptado Condicional';\n mensajes?: Mensaje[];\n encf: string;\n secuenciaUtilizada: boolean;\n}\n\nexport interface ServiceDirectoryResponse {\n nombre: string;\n rnc: string;\n urlRecepcion: string;\n urlAceptacion: string;\n urlOpcional: string;\n}\n\nexport interface InquiryInvoiceSummary {\n rnc: string;\n encf: string;\n secuenciaUtilizada: boolean;\n codigo: InquiryStatusCode;\n estado: InquiryStatus;\n mensajes?: Mensaje[];\n}\n\nexport interface CommercialApprovalResponse {\n codigo: '01' | '02';\n estado: 'Aprobación Comercial Aprobada.' | 'Aprobacion Comercial Rechazada.';\n mensaje: string[];\n}\n\nexport interface VoidNCFResponse {\n rnc: string;\n codigo: string;\n nombre: string;\n mensajes: string[];\n}\n","import type { Mensaje } from './types.js';\n\nexport type DgiiErrorCode =\n | 'INVALID_XML'\n | 'CERTIFICATE'\n | 'SIGNING'\n | 'HTTP'\n | 'AUTH'\n | 'TIMEOUT'\n | 'CIRCUIT_OPEN'\n | 'IDEMPOTENCY'\n | 'VALIDATION'\n | 'UNKNOWN';\n\nconst RETRYABLE_STATUSES = new Set<number>([408, 429, 500, 502, 503, 504]);\n\nexport const isRetryableStatus = (status: number | undefined): boolean =>\n status !== undefined && RETRYABLE_STATUSES.has(status);\n\nexport interface DgiiErrorOptions {\n code?: DgiiErrorCode;\n status?: number;\n statusText?: string;\n resource?: string;\n method?: string;\n baseURL?: string;\n data?: unknown;\n mensajes?: Mensaje[];\n retryable?: boolean;\n cause?: unknown;\n}\n\nconst MAX_RAW = 1000;\n\nconst truncate = (value: string): string =>\n value.length > MAX_RAW ? `${value.slice(0, MAX_RAW)}…` : value;\n\nconst collapseWhitespace = (value: string): string =>\n value.replace(/\\s+/g, ' ').trim();\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst looksLikeHtml = (value: string): boolean =>\n /^\\s*<(?:!doctype|html|body|head)\\b/i.test(value);\n\nconst stripHtml = (value: string): string =>\n collapseWhitespace(\n value\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<[^>]+>/g, ' '),\n );\n\nconst readMensajes = (value: unknown): Mensaje[] | undefined => {\n if (!Array.isArray(value) || value.length === 0) {\n return undefined;\n }\n const out: Mensaje[] = [];\n for (const item of value) {\n if (typeof item === 'string' && item.trim()) {\n out.push({ valor: item.trim(), codigo: 0 });\n } else if (isObject(item) && typeof item.valor === 'string') {\n out.push({\n valor: item.valor,\n codigo: typeof item.codigo === 'number' ? item.codigo : 0,\n });\n }\n }\n return out.length ? out : undefined;\n};\n\nconst MESSAGE_KEYS = [\n 'mensaje',\n 'Mensaje',\n 'message',\n 'Message',\n 'error',\n 'Error',\n 'errorMessage',\n 'error_description',\n 'detail',\n 'Detail',\n 'title',\n 'Title',\n 'descripcion',\n 'Descripcion',\n];\n\n/**\n * Reduce DGII's inconsistent error payloads (bare string, `{ mensajes }`,\n * ASP.NET ProblemDetails/ModelState, or an HTML page) to a single message.\n */\nexport const extractDgiiErrorMessage = (\n data: unknown,\n seen: WeakSet<object> = new WeakSet<object>(),\n): string | undefined => {\n if (data === undefined || data === null) {\n return undefined;\n }\n\n if (typeof data === 'string') {\n const trimmed = data.trim();\n if (!trimmed) {\n return undefined;\n }\n if (/^[[{\"]/.test(trimmed)) {\n try {\n return extractDgiiErrorMessage(JSON.parse(trimmed), seen);\n } catch {\n // Not JSON after all — fall through to raw text.\n }\n }\n if (looksLikeHtml(trimmed)) {\n const text = stripHtml(trimmed);\n return text ? truncate(text) : undefined;\n }\n return truncate(collapseWhitespace(trimmed));\n }\n\n if (typeof data === 'number' || typeof data === 'boolean') {\n return String(data);\n }\n\n if (data instanceof Error) {\n return data.message || undefined;\n }\n\n if (Array.isArray(data)) {\n if (seen.has(data)) {\n return undefined;\n }\n seen.add(data);\n const parts = data\n .map((item) => extractDgiiErrorMessage(item, seen))\n .filter((item): item is string => Boolean(item));\n return parts.length ? truncate(parts.join(' | ')) : undefined;\n }\n\n if (isObject(data)) {\n if (seen.has(data)) {\n return undefined;\n }\n seen.add(data);\n\n const mensajes = readMensajes(data.mensajes ?? data.Mensajes);\n if (mensajes) {\n return truncate(mensajes.map((mensaje) => mensaje.valor).join(' | '));\n }\n\n for (const key of MESSAGE_KEYS) {\n const value = data[key];\n if (typeof value === 'string' && value.trim()) {\n return truncate(collapseWhitespace(value));\n }\n if (key === 'error' && (isObject(value) || Array.isArray(value))) {\n const nested = extractDgiiErrorMessage(value, seen);\n if (nested) {\n return nested;\n }\n }\n }\n\n const errors = data.errors ?? data.Errors;\n if (isObject(errors)) {\n const parts = Object.entries(errors)\n .map(([field, value]) => {\n const nested = extractDgiiErrorMessage(value, seen);\n return nested ? `${field}: ${nested}` : undefined;\n })\n .filter((item): item is string => Boolean(item));\n if (parts.length) {\n return truncate(parts.join(' | '));\n }\n } else if (errors) {\n const nested = extractDgiiErrorMessage(errors, seen);\n if (nested) {\n return nested;\n }\n }\n\n try {\n const serialized = JSON.stringify(data);\n if (serialized && serialized !== '{}') {\n return truncate(serialized);\n }\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n};\n\nexport class DgiiError extends Error {\n readonly code: DgiiErrorCode;\n readonly status?: number;\n readonly statusText?: string;\n readonly resource?: string;\n readonly method?: string;\n readonly baseURL?: string;\n readonly data?: unknown;\n readonly mensajes?: Mensaje[];\n readonly retryable: boolean;\n\n constructor(message: string, options: DgiiErrorOptions = {}) {\n super(message);\n this.name = 'DgiiError';\n Object.setPrototypeOf(this, DgiiError.prototype);\n\n this.code = options.code ?? 'UNKNOWN';\n this.status = options.status;\n this.statusText = options.statusText;\n this.resource = options.resource;\n this.method = options.method;\n this.baseURL = options.baseURL;\n this.data = options.data;\n this.mensajes = options.mensajes;\n this.retryable = options.retryable ?? isRetryableStatus(options.status);\n\n if (options.cause !== undefined) {\n Object.defineProperty(this, 'cause', {\n value: options.cause,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n }\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n status: this.status,\n statusText: this.statusText,\n resource: this.resource,\n method: this.method,\n mensajes: this.mensajes,\n data: this.data,\n };\n }\n}\n\nexport interface DgiiErrorContext {\n code?: DgiiErrorCode;\n status?: number;\n statusText?: string;\n resource?: string;\n method?: string;\n baseURL?: string;\n fallbackMessage?: string;\n}\n\n/** Normalize any thrown value into a {@link DgiiError}. */\nexport const toDgiiError = (\n err: unknown,\n context: DgiiErrorContext = {},\n): DgiiError => {\n if (err instanceof DgiiError) {\n return err;\n }\n\n if (err instanceof Error) {\n return new DgiiError(\n err.message || context.fallbackMessage || 'DGII request failed',\n {\n ...context,\n cause: err,\n },\n );\n }\n\n const message =\n extractDgiiErrorMessage(err) ||\n context.fallbackMessage ||\n 'DGII request failed';\n const status =\n isObject(err) && typeof err.status === 'number'\n ? err.status\n : context.status;\n\n return new DgiiError(message, {\n ...context,\n status,\n data: err,\n mensajes: isObject(err)\n ? readMensajes(err.mensajes ?? err.Mensajes)\n : undefined,\n cause: err,\n });\n};\n","import type { Result } from 'neverthrow';\nimport type { DgiiError } from './errors.js';\n\nexport type { Result } from 'neverthrow';\n\nexport {\n Ok,\n Err,\n ok,\n err,\n okAsync,\n errAsync,\n fromThrowable,\n fromPromise,\n fromSafePromise,\n ResultAsync,\n} from 'neverthrow';\n\n/** A {@link Result} whose failure channel is always {@link DgiiError}. */\nexport type DgiiResult<T> = Result<T, DgiiError>;\n","import {\n ConsecutiveBreaker,\n ExponentialBackoff,\n TimeoutStrategy,\n bulkhead,\n circuitBreaker,\n handleAll,\n handleWhen,\n retry,\n timeout,\n wrap,\n type IPolicy,\n} from 'cockatiel';\nimport { DgiiError } from './errors.js';\n\nexport interface ResilienceOptions {\n /** Maximum number of attempts (including the first). Default 3. */\n maxRetries?: number;\n /** Consecutive failures before the circuit opens. Default 5. */\n breakerThreshold?: number;\n /** Milliseconds the circuit stays open before half-opening. Default 30s. */\n halfOpenAfterMs?: number;\n /** Per-attempt timeout in milliseconds. Default 15s. */\n timeoutMs?: number;\n /** Initial retry backoff delay in milliseconds. Default 100. */\n retryInitialDelayMs?: number;\n /** Maximum concurrent in-flight requests. Default 20. */\n bulkheadLimit?: number;\n /** Maximum queued requests while the bulkhead is saturated. Default 40. */\n bulkheadQueue?: number;\n}\n\nexport const defaultResilienceOptions: Required<ResilienceOptions> = {\n maxRetries: 3,\n breakerThreshold: 5,\n halfOpenAfterMs: 30_000,\n timeoutMs: 15_000,\n retryInitialDelayMs: 100,\n bulkheadLimit: 20,\n bulkheadQueue: 40,\n};\n\n/**\n * Only transient failures are retried: network errors, timeouts, 408, 429 and\n * 5xx. A rejected e-CF (4xx) must never be blindly re-sent.\n */\nexport const isRetryableError = (error: unknown): boolean => {\n if (error instanceof DgiiError) {\n return error.retryable;\n }\n if (error instanceof Error) {\n const name = error.name.toLowerCase();\n const message = error.message.toLowerCase();\n return (\n name === 'typeerror' ||\n name === 'aborterror' ||\n name === 'fetcherror' ||\n name === 'timeouterror' ||\n name.includes('cancel') ||\n message.includes('timeout') ||\n message.includes('aborted') ||\n message.includes('network')\n );\n }\n return false;\n};\n\nexport interface ResiliencePolicies {\n readonly retry: IPolicy;\n readonly circuitBreaker: IPolicy;\n readonly timeout: IPolicy;\n readonly bulkhead: IPolicy;\n /** Composed policy: `retry → circuitBreaker → timeout → bulkhead`. */\n readonly policy: IPolicy;\n}\n\n/** Build the composed resilience policy used by the HTTP client. */\nexport const createResiliencePolicies = (\n options: ResilienceOptions = {},\n): ResiliencePolicies => {\n const opts = { ...defaultResilienceOptions, ...options };\n\n const retryPolicy = retry(handleWhen(isRetryableError), {\n maxAttempts: opts.maxRetries,\n backoff: new ExponentialBackoff({ initialDelay: opts.retryInitialDelayMs }),\n });\n\n const breakerPolicy = circuitBreaker(handleAll, {\n halfOpenAfter: opts.halfOpenAfterMs,\n breaker: new ConsecutiveBreaker(opts.breakerThreshold),\n });\n\n const timeoutPolicy = timeout(opts.timeoutMs, TimeoutStrategy.Aggressive);\n const bulkheadPolicy = bulkhead(opts.bulkheadLimit, opts.bulkheadQueue);\n\n const policy = wrap(\n retryPolicy,\n breakerPolicy,\n timeoutPolicy,\n bulkheadPolicy,\n );\n\n return {\n retry: retryPolicy,\n circuitBreaker: breakerPolicy,\n timeout: timeoutPolicy,\n bulkhead: bulkheadPolicy,\n policy,\n };\n};\n","import { err, ok, type Result } from './result.js';\nimport { DgiiError, extractDgiiErrorMessage, toDgiiError } from './errors.js';\nimport {\n createResiliencePolicies,\n type ResilienceOptions,\n type ResiliencePolicies,\n} from './resilience.js';\n\n/**\n * Pluggable idempotency store. Provide a Redis/Postgres-backed implementation\n * in production so a retried or duplicated submission never double-issues.\n */\nexport interface IdempotencyStore {\n get<T>(key: string): Promise<T | undefined>;\n set<T>(key: string, value: T): Promise<void>;\n delete(key: string): Promise<void>;\n}\n\n/** Process-local default. Fine for single-instance usage and tests. */\nexport class InMemoryIdempotencyStore implements IdempotencyStore {\n private readonly store = new Map<string, unknown>();\n\n async get<T>(key: string): Promise<T | undefined> {\n return this.store.get(key) as T | undefined;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.store.set(key, value);\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n}\n\nexport interface HttpClientOptions {\n baseUrl: string;\n token?: string;\n resilience?: ResilienceOptions;\n policies?: ResiliencePolicies;\n timeoutMs?: number;\n fetchImpl?: typeof fetch;\n}\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST';\n /** Absolute URL when `absoluteUrl` is true, otherwise a path appended to baseUrl. */\n path: string;\n absoluteUrl?: boolean;\n headers?: Record<string, string>;\n body?: BodyInit;\n query?: Record<string, string | number | undefined>;\n resource?: string;\n}\n\ninterface RequestContext {\n method: string;\n resource: string;\n baseURL: string;\n}\n\n/** Thin HTTP client over the native `fetch`, wrapped in resilience policies. */\nexport class HttpClient {\n private token?: string;\n private readonly policies: ResiliencePolicies;\n private readonly fetchImpl: typeof fetch;\n private readonly baseUrl: string;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '');\n this.token = options.token;\n this.policies =\n options.policies ??\n createResiliencePolicies({\n ...options.resilience,\n ...(options.timeoutMs !== undefined\n ? { timeoutMs: options.timeoutMs }\n : {}),\n });\n this.fetchImpl = options.fetchImpl ?? fetch;\n }\n\n setToken(token: string): void {\n this.token = token;\n }\n\n clearToken(): void {\n this.token = undefined;\n }\n\n private buildUrl(\n path: string,\n absoluteUrl: boolean | undefined,\n query: RequestOptions['query'],\n ): string {\n let url = absoluteUrl\n ? path\n : `${this.baseUrl}${path.startsWith('/') ? '' : '/'}${path}`;\n\n if (query) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== '') {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) {\n url += (url.includes('?') ? '&' : '?') + qs;\n }\n }\n return url;\n }\n\n private authHeaders(extra?: Record<string, string>): Record<string, string> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (this.token) {\n headers.Authorization = `Bearer ${this.token}`;\n }\n return { ...headers, ...extra };\n }\n\n private async readBody(response: Response): Promise<unknown> {\n const contentType = response.headers.get('content-type') ?? '';\n try {\n if (contentType.includes('json')) {\n return await response.json();\n }\n const text = await response.text();\n return text.length ? text : undefined;\n } catch {\n return undefined;\n }\n }\n\n private async parseResponse<T>(\n response: Response,\n ctx: RequestContext,\n ): Promise<Result<T, DgiiError>> {\n const data = await this.readBody(response);\n\n if (response.ok) {\n return ok(data as T);\n }\n\n const message =\n extractDgiiErrorMessage(data) ??\n `DGII request failed with status ${response.status}`;\n const error = new DgiiError(message, {\n code: response.status === 401 ? 'AUTH' : 'HTTP',\n status: response.status,\n statusText: response.statusText,\n resource: ctx.resource,\n method: ctx.method,\n baseURL: ctx.baseURL,\n data,\n });\n\n // Throw retryable failures so the retry/breaker policies can act on them;\n // non-retryable client errors are returned as a typed failure.\n if (error.retryable) {\n throw error;\n }\n return err(error);\n }\n\n async request<T>(options: RequestOptions): Promise<Result<T, DgiiError>> {\n const url = this.buildUrl(options.path, options.absoluteUrl, options.query);\n const method = options.method ?? 'GET';\n const headers = this.authHeaders(options.headers);\n const ctx: RequestContext = {\n method,\n resource: options.resource ?? options.path,\n baseURL: this.baseUrl,\n };\n\n try {\n return await this.policies.policy.execute(async ({ signal }) => {\n const response = await this.fetchImpl(url, {\n method,\n headers,\n body: options.body,\n signal,\n });\n return this.parseResponse<T>(response, ctx);\n });\n } catch (error) {\n return err(toDgiiError(error, ctx));\n }\n }\n\n get<T>(\n path: string,\n query?: RequestOptions['query'],\n opts?: { absoluteUrl?: boolean; resource?: string },\n ): Promise<Result<T, DgiiError>> {\n return this.request<T>({\n method: 'GET',\n path,\n query,\n absoluteUrl: opts?.absoluteUrl,\n resource: opts?.resource,\n });\n }\n\n /**\n * POST a signed XML as a multipart `xml` file part. The runtime computes\n * `Content-Length` from the Blob — never set it manually.\n */\n postMultipart<T>(\n path: string,\n fileName: string,\n xml: string,\n opts?: { absoluteUrl?: boolean; resource?: string },\n ): Promise<Result<T, DgiiError>> {\n const form = new FormData();\n form.append('xml', new Blob([xml], { type: 'application/xml' }), fileName);\n return this.request<T>({\n method: 'POST',\n path,\n body: form,\n headers: { Accept: 'application/json' },\n absoluteUrl: opts?.absoluteUrl,\n resource: opts?.resource,\n });\n }\n}\n","import { readFileSync } from 'node:fs';\nimport forge from 'node-forge';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\nexport interface P12ReaderData {\n key?: string;\n cert?: string;\n publicKey?: string;\n}\n\nexport interface CertificateInfo {\n subject: string;\n issuer: string;\n validFrom: Date;\n validTo: Date;\n serialNumber: string;\n}\n\nconst asErrorMessage = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/** Reads a PKCS#12 (.p12) bundle and extracts the private key + certificate. */\nexport class P12Reader {\n constructor(private readonly passphrase: string) {}\n\n private load(base64: string): forge.pkcs12.Pkcs12Pfx {\n const der = forge.util.decode64(base64);\n const asn1 = forge.asn1.fromDer(der);\n return forge.pkcs12.pkcs12FromAsn1(asn1, false, this.passphrase);\n }\n\n private extractKey(p12: forge.pkcs12.Pkcs12Pfx): string | undefined {\n const keyBags = p12.getBags({\n bagType: forge.pki.oids.pkcs8ShroudedKeyBag,\n });\n const pkcs8Key = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag]?.[0];\n if (pkcs8Key?.key) {\n return forge.pki.privateKeyToPem(pkcs8Key.key);\n }\n const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });\n const certBag = certBags[forge.pki.oids.certBag]?.[0];\n if (certBag?.key) {\n return forge.pki.privateKeyToPem(certBag.key);\n }\n return undefined;\n }\n\n private extractCertificate(p12: forge.pkcs12.Pkcs12Pfx): string | undefined {\n const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });\n const certBag = certBags[forge.pki.oids.certBag]?.[0];\n if (!certBag?.cert) {\n return undefined;\n }\n return forge.pki.certificateToPem(certBag.cert);\n }\n\n getKeyFromFile(fileName: string): Result<P12ReaderData, DgiiError> {\n try {\n const base64 = readFileSync(fileName, 'base64');\n return this.getKeyFromStringBase64(base64);\n } catch (error) {\n return err(\n new DgiiError(`Unable to read .p12 file: ${fileName}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n getKeyFromStringBase64(base64: string): Result<P12ReaderData, DgiiError> {\n try {\n const p12 = this.load(base64);\n const key = this.extractKey(p12);\n const cert = this.extractCertificate(p12);\n if (!key || !cert) {\n return err(\n new DgiiError('PKCS#12 must contain a private key and certificate', {\n code: 'CERTIFICATE',\n }),\n );\n }\n const publicKey = forge.pki.publicKeyToPem(\n forge.pki.certificateFromPem(cert).publicKey,\n );\n return ok({ key, cert, publicKey });\n } catch (error) {\n return err(\n new DgiiError(`Unable to parse .p12: ${asErrorMessage(error)}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n private toCertificateInfo(certPem: string): CertificateInfo {\n const certificate = forge.pki.certificateFromPem(certPem);\n return {\n subject: certificate.subject.attributes\n .map((attribute) => `${attribute.shortName}=${attribute.value}`)\n .join(', '),\n issuer: certificate.issuer.attributes\n .map((attribute) => `${attribute.shortName}=${attribute.value}`)\n .join(', '),\n validFrom: certificate.validity.notBefore,\n validTo: certificate.validity.notAfter,\n serialNumber: certificate.serialNumber,\n };\n }\n\n getCertificateInfo(fileName: string): Result<CertificateInfo, DgiiError> {\n try {\n const base64 = readFileSync(fileName, 'base64');\n return this.getCertificateInfoFromBase64(base64);\n } catch (error) {\n return err(\n new DgiiError(`Unable to read .p12 file: ${fileName}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n getCertificateInfoFromBase64(\n base64: string,\n ): Result<CertificateInfo, DgiiError> {\n try {\n const certPem = this.extractCertificate(this.load(base64));\n if (!certPem) {\n return err(\n new DgiiError('Certificate not found in PKCS#12', {\n code: 'CERTIFICATE',\n }),\n );\n }\n return ok(this.toCertificateInfo(certPem));\n } catch (error) {\n return err(\n new DgiiError(\n `Unable to extract certificate info: ${asErrorMessage(error)}`,\n { code: 'CERTIFICATE', cause: error },\n ),\n );\n }\n }\n}\n","import crypto from 'node:crypto';\nimport { DOMParser } from '@xmldom/xmldom';\nimport { SignedXml } from 'xml-crypto';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\nexport type DgiiDocumentType =\n 'SemillaModel' | 'ECF' | 'RFCE' | 'ARECF' | 'ACECF' | 'ANECF' | (string & {});\n\nconst C14N_INCLUSIVE = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';\nconst RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';\nconst SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256';\nconst ENVELOPED = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature';\n/**\n * DGII's .NET stack hashes the document with the root element's `xmlns`\n * attributes sorted. xml-crypto's built-in SHA-256 does not, so we register\n * a custom digest under this private URI.\n */\nconst CUSTOM_DIGEST_URI = 'http://dgii.gov.do/digest/sha256-sorted';\n\ninterface XmldomDocument extends Document {\n childNodes: NodeListOf<ChildNode>;\n}\n\n/**\n * DGII-compatible digest: sort the root element attributes (fixes\n * `xmlns:xsd`/`xmlns:xsi` ordering) before hashing with SHA-256.\n */\nclass DgiiDigest {\n private static sortAttributes(attributes: NamedNodeMap): Attr[] {\n return Array.from(attributes).sort((a, b) => {\n const left = `${a.name}=\"${a.value}\"`;\n const right = `${b.name}=\"${b.value}\"`;\n return left < right ? -1 : left > right ? 1 : 0;\n });\n }\n\n getHash(xml: string): string {\n const doc = new DOMParser().parseFromString(\n xml,\n ) as unknown as XmldomDocument;\n const root = doc.childNodes[0] as unknown as Element | undefined;\n if (root?.attributes) {\n const sorted = DgiiDigest.sortAttributes(root.attributes as NamedNodeMap);\n Object.assign(root.attributes, sorted);\n }\n return crypto\n .createHash('sha256')\n .update(doc.toString(), 'utf8')\n .digest('base64');\n }\n\n getAlgorithmName(): string {\n return SHA256;\n }\n}\n\ninterface StrictParseResult {\n doc: XmldomDocument;\n rootName: string;\n}\n\nconst parseStrict = (xml: string): StrictParseResult => {\n const errors: string[] = [];\n const doc = new DOMParser({\n errorHandler: {\n warning: () => undefined,\n error: (message: string) => errors.push(message),\n fatalError: (message: string) => errors.push(message),\n },\n }).parseFromString(xml, 'text/xml') as unknown as XmldomDocument;\n\n if (errors.length) {\n throw new Error(`Invalid XML: ${errors.join('; ')}`);\n }\n const root = doc.documentElement;\n if (!root) {\n throw new Error('Unable to parse XML or find root element');\n }\n if (root.nodeName === 'parsererror' || root.localName === 'parsererror') {\n throw new Error(`Invalid XML: ${root.textContent ?? 'parse error'}`);\n }\n return {\n doc,\n rootName: root.localName ?? root.nodeName,\n };\n};\n\n/** Remove whitespace-only text nodes and comments before canonicalization. */\nconst cleanNodes = (node: Node): void => {\n for (let index = 0; index < node.childNodes.length; index += 1) {\n const child = node.childNodes[index];\n if (!child) {\n continue;\n }\n const isComment = child.nodeType === 8;\n const isWhitespace =\n child.nodeType === 3 && !/\\S/.test(child.nodeValue ?? '');\n if (isComment || isWhitespace) {\n node.removeChild(child);\n index -= 1;\n } else if (child.nodeType === 1) {\n cleanNodes(child);\n }\n }\n};\n\n/** Signs DGII XML documents with XMLDSig (enveloped, inclusive C14N, RSA-SHA256). */\nexport class Signature {\n constructor(\n private readonly privateKey: string,\n private readonly certificatePem: string,\n ) {}\n\n signXml(\n xml: string,\n rootElName?: DgiiDocumentType,\n ): Result<string, DgiiError> {\n try {\n const { doc, rootName } = parseStrict(xml);\n const elementName = rootElName ?? rootName;\n\n const sig = new SignedXml({\n privateKey: this.privateKey,\n publicCert: this.certificatePem,\n signatureAlgorithm: RSA_SHA256,\n canonicalizationAlgorithm: C14N_INCLUSIVE,\n });\n\n const hashAlgorithms = (\n sig as unknown as {\n HashAlgorithms: Record<string, unknown>;\n }\n ).HashAlgorithms;\n hashAlgorithms[CUSTOM_DIGEST_URI] = DgiiDigest;\n\n sig.addReference({\n xpath: `//*[local-name(.)='${elementName}']`,\n transforms: [ENVELOPED],\n digestAlgorithm: CUSTOM_DIGEST_URI,\n isEmptyUri: true,\n } as unknown as Parameters<SignedXml['addReference']>[0]);\n\n cleanNodes(doc as unknown as Node);\n sig.computeSignature(doc.toString());\n return ok(sig.getSignedXml());\n } catch (error) {\n return err(\n new DgiiError(\n `Failed to sign XML: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'SIGNING', cause: error },\n ),\n );\n }\n }\n}\n\nexport interface XmlCertificateValidation {\n isValid: boolean;\n subject?: string;\n issuer?: string;\n validFrom?: string;\n validTo?: string;\n error?: string;\n}\n\n/** Validate the embedded X509 certificate of a signed XML document. */\nexport const validateXMLCertificate = (\n xml: string,\n): XmlCertificateValidation => {\n try {\n const match = xml.match(/<X509Certificate>([\\s\\S]*?)<\\/X509Certificate>/);\n if (!match?.[1]) {\n return { isValid: false, error: 'X509Certificate not found' };\n }\n const der = Buffer.from(match[1].replace(/\\s+/g, ''), 'base64');\n const certificate = new crypto.X509Certificate(der);\n const notBefore = new Date(certificate.validFrom).getTime();\n const notAfter = new Date(certificate.validTo).getTime();\n const now = Date.now();\n const isValid = now >= notBefore && now <= notAfter;\n return {\n isValid,\n subject: certificate.subject,\n issuer: certificate.issuer,\n validFrom: certificate.validFrom,\n validTo: certificate.validTo,\n error: isValid ? undefined : 'Certificate expired or not yet valid',\n };\n } catch (error) {\n return {\n isValid: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n};\n","import convert from 'xml-js';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\n/**\n * Converts between the DGII XML documents and the \"compact\" JSON shape used by\n * `xml-js` (a dict key is an element, an array is a repeated element, and\n * `_attributes` / `_text` carry attributes and text).\n */\nexport class Transformer {\n json2xml(dataObject: object, round = false): Result<string, DgiiError> {\n try {\n const data: Record<string, unknown> = {\n _declaration: { _attributes: { version: '1.0', encoding: 'utf-8' } },\n ...dataObject,\n };\n\n const xml = convert.js2xml(data as convert.ElementCompact, {\n compact: true,\n ignoreComment: true,\n spaces: 2,\n fullTagEmptyElement: true,\n textFn: (value: string, label: string) => {\n const omits = ['version'];\n if (\n /^\\d+\\.\\d+$/.test(value) &&\n round &&\n !omits.includes(label.toLowerCase())\n ) {\n return parseFloat(value).toFixed(2);\n }\n return value;\n },\n });\n\n return ok(xml);\n } catch (error) {\n return err(\n new DgiiError(\n `Error converting JSON to XML: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n }\n\n xml2json<T>(xml: string): Result<T, DgiiError> {\n try {\n const json = convert.xml2js(xml, {\n compact: true,\n ignoreComment: true,\n nativeType: false,\n });\n return ok(json as T);\n } catch (error) {\n return err(\n new DgiiError(\n `Error converting XML to JSON: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n }\n}\n","import { BaseUrl, Environment } from './environment.js';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\nimport { Transformer } from './transformer.js';\n\n/** First 6 chars of the `<SignatureValue>` (DGII security code). */\nexport const getCodeSixDigitfromSignature = (\n signedXml: string,\n): Result<string, DgiiError> => {\n const match = signedXml.match(/<SignatureValue>([\\s\\S]*?)<\\/SignatureValue>/);\n const value = match?.[1]?.trim();\n if (!value) {\n return err(new DgiiError('SignatureValue not found', { code: 'SIGNING' }));\n }\n if (value.length < 6) {\n return err(\n new DgiiError('SignatureValue is too short', { code: 'SIGNING' }),\n );\n }\n return ok(value.slice(0, 6));\n};\n\n/** QR URL for a factura de consumo (FC). */\nexport const generateFcQRCodeURL = (\n rncemisor: string,\n encf: string,\n montototal: number,\n codigoseguridad: string,\n env: Environment,\n): string =>\n `${BaseUrl.CF}/${env.toLowerCase()}/consultatimbrefc?rncemisor=${encodeURIComponent(\n rncemisor,\n )}&encf=${encodeURIComponent(encf)}&montototal=${encodeURIComponent(\n String(montototal),\n )}&codigoseguridad=${encodeURIComponent(codigoseguridad)}`;\n\n/** QR URL for a crédito fiscal (e-CF). */\nexport const generateEcfQRCodeURL = (\n rncemisor: string,\n rncComprador: string,\n encf: string,\n montototal: string,\n fechaEmision: string,\n fechaFirma: string,\n codigoseguridad: string,\n env: Environment,\n): string => {\n let rncCompradorParam = '';\n if (rncComprador && !/E43/i.test(encf) && !/E47/i.test(encf)) {\n rncCompradorParam = `RncComprador=${encodeURIComponent(rncComprador)}&`;\n }\n return `${BaseUrl.ECF}/${env.toLowerCase()}/consultatimbre?rncemisor=${encodeURIComponent(\n rncemisor,\n )}&${rncCompradorParam}encf=${encodeURIComponent(\n encf,\n )}&fechaemision=${encodeURIComponent(\n fechaEmision,\n )}&montototal=${encodeURIComponent(\n montototal,\n )}&fechafirma=${encodeURIComponent(\n fechaFirma,\n )}&codigoseguridad=${encodeURIComponent(codigoseguridad)}`;\n};\n\nconst formatInSantoDomingo = (date: Date, withTime: boolean): string => {\n const parts = new Intl.DateTimeFormat('es-DO', {\n timeZone: 'America/Santo_Domingo',\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n ...(withTime\n ? { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }\n : {}),\n })\n .formatToParts(date)\n .reduce<Record<string, string>>((acc, part) => {\n acc[part.type] = part.value;\n return acc;\n }, {});\n\n const datePart = `${parts.day}-${parts.month}-${parts.year}`;\n return withTime\n ? `${datePart} ${parts.hour}:${parts.minute}:${parts.second}`\n : datePart;\n};\n\n/** `DD-MM-YYYY HH:mm:ss` in America/Santo_Domingo. */\nexport const getCurrentFormattedDateTime = (date: Date = new Date()): string =>\n formatInSantoDomingo(date, true);\n\n/** `DD-MM-YYYY` in America/Santo_Domingo. */\nexport const getCurrentFormattedDate = (date: Date = new Date()): string =>\n formatInSantoDomingo(date, false);\n\n/** Extract the XML payload embedded in a DGII commercial-approval body. */\nexport const getXmlFromBodyResponse = (\n body: string,\n lastTagName = 'ACECF',\n): string | undefined =>\n body.match(new RegExp(`<\\\\?xml[\\\\s\\\\S]*?<\\\\/${lastTagName}>`))?.[0];\n\ninterface CompactElement {\n _text?: string;\n [key: string]: unknown;\n}\n\ninterface ImpuestoAdicional {\n TipoImpuesto?: CompactElement;\n MontoImpuestoSelectivoConsumoEspecifico?: CompactElement;\n MontoImpuestoSelectivoConsumoAdvalorem?: CompactElement;\n OtrosImpuestosAdicionales?: CompactElement;\n}\n\ninterface EcfTotales {\n MontoGravadoTotal?: CompactElement;\n MontoGravadoI1?: CompactElement;\n MontoGravadoI2?: CompactElement;\n MontoGravadoI3?: CompactElement;\n MontoExento?: CompactElement;\n TotalITBIS?: CompactElement;\n TotalITBIS1?: CompactElement;\n TotalITBIS2?: CompactElement;\n TotalITBIS3?: CompactElement;\n MontoImpuestoAdicional?: CompactElement;\n ImpuestosAdicionales?: {\n ImpuestoAdicional?: ImpuestoAdicional | ImpuestoAdicional[];\n };\n MontoTotal?: CompactElement;\n MontoNoFacturable?: CompactElement;\n MontoPeriodo?: CompactElement;\n}\n\ninterface EcfJson {\n ECF: {\n Encabezado?: {\n Version?: CompactElement;\n IdDoc?: {\n TipoeCF?: CompactElement;\n eNCF?: CompactElement;\n TipoIngresos?: CompactElement;\n TipoPago?: CompactElement;\n TablaFormasPago?: CompactElement;\n };\n Emisor?: {\n RNCEmisor?: CompactElement;\n RazonSocialEmisor?: CompactElement;\n FechaEmision?: CompactElement;\n };\n Comprador?: {\n RNCComprador?: CompactElement;\n IdentificadorExtranjero?: CompactElement;\n RazonSocialComprador?: CompactElement;\n };\n Totales?: EcfTotales;\n };\n };\n}\n\nconst toArray = <T>(value: T | T[] | undefined | null): T[] => {\n if (value === undefined || value === null) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n};\n\nconst isEmptyObject = (value: unknown): boolean =>\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n Object.keys(value as Record<string, unknown>).length === 0;\n\nconst removeEmptyValues = (input: unknown): unknown => {\n if (input === null || input === undefined || input === '') {\n return undefined;\n }\n if (Array.isArray(input)) {\n const filtered = input\n .map(removeEmptyValues)\n .filter(\n (item) =>\n item !== null &&\n item !== undefined &&\n item !== '' &&\n !isEmptyObject(item),\n );\n return filtered.length ? filtered : undefined;\n }\n if (typeof input === 'object') {\n const output: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(\n input as Record<string, unknown>,\n )) {\n const cleaned = removeEmptyValues(value);\n if (cleaned !== undefined && cleaned !== '' && !isEmptyObject(cleaned)) {\n output[key] = cleaned;\n }\n }\n return Object.keys(output).length ? output : undefined;\n }\n return input;\n};\n\n/**\n * Build the RFCE (summary invoice) document from a signed ECF-32 document.\n * Returns the unsigned RFCE XML plus the 6-digit security code.\n */\nexport const convertECF32ToRFCE = (\n ecf32Xml: string,\n): Result<{ xml: string; securityCode: string }, DgiiError> => {\n const securityCode = getCodeSixDigitfromSignature(ecf32Xml);\n if (securityCode.isErr()) {\n return err(securityCode.error);\n }\n\n const transformer = new Transformer();\n const parsed = transformer.xml2json<EcfJson>(ecf32Xml);\n if (parsed.isErr()) {\n return err(parsed.error);\n }\n\n const encabezado = parsed.value.ECF.Encabezado;\n const impuestos = toArray(\n encabezado?.Totales?.ImpuestosAdicionales?.ImpuestoAdicional,\n );\n\n const rfce = removeEmptyValues({\n RFCE: {\n Encabezado: {\n Version: encabezado?.Version,\n IdDoc: {\n TipoeCF: encabezado?.IdDoc?.TipoeCF,\n eNCF: encabezado?.IdDoc?.eNCF,\n TipoIngresos: encabezado?.IdDoc?.TipoIngresos,\n TipoPago: encabezado?.IdDoc?.TipoPago,\n TablaFormasPago: encabezado?.IdDoc?.TablaFormasPago,\n },\n Emisor: {\n RNCEmisor: encabezado?.Emisor?.RNCEmisor,\n RazonSocialEmisor: encabezado?.Emisor?.RazonSocialEmisor,\n FechaEmision: encabezado?.Emisor?.FechaEmision,\n },\n Comprador: {\n RNCComprador: encabezado?.Comprador?.RNCComprador,\n IdentificadorExtranjero:\n encabezado?.Comprador?.IdentificadorExtranjero,\n RazonSocialComprador: encabezado?.Comprador?.RazonSocialComprador,\n },\n Totales: {\n MontoGravadoTotal: encabezado?.Totales?.MontoGravadoTotal,\n MontoGravadoI1: encabezado?.Totales?.MontoGravadoI1,\n MontoGravadoI2: encabezado?.Totales?.MontoGravadoI2,\n MontoGravadoI3: encabezado?.Totales?.MontoGravadoI3,\n MontoExento: encabezado?.Totales?.MontoExento,\n TotalITBIS: encabezado?.Totales?.TotalITBIS,\n TotalITBIS1: encabezado?.Totales?.TotalITBIS1,\n TotalITBIS2: encabezado?.Totales?.TotalITBIS2,\n TotalITBIS3: encabezado?.Totales?.TotalITBIS3,\n MontoImpuestoAdicional: encabezado?.Totales?.MontoImpuestoAdicional,\n ImpuestosAdicionales: {\n ImpuestoAdicional: impuestos.map((impuesto) => ({\n TipoImpuesto: impuesto.TipoImpuesto,\n MontoImpuestoSelectivoConsumoEspecifico:\n impuesto.MontoImpuestoSelectivoConsumoEspecifico,\n MontoImpuestoSelectivoConsumoAdvalorem:\n impuesto.MontoImpuestoSelectivoConsumoAdvalorem,\n OtrosImpuestosAdicionales: impuesto.OtrosImpuestosAdicionales,\n })),\n },\n MontoTotal: encabezado?.Totales?.MontoTotal,\n MontoNoFacturable: encabezado?.Totales?.MontoNoFacturable,\n MontoPeriodo: encabezado?.Totales?.MontoPeriodo,\n },\n CodigoSeguridadeCF: securityCode.value,\n },\n },\n });\n\n if (typeof rfce !== 'object' || rfce === null) {\n return err(\n new DgiiError('Unable to build RFCE document', { code: 'VALIDATION' }),\n );\n }\n\n const xml = transformer.json2xml(rfce);\n if (xml.isErr()) {\n return err(xml.error);\n }\n\n return ok({ xml: xml.value, securityCode: securityCode.value });\n};\n","import { createHash } from 'node:crypto';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\nimport {\n BaseUrl,\n Endpoint,\n Environment,\n SenderReceiverEndpoint,\n buildSenderReceiverUrl,\n buildUrl,\n} from './environment.js';\nimport {\n HttpClient,\n InMemoryIdempotencyStore,\n type IdempotencyStore,\n} from './http.js';\nimport type { ResilienceOptions } from './resilience.js';\nimport { Signature } from './signing.js';\nimport type { P12ReaderData } from './certificate.js';\nimport type {\n AuthToken,\n CommercialApprovalResponse,\n InquiryInvoiceSummary,\n InquiryStatusResponse,\n InvoiceResponse,\n InvoiceSummaryResponse,\n ServiceDirectoryResponse,\n SummaryTrackingStatusResponse,\n TrackingStatusResponse,\n VoidNCFResponse,\n} from './types.js';\n\nexport interface EcfOptions {\n /** Pre-existing bearer token (skips the authentication round-trip). */\n token?: string;\n /** Pluggable idempotency store; defaults to an in-memory store. */\n idempotencyStore?: IdempotencyStore;\n resilience?: ResilienceOptions;\n timeoutMs?: number;\n /** Injectable fetch (useful for tests). */\n fetchImpl?: typeof fetch;\n}\n\nconst sha256Hex = (value: string): string =>\n createHash('sha256').update(value, 'utf8').digest('hex');\n\nconst extractTag = (xml: string, tag: string): string | undefined => {\n const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));\n return match?.[1]?.trim();\n};\n\n/**\n * DGII e-CF client. Every method returns a `Result` — no thrown domain errors.\n */\nexport class ECF {\n private readonly environment: Environment;\n private readonly http: HttpClient;\n private readonly idempotency: IdempotencyStore;\n private readonly credentials: P12ReaderData;\n private readonly inFlight = new Map<\n string,\n Promise<Result<unknown, DgiiError>>\n >();\n\n constructor(\n credentials: P12ReaderData,\n environment: Environment = Environment.Dev,\n options: EcfOptions = {},\n ) {\n this.credentials = credentials;\n this.environment = environment;\n this.idempotency =\n options.idempotencyStore ?? new InMemoryIdempotencyStore();\n this.http = new HttpClient({\n baseUrl: BaseUrl.ECF,\n ...(options.token !== undefined ? { token: options.token } : {}),\n ...(options.resilience !== undefined\n ? { resilience: options.resilience }\n : {}),\n ...(options.timeoutMs !== undefined\n ? { timeoutMs: options.timeoutMs }\n : {}),\n ...(options.fetchImpl !== undefined\n ? { fetchImpl: options.fetchImpl }\n : {}),\n });\n }\n\n private buildIdempotencyKey(signedXml: string): string {\n const rnc = extractTag(signedXml, 'RNCEmisor') ?? 'unknown-rnc';\n const encf = extractTag(signedXml, 'eNCF') ?? 'unknown-encf';\n return `${rnc}:${encf}:${sha256Hex(signedXml)}`;\n }\n\n private async singleFlight<T>(\n key: string,\n task: () => Promise<Result<T, DgiiError>>,\n ): Promise<Result<T, DgiiError>> {\n const existing = this.inFlight.get(key);\n if (existing) {\n return existing as Promise<Result<T, DgiiError>>;\n }\n const promise = task();\n this.inFlight.set(key, promise as Promise<Result<unknown, DgiiError>>);\n try {\n return await promise;\n } finally {\n this.inFlight.delete(key);\n }\n }\n\n /** Authenticate against DGII (or a buyer host) and store the bearer token. */\n async authenticate(\n buyerHost?: string,\n ): Promise<Result<AuthToken, DgiiError>> {\n const seed = await this.getSeed(buyerHost);\n if (seed.isErr()) {\n return err(seed.error);\n }\n if (\n typeof this.credentials.key !== 'string' ||\n typeof this.credentials.cert !== 'string'\n ) {\n return err(\n new DgiiError(\n 'A private key and certificate PEM are required to authenticate',\n { code: 'CERTIFICATE' },\n ),\n );\n }\n\n const signed = new Signature(\n this.credentials.key,\n this.credentials.cert,\n ).signXml(seed.value, 'SemillaModel');\n if (signed.isErr()) {\n return err(signed.error);\n }\n\n const token = await this.getAuthToken(signed.value, buyerHost);\n if (token.isErr()) {\n return err(token.error);\n }\n this.http.setToken(token.value.token);\n return ok(token.value);\n }\n\n private getSeed(buyerHost?: string): Promise<Result<string, DgiiError>> {\n if (buyerHost) {\n const url = buildSenderReceiverUrl(\n buyerHost,\n SenderReceiverEndpoint.Seed,\n );\n return this.http.get<string>(url, undefined, {\n absoluteUrl: true,\n resource: SenderReceiverEndpoint.Seed,\n });\n }\n const url = buildUrl(this.environment, Endpoint.Seed);\n return this.http.get<string>(url, undefined, {\n absoluteUrl: true,\n resource: Endpoint.Seed,\n });\n }\n\n private getAuthToken(\n signedSeed: string,\n buyerHost?: string,\n ): Promise<Result<AuthToken, DgiiError>> {\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.ValidateSeed)\n : buildUrl(this.environment, Endpoint.ValidateSeed);\n return this.http.postMultipart<AuthToken>(url, 'signed.xml', signedSeed, {\n absoluteUrl: true,\n resource: Endpoint.ValidateSeed,\n });\n }\n\n /**\n * Submit a signed e-CF. Idempotent on `RNC + eNCF + SHA-256(signed XML)`:\n * a repeated call returns the cached response instead of double-issuing.\n */\n async sendElectronicDocument(\n signedXml: string,\n fileName: string,\n buyerHost?: string,\n ): Promise<Result<InvoiceResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n const cached = await this.idempotency.get<InvoiceResponse>(key);\n if (cached) {\n return ok(cached);\n }\n return this.singleFlight(key, async () => {\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.SendInvoice)\n : buildUrl(this.environment, Endpoint.SendInvoice);\n const result = await this.http.postMultipart<InvoiceResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendInvoice },\n );\n if (result.isOk()) {\n await this.idempotency.set(key, result.value);\n }\n return result;\n });\n }\n\n /** Submit a signed summary invoice (RFCE). Idempotent like submissions. */\n async sendSummary(\n signedXml: string,\n fileName: string,\n ): Promise<Result<InvoiceSummaryResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n const cached = await this.idempotency.get<InvoiceSummaryResponse>(key);\n if (cached) {\n return ok(cached);\n }\n return this.singleFlight(key, async () => {\n const url = buildUrl(this.environment, Endpoint.SendSummary, BaseUrl.CF);\n const result = await this.http.postMultipart<InvoiceSummaryResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendSummary },\n );\n if (result.isOk()) {\n await this.idempotency.set(key, result.value);\n }\n return result;\n });\n }\n\n statusTrackId(\n trackId: string,\n ): Promise<Result<TrackingStatusResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.TrackResultStatus);\n return this.http.get<TrackingStatusResponse>(\n url,\n { trackId },\n { absoluteUrl: true, resource: Endpoint.TrackResultStatus },\n );\n }\n\n inquiryStatus(\n rncEmisor: string,\n ncfElectronico: string,\n rncComprador?: string,\n codigoSeguridad?: string,\n ): Promise<Result<InquiryStatusResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.InquiryStatus);\n return this.http.get<InquiryStatusResponse>(\n url,\n { rncEmisor, ncfElectronico, rncComprador, codigoSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryStatus },\n );\n }\n\n trackStatuses(\n rncEmisor: string,\n encf: string,\n ): Promise<Result<SummaryTrackingStatusResponse[], DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.AllTrackingEcf);\n return this.http.get<SummaryTrackingStatusResponse[]>(\n url,\n { rncEmisor, encf },\n { absoluteUrl: true, resource: Endpoint.AllTrackingEcf },\n );\n }\n\n /** Normalizes DGII's inconsistent (array | single object) directory payload. */\n async getCustomerDirectory(\n rnc: string,\n ): Promise<Result<ServiceDirectoryResponse[] | undefined, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Directory);\n const result = await this.http.get<\n ServiceDirectoryResponse[] | ServiceDirectoryResponse\n >(url, { rnc }, { absoluteUrl: true, resource: Endpoint.Directory });\n if (result.isErr()) {\n return err(result.error);\n }\n const data = result.value;\n if (data === undefined || data === null) {\n return ok(undefined);\n }\n return ok(Array.isArray(data) ? data : [data]);\n }\n\n /** RFCE inquiry — DGII production only. */\n getSummaryInvoiceInquiry(\n rnc: string,\n encf: string,\n codSeguridad: string,\n ): Promise<Result<InquiryInvoiceSummary, DgiiError>> {\n const url = buildUrl(\n this.environment,\n Endpoint.InquiryInvoiceSummary,\n BaseUrl.CF,\n );\n return this.http.get<InquiryInvoiceSummary>(\n url,\n { rnc_emisor: rnc, encf, cod_seguridad_eCF: codSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryInvoiceSummary },\n );\n }\n\n sendCommercialApproval(\n signedXml: string,\n fileName: string,\n ): Promise<Result<CommercialApprovalResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.CommercialApproval);\n return this.http.postMultipart<CommercialApprovalResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.CommercialApproval },\n );\n }\n\n voidENCF(\n signedXml: string,\n fileName: string,\n ): Promise<Result<VoidNCFResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Void);\n return this.http.postMultipart<VoidNCFResponse>(url, fileName, signedXml, {\n absoluteUrl: true,\n resource: Endpoint.Void,\n });\n }\n}\n"],"mappings":"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","names":["Environment","Endpoint","SenderReceiverEndpoint","TrackStatusEnum","err","forge","crypto","convert","import_node_crypto","url"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/types.ts","../src/errors.ts","../src/result.ts","../src/resilience.ts","../src/http.ts","../src/certificate.ts","../src/signing.ts","../src/transformer.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["export * from './environment.js';\nexport * from './types.js';\nexport * from './errors.js';\nexport * from './result.js';\nexport * from './resilience.js';\nexport * from './http.js';\nexport * from './certificate.js';\nexport * from './signing.js';\nexport * from './transformer.js';\nexport * from './utils.js';\nexport * from './client.js';\n","export enum Environment {\n /** DGII test environment */\n Dev = 'TesteCF',\n /** DGII certification environment */\n Cert = 'CerteCF',\n /** DGII production environment */\n Prod = 'eCF',\n}\n\nexport const BaseUrl = {\n /** Crédito fiscal / general e-CF services */\n ECF: 'https://ecf.dgii.gov.do',\n /** Factura de consumo (< DOP 250,000) */\n CF: 'https://fc.dgii.gov.do',\n /** DGII service status */\n STATUS: 'https://statusecf.dgii.gov.do',\n} as const;\n\nexport type BaseUrlKey = keyof typeof BaseUrl;\n\nexport enum Endpoint {\n Seed = 'Autenticacion/api/Autenticacion/Semilla',\n ValidateSeed = 'autenticacion/api/Autenticacion/ValidarSemilla',\n SendInvoice = 'recepcion/api/FacturasElectronicas',\n SendSummary = 'recepcionfc/api/recepcion/ecf',\n InquiryInvoiceSummary = 'consultarfce/api/Consultas/Consulta',\n CommercialApproval = 'aprobacionComercial/api/AprobacionComercial',\n TrackResultStatus = 'consultaresultado/api/Consultas/Estado',\n InquiryStatus = 'consultaestado/api/Consultas/Estado',\n AllTrackingEcf = 'ConsultaTrackIds/api/TrackIds/Consulta',\n Directory = 'consultadirectorio/api/consultas/obtenerdirectorioporrnc',\n Void = 'anulacionrangos/api/operaciones/anularrango',\n}\n\n/** Endpoints used when talking to a buyer's Sender↔Receiver host. */\nexport enum SenderReceiverEndpoint {\n Seed = 'fe/autenticacion/api/semilla',\n ValidateSeed = 'fe/autenticacion/api/validacioncertificado',\n SendInvoice = 'fe/recepcion/api/ecf',\n CommercialApproval = 'fe/aprobacioncomercial/api/ecf',\n}\n\n/** Build an absolute DGII URL: `${baseUrl}/${environment}/${endpoint}`. */\nexport const buildUrl = (\n environment: Environment,\n endpoint: Endpoint,\n baseUrl: string = BaseUrl.ECF,\n): string => `${baseUrl.replace(/\\/+$/, '')}/${environment}/${endpoint}`;\n\n/** Build an absolute Sender↔Receiver URL against a buyer host. */\nexport const buildSenderReceiverUrl = (\n host: string,\n endpoint: SenderReceiverEndpoint,\n): string => `${host.replace(/\\/+$/, '')}/${endpoint}`;\n","export interface Mensaje {\n valor: string;\n codigo: number;\n}\n\nexport interface AuthToken {\n token: string;\n expira: string;\n expedido: string;\n}\n\nexport enum TrackStatusEnum {\n NotFound = 'No encontrado',\n Accepted = 'Aceptado',\n Rejected = 'Rechazado',\n InProcess = 'En Proceso',\n ConditionalAccepted = 'Aceptado Condicional',\n}\n\nexport type TrackStatusCode = 0 | 1 | 2 | 3 | 4;\n\nexport interface TrackingStatusResponse {\n trackId: string;\n codigo: TrackStatusCode;\n estado: TrackStatusEnum;\n rnc: string;\n encf: string;\n secuenciaUtilizada: boolean;\n fechaRecepcion: string;\n mensajes?: Mensaje[];\n}\n\nexport type InquiryStatusCode = 0 | 1 | 2;\n\nexport type InquiryStatus = 'No encontrado' | 'Aceptado' | 'Rechazado';\n\nexport interface InquiryStatusResponse {\n codigo: InquiryStatusCode;\n estado: InquiryStatus;\n rncEmisor?: string;\n ncfElectronico?: string;\n montoTotal?: number;\n totalITBIS?: number;\n fechaEmision?: string;\n fechaFirma?: string;\n rncComprador?: string;\n codigoSeguridad?: string;\n idExtranjero?: string;\n}\n\nexport interface SummaryTrackingStatusResponse {\n trackId: string;\n estado: string;\n fechaRecepcion: string;\n}\n\nexport interface InvoiceResponse {\n trackId?: string;\n error?: string;\n mensajes?: Mensaje[];\n}\n\nexport interface InvoiceSummaryResponse {\n codigo: number;\n estado: 'Aceptado' | 'Rechazado' | 'Aceptado Condicional';\n mensajes?: Mensaje[];\n encf: string;\n secuenciaUtilizada: boolean;\n}\n\nexport interface ServiceDirectoryResponse {\n nombre: string;\n rnc: string;\n urlRecepcion: string;\n urlAceptacion: string;\n urlOpcional: string;\n}\n\nexport interface InquiryInvoiceSummary {\n rnc: string;\n encf: string;\n secuenciaUtilizada: boolean;\n codigo: InquiryStatusCode;\n estado: InquiryStatus;\n mensajes?: Mensaje[];\n}\n\nexport interface CommercialApprovalResponse {\n codigo: '01' | '02';\n estado: 'Aprobación Comercial Aprobada.' | 'Aprobacion Comercial Rechazada.';\n mensaje: string[];\n}\n\nexport interface VoidNCFResponse {\n rnc: string;\n codigo: string;\n nombre: string;\n mensajes: string[];\n}\n","import type { Mensaje } from './types.js';\n\nexport type DgiiErrorCode =\n | 'INVALID_XML'\n | 'CERTIFICATE'\n | 'SIGNING'\n | 'HTTP'\n | 'AUTH'\n | 'TIMEOUT'\n | 'CIRCUIT_OPEN'\n | 'IDEMPOTENCY'\n | 'VALIDATION'\n | 'UNKNOWN';\n\nconst RETRYABLE_STATUSES = new Set<number>([408, 429, 500, 502, 503, 504]);\n\nexport const isRetryableStatus = (status: number | undefined): boolean =>\n status !== undefined && RETRYABLE_STATUSES.has(status);\n\nexport interface DgiiErrorOptions {\n code?: DgiiErrorCode;\n status?: number;\n statusText?: string;\n resource?: string;\n method?: string;\n baseURL?: string;\n data?: unknown;\n mensajes?: Mensaje[];\n retryable?: boolean;\n cause?: unknown;\n}\n\nconst MAX_RAW = 1000;\n\nconst truncate = (value: string): string =>\n value.length > MAX_RAW ? `${value.slice(0, MAX_RAW)}…` : value;\n\nconst collapseWhitespace = (value: string): string =>\n value.replace(/\\s+/g, ' ').trim();\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst looksLikeHtml = (value: string): boolean =>\n /^\\s*<(?:!doctype|html|body|head)\\b/i.test(value);\n\nconst stripHtml = (value: string): string =>\n collapseWhitespace(\n value\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<[^>]+>/g, ' '),\n );\n\nconst readMensajes = (value: unknown): Mensaje[] | undefined => {\n if (!Array.isArray(value) || value.length === 0) {\n return undefined;\n }\n const out: Mensaje[] = [];\n for (const item of value) {\n if (typeof item === 'string' && item.trim()) {\n out.push({ valor: item.trim(), codigo: 0 });\n } else if (isObject(item) && typeof item.valor === 'string') {\n out.push({\n valor: item.valor,\n codigo: typeof item.codigo === 'number' ? item.codigo : 0,\n });\n }\n }\n return out.length ? out : undefined;\n};\n\nconst MESSAGE_KEYS = [\n 'mensaje',\n 'Mensaje',\n 'message',\n 'Message',\n 'error',\n 'Error',\n 'errorMessage',\n 'error_description',\n 'detail',\n 'Detail',\n 'title',\n 'Title',\n 'descripcion',\n 'Descripcion',\n];\n\n/**\n * Reduce DGII's inconsistent error payloads (bare string, `{ mensajes }`,\n * ASP.NET ProblemDetails/ModelState, or an HTML page) to a single message.\n */\nexport const extractDgiiErrorMessage = (\n data: unknown,\n seen: WeakSet<object> = new WeakSet<object>(),\n): string | undefined => {\n if (data === undefined || data === null) {\n return undefined;\n }\n\n if (typeof data === 'string') {\n const trimmed = data.trim();\n if (!trimmed) {\n return undefined;\n }\n if (/^[[{\"]/.test(trimmed)) {\n try {\n return extractDgiiErrorMessage(JSON.parse(trimmed), seen);\n } catch {\n // Not JSON after all — fall through to raw text.\n }\n }\n if (looksLikeHtml(trimmed)) {\n const text = stripHtml(trimmed);\n return text ? truncate(text) : undefined;\n }\n return truncate(collapseWhitespace(trimmed));\n }\n\n if (typeof data === 'number' || typeof data === 'boolean') {\n return String(data);\n }\n\n if (data instanceof Error) {\n return data.message || undefined;\n }\n\n if (Array.isArray(data)) {\n if (seen.has(data)) {\n return undefined;\n }\n seen.add(data);\n const parts = data\n .map((item) => extractDgiiErrorMessage(item, seen))\n .filter((item): item is string => Boolean(item));\n return parts.length ? truncate(parts.join(' | ')) : undefined;\n }\n\n if (isObject(data)) {\n if (seen.has(data)) {\n return undefined;\n }\n seen.add(data);\n\n const mensajes = readMensajes(data.mensajes ?? data.Mensajes);\n if (mensajes) {\n return truncate(mensajes.map((mensaje) => mensaje.valor).join(' | '));\n }\n\n for (const key of MESSAGE_KEYS) {\n const value = data[key];\n if (typeof value === 'string' && value.trim()) {\n return truncate(collapseWhitespace(value));\n }\n if (key === 'error' && (isObject(value) || Array.isArray(value))) {\n const nested = extractDgiiErrorMessage(value, seen);\n if (nested) {\n return nested;\n }\n }\n }\n\n const errors = data.errors ?? data.Errors;\n if (isObject(errors)) {\n const parts = Object.entries(errors)\n .map(([field, value]) => {\n const nested = extractDgiiErrorMessage(value, seen);\n return nested ? `${field}: ${nested}` : undefined;\n })\n .filter((item): item is string => Boolean(item));\n if (parts.length) {\n return truncate(parts.join(' | '));\n }\n } else if (errors) {\n const nested = extractDgiiErrorMessage(errors, seen);\n if (nested) {\n return nested;\n }\n }\n\n try {\n const serialized = JSON.stringify(data);\n if (serialized && serialized !== '{}') {\n return truncate(serialized);\n }\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n};\n\nexport class DgiiError extends Error {\n readonly code: DgiiErrorCode;\n readonly status?: number;\n readonly statusText?: string;\n readonly resource?: string;\n readonly method?: string;\n readonly baseURL?: string;\n readonly data?: unknown;\n readonly mensajes?: Mensaje[];\n readonly retryable: boolean;\n\n constructor(message: string, options: DgiiErrorOptions = {}) {\n super(message);\n this.name = 'DgiiError';\n Object.setPrototypeOf(this, DgiiError.prototype);\n\n this.code = options.code ?? 'UNKNOWN';\n this.status = options.status;\n this.statusText = options.statusText;\n this.resource = options.resource;\n this.method = options.method;\n this.baseURL = options.baseURL;\n this.data = options.data;\n this.mensajes = options.mensajes;\n this.retryable = options.retryable ?? isRetryableStatus(options.status);\n\n if (options.cause !== undefined) {\n Object.defineProperty(this, 'cause', {\n value: options.cause,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n }\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n status: this.status,\n statusText: this.statusText,\n resource: this.resource,\n method: this.method,\n mensajes: this.mensajes,\n data: this.data,\n };\n }\n}\n\nexport interface DgiiErrorContext {\n code?: DgiiErrorCode;\n status?: number;\n statusText?: string;\n resource?: string;\n method?: string;\n baseURL?: string;\n fallbackMessage?: string;\n}\n\n/** Normalize any thrown value into a {@link DgiiError}. */\nexport const toDgiiError = (\n err: unknown,\n context: DgiiErrorContext = {},\n): DgiiError => {\n if (err instanceof DgiiError) {\n return err;\n }\n\n if (err instanceof Error) {\n return new DgiiError(\n err.message || context.fallbackMessage || 'DGII request failed',\n {\n ...context,\n cause: err,\n },\n );\n }\n\n const message =\n extractDgiiErrorMessage(err) ||\n context.fallbackMessage ||\n 'DGII request failed';\n const status =\n isObject(err) && typeof err.status === 'number'\n ? err.status\n : context.status;\n\n return new DgiiError(message, {\n ...context,\n status,\n data: err,\n mensajes: isObject(err)\n ? readMensajes(err.mensajes ?? err.Mensajes)\n : undefined,\n cause: err,\n });\n};\n","import type { Result } from 'neverthrow';\nimport type { DgiiError } from './errors.js';\n\nexport type { Result } from 'neverthrow';\n\nexport {\n Ok,\n Err,\n ok,\n err,\n okAsync,\n errAsync,\n fromThrowable,\n fromPromise,\n fromSafePromise,\n ResultAsync,\n} from 'neverthrow';\n\n/** A {@link Result} whose failure channel is always {@link DgiiError}. */\nexport type DgiiResult<T> = Result<T, DgiiError>;\n","import {\n ConsecutiveBreaker,\n ExponentialBackoff,\n TimeoutStrategy,\n bulkhead,\n circuitBreaker,\n handleAll,\n handleWhen,\n retry,\n timeout,\n wrap,\n type IPolicy,\n} from 'cockatiel';\nimport { DgiiError } from './errors.js';\n\nexport interface ResilienceOptions {\n /** Maximum number of attempts (including the first). Default 3. */\n maxRetries?: number;\n /** Consecutive failures before the circuit opens. Default 5. */\n breakerThreshold?: number;\n /** Milliseconds the circuit stays open before half-opening. Default 30s. */\n halfOpenAfterMs?: number;\n /** Per-attempt timeout in milliseconds. Default 15s. */\n timeoutMs?: number;\n /** Initial retry backoff delay in milliseconds. Default 100. */\n retryInitialDelayMs?: number;\n /** Maximum concurrent in-flight requests. Default 20. */\n bulkheadLimit?: number;\n /** Maximum queued requests while the bulkhead is saturated. Default 40. */\n bulkheadQueue?: number;\n}\n\nexport const defaultResilienceOptions: Required<ResilienceOptions> = {\n maxRetries: 3,\n breakerThreshold: 5,\n halfOpenAfterMs: 30_000,\n timeoutMs: 15_000,\n retryInitialDelayMs: 100,\n bulkheadLimit: 20,\n bulkheadQueue: 40,\n};\n\n/**\n * Only transient failures are retried: network errors, timeouts, 408, 429 and\n * 5xx. A rejected e-CF (4xx) must never be blindly re-sent.\n */\nexport const isRetryableError = (error: unknown): boolean => {\n if (error instanceof DgiiError) {\n return error.retryable;\n }\n if (error instanceof Error) {\n const name = error.name.toLowerCase();\n const message = error.message.toLowerCase();\n return (\n name === 'typeerror' ||\n name === 'aborterror' ||\n name === 'fetcherror' ||\n name === 'timeouterror' ||\n name.includes('cancel') ||\n message.includes('timeout') ||\n message.includes('aborted') ||\n message.includes('network')\n );\n }\n return false;\n};\n\nexport interface ResiliencePolicies {\n readonly retry: IPolicy;\n readonly circuitBreaker: IPolicy;\n readonly timeout: IPolicy;\n readonly bulkhead: IPolicy;\n /** Composed policy: `retry → circuitBreaker → timeout → bulkhead`. */\n readonly policy: IPolicy;\n}\n\n/** Build the composed resilience policy used by the HTTP client. */\nexport const createResiliencePolicies = (\n options: ResilienceOptions = {},\n): ResiliencePolicies => {\n const opts = { ...defaultResilienceOptions, ...options };\n\n const retryPolicy = retry(handleWhen(isRetryableError), {\n maxAttempts: opts.maxRetries,\n backoff: new ExponentialBackoff({ initialDelay: opts.retryInitialDelayMs }),\n });\n\n const breakerPolicy = circuitBreaker(handleAll, {\n halfOpenAfter: opts.halfOpenAfterMs,\n breaker: new ConsecutiveBreaker(opts.breakerThreshold),\n });\n\n const timeoutPolicy = timeout(opts.timeoutMs, TimeoutStrategy.Aggressive);\n const bulkheadPolicy = bulkhead(opts.bulkheadLimit, opts.bulkheadQueue);\n\n const policy = wrap(\n retryPolicy,\n breakerPolicy,\n timeoutPolicy,\n bulkheadPolicy,\n );\n\n return {\n retry: retryPolicy,\n circuitBreaker: breakerPolicy,\n timeout: timeoutPolicy,\n bulkhead: bulkheadPolicy,\n policy,\n };\n};\n","import { err, ok, type Result } from './result.js';\nimport { DgiiError, extractDgiiErrorMessage, toDgiiError } from './errors.js';\nimport {\n createResiliencePolicies,\n type ResilienceOptions,\n type ResiliencePolicies,\n} from './resilience.js';\n\n/**\n * Pluggable idempotency store. Provide a Redis/Postgres-backed implementation\n * in production so a retried or duplicated submission never double-issues.\n */\nexport interface IdempotencyStore {\n get<T>(key: string): Promise<T | undefined>;\n set<T>(key: string, value: T): Promise<void>;\n delete(key: string): Promise<void>;\n}\n\n/** Process-local default. Fine for single-instance usage and tests. */\nexport class InMemoryIdempotencyStore implements IdempotencyStore {\n private readonly store = new Map<string, unknown>();\n\n async get<T>(key: string): Promise<T | undefined> {\n return this.store.get(key) as T | undefined;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.store.set(key, value);\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n}\n\nexport interface HttpClientOptions {\n baseUrl: string;\n token?: string;\n resilience?: ResilienceOptions;\n policies?: ResiliencePolicies;\n timeoutMs?: number;\n fetchImpl?: typeof fetch;\n}\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST';\n /** Absolute URL when `absoluteUrl` is true, otherwise a path appended to baseUrl. */\n path: string;\n absoluteUrl?: boolean;\n headers?: Record<string, string>;\n body?: BodyInit;\n query?: Record<string, string | number | undefined>;\n resource?: string;\n}\n\ninterface RequestContext {\n method: string;\n resource: string;\n baseURL: string;\n}\n\n/** Thin HTTP client over the native `fetch`, wrapped in resilience policies. */\nexport class HttpClient {\n private token?: string;\n private readonly policies: ResiliencePolicies;\n private readonly fetchImpl: typeof fetch;\n private readonly baseUrl: string;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '');\n this.token = options.token;\n this.policies =\n options.policies ??\n createResiliencePolicies({\n ...options.resilience,\n ...(options.timeoutMs !== undefined\n ? { timeoutMs: options.timeoutMs }\n : {}),\n });\n this.fetchImpl = options.fetchImpl ?? fetch;\n }\n\n setToken(token: string): void {\n this.token = token;\n }\n\n clearToken(): void {\n this.token = undefined;\n }\n\n private buildUrl(\n path: string,\n absoluteUrl: boolean | undefined,\n query: RequestOptions['query'],\n ): string {\n let url = absoluteUrl\n ? path\n : `${this.baseUrl}${path.startsWith('/') ? '' : '/'}${path}`;\n\n if (query) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== '') {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) {\n url += (url.includes('?') ? '&' : '?') + qs;\n }\n }\n return url;\n }\n\n private authHeaders(extra?: Record<string, string>): Record<string, string> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (this.token) {\n headers.Authorization = `Bearer ${this.token}`;\n }\n return { ...headers, ...extra };\n }\n\n private async readBody(response: Response): Promise<unknown> {\n const contentType = response.headers.get('content-type') ?? '';\n try {\n if (contentType.includes('json')) {\n return await response.json();\n }\n const text = await response.text();\n return text.length ? text : undefined;\n } catch {\n return undefined;\n }\n }\n\n private async parseResponse<T>(\n response: Response,\n ctx: RequestContext,\n ): Promise<Result<T, DgiiError>> {\n const data = await this.readBody(response);\n\n if (response.ok) {\n return ok(data as T);\n }\n\n const message =\n extractDgiiErrorMessage(data) ??\n `DGII request failed with status ${response.status}`;\n const error = new DgiiError(message, {\n code: response.status === 401 ? 'AUTH' : 'HTTP',\n status: response.status,\n statusText: response.statusText,\n resource: ctx.resource,\n method: ctx.method,\n baseURL: ctx.baseURL,\n data,\n });\n\n // Throw retryable failures so the retry/breaker policies can act on them;\n // non-retryable client errors are returned as a typed failure.\n if (error.retryable) {\n throw error;\n }\n return err(error);\n }\n\n async request<T>(options: RequestOptions): Promise<Result<T, DgiiError>> {\n const url = this.buildUrl(options.path, options.absoluteUrl, options.query);\n const method = options.method ?? 'GET';\n const headers = this.authHeaders(options.headers);\n const ctx: RequestContext = {\n method,\n resource: options.resource ?? options.path,\n baseURL: this.baseUrl,\n };\n\n try {\n return await this.policies.policy.execute(async ({ signal }) => {\n const response = await this.fetchImpl(url, {\n method,\n headers,\n body: options.body,\n signal,\n });\n return this.parseResponse<T>(response, ctx);\n });\n } catch (error) {\n return err(toDgiiError(error, ctx));\n }\n }\n\n get<T>(\n path: string,\n query?: RequestOptions['query'],\n opts?: { absoluteUrl?: boolean; resource?: string },\n ): Promise<Result<T, DgiiError>> {\n return this.request<T>({\n method: 'GET',\n path,\n query,\n absoluteUrl: opts?.absoluteUrl,\n resource: opts?.resource,\n });\n }\n\n /**\n * POST a signed XML as a multipart `xml` file part. The runtime computes\n * `Content-Length` from the Blob — never set it manually.\n */\n postMultipart<T>(\n path: string,\n fileName: string,\n xml: string,\n opts?: { absoluteUrl?: boolean; resource?: string },\n ): Promise<Result<T, DgiiError>> {\n const form = new FormData();\n form.append('xml', new Blob([xml], { type: 'application/xml' }), fileName);\n return this.request<T>({\n method: 'POST',\n path,\n body: form,\n headers: { Accept: 'application/json' },\n absoluteUrl: opts?.absoluteUrl,\n resource: opts?.resource,\n });\n }\n}\n","import { readFileSync } from 'node:fs';\nimport forge from 'node-forge';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\nexport interface P12ReaderData {\n key?: string;\n cert?: string;\n publicKey?: string;\n}\n\nexport interface CertificateInfo {\n subject: string;\n issuer: string;\n validFrom: Date;\n validTo: Date;\n serialNumber: string;\n}\n\nconst asErrorMessage = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/** Reads a PKCS#12 (.p12) bundle and extracts the private key + certificate. */\nexport class P12Reader {\n constructor(private readonly passphrase: string) {}\n\n private load(base64: string): forge.pkcs12.Pkcs12Pfx {\n const der = forge.util.decode64(base64);\n const asn1 = forge.asn1.fromDer(der);\n return forge.pkcs12.pkcs12FromAsn1(asn1, false, this.passphrase);\n }\n\n private extractKey(p12: forge.pkcs12.Pkcs12Pfx): string | undefined {\n const keyBags = p12.getBags({\n bagType: forge.pki.oids.pkcs8ShroudedKeyBag,\n });\n const pkcs8Key = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag]?.[0];\n if (pkcs8Key?.key) {\n return forge.pki.privateKeyToPem(pkcs8Key.key);\n }\n const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });\n const certBag = certBags[forge.pki.oids.certBag]?.[0];\n if (certBag?.key) {\n return forge.pki.privateKeyToPem(certBag.key);\n }\n return undefined;\n }\n\n private extractCertificate(p12: forge.pkcs12.Pkcs12Pfx): string | undefined {\n const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });\n const certBag = certBags[forge.pki.oids.certBag]?.[0];\n if (!certBag?.cert) {\n return undefined;\n }\n return forge.pki.certificateToPem(certBag.cert);\n }\n\n getKeyFromFile(fileName: string): Result<P12ReaderData, DgiiError> {\n try {\n const base64 = readFileSync(fileName, 'base64');\n return this.getKeyFromStringBase64(base64);\n } catch (error) {\n return err(\n new DgiiError(`Unable to read .p12 file: ${fileName}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n getKeyFromStringBase64(base64: string): Result<P12ReaderData, DgiiError> {\n try {\n const p12 = this.load(base64);\n const key = this.extractKey(p12);\n const cert = this.extractCertificate(p12);\n if (!key || !cert) {\n return err(\n new DgiiError('PKCS#12 must contain a private key and certificate', {\n code: 'CERTIFICATE',\n }),\n );\n }\n const publicKey = forge.pki.publicKeyToPem(\n forge.pki.certificateFromPem(cert).publicKey,\n );\n return ok({ key, cert, publicKey });\n } catch (error) {\n return err(\n new DgiiError(`Unable to parse .p12: ${asErrorMessage(error)}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n private toCertificateInfo(certPem: string): CertificateInfo {\n const certificate = forge.pki.certificateFromPem(certPem);\n return {\n subject: certificate.subject.attributes\n .map((attribute) => `${attribute.shortName}=${attribute.value}`)\n .join(', '),\n issuer: certificate.issuer.attributes\n .map((attribute) => `${attribute.shortName}=${attribute.value}`)\n .join(', '),\n validFrom: certificate.validity.notBefore,\n validTo: certificate.validity.notAfter,\n serialNumber: certificate.serialNumber,\n };\n }\n\n getCertificateInfo(fileName: string): Result<CertificateInfo, DgiiError> {\n try {\n const base64 = readFileSync(fileName, 'base64');\n return this.getCertificateInfoFromBase64(base64);\n } catch (error) {\n return err(\n new DgiiError(`Unable to read .p12 file: ${fileName}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n getCertificateInfoFromBase64(\n base64: string,\n ): Result<CertificateInfo, DgiiError> {\n try {\n const certPem = this.extractCertificate(this.load(base64));\n if (!certPem) {\n return err(\n new DgiiError('Certificate not found in PKCS#12', {\n code: 'CERTIFICATE',\n }),\n );\n }\n return ok(this.toCertificateInfo(certPem));\n } catch (error) {\n return err(\n new DgiiError(\n `Unable to extract certificate info: ${asErrorMessage(error)}`,\n { code: 'CERTIFICATE', cause: error },\n ),\n );\n }\n }\n}\n","import crypto from 'node:crypto';\nimport { DOMParser } from '@xmldom/xmldom';\nimport { C14nCanonicalization, SignedXml } from 'xml-crypto';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\nexport type DgiiDocumentType =\n 'SemillaModel' | 'ECF' | 'RFCE' | 'ARECF' | 'ACECF' | 'ANECF' | (string & {});\n\nconst C14N_INCLUSIVE = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';\nconst RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';\nconst SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256';\nconst ENVELOPED = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature';\n/**\n * Custom digest URI: DGII hashes the inclusive C14N 1.0 form of the referenced\n * document. xml-crypto's built-in SHA-256 hashes its raw serialization, so we\n * register a digest backed by xml-crypto's inclusive C14N implementation.\n */\nconst CUSTOM_DIGEST_URI = 'http://dgii.gov.do/digest/sha256-c14n';\n\ninterface XmldomDocument extends Document {\n childNodes: NodeListOf<ChildNode>;\n}\n\n/**\n * DGII-compatible digest: hash the inclusive C14N 1.0 form of the referenced\n * document — the exact bytes a .NET/DGII verifier computes.\n */\nclass DgiiDigest {\n getHash(xml: string): string {\n const doc = new DOMParser().parseFromString(\n xml,\n ) as unknown as XmldomDocument;\n const canonical = new C14nCanonicalization().process(\n doc as unknown as Node,\n {},\n );\n return crypto\n .createHash('sha256')\n .update(canonical, 'utf8')\n .digest('base64');\n }\n\n getAlgorithmName(): string {\n return SHA256;\n }\n}\n\ninterface StrictParseResult {\n doc: XmldomDocument;\n rootName: string;\n}\n\nconst parseStrict = (xml: string): StrictParseResult => {\n const errors: string[] = [];\n const doc = new DOMParser({\n errorHandler: {\n warning: () => undefined,\n error: (message: string) => errors.push(message),\n fatalError: (message: string) => errors.push(message),\n },\n }).parseFromString(xml, 'text/xml') as unknown as XmldomDocument;\n\n if (errors.length) {\n throw new Error(`Invalid XML: ${errors.join('; ')}`);\n }\n const root = doc.documentElement;\n if (!root) {\n throw new Error('Unable to parse XML or find root element');\n }\n if (root.nodeName === 'parsererror' || root.localName === 'parsererror') {\n throw new Error(`Invalid XML: ${root.textContent ?? 'parse error'}`);\n }\n return {\n doc,\n rootName: root.localName ?? root.nodeName,\n };\n};\n\n/** Remove whitespace-only text nodes and comments before canonicalization. */\nconst cleanNodes = (node: Node): void => {\n for (let index = 0; index < node.childNodes.length; index += 1) {\n const child = node.childNodes[index];\n if (!child) {\n continue;\n }\n const isComment = child.nodeType === 8;\n const isWhitespace =\n child.nodeType === 3 && !/\\S/.test(child.nodeValue ?? '');\n if (isComment || isWhitespace) {\n node.removeChild(child);\n index -= 1;\n } else if (child.nodeType === 1) {\n cleanNodes(child);\n }\n }\n};\n\n/** Signs DGII XML documents with XMLDSig (enveloped, inclusive C14N, RSA-SHA256). */\nexport class Signature {\n constructor(\n private readonly privateKey: string,\n private readonly certificatePem: string,\n ) {}\n\n signXml(\n xml: string,\n rootElName?: DgiiDocumentType,\n ): Result<string, DgiiError> {\n try {\n const { doc, rootName } = parseStrict(xml);\n const elementName = rootElName ?? rootName;\n\n const sig = new SignedXml({\n privateKey: this.privateKey,\n publicCert: this.certificatePem,\n signatureAlgorithm: RSA_SHA256,\n canonicalizationAlgorithm: C14N_INCLUSIVE,\n });\n\n const hashAlgorithms = (\n sig as unknown as {\n HashAlgorithms: Record<string, unknown>;\n }\n ).HashAlgorithms;\n hashAlgorithms[CUSTOM_DIGEST_URI] = DgiiDigest;\n\n sig.addReference({\n xpath: `//*[local-name(.)='${elementName}']`,\n transforms: [ENVELOPED],\n digestAlgorithm: CUSTOM_DIGEST_URI,\n isEmptyUri: true,\n } as unknown as Parameters<SignedXml['addReference']>[0]);\n\n cleanNodes(doc as unknown as Node);\n sig.computeSignature(doc.toString());\n return ok(sig.getSignedXml());\n } catch (error) {\n return err(\n new DgiiError(\n `Failed to sign XML: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'SIGNING', cause: error },\n ),\n );\n }\n }\n}\n\nexport interface XmlCertificateValidation {\n isValid: boolean;\n subject?: string;\n issuer?: string;\n validFrom?: string;\n validTo?: string;\n error?: string;\n}\n\n/** Validate the embedded X509 certificate of a signed XML document. */\nexport const validateXMLCertificate = (\n xml: string,\n): XmlCertificateValidation => {\n try {\n const match = xml.match(/<X509Certificate>([\\s\\S]*?)<\\/X509Certificate>/);\n if (!match?.[1]) {\n return { isValid: false, error: 'X509Certificate not found' };\n }\n const der = Buffer.from(match[1].replace(/\\s+/g, ''), 'base64');\n const certificate = new crypto.X509Certificate(der);\n const notBefore = new Date(certificate.validFrom).getTime();\n const notAfter = new Date(certificate.validTo).getTime();\n const now = Date.now();\n const isValid = now >= notBefore && now <= notAfter;\n return {\n isValid,\n subject: certificate.subject,\n issuer: certificate.issuer,\n validFrom: certificate.validFrom,\n validTo: certificate.validTo,\n error: isValid ? undefined : 'Certificate expired or not yet valid',\n };\n } catch (error) {\n return {\n isValid: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n};\n","import convert from 'xml-js';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\n/**\n * Converts between the DGII XML documents and the \"compact\" JSON shape used by\n * `xml-js` (a dict key is an element, an array is a repeated element, and\n * `_attributes` / `_text` carry attributes and text).\n */\nexport class Transformer {\n json2xml(dataObject: object, round = false): Result<string, DgiiError> {\n try {\n const data: Record<string, unknown> = {\n _declaration: { _attributes: { version: '1.0', encoding: 'utf-8' } },\n ...dataObject,\n };\n\n const xml = convert.js2xml(data as convert.ElementCompact, {\n compact: true,\n ignoreComment: true,\n spaces: 2,\n fullTagEmptyElement: true,\n textFn: (value: string, label: string) => {\n const omits = ['version'];\n if (\n /^\\d+\\.\\d+$/.test(value) &&\n round &&\n !omits.includes(label.toLowerCase())\n ) {\n return parseFloat(value).toFixed(2);\n }\n return value;\n },\n });\n\n return ok(xml);\n } catch (error) {\n return err(\n new DgiiError(\n `Error converting JSON to XML: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n }\n\n xml2json<T>(xml: string): Result<T, DgiiError> {\n try {\n const json = convert.xml2js(xml, {\n compact: true,\n ignoreComment: true,\n nativeType: false,\n });\n return ok(json as T);\n } catch (error) {\n return err(\n new DgiiError(\n `Error converting XML to JSON: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n }\n}\n","import { BaseUrl, Environment } from './environment.js';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\nimport { Transformer } from './transformer.js';\n\n/** First 6 chars of the `<SignatureValue>` (DGII security code). */\nexport const getCodeSixDigitfromSignature = (\n signedXml: string,\n): Result<string, DgiiError> => {\n const match = signedXml.match(/<SignatureValue>([\\s\\S]*?)<\\/SignatureValue>/);\n const value = match?.[1]?.trim();\n if (!value) {\n return err(new DgiiError('SignatureValue not found', { code: 'SIGNING' }));\n }\n if (value.length < 6) {\n return err(\n new DgiiError('SignatureValue is too short', { code: 'SIGNING' }),\n );\n }\n return ok(value.slice(0, 6));\n};\n\n/** QR URL for a factura de consumo (FC). */\nexport const generateFcQRCodeURL = (\n rncemisor: string,\n encf: string,\n montototal: number,\n codigoseguridad: string,\n env: Environment,\n): string =>\n `${BaseUrl.CF}/${env.toLowerCase()}/consultatimbrefc?rncemisor=${encodeURIComponent(\n rncemisor,\n )}&encf=${encodeURIComponent(encf)}&montototal=${encodeURIComponent(\n String(montototal),\n )}&codigoseguridad=${encodeURIComponent(codigoseguridad)}`;\n\n/** QR URL for a crédito fiscal (e-CF). */\nexport const generateEcfQRCodeURL = (\n rncemisor: string,\n rncComprador: string,\n encf: string,\n montototal: string,\n fechaEmision: string,\n fechaFirma: string,\n codigoseguridad: string,\n env: Environment,\n): string => {\n let rncCompradorParam = '';\n if (rncComprador && !/E43/i.test(encf) && !/E47/i.test(encf)) {\n rncCompradorParam = `RncComprador=${encodeURIComponent(rncComprador)}&`;\n }\n return `${BaseUrl.ECF}/${env.toLowerCase()}/consultatimbre?rncemisor=${encodeURIComponent(\n rncemisor,\n )}&${rncCompradorParam}encf=${encodeURIComponent(\n encf,\n )}&fechaemision=${encodeURIComponent(\n fechaEmision,\n )}&montototal=${encodeURIComponent(\n montototal,\n )}&fechafirma=${encodeURIComponent(\n fechaFirma,\n )}&codigoseguridad=${encodeURIComponent(codigoseguridad)}`;\n};\n\nconst formatInSantoDomingo = (date: Date, withTime: boolean): string => {\n const parts = new Intl.DateTimeFormat('es-DO', {\n timeZone: 'America/Santo_Domingo',\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n ...(withTime\n ? { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }\n : {}),\n })\n .formatToParts(date)\n .reduce<Record<string, string>>((acc, part) => {\n acc[part.type] = part.value;\n return acc;\n }, {});\n\n const datePart = `${parts.day}-${parts.month}-${parts.year}`;\n return withTime\n ? `${datePart} ${parts.hour}:${parts.minute}:${parts.second}`\n : datePart;\n};\n\n/** `DD-MM-YYYY HH:mm:ss` in America/Santo_Domingo. */\nexport const getCurrentFormattedDateTime = (date: Date = new Date()): string =>\n formatInSantoDomingo(date, true);\n\n/** `DD-MM-YYYY` in America/Santo_Domingo. */\nexport const getCurrentFormattedDate = (date: Date = new Date()): string =>\n formatInSantoDomingo(date, false);\n\n/** Extract the XML payload embedded in a DGII commercial-approval body. */\nexport const getXmlFromBodyResponse = (\n body: string,\n lastTagName = 'ACECF',\n): string | undefined =>\n body.match(new RegExp(`<\\\\?xml[\\\\s\\\\S]*?<\\\\/${lastTagName}>`))?.[0];\n\ninterface CompactElement {\n _text?: string;\n [key: string]: unknown;\n}\n\ninterface ImpuestoAdicional {\n TipoImpuesto?: CompactElement;\n MontoImpuestoSelectivoConsumoEspecifico?: CompactElement;\n MontoImpuestoSelectivoConsumoAdvalorem?: CompactElement;\n OtrosImpuestosAdicionales?: CompactElement;\n}\n\ninterface EcfTotales {\n MontoGravadoTotal?: CompactElement;\n MontoGravadoI1?: CompactElement;\n MontoGravadoI2?: CompactElement;\n MontoGravadoI3?: CompactElement;\n MontoExento?: CompactElement;\n TotalITBIS?: CompactElement;\n TotalITBIS1?: CompactElement;\n TotalITBIS2?: CompactElement;\n TotalITBIS3?: CompactElement;\n MontoImpuestoAdicional?: CompactElement;\n ImpuestosAdicionales?: {\n ImpuestoAdicional?: ImpuestoAdicional | ImpuestoAdicional[];\n };\n MontoTotal?: CompactElement;\n MontoNoFacturable?: CompactElement;\n MontoPeriodo?: CompactElement;\n}\n\ninterface EcfJson {\n ECF: {\n Encabezado?: {\n Version?: CompactElement;\n IdDoc?: {\n TipoeCF?: CompactElement;\n eNCF?: CompactElement;\n TipoIngresos?: CompactElement;\n TipoPago?: CompactElement;\n TablaFormasPago?: CompactElement;\n };\n Emisor?: {\n RNCEmisor?: CompactElement;\n RazonSocialEmisor?: CompactElement;\n FechaEmision?: CompactElement;\n };\n Comprador?: {\n RNCComprador?: CompactElement;\n IdentificadorExtranjero?: CompactElement;\n RazonSocialComprador?: CompactElement;\n };\n Totales?: EcfTotales;\n };\n };\n}\n\nconst toArray = <T>(value: T | T[] | undefined | null): T[] => {\n if (value === undefined || value === null) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n};\n\nconst isEmptyObject = (value: unknown): boolean =>\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n Object.keys(value as Record<string, unknown>).length === 0;\n\nconst removeEmptyValues = (input: unknown): unknown => {\n if (input === null || input === undefined || input === '') {\n return undefined;\n }\n if (Array.isArray(input)) {\n const filtered = input\n .map(removeEmptyValues)\n .filter(\n (item) =>\n item !== null &&\n item !== undefined &&\n item !== '' &&\n !isEmptyObject(item),\n );\n return filtered.length ? filtered : undefined;\n }\n if (typeof input === 'object') {\n const output: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(\n input as Record<string, unknown>,\n )) {\n const cleaned = removeEmptyValues(value);\n if (cleaned !== undefined && cleaned !== '' && !isEmptyObject(cleaned)) {\n output[key] = cleaned;\n }\n }\n return Object.keys(output).length ? output : undefined;\n }\n return input;\n};\n\n/**\n * Build the RFCE (summary invoice) document from a signed ECF-32 document.\n * Returns the unsigned RFCE XML plus the 6-digit security code.\n */\nexport const convertECF32ToRFCE = (\n ecf32Xml: string,\n): Result<{ xml: string; securityCode: string }, DgiiError> => {\n const securityCode = getCodeSixDigitfromSignature(ecf32Xml);\n if (securityCode.isErr()) {\n return err(securityCode.error);\n }\n\n const transformer = new Transformer();\n const parsed = transformer.xml2json<EcfJson>(ecf32Xml);\n if (parsed.isErr()) {\n return err(parsed.error);\n }\n\n const encabezado = parsed.value.ECF.Encabezado;\n const impuestos = toArray(\n encabezado?.Totales?.ImpuestosAdicionales?.ImpuestoAdicional,\n );\n\n const rfce = removeEmptyValues({\n RFCE: {\n Encabezado: {\n Version: encabezado?.Version,\n IdDoc: {\n TipoeCF: encabezado?.IdDoc?.TipoeCF,\n eNCF: encabezado?.IdDoc?.eNCF,\n TipoIngresos: encabezado?.IdDoc?.TipoIngresos,\n TipoPago: encabezado?.IdDoc?.TipoPago,\n TablaFormasPago: encabezado?.IdDoc?.TablaFormasPago,\n },\n Emisor: {\n RNCEmisor: encabezado?.Emisor?.RNCEmisor,\n RazonSocialEmisor: encabezado?.Emisor?.RazonSocialEmisor,\n FechaEmision: encabezado?.Emisor?.FechaEmision,\n },\n Comprador: {\n RNCComprador: encabezado?.Comprador?.RNCComprador,\n IdentificadorExtranjero:\n encabezado?.Comprador?.IdentificadorExtranjero,\n RazonSocialComprador: encabezado?.Comprador?.RazonSocialComprador,\n },\n Totales: {\n MontoGravadoTotal: encabezado?.Totales?.MontoGravadoTotal,\n MontoGravadoI1: encabezado?.Totales?.MontoGravadoI1,\n MontoGravadoI2: encabezado?.Totales?.MontoGravadoI2,\n MontoGravadoI3: encabezado?.Totales?.MontoGravadoI3,\n MontoExento: encabezado?.Totales?.MontoExento,\n TotalITBIS: encabezado?.Totales?.TotalITBIS,\n TotalITBIS1: encabezado?.Totales?.TotalITBIS1,\n TotalITBIS2: encabezado?.Totales?.TotalITBIS2,\n TotalITBIS3: encabezado?.Totales?.TotalITBIS3,\n MontoImpuestoAdicional: encabezado?.Totales?.MontoImpuestoAdicional,\n ImpuestosAdicionales: {\n ImpuestoAdicional: impuestos.map((impuesto) => ({\n TipoImpuesto: impuesto.TipoImpuesto,\n MontoImpuestoSelectivoConsumoEspecifico:\n impuesto.MontoImpuestoSelectivoConsumoEspecifico,\n MontoImpuestoSelectivoConsumoAdvalorem:\n impuesto.MontoImpuestoSelectivoConsumoAdvalorem,\n OtrosImpuestosAdicionales: impuesto.OtrosImpuestosAdicionales,\n })),\n },\n MontoTotal: encabezado?.Totales?.MontoTotal,\n MontoNoFacturable: encabezado?.Totales?.MontoNoFacturable,\n MontoPeriodo: encabezado?.Totales?.MontoPeriodo,\n },\n CodigoSeguridadeCF: securityCode.value,\n },\n },\n });\n\n if (typeof rfce !== 'object' || rfce === null) {\n return err(\n new DgiiError('Unable to build RFCE document', { code: 'VALIDATION' }),\n );\n }\n\n const xml = transformer.json2xml(rfce);\n if (xml.isErr()) {\n return err(xml.error);\n }\n\n return ok({ xml: xml.value, securityCode: securityCode.value });\n};\n","import { createHash } from 'node:crypto';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\nimport {\n BaseUrl,\n Endpoint,\n Environment,\n SenderReceiverEndpoint,\n buildSenderReceiverUrl,\n buildUrl,\n} from './environment.js';\nimport {\n HttpClient,\n InMemoryIdempotencyStore,\n type IdempotencyStore,\n} from './http.js';\nimport type { ResilienceOptions } from './resilience.js';\nimport { Signature } from './signing.js';\nimport type { P12ReaderData } from './certificate.js';\nimport type {\n AuthToken,\n CommercialApprovalResponse,\n InquiryInvoiceSummary,\n InquiryStatusResponse,\n InvoiceResponse,\n InvoiceSummaryResponse,\n ServiceDirectoryResponse,\n SummaryTrackingStatusResponse,\n TrackingStatusResponse,\n VoidNCFResponse,\n} from './types.js';\n\nexport interface EcfOptions {\n /** Pre-existing bearer token (skips the authentication round-trip). */\n token?: string;\n /** Pluggable idempotency store; defaults to an in-memory store. */\n idempotencyStore?: IdempotencyStore;\n resilience?: ResilienceOptions;\n timeoutMs?: number;\n /** Injectable fetch (useful for tests). */\n fetchImpl?: typeof fetch;\n}\n\ninterface PendingSubmission {\n readonly pending: true;\n}\n\nconst PENDING_SUBMISSION: PendingSubmission = { pending: true };\n\nconst isPendingSubmission = (value: unknown): value is PendingSubmission =>\n typeof value === 'object' &&\n value !== null &&\n (value as { pending?: unknown }).pending === true;\n\nconst sha256Hex = (value: string): string =>\n createHash('sha256').update(value, 'utf8').digest('hex');\n\nconst extractTag = (xml: string, tag: string): string | undefined => {\n const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));\n return match?.[1]?.trim();\n};\n\n/**\n * DGII e-CF client. Every method returns a `Result` — no thrown domain errors.\n */\nexport class ECF {\n private readonly environment: Environment;\n private readonly http: HttpClient;\n private readonly idempotency: IdempotencyStore;\n private readonly credentials: P12ReaderData;\n private readonly inFlight = new Map<\n string,\n Promise<Result<unknown, DgiiError>>\n >();\n\n constructor(\n credentials: P12ReaderData,\n environment: Environment = Environment.Dev,\n options: EcfOptions = {},\n ) {\n this.credentials = credentials;\n this.environment = environment;\n this.idempotency =\n options.idempotencyStore ?? new InMemoryIdempotencyStore();\n this.http = new HttpClient({\n baseUrl: BaseUrl.ECF,\n ...(options.token !== undefined ? { token: options.token } : {}),\n ...(options.resilience !== undefined\n ? { resilience: options.resilience }\n : {}),\n ...(options.timeoutMs !== undefined\n ? { timeoutMs: options.timeoutMs }\n : {}),\n ...(options.fetchImpl !== undefined\n ? { fetchImpl: options.fetchImpl }\n : {}),\n });\n }\n\n private buildIdempotencyKey(signedXml: string): string {\n const rnc = extractTag(signedXml, 'RNCEmisor') ?? 'unknown-rnc';\n const encf = extractTag(signedXml, 'eNCF') ?? 'unknown-encf';\n return `${rnc}:${encf}:${sha256Hex(signedXml)}`;\n }\n\n private async singleFlight<T>(\n key: string,\n task: () => Promise<Result<T, DgiiError>>,\n ): Promise<Result<T, DgiiError>> {\n const existing = this.inFlight.get(key);\n if (existing) {\n return existing as Promise<Result<T, DgiiError>>;\n }\n const promise = task();\n this.inFlight.set(key, promise as Promise<Result<unknown, DgiiError>>);\n try {\n return await promise;\n } finally {\n this.inFlight.delete(key);\n }\n }\n\n /** Authenticate against DGII (or a buyer host) and store the bearer token. */\n async authenticate(\n buyerHost?: string,\n ): Promise<Result<AuthToken, DgiiError>> {\n const seed = await this.getSeed(buyerHost);\n if (seed.isErr()) {\n return err(seed.error);\n }\n if (\n typeof this.credentials.key !== 'string' ||\n typeof this.credentials.cert !== 'string'\n ) {\n return err(\n new DgiiError(\n 'A private key and certificate PEM are required to authenticate',\n { code: 'CERTIFICATE' },\n ),\n );\n }\n\n const signed = new Signature(\n this.credentials.key,\n this.credentials.cert,\n ).signXml(seed.value, 'SemillaModel');\n if (signed.isErr()) {\n return err(signed.error);\n }\n\n const token = await this.getAuthToken(signed.value, buyerHost);\n if (token.isErr()) {\n return err(token.error);\n }\n this.http.setToken(token.value.token);\n return ok(token.value);\n }\n\n private getSeed(buyerHost?: string): Promise<Result<string, DgiiError>> {\n if (buyerHost) {\n const url = buildSenderReceiverUrl(\n buyerHost,\n SenderReceiverEndpoint.Seed,\n );\n return this.http.get<string>(url, undefined, {\n absoluteUrl: true,\n resource: SenderReceiverEndpoint.Seed,\n });\n }\n const url = buildUrl(this.environment, Endpoint.Seed);\n return this.http.get<string>(url, undefined, {\n absoluteUrl: true,\n resource: Endpoint.Seed,\n });\n }\n\n private getAuthToken(\n signedSeed: string,\n buyerHost?: string,\n ): Promise<Result<AuthToken, DgiiError>> {\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.ValidateSeed)\n : buildUrl(this.environment, Endpoint.ValidateSeed);\n return this.http.postMultipart<AuthToken>(url, 'signed.xml', signedSeed, {\n absoluteUrl: true,\n resource: Endpoint.ValidateSeed,\n });\n }\n\n /**\n * Submit a signed e-CF. Idempotent on `RNC + eNCF + SHA-256(signed XML)`:\n * a repeated call returns the cached response instead of double-issuing.\n */\n async sendElectronicDocument(\n signedXml: string,\n fileName: string,\n buyerHost?: string,\n ): Promise<Result<InvoiceResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n const cached = await this.idempotency.get<\n InvoiceResponse | PendingSubmission\n >(key);\n if (cached !== undefined) {\n if (isPendingSubmission(cached)) {\n return err(\n new DgiiError(\n 'A submission with this key is already pending; reconcile via a status lookup before retrying',\n { code: 'IDEMPOTENCY' },\n ),\n );\n }\n return ok(cached);\n }\n return this.singleFlight(key, async () => {\n // Persist-before-transmit: record the pending submission before the\n // network call so an interrupted send can be reconciled, not re-issued.\n await this.idempotency.set(key, PENDING_SUBMISSION);\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.SendInvoice)\n : buildUrl(this.environment, Endpoint.SendInvoice);\n const result = await this.http.postMultipart<InvoiceResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendInvoice },\n );\n if (result.isOk()) {\n await this.idempotency.set(key, result.value);\n } else {\n await this.idempotency.delete(key);\n }\n return result;\n });\n }\n\n /** Submit a signed summary invoice (RFCE). Idempotent like submissions. */\n async sendSummary(\n signedXml: string,\n fileName: string,\n ): Promise<Result<InvoiceSummaryResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n const cached = await this.idempotency.get<\n InvoiceSummaryResponse | PendingSubmission\n >(key);\n if (cached !== undefined) {\n if (isPendingSubmission(cached)) {\n return err(\n new DgiiError(\n 'A submission with this key is already pending; reconcile via a status lookup before retrying',\n { code: 'IDEMPOTENCY' },\n ),\n );\n }\n return ok(cached);\n }\n return this.singleFlight(key, async () => {\n // Persist-before-transmit (see sendElectronicDocument).\n await this.idempotency.set(key, PENDING_SUBMISSION);\n const url = buildUrl(this.environment, Endpoint.SendSummary, BaseUrl.CF);\n const result = await this.http.postMultipart<InvoiceSummaryResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendSummary },\n );\n if (result.isOk()) {\n await this.idempotency.set(key, result.value);\n } else {\n await this.idempotency.delete(key);\n }\n return result;\n });\n }\n\n statusTrackId(\n trackId: string,\n ): Promise<Result<TrackingStatusResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.TrackResultStatus);\n return this.http.get<TrackingStatusResponse>(\n url,\n { trackId },\n { absoluteUrl: true, resource: Endpoint.TrackResultStatus },\n );\n }\n\n inquiryStatus(\n rncEmisor: string,\n ncfElectronico: string,\n rncComprador?: string,\n codigoSeguridad?: string,\n ): Promise<Result<InquiryStatusResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.InquiryStatus);\n return this.http.get<InquiryStatusResponse>(\n url,\n { rncEmisor, ncfElectronico, rncComprador, codigoSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryStatus },\n );\n }\n\n trackStatuses(\n rncEmisor: string,\n encf: string,\n ): Promise<Result<SummaryTrackingStatusResponse[], DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.AllTrackingEcf);\n return this.http.get<SummaryTrackingStatusResponse[]>(\n url,\n { rncEmisor, encf },\n { absoluteUrl: true, resource: Endpoint.AllTrackingEcf },\n );\n }\n\n /** Normalizes DGII's inconsistent (array | single object) directory payload. */\n async getCustomerDirectory(\n rnc: string,\n ): Promise<Result<ServiceDirectoryResponse[] | undefined, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Directory);\n const result = await this.http.get<\n ServiceDirectoryResponse[] | ServiceDirectoryResponse\n >(url, { rnc }, { absoluteUrl: true, resource: Endpoint.Directory });\n if (result.isErr()) {\n return err(result.error);\n }\n const data = result.value;\n if (data === undefined || data === null) {\n return ok(undefined);\n }\n return ok(Array.isArray(data) ? data : [data]);\n }\n\n /** RFCE inquiry — DGII production only. */\n getSummaryInvoiceInquiry(\n rnc: string,\n encf: string,\n codSeguridad: string,\n ): Promise<Result<InquiryInvoiceSummary, DgiiError>> {\n const url = buildUrl(\n this.environment,\n Endpoint.InquiryInvoiceSummary,\n BaseUrl.CF,\n );\n return this.http.get<InquiryInvoiceSummary>(\n url,\n { rnc_emisor: rnc, encf, cod_seguridad_eCF: codSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryInvoiceSummary },\n );\n }\n\n sendCommercialApproval(\n signedXml: string,\n fileName: string,\n ): Promise<Result<CommercialApprovalResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.CommercialApproval);\n return this.http.postMultipart<CommercialApprovalResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.CommercialApproval },\n );\n }\n\n voidENCF(\n signedXml: string,\n fileName: string,\n ): Promise<Result<VoidNCFResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Void);\n return this.http.postMultipart<VoidNCFResponse>(url, fileName, signedXml, {\n absoluteUrl: true,\n resource: Endpoint.Void,\n });\n }\n}\n"],"mappings":"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","names":["Environment","Endpoint","SenderReceiverEndpoint","TrackStatusEnum","err","forge","crypto","convert","import_node_crypto","url"]}
|
package/dist/index.js
CHANGED
|
@@ -578,30 +578,22 @@ var P12Reader = class {
|
|
|
578
578
|
// src/signing.ts
|
|
579
579
|
import crypto from "crypto";
|
|
580
580
|
import { DOMParser } from "@xmldom/xmldom";
|
|
581
|
-
import { SignedXml } from "xml-crypto";
|
|
581
|
+
import { C14nCanonicalization, SignedXml } from "xml-crypto";
|
|
582
582
|
var C14N_INCLUSIVE = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
|
|
583
583
|
var RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
|
584
584
|
var SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256";
|
|
585
585
|
var ENVELOPED = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
|
|
586
|
-
var CUSTOM_DIGEST_URI = "http://dgii.gov.do/digest/sha256-
|
|
587
|
-
var DgiiDigest = class
|
|
588
|
-
static sortAttributes(attributes) {
|
|
589
|
-
return Array.from(attributes).sort((a, b) => {
|
|
590
|
-
const left = `${a.name}="${a.value}"`;
|
|
591
|
-
const right = `${b.name}="${b.value}"`;
|
|
592
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
593
|
-
});
|
|
594
|
-
}
|
|
586
|
+
var CUSTOM_DIGEST_URI = "http://dgii.gov.do/digest/sha256-c14n";
|
|
587
|
+
var DgiiDigest = class {
|
|
595
588
|
getHash(xml) {
|
|
596
589
|
const doc = new DOMParser().parseFromString(
|
|
597
590
|
xml
|
|
598
591
|
);
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
return crypto.createHash("sha256").update(doc.toString(), "utf8").digest("base64");
|
|
592
|
+
const canonical = new C14nCanonicalization().process(
|
|
593
|
+
doc,
|
|
594
|
+
{}
|
|
595
|
+
);
|
|
596
|
+
return crypto.createHash("sha256").update(canonical, "utf8").digest("base64");
|
|
605
597
|
}
|
|
606
598
|
getAlgorithmName() {
|
|
607
599
|
return SHA256;
|
|
@@ -924,6 +916,8 @@ var convertECF32ToRFCE = (ecf32Xml) => {
|
|
|
924
916
|
|
|
925
917
|
// src/client.ts
|
|
926
918
|
import { createHash } from "crypto";
|
|
919
|
+
var PENDING_SUBMISSION = { pending: true };
|
|
920
|
+
var isPendingSubmission = (value) => typeof value === "object" && value !== null && value.pending === true;
|
|
927
921
|
var sha256Hex = (value) => createHash("sha256").update(value, "utf8").digest("hex");
|
|
928
922
|
var extractTag = (xml, tag) => {
|
|
929
923
|
const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));
|
|
@@ -1024,10 +1018,19 @@ var ECF = class {
|
|
|
1024
1018
|
async sendElectronicDocument(signedXml, fileName, buyerHost) {
|
|
1025
1019
|
const key = this.buildIdempotencyKey(signedXml);
|
|
1026
1020
|
const cached = await this.idempotency.get(key);
|
|
1027
|
-
if (cached) {
|
|
1021
|
+
if (cached !== void 0) {
|
|
1022
|
+
if (isPendingSubmission(cached)) {
|
|
1023
|
+
return err(
|
|
1024
|
+
new DgiiError(
|
|
1025
|
+
"A submission with this key is already pending; reconcile via a status lookup before retrying",
|
|
1026
|
+
{ code: "IDEMPOTENCY" }
|
|
1027
|
+
)
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1028
1030
|
return ok(cached);
|
|
1029
1031
|
}
|
|
1030
1032
|
return this.singleFlight(key, async () => {
|
|
1033
|
+
await this.idempotency.set(key, PENDING_SUBMISSION);
|
|
1031
1034
|
const url = buyerHost ? buildSenderReceiverUrl(buyerHost, "fe/recepcion/api/ecf" /* SendInvoice */) : buildUrl(this.environment, "recepcion/api/FacturasElectronicas" /* SendInvoice */);
|
|
1032
1035
|
const result = await this.http.postMultipart(
|
|
1033
1036
|
url,
|
|
@@ -1037,6 +1040,8 @@ var ECF = class {
|
|
|
1037
1040
|
);
|
|
1038
1041
|
if (result.isOk()) {
|
|
1039
1042
|
await this.idempotency.set(key, result.value);
|
|
1043
|
+
} else {
|
|
1044
|
+
await this.idempotency.delete(key);
|
|
1040
1045
|
}
|
|
1041
1046
|
return result;
|
|
1042
1047
|
});
|
|
@@ -1045,10 +1050,19 @@ var ECF = class {
|
|
|
1045
1050
|
async sendSummary(signedXml, fileName) {
|
|
1046
1051
|
const key = this.buildIdempotencyKey(signedXml);
|
|
1047
1052
|
const cached = await this.idempotency.get(key);
|
|
1048
|
-
if (cached) {
|
|
1053
|
+
if (cached !== void 0) {
|
|
1054
|
+
if (isPendingSubmission(cached)) {
|
|
1055
|
+
return err(
|
|
1056
|
+
new DgiiError(
|
|
1057
|
+
"A submission with this key is already pending; reconcile via a status lookup before retrying",
|
|
1058
|
+
{ code: "IDEMPOTENCY" }
|
|
1059
|
+
)
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1049
1062
|
return ok(cached);
|
|
1050
1063
|
}
|
|
1051
1064
|
return this.singleFlight(key, async () => {
|
|
1065
|
+
await this.idempotency.set(key, PENDING_SUBMISSION);
|
|
1052
1066
|
const url = buildUrl(this.environment, "recepcionfc/api/recepcion/ecf" /* SendSummary */, BaseUrl.CF);
|
|
1053
1067
|
const result = await this.http.postMultipart(
|
|
1054
1068
|
url,
|
|
@@ -1058,6 +1072,8 @@ var ECF = class {
|
|
|
1058
1072
|
);
|
|
1059
1073
|
if (result.isOk()) {
|
|
1060
1074
|
await this.idempotency.set(key, result.value);
|
|
1075
|
+
} else {
|
|
1076
|
+
await this.idempotency.delete(key);
|
|
1061
1077
|
}
|
|
1062
1078
|
return result;
|
|
1063
1079
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/environment.ts","../src/types.ts","../src/errors.ts","../src/result.ts","../src/resilience.ts","../src/http.ts","../src/certificate.ts","../src/signing.ts","../src/transformer.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["export enum Environment {\n /** DGII test environment */\n Dev = 'TesteCF',\n /** DGII certification environment */\n Cert = 'CerteCF',\n /** DGII production environment */\n Prod = 'eCF',\n}\n\nexport const BaseUrl = {\n /** Crédito fiscal / general e-CF services */\n ECF: 'https://ecf.dgii.gov.do',\n /** Factura de consumo (< DOP 250,000) */\n CF: 'https://fc.dgii.gov.do',\n /** DGII service status */\n STATUS: 'https://statusecf.dgii.gov.do',\n} as const;\n\nexport type BaseUrlKey = keyof typeof BaseUrl;\n\nexport enum Endpoint {\n Seed = 'Autenticacion/api/Autenticacion/Semilla',\n ValidateSeed = 'autenticacion/api/Autenticacion/ValidarSemilla',\n SendInvoice = 'recepcion/api/FacturasElectronicas',\n SendSummary = 'recepcionfc/api/recepcion/ecf',\n InquiryInvoiceSummary = 'consultarfce/api/Consultas/Consulta',\n CommercialApproval = 'aprobacionComercial/api/AprobacionComercial',\n TrackResultStatus = 'consultaresultado/api/Consultas/Estado',\n InquiryStatus = 'consultaestado/api/Consultas/Estado',\n AllTrackingEcf = 'ConsultaTrackIds/api/TrackIds/Consulta',\n Directory = 'consultadirectorio/api/consultas/obtenerdirectorioporrnc',\n Void = 'anulacionrangos/api/operaciones/anularrango',\n}\n\n/** Endpoints used when talking to a buyer's Sender↔Receiver host. */\nexport enum SenderReceiverEndpoint {\n Seed = 'fe/autenticacion/api/semilla',\n ValidateSeed = 'fe/autenticacion/api/validacioncertificado',\n SendInvoice = 'fe/recepcion/api/ecf',\n CommercialApproval = 'fe/aprobacioncomercial/api/ecf',\n}\n\n/** Build an absolute DGII URL: `${baseUrl}/${environment}/${endpoint}`. */\nexport const buildUrl = (\n environment: Environment,\n endpoint: Endpoint,\n baseUrl: string = BaseUrl.ECF,\n): string => `${baseUrl.replace(/\\/+$/, '')}/${environment}/${endpoint}`;\n\n/** Build an absolute Sender↔Receiver URL against a buyer host. */\nexport const buildSenderReceiverUrl = (\n host: string,\n endpoint: SenderReceiverEndpoint,\n): string => `${host.replace(/\\/+$/, '')}/${endpoint}`;\n","export interface Mensaje {\n valor: string;\n codigo: number;\n}\n\nexport interface AuthToken {\n token: string;\n expira: string;\n expedido: string;\n}\n\nexport enum TrackStatusEnum {\n NotFound = 'No encontrado',\n Accepted = 'Aceptado',\n Rejected = 'Rechazado',\n InProcess = 'En Proceso',\n ConditionalAccepted = 'Aceptado Condicional',\n}\n\nexport type TrackStatusCode = 0 | 1 | 2 | 3 | 4;\n\nexport interface TrackingStatusResponse {\n trackId: string;\n codigo: TrackStatusCode;\n estado: TrackStatusEnum;\n rnc: string;\n encf: string;\n secuenciaUtilizada: boolean;\n fechaRecepcion: string;\n mensajes?: Mensaje[];\n}\n\nexport type InquiryStatusCode = 0 | 1 | 2;\n\nexport type InquiryStatus = 'No encontrado' | 'Aceptado' | 'Rechazado';\n\nexport interface InquiryStatusResponse {\n codigo: InquiryStatusCode;\n estado: InquiryStatus;\n rncEmisor?: string;\n ncfElectronico?: string;\n montoTotal?: number;\n totalITBIS?: number;\n fechaEmision?: string;\n fechaFirma?: string;\n rncComprador?: string;\n codigoSeguridad?: string;\n idExtranjero?: string;\n}\n\nexport interface SummaryTrackingStatusResponse {\n trackId: string;\n estado: string;\n fechaRecepcion: string;\n}\n\nexport interface InvoiceResponse {\n trackId?: string;\n error?: string;\n mensajes?: Mensaje[];\n}\n\nexport interface InvoiceSummaryResponse {\n codigo: number;\n estado: 'Aceptado' | 'Rechazado' | 'Aceptado Condicional';\n mensajes?: Mensaje[];\n encf: string;\n secuenciaUtilizada: boolean;\n}\n\nexport interface ServiceDirectoryResponse {\n nombre: string;\n rnc: string;\n urlRecepcion: string;\n urlAceptacion: string;\n urlOpcional: string;\n}\n\nexport interface InquiryInvoiceSummary {\n rnc: string;\n encf: string;\n secuenciaUtilizada: boolean;\n codigo: InquiryStatusCode;\n estado: InquiryStatus;\n mensajes?: Mensaje[];\n}\n\nexport interface CommercialApprovalResponse {\n codigo: '01' | '02';\n estado: 'Aprobación Comercial Aprobada.' | 'Aprobacion Comercial Rechazada.';\n mensaje: string[];\n}\n\nexport interface VoidNCFResponse {\n rnc: string;\n codigo: string;\n nombre: string;\n mensajes: string[];\n}\n","import type { Mensaje } from './types.js';\n\nexport type DgiiErrorCode =\n | 'INVALID_XML'\n | 'CERTIFICATE'\n | 'SIGNING'\n | 'HTTP'\n | 'AUTH'\n | 'TIMEOUT'\n | 'CIRCUIT_OPEN'\n | 'IDEMPOTENCY'\n | 'VALIDATION'\n | 'UNKNOWN';\n\nconst RETRYABLE_STATUSES = new Set<number>([408, 429, 500, 502, 503, 504]);\n\nexport const isRetryableStatus = (status: number | undefined): boolean =>\n status !== undefined && RETRYABLE_STATUSES.has(status);\n\nexport interface DgiiErrorOptions {\n code?: DgiiErrorCode;\n status?: number;\n statusText?: string;\n resource?: string;\n method?: string;\n baseURL?: string;\n data?: unknown;\n mensajes?: Mensaje[];\n retryable?: boolean;\n cause?: unknown;\n}\n\nconst MAX_RAW = 1000;\n\nconst truncate = (value: string): string =>\n value.length > MAX_RAW ? `${value.slice(0, MAX_RAW)}…` : value;\n\nconst collapseWhitespace = (value: string): string =>\n value.replace(/\\s+/g, ' ').trim();\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst looksLikeHtml = (value: string): boolean =>\n /^\\s*<(?:!doctype|html|body|head)\\b/i.test(value);\n\nconst stripHtml = (value: string): string =>\n collapseWhitespace(\n value\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<[^>]+>/g, ' '),\n );\n\nconst readMensajes = (value: unknown): Mensaje[] | undefined => {\n if (!Array.isArray(value) || value.length === 0) {\n return undefined;\n }\n const out: Mensaje[] = [];\n for (const item of value) {\n if (typeof item === 'string' && item.trim()) {\n out.push({ valor: item.trim(), codigo: 0 });\n } else if (isObject(item) && typeof item.valor === 'string') {\n out.push({\n valor: item.valor,\n codigo: typeof item.codigo === 'number' ? item.codigo : 0,\n });\n }\n }\n return out.length ? out : undefined;\n};\n\nconst MESSAGE_KEYS = [\n 'mensaje',\n 'Mensaje',\n 'message',\n 'Message',\n 'error',\n 'Error',\n 'errorMessage',\n 'error_description',\n 'detail',\n 'Detail',\n 'title',\n 'Title',\n 'descripcion',\n 'Descripcion',\n];\n\n/**\n * Reduce DGII's inconsistent error payloads (bare string, `{ mensajes }`,\n * ASP.NET ProblemDetails/ModelState, or an HTML page) to a single message.\n */\nexport const extractDgiiErrorMessage = (\n data: unknown,\n seen: WeakSet<object> = new WeakSet<object>(),\n): string | undefined => {\n if (data === undefined || data === null) {\n return undefined;\n }\n\n if (typeof data === 'string') {\n const trimmed = data.trim();\n if (!trimmed) {\n return undefined;\n }\n if (/^[[{\"]/.test(trimmed)) {\n try {\n return extractDgiiErrorMessage(JSON.parse(trimmed), seen);\n } catch {\n // Not JSON after all — fall through to raw text.\n }\n }\n if (looksLikeHtml(trimmed)) {\n const text = stripHtml(trimmed);\n return text ? truncate(text) : undefined;\n }\n return truncate(collapseWhitespace(trimmed));\n }\n\n if (typeof data === 'number' || typeof data === 'boolean') {\n return String(data);\n }\n\n if (data instanceof Error) {\n return data.message || undefined;\n }\n\n if (Array.isArray(data)) {\n if (seen.has(data)) {\n return undefined;\n }\n seen.add(data);\n const parts = data\n .map((item) => extractDgiiErrorMessage(item, seen))\n .filter((item): item is string => Boolean(item));\n return parts.length ? truncate(parts.join(' | ')) : undefined;\n }\n\n if (isObject(data)) {\n if (seen.has(data)) {\n return undefined;\n }\n seen.add(data);\n\n const mensajes = readMensajes(data.mensajes ?? data.Mensajes);\n if (mensajes) {\n return truncate(mensajes.map((mensaje) => mensaje.valor).join(' | '));\n }\n\n for (const key of MESSAGE_KEYS) {\n const value = data[key];\n if (typeof value === 'string' && value.trim()) {\n return truncate(collapseWhitespace(value));\n }\n if (key === 'error' && (isObject(value) || Array.isArray(value))) {\n const nested = extractDgiiErrorMessage(value, seen);\n if (nested) {\n return nested;\n }\n }\n }\n\n const errors = data.errors ?? data.Errors;\n if (isObject(errors)) {\n const parts = Object.entries(errors)\n .map(([field, value]) => {\n const nested = extractDgiiErrorMessage(value, seen);\n return nested ? `${field}: ${nested}` : undefined;\n })\n .filter((item): item is string => Boolean(item));\n if (parts.length) {\n return truncate(parts.join(' | '));\n }\n } else if (errors) {\n const nested = extractDgiiErrorMessage(errors, seen);\n if (nested) {\n return nested;\n }\n }\n\n try {\n const serialized = JSON.stringify(data);\n if (serialized && serialized !== '{}') {\n return truncate(serialized);\n }\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n};\n\nexport class DgiiError extends Error {\n readonly code: DgiiErrorCode;\n readonly status?: number;\n readonly statusText?: string;\n readonly resource?: string;\n readonly method?: string;\n readonly baseURL?: string;\n readonly data?: unknown;\n readonly mensajes?: Mensaje[];\n readonly retryable: boolean;\n\n constructor(message: string, options: DgiiErrorOptions = {}) {\n super(message);\n this.name = 'DgiiError';\n Object.setPrototypeOf(this, DgiiError.prototype);\n\n this.code = options.code ?? 'UNKNOWN';\n this.status = options.status;\n this.statusText = options.statusText;\n this.resource = options.resource;\n this.method = options.method;\n this.baseURL = options.baseURL;\n this.data = options.data;\n this.mensajes = options.mensajes;\n this.retryable = options.retryable ?? isRetryableStatus(options.status);\n\n if (options.cause !== undefined) {\n Object.defineProperty(this, 'cause', {\n value: options.cause,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n }\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n status: this.status,\n statusText: this.statusText,\n resource: this.resource,\n method: this.method,\n mensajes: this.mensajes,\n data: this.data,\n };\n }\n}\n\nexport interface DgiiErrorContext {\n code?: DgiiErrorCode;\n status?: number;\n statusText?: string;\n resource?: string;\n method?: string;\n baseURL?: string;\n fallbackMessage?: string;\n}\n\n/** Normalize any thrown value into a {@link DgiiError}. */\nexport const toDgiiError = (\n err: unknown,\n context: DgiiErrorContext = {},\n): DgiiError => {\n if (err instanceof DgiiError) {\n return err;\n }\n\n if (err instanceof Error) {\n return new DgiiError(\n err.message || context.fallbackMessage || 'DGII request failed',\n {\n ...context,\n cause: err,\n },\n );\n }\n\n const message =\n extractDgiiErrorMessage(err) ||\n context.fallbackMessage ||\n 'DGII request failed';\n const status =\n isObject(err) && typeof err.status === 'number'\n ? err.status\n : context.status;\n\n return new DgiiError(message, {\n ...context,\n status,\n data: err,\n mensajes: isObject(err)\n ? readMensajes(err.mensajes ?? err.Mensajes)\n : undefined,\n cause: err,\n });\n};\n","import type { Result } from 'neverthrow';\nimport type { DgiiError } from './errors.js';\n\nexport type { Result } from 'neverthrow';\n\nexport {\n Ok,\n Err,\n ok,\n err,\n okAsync,\n errAsync,\n fromThrowable,\n fromPromise,\n fromSafePromise,\n ResultAsync,\n} from 'neverthrow';\n\n/** A {@link Result} whose failure channel is always {@link DgiiError}. */\nexport type DgiiResult<T> = Result<T, DgiiError>;\n","import {\n ConsecutiveBreaker,\n ExponentialBackoff,\n TimeoutStrategy,\n bulkhead,\n circuitBreaker,\n handleAll,\n handleWhen,\n retry,\n timeout,\n wrap,\n type IPolicy,\n} from 'cockatiel';\nimport { DgiiError } from './errors.js';\n\nexport interface ResilienceOptions {\n /** Maximum number of attempts (including the first). Default 3. */\n maxRetries?: number;\n /** Consecutive failures before the circuit opens. Default 5. */\n breakerThreshold?: number;\n /** Milliseconds the circuit stays open before half-opening. Default 30s. */\n halfOpenAfterMs?: number;\n /** Per-attempt timeout in milliseconds. Default 15s. */\n timeoutMs?: number;\n /** Initial retry backoff delay in milliseconds. Default 100. */\n retryInitialDelayMs?: number;\n /** Maximum concurrent in-flight requests. Default 20. */\n bulkheadLimit?: number;\n /** Maximum queued requests while the bulkhead is saturated. Default 40. */\n bulkheadQueue?: number;\n}\n\nexport const defaultResilienceOptions: Required<ResilienceOptions> = {\n maxRetries: 3,\n breakerThreshold: 5,\n halfOpenAfterMs: 30_000,\n timeoutMs: 15_000,\n retryInitialDelayMs: 100,\n bulkheadLimit: 20,\n bulkheadQueue: 40,\n};\n\n/**\n * Only transient failures are retried: network errors, timeouts, 408, 429 and\n * 5xx. A rejected e-CF (4xx) must never be blindly re-sent.\n */\nexport const isRetryableError = (error: unknown): boolean => {\n if (error instanceof DgiiError) {\n return error.retryable;\n }\n if (error instanceof Error) {\n const name = error.name.toLowerCase();\n const message = error.message.toLowerCase();\n return (\n name === 'typeerror' ||\n name === 'aborterror' ||\n name === 'fetcherror' ||\n name === 'timeouterror' ||\n name.includes('cancel') ||\n message.includes('timeout') ||\n message.includes('aborted') ||\n message.includes('network')\n );\n }\n return false;\n};\n\nexport interface ResiliencePolicies {\n readonly retry: IPolicy;\n readonly circuitBreaker: IPolicy;\n readonly timeout: IPolicy;\n readonly bulkhead: IPolicy;\n /** Composed policy: `retry → circuitBreaker → timeout → bulkhead`. */\n readonly policy: IPolicy;\n}\n\n/** Build the composed resilience policy used by the HTTP client. */\nexport const createResiliencePolicies = (\n options: ResilienceOptions = {},\n): ResiliencePolicies => {\n const opts = { ...defaultResilienceOptions, ...options };\n\n const retryPolicy = retry(handleWhen(isRetryableError), {\n maxAttempts: opts.maxRetries,\n backoff: new ExponentialBackoff({ initialDelay: opts.retryInitialDelayMs }),\n });\n\n const breakerPolicy = circuitBreaker(handleAll, {\n halfOpenAfter: opts.halfOpenAfterMs,\n breaker: new ConsecutiveBreaker(opts.breakerThreshold),\n });\n\n const timeoutPolicy = timeout(opts.timeoutMs, TimeoutStrategy.Aggressive);\n const bulkheadPolicy = bulkhead(opts.bulkheadLimit, opts.bulkheadQueue);\n\n const policy = wrap(\n retryPolicy,\n breakerPolicy,\n timeoutPolicy,\n bulkheadPolicy,\n );\n\n return {\n retry: retryPolicy,\n circuitBreaker: breakerPolicy,\n timeout: timeoutPolicy,\n bulkhead: bulkheadPolicy,\n policy,\n };\n};\n","import { err, ok, type Result } from './result.js';\nimport { DgiiError, extractDgiiErrorMessage, toDgiiError } from './errors.js';\nimport {\n createResiliencePolicies,\n type ResilienceOptions,\n type ResiliencePolicies,\n} from './resilience.js';\n\n/**\n * Pluggable idempotency store. Provide a Redis/Postgres-backed implementation\n * in production so a retried or duplicated submission never double-issues.\n */\nexport interface IdempotencyStore {\n get<T>(key: string): Promise<T | undefined>;\n set<T>(key: string, value: T): Promise<void>;\n delete(key: string): Promise<void>;\n}\n\n/** Process-local default. Fine for single-instance usage and tests. */\nexport class InMemoryIdempotencyStore implements IdempotencyStore {\n private readonly store = new Map<string, unknown>();\n\n async get<T>(key: string): Promise<T | undefined> {\n return this.store.get(key) as T | undefined;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.store.set(key, value);\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n}\n\nexport interface HttpClientOptions {\n baseUrl: string;\n token?: string;\n resilience?: ResilienceOptions;\n policies?: ResiliencePolicies;\n timeoutMs?: number;\n fetchImpl?: typeof fetch;\n}\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST';\n /** Absolute URL when `absoluteUrl` is true, otherwise a path appended to baseUrl. */\n path: string;\n absoluteUrl?: boolean;\n headers?: Record<string, string>;\n body?: BodyInit;\n query?: Record<string, string | number | undefined>;\n resource?: string;\n}\n\ninterface RequestContext {\n method: string;\n resource: string;\n baseURL: string;\n}\n\n/** Thin HTTP client over the native `fetch`, wrapped in resilience policies. */\nexport class HttpClient {\n private token?: string;\n private readonly policies: ResiliencePolicies;\n private readonly fetchImpl: typeof fetch;\n private readonly baseUrl: string;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '');\n this.token = options.token;\n this.policies =\n options.policies ??\n createResiliencePolicies({\n ...options.resilience,\n ...(options.timeoutMs !== undefined\n ? { timeoutMs: options.timeoutMs }\n : {}),\n });\n this.fetchImpl = options.fetchImpl ?? fetch;\n }\n\n setToken(token: string): void {\n this.token = token;\n }\n\n clearToken(): void {\n this.token = undefined;\n }\n\n private buildUrl(\n path: string,\n absoluteUrl: boolean | undefined,\n query: RequestOptions['query'],\n ): string {\n let url = absoluteUrl\n ? path\n : `${this.baseUrl}${path.startsWith('/') ? '' : '/'}${path}`;\n\n if (query) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== '') {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) {\n url += (url.includes('?') ? '&' : '?') + qs;\n }\n }\n return url;\n }\n\n private authHeaders(extra?: Record<string, string>): Record<string, string> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (this.token) {\n headers.Authorization = `Bearer ${this.token}`;\n }\n return { ...headers, ...extra };\n }\n\n private async readBody(response: Response): Promise<unknown> {\n const contentType = response.headers.get('content-type') ?? '';\n try {\n if (contentType.includes('json')) {\n return await response.json();\n }\n const text = await response.text();\n return text.length ? text : undefined;\n } catch {\n return undefined;\n }\n }\n\n private async parseResponse<T>(\n response: Response,\n ctx: RequestContext,\n ): Promise<Result<T, DgiiError>> {\n const data = await this.readBody(response);\n\n if (response.ok) {\n return ok(data as T);\n }\n\n const message =\n extractDgiiErrorMessage(data) ??\n `DGII request failed with status ${response.status}`;\n const error = new DgiiError(message, {\n code: response.status === 401 ? 'AUTH' : 'HTTP',\n status: response.status,\n statusText: response.statusText,\n resource: ctx.resource,\n method: ctx.method,\n baseURL: ctx.baseURL,\n data,\n });\n\n // Throw retryable failures so the retry/breaker policies can act on them;\n // non-retryable client errors are returned as a typed failure.\n if (error.retryable) {\n throw error;\n }\n return err(error);\n }\n\n async request<T>(options: RequestOptions): Promise<Result<T, DgiiError>> {\n const url = this.buildUrl(options.path, options.absoluteUrl, options.query);\n const method = options.method ?? 'GET';\n const headers = this.authHeaders(options.headers);\n const ctx: RequestContext = {\n method,\n resource: options.resource ?? options.path,\n baseURL: this.baseUrl,\n };\n\n try {\n return await this.policies.policy.execute(async ({ signal }) => {\n const response = await this.fetchImpl(url, {\n method,\n headers,\n body: options.body,\n signal,\n });\n return this.parseResponse<T>(response, ctx);\n });\n } catch (error) {\n return err(toDgiiError(error, ctx));\n }\n }\n\n get<T>(\n path: string,\n query?: RequestOptions['query'],\n opts?: { absoluteUrl?: boolean; resource?: string },\n ): Promise<Result<T, DgiiError>> {\n return this.request<T>({\n method: 'GET',\n path,\n query,\n absoluteUrl: opts?.absoluteUrl,\n resource: opts?.resource,\n });\n }\n\n /**\n * POST a signed XML as a multipart `xml` file part. The runtime computes\n * `Content-Length` from the Blob — never set it manually.\n */\n postMultipart<T>(\n path: string,\n fileName: string,\n xml: string,\n opts?: { absoluteUrl?: boolean; resource?: string },\n ): Promise<Result<T, DgiiError>> {\n const form = new FormData();\n form.append('xml', new Blob([xml], { type: 'application/xml' }), fileName);\n return this.request<T>({\n method: 'POST',\n path,\n body: form,\n headers: { Accept: 'application/json' },\n absoluteUrl: opts?.absoluteUrl,\n resource: opts?.resource,\n });\n }\n}\n","import { readFileSync } from 'node:fs';\nimport forge from 'node-forge';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\nexport interface P12ReaderData {\n key?: string;\n cert?: string;\n publicKey?: string;\n}\n\nexport interface CertificateInfo {\n subject: string;\n issuer: string;\n validFrom: Date;\n validTo: Date;\n serialNumber: string;\n}\n\nconst asErrorMessage = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/** Reads a PKCS#12 (.p12) bundle and extracts the private key + certificate. */\nexport class P12Reader {\n constructor(private readonly passphrase: string) {}\n\n private load(base64: string): forge.pkcs12.Pkcs12Pfx {\n const der = forge.util.decode64(base64);\n const asn1 = forge.asn1.fromDer(der);\n return forge.pkcs12.pkcs12FromAsn1(asn1, false, this.passphrase);\n }\n\n private extractKey(p12: forge.pkcs12.Pkcs12Pfx): string | undefined {\n const keyBags = p12.getBags({\n bagType: forge.pki.oids.pkcs8ShroudedKeyBag,\n });\n const pkcs8Key = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag]?.[0];\n if (pkcs8Key?.key) {\n return forge.pki.privateKeyToPem(pkcs8Key.key);\n }\n const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });\n const certBag = certBags[forge.pki.oids.certBag]?.[0];\n if (certBag?.key) {\n return forge.pki.privateKeyToPem(certBag.key);\n }\n return undefined;\n }\n\n private extractCertificate(p12: forge.pkcs12.Pkcs12Pfx): string | undefined {\n const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });\n const certBag = certBags[forge.pki.oids.certBag]?.[0];\n if (!certBag?.cert) {\n return undefined;\n }\n return forge.pki.certificateToPem(certBag.cert);\n }\n\n getKeyFromFile(fileName: string): Result<P12ReaderData, DgiiError> {\n try {\n const base64 = readFileSync(fileName, 'base64');\n return this.getKeyFromStringBase64(base64);\n } catch (error) {\n return err(\n new DgiiError(`Unable to read .p12 file: ${fileName}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n getKeyFromStringBase64(base64: string): Result<P12ReaderData, DgiiError> {\n try {\n const p12 = this.load(base64);\n const key = this.extractKey(p12);\n const cert = this.extractCertificate(p12);\n if (!key || !cert) {\n return err(\n new DgiiError('PKCS#12 must contain a private key and certificate', {\n code: 'CERTIFICATE',\n }),\n );\n }\n const publicKey = forge.pki.publicKeyToPem(\n forge.pki.certificateFromPem(cert).publicKey,\n );\n return ok({ key, cert, publicKey });\n } catch (error) {\n return err(\n new DgiiError(`Unable to parse .p12: ${asErrorMessage(error)}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n private toCertificateInfo(certPem: string): CertificateInfo {\n const certificate = forge.pki.certificateFromPem(certPem);\n return {\n subject: certificate.subject.attributes\n .map((attribute) => `${attribute.shortName}=${attribute.value}`)\n .join(', '),\n issuer: certificate.issuer.attributes\n .map((attribute) => `${attribute.shortName}=${attribute.value}`)\n .join(', '),\n validFrom: certificate.validity.notBefore,\n validTo: certificate.validity.notAfter,\n serialNumber: certificate.serialNumber,\n };\n }\n\n getCertificateInfo(fileName: string): Result<CertificateInfo, DgiiError> {\n try {\n const base64 = readFileSync(fileName, 'base64');\n return this.getCertificateInfoFromBase64(base64);\n } catch (error) {\n return err(\n new DgiiError(`Unable to read .p12 file: ${fileName}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n getCertificateInfoFromBase64(\n base64: string,\n ): Result<CertificateInfo, DgiiError> {\n try {\n const certPem = this.extractCertificate(this.load(base64));\n if (!certPem) {\n return err(\n new DgiiError('Certificate not found in PKCS#12', {\n code: 'CERTIFICATE',\n }),\n );\n }\n return ok(this.toCertificateInfo(certPem));\n } catch (error) {\n return err(\n new DgiiError(\n `Unable to extract certificate info: ${asErrorMessage(error)}`,\n { code: 'CERTIFICATE', cause: error },\n ),\n );\n }\n }\n}\n","import crypto from 'node:crypto';\nimport { DOMParser } from '@xmldom/xmldom';\nimport { SignedXml } from 'xml-crypto';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\nexport type DgiiDocumentType =\n 'SemillaModel' | 'ECF' | 'RFCE' | 'ARECF' | 'ACECF' | 'ANECF' | (string & {});\n\nconst C14N_INCLUSIVE = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';\nconst RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';\nconst SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256';\nconst ENVELOPED = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature';\n/**\n * DGII's .NET stack hashes the document with the root element's `xmlns`\n * attributes sorted. xml-crypto's built-in SHA-256 does not, so we register\n * a custom digest under this private URI.\n */\nconst CUSTOM_DIGEST_URI = 'http://dgii.gov.do/digest/sha256-sorted';\n\ninterface XmldomDocument extends Document {\n childNodes: NodeListOf<ChildNode>;\n}\n\n/**\n * DGII-compatible digest: sort the root element attributes (fixes\n * `xmlns:xsd`/`xmlns:xsi` ordering) before hashing with SHA-256.\n */\nclass DgiiDigest {\n private static sortAttributes(attributes: NamedNodeMap): Attr[] {\n return Array.from(attributes).sort((a, b) => {\n const left = `${a.name}=\"${a.value}\"`;\n const right = `${b.name}=\"${b.value}\"`;\n return left < right ? -1 : left > right ? 1 : 0;\n });\n }\n\n getHash(xml: string): string {\n const doc = new DOMParser().parseFromString(\n xml,\n ) as unknown as XmldomDocument;\n const root = doc.childNodes[0] as unknown as Element | undefined;\n if (root?.attributes) {\n const sorted = DgiiDigest.sortAttributes(root.attributes as NamedNodeMap);\n Object.assign(root.attributes, sorted);\n }\n return crypto\n .createHash('sha256')\n .update(doc.toString(), 'utf8')\n .digest('base64');\n }\n\n getAlgorithmName(): string {\n return SHA256;\n }\n}\n\ninterface StrictParseResult {\n doc: XmldomDocument;\n rootName: string;\n}\n\nconst parseStrict = (xml: string): StrictParseResult => {\n const errors: string[] = [];\n const doc = new DOMParser({\n errorHandler: {\n warning: () => undefined,\n error: (message: string) => errors.push(message),\n fatalError: (message: string) => errors.push(message),\n },\n }).parseFromString(xml, 'text/xml') as unknown as XmldomDocument;\n\n if (errors.length) {\n throw new Error(`Invalid XML: ${errors.join('; ')}`);\n }\n const root = doc.documentElement;\n if (!root) {\n throw new Error('Unable to parse XML or find root element');\n }\n if (root.nodeName === 'parsererror' || root.localName === 'parsererror') {\n throw new Error(`Invalid XML: ${root.textContent ?? 'parse error'}`);\n }\n return {\n doc,\n rootName: root.localName ?? root.nodeName,\n };\n};\n\n/** Remove whitespace-only text nodes and comments before canonicalization. */\nconst cleanNodes = (node: Node): void => {\n for (let index = 0; index < node.childNodes.length; index += 1) {\n const child = node.childNodes[index];\n if (!child) {\n continue;\n }\n const isComment = child.nodeType === 8;\n const isWhitespace =\n child.nodeType === 3 && !/\\S/.test(child.nodeValue ?? '');\n if (isComment || isWhitespace) {\n node.removeChild(child);\n index -= 1;\n } else if (child.nodeType === 1) {\n cleanNodes(child);\n }\n }\n};\n\n/** Signs DGII XML documents with XMLDSig (enveloped, inclusive C14N, RSA-SHA256). */\nexport class Signature {\n constructor(\n private readonly privateKey: string,\n private readonly certificatePem: string,\n ) {}\n\n signXml(\n xml: string,\n rootElName?: DgiiDocumentType,\n ): Result<string, DgiiError> {\n try {\n const { doc, rootName } = parseStrict(xml);\n const elementName = rootElName ?? rootName;\n\n const sig = new SignedXml({\n privateKey: this.privateKey,\n publicCert: this.certificatePem,\n signatureAlgorithm: RSA_SHA256,\n canonicalizationAlgorithm: C14N_INCLUSIVE,\n });\n\n const hashAlgorithms = (\n sig as unknown as {\n HashAlgorithms: Record<string, unknown>;\n }\n ).HashAlgorithms;\n hashAlgorithms[CUSTOM_DIGEST_URI] = DgiiDigest;\n\n sig.addReference({\n xpath: `//*[local-name(.)='${elementName}']`,\n transforms: [ENVELOPED],\n digestAlgorithm: CUSTOM_DIGEST_URI,\n isEmptyUri: true,\n } as unknown as Parameters<SignedXml['addReference']>[0]);\n\n cleanNodes(doc as unknown as Node);\n sig.computeSignature(doc.toString());\n return ok(sig.getSignedXml());\n } catch (error) {\n return err(\n new DgiiError(\n `Failed to sign XML: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'SIGNING', cause: error },\n ),\n );\n }\n }\n}\n\nexport interface XmlCertificateValidation {\n isValid: boolean;\n subject?: string;\n issuer?: string;\n validFrom?: string;\n validTo?: string;\n error?: string;\n}\n\n/** Validate the embedded X509 certificate of a signed XML document. */\nexport const validateXMLCertificate = (\n xml: string,\n): XmlCertificateValidation => {\n try {\n const match = xml.match(/<X509Certificate>([\\s\\S]*?)<\\/X509Certificate>/);\n if (!match?.[1]) {\n return { isValid: false, error: 'X509Certificate not found' };\n }\n const der = Buffer.from(match[1].replace(/\\s+/g, ''), 'base64');\n const certificate = new crypto.X509Certificate(der);\n const notBefore = new Date(certificate.validFrom).getTime();\n const notAfter = new Date(certificate.validTo).getTime();\n const now = Date.now();\n const isValid = now >= notBefore && now <= notAfter;\n return {\n isValid,\n subject: certificate.subject,\n issuer: certificate.issuer,\n validFrom: certificate.validFrom,\n validTo: certificate.validTo,\n error: isValid ? undefined : 'Certificate expired or not yet valid',\n };\n } catch (error) {\n return {\n isValid: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n};\n","import convert from 'xml-js';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\n/**\n * Converts between the DGII XML documents and the \"compact\" JSON shape used by\n * `xml-js` (a dict key is an element, an array is a repeated element, and\n * `_attributes` / `_text` carry attributes and text).\n */\nexport class Transformer {\n json2xml(dataObject: object, round = false): Result<string, DgiiError> {\n try {\n const data: Record<string, unknown> = {\n _declaration: { _attributes: { version: '1.0', encoding: 'utf-8' } },\n ...dataObject,\n };\n\n const xml = convert.js2xml(data as convert.ElementCompact, {\n compact: true,\n ignoreComment: true,\n spaces: 2,\n fullTagEmptyElement: true,\n textFn: (value: string, label: string) => {\n const omits = ['version'];\n if (\n /^\\d+\\.\\d+$/.test(value) &&\n round &&\n !omits.includes(label.toLowerCase())\n ) {\n return parseFloat(value).toFixed(2);\n }\n return value;\n },\n });\n\n return ok(xml);\n } catch (error) {\n return err(\n new DgiiError(\n `Error converting JSON to XML: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n }\n\n xml2json<T>(xml: string): Result<T, DgiiError> {\n try {\n const json = convert.xml2js(xml, {\n compact: true,\n ignoreComment: true,\n nativeType: false,\n });\n return ok(json as T);\n } catch (error) {\n return err(\n new DgiiError(\n `Error converting XML to JSON: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n }\n}\n","import { BaseUrl, Environment } from './environment.js';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\nimport { Transformer } from './transformer.js';\n\n/** First 6 chars of the `<SignatureValue>` (DGII security code). */\nexport const getCodeSixDigitfromSignature = (\n signedXml: string,\n): Result<string, DgiiError> => {\n const match = signedXml.match(/<SignatureValue>([\\s\\S]*?)<\\/SignatureValue>/);\n const value = match?.[1]?.trim();\n if (!value) {\n return err(new DgiiError('SignatureValue not found', { code: 'SIGNING' }));\n }\n if (value.length < 6) {\n return err(\n new DgiiError('SignatureValue is too short', { code: 'SIGNING' }),\n );\n }\n return ok(value.slice(0, 6));\n};\n\n/** QR URL for a factura de consumo (FC). */\nexport const generateFcQRCodeURL = (\n rncemisor: string,\n encf: string,\n montototal: number,\n codigoseguridad: string,\n env: Environment,\n): string =>\n `${BaseUrl.CF}/${env.toLowerCase()}/consultatimbrefc?rncemisor=${encodeURIComponent(\n rncemisor,\n )}&encf=${encodeURIComponent(encf)}&montototal=${encodeURIComponent(\n String(montototal),\n )}&codigoseguridad=${encodeURIComponent(codigoseguridad)}`;\n\n/** QR URL for a crédito fiscal (e-CF). */\nexport const generateEcfQRCodeURL = (\n rncemisor: string,\n rncComprador: string,\n encf: string,\n montototal: string,\n fechaEmision: string,\n fechaFirma: string,\n codigoseguridad: string,\n env: Environment,\n): string => {\n let rncCompradorParam = '';\n if (rncComprador && !/E43/i.test(encf) && !/E47/i.test(encf)) {\n rncCompradorParam = `RncComprador=${encodeURIComponent(rncComprador)}&`;\n }\n return `${BaseUrl.ECF}/${env.toLowerCase()}/consultatimbre?rncemisor=${encodeURIComponent(\n rncemisor,\n )}&${rncCompradorParam}encf=${encodeURIComponent(\n encf,\n )}&fechaemision=${encodeURIComponent(\n fechaEmision,\n )}&montototal=${encodeURIComponent(\n montototal,\n )}&fechafirma=${encodeURIComponent(\n fechaFirma,\n )}&codigoseguridad=${encodeURIComponent(codigoseguridad)}`;\n};\n\nconst formatInSantoDomingo = (date: Date, withTime: boolean): string => {\n const parts = new Intl.DateTimeFormat('es-DO', {\n timeZone: 'America/Santo_Domingo',\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n ...(withTime\n ? { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }\n : {}),\n })\n .formatToParts(date)\n .reduce<Record<string, string>>((acc, part) => {\n acc[part.type] = part.value;\n return acc;\n }, {});\n\n const datePart = `${parts.day}-${parts.month}-${parts.year}`;\n return withTime\n ? `${datePart} ${parts.hour}:${parts.minute}:${parts.second}`\n : datePart;\n};\n\n/** `DD-MM-YYYY HH:mm:ss` in America/Santo_Domingo. */\nexport const getCurrentFormattedDateTime = (date: Date = new Date()): string =>\n formatInSantoDomingo(date, true);\n\n/** `DD-MM-YYYY` in America/Santo_Domingo. */\nexport const getCurrentFormattedDate = (date: Date = new Date()): string =>\n formatInSantoDomingo(date, false);\n\n/** Extract the XML payload embedded in a DGII commercial-approval body. */\nexport const getXmlFromBodyResponse = (\n body: string,\n lastTagName = 'ACECF',\n): string | undefined =>\n body.match(new RegExp(`<\\\\?xml[\\\\s\\\\S]*?<\\\\/${lastTagName}>`))?.[0];\n\ninterface CompactElement {\n _text?: string;\n [key: string]: unknown;\n}\n\ninterface ImpuestoAdicional {\n TipoImpuesto?: CompactElement;\n MontoImpuestoSelectivoConsumoEspecifico?: CompactElement;\n MontoImpuestoSelectivoConsumoAdvalorem?: CompactElement;\n OtrosImpuestosAdicionales?: CompactElement;\n}\n\ninterface EcfTotales {\n MontoGravadoTotal?: CompactElement;\n MontoGravadoI1?: CompactElement;\n MontoGravadoI2?: CompactElement;\n MontoGravadoI3?: CompactElement;\n MontoExento?: CompactElement;\n TotalITBIS?: CompactElement;\n TotalITBIS1?: CompactElement;\n TotalITBIS2?: CompactElement;\n TotalITBIS3?: CompactElement;\n MontoImpuestoAdicional?: CompactElement;\n ImpuestosAdicionales?: {\n ImpuestoAdicional?: ImpuestoAdicional | ImpuestoAdicional[];\n };\n MontoTotal?: CompactElement;\n MontoNoFacturable?: CompactElement;\n MontoPeriodo?: CompactElement;\n}\n\ninterface EcfJson {\n ECF: {\n Encabezado?: {\n Version?: CompactElement;\n IdDoc?: {\n TipoeCF?: CompactElement;\n eNCF?: CompactElement;\n TipoIngresos?: CompactElement;\n TipoPago?: CompactElement;\n TablaFormasPago?: CompactElement;\n };\n Emisor?: {\n RNCEmisor?: CompactElement;\n RazonSocialEmisor?: CompactElement;\n FechaEmision?: CompactElement;\n };\n Comprador?: {\n RNCComprador?: CompactElement;\n IdentificadorExtranjero?: CompactElement;\n RazonSocialComprador?: CompactElement;\n };\n Totales?: EcfTotales;\n };\n };\n}\n\nconst toArray = <T>(value: T | T[] | undefined | null): T[] => {\n if (value === undefined || value === null) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n};\n\nconst isEmptyObject = (value: unknown): boolean =>\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n Object.keys(value as Record<string, unknown>).length === 0;\n\nconst removeEmptyValues = (input: unknown): unknown => {\n if (input === null || input === undefined || input === '') {\n return undefined;\n }\n if (Array.isArray(input)) {\n const filtered = input\n .map(removeEmptyValues)\n .filter(\n (item) =>\n item !== null &&\n item !== undefined &&\n item !== '' &&\n !isEmptyObject(item),\n );\n return filtered.length ? filtered : undefined;\n }\n if (typeof input === 'object') {\n const output: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(\n input as Record<string, unknown>,\n )) {\n const cleaned = removeEmptyValues(value);\n if (cleaned !== undefined && cleaned !== '' && !isEmptyObject(cleaned)) {\n output[key] = cleaned;\n }\n }\n return Object.keys(output).length ? output : undefined;\n }\n return input;\n};\n\n/**\n * Build the RFCE (summary invoice) document from a signed ECF-32 document.\n * Returns the unsigned RFCE XML plus the 6-digit security code.\n */\nexport const convertECF32ToRFCE = (\n ecf32Xml: string,\n): Result<{ xml: string; securityCode: string }, DgiiError> => {\n const securityCode = getCodeSixDigitfromSignature(ecf32Xml);\n if (securityCode.isErr()) {\n return err(securityCode.error);\n }\n\n const transformer = new Transformer();\n const parsed = transformer.xml2json<EcfJson>(ecf32Xml);\n if (parsed.isErr()) {\n return err(parsed.error);\n }\n\n const encabezado = parsed.value.ECF.Encabezado;\n const impuestos = toArray(\n encabezado?.Totales?.ImpuestosAdicionales?.ImpuestoAdicional,\n );\n\n const rfce = removeEmptyValues({\n RFCE: {\n Encabezado: {\n Version: encabezado?.Version,\n IdDoc: {\n TipoeCF: encabezado?.IdDoc?.TipoeCF,\n eNCF: encabezado?.IdDoc?.eNCF,\n TipoIngresos: encabezado?.IdDoc?.TipoIngresos,\n TipoPago: encabezado?.IdDoc?.TipoPago,\n TablaFormasPago: encabezado?.IdDoc?.TablaFormasPago,\n },\n Emisor: {\n RNCEmisor: encabezado?.Emisor?.RNCEmisor,\n RazonSocialEmisor: encabezado?.Emisor?.RazonSocialEmisor,\n FechaEmision: encabezado?.Emisor?.FechaEmision,\n },\n Comprador: {\n RNCComprador: encabezado?.Comprador?.RNCComprador,\n IdentificadorExtranjero:\n encabezado?.Comprador?.IdentificadorExtranjero,\n RazonSocialComprador: encabezado?.Comprador?.RazonSocialComprador,\n },\n Totales: {\n MontoGravadoTotal: encabezado?.Totales?.MontoGravadoTotal,\n MontoGravadoI1: encabezado?.Totales?.MontoGravadoI1,\n MontoGravadoI2: encabezado?.Totales?.MontoGravadoI2,\n MontoGravadoI3: encabezado?.Totales?.MontoGravadoI3,\n MontoExento: encabezado?.Totales?.MontoExento,\n TotalITBIS: encabezado?.Totales?.TotalITBIS,\n TotalITBIS1: encabezado?.Totales?.TotalITBIS1,\n TotalITBIS2: encabezado?.Totales?.TotalITBIS2,\n TotalITBIS3: encabezado?.Totales?.TotalITBIS3,\n MontoImpuestoAdicional: encabezado?.Totales?.MontoImpuestoAdicional,\n ImpuestosAdicionales: {\n ImpuestoAdicional: impuestos.map((impuesto) => ({\n TipoImpuesto: impuesto.TipoImpuesto,\n MontoImpuestoSelectivoConsumoEspecifico:\n impuesto.MontoImpuestoSelectivoConsumoEspecifico,\n MontoImpuestoSelectivoConsumoAdvalorem:\n impuesto.MontoImpuestoSelectivoConsumoAdvalorem,\n OtrosImpuestosAdicionales: impuesto.OtrosImpuestosAdicionales,\n })),\n },\n MontoTotal: encabezado?.Totales?.MontoTotal,\n MontoNoFacturable: encabezado?.Totales?.MontoNoFacturable,\n MontoPeriodo: encabezado?.Totales?.MontoPeriodo,\n },\n CodigoSeguridadeCF: securityCode.value,\n },\n },\n });\n\n if (typeof rfce !== 'object' || rfce === null) {\n return err(\n new DgiiError('Unable to build RFCE document', { code: 'VALIDATION' }),\n );\n }\n\n const xml = transformer.json2xml(rfce);\n if (xml.isErr()) {\n return err(xml.error);\n }\n\n return ok({ xml: xml.value, securityCode: securityCode.value });\n};\n","import { createHash } from 'node:crypto';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\nimport {\n BaseUrl,\n Endpoint,\n Environment,\n SenderReceiverEndpoint,\n buildSenderReceiverUrl,\n buildUrl,\n} from './environment.js';\nimport {\n HttpClient,\n InMemoryIdempotencyStore,\n type IdempotencyStore,\n} from './http.js';\nimport type { ResilienceOptions } from './resilience.js';\nimport { Signature } from './signing.js';\nimport type { P12ReaderData } from './certificate.js';\nimport type {\n AuthToken,\n CommercialApprovalResponse,\n InquiryInvoiceSummary,\n InquiryStatusResponse,\n InvoiceResponse,\n InvoiceSummaryResponse,\n ServiceDirectoryResponse,\n SummaryTrackingStatusResponse,\n TrackingStatusResponse,\n VoidNCFResponse,\n} from './types.js';\n\nexport interface EcfOptions {\n /** Pre-existing bearer token (skips the authentication round-trip). */\n token?: string;\n /** Pluggable idempotency store; defaults to an in-memory store. */\n idempotencyStore?: IdempotencyStore;\n resilience?: ResilienceOptions;\n timeoutMs?: number;\n /** Injectable fetch (useful for tests). */\n fetchImpl?: typeof fetch;\n}\n\nconst sha256Hex = (value: string): string =>\n createHash('sha256').update(value, 'utf8').digest('hex');\n\nconst extractTag = (xml: string, tag: string): string | undefined => {\n const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));\n return match?.[1]?.trim();\n};\n\n/**\n * DGII e-CF client. Every method returns a `Result` — no thrown domain errors.\n */\nexport class ECF {\n private readonly environment: Environment;\n private readonly http: HttpClient;\n private readonly idempotency: IdempotencyStore;\n private readonly credentials: P12ReaderData;\n private readonly inFlight = new Map<\n string,\n Promise<Result<unknown, DgiiError>>\n >();\n\n constructor(\n credentials: P12ReaderData,\n environment: Environment = Environment.Dev,\n options: EcfOptions = {},\n ) {\n this.credentials = credentials;\n this.environment = environment;\n this.idempotency =\n options.idempotencyStore ?? new InMemoryIdempotencyStore();\n this.http = new HttpClient({\n baseUrl: BaseUrl.ECF,\n ...(options.token !== undefined ? { token: options.token } : {}),\n ...(options.resilience !== undefined\n ? { resilience: options.resilience }\n : {}),\n ...(options.timeoutMs !== undefined\n ? { timeoutMs: options.timeoutMs }\n : {}),\n ...(options.fetchImpl !== undefined\n ? { fetchImpl: options.fetchImpl }\n : {}),\n });\n }\n\n private buildIdempotencyKey(signedXml: string): string {\n const rnc = extractTag(signedXml, 'RNCEmisor') ?? 'unknown-rnc';\n const encf = extractTag(signedXml, 'eNCF') ?? 'unknown-encf';\n return `${rnc}:${encf}:${sha256Hex(signedXml)}`;\n }\n\n private async singleFlight<T>(\n key: string,\n task: () => Promise<Result<T, DgiiError>>,\n ): Promise<Result<T, DgiiError>> {\n const existing = this.inFlight.get(key);\n if (existing) {\n return existing as Promise<Result<T, DgiiError>>;\n }\n const promise = task();\n this.inFlight.set(key, promise as Promise<Result<unknown, DgiiError>>);\n try {\n return await promise;\n } finally {\n this.inFlight.delete(key);\n }\n }\n\n /** Authenticate against DGII (or a buyer host) and store the bearer token. */\n async authenticate(\n buyerHost?: string,\n ): Promise<Result<AuthToken, DgiiError>> {\n const seed = await this.getSeed(buyerHost);\n if (seed.isErr()) {\n return err(seed.error);\n }\n if (\n typeof this.credentials.key !== 'string' ||\n typeof this.credentials.cert !== 'string'\n ) {\n return err(\n new DgiiError(\n 'A private key and certificate PEM are required to authenticate',\n { code: 'CERTIFICATE' },\n ),\n );\n }\n\n const signed = new Signature(\n this.credentials.key,\n this.credentials.cert,\n ).signXml(seed.value, 'SemillaModel');\n if (signed.isErr()) {\n return err(signed.error);\n }\n\n const token = await this.getAuthToken(signed.value, buyerHost);\n if (token.isErr()) {\n return err(token.error);\n }\n this.http.setToken(token.value.token);\n return ok(token.value);\n }\n\n private getSeed(buyerHost?: string): Promise<Result<string, DgiiError>> {\n if (buyerHost) {\n const url = buildSenderReceiverUrl(\n buyerHost,\n SenderReceiverEndpoint.Seed,\n );\n return this.http.get<string>(url, undefined, {\n absoluteUrl: true,\n resource: SenderReceiverEndpoint.Seed,\n });\n }\n const url = buildUrl(this.environment, Endpoint.Seed);\n return this.http.get<string>(url, undefined, {\n absoluteUrl: true,\n resource: Endpoint.Seed,\n });\n }\n\n private getAuthToken(\n signedSeed: string,\n buyerHost?: string,\n ): Promise<Result<AuthToken, DgiiError>> {\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.ValidateSeed)\n : buildUrl(this.environment, Endpoint.ValidateSeed);\n return this.http.postMultipart<AuthToken>(url, 'signed.xml', signedSeed, {\n absoluteUrl: true,\n resource: Endpoint.ValidateSeed,\n });\n }\n\n /**\n * Submit a signed e-CF. Idempotent on `RNC + eNCF + SHA-256(signed XML)`:\n * a repeated call returns the cached response instead of double-issuing.\n */\n async sendElectronicDocument(\n signedXml: string,\n fileName: string,\n buyerHost?: string,\n ): Promise<Result<InvoiceResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n const cached = await this.idempotency.get<InvoiceResponse>(key);\n if (cached) {\n return ok(cached);\n }\n return this.singleFlight(key, async () => {\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.SendInvoice)\n : buildUrl(this.environment, Endpoint.SendInvoice);\n const result = await this.http.postMultipart<InvoiceResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendInvoice },\n );\n if (result.isOk()) {\n await this.idempotency.set(key, result.value);\n }\n return result;\n });\n }\n\n /** Submit a signed summary invoice (RFCE). Idempotent like submissions. */\n async sendSummary(\n signedXml: string,\n fileName: string,\n ): Promise<Result<InvoiceSummaryResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n const cached = await this.idempotency.get<InvoiceSummaryResponse>(key);\n if (cached) {\n return ok(cached);\n }\n return this.singleFlight(key, async () => {\n const url = buildUrl(this.environment, Endpoint.SendSummary, BaseUrl.CF);\n const result = await this.http.postMultipart<InvoiceSummaryResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendSummary },\n );\n if (result.isOk()) {\n await this.idempotency.set(key, result.value);\n }\n return result;\n });\n }\n\n statusTrackId(\n trackId: string,\n ): Promise<Result<TrackingStatusResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.TrackResultStatus);\n return this.http.get<TrackingStatusResponse>(\n url,\n { trackId },\n { absoluteUrl: true, resource: Endpoint.TrackResultStatus },\n );\n }\n\n inquiryStatus(\n rncEmisor: string,\n ncfElectronico: string,\n rncComprador?: string,\n codigoSeguridad?: string,\n ): Promise<Result<InquiryStatusResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.InquiryStatus);\n return this.http.get<InquiryStatusResponse>(\n url,\n { rncEmisor, ncfElectronico, rncComprador, codigoSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryStatus },\n );\n }\n\n trackStatuses(\n rncEmisor: string,\n encf: string,\n ): Promise<Result<SummaryTrackingStatusResponse[], DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.AllTrackingEcf);\n return this.http.get<SummaryTrackingStatusResponse[]>(\n url,\n { rncEmisor, encf },\n { absoluteUrl: true, resource: Endpoint.AllTrackingEcf },\n );\n }\n\n /** Normalizes DGII's inconsistent (array | single object) directory payload. */\n async getCustomerDirectory(\n rnc: string,\n ): Promise<Result<ServiceDirectoryResponse[] | undefined, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Directory);\n const result = await this.http.get<\n ServiceDirectoryResponse[] | ServiceDirectoryResponse\n >(url, { rnc }, { absoluteUrl: true, resource: Endpoint.Directory });\n if (result.isErr()) {\n return err(result.error);\n }\n const data = result.value;\n if (data === undefined || data === null) {\n return ok(undefined);\n }\n return ok(Array.isArray(data) ? data : [data]);\n }\n\n /** RFCE inquiry — DGII production only. */\n getSummaryInvoiceInquiry(\n rnc: string,\n encf: string,\n codSeguridad: string,\n ): Promise<Result<InquiryInvoiceSummary, DgiiError>> {\n const url = buildUrl(\n this.environment,\n Endpoint.InquiryInvoiceSummary,\n BaseUrl.CF,\n );\n return this.http.get<InquiryInvoiceSummary>(\n url,\n { rnc_emisor: rnc, encf, cod_seguridad_eCF: codSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryInvoiceSummary },\n );\n }\n\n sendCommercialApproval(\n signedXml: string,\n fileName: string,\n ): Promise<Result<CommercialApprovalResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.CommercialApproval);\n return this.http.postMultipart<CommercialApprovalResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.CommercialApproval },\n );\n }\n\n voidENCF(\n signedXml: string,\n fileName: string,\n ): Promise<Result<VoidNCFResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Void);\n return this.http.postMultipart<VoidNCFResponse>(url, fileName, signedXml, {\n absoluteUrl: true,\n resource: Endpoint.Void,\n });\n }\n}\n"],"mappings":"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","names":["Environment","Endpoint","SenderReceiverEndpoint","TrackStatusEnum","err","url"]}
|
|
1
|
+
{"version":3,"sources":["../src/environment.ts","../src/types.ts","../src/errors.ts","../src/result.ts","../src/resilience.ts","../src/http.ts","../src/certificate.ts","../src/signing.ts","../src/transformer.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["export enum Environment {\n /** DGII test environment */\n Dev = 'TesteCF',\n /** DGII certification environment */\n Cert = 'CerteCF',\n /** DGII production environment */\n Prod = 'eCF',\n}\n\nexport const BaseUrl = {\n /** Crédito fiscal / general e-CF services */\n ECF: 'https://ecf.dgii.gov.do',\n /** Factura de consumo (< DOP 250,000) */\n CF: 'https://fc.dgii.gov.do',\n /** DGII service status */\n STATUS: 'https://statusecf.dgii.gov.do',\n} as const;\n\nexport type BaseUrlKey = keyof typeof BaseUrl;\n\nexport enum Endpoint {\n Seed = 'Autenticacion/api/Autenticacion/Semilla',\n ValidateSeed = 'autenticacion/api/Autenticacion/ValidarSemilla',\n SendInvoice = 'recepcion/api/FacturasElectronicas',\n SendSummary = 'recepcionfc/api/recepcion/ecf',\n InquiryInvoiceSummary = 'consultarfce/api/Consultas/Consulta',\n CommercialApproval = 'aprobacionComercial/api/AprobacionComercial',\n TrackResultStatus = 'consultaresultado/api/Consultas/Estado',\n InquiryStatus = 'consultaestado/api/Consultas/Estado',\n AllTrackingEcf = 'ConsultaTrackIds/api/TrackIds/Consulta',\n Directory = 'consultadirectorio/api/consultas/obtenerdirectorioporrnc',\n Void = 'anulacionrangos/api/operaciones/anularrango',\n}\n\n/** Endpoints used when talking to a buyer's Sender↔Receiver host. */\nexport enum SenderReceiverEndpoint {\n Seed = 'fe/autenticacion/api/semilla',\n ValidateSeed = 'fe/autenticacion/api/validacioncertificado',\n SendInvoice = 'fe/recepcion/api/ecf',\n CommercialApproval = 'fe/aprobacioncomercial/api/ecf',\n}\n\n/** Build an absolute DGII URL: `${baseUrl}/${environment}/${endpoint}`. */\nexport const buildUrl = (\n environment: Environment,\n endpoint: Endpoint,\n baseUrl: string = BaseUrl.ECF,\n): string => `${baseUrl.replace(/\\/+$/, '')}/${environment}/${endpoint}`;\n\n/** Build an absolute Sender↔Receiver URL against a buyer host. */\nexport const buildSenderReceiverUrl = (\n host: string,\n endpoint: SenderReceiverEndpoint,\n): string => `${host.replace(/\\/+$/, '')}/${endpoint}`;\n","export interface Mensaje {\n valor: string;\n codigo: number;\n}\n\nexport interface AuthToken {\n token: string;\n expira: string;\n expedido: string;\n}\n\nexport enum TrackStatusEnum {\n NotFound = 'No encontrado',\n Accepted = 'Aceptado',\n Rejected = 'Rechazado',\n InProcess = 'En Proceso',\n ConditionalAccepted = 'Aceptado Condicional',\n}\n\nexport type TrackStatusCode = 0 | 1 | 2 | 3 | 4;\n\nexport interface TrackingStatusResponse {\n trackId: string;\n codigo: TrackStatusCode;\n estado: TrackStatusEnum;\n rnc: string;\n encf: string;\n secuenciaUtilizada: boolean;\n fechaRecepcion: string;\n mensajes?: Mensaje[];\n}\n\nexport type InquiryStatusCode = 0 | 1 | 2;\n\nexport type InquiryStatus = 'No encontrado' | 'Aceptado' | 'Rechazado';\n\nexport interface InquiryStatusResponse {\n codigo: InquiryStatusCode;\n estado: InquiryStatus;\n rncEmisor?: string;\n ncfElectronico?: string;\n montoTotal?: number;\n totalITBIS?: number;\n fechaEmision?: string;\n fechaFirma?: string;\n rncComprador?: string;\n codigoSeguridad?: string;\n idExtranjero?: string;\n}\n\nexport interface SummaryTrackingStatusResponse {\n trackId: string;\n estado: string;\n fechaRecepcion: string;\n}\n\nexport interface InvoiceResponse {\n trackId?: string;\n error?: string;\n mensajes?: Mensaje[];\n}\n\nexport interface InvoiceSummaryResponse {\n codigo: number;\n estado: 'Aceptado' | 'Rechazado' | 'Aceptado Condicional';\n mensajes?: Mensaje[];\n encf: string;\n secuenciaUtilizada: boolean;\n}\n\nexport interface ServiceDirectoryResponse {\n nombre: string;\n rnc: string;\n urlRecepcion: string;\n urlAceptacion: string;\n urlOpcional: string;\n}\n\nexport interface InquiryInvoiceSummary {\n rnc: string;\n encf: string;\n secuenciaUtilizada: boolean;\n codigo: InquiryStatusCode;\n estado: InquiryStatus;\n mensajes?: Mensaje[];\n}\n\nexport interface CommercialApprovalResponse {\n codigo: '01' | '02';\n estado: 'Aprobación Comercial Aprobada.' | 'Aprobacion Comercial Rechazada.';\n mensaje: string[];\n}\n\nexport interface VoidNCFResponse {\n rnc: string;\n codigo: string;\n nombre: string;\n mensajes: string[];\n}\n","import type { Mensaje } from './types.js';\n\nexport type DgiiErrorCode =\n | 'INVALID_XML'\n | 'CERTIFICATE'\n | 'SIGNING'\n | 'HTTP'\n | 'AUTH'\n | 'TIMEOUT'\n | 'CIRCUIT_OPEN'\n | 'IDEMPOTENCY'\n | 'VALIDATION'\n | 'UNKNOWN';\n\nconst RETRYABLE_STATUSES = new Set<number>([408, 429, 500, 502, 503, 504]);\n\nexport const isRetryableStatus = (status: number | undefined): boolean =>\n status !== undefined && RETRYABLE_STATUSES.has(status);\n\nexport interface DgiiErrorOptions {\n code?: DgiiErrorCode;\n status?: number;\n statusText?: string;\n resource?: string;\n method?: string;\n baseURL?: string;\n data?: unknown;\n mensajes?: Mensaje[];\n retryable?: boolean;\n cause?: unknown;\n}\n\nconst MAX_RAW = 1000;\n\nconst truncate = (value: string): string =>\n value.length > MAX_RAW ? `${value.slice(0, MAX_RAW)}…` : value;\n\nconst collapseWhitespace = (value: string): string =>\n value.replace(/\\s+/g, ' ').trim();\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst looksLikeHtml = (value: string): boolean =>\n /^\\s*<(?:!doctype|html|body|head)\\b/i.test(value);\n\nconst stripHtml = (value: string): string =>\n collapseWhitespace(\n value\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<[^>]+>/g, ' '),\n );\n\nconst readMensajes = (value: unknown): Mensaje[] | undefined => {\n if (!Array.isArray(value) || value.length === 0) {\n return undefined;\n }\n const out: Mensaje[] = [];\n for (const item of value) {\n if (typeof item === 'string' && item.trim()) {\n out.push({ valor: item.trim(), codigo: 0 });\n } else if (isObject(item) && typeof item.valor === 'string') {\n out.push({\n valor: item.valor,\n codigo: typeof item.codigo === 'number' ? item.codigo : 0,\n });\n }\n }\n return out.length ? out : undefined;\n};\n\nconst MESSAGE_KEYS = [\n 'mensaje',\n 'Mensaje',\n 'message',\n 'Message',\n 'error',\n 'Error',\n 'errorMessage',\n 'error_description',\n 'detail',\n 'Detail',\n 'title',\n 'Title',\n 'descripcion',\n 'Descripcion',\n];\n\n/**\n * Reduce DGII's inconsistent error payloads (bare string, `{ mensajes }`,\n * ASP.NET ProblemDetails/ModelState, or an HTML page) to a single message.\n */\nexport const extractDgiiErrorMessage = (\n data: unknown,\n seen: WeakSet<object> = new WeakSet<object>(),\n): string | undefined => {\n if (data === undefined || data === null) {\n return undefined;\n }\n\n if (typeof data === 'string') {\n const trimmed = data.trim();\n if (!trimmed) {\n return undefined;\n }\n if (/^[[{\"]/.test(trimmed)) {\n try {\n return extractDgiiErrorMessage(JSON.parse(trimmed), seen);\n } catch {\n // Not JSON after all — fall through to raw text.\n }\n }\n if (looksLikeHtml(trimmed)) {\n const text = stripHtml(trimmed);\n return text ? truncate(text) : undefined;\n }\n return truncate(collapseWhitespace(trimmed));\n }\n\n if (typeof data === 'number' || typeof data === 'boolean') {\n return String(data);\n }\n\n if (data instanceof Error) {\n return data.message || undefined;\n }\n\n if (Array.isArray(data)) {\n if (seen.has(data)) {\n return undefined;\n }\n seen.add(data);\n const parts = data\n .map((item) => extractDgiiErrorMessage(item, seen))\n .filter((item): item is string => Boolean(item));\n return parts.length ? truncate(parts.join(' | ')) : undefined;\n }\n\n if (isObject(data)) {\n if (seen.has(data)) {\n return undefined;\n }\n seen.add(data);\n\n const mensajes = readMensajes(data.mensajes ?? data.Mensajes);\n if (mensajes) {\n return truncate(mensajes.map((mensaje) => mensaje.valor).join(' | '));\n }\n\n for (const key of MESSAGE_KEYS) {\n const value = data[key];\n if (typeof value === 'string' && value.trim()) {\n return truncate(collapseWhitespace(value));\n }\n if (key === 'error' && (isObject(value) || Array.isArray(value))) {\n const nested = extractDgiiErrorMessage(value, seen);\n if (nested) {\n return nested;\n }\n }\n }\n\n const errors = data.errors ?? data.Errors;\n if (isObject(errors)) {\n const parts = Object.entries(errors)\n .map(([field, value]) => {\n const nested = extractDgiiErrorMessage(value, seen);\n return nested ? `${field}: ${nested}` : undefined;\n })\n .filter((item): item is string => Boolean(item));\n if (parts.length) {\n return truncate(parts.join(' | '));\n }\n } else if (errors) {\n const nested = extractDgiiErrorMessage(errors, seen);\n if (nested) {\n return nested;\n }\n }\n\n try {\n const serialized = JSON.stringify(data);\n if (serialized && serialized !== '{}') {\n return truncate(serialized);\n }\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n};\n\nexport class DgiiError extends Error {\n readonly code: DgiiErrorCode;\n readonly status?: number;\n readonly statusText?: string;\n readonly resource?: string;\n readonly method?: string;\n readonly baseURL?: string;\n readonly data?: unknown;\n readonly mensajes?: Mensaje[];\n readonly retryable: boolean;\n\n constructor(message: string, options: DgiiErrorOptions = {}) {\n super(message);\n this.name = 'DgiiError';\n Object.setPrototypeOf(this, DgiiError.prototype);\n\n this.code = options.code ?? 'UNKNOWN';\n this.status = options.status;\n this.statusText = options.statusText;\n this.resource = options.resource;\n this.method = options.method;\n this.baseURL = options.baseURL;\n this.data = options.data;\n this.mensajes = options.mensajes;\n this.retryable = options.retryable ?? isRetryableStatus(options.status);\n\n if (options.cause !== undefined) {\n Object.defineProperty(this, 'cause', {\n value: options.cause,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n }\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n status: this.status,\n statusText: this.statusText,\n resource: this.resource,\n method: this.method,\n mensajes: this.mensajes,\n data: this.data,\n };\n }\n}\n\nexport interface DgiiErrorContext {\n code?: DgiiErrorCode;\n status?: number;\n statusText?: string;\n resource?: string;\n method?: string;\n baseURL?: string;\n fallbackMessage?: string;\n}\n\n/** Normalize any thrown value into a {@link DgiiError}. */\nexport const toDgiiError = (\n err: unknown,\n context: DgiiErrorContext = {},\n): DgiiError => {\n if (err instanceof DgiiError) {\n return err;\n }\n\n if (err instanceof Error) {\n return new DgiiError(\n err.message || context.fallbackMessage || 'DGII request failed',\n {\n ...context,\n cause: err,\n },\n );\n }\n\n const message =\n extractDgiiErrorMessage(err) ||\n context.fallbackMessage ||\n 'DGII request failed';\n const status =\n isObject(err) && typeof err.status === 'number'\n ? err.status\n : context.status;\n\n return new DgiiError(message, {\n ...context,\n status,\n data: err,\n mensajes: isObject(err)\n ? readMensajes(err.mensajes ?? err.Mensajes)\n : undefined,\n cause: err,\n });\n};\n","import type { Result } from 'neverthrow';\nimport type { DgiiError } from './errors.js';\n\nexport type { Result } from 'neverthrow';\n\nexport {\n Ok,\n Err,\n ok,\n err,\n okAsync,\n errAsync,\n fromThrowable,\n fromPromise,\n fromSafePromise,\n ResultAsync,\n} from 'neverthrow';\n\n/** A {@link Result} whose failure channel is always {@link DgiiError}. */\nexport type DgiiResult<T> = Result<T, DgiiError>;\n","import {\n ConsecutiveBreaker,\n ExponentialBackoff,\n TimeoutStrategy,\n bulkhead,\n circuitBreaker,\n handleAll,\n handleWhen,\n retry,\n timeout,\n wrap,\n type IPolicy,\n} from 'cockatiel';\nimport { DgiiError } from './errors.js';\n\nexport interface ResilienceOptions {\n /** Maximum number of attempts (including the first). Default 3. */\n maxRetries?: number;\n /** Consecutive failures before the circuit opens. Default 5. */\n breakerThreshold?: number;\n /** Milliseconds the circuit stays open before half-opening. Default 30s. */\n halfOpenAfterMs?: number;\n /** Per-attempt timeout in milliseconds. Default 15s. */\n timeoutMs?: number;\n /** Initial retry backoff delay in milliseconds. Default 100. */\n retryInitialDelayMs?: number;\n /** Maximum concurrent in-flight requests. Default 20. */\n bulkheadLimit?: number;\n /** Maximum queued requests while the bulkhead is saturated. Default 40. */\n bulkheadQueue?: number;\n}\n\nexport const defaultResilienceOptions: Required<ResilienceOptions> = {\n maxRetries: 3,\n breakerThreshold: 5,\n halfOpenAfterMs: 30_000,\n timeoutMs: 15_000,\n retryInitialDelayMs: 100,\n bulkheadLimit: 20,\n bulkheadQueue: 40,\n};\n\n/**\n * Only transient failures are retried: network errors, timeouts, 408, 429 and\n * 5xx. A rejected e-CF (4xx) must never be blindly re-sent.\n */\nexport const isRetryableError = (error: unknown): boolean => {\n if (error instanceof DgiiError) {\n return error.retryable;\n }\n if (error instanceof Error) {\n const name = error.name.toLowerCase();\n const message = error.message.toLowerCase();\n return (\n name === 'typeerror' ||\n name === 'aborterror' ||\n name === 'fetcherror' ||\n name === 'timeouterror' ||\n name.includes('cancel') ||\n message.includes('timeout') ||\n message.includes('aborted') ||\n message.includes('network')\n );\n }\n return false;\n};\n\nexport interface ResiliencePolicies {\n readonly retry: IPolicy;\n readonly circuitBreaker: IPolicy;\n readonly timeout: IPolicy;\n readonly bulkhead: IPolicy;\n /** Composed policy: `retry → circuitBreaker → timeout → bulkhead`. */\n readonly policy: IPolicy;\n}\n\n/** Build the composed resilience policy used by the HTTP client. */\nexport const createResiliencePolicies = (\n options: ResilienceOptions = {},\n): ResiliencePolicies => {\n const opts = { ...defaultResilienceOptions, ...options };\n\n const retryPolicy = retry(handleWhen(isRetryableError), {\n maxAttempts: opts.maxRetries,\n backoff: new ExponentialBackoff({ initialDelay: opts.retryInitialDelayMs }),\n });\n\n const breakerPolicy = circuitBreaker(handleAll, {\n halfOpenAfter: opts.halfOpenAfterMs,\n breaker: new ConsecutiveBreaker(opts.breakerThreshold),\n });\n\n const timeoutPolicy = timeout(opts.timeoutMs, TimeoutStrategy.Aggressive);\n const bulkheadPolicy = bulkhead(opts.bulkheadLimit, opts.bulkheadQueue);\n\n const policy = wrap(\n retryPolicy,\n breakerPolicy,\n timeoutPolicy,\n bulkheadPolicy,\n );\n\n return {\n retry: retryPolicy,\n circuitBreaker: breakerPolicy,\n timeout: timeoutPolicy,\n bulkhead: bulkheadPolicy,\n policy,\n };\n};\n","import { err, ok, type Result } from './result.js';\nimport { DgiiError, extractDgiiErrorMessage, toDgiiError } from './errors.js';\nimport {\n createResiliencePolicies,\n type ResilienceOptions,\n type ResiliencePolicies,\n} from './resilience.js';\n\n/**\n * Pluggable idempotency store. Provide a Redis/Postgres-backed implementation\n * in production so a retried or duplicated submission never double-issues.\n */\nexport interface IdempotencyStore {\n get<T>(key: string): Promise<T | undefined>;\n set<T>(key: string, value: T): Promise<void>;\n delete(key: string): Promise<void>;\n}\n\n/** Process-local default. Fine for single-instance usage and tests. */\nexport class InMemoryIdempotencyStore implements IdempotencyStore {\n private readonly store = new Map<string, unknown>();\n\n async get<T>(key: string): Promise<T | undefined> {\n return this.store.get(key) as T | undefined;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.store.set(key, value);\n }\n\n async delete(key: string): Promise<void> {\n this.store.delete(key);\n }\n}\n\nexport interface HttpClientOptions {\n baseUrl: string;\n token?: string;\n resilience?: ResilienceOptions;\n policies?: ResiliencePolicies;\n timeoutMs?: number;\n fetchImpl?: typeof fetch;\n}\n\nexport interface RequestOptions {\n method?: 'GET' | 'POST';\n /** Absolute URL when `absoluteUrl` is true, otherwise a path appended to baseUrl. */\n path: string;\n absoluteUrl?: boolean;\n headers?: Record<string, string>;\n body?: BodyInit;\n query?: Record<string, string | number | undefined>;\n resource?: string;\n}\n\ninterface RequestContext {\n method: string;\n resource: string;\n baseURL: string;\n}\n\n/** Thin HTTP client over the native `fetch`, wrapped in resilience policies. */\nexport class HttpClient {\n private token?: string;\n private readonly policies: ResiliencePolicies;\n private readonly fetchImpl: typeof fetch;\n private readonly baseUrl: string;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/+$/, '');\n this.token = options.token;\n this.policies =\n options.policies ??\n createResiliencePolicies({\n ...options.resilience,\n ...(options.timeoutMs !== undefined\n ? { timeoutMs: options.timeoutMs }\n : {}),\n });\n this.fetchImpl = options.fetchImpl ?? fetch;\n }\n\n setToken(token: string): void {\n this.token = token;\n }\n\n clearToken(): void {\n this.token = undefined;\n }\n\n private buildUrl(\n path: string,\n absoluteUrl: boolean | undefined,\n query: RequestOptions['query'],\n ): string {\n let url = absoluteUrl\n ? path\n : `${this.baseUrl}${path.startsWith('/') ? '' : '/'}${path}`;\n\n if (query) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== '') {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) {\n url += (url.includes('?') ? '&' : '?') + qs;\n }\n }\n return url;\n }\n\n private authHeaders(extra?: Record<string, string>): Record<string, string> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (this.token) {\n headers.Authorization = `Bearer ${this.token}`;\n }\n return { ...headers, ...extra };\n }\n\n private async readBody(response: Response): Promise<unknown> {\n const contentType = response.headers.get('content-type') ?? '';\n try {\n if (contentType.includes('json')) {\n return await response.json();\n }\n const text = await response.text();\n return text.length ? text : undefined;\n } catch {\n return undefined;\n }\n }\n\n private async parseResponse<T>(\n response: Response,\n ctx: RequestContext,\n ): Promise<Result<T, DgiiError>> {\n const data = await this.readBody(response);\n\n if (response.ok) {\n return ok(data as T);\n }\n\n const message =\n extractDgiiErrorMessage(data) ??\n `DGII request failed with status ${response.status}`;\n const error = new DgiiError(message, {\n code: response.status === 401 ? 'AUTH' : 'HTTP',\n status: response.status,\n statusText: response.statusText,\n resource: ctx.resource,\n method: ctx.method,\n baseURL: ctx.baseURL,\n data,\n });\n\n // Throw retryable failures so the retry/breaker policies can act on them;\n // non-retryable client errors are returned as a typed failure.\n if (error.retryable) {\n throw error;\n }\n return err(error);\n }\n\n async request<T>(options: RequestOptions): Promise<Result<T, DgiiError>> {\n const url = this.buildUrl(options.path, options.absoluteUrl, options.query);\n const method = options.method ?? 'GET';\n const headers = this.authHeaders(options.headers);\n const ctx: RequestContext = {\n method,\n resource: options.resource ?? options.path,\n baseURL: this.baseUrl,\n };\n\n try {\n return await this.policies.policy.execute(async ({ signal }) => {\n const response = await this.fetchImpl(url, {\n method,\n headers,\n body: options.body,\n signal,\n });\n return this.parseResponse<T>(response, ctx);\n });\n } catch (error) {\n return err(toDgiiError(error, ctx));\n }\n }\n\n get<T>(\n path: string,\n query?: RequestOptions['query'],\n opts?: { absoluteUrl?: boolean; resource?: string },\n ): Promise<Result<T, DgiiError>> {\n return this.request<T>({\n method: 'GET',\n path,\n query,\n absoluteUrl: opts?.absoluteUrl,\n resource: opts?.resource,\n });\n }\n\n /**\n * POST a signed XML as a multipart `xml` file part. The runtime computes\n * `Content-Length` from the Blob — never set it manually.\n */\n postMultipart<T>(\n path: string,\n fileName: string,\n xml: string,\n opts?: { absoluteUrl?: boolean; resource?: string },\n ): Promise<Result<T, DgiiError>> {\n const form = new FormData();\n form.append('xml', new Blob([xml], { type: 'application/xml' }), fileName);\n return this.request<T>({\n method: 'POST',\n path,\n body: form,\n headers: { Accept: 'application/json' },\n absoluteUrl: opts?.absoluteUrl,\n resource: opts?.resource,\n });\n }\n}\n","import { readFileSync } from 'node:fs';\nimport forge from 'node-forge';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\nexport interface P12ReaderData {\n key?: string;\n cert?: string;\n publicKey?: string;\n}\n\nexport interface CertificateInfo {\n subject: string;\n issuer: string;\n validFrom: Date;\n validTo: Date;\n serialNumber: string;\n}\n\nconst asErrorMessage = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/** Reads a PKCS#12 (.p12) bundle and extracts the private key + certificate. */\nexport class P12Reader {\n constructor(private readonly passphrase: string) {}\n\n private load(base64: string): forge.pkcs12.Pkcs12Pfx {\n const der = forge.util.decode64(base64);\n const asn1 = forge.asn1.fromDer(der);\n return forge.pkcs12.pkcs12FromAsn1(asn1, false, this.passphrase);\n }\n\n private extractKey(p12: forge.pkcs12.Pkcs12Pfx): string | undefined {\n const keyBags = p12.getBags({\n bagType: forge.pki.oids.pkcs8ShroudedKeyBag,\n });\n const pkcs8Key = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag]?.[0];\n if (pkcs8Key?.key) {\n return forge.pki.privateKeyToPem(pkcs8Key.key);\n }\n const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });\n const certBag = certBags[forge.pki.oids.certBag]?.[0];\n if (certBag?.key) {\n return forge.pki.privateKeyToPem(certBag.key);\n }\n return undefined;\n }\n\n private extractCertificate(p12: forge.pkcs12.Pkcs12Pfx): string | undefined {\n const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });\n const certBag = certBags[forge.pki.oids.certBag]?.[0];\n if (!certBag?.cert) {\n return undefined;\n }\n return forge.pki.certificateToPem(certBag.cert);\n }\n\n getKeyFromFile(fileName: string): Result<P12ReaderData, DgiiError> {\n try {\n const base64 = readFileSync(fileName, 'base64');\n return this.getKeyFromStringBase64(base64);\n } catch (error) {\n return err(\n new DgiiError(`Unable to read .p12 file: ${fileName}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n getKeyFromStringBase64(base64: string): Result<P12ReaderData, DgiiError> {\n try {\n const p12 = this.load(base64);\n const key = this.extractKey(p12);\n const cert = this.extractCertificate(p12);\n if (!key || !cert) {\n return err(\n new DgiiError('PKCS#12 must contain a private key and certificate', {\n code: 'CERTIFICATE',\n }),\n );\n }\n const publicKey = forge.pki.publicKeyToPem(\n forge.pki.certificateFromPem(cert).publicKey,\n );\n return ok({ key, cert, publicKey });\n } catch (error) {\n return err(\n new DgiiError(`Unable to parse .p12: ${asErrorMessage(error)}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n private toCertificateInfo(certPem: string): CertificateInfo {\n const certificate = forge.pki.certificateFromPem(certPem);\n return {\n subject: certificate.subject.attributes\n .map((attribute) => `${attribute.shortName}=${attribute.value}`)\n .join(', '),\n issuer: certificate.issuer.attributes\n .map((attribute) => `${attribute.shortName}=${attribute.value}`)\n .join(', '),\n validFrom: certificate.validity.notBefore,\n validTo: certificate.validity.notAfter,\n serialNumber: certificate.serialNumber,\n };\n }\n\n getCertificateInfo(fileName: string): Result<CertificateInfo, DgiiError> {\n try {\n const base64 = readFileSync(fileName, 'base64');\n return this.getCertificateInfoFromBase64(base64);\n } catch (error) {\n return err(\n new DgiiError(`Unable to read .p12 file: ${fileName}`, {\n code: 'CERTIFICATE',\n cause: error,\n }),\n );\n }\n }\n\n getCertificateInfoFromBase64(\n base64: string,\n ): Result<CertificateInfo, DgiiError> {\n try {\n const certPem = this.extractCertificate(this.load(base64));\n if (!certPem) {\n return err(\n new DgiiError('Certificate not found in PKCS#12', {\n code: 'CERTIFICATE',\n }),\n );\n }\n return ok(this.toCertificateInfo(certPem));\n } catch (error) {\n return err(\n new DgiiError(\n `Unable to extract certificate info: ${asErrorMessage(error)}`,\n { code: 'CERTIFICATE', cause: error },\n ),\n );\n }\n }\n}\n","import crypto from 'node:crypto';\nimport { DOMParser } from '@xmldom/xmldom';\nimport { C14nCanonicalization, SignedXml } from 'xml-crypto';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\nexport type DgiiDocumentType =\n 'SemillaModel' | 'ECF' | 'RFCE' | 'ARECF' | 'ACECF' | 'ANECF' | (string & {});\n\nconst C14N_INCLUSIVE = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';\nconst RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';\nconst SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256';\nconst ENVELOPED = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature';\n/**\n * Custom digest URI: DGII hashes the inclusive C14N 1.0 form of the referenced\n * document. xml-crypto's built-in SHA-256 hashes its raw serialization, so we\n * register a digest backed by xml-crypto's inclusive C14N implementation.\n */\nconst CUSTOM_DIGEST_URI = 'http://dgii.gov.do/digest/sha256-c14n';\n\ninterface XmldomDocument extends Document {\n childNodes: NodeListOf<ChildNode>;\n}\n\n/**\n * DGII-compatible digest: hash the inclusive C14N 1.0 form of the referenced\n * document — the exact bytes a .NET/DGII verifier computes.\n */\nclass DgiiDigest {\n getHash(xml: string): string {\n const doc = new DOMParser().parseFromString(\n xml,\n ) as unknown as XmldomDocument;\n const canonical = new C14nCanonicalization().process(\n doc as unknown as Node,\n {},\n );\n return crypto\n .createHash('sha256')\n .update(canonical, 'utf8')\n .digest('base64');\n }\n\n getAlgorithmName(): string {\n return SHA256;\n }\n}\n\ninterface StrictParseResult {\n doc: XmldomDocument;\n rootName: string;\n}\n\nconst parseStrict = (xml: string): StrictParseResult => {\n const errors: string[] = [];\n const doc = new DOMParser({\n errorHandler: {\n warning: () => undefined,\n error: (message: string) => errors.push(message),\n fatalError: (message: string) => errors.push(message),\n },\n }).parseFromString(xml, 'text/xml') as unknown as XmldomDocument;\n\n if (errors.length) {\n throw new Error(`Invalid XML: ${errors.join('; ')}`);\n }\n const root = doc.documentElement;\n if (!root) {\n throw new Error('Unable to parse XML or find root element');\n }\n if (root.nodeName === 'parsererror' || root.localName === 'parsererror') {\n throw new Error(`Invalid XML: ${root.textContent ?? 'parse error'}`);\n }\n return {\n doc,\n rootName: root.localName ?? root.nodeName,\n };\n};\n\n/** Remove whitespace-only text nodes and comments before canonicalization. */\nconst cleanNodes = (node: Node): void => {\n for (let index = 0; index < node.childNodes.length; index += 1) {\n const child = node.childNodes[index];\n if (!child) {\n continue;\n }\n const isComment = child.nodeType === 8;\n const isWhitespace =\n child.nodeType === 3 && !/\\S/.test(child.nodeValue ?? '');\n if (isComment || isWhitespace) {\n node.removeChild(child);\n index -= 1;\n } else if (child.nodeType === 1) {\n cleanNodes(child);\n }\n }\n};\n\n/** Signs DGII XML documents with XMLDSig (enveloped, inclusive C14N, RSA-SHA256). */\nexport class Signature {\n constructor(\n private readonly privateKey: string,\n private readonly certificatePem: string,\n ) {}\n\n signXml(\n xml: string,\n rootElName?: DgiiDocumentType,\n ): Result<string, DgiiError> {\n try {\n const { doc, rootName } = parseStrict(xml);\n const elementName = rootElName ?? rootName;\n\n const sig = new SignedXml({\n privateKey: this.privateKey,\n publicCert: this.certificatePem,\n signatureAlgorithm: RSA_SHA256,\n canonicalizationAlgorithm: C14N_INCLUSIVE,\n });\n\n const hashAlgorithms = (\n sig as unknown as {\n HashAlgorithms: Record<string, unknown>;\n }\n ).HashAlgorithms;\n hashAlgorithms[CUSTOM_DIGEST_URI] = DgiiDigest;\n\n sig.addReference({\n xpath: `//*[local-name(.)='${elementName}']`,\n transforms: [ENVELOPED],\n digestAlgorithm: CUSTOM_DIGEST_URI,\n isEmptyUri: true,\n } as unknown as Parameters<SignedXml['addReference']>[0]);\n\n cleanNodes(doc as unknown as Node);\n sig.computeSignature(doc.toString());\n return ok(sig.getSignedXml());\n } catch (error) {\n return err(\n new DgiiError(\n `Failed to sign XML: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'SIGNING', cause: error },\n ),\n );\n }\n }\n}\n\nexport interface XmlCertificateValidation {\n isValid: boolean;\n subject?: string;\n issuer?: string;\n validFrom?: string;\n validTo?: string;\n error?: string;\n}\n\n/** Validate the embedded X509 certificate of a signed XML document. */\nexport const validateXMLCertificate = (\n xml: string,\n): XmlCertificateValidation => {\n try {\n const match = xml.match(/<X509Certificate>([\\s\\S]*?)<\\/X509Certificate>/);\n if (!match?.[1]) {\n return { isValid: false, error: 'X509Certificate not found' };\n }\n const der = Buffer.from(match[1].replace(/\\s+/g, ''), 'base64');\n const certificate = new crypto.X509Certificate(der);\n const notBefore = new Date(certificate.validFrom).getTime();\n const notAfter = new Date(certificate.validTo).getTime();\n const now = Date.now();\n const isValid = now >= notBefore && now <= notAfter;\n return {\n isValid,\n subject: certificate.subject,\n issuer: certificate.issuer,\n validFrom: certificate.validFrom,\n validTo: certificate.validTo,\n error: isValid ? undefined : 'Certificate expired or not yet valid',\n };\n } catch (error) {\n return {\n isValid: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n};\n","import convert from 'xml-js';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\n\n/**\n * Converts between the DGII XML documents and the \"compact\" JSON shape used by\n * `xml-js` (a dict key is an element, an array is a repeated element, and\n * `_attributes` / `_text` carry attributes and text).\n */\nexport class Transformer {\n json2xml(dataObject: object, round = false): Result<string, DgiiError> {\n try {\n const data: Record<string, unknown> = {\n _declaration: { _attributes: { version: '1.0', encoding: 'utf-8' } },\n ...dataObject,\n };\n\n const xml = convert.js2xml(data as convert.ElementCompact, {\n compact: true,\n ignoreComment: true,\n spaces: 2,\n fullTagEmptyElement: true,\n textFn: (value: string, label: string) => {\n const omits = ['version'];\n if (\n /^\\d+\\.\\d+$/.test(value) &&\n round &&\n !omits.includes(label.toLowerCase())\n ) {\n return parseFloat(value).toFixed(2);\n }\n return value;\n },\n });\n\n return ok(xml);\n } catch (error) {\n return err(\n new DgiiError(\n `Error converting JSON to XML: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n }\n\n xml2json<T>(xml: string): Result<T, DgiiError> {\n try {\n const json = convert.xml2js(xml, {\n compact: true,\n ignoreComment: true,\n nativeType: false,\n });\n return ok(json as T);\n } catch (error) {\n return err(\n new DgiiError(\n `Error converting XML to JSON: ${error instanceof Error ? error.message : String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n }\n}\n","import { BaseUrl, Environment } from './environment.js';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\nimport { Transformer } from './transformer.js';\n\n/** First 6 chars of the `<SignatureValue>` (DGII security code). */\nexport const getCodeSixDigitfromSignature = (\n signedXml: string,\n): Result<string, DgiiError> => {\n const match = signedXml.match(/<SignatureValue>([\\s\\S]*?)<\\/SignatureValue>/);\n const value = match?.[1]?.trim();\n if (!value) {\n return err(new DgiiError('SignatureValue not found', { code: 'SIGNING' }));\n }\n if (value.length < 6) {\n return err(\n new DgiiError('SignatureValue is too short', { code: 'SIGNING' }),\n );\n }\n return ok(value.slice(0, 6));\n};\n\n/** QR URL for a factura de consumo (FC). */\nexport const generateFcQRCodeURL = (\n rncemisor: string,\n encf: string,\n montototal: number,\n codigoseguridad: string,\n env: Environment,\n): string =>\n `${BaseUrl.CF}/${env.toLowerCase()}/consultatimbrefc?rncemisor=${encodeURIComponent(\n rncemisor,\n )}&encf=${encodeURIComponent(encf)}&montototal=${encodeURIComponent(\n String(montototal),\n )}&codigoseguridad=${encodeURIComponent(codigoseguridad)}`;\n\n/** QR URL for a crédito fiscal (e-CF). */\nexport const generateEcfQRCodeURL = (\n rncemisor: string,\n rncComprador: string,\n encf: string,\n montototal: string,\n fechaEmision: string,\n fechaFirma: string,\n codigoseguridad: string,\n env: Environment,\n): string => {\n let rncCompradorParam = '';\n if (rncComprador && !/E43/i.test(encf) && !/E47/i.test(encf)) {\n rncCompradorParam = `RncComprador=${encodeURIComponent(rncComprador)}&`;\n }\n return `${BaseUrl.ECF}/${env.toLowerCase()}/consultatimbre?rncemisor=${encodeURIComponent(\n rncemisor,\n )}&${rncCompradorParam}encf=${encodeURIComponent(\n encf,\n )}&fechaemision=${encodeURIComponent(\n fechaEmision,\n )}&montototal=${encodeURIComponent(\n montototal,\n )}&fechafirma=${encodeURIComponent(\n fechaFirma,\n )}&codigoseguridad=${encodeURIComponent(codigoseguridad)}`;\n};\n\nconst formatInSantoDomingo = (date: Date, withTime: boolean): string => {\n const parts = new Intl.DateTimeFormat('es-DO', {\n timeZone: 'America/Santo_Domingo',\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n ...(withTime\n ? { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }\n : {}),\n })\n .formatToParts(date)\n .reduce<Record<string, string>>((acc, part) => {\n acc[part.type] = part.value;\n return acc;\n }, {});\n\n const datePart = `${parts.day}-${parts.month}-${parts.year}`;\n return withTime\n ? `${datePart} ${parts.hour}:${parts.minute}:${parts.second}`\n : datePart;\n};\n\n/** `DD-MM-YYYY HH:mm:ss` in America/Santo_Domingo. */\nexport const getCurrentFormattedDateTime = (date: Date = new Date()): string =>\n formatInSantoDomingo(date, true);\n\n/** `DD-MM-YYYY` in America/Santo_Domingo. */\nexport const getCurrentFormattedDate = (date: Date = new Date()): string =>\n formatInSantoDomingo(date, false);\n\n/** Extract the XML payload embedded in a DGII commercial-approval body. */\nexport const getXmlFromBodyResponse = (\n body: string,\n lastTagName = 'ACECF',\n): string | undefined =>\n body.match(new RegExp(`<\\\\?xml[\\\\s\\\\S]*?<\\\\/${lastTagName}>`))?.[0];\n\ninterface CompactElement {\n _text?: string;\n [key: string]: unknown;\n}\n\ninterface ImpuestoAdicional {\n TipoImpuesto?: CompactElement;\n MontoImpuestoSelectivoConsumoEspecifico?: CompactElement;\n MontoImpuestoSelectivoConsumoAdvalorem?: CompactElement;\n OtrosImpuestosAdicionales?: CompactElement;\n}\n\ninterface EcfTotales {\n MontoGravadoTotal?: CompactElement;\n MontoGravadoI1?: CompactElement;\n MontoGravadoI2?: CompactElement;\n MontoGravadoI3?: CompactElement;\n MontoExento?: CompactElement;\n TotalITBIS?: CompactElement;\n TotalITBIS1?: CompactElement;\n TotalITBIS2?: CompactElement;\n TotalITBIS3?: CompactElement;\n MontoImpuestoAdicional?: CompactElement;\n ImpuestosAdicionales?: {\n ImpuestoAdicional?: ImpuestoAdicional | ImpuestoAdicional[];\n };\n MontoTotal?: CompactElement;\n MontoNoFacturable?: CompactElement;\n MontoPeriodo?: CompactElement;\n}\n\ninterface EcfJson {\n ECF: {\n Encabezado?: {\n Version?: CompactElement;\n IdDoc?: {\n TipoeCF?: CompactElement;\n eNCF?: CompactElement;\n TipoIngresos?: CompactElement;\n TipoPago?: CompactElement;\n TablaFormasPago?: CompactElement;\n };\n Emisor?: {\n RNCEmisor?: CompactElement;\n RazonSocialEmisor?: CompactElement;\n FechaEmision?: CompactElement;\n };\n Comprador?: {\n RNCComprador?: CompactElement;\n IdentificadorExtranjero?: CompactElement;\n RazonSocialComprador?: CompactElement;\n };\n Totales?: EcfTotales;\n };\n };\n}\n\nconst toArray = <T>(value: T | T[] | undefined | null): T[] => {\n if (value === undefined || value === null) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n};\n\nconst isEmptyObject = (value: unknown): boolean =>\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n Object.keys(value as Record<string, unknown>).length === 0;\n\nconst removeEmptyValues = (input: unknown): unknown => {\n if (input === null || input === undefined || input === '') {\n return undefined;\n }\n if (Array.isArray(input)) {\n const filtered = input\n .map(removeEmptyValues)\n .filter(\n (item) =>\n item !== null &&\n item !== undefined &&\n item !== '' &&\n !isEmptyObject(item),\n );\n return filtered.length ? filtered : undefined;\n }\n if (typeof input === 'object') {\n const output: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(\n input as Record<string, unknown>,\n )) {\n const cleaned = removeEmptyValues(value);\n if (cleaned !== undefined && cleaned !== '' && !isEmptyObject(cleaned)) {\n output[key] = cleaned;\n }\n }\n return Object.keys(output).length ? output : undefined;\n }\n return input;\n};\n\n/**\n * Build the RFCE (summary invoice) document from a signed ECF-32 document.\n * Returns the unsigned RFCE XML plus the 6-digit security code.\n */\nexport const convertECF32ToRFCE = (\n ecf32Xml: string,\n): Result<{ xml: string; securityCode: string }, DgiiError> => {\n const securityCode = getCodeSixDigitfromSignature(ecf32Xml);\n if (securityCode.isErr()) {\n return err(securityCode.error);\n }\n\n const transformer = new Transformer();\n const parsed = transformer.xml2json<EcfJson>(ecf32Xml);\n if (parsed.isErr()) {\n return err(parsed.error);\n }\n\n const encabezado = parsed.value.ECF.Encabezado;\n const impuestos = toArray(\n encabezado?.Totales?.ImpuestosAdicionales?.ImpuestoAdicional,\n );\n\n const rfce = removeEmptyValues({\n RFCE: {\n Encabezado: {\n Version: encabezado?.Version,\n IdDoc: {\n TipoeCF: encabezado?.IdDoc?.TipoeCF,\n eNCF: encabezado?.IdDoc?.eNCF,\n TipoIngresos: encabezado?.IdDoc?.TipoIngresos,\n TipoPago: encabezado?.IdDoc?.TipoPago,\n TablaFormasPago: encabezado?.IdDoc?.TablaFormasPago,\n },\n Emisor: {\n RNCEmisor: encabezado?.Emisor?.RNCEmisor,\n RazonSocialEmisor: encabezado?.Emisor?.RazonSocialEmisor,\n FechaEmision: encabezado?.Emisor?.FechaEmision,\n },\n Comprador: {\n RNCComprador: encabezado?.Comprador?.RNCComprador,\n IdentificadorExtranjero:\n encabezado?.Comprador?.IdentificadorExtranjero,\n RazonSocialComprador: encabezado?.Comprador?.RazonSocialComprador,\n },\n Totales: {\n MontoGravadoTotal: encabezado?.Totales?.MontoGravadoTotal,\n MontoGravadoI1: encabezado?.Totales?.MontoGravadoI1,\n MontoGravadoI2: encabezado?.Totales?.MontoGravadoI2,\n MontoGravadoI3: encabezado?.Totales?.MontoGravadoI3,\n MontoExento: encabezado?.Totales?.MontoExento,\n TotalITBIS: encabezado?.Totales?.TotalITBIS,\n TotalITBIS1: encabezado?.Totales?.TotalITBIS1,\n TotalITBIS2: encabezado?.Totales?.TotalITBIS2,\n TotalITBIS3: encabezado?.Totales?.TotalITBIS3,\n MontoImpuestoAdicional: encabezado?.Totales?.MontoImpuestoAdicional,\n ImpuestosAdicionales: {\n ImpuestoAdicional: impuestos.map((impuesto) => ({\n TipoImpuesto: impuesto.TipoImpuesto,\n MontoImpuestoSelectivoConsumoEspecifico:\n impuesto.MontoImpuestoSelectivoConsumoEspecifico,\n MontoImpuestoSelectivoConsumoAdvalorem:\n impuesto.MontoImpuestoSelectivoConsumoAdvalorem,\n OtrosImpuestosAdicionales: impuesto.OtrosImpuestosAdicionales,\n })),\n },\n MontoTotal: encabezado?.Totales?.MontoTotal,\n MontoNoFacturable: encabezado?.Totales?.MontoNoFacturable,\n MontoPeriodo: encabezado?.Totales?.MontoPeriodo,\n },\n CodigoSeguridadeCF: securityCode.value,\n },\n },\n });\n\n if (typeof rfce !== 'object' || rfce === null) {\n return err(\n new DgiiError('Unable to build RFCE document', { code: 'VALIDATION' }),\n );\n }\n\n const xml = transformer.json2xml(rfce);\n if (xml.isErr()) {\n return err(xml.error);\n }\n\n return ok({ xml: xml.value, securityCode: securityCode.value });\n};\n","import { createHash } from 'node:crypto';\nimport { err, ok, type Result } from './result.js';\nimport { DgiiError } from './errors.js';\nimport {\n BaseUrl,\n Endpoint,\n Environment,\n SenderReceiverEndpoint,\n buildSenderReceiverUrl,\n buildUrl,\n} from './environment.js';\nimport {\n HttpClient,\n InMemoryIdempotencyStore,\n type IdempotencyStore,\n} from './http.js';\nimport type { ResilienceOptions } from './resilience.js';\nimport { Signature } from './signing.js';\nimport type { P12ReaderData } from './certificate.js';\nimport type {\n AuthToken,\n CommercialApprovalResponse,\n InquiryInvoiceSummary,\n InquiryStatusResponse,\n InvoiceResponse,\n InvoiceSummaryResponse,\n ServiceDirectoryResponse,\n SummaryTrackingStatusResponse,\n TrackingStatusResponse,\n VoidNCFResponse,\n} from './types.js';\n\nexport interface EcfOptions {\n /** Pre-existing bearer token (skips the authentication round-trip). */\n token?: string;\n /** Pluggable idempotency store; defaults to an in-memory store. */\n idempotencyStore?: IdempotencyStore;\n resilience?: ResilienceOptions;\n timeoutMs?: number;\n /** Injectable fetch (useful for tests). */\n fetchImpl?: typeof fetch;\n}\n\ninterface PendingSubmission {\n readonly pending: true;\n}\n\nconst PENDING_SUBMISSION: PendingSubmission = { pending: true };\n\nconst isPendingSubmission = (value: unknown): value is PendingSubmission =>\n typeof value === 'object' &&\n value !== null &&\n (value as { pending?: unknown }).pending === true;\n\nconst sha256Hex = (value: string): string =>\n createHash('sha256').update(value, 'utf8').digest('hex');\n\nconst extractTag = (xml: string, tag: string): string | undefined => {\n const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));\n return match?.[1]?.trim();\n};\n\n/**\n * DGII e-CF client. Every method returns a `Result` — no thrown domain errors.\n */\nexport class ECF {\n private readonly environment: Environment;\n private readonly http: HttpClient;\n private readonly idempotency: IdempotencyStore;\n private readonly credentials: P12ReaderData;\n private readonly inFlight = new Map<\n string,\n Promise<Result<unknown, DgiiError>>\n >();\n\n constructor(\n credentials: P12ReaderData,\n environment: Environment = Environment.Dev,\n options: EcfOptions = {},\n ) {\n this.credentials = credentials;\n this.environment = environment;\n this.idempotency =\n options.idempotencyStore ?? new InMemoryIdempotencyStore();\n this.http = new HttpClient({\n baseUrl: BaseUrl.ECF,\n ...(options.token !== undefined ? { token: options.token } : {}),\n ...(options.resilience !== undefined\n ? { resilience: options.resilience }\n : {}),\n ...(options.timeoutMs !== undefined\n ? { timeoutMs: options.timeoutMs }\n : {}),\n ...(options.fetchImpl !== undefined\n ? { fetchImpl: options.fetchImpl }\n : {}),\n });\n }\n\n private buildIdempotencyKey(signedXml: string): string {\n const rnc = extractTag(signedXml, 'RNCEmisor') ?? 'unknown-rnc';\n const encf = extractTag(signedXml, 'eNCF') ?? 'unknown-encf';\n return `${rnc}:${encf}:${sha256Hex(signedXml)}`;\n }\n\n private async singleFlight<T>(\n key: string,\n task: () => Promise<Result<T, DgiiError>>,\n ): Promise<Result<T, DgiiError>> {\n const existing = this.inFlight.get(key);\n if (existing) {\n return existing as Promise<Result<T, DgiiError>>;\n }\n const promise = task();\n this.inFlight.set(key, promise as Promise<Result<unknown, DgiiError>>);\n try {\n return await promise;\n } finally {\n this.inFlight.delete(key);\n }\n }\n\n /** Authenticate against DGII (or a buyer host) and store the bearer token. */\n async authenticate(\n buyerHost?: string,\n ): Promise<Result<AuthToken, DgiiError>> {\n const seed = await this.getSeed(buyerHost);\n if (seed.isErr()) {\n return err(seed.error);\n }\n if (\n typeof this.credentials.key !== 'string' ||\n typeof this.credentials.cert !== 'string'\n ) {\n return err(\n new DgiiError(\n 'A private key and certificate PEM are required to authenticate',\n { code: 'CERTIFICATE' },\n ),\n );\n }\n\n const signed = new Signature(\n this.credentials.key,\n this.credentials.cert,\n ).signXml(seed.value, 'SemillaModel');\n if (signed.isErr()) {\n return err(signed.error);\n }\n\n const token = await this.getAuthToken(signed.value, buyerHost);\n if (token.isErr()) {\n return err(token.error);\n }\n this.http.setToken(token.value.token);\n return ok(token.value);\n }\n\n private getSeed(buyerHost?: string): Promise<Result<string, DgiiError>> {\n if (buyerHost) {\n const url = buildSenderReceiverUrl(\n buyerHost,\n SenderReceiverEndpoint.Seed,\n );\n return this.http.get<string>(url, undefined, {\n absoluteUrl: true,\n resource: SenderReceiverEndpoint.Seed,\n });\n }\n const url = buildUrl(this.environment, Endpoint.Seed);\n return this.http.get<string>(url, undefined, {\n absoluteUrl: true,\n resource: Endpoint.Seed,\n });\n }\n\n private getAuthToken(\n signedSeed: string,\n buyerHost?: string,\n ): Promise<Result<AuthToken, DgiiError>> {\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.ValidateSeed)\n : buildUrl(this.environment, Endpoint.ValidateSeed);\n return this.http.postMultipart<AuthToken>(url, 'signed.xml', signedSeed, {\n absoluteUrl: true,\n resource: Endpoint.ValidateSeed,\n });\n }\n\n /**\n * Submit a signed e-CF. Idempotent on `RNC + eNCF + SHA-256(signed XML)`:\n * a repeated call returns the cached response instead of double-issuing.\n */\n async sendElectronicDocument(\n signedXml: string,\n fileName: string,\n buyerHost?: string,\n ): Promise<Result<InvoiceResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n const cached = await this.idempotency.get<\n InvoiceResponse | PendingSubmission\n >(key);\n if (cached !== undefined) {\n if (isPendingSubmission(cached)) {\n return err(\n new DgiiError(\n 'A submission with this key is already pending; reconcile via a status lookup before retrying',\n { code: 'IDEMPOTENCY' },\n ),\n );\n }\n return ok(cached);\n }\n return this.singleFlight(key, async () => {\n // Persist-before-transmit: record the pending submission before the\n // network call so an interrupted send can be reconciled, not re-issued.\n await this.idempotency.set(key, PENDING_SUBMISSION);\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.SendInvoice)\n : buildUrl(this.environment, Endpoint.SendInvoice);\n const result = await this.http.postMultipart<InvoiceResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendInvoice },\n );\n if (result.isOk()) {\n await this.idempotency.set(key, result.value);\n } else {\n await this.idempotency.delete(key);\n }\n return result;\n });\n }\n\n /** Submit a signed summary invoice (RFCE). Idempotent like submissions. */\n async sendSummary(\n signedXml: string,\n fileName: string,\n ): Promise<Result<InvoiceSummaryResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n const cached = await this.idempotency.get<\n InvoiceSummaryResponse | PendingSubmission\n >(key);\n if (cached !== undefined) {\n if (isPendingSubmission(cached)) {\n return err(\n new DgiiError(\n 'A submission with this key is already pending; reconcile via a status lookup before retrying',\n { code: 'IDEMPOTENCY' },\n ),\n );\n }\n return ok(cached);\n }\n return this.singleFlight(key, async () => {\n // Persist-before-transmit (see sendElectronicDocument).\n await this.idempotency.set(key, PENDING_SUBMISSION);\n const url = buildUrl(this.environment, Endpoint.SendSummary, BaseUrl.CF);\n const result = await this.http.postMultipart<InvoiceSummaryResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendSummary },\n );\n if (result.isOk()) {\n await this.idempotency.set(key, result.value);\n } else {\n await this.idempotency.delete(key);\n }\n return result;\n });\n }\n\n statusTrackId(\n trackId: string,\n ): Promise<Result<TrackingStatusResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.TrackResultStatus);\n return this.http.get<TrackingStatusResponse>(\n url,\n { trackId },\n { absoluteUrl: true, resource: Endpoint.TrackResultStatus },\n );\n }\n\n inquiryStatus(\n rncEmisor: string,\n ncfElectronico: string,\n rncComprador?: string,\n codigoSeguridad?: string,\n ): Promise<Result<InquiryStatusResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.InquiryStatus);\n return this.http.get<InquiryStatusResponse>(\n url,\n { rncEmisor, ncfElectronico, rncComprador, codigoSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryStatus },\n );\n }\n\n trackStatuses(\n rncEmisor: string,\n encf: string,\n ): Promise<Result<SummaryTrackingStatusResponse[], DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.AllTrackingEcf);\n return this.http.get<SummaryTrackingStatusResponse[]>(\n url,\n { rncEmisor, encf },\n { absoluteUrl: true, resource: Endpoint.AllTrackingEcf },\n );\n }\n\n /** Normalizes DGII's inconsistent (array | single object) directory payload. */\n async getCustomerDirectory(\n rnc: string,\n ): Promise<Result<ServiceDirectoryResponse[] | undefined, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Directory);\n const result = await this.http.get<\n ServiceDirectoryResponse[] | ServiceDirectoryResponse\n >(url, { rnc }, { absoluteUrl: true, resource: Endpoint.Directory });\n if (result.isErr()) {\n return err(result.error);\n }\n const data = result.value;\n if (data === undefined || data === null) {\n return ok(undefined);\n }\n return ok(Array.isArray(data) ? data : [data]);\n }\n\n /** RFCE inquiry — DGII production only. */\n getSummaryInvoiceInquiry(\n rnc: string,\n encf: string,\n codSeguridad: string,\n ): Promise<Result<InquiryInvoiceSummary, DgiiError>> {\n const url = buildUrl(\n this.environment,\n Endpoint.InquiryInvoiceSummary,\n BaseUrl.CF,\n );\n return this.http.get<InquiryInvoiceSummary>(\n url,\n { rnc_emisor: rnc, encf, cod_seguridad_eCF: codSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryInvoiceSummary },\n );\n }\n\n sendCommercialApproval(\n signedXml: string,\n fileName: string,\n ): Promise<Result<CommercialApprovalResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.CommercialApproval);\n return this.http.postMultipart<CommercialApprovalResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.CommercialApproval },\n );\n }\n\n voidENCF(\n signedXml: string,\n fileName: string,\n ): Promise<Result<VoidNCFResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Void);\n return this.http.postMultipart<VoidNCFResponse>(url, fileName, signedXml, {\n absoluteUrl: true,\n resource: Endpoint.Void,\n });\n }\n}\n"],"mappings":";AAAO,IAAK,cAAL,kBAAKA,iBAAL;AAEL,EAAAA,aAAA,SAAM;AAEN,EAAAA,aAAA,UAAO;AAEP,EAAAA,aAAA,UAAO;AANG,SAAAA;AAAA,GAAA;AASL,IAAM,UAAU;AAAA;AAAA,EAErB,KAAK;AAAA;AAAA,EAEL,IAAI;AAAA;AAAA,EAEJ,QAAQ;AACV;AAIO,IAAK,WAAL,kBAAKC,cAAL;AACL,EAAAA,UAAA,UAAO;AACP,EAAAA,UAAA,kBAAe;AACf,EAAAA,UAAA,iBAAc;AACd,EAAAA,UAAA,iBAAc;AACd,EAAAA,UAAA,2BAAwB;AACxB,EAAAA,UAAA,wBAAqB;AACrB,EAAAA,UAAA,uBAAoB;AACpB,EAAAA,UAAA,mBAAgB;AAChB,EAAAA,UAAA,oBAAiB;AACjB,EAAAA,UAAA,eAAY;AACZ,EAAAA,UAAA,UAAO;AAXG,SAAAA;AAAA,GAAA;AAeL,IAAK,yBAAL,kBAAKC,4BAAL;AACL,EAAAA,wBAAA,UAAO;AACP,EAAAA,wBAAA,kBAAe;AACf,EAAAA,wBAAA,iBAAc;AACd,EAAAA,wBAAA,wBAAqB;AAJX,SAAAA;AAAA,GAAA;AAQL,IAAM,WAAW,CACtB,aACA,UACA,UAAkB,QAAQ,QACf,GAAG,QAAQ,QAAQ,QAAQ,EAAE,CAAC,IAAI,WAAW,IAAI,QAAQ;AAG/D,IAAM,yBAAyB,CACpC,MACA,aACW,GAAG,KAAK,QAAQ,QAAQ,EAAE,CAAC,IAAI,QAAQ;;;AC1C7C,IAAK,kBAAL,kBAAKC,qBAAL;AACL,EAAAA,iBAAA,cAAW;AACX,EAAAA,iBAAA,cAAW;AACX,EAAAA,iBAAA,cAAW;AACX,EAAAA,iBAAA,eAAY;AACZ,EAAAA,iBAAA,yBAAsB;AALZ,SAAAA;AAAA,GAAA;;;ACGZ,IAAM,qBAAqB,oBAAI,IAAY,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AAElE,IAAM,oBAAoB,CAAC,WAChC,WAAW,UAAa,mBAAmB,IAAI,MAAM;AAevD,IAAM,UAAU;AAEhB,IAAM,WAAW,CAAC,UAChB,MAAM,SAAS,UAAU,GAAG,MAAM,MAAM,GAAG,OAAO,CAAC,WAAM;AAE3D,IAAM,qBAAqB,CAAC,UAC1B,MAAM,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAElC,IAAM,WAAW,CAAC,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,IAAM,gBAAgB,CAAC,UACrB,sCAAsC,KAAK,KAAK;AAElD,IAAM,YAAY,CAAC,UACjB;AAAA,EACE,MACG,QAAQ,uCAAuC,GAAG,EAClD,QAAQ,qCAAqC,GAAG,EAChD,QAAQ,YAAY,GAAG;AAC5B;AAEF,IAAM,eAAe,CAAC,UAA0C;AAC9D,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAAG;AAC/C,WAAO;AAAA,EACT;AACA,QAAM,MAAiB,CAAC;AACxB,aAAW,QAAQ,OAAO;AACxB,QAAI,OAAO,SAAS,YAAY,KAAK,KAAK,GAAG;AAC3C,UAAI,KAAK,EAAE,OAAO,KAAK,KAAK,GAAG,QAAQ,EAAE,CAAC;AAAA,IAC5C,WAAW,SAAS,IAAI,KAAK,OAAO,KAAK,UAAU,UAAU;AAC3D,UAAI,KAAK;AAAA,QACP,OAAO,KAAK;AAAA,QACZ,QAAQ,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,IAAI,SAAS,MAAM;AAC5B;AAEA,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMO,IAAM,0BAA0B,CACrC,MACA,OAAwB,oBAAI,QAAgB,MACrB;AACvB,MAAI,SAAS,UAAa,SAAS,MAAM;AACvC,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AACA,QAAI,SAAS,KAAK,OAAO,GAAG;AAC1B,UAAI;AACF,eAAO,wBAAwB,KAAK,MAAM,OAAO,GAAG,IAAI;AAAA,MAC1D,QAAQ;AAAA,MAER;AAAA,IACF;AACA,QAAI,cAAc,OAAO,GAAG;AAC1B,YAAM,OAAO,UAAU,OAAO;AAC9B,aAAO,OAAO,SAAS,IAAI,IAAI;AAAA,IACjC;AACA,WAAO,SAAS,mBAAmB,OAAO,CAAC;AAAA,EAC7C;AAEA,MAAI,OAAO,SAAS,YAAY,OAAO,SAAS,WAAW;AACzD,WAAO,OAAO,IAAI;AAAA,EACpB;AAEA,MAAI,gBAAgB,OAAO;AACzB,WAAO,KAAK,WAAW;AAAA,EACzB;AAEA,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,QAAI,KAAK,IAAI,IAAI,GAAG;AAClB,aAAO;AAAA,IACT;AACA,SAAK,IAAI,IAAI;AACb,UAAM,QAAQ,KACX,IAAI,CAAC,SAAS,wBAAwB,MAAM,IAAI,CAAC,EACjD,OAAO,CAAC,SAAyB,QAAQ,IAAI,CAAC;AACjD,WAAO,MAAM,SAAS,SAAS,MAAM,KAAK,KAAK,CAAC,IAAI;AAAA,EACtD;AAEA,MAAI,SAAS,IAAI,GAAG;AAClB,QAAI,KAAK,IAAI,IAAI,GAAG;AAClB,aAAO;AAAA,IACT;AACA,SAAK,IAAI,IAAI;AAEb,UAAM,WAAW,aAAa,KAAK,YAAY,KAAK,QAAQ;AAC5D,QAAI,UAAU;AACZ,aAAO,SAAS,SAAS,IAAI,CAAC,YAAY,QAAQ,KAAK,EAAE,KAAK,KAAK,CAAC;AAAA,IACtE;AAEA,eAAW,OAAO,cAAc;AAC9B,YAAM,QAAQ,KAAK,GAAG;AACtB,UAAI,OAAO,UAAU,YAAY,MAAM,KAAK,GAAG;AAC7C,eAAO,SAAS,mBAAmB,KAAK,CAAC;AAAA,MAC3C;AACA,UAAI,QAAQ,YAAY,SAAS,KAAK,KAAK,MAAM,QAAQ,KAAK,IAAI;AAChE,cAAM,SAAS,wBAAwB,OAAO,IAAI;AAClD,YAAI,QAAQ;AACV,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,UAAU,KAAK;AACnC,QAAI,SAAS,MAAM,GAAG;AACpB,YAAM,QAAQ,OAAO,QAAQ,MAAM,EAChC,IAAI,CAAC,CAAC,OAAO,KAAK,MAAM;AACvB,cAAM,SAAS,wBAAwB,OAAO,IAAI;AAClD,eAAO,SAAS,GAAG,KAAK,KAAK,MAAM,KAAK;AAAA,MAC1C,CAAC,EACA,OAAO,CAAC,SAAyB,QAAQ,IAAI,CAAC;AACjD,UAAI,MAAM,QAAQ;AAChB,eAAO,SAAS,MAAM,KAAK,KAAK,CAAC;AAAA,MACnC;AAAA,IACF,WAAW,QAAQ;AACjB,YAAM,SAAS,wBAAwB,QAAQ,IAAI;AACnD,UAAI,QAAQ;AACV,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI;AACF,YAAM,aAAa,KAAK,UAAU,IAAI;AACtC,UAAI,cAAc,eAAe,MAAM;AACrC,eAAO,SAAS,UAAU;AAAA,MAC5B;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,YAAN,MAAM,mBAAkB,MAAM;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,UAA4B,CAAC,GAAG;AAC3D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAU,SAAS;AAE/C,SAAK,OAAO,QAAQ,QAAQ;AAC5B,SAAK,SAAS,QAAQ;AACtB,SAAK,aAAa,QAAQ;AAC1B,SAAK,WAAW,QAAQ;AACxB,SAAK,SAAS,QAAQ;AACtB,SAAK,UAAU,QAAQ;AACvB,SAAK,OAAO,QAAQ;AACpB,SAAK,WAAW,QAAQ;AACxB,SAAK,YAAY,QAAQ,aAAa,kBAAkB,QAAQ,MAAM;AAEtE,QAAI,QAAQ,UAAU,QAAW;AAC/B,aAAO,eAAe,MAAM,SAAS;AAAA,QACnC,OAAO,QAAQ;AAAA,QACf,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,SAAkC;AAChC,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,YAAY,KAAK;AAAA,MACjB,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,MAAM,KAAK;AAAA,IACb;AAAA,EACF;AACF;AAaO,IAAM,cAAc,CACzBC,MACA,UAA4B,CAAC,MACf;AACd,MAAIA,gBAAe,WAAW;AAC5B,WAAOA;AAAA,EACT;AAEA,MAAIA,gBAAe,OAAO;AACxB,WAAO,IAAI;AAAA,MACTA,KAAI,WAAW,QAAQ,mBAAmB;AAAA,MAC1C;AAAA,QACE,GAAG;AAAA,QACH,OAAOA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UACJ,wBAAwBA,IAAG,KAC3B,QAAQ,mBACR;AACF,QAAM,SACJ,SAASA,IAAG,KAAK,OAAOA,KAAI,WAAW,WACnCA,KAAI,SACJ,QAAQ;AAEd,SAAO,IAAI,UAAU,SAAS;AAAA,IAC5B,GAAG;AAAA,IACH;AAAA,IACA,MAAMA;AAAA,IACN,UAAU,SAASA,IAAG,IAClB,aAAaA,KAAI,YAAYA,KAAI,QAAQ,IACzC;AAAA,IACJ,OAAOA;AAAA,EACT,CAAC;AACH;;;AC/RA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;AChBP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAoBA,IAAM,2BAAwD;AAAA,EACnE,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,eAAe;AACjB;AAMO,IAAM,mBAAmB,CAAC,UAA4B;AAC3D,MAAI,iBAAiB,WAAW;AAC9B,WAAO,MAAM;AAAA,EACf;AACA,MAAI,iBAAiB,OAAO;AAC1B,UAAM,OAAO,MAAM,KAAK,YAAY;AACpC,UAAM,UAAU,MAAM,QAAQ,YAAY;AAC1C,WACE,SAAS,eACT,SAAS,gBACT,SAAS,gBACT,SAAS,kBACT,KAAK,SAAS,QAAQ,KACtB,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,SAAS;AAAA,EAE9B;AACA,SAAO;AACT;AAYO,IAAM,2BAA2B,CACtC,UAA6B,CAAC,MACP;AACvB,QAAM,OAAO,EAAE,GAAG,0BAA0B,GAAG,QAAQ;AAEvD,QAAM,cAAc,MAAM,WAAW,gBAAgB,GAAG;AAAA,IACtD,aAAa,KAAK;AAAA,IAClB,SAAS,IAAI,mBAAmB,EAAE,cAAc,KAAK,oBAAoB,CAAC;AAAA,EAC5E,CAAC;AAED,QAAM,gBAAgB,eAAe,WAAW;AAAA,IAC9C,eAAe,KAAK;AAAA,IACpB,SAAS,IAAI,mBAAmB,KAAK,gBAAgB;AAAA,EACvD,CAAC;AAED,QAAM,gBAAgB,QAAQ,KAAK,WAAW,gBAAgB,UAAU;AACxE,QAAM,iBAAiB,SAAS,KAAK,eAAe,KAAK,aAAa;AAEtE,QAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,UAAU;AAAA,IACV;AAAA,EACF;AACF;;;AC1FO,IAAM,2BAAN,MAA2D;AAAA,EAC/C,QAAQ,oBAAI,IAAqB;AAAA,EAElD,MAAM,IAAO,KAAqC;AAChD,WAAO,KAAK,MAAM,IAAI,GAAG;AAAA,EAC3B;AAAA,EAEA,MAAM,IAAO,KAAa,OAAyB;AACjD,SAAK,MAAM,IAAI,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,MAAM,OAAO,KAA4B;AACvC,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AACF;AA6BO,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAA4B;AACtC,SAAK,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AACjD,SAAK,QAAQ,QAAQ;AACrB,SAAK,WACH,QAAQ,YACR,yBAAyB;AAAA,MACvB,GAAG,QAAQ;AAAA,MACX,GAAI,QAAQ,cAAc,SACtB,EAAE,WAAW,QAAQ,UAAU,IAC/B,CAAC;AAAA,IACP,CAAC;AACH,SAAK,YAAY,QAAQ,aAAa;AAAA,EACxC;AAAA,EAEA,SAAS,OAAqB;AAC5B,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,aAAmB;AACjB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,SACN,MACA,aACA,OACQ;AACR,QAAI,MAAM,cACN,OACA,GAAG,KAAK,OAAO,GAAG,KAAK,WAAW,GAAG,IAAI,KAAK,GAAG,GAAG,IAAI;AAE5D,QAAI,OAAO;AACT,YAAM,SAAS,IAAI,gBAAgB;AACnC,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,YAAI,UAAU,UAAa,UAAU,IAAI;AACvC,iBAAO,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,QAC/B;AAAA,MACF;AACA,YAAM,KAAK,OAAO,SAAS;AAC3B,UAAI,IAAI;AACN,gBAAQ,IAAI,SAAS,GAAG,IAAI,MAAM,OAAO;AAAA,MAC3C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,YAAY,OAAwD;AAC1E,UAAM,UAAkC,EAAE,QAAQ,mBAAmB;AACrE,QAAI,KAAK,OAAO;AACd,cAAQ,gBAAgB,UAAU,KAAK,KAAK;AAAA,IAC9C;AACA,WAAO,EAAE,GAAG,SAAS,GAAG,MAAM;AAAA,EAChC;AAAA,EAEA,MAAc,SAAS,UAAsC;AAC3D,UAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;AAC5D,QAAI;AACF,UAAI,YAAY,SAAS,MAAM,GAAG;AAChC,eAAO,MAAM,SAAS,KAAK;AAAA,MAC7B;AACA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO,KAAK,SAAS,OAAO;AAAA,IAC9B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,cACZ,UACA,KAC+B;AAC/B,UAAM,OAAO,MAAM,KAAK,SAAS,QAAQ;AAEzC,QAAI,SAAS,IAAI;AACf,aAAO,GAAG,IAAS;AAAA,IACrB;AAEA,UAAM,UACJ,wBAAwB,IAAI,KAC5B,mCAAmC,SAAS,MAAM;AACpD,UAAM,QAAQ,IAAI,UAAU,SAAS;AAAA,MACnC,MAAM,SAAS,WAAW,MAAM,SAAS;AAAA,MACzC,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS;AAAA,MACrB,UAAU,IAAI;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,MACb;AAAA,IACF,CAAC;AAID,QAAI,MAAM,WAAW;AACnB,YAAM;AAAA,IACR;AACA,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA,EAEA,MAAM,QAAW,SAAwD;AACvE,UAAM,MAAM,KAAK,SAAS,QAAQ,MAAM,QAAQ,aAAa,QAAQ,KAAK;AAC1E,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,UAAU,KAAK,YAAY,QAAQ,OAAO;AAChD,UAAM,MAAsB;AAAA,MAC1B;AAAA,MACA,UAAU,QAAQ,YAAY,QAAQ;AAAA,MACtC,SAAS,KAAK;AAAA,IAChB;AAEA,QAAI;AACF,aAAO,MAAM,KAAK,SAAS,OAAO,QAAQ,OAAO,EAAE,OAAO,MAAM;AAC9D,cAAM,WAAW,MAAM,KAAK,UAAU,KAAK;AAAA,UACzC;AAAA,UACA;AAAA,UACA,MAAM,QAAQ;AAAA,UACd;AAAA,QACF,CAAC;AACD,eAAO,KAAK,cAAiB,UAAU,GAAG;AAAA,MAC5C,CAAC;AAAA,IACH,SAAS,OAAO;AACd,aAAO,IAAI,YAAY,OAAO,GAAG,CAAC;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,IACE,MACA,OACA,MAC+B;AAC/B,WAAO,KAAK,QAAW;AAAA,MACrB,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,aAAa,MAAM;AAAA,MACnB,UAAU,MAAM;AAAA,IAClB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cACE,MACA,UACA,KACA,MAC+B;AAC/B,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,OAAO,OAAO,IAAI,KAAK,CAAC,GAAG,GAAG,EAAE,MAAM,kBAAkB,CAAC,GAAG,QAAQ;AACzE,WAAO,KAAK,QAAW;AAAA,MACrB,QAAQ;AAAA,MACR;AAAA,MACA,MAAM;AAAA,MACN,SAAS,EAAE,QAAQ,mBAAmB;AAAA,MACtC,aAAa,MAAM;AAAA,MACnB,UAAU,MAAM;AAAA,IAClB,CAAC;AAAA,EACH;AACF;;;AClOA,SAAS,oBAAoB;AAC7B,OAAO,WAAW;AAkBlB,IAAM,iBAAiB,CAAC,UACtB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAGhD,IAAM,YAAN,MAAgB;AAAA,EACrB,YAA6B,YAAoB;AAApB;AAAA,EAAqB;AAAA,EAArB;AAAA,EAErB,KAAK,QAAwC;AACnD,UAAM,MAAM,MAAM,KAAK,SAAS,MAAM;AACtC,UAAM,OAAO,MAAM,KAAK,QAAQ,GAAG;AACnC,WAAO,MAAM,OAAO,eAAe,MAAM,OAAO,KAAK,UAAU;AAAA,EACjE;AAAA,EAEQ,WAAW,KAAiD;AAClE,UAAM,UAAU,IAAI,QAAQ;AAAA,MAC1B,SAAS,MAAM,IAAI,KAAK;AAAA,IAC1B,CAAC;AACD,UAAM,WAAW,QAAQ,MAAM,IAAI,KAAK,mBAAmB,IAAI,CAAC;AAChE,QAAI,UAAU,KAAK;AACjB,aAAO,MAAM,IAAI,gBAAgB,SAAS,GAAG;AAAA,IAC/C;AACA,UAAM,WAAW,IAAI,QAAQ,EAAE,SAAS,MAAM,IAAI,KAAK,QAAQ,CAAC;AAChE,UAAM,UAAU,SAAS,MAAM,IAAI,KAAK,OAAO,IAAI,CAAC;AACpD,QAAI,SAAS,KAAK;AAChB,aAAO,MAAM,IAAI,gBAAgB,QAAQ,GAAG;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB,KAAiD;AAC1E,UAAM,WAAW,IAAI,QAAQ,EAAE,SAAS,MAAM,IAAI,KAAK,QAAQ,CAAC;AAChE,UAAM,UAAU,SAAS,MAAM,IAAI,KAAK,OAAO,IAAI,CAAC;AACpD,QAAI,CAAC,SAAS,MAAM;AAClB,aAAO;AAAA,IACT;AACA,WAAO,MAAM,IAAI,iBAAiB,QAAQ,IAAI;AAAA,EAChD;AAAA,EAEA,eAAe,UAAoD;AACjE,QAAI;AACF,YAAM,SAAS,aAAa,UAAU,QAAQ;AAC9C,aAAO,KAAK,uBAAuB,MAAM;AAAA,IAC3C,SAAS,OAAO;AACd,aAAO;AAAA,QACL,IAAI,UAAU,6BAA6B,QAAQ,IAAI;AAAA,UACrD,MAAM;AAAA,UACN,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,uBAAuB,QAAkD;AACvE,QAAI;AACF,YAAM,MAAM,KAAK,KAAK,MAAM;AAC5B,YAAM,MAAM,KAAK,WAAW,GAAG;AAC/B,YAAM,OAAO,KAAK,mBAAmB,GAAG;AACxC,UAAI,CAAC,OAAO,CAAC,MAAM;AACjB,eAAO;AAAA,UACL,IAAI,UAAU,sDAAsD;AAAA,YAClE,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAAA,MACF;AACA,YAAM,YAAY,MAAM,IAAI;AAAA,QAC1B,MAAM,IAAI,mBAAmB,IAAI,EAAE;AAAA,MACrC;AACA,aAAO,GAAG,EAAE,KAAK,MAAM,UAAU,CAAC;AAAA,IACpC,SAAS,OAAO;AACd,aAAO;AAAA,QACL,IAAI,UAAU,yBAAyB,eAAe,KAAK,CAAC,IAAI;AAAA,UAC9D,MAAM;AAAA,UACN,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,kBAAkB,SAAkC;AAC1D,UAAM,cAAc,MAAM,IAAI,mBAAmB,OAAO;AACxD,WAAO;AAAA,MACL,SAAS,YAAY,QAAQ,WAC1B,IAAI,CAAC,cAAc,GAAG,UAAU,SAAS,IAAI,UAAU,KAAK,EAAE,EAC9D,KAAK,IAAI;AAAA,MACZ,QAAQ,YAAY,OAAO,WACxB,IAAI,CAAC,cAAc,GAAG,UAAU,SAAS,IAAI,UAAU,KAAK,EAAE,EAC9D,KAAK,IAAI;AAAA,MACZ,WAAW,YAAY,SAAS;AAAA,MAChC,SAAS,YAAY,SAAS;AAAA,MAC9B,cAAc,YAAY;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,mBAAmB,UAAsD;AACvE,QAAI;AACF,YAAM,SAAS,aAAa,UAAU,QAAQ;AAC9C,aAAO,KAAK,6BAA6B,MAAM;AAAA,IACjD,SAAS,OAAO;AACd,aAAO;AAAA,QACL,IAAI,UAAU,6BAA6B,QAAQ,IAAI;AAAA,UACrD,MAAM;AAAA,UACN,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,6BACE,QACoC;AACpC,QAAI;AACF,YAAM,UAAU,KAAK,mBAAmB,KAAK,KAAK,MAAM,CAAC;AACzD,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,UACL,IAAI,UAAU,oCAAoC;AAAA,YAChD,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAAA,MACF;AACA,aAAO,GAAG,KAAK,kBAAkB,OAAO,CAAC;AAAA,IAC3C,SAAS,OAAO;AACd,aAAO;AAAA,QACL,IAAI;AAAA,UACF,uCAAuC,eAAe,KAAK,CAAC;AAAA,UAC5D,EAAE,MAAM,eAAe,OAAO,MAAM;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACpJA,OAAO,YAAY;AACnB,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB,iBAAiB;AAOhD,IAAM,iBAAiB;AACvB,IAAM,aAAa;AACnB,IAAM,SAAS;AACf,IAAM,YAAY;AAMlB,IAAM,oBAAoB;AAU1B,IAAM,aAAN,MAAiB;AAAA,EACf,QAAQ,KAAqB;AAC3B,UAAM,MAAM,IAAI,UAAU,EAAE;AAAA,MAC1B;AAAA,IACF;AACA,UAAM,YAAY,IAAI,qBAAqB,EAAE;AAAA,MAC3C;AAAA,MACA,CAAC;AAAA,IACH;AACA,WAAO,OACJ,WAAW,QAAQ,EACnB,OAAO,WAAW,MAAM,EACxB,OAAO,QAAQ;AAAA,EACpB;AAAA,EAEA,mBAA2B;AACzB,WAAO;AAAA,EACT;AACF;AAOA,IAAM,cAAc,CAAC,QAAmC;AACtD,QAAM,SAAmB,CAAC;AAC1B,QAAM,MAAM,IAAI,UAAU;AAAA,IACxB,cAAc;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,OAAO,CAAC,YAAoB,OAAO,KAAK,OAAO;AAAA,MAC/C,YAAY,CAAC,YAAoB,OAAO,KAAK,OAAO;AAAA,IACtD;AAAA,EACF,CAAC,EAAE,gBAAgB,KAAK,UAAU;AAElC,MAAI,OAAO,QAAQ;AACjB,UAAM,IAAI,MAAM,gBAAgB,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,EACrD;AACA,QAAM,OAAO,IAAI;AACjB,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACA,MAAI,KAAK,aAAa,iBAAiB,KAAK,cAAc,eAAe;AACvE,UAAM,IAAI,MAAM,gBAAgB,KAAK,eAAe,aAAa,EAAE;AAAA,EACrE;AACA,SAAO;AAAA,IACL;AAAA,IACA,UAAU,KAAK,aAAa,KAAK;AAAA,EACnC;AACF;AAGA,IAAM,aAAa,CAAC,SAAqB;AACvC,WAAS,QAAQ,GAAG,QAAQ,KAAK,WAAW,QAAQ,SAAS,GAAG;AAC9D,UAAM,QAAQ,KAAK,WAAW,KAAK;AACnC,QAAI,CAAC,OAAO;AACV;AAAA,IACF;AACA,UAAM,YAAY,MAAM,aAAa;AACrC,UAAM,eACJ,MAAM,aAAa,KAAK,CAAC,KAAK,KAAK,MAAM,aAAa,EAAE;AAC1D,QAAI,aAAa,cAAc;AAC7B,WAAK,YAAY,KAAK;AACtB,eAAS;AAAA,IACX,WAAW,MAAM,aAAa,GAAG;AAC/B,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AACF;AAGO,IAAM,YAAN,MAAgB;AAAA,EACrB,YACmB,YACA,gBACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EAGnB,QACE,KACA,YAC2B;AAC3B,QAAI;AACF,YAAM,EAAE,KAAK,SAAS,IAAI,YAAY,GAAG;AACzC,YAAM,cAAc,cAAc;AAElC,YAAM,MAAM,IAAI,UAAU;AAAA,QACxB,YAAY,KAAK;AAAA,QACjB,YAAY,KAAK;AAAA,QACjB,oBAAoB;AAAA,QACpB,2BAA2B;AAAA,MAC7B,CAAC;AAED,YAAM,iBACJ,IAGA;AACF,qBAAe,iBAAiB,IAAI;AAEpC,UAAI,aAAa;AAAA,QACf,OAAO,sBAAsB,WAAW;AAAA,QACxC,YAAY,CAAC,SAAS;AAAA,QACtB,iBAAiB;AAAA,QACjB,YAAY;AAAA,MACd,CAAwD;AAExD,iBAAW,GAAsB;AACjC,UAAI,iBAAiB,IAAI,SAAS,CAAC;AACnC,aAAO,GAAG,IAAI,aAAa,CAAC;AAAA,IAC9B,SAAS,OAAO;AACd,aAAO;AAAA,QACL,IAAI;AAAA,UACF,uBAAuB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UAC7E,EAAE,MAAM,WAAW,OAAO,MAAM;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAYO,IAAM,yBAAyB,CACpC,QAC6B;AAC7B,MAAI;AACF,UAAM,QAAQ,IAAI,MAAM,gDAAgD;AACxE,QAAI,CAAC,QAAQ,CAAC,GAAG;AACf,aAAO,EAAE,SAAS,OAAO,OAAO,4BAA4B;AAAA,IAC9D;AACA,UAAM,MAAM,OAAO,KAAK,MAAM,CAAC,EAAE,QAAQ,QAAQ,EAAE,GAAG,QAAQ;AAC9D,UAAM,cAAc,IAAI,OAAO,gBAAgB,GAAG;AAClD,UAAM,YAAY,IAAI,KAAK,YAAY,SAAS,EAAE,QAAQ;AAC1D,UAAM,WAAW,IAAI,KAAK,YAAY,OAAO,EAAE,QAAQ;AACvD,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,UAAU,OAAO,aAAa,OAAO;AAC3C,WAAO;AAAA,MACL;AAAA,MACA,SAAS,YAAY;AAAA,MACrB,QAAQ,YAAY;AAAA,MACpB,WAAW,YAAY;AAAA,MACvB,SAAS,YAAY;AAAA,MACrB,OAAO,UAAU,SAAY;AAAA,IAC/B;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D;AAAA,EACF;AACF;;;AC1LA,OAAO,aAAa;AASb,IAAM,cAAN,MAAkB;AAAA,EACvB,SAAS,YAAoB,QAAQ,OAAkC;AACrE,QAAI;AACF,YAAM,OAAgC;AAAA,QACpC,cAAc,EAAE,aAAa,EAAE,SAAS,OAAO,UAAU,QAAQ,EAAE;AAAA,QACnE,GAAG;AAAA,MACL;AAEA,YAAM,MAAM,QAAQ,OAAO,MAAgC;AAAA,QACzD,SAAS;AAAA,QACT,eAAe;AAAA,QACf,QAAQ;AAAA,QACR,qBAAqB;AAAA,QACrB,QAAQ,CAAC,OAAe,UAAkB;AACxC,gBAAM,QAAQ,CAAC,SAAS;AACxB,cACE,aAAa,KAAK,KAAK,KACvB,SACA,CAAC,MAAM,SAAS,MAAM,YAAY,CAAC,GACnC;AACA,mBAAO,WAAW,KAAK,EAAE,QAAQ,CAAC;AAAA,UACpC;AACA,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAED,aAAO,GAAG,GAAG;AAAA,IACf,SAAS,OAAO;AACd,aAAO;AAAA,QACL,IAAI;AAAA,UACF,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACvF,EAAE,MAAM,eAAe,OAAO,MAAM;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,SAAY,KAAmC;AAC7C,QAAI;AACF,YAAM,OAAO,QAAQ,OAAO,KAAK;AAAA,QAC/B,SAAS;AAAA,QACT,eAAe;AAAA,QACf,YAAY;AAAA,MACd,CAAC;AACD,aAAO,GAAG,IAAS;AAAA,IACrB,SAAS,OAAO;AACd,aAAO;AAAA,QACL,IAAI;AAAA,UACF,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACvF,EAAE,MAAM,eAAe,OAAO,MAAM;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACzDO,IAAM,+BAA+B,CAC1C,cAC8B;AAC9B,QAAM,QAAQ,UAAU,MAAM,8CAA8C;AAC5E,QAAM,QAAQ,QAAQ,CAAC,GAAG,KAAK;AAC/B,MAAI,CAAC,OAAO;AACV,WAAO,IAAI,IAAI,UAAU,4BAA4B,EAAE,MAAM,UAAU,CAAC,CAAC;AAAA,EAC3E;AACA,MAAI,MAAM,SAAS,GAAG;AACpB,WAAO;AAAA,MACL,IAAI,UAAU,+BAA+B,EAAE,MAAM,UAAU,CAAC;AAAA,IAClE;AAAA,EACF;AACA,SAAO,GAAG,MAAM,MAAM,GAAG,CAAC,CAAC;AAC7B;AAGO,IAAM,sBAAsB,CACjC,WACA,MACA,YACA,iBACA,QAEA,GAAG,QAAQ,EAAE,IAAI,IAAI,YAAY,CAAC,+BAA+B;AAAA,EAC/D;AACF,CAAC,SAAS,mBAAmB,IAAI,CAAC,eAAe;AAAA,EAC/C,OAAO,UAAU;AACnB,CAAC,oBAAoB,mBAAmB,eAAe,CAAC;AAGnD,IAAM,uBAAuB,CAClC,WACA,cACA,MACA,YACA,cACA,YACA,iBACA,QACW;AACX,MAAI,oBAAoB;AACxB,MAAI,gBAAgB,CAAC,OAAO,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,GAAG;AAC5D,wBAAoB,gBAAgB,mBAAmB,YAAY,CAAC;AAAA,EACtE;AACA,SAAO,GAAG,QAAQ,GAAG,IAAI,IAAI,YAAY,CAAC,6BAA6B;AAAA,IACrE;AAAA,EACF,CAAC,IAAI,iBAAiB,QAAQ;AAAA,IAC5B;AAAA,EACF,CAAC,iBAAiB;AAAA,IAChB;AAAA,EACF,CAAC,eAAe;AAAA,IACd;AAAA,EACF,CAAC,eAAe;AAAA,IACd;AAAA,EACF,CAAC,oBAAoB,mBAAmB,eAAe,CAAC;AAC1D;AAEA,IAAM,uBAAuB,CAAC,MAAY,aAA8B;AACtE,QAAM,QAAQ,IAAI,KAAK,eAAe,SAAS;AAAA,IAC7C,UAAU;AAAA,IACV,KAAK;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,GAAI,WACA,EAAE,MAAM,WAAW,QAAQ,WAAW,QAAQ,WAAW,QAAQ,MAAM,IACvE,CAAC;AAAA,EACP,CAAC,EACE,cAAc,IAAI,EAClB,OAA+B,CAAC,KAAK,SAAS;AAC7C,QAAI,KAAK,IAAI,IAAI,KAAK;AACtB,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEP,QAAM,WAAW,GAAG,MAAM,GAAG,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI;AAC1D,SAAO,WACH,GAAG,QAAQ,IAAI,MAAM,IAAI,IAAI,MAAM,MAAM,IAAI,MAAM,MAAM,KACzD;AACN;AAGO,IAAM,8BAA8B,CAAC,OAAa,oBAAI,KAAK,MAChE,qBAAqB,MAAM,IAAI;AAG1B,IAAM,0BAA0B,CAAC,OAAa,oBAAI,KAAK,MAC5D,qBAAqB,MAAM,KAAK;AAG3B,IAAM,yBAAyB,CACpC,MACA,cAAc,YAEd,KAAK,MAAM,IAAI,OAAO,wBAAwB,WAAW,GAAG,CAAC,IAAI,CAAC;AA2DpE,IAAM,UAAU,CAAI,UAA2C;AAC7D,MAAI,UAAU,UAAa,UAAU,MAAM;AACzC,WAAO,CAAC;AAAA,EACV;AACA,SAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;AAEA,IAAM,gBAAgB,CAAC,UACrB,OAAO,UAAU,YACjB,UAAU,QACV,CAAC,MAAM,QAAQ,KAAK,KACpB,OAAO,KAAK,KAAgC,EAAE,WAAW;AAE3D,IAAM,oBAAoB,CAAC,UAA4B;AACrD,MAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,IAAI;AACzD,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAM,WAAW,MACd,IAAI,iBAAiB,EACrB;AAAA,MACC,CAAC,SACC,SAAS,QACT,SAAS,UACT,SAAS,MACT,CAAC,cAAc,IAAI;AAAA,IACvB;AACF,WAAO,SAAS,SAAS,WAAW;AAAA,EACtC;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,SAAkC,CAAC;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO;AAAA,MAChC;AAAA,IACF,GAAG;AACD,YAAM,UAAU,kBAAkB,KAAK;AACvC,UAAI,YAAY,UAAa,YAAY,MAAM,CAAC,cAAc,OAAO,GAAG;AACtE,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO,OAAO,KAAK,MAAM,EAAE,SAAS,SAAS;AAAA,EAC/C;AACA,SAAO;AACT;AAMO,IAAM,qBAAqB,CAChC,aAC6D;AAC7D,QAAM,eAAe,6BAA6B,QAAQ;AAC1D,MAAI,aAAa,MAAM,GAAG;AACxB,WAAO,IAAI,aAAa,KAAK;AAAA,EAC/B;AAEA,QAAM,cAAc,IAAI,YAAY;AACpC,QAAM,SAAS,YAAY,SAAkB,QAAQ;AACrD,MAAI,OAAO,MAAM,GAAG;AAClB,WAAO,IAAI,OAAO,KAAK;AAAA,EACzB;AAEA,QAAM,aAAa,OAAO,MAAM,IAAI;AACpC,QAAM,YAAY;AAAA,IAChB,YAAY,SAAS,sBAAsB;AAAA,EAC7C;AAEA,QAAM,OAAO,kBAAkB;AAAA,IAC7B,MAAM;AAAA,MACJ,YAAY;AAAA,QACV,SAAS,YAAY;AAAA,QACrB,OAAO;AAAA,UACL,SAAS,YAAY,OAAO;AAAA,UAC5B,MAAM,YAAY,OAAO;AAAA,UACzB,cAAc,YAAY,OAAO;AAAA,UACjC,UAAU,YAAY,OAAO;AAAA,UAC7B,iBAAiB,YAAY,OAAO;AAAA,QACtC;AAAA,QACA,QAAQ;AAAA,UACN,WAAW,YAAY,QAAQ;AAAA,UAC/B,mBAAmB,YAAY,QAAQ;AAAA,UACvC,cAAc,YAAY,QAAQ;AAAA,QACpC;AAAA,QACA,WAAW;AAAA,UACT,cAAc,YAAY,WAAW;AAAA,UACrC,yBACE,YAAY,WAAW;AAAA,UACzB,sBAAsB,YAAY,WAAW;AAAA,QAC/C;AAAA,QACA,SAAS;AAAA,UACP,mBAAmB,YAAY,SAAS;AAAA,UACxC,gBAAgB,YAAY,SAAS;AAAA,UACrC,gBAAgB,YAAY,SAAS;AAAA,UACrC,gBAAgB,YAAY,SAAS;AAAA,UACrC,aAAa,YAAY,SAAS;AAAA,UAClC,YAAY,YAAY,SAAS;AAAA,UACjC,aAAa,YAAY,SAAS;AAAA,UAClC,aAAa,YAAY,SAAS;AAAA,UAClC,aAAa,YAAY,SAAS;AAAA,UAClC,wBAAwB,YAAY,SAAS;AAAA,UAC7C,sBAAsB;AAAA,YACpB,mBAAmB,UAAU,IAAI,CAAC,cAAc;AAAA,cAC9C,cAAc,SAAS;AAAA,cACvB,yCACE,SAAS;AAAA,cACX,wCACE,SAAS;AAAA,cACX,2BAA2B,SAAS;AAAA,YACtC,EAAE;AAAA,UACJ;AAAA,UACA,YAAY,YAAY,SAAS;AAAA,UACjC,mBAAmB,YAAY,SAAS;AAAA,UACxC,cAAc,YAAY,SAAS;AAAA,QACrC;AAAA,QACA,oBAAoB,aAAa;AAAA,MACnC;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,WAAO;AAAA,MACL,IAAI,UAAU,iCAAiC,EAAE,MAAM,aAAa,CAAC;AAAA,IACvE;AAAA,EACF;AAEA,QAAM,MAAM,YAAY,SAAS,IAAI;AACrC,MAAI,IAAI,MAAM,GAAG;AACf,WAAO,IAAI,IAAI,KAAK;AAAA,EACtB;AAEA,SAAO,GAAG,EAAE,KAAK,IAAI,OAAO,cAAc,aAAa,MAAM,CAAC;AAChE;;;ACjSA,SAAS,kBAAkB;AA+C3B,IAAM,qBAAwC,EAAE,SAAS,KAAK;AAE9D,IAAM,sBAAsB,CAAC,UAC3B,OAAO,UAAU,YACjB,UAAU,QACT,MAAgC,YAAY;AAE/C,IAAM,YAAY,CAAC,UACjB,WAAW,QAAQ,EAAE,OAAO,OAAO,MAAM,EAAE,OAAO,KAAK;AAEzD,IAAM,aAAa,CAAC,KAAa,QAAoC;AACnE,QAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,GAAG,aAAa,GAAG,GAAG,CAAC;AAC9D,SAAO,QAAQ,CAAC,GAAG,KAAK;AAC1B;AAKO,IAAM,MAAN,MAAU;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW,oBAAI,IAG9B;AAAA,EAEF,YACE,aACA,mCACA,UAAsB,CAAC,GACvB;AACA,SAAK,cAAc;AACnB,SAAK,cAAc;AACnB,SAAK,cACH,QAAQ,oBAAoB,IAAI,yBAAyB;AAC3D,SAAK,OAAO,IAAI,WAAW;AAAA,MACzB,SAAS,QAAQ;AAAA,MACjB,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,MAC9D,GAAI,QAAQ,eAAe,SACvB,EAAE,YAAY,QAAQ,WAAW,IACjC,CAAC;AAAA,MACL,GAAI,QAAQ,cAAc,SACtB,EAAE,WAAW,QAAQ,UAAU,IAC/B,CAAC;AAAA,MACL,GAAI,QAAQ,cAAc,SACtB,EAAE,WAAW,QAAQ,UAAU,IAC/B,CAAC;AAAA,IACP,CAAC;AAAA,EACH;AAAA,EAEQ,oBAAoB,WAA2B;AACrD,UAAM,MAAM,WAAW,WAAW,WAAW,KAAK;AAClD,UAAM,OAAO,WAAW,WAAW,MAAM,KAAK;AAC9C,WAAO,GAAG,GAAG,IAAI,IAAI,IAAI,UAAU,SAAS,CAAC;AAAA,EAC/C;AAAA,EAEA,MAAc,aACZ,KACA,MAC+B;AAC/B,UAAM,WAAW,KAAK,SAAS,IAAI,GAAG;AACtC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK;AACrB,SAAK,SAAS,IAAI,KAAK,OAA8C;AACrE,QAAI;AACF,aAAO,MAAM;AAAA,IACf,UAAE;AACA,WAAK,SAAS,OAAO,GAAG;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,aACJ,WACuC;AACvC,UAAM,OAAO,MAAM,KAAK,QAAQ,SAAS;AACzC,QAAI,KAAK,MAAM,GAAG;AAChB,aAAO,IAAI,KAAK,KAAK;AAAA,IACvB;AACA,QACE,OAAO,KAAK,YAAY,QAAQ,YAChC,OAAO,KAAK,YAAY,SAAS,UACjC;AACA,aAAO;AAAA,QACL,IAAI;AAAA,UACF;AAAA,UACA,EAAE,MAAM,cAAc;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,IAAI;AAAA,MACjB,KAAK,YAAY;AAAA,MACjB,KAAK,YAAY;AAAA,IACnB,EAAE,QAAQ,KAAK,OAAO,cAAc;AACpC,QAAI,OAAO,MAAM,GAAG;AAClB,aAAO,IAAI,OAAO,KAAK;AAAA,IACzB;AAEA,UAAM,QAAQ,MAAM,KAAK,aAAa,OAAO,OAAO,SAAS;AAC7D,QAAI,MAAM,MAAM,GAAG;AACjB,aAAO,IAAI,MAAM,KAAK;AAAA,IACxB;AACA,SAAK,KAAK,SAAS,MAAM,MAAM,KAAK;AACpC,WAAO,GAAG,MAAM,KAAK;AAAA,EACvB;AAAA,EAEQ,QAAQ,WAAwD;AACtE,QAAI,WAAW;AACb,YAAMC,OAAM;AAAA,QACV;AAAA;AAAA,MAEF;AACA,aAAO,KAAK,KAAK,IAAYA,MAAK,QAAW;AAAA,QAC3C,aAAa;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,MAAM,SAAS,KAAK,iEAA0B;AACpD,WAAO,KAAK,KAAK,IAAY,KAAK,QAAW;AAAA,MAC3C,aAAa;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,aACN,YACA,WACuC;AACvC,UAAM,MAAM,YACR,uBAAuB,0EAA8C,IACrE,SAAS,KAAK,gFAAkC;AACpD,WAAO,KAAK,KAAK,cAAyB,KAAK,cAAc,YAAY;AAAA,MACvE,aAAa;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,uBACJ,WACA,UACA,WAC6C;AAC7C,UAAM,MAAM,KAAK,oBAAoB,SAAS;AAC9C,UAAM,SAAS,MAAM,KAAK,YAAY,IAEpC,GAAG;AACL,QAAI,WAAW,QAAW;AACxB,UAAI,oBAAoB,MAAM,GAAG;AAC/B,eAAO;AAAA,UACL,IAAI;AAAA,YACF;AAAA,YACA,EAAE,MAAM,cAAc;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AACA,aAAO,GAAG,MAAM;AAAA,IAClB;AACA,WAAO,KAAK,aAAa,KAAK,YAAY;AAGxC,YAAM,KAAK,YAAY,IAAI,KAAK,kBAAkB;AAClD,YAAM,MAAM,YACR,uBAAuB,mDAA6C,IACpE,SAAS,KAAK,mEAAiC;AACnD,YAAM,SAAS,MAAM,KAAK,KAAK;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA,EAAE,aAAa,MAAM,iEAA+B;AAAA,MACtD;AACA,UAAI,OAAO,KAAK,GAAG;AACjB,cAAM,KAAK,YAAY,IAAI,KAAK,OAAO,KAAK;AAAA,MAC9C,OAAO;AACL,cAAM,KAAK,YAAY,OAAO,GAAG;AAAA,MACnC;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,YACJ,WACA,UACoD;AACpD,UAAM,MAAM,KAAK,oBAAoB,SAAS;AAC9C,UAAM,SAAS,MAAM,KAAK,YAAY,IAEpC,GAAG;AACL,QAAI,WAAW,QAAW;AACxB,UAAI,oBAAoB,MAAM,GAAG;AAC/B,eAAO;AAAA,UACL,IAAI;AAAA,YACF;AAAA,YACA,EAAE,MAAM,cAAc;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AACA,aAAO,GAAG,MAAM;AAAA,IAClB;AACA,WAAO,KAAK,aAAa,KAAK,YAAY;AAExC,YAAM,KAAK,YAAY,IAAI,KAAK,kBAAkB;AAClD,YAAM,MAAM,SAAS,KAAK,gEAAmC,QAAQ,EAAE;AACvE,YAAM,SAAS,MAAM,KAAK,KAAK;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA,EAAE,aAAa,MAAM,4DAA+B;AAAA,MACtD;AACA,UAAI,OAAO,KAAK,GAAG;AACjB,cAAM,KAAK,YAAY,IAAI,KAAK,OAAO,KAAK;AAAA,MAC9C,OAAO;AACL,cAAM,KAAK,YAAY,OAAO,GAAG;AAAA,MACnC;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,cACE,SACoD;AACpD,UAAM,MAAM,SAAS,KAAK,6EAAuC;AACjE,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA,EAAE,QAAQ;AAAA,MACV,EAAE,aAAa,MAAM,2EAAqC;AAAA,IAC5D;AAAA,EACF;AAAA,EAEA,cACE,WACA,gBACA,cACA,iBACmD;AACnD,UAAM,MAAM,SAAS,KAAK,sEAAmC;AAC7D,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA,EAAE,WAAW,gBAAgB,cAAc,gBAAgB;AAAA,MAC3D,EAAE,aAAa,MAAM,oEAAiC;AAAA,IACxD;AAAA,EACF;AAAA,EAEA,cACE,WACA,MAC6D;AAC7D,UAAM,MAAM,SAAS,KAAK,0EAAoC;AAC9D,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA,EAAE,WAAW,KAAK;AAAA,MAClB,EAAE,aAAa,MAAM,wEAAkC;AAAA,IACzD;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,qBACJ,KACoE;AACpE,UAAM,MAAM,SAAS,KAAK,uFAA+B;AACzD,UAAM,SAAS,MAAM,KAAK,KAAK,IAE7B,KAAK,EAAE,IAAI,GAAG,EAAE,aAAa,MAAM,qFAA6B,CAAC;AACnE,QAAI,OAAO,MAAM,GAAG;AAClB,aAAO,IAAI,OAAO,KAAK;AAAA,IACzB;AACA,UAAM,OAAO,OAAO;AACpB,QAAI,SAAS,UAAa,SAAS,MAAM;AACvC,aAAO,GAAG,MAAS;AAAA,IACrB;AACA,WAAO,GAAG,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;AAAA,EAC/C;AAAA;AAAA,EAGA,yBACE,KACA,MACA,cACmD;AACnD,UAAM,MAAM;AAAA,MACV,KAAK;AAAA;AAAA,MAEL,QAAQ;AAAA,IACV;AACA,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA,EAAE,YAAY,KAAK,MAAM,mBAAmB,aAAa;AAAA,MACzD,EAAE,aAAa,MAAM,4EAAyC;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,uBACE,WACA,UACwD;AACxD,UAAM,MAAM,SAAS,KAAK,mFAAwC;AAClE,WAAO,KAAK,KAAK;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,aAAa,MAAM,iFAAsC;AAAA,IAC7D;AAAA,EACF;AAAA,EAEA,SACE,WACA,UAC6C;AAC7C,UAAM,MAAM,SAAS,KAAK,qEAA0B;AACpD,WAAO,KAAK,KAAK,cAA+B,KAAK,UAAU,WAAW;AAAA,MACxE,aAAa;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AACF;","names":["Environment","Endpoint","SenderReceiverEndpoint","TrackStatusEnum","err","url"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deuriib/dgii-ecf",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "DGII e-CF electronic invoicing SDK for the Dominican Republic — authenticate, sign (XMLDSig/C14N) and transmit electronic tax documents. Bun-first, native fetch, result-pattern.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"url": "git+https://github.com/deuriib/dgii-ecf.git",
|
|
11
11
|
"directory": "packages/typescript"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://github.
|
|
13
|
+
"homepage": "https://deuriib.github.io/dgii-ecf/",
|
|
14
14
|
"keywords": [
|
|
15
15
|
"dgii",
|
|
16
16
|
"ecf",
|