@deuriib/dgii-ecf 0.2.1 → 0.2.3

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 CHANGED
@@ -521,17 +521,15 @@ var P12Reader = class {
521
521
  return import_node_forge.default.pkcs12.pkcs12FromAsn1(asn1, false, this.passphrase);
522
522
  }
523
523
  extractKey(p12) {
524
- const keyBags = p12.getBags({
525
- bagType: import_node_forge.default.pki.oids.pkcs8ShroudedKeyBag
526
- });
527
- const pkcs8Key = keyBags[import_node_forge.default.pki.oids.pkcs8ShroudedKeyBag]?.[0];
528
- if (pkcs8Key?.key) {
529
- return import_node_forge.default.pki.privateKeyToPem(pkcs8Key.key);
530
- }
531
- const certBags = p12.getBags({ bagType: import_node_forge.default.pki.oids.certBag });
532
- const certBag = certBags[import_node_forge.default.pki.oids.certBag]?.[0];
533
- if (certBag?.key) {
534
- return import_node_forge.default.pki.privateKeyToPem(certBag.key);
524
+ const keyBagTypes = [
525
+ import_node_forge.default.pki.oids.pkcs8ShroudedKeyBag,
526
+ import_node_forge.default.pki.oids.keyBag
527
+ ];
528
+ for (const bagType of keyBagTypes) {
529
+ const bag = p12.getBags({ bagType })[bagType]?.[0];
530
+ if (bag?.key) {
531
+ return import_node_forge.default.pki.privateKeyToPem(bag.key);
532
+ }
535
533
  }
536
534
  return void 0;
537
535
  }
@@ -634,25 +632,17 @@ var C14N_INCLUSIVE = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
634
632
  var RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
635
633
  var SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256";
636
634
  var ENVELOPED = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
637
- var CUSTOM_DIGEST_URI = "http://dgii.gov.do/digest/sha256-sorted";
638
- var DgiiDigest = class _DgiiDigest {
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
- }
635
+ var CUSTOM_DIGEST_URI = "http://dgii.gov.do/digest/sha256-c14n";
636
+ var DgiiDigest = class {
646
637
  getHash(xml) {
647
638
  const doc = new import_xmldom.DOMParser().parseFromString(
648
639
  xml
649
640
  );
650
- const root = doc.childNodes[0];
651
- if (root?.attributes) {
652
- const sorted = _DgiiDigest.sortAttributes(root.attributes);
653
- Object.assign(root.attributes, sorted);
654
- }
655
- return import_node_crypto.default.createHash("sha256").update(doc.toString(), "utf8").digest("base64");
641
+ const canonical = new import_xml_crypto.C14nCanonicalization().process(
642
+ doc,
643
+ {}
644
+ );
645
+ return import_node_crypto.default.createHash("sha256").update(canonical, "utf8").digest("base64");
656
646
  }
657
647
  getAlgorithmName() {
658
648
  return SHA256;
@@ -706,8 +696,19 @@ var Signature = class {
706
696
  privateKey;
707
697
  certificatePem;
708
698
  signXml(xml, rootElName) {
699
+ let parsed;
709
700
  try {
710
- const { doc, rootName } = parseStrict(xml);
701
+ parsed = parseStrict(xml);
702
+ } catch (error) {
703
+ return (0, import_neverthrow.err)(
704
+ new DgiiError(
705
+ error instanceof Error ? error.message : `Invalid XML: ${String(error)}`,
706
+ { code: "INVALID_XML", cause: error }
707
+ )
708
+ );
709
+ }
710
+ try {
711
+ const { doc, rootName } = parsed;
711
712
  const elementName = rootElName ?? rootName;
712
713
  const sig = new import_xml_crypto.SignedXml({
713
714
  privateKey: this.privateKey,
@@ -736,9 +737,10 @@ var Signature = class {
736
737
  }
737
738
  }
738
739
  };
740
+ var X509_CERTIFICATE_RE = /<(?:[\w]+:)?X509Certificate>([\s\S]*?)<\/(?:[\w]+:)?X509Certificate>/;
739
741
  var validateXMLCertificate = (xml) => {
740
742
  try {
741
- const match = xml.match(/<X509Certificate>([\s\S]*?)<\/X509Certificate>/);
743
+ const match = xml.match(X509_CERTIFICATE_RE);
742
744
  if (!match?.[1]) {
743
745
  return { isValid: false, error: "X509Certificate not found" };
744
746
  }
@@ -816,8 +818,9 @@ var Transformer = class {
816
818
  };
817
819
 
818
820
  // src/utils.ts
821
+ var SIGNATURE_VALUE_RE = /<(?:[\w]+:)?SignatureValue>([\s\S]*?)<\/(?:[\w]+:)?SignatureValue>/;
819
822
  var getCodeSixDigitfromSignature = (signedXml) => {
820
- const match = signedXml.match(/<SignatureValue>([\s\S]*?)<\/SignatureValue>/);
823
+ const match = signedXml.match(SIGNATURE_VALUE_RE);
821
824
  const value = match?.[1]?.trim();
822
825
  if (!value) {
823
826
  return (0, import_neverthrow.err)(new DgiiError("SignatureValue not found", { code: "SIGNING" }));
@@ -975,6 +978,8 @@ var convertECF32ToRFCE = (ecf32Xml) => {
975
978
 
976
979
  // src/client.ts
977
980
  var import_node_crypto2 = require("crypto");
981
+ var PENDING_SUBMISSION = { pending: true };
982
+ var isPendingSubmission = (value) => typeof value === "object" && value !== null && value.pending === true;
978
983
  var sha256Hex = (value) => (0, import_node_crypto2.createHash)("sha256").update(value, "utf8").digest("hex");
979
984
  var extractTag = (xml, tag) => {
980
985
  const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));
@@ -1075,10 +1080,19 @@ var ECF = class {
1075
1080
  async sendElectronicDocument(signedXml, fileName, buyerHost) {
1076
1081
  const key = this.buildIdempotencyKey(signedXml);
1077
1082
  const cached = await this.idempotency.get(key);
1078
- if (cached) {
1083
+ if (cached !== void 0) {
1084
+ if (isPendingSubmission(cached)) {
1085
+ return (0, import_neverthrow.err)(
1086
+ new DgiiError(
1087
+ "A submission with this key is already pending; reconcile via a status lookup before retrying",
1088
+ { code: "IDEMPOTENCY" }
1089
+ )
1090
+ );
1091
+ }
1079
1092
  return (0, import_neverthrow.ok)(cached);
1080
1093
  }
1081
1094
  return this.singleFlight(key, async () => {
1095
+ await this.idempotency.set(key, PENDING_SUBMISSION);
1082
1096
  const url = buyerHost ? buildSenderReceiverUrl(buyerHost, "fe/recepcion/api/ecf" /* SendInvoice */) : buildUrl(this.environment, "recepcion/api/FacturasElectronicas" /* SendInvoice */);
1083
1097
  const result = await this.http.postMultipart(
1084
1098
  url,
@@ -1088,6 +1102,8 @@ var ECF = class {
1088
1102
  );
1089
1103
  if (result.isOk()) {
1090
1104
  await this.idempotency.set(key, result.value);
1105
+ } else {
1106
+ await this.idempotency.delete(key);
1091
1107
  }
1092
1108
  return result;
1093
1109
  });
@@ -1096,10 +1112,19 @@ var ECF = class {
1096
1112
  async sendSummary(signedXml, fileName) {
1097
1113
  const key = this.buildIdempotencyKey(signedXml);
1098
1114
  const cached = await this.idempotency.get(key);
1099
- if (cached) {
1115
+ if (cached !== void 0) {
1116
+ if (isPendingSubmission(cached)) {
1117
+ return (0, import_neverthrow.err)(
1118
+ new DgiiError(
1119
+ "A submission with this key is already pending; reconcile via a status lookup before retrying",
1120
+ { code: "IDEMPOTENCY" }
1121
+ )
1122
+ );
1123
+ }
1100
1124
  return (0, import_neverthrow.ok)(cached);
1101
1125
  }
1102
1126
  return this.singleFlight(key, async () => {
1127
+ await this.idempotency.set(key, PENDING_SUBMISSION);
1103
1128
  const url = buildUrl(this.environment, "recepcionfc/api/recepcion/ecf" /* SendSummary */, BaseUrl.CF);
1104
1129
  const result = await this.http.postMultipart(
1105
1130
  url,
@@ -1109,6 +1134,8 @@ var ECF = class {
1109
1134
  );
1110
1135
  if (result.isOk()) {
1111
1136
  await this.idempotency.set(key, result.value);
1137
+ } else {
1138
+ await this.idempotency.delete(key);
1112
1139
  }
1113
1140
  return result;
1114
1141
  });
@@ -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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,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,wBAWO;;;AChBP,uBAYO;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,kBAAc,4BAAM,6BAAW,gBAAgB,GAAG;AAAA,IACtD,aAAa,KAAK;AAAA,IAClB,SAAS,IAAI,oCAAmB,EAAE,cAAc,KAAK,oBAAoB,CAAC;AAAA,EAC5E,CAAC;AAED,QAAM,oBAAgB,iCAAe,4BAAW;AAAA,IAC9C,eAAe,KAAK;AAAA,IACpB,SAAS,IAAI,oCAAmB,KAAK,gBAAgB;AAAA,EACvD,CAAC;AAED,QAAM,oBAAgB,0BAAQ,KAAK,WAAW,iCAAgB,UAAU;AACxE,QAAM,qBAAiB,2BAAS,KAAK,eAAe,KAAK,aAAa;AAEtE,QAAM,aAAS;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,iBAAO,sBAAG,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,eAAO,uBAAI,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,iBAAO,uBAAI,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,qBAA6B;AAC7B,wBAAkB;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,kBAAAC,QAAM,KAAK,SAAS,MAAM;AACtC,UAAM,OAAO,kBAAAA,QAAM,KAAK,QAAQ,GAAG;AACnC,WAAO,kBAAAA,QAAM,OAAO,eAAe,MAAM,OAAO,KAAK,UAAU;AAAA,EACjE;AAAA,EAEQ,WAAW,KAAiD;AAClE,UAAM,UAAU,IAAI,QAAQ;AAAA,MAC1B,SAAS,kBAAAA,QAAM,IAAI,KAAK;AAAA,IAC1B,CAAC;AACD,UAAM,WAAW,QAAQ,kBAAAA,QAAM,IAAI,KAAK,mBAAmB,IAAI,CAAC;AAChE,QAAI,UAAU,KAAK;AACjB,aAAO,kBAAAA,QAAM,IAAI,gBAAgB,SAAS,GAAG;AAAA,IAC/C;AACA,UAAM,WAAW,IAAI,QAAQ,EAAE,SAAS,kBAAAA,QAAM,IAAI,KAAK,QAAQ,CAAC;AAChE,UAAM,UAAU,SAAS,kBAAAA,QAAM,IAAI,KAAK,OAAO,IAAI,CAAC;AACpD,QAAI,SAAS,KAAK;AAChB,aAAO,kBAAAA,QAAM,IAAI,gBAAgB,QAAQ,GAAG;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB,KAAiD;AAC1E,UAAM,WAAW,IAAI,QAAQ,EAAE,SAAS,kBAAAA,QAAM,IAAI,KAAK,QAAQ,CAAC;AAChE,UAAM,UAAU,SAAS,kBAAAA,QAAM,IAAI,KAAK,OAAO,IAAI,CAAC;AACpD,QAAI,CAAC,SAAS,MAAM;AAClB,aAAO;AAAA,IACT;AACA,WAAO,kBAAAA,QAAM,IAAI,iBAAiB,QAAQ,IAAI;AAAA,EAChD;AAAA,EAEA,eAAe,UAAoD;AACjE,QAAI;AACF,YAAM,aAAS,6BAAa,UAAU,QAAQ;AAC9C,aAAO,KAAK,uBAAuB,MAAM;AAAA,IAC3C,SAAS,OAAO;AACd,iBAAO;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,mBAAO;AAAA,UACL,IAAI,UAAU,sDAAsD;AAAA,YAClE,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAAA,MACF;AACA,YAAM,YAAY,kBAAAA,QAAM,IAAI;AAAA,QAC1B,kBAAAA,QAAM,IAAI,mBAAmB,IAAI,EAAE;AAAA,MACrC;AACA,iBAAO,sBAAG,EAAE,KAAK,MAAM,UAAU,CAAC;AAAA,IACpC,SAAS,OAAO;AACd,iBAAO;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,kBAAAA,QAAM,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,aAAS,6BAAa,UAAU,QAAQ;AAC9C,aAAO,KAAK,6BAA6B,MAAM;AAAA,IACjD,SAAS,OAAO;AACd,iBAAO;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,mBAAO;AAAA,UACL,IAAI,UAAU,oCAAoC;AAAA,YAChD,MAAM;AAAA,UACR,CAAC;AAAA,QACH;AAAA,MACF;AACA,iBAAO,sBAAG,KAAK,kBAAkB,OAAO,CAAC;AAAA,IAC3C,SAAS,OAAO;AACd,iBAAO;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,yBAAmB;AACnB,oBAA0B;AAC1B,wBAA0B;AAO1B,IAAM,iBAAiB;AACvB,IAAM,aAAa;AACnB,IAAM,SAAS;AACf,IAAM,YAAY;AAMlB,IAAM,oBAAoB;AAU1B,IAAM,aAAN,MAAM,YAAW;AAAA,EACf,OAAe,eAAe,YAAkC;AAC9D,WAAO,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM;AAC3C,YAAM,OAAO,GAAG,EAAE,IAAI,KAAK,EAAE,KAAK;AAClC,YAAM,QAAQ,GAAG,EAAE,IAAI,KAAK,EAAE,KAAK;AACnC,aAAO,OAAO,QAAQ,KAAK,OAAO,QAAQ,IAAI;AAAA,IAChD,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,KAAqB;AAC3B,UAAM,MAAM,IAAI,wBAAU,EAAE;AAAA,MAC1B;AAAA,IACF;AACA,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,QAAI,MAAM,YAAY;AACpB,YAAM,SAAS,YAAW,eAAe,KAAK,UAA0B;AACxE,aAAO,OAAO,KAAK,YAAY,MAAM;AAAA,IACvC;AACA,WAAO,mBAAAC,QACJ,WAAW,QAAQ,EACnB,OAAO,IAAI,SAAS,GAAG,MAAM,EAC7B,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,wBAAU;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,4BAAU;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,iBAAO,sBAAG,IAAI,aAAa,CAAC;AAAA,IAC9B,SAAS,OAAO;AACd,iBAAO;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,mBAAAA,QAAO,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;;;ACnMA,oBAAoB;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,cAAAC,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,iBAAO,sBAAG,GAAG;AAAA,IACf,SAAS,OAAO;AACd,iBAAO;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,cAAAA,QAAQ,OAAO,KAAK;AAAA,QAC/B,SAAS;AAAA,QACT,eAAe;AAAA,QACf,YAAY;AAAA,MACd,CAAC;AACD,iBAAO,sBAAG,IAAS;AAAA,IACrB,SAAS,OAAO;AACd,iBAAO;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,eAAO,uBAAI,IAAI,UAAU,4BAA4B,EAAE,MAAM,UAAU,CAAC,CAAC;AAAA,EAC3E;AACA,MAAI,MAAM,SAAS,GAAG;AACpB,eAAO;AAAA,MACL,IAAI,UAAU,+BAA+B,EAAE,MAAM,UAAU,CAAC;AAAA,IAClE;AAAA,EACF;AACA,aAAO,sBAAG,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,eAAO,uBAAI,aAAa,KAAK;AAAA,EAC/B;AAEA,QAAM,cAAc,IAAI,YAAY;AACpC,QAAM,SAAS,YAAY,SAAkB,QAAQ;AACrD,MAAI,OAAO,MAAM,GAAG;AAClB,eAAO,uBAAI,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,eAAO;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,eAAO,uBAAI,IAAI,KAAK;AAAA,EACtB;AAEA,aAAO,sBAAG,EAAE,KAAK,IAAI,OAAO,cAAc,aAAa,MAAM,CAAC;AAChE;;;ACjSA,IAAAC,sBAA2B;AA2C3B,IAAM,YAAY,CAAC,cACjB,gCAAW,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,iBAAO,uBAAI,KAAK,KAAK;AAAA,IACvB;AACA,QACE,OAAO,KAAK,YAAY,QAAQ,YAChC,OAAO,KAAK,YAAY,SAAS,UACjC;AACA,iBAAO;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,iBAAO,uBAAI,OAAO,KAAK;AAAA,IACzB;AAEA,UAAM,QAAQ,MAAM,KAAK,aAAa,OAAO,OAAO,SAAS;AAC7D,QAAI,MAAM,MAAM,GAAG;AACjB,iBAAO,uBAAI,MAAM,KAAK;AAAA,IACxB;AACA,SAAK,KAAK,SAAS,MAAM,MAAM,KAAK;AACpC,eAAO,sBAAG,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,IAAqB,GAAG;AAC9D,QAAI,QAAQ;AACV,iBAAO,sBAAG,MAAM;AAAA,IAClB;AACA,WAAO,KAAK,aAAa,KAAK,YAAY;AACxC,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;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,IAA4B,GAAG;AACrE,QAAI,QAAQ;AACV,iBAAO,sBAAG,MAAM;AAAA,IAClB;AACA,WAAO,KAAK,aAAa,KAAK,YAAY;AACxC,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;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,iBAAO,uBAAI,OAAO,KAAK;AAAA,IACzB;AACA,UAAM,OAAO,OAAO;AACpB,QAAI,SAAS,UAAa,SAAS,MAAM;AACvC,iBAAO,sBAAG,MAAS;AAAA,IACrB;AACA,eAAO,sBAAG,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","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 // DGII bundles normally carry a shrouded (encrypted) PKCS#8 key bag, but\n // unencrypted bundles use a plain keyBag. A certBag never holds a private\n // key, so it must not be used as a fallback.\n const keyBagTypes = [\n forge.pki.oids.pkcs8ShroudedKeyBag,\n forge.pki.oids.keyBag,\n ];\n for (const bagType of keyBagTypes) {\n const bag = p12.getBags({ bagType })[bagType]?.[0];\n if (bag?.key) {\n return forge.pki.privateKeyToPem(bag.key);\n }\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 let parsed: StrictParseResult;\n try {\n parsed = parseStrict(xml);\n } catch (error) {\n // Malformed input is an INVALID_XML error, not a signing failure —\n // aligning with the Python SDK.\n return err(\n new DgiiError(\n error instanceof Error\n ? error.message\n : `Invalid XML: ${String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n\n try {\n const { doc, rootName } = parsed;\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/**\n * Matches `<X509Certificate>` with or without a namespace prefix (`ds:`).\n */\nconst X509_CERTIFICATE_RE =\n /<(?:[\\w]+:)?X509Certificate>([\\s\\S]*?)<\\/(?:[\\w]+:)?X509Certificate>/;\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(X509_CERTIFICATE_RE);\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/**\n * Matches `<SignatureValue>` with or without a namespace prefix (`ds:`), which\n * is how .NET and other XMLDSig implementations emit the signature.\n */\nconst SIGNATURE_VALUE_RE =\n /<(?:[\\w]+:)?SignatureValue>([\\s\\S]*?)<\\/(?:[\\w]+:)?SignatureValue>/;\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(SIGNATURE_VALUE_RE);\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
@@ -470,17 +470,15 @@ var P12Reader = class {
470
470
  return forge.pkcs12.pkcs12FromAsn1(asn1, false, this.passphrase);
471
471
  }
472
472
  extractKey(p12) {
473
- const keyBags = p12.getBags({
474
- bagType: forge.pki.oids.pkcs8ShroudedKeyBag
475
- });
476
- const pkcs8Key = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag]?.[0];
477
- if (pkcs8Key?.key) {
478
- return forge.pki.privateKeyToPem(pkcs8Key.key);
479
- }
480
- const certBags = p12.getBags({ bagType: forge.pki.oids.certBag });
481
- const certBag = certBags[forge.pki.oids.certBag]?.[0];
482
- if (certBag?.key) {
483
- return forge.pki.privateKeyToPem(certBag.key);
473
+ const keyBagTypes = [
474
+ forge.pki.oids.pkcs8ShroudedKeyBag,
475
+ forge.pki.oids.keyBag
476
+ ];
477
+ for (const bagType of keyBagTypes) {
478
+ const bag = p12.getBags({ bagType })[bagType]?.[0];
479
+ if (bag?.key) {
480
+ return forge.pki.privateKeyToPem(bag.key);
481
+ }
484
482
  }
485
483
  return void 0;
486
484
  }
@@ -578,30 +576,22 @@ var P12Reader = class {
578
576
  // src/signing.ts
579
577
  import crypto from "crypto";
580
578
  import { DOMParser } from "@xmldom/xmldom";
581
- import { SignedXml } from "xml-crypto";
579
+ import { C14nCanonicalization, SignedXml } from "xml-crypto";
582
580
  var C14N_INCLUSIVE = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
583
581
  var RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
584
582
  var SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256";
585
583
  var ENVELOPED = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
586
- var CUSTOM_DIGEST_URI = "http://dgii.gov.do/digest/sha256-sorted";
587
- var DgiiDigest = class _DgiiDigest {
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
- }
584
+ var CUSTOM_DIGEST_URI = "http://dgii.gov.do/digest/sha256-c14n";
585
+ var DgiiDigest = class {
595
586
  getHash(xml) {
596
587
  const doc = new DOMParser().parseFromString(
597
588
  xml
598
589
  );
599
- const root = doc.childNodes[0];
600
- if (root?.attributes) {
601
- const sorted = _DgiiDigest.sortAttributes(root.attributes);
602
- Object.assign(root.attributes, sorted);
603
- }
604
- return crypto.createHash("sha256").update(doc.toString(), "utf8").digest("base64");
590
+ const canonical = new C14nCanonicalization().process(
591
+ doc,
592
+ {}
593
+ );
594
+ return crypto.createHash("sha256").update(canonical, "utf8").digest("base64");
605
595
  }
606
596
  getAlgorithmName() {
607
597
  return SHA256;
@@ -655,8 +645,19 @@ var Signature = class {
655
645
  privateKey;
656
646
  certificatePem;
657
647
  signXml(xml, rootElName) {
648
+ let parsed;
658
649
  try {
659
- const { doc, rootName } = parseStrict(xml);
650
+ parsed = parseStrict(xml);
651
+ } catch (error) {
652
+ return err(
653
+ new DgiiError(
654
+ error instanceof Error ? error.message : `Invalid XML: ${String(error)}`,
655
+ { code: "INVALID_XML", cause: error }
656
+ )
657
+ );
658
+ }
659
+ try {
660
+ const { doc, rootName } = parsed;
660
661
  const elementName = rootElName ?? rootName;
661
662
  const sig = new SignedXml({
662
663
  privateKey: this.privateKey,
@@ -685,9 +686,10 @@ var Signature = class {
685
686
  }
686
687
  }
687
688
  };
689
+ var X509_CERTIFICATE_RE = /<(?:[\w]+:)?X509Certificate>([\s\S]*?)<\/(?:[\w]+:)?X509Certificate>/;
688
690
  var validateXMLCertificate = (xml) => {
689
691
  try {
690
- const match = xml.match(/<X509Certificate>([\s\S]*?)<\/X509Certificate>/);
692
+ const match = xml.match(X509_CERTIFICATE_RE);
691
693
  if (!match?.[1]) {
692
694
  return { isValid: false, error: "X509Certificate not found" };
693
695
  }
@@ -765,8 +767,9 @@ var Transformer = class {
765
767
  };
766
768
 
767
769
  // src/utils.ts
770
+ var SIGNATURE_VALUE_RE = /<(?:[\w]+:)?SignatureValue>([\s\S]*?)<\/(?:[\w]+:)?SignatureValue>/;
768
771
  var getCodeSixDigitfromSignature = (signedXml) => {
769
- const match = signedXml.match(/<SignatureValue>([\s\S]*?)<\/SignatureValue>/);
772
+ const match = signedXml.match(SIGNATURE_VALUE_RE);
770
773
  const value = match?.[1]?.trim();
771
774
  if (!value) {
772
775
  return err(new DgiiError("SignatureValue not found", { code: "SIGNING" }));
@@ -924,6 +927,8 @@ var convertECF32ToRFCE = (ecf32Xml) => {
924
927
 
925
928
  // src/client.ts
926
929
  import { createHash } from "crypto";
930
+ var PENDING_SUBMISSION = { pending: true };
931
+ var isPendingSubmission = (value) => typeof value === "object" && value !== null && value.pending === true;
927
932
  var sha256Hex = (value) => createHash("sha256").update(value, "utf8").digest("hex");
928
933
  var extractTag = (xml, tag) => {
929
934
  const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));
@@ -1024,10 +1029,19 @@ var ECF = class {
1024
1029
  async sendElectronicDocument(signedXml, fileName, buyerHost) {
1025
1030
  const key = this.buildIdempotencyKey(signedXml);
1026
1031
  const cached = await this.idempotency.get(key);
1027
- if (cached) {
1032
+ if (cached !== void 0) {
1033
+ if (isPendingSubmission(cached)) {
1034
+ return err(
1035
+ new DgiiError(
1036
+ "A submission with this key is already pending; reconcile via a status lookup before retrying",
1037
+ { code: "IDEMPOTENCY" }
1038
+ )
1039
+ );
1040
+ }
1028
1041
  return ok(cached);
1029
1042
  }
1030
1043
  return this.singleFlight(key, async () => {
1044
+ await this.idempotency.set(key, PENDING_SUBMISSION);
1031
1045
  const url = buyerHost ? buildSenderReceiverUrl(buyerHost, "fe/recepcion/api/ecf" /* SendInvoice */) : buildUrl(this.environment, "recepcion/api/FacturasElectronicas" /* SendInvoice */);
1032
1046
  const result = await this.http.postMultipart(
1033
1047
  url,
@@ -1037,6 +1051,8 @@ var ECF = class {
1037
1051
  );
1038
1052
  if (result.isOk()) {
1039
1053
  await this.idempotency.set(key, result.value);
1054
+ } else {
1055
+ await this.idempotency.delete(key);
1040
1056
  }
1041
1057
  return result;
1042
1058
  });
@@ -1045,10 +1061,19 @@ var ECF = class {
1045
1061
  async sendSummary(signedXml, fileName) {
1046
1062
  const key = this.buildIdempotencyKey(signedXml);
1047
1063
  const cached = await this.idempotency.get(key);
1048
- if (cached) {
1064
+ if (cached !== void 0) {
1065
+ if (isPendingSubmission(cached)) {
1066
+ return err(
1067
+ new DgiiError(
1068
+ "A submission with this key is already pending; reconcile via a status lookup before retrying",
1069
+ { code: "IDEMPOTENCY" }
1070
+ )
1071
+ );
1072
+ }
1049
1073
  return ok(cached);
1050
1074
  }
1051
1075
  return this.singleFlight(key, async () => {
1076
+ await this.idempotency.set(key, PENDING_SUBMISSION);
1052
1077
  const url = buildUrl(this.environment, "recepcionfc/api/recepcion/ecf" /* SendSummary */, BaseUrl.CF);
1053
1078
  const result = await this.http.postMultipart(
1054
1079
  url,
@@ -1058,6 +1083,8 @@ var ECF = class {
1058
1083
  );
1059
1084
  if (result.isOk()) {
1060
1085
  await this.idempotency.set(key, result.value);
1086
+ } else {
1087
+ await this.idempotency.delete(key);
1061
1088
  }
1062
1089
  return result;
1063
1090
  });
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 // DGII bundles normally carry a shrouded (encrypted) PKCS#8 key bag, but\n // unencrypted bundles use a plain keyBag. A certBag never holds a private\n // key, so it must not be used as a fallback.\n const keyBagTypes = [\n forge.pki.oids.pkcs8ShroudedKeyBag,\n forge.pki.oids.keyBag,\n ];\n for (const bagType of keyBagTypes) {\n const bag = p12.getBags({ bagType })[bagType]?.[0];\n if (bag?.key) {\n return forge.pki.privateKeyToPem(bag.key);\n }\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 let parsed: StrictParseResult;\n try {\n parsed = parseStrict(xml);\n } catch (error) {\n // Malformed input is an INVALID_XML error, not a signing failure —\n // aligning with the Python SDK.\n return err(\n new DgiiError(\n error instanceof Error\n ? error.message\n : `Invalid XML: ${String(error)}`,\n { code: 'INVALID_XML', cause: error },\n ),\n );\n }\n\n try {\n const { doc, rootName } = parsed;\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/**\n * Matches `<X509Certificate>` with or without a namespace prefix (`ds:`).\n */\nconst X509_CERTIFICATE_RE =\n /<(?:[\\w]+:)?X509Certificate>([\\s\\S]*?)<\\/(?:[\\w]+:)?X509Certificate>/;\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(X509_CERTIFICATE_RE);\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/**\n * Matches `<SignatureValue>` with or without a namespace prefix (`ds:`), which\n * is how .NET and other XMLDSig implementations emit the signature.\n */\nconst SIGNATURE_VALUE_RE =\n /<(?:[\\w]+:)?SignatureValue>([\\s\\S]*?)<\\/(?:[\\w]+:)?SignatureValue>/;\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(SIGNATURE_VALUE_RE);\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","url"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deuriib/dgii-ecf",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
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.com/deuriib/dgii-ecf/tree/main/packages/typescript",
13
+ "homepage": "https://deuriib.github.io/dgii-ecf/",
14
14
  "keywords": [
15
15
  "dgii",
16
16
  "ecf",