@deuriib/dgii-ecf 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +107 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -3
- package/dist/index.d.ts +38 -3
- package/dist/index.js +107 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/types.ts","../src/errors.ts","../src/result.ts","../src/resilience.ts","../src/http.ts","../src/certificate.ts","../src/signing.ts","../src/transformer.ts","../src/xml.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\nconst MONETARY_RE = /^(-?)(\\d+)\\.(\\d+)$/;\n\n/** Increment a string of decimal digits (\"267\" -> \"268\", \"999\" -> \"1000\"). */\nconst incrementDigits = (digits: string): string => {\n const chars = digits.split('');\n let index = chars.length - 1;\n while (index >= 0) {\n const current = chars[index];\n if (current === '9') {\n chars[index] = '0';\n index -= 1;\n continue;\n }\n chars[index] = String(Number(current) + 1);\n return chars.join('');\n }\n return `1${chars.join('')}`;\n};\n\n/**\n * Round a decimal string to 2 places with ROUND_HALF_UP semantics.\n *\n * `Number.prototype.toFixed` cannot be used: `(2.675).toFixed(2)` is `'2.67'`\n * because the literal is not representable in binary floating point. DGII\n * expects the decimal, half-up result (`'2.68'`) — the same contract as the\n * Python SDK's `Decimal.quantize(..., rounding=ROUND_HALF_UP)`.\n *\n * Values that are not plain decimals (e.g. `1.0e3`) are returned unchanged.\n */\nexport const roundHalfUpToCents = (value: string): string => {\n const match = MONETARY_RE.exec(value);\n if (!match) {\n return value;\n }\n const sign = match[1] === '-' ? '-' : '';\n const integerPart = (match[2] ?? '0').replace(/^0+(?=\\d)/, '');\n const fractionPart = `${match[3] ?? ''}000`;\n const cents = `${integerPart}${fractionPart.slice(0, 2)}`;\n const rounded = fractionPart[2] >= '5' ? incrementDigits(cents) : cents;\n const padded = rounded.padStart(3, '0');\n return `${sign}${padded.slice(0, -2)}.${padded.slice(-2)}`;\n};\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 if (round && label.toLowerCase() !== 'version') {\n return roundHalfUpToCents(value);\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","/**\n * Tolerant element-text extraction for signed DGII XML.\n *\n * The SDK never owns the XML it inspects: DGII responses, .NET-produced\n * signatures, and third-party generators all wrap the same element in a\n * namespace prefix and add attributes to it. A literal `<tag>` match misses\n * those variants and silently degrades the caller to a fallback — which on the\n * idempotency path means a duplicate fiscal submission.\n */\n\nconst PATTERN_CACHE = new Map<string, RegExp>();\n\n/**\n * Attribute spans may contain `>` inside quotes (`nota=\"a > b\"`), so both\n * quoted forms get their own alternative instead of a blanket `[^>]*`.\n */\nconst ATTRIBUTE_SPAN = `(?:[^>\"']|\"[^\"]*\"|'[^']*')*`;\n\nconst escapeRegExp = (value: string): string =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nconst elementPattern = (tag: string): RegExp => {\n const cached = PATTERN_CACHE.get(tag);\n if (cached !== undefined) {\n return cached;\n }\n const name = escapeRegExp(tag);\n const prefix = '(?:[\\\\w.-]+:)?';\n const pattern = new RegExp(\n `<${prefix}${name}${ATTRIBUTE_SPAN}>([\\\\s\\\\S]*?)<\\\\/${prefix}${name}\\\\s*>`,\n );\n PATTERN_CACHE.set(tag, pattern);\n return pattern;\n};\n\n/**\n * Text content of the first `<tag>` element, tolerating a namespace prefix\n * (`ns:eNCF`) and attributes (`<eNCF version=\"1.0\">`).\n *\n * Returns `undefined` when the element is absent, self-closing, or blank, so\n * callers fall back deliberately instead of building a key out of an empty\n * segment. Matching is case-sensitive, as XML element names are.\n */\nexport const extractElementText = (\n xml: string,\n tag: string,\n): string | undefined => {\n const match = elementPattern(tag).exec(xml);\n const text = match?.[1]?.trim();\n return text === undefined || text === '' ? undefined : text;\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';\nimport { extractElementText } from './xml.js';\n\n/** First 6 chars of the `<SignatureValue>` (DGII security code). */\nexport const getCodeSixDigitfromSignature = (\n signedXml: string,\n): Result<string, DgiiError> => {\n const value = extractElementText(signedXml, 'SignatureValue');\n if (value === undefined) {\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 { extractElementText } from './xml.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\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 = extractElementText(signedXml, 'RNCEmisor') ?? 'unknown-rnc';\n const encf = extractElementText(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 async getSummaryInvoiceInquiry(\n rnc: string,\n encf: string,\n codSeguridad: string,\n ): Promise<Result<InquiryInvoiceSummary, DgiiError>> {\n if (this.environment !== Environment.Prod) {\n return err(\n new DgiiError(\n `getSummaryInvoiceInquiry is only available in the production environment (eCF); current environment is ${this.environment}`,\n { code: 'VALIDATION' },\n ),\n );\n }\n const url = buildUrl(\n this.environment,\n Endpoint.InquiryInvoiceSummary,\n BaseUrl.CF,\n );\n return this.http.get<InquiryInvoiceSummary>(\n url,\n { rnc_emisor: rnc, encf, cod_seguridad_eCF: codSeguridad },\n { absoluteUrl: true, resource: Endpoint.InquiryInvoiceSummary },\n );\n }\n\n sendCommercialApproval(\n signedXml: string,\n fileName: string,\n ): Promise<Result<CommercialApprovalResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.CommercialApproval);\n return this.http.postMultipart<CommercialApprovalResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.CommercialApproval },\n );\n }\n\n voidENCF(\n signedXml: string,\n fileName: string,\n ): Promise<Result<VoidNCFResponse, DgiiError>> {\n const url = buildUrl(this.environment, Endpoint.Void);\n return this.http.postMultipart<VoidNCFResponse>(url, fileName, signedXml, {\n absoluteUrl: true,\n resource: Endpoint.Void,\n });\n }\n}\n"],"mappings":"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","names":["Environment","Endpoint","SenderReceiverEndpoint","TrackStatusEnum","err","forge","crypto","convert","import_node_crypto","url"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/types.ts","../src/errors.ts","../src/result.ts","../src/resilience.ts","../src/http.ts","../src/certificate.ts","../src/signing.ts","../src/transformer.ts","../src/xml.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/** Default lifetime of a cached submission: 24 hours. */\nconst DEFAULT_IDEMPOTENCY_TTL_MS = 24 * 60 * 60 * 1000;\n/** Sweep expired entries once the map grows past this many live slots. */\nconst IDEMPOTENCY_SWEEP_THRESHOLD = 1_000;\n\nexport interface InMemoryIdempotencyStoreOptions {\n /** How long a cached entry stays valid. Defaults to 24 hours. */\n readonly ttlMs?: number;\n /** Clock used for expiry, injectable for tests. Defaults to `Date.now`. */\n readonly now?: () => number;\n}\n\ninterface IdempotencyEntry {\n readonly value: unknown;\n readonly expiresAt: number;\n}\n\n/**\n * Process-local default. Fine for single-instance usage and tests.\n *\n * Entries expire after `ttlMs` so a long-running process cannot grow without\n * bound; reads drop expired entries and the map is swept once it passes\n * `IDEMPOTENCY_SWEEP_THRESHOLD`. For more than one instance, back the store\n * with Redis or Postgres.\n */\nexport class InMemoryIdempotencyStore implements IdempotencyStore {\n private readonly entries = new Map<string, IdempotencyEntry>();\n private readonly ttlMs: number;\n private readonly now: () => number;\n\n constructor(options: InMemoryIdempotencyStoreOptions = {}) {\n this.ttlMs = options.ttlMs ?? DEFAULT_IDEMPOTENCY_TTL_MS;\n if (!Number.isFinite(this.ttlMs) || this.ttlMs <= 0) {\n throw new RangeError('ttlMs must be a positive finite number');\n }\n this.now = options.now ?? Date.now;\n }\n\n /** Number of live entries; expired ones are swept first. */\n get size(): number {\n this.sweepExpired();\n return this.entries.size;\n }\n\n async get<T>(key: string): Promise<T | undefined> {\n const entry = this.entries.get(key);\n if (entry === undefined) {\n return undefined;\n }\n if (entry.expiresAt <= this.now()) {\n this.entries.delete(key);\n return undefined;\n }\n return entry.value as T;\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.entries.set(key, { value, expiresAt: this.now() + this.ttlMs });\n if (this.entries.size > IDEMPOTENCY_SWEEP_THRESHOLD) {\n this.sweepExpired();\n }\n }\n\n async delete(key: string): Promise<void> {\n this.entries.delete(key);\n }\n\n private sweepExpired(): void {\n const now = this.now();\n for (const [key, entry] of this.entries) {\n if (entry.expiresAt <= now) {\n this.entries.delete(key);\n }\n }\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\nconst MONETARY_RE = /^(-?)(\\d+)\\.(\\d+)$/;\n\n/** Increment a string of decimal digits (\"267\" -> \"268\", \"999\" -> \"1000\"). */\nconst incrementDigits = (digits: string): string => {\n const chars = digits.split('');\n let index = chars.length - 1;\n while (index >= 0) {\n const current = chars[index];\n if (current === '9') {\n chars[index] = '0';\n index -= 1;\n continue;\n }\n chars[index] = String(Number(current) + 1);\n return chars.join('');\n }\n return `1${chars.join('')}`;\n};\n\n/**\n * Round a decimal string to 2 places with ROUND_HALF_UP semantics.\n *\n * `Number.prototype.toFixed` cannot be used: `(2.675).toFixed(2)` is `'2.67'`\n * because the literal is not representable in binary floating point. DGII\n * expects the decimal, half-up result (`'2.68'`) — the same contract as the\n * Python SDK's `Decimal.quantize(..., rounding=ROUND_HALF_UP)`.\n *\n * Values that are not plain decimals (e.g. `1.0e3`) are returned unchanged.\n */\nexport const roundHalfUpToCents = (value: string): string => {\n const match = MONETARY_RE.exec(value);\n if (!match) {\n return value;\n }\n const sign = match[1] === '-' ? '-' : '';\n const integerPart = (match[2] ?? '0').replace(/^0+(?=\\d)/, '');\n const fractionPart = `${match[3] ?? ''}000`;\n const cents = `${integerPart}${fractionPart.slice(0, 2)}`;\n const rounded = fractionPart[2] >= '5' ? incrementDigits(cents) : cents;\n const padded = rounded.padStart(3, '0');\n return `${sign}${padded.slice(0, -2)}.${padded.slice(-2)}`;\n};\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 if (round && label.toLowerCase() !== 'version') {\n return roundHalfUpToCents(value);\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","/**\n * Tolerant element-text extraction for signed DGII XML.\n *\n * The SDK never owns the XML it inspects: DGII responses, .NET-produced\n * signatures, and third-party generators all wrap the same element in a\n * namespace prefix and add attributes to it. A literal `<tag>` match misses\n * those variants and silently degrades the caller to a fallback — which on the\n * idempotency path means a duplicate fiscal submission.\n */\n\nconst PATTERN_CACHE = new Map<string, RegExp>();\n\n/**\n * Attribute spans may contain `>` inside quotes (`nota=\"a > b\"`), so both\n * quoted forms get their own alternative instead of a blanket `[^>]*`.\n */\nconst ATTRIBUTE_SPAN = `(?:[^>\"']|\"[^\"]*\"|'[^']*')*`;\n\nconst escapeRegExp = (value: string): string =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\nconst elementPattern = (tag: string): RegExp => {\n const cached = PATTERN_CACHE.get(tag);\n if (cached !== undefined) {\n return cached;\n }\n const name = escapeRegExp(tag);\n const prefix = '(?:[\\\\w.-]+:)?';\n const pattern = new RegExp(\n `<${prefix}${name}${ATTRIBUTE_SPAN}>([\\\\s\\\\S]*?)<\\\\/${prefix}${name}\\\\s*>`,\n );\n PATTERN_CACHE.set(tag, pattern);\n return pattern;\n};\n\n/**\n * Text content of the first `<tag>` element, tolerating a namespace prefix\n * (`ns:eNCF`) and attributes (`<eNCF version=\"1.0\">`).\n *\n * Returns `undefined` when the element is absent, self-closing, or blank, so\n * callers fall back deliberately instead of building a key out of an empty\n * segment. Matching is case-sensitive, as XML element names are.\n */\nexport const extractElementText = (\n xml: string,\n tag: string,\n): string | undefined => {\n const match = elementPattern(tag).exec(xml);\n const text = match?.[1]?.trim();\n return text === undefined || text === '' ? undefined : text;\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';\nimport { extractElementText } from './xml.js';\n\n/** First 6 chars of the `<SignatureValue>` (DGII security code). */\nexport const getCodeSixDigitfromSignature = (\n signedXml: string,\n): Result<string, DgiiError> => {\n const value = extractElementText(signedXml, 'SignatureValue');\n if (value === undefined) {\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 { extractElementText } from './xml.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\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 = extractElementText(signedXml, 'RNCEmisor') ?? 'unknown-rnc';\n // ACECF carries `eNCF`; ANECF uses `RangoNCF`. Fall back to the hash if\n // neither is present, so the key is still unique per document.\n const ncf =\n extractElementText(signedXml, 'eNCF') ??\n extractElementText(signedXml, 'RangoNCF') ??\n 'unknown-ncf';\n return `${rnc}:${ncf}:${sha256Hex(signedXml)}`;\n }\n\n /**\n * Run a submission through the persist-before-transmit idempotency flow.\n *\n * The pending marker is written first so an interrupted send can be\n * reconciled instead of re-issued; a successful response replaces it, and\n * a failure clears it so the caller can retry.\n */\n private async submitIdempotent<T>(\n key: string,\n send: () => Promise<Result<T, DgiiError>>,\n ): Promise<Result<T, DgiiError>> {\n const cached = await this.idempotency.get<T | PendingSubmission>(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 await this.idempotency.set(key, PENDING_SUBMISSION);\n const result = await send();\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 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 return this.submitIdempotent(key, () => {\n const url = buyerHost\n ? buildSenderReceiverUrl(buyerHost, SenderReceiverEndpoint.SendInvoice)\n : buildUrl(this.environment, Endpoint.SendInvoice);\n return this.http.postMultipart<InvoiceResponse>(\n url,\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendInvoice },\n );\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 return this.submitIdempotent(key, () =>\n this.http.postMultipart<InvoiceSummaryResponse>(\n buildUrl(this.environment, Endpoint.SendSummary, BaseUrl.CF),\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.SendSummary },\n ),\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 async getSummaryInvoiceInquiry(\n rnc: string,\n encf: string,\n codSeguridad: string,\n ): Promise<Result<InquiryInvoiceSummary, DgiiError>> {\n if (this.environment !== Environment.Prod) {\n return err(\n new DgiiError(\n `getSummaryInvoiceInquiry is only available in the production environment (eCF); current environment is ${this.environment}`,\n { code: 'VALIDATION' },\n ),\n );\n }\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 /**\n * Submit a signed commercial approval (ACECF). Idempotent like submissions,\n * keyed on `RNC + eNCF + SHA-256(signed XML)`.\n */\n sendCommercialApproval(\n signedXml: string,\n fileName: string,\n ): Promise<Result<CommercialApprovalResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n return this.submitIdempotent(key, () =>\n this.http.postMultipart<CommercialApprovalResponse>(\n buildUrl(this.environment, Endpoint.CommercialApproval),\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.CommercialApproval },\n ),\n );\n }\n\n /**\n * Submit a signed range-voiding request (ANECF). Idempotent like\n * submissions, keyed on `RNC + RangoNCF + SHA-256(signed XML)`.\n */\n voidENCF(\n signedXml: string,\n fileName: string,\n ): Promise<Result<VoidNCFResponse, DgiiError>> {\n const key = this.buildIdempotencyKey(signedXml);\n return this.submitIdempotent(key, () =>\n this.http.postMultipart<VoidNCFResponse>(\n buildUrl(this.environment, Endpoint.Void),\n fileName,\n signedXml,\n { absoluteUrl: true, resource: Endpoint.Void },\n ),\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.d.cts
CHANGED
|
@@ -219,12 +219,31 @@ interface IdempotencyStore {
|
|
|
219
219
|
set<T>(key: string, value: T): Promise<void>;
|
|
220
220
|
delete(key: string): Promise<void>;
|
|
221
221
|
}
|
|
222
|
-
|
|
222
|
+
interface InMemoryIdempotencyStoreOptions {
|
|
223
|
+
/** How long a cached entry stays valid. Defaults to 24 hours. */
|
|
224
|
+
readonly ttlMs?: number;
|
|
225
|
+
/** Clock used for expiry, injectable for tests. Defaults to `Date.now`. */
|
|
226
|
+
readonly now?: () => number;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Process-local default. Fine for single-instance usage and tests.
|
|
230
|
+
*
|
|
231
|
+
* Entries expire after `ttlMs` so a long-running process cannot grow without
|
|
232
|
+
* bound; reads drop expired entries and the map is swept once it passes
|
|
233
|
+
* `IDEMPOTENCY_SWEEP_THRESHOLD`. For more than one instance, back the store
|
|
234
|
+
* with Redis or Postgres.
|
|
235
|
+
*/
|
|
223
236
|
declare class InMemoryIdempotencyStore implements IdempotencyStore {
|
|
224
|
-
private readonly
|
|
237
|
+
private readonly entries;
|
|
238
|
+
private readonly ttlMs;
|
|
239
|
+
private readonly now;
|
|
240
|
+
constructor(options?: InMemoryIdempotencyStoreOptions);
|
|
241
|
+
/** Number of live entries; expired ones are swept first. */
|
|
242
|
+
get size(): number;
|
|
225
243
|
get<T>(key: string): Promise<T | undefined>;
|
|
226
244
|
set<T>(key: string, value: T): Promise<void>;
|
|
227
245
|
delete(key: string): Promise<void>;
|
|
246
|
+
private sweepExpired;
|
|
228
247
|
}
|
|
229
248
|
interface HttpClientOptions {
|
|
230
249
|
baseUrl: string;
|
|
@@ -380,6 +399,14 @@ declare class ECF {
|
|
|
380
399
|
private readonly inFlight;
|
|
381
400
|
constructor(credentials: P12ReaderData, environment?: Environment, options?: EcfOptions);
|
|
382
401
|
private buildIdempotencyKey;
|
|
402
|
+
/**
|
|
403
|
+
* Run a submission through the persist-before-transmit idempotency flow.
|
|
404
|
+
*
|
|
405
|
+
* The pending marker is written first so an interrupted send can be
|
|
406
|
+
* reconciled instead of re-issued; a successful response replaces it, and
|
|
407
|
+
* a failure clears it so the caller can retry.
|
|
408
|
+
*/
|
|
409
|
+
private submitIdempotent;
|
|
383
410
|
private singleFlight;
|
|
384
411
|
/** Authenticate against DGII (or a buyer host) and store the bearer token. */
|
|
385
412
|
authenticate(buyerHost?: string): Promise<Result<AuthToken, DgiiError>>;
|
|
@@ -399,8 +426,16 @@ declare class ECF {
|
|
|
399
426
|
getCustomerDirectory(rnc: string): Promise<Result<ServiceDirectoryResponse[] | undefined, DgiiError>>;
|
|
400
427
|
/** RFCE inquiry — DGII production only. */
|
|
401
428
|
getSummaryInvoiceInquiry(rnc: string, encf: string, codSeguridad: string): Promise<Result<InquiryInvoiceSummary, DgiiError>>;
|
|
429
|
+
/**
|
|
430
|
+
* Submit a signed commercial approval (ACECF). Idempotent like submissions,
|
|
431
|
+
* keyed on `RNC + eNCF + SHA-256(signed XML)`.
|
|
432
|
+
*/
|
|
402
433
|
sendCommercialApproval(signedXml: string, fileName: string): Promise<Result<CommercialApprovalResponse, DgiiError>>;
|
|
434
|
+
/**
|
|
435
|
+
* Submit a signed range-voiding request (ANECF). Idempotent like
|
|
436
|
+
* submissions, keyed on `RNC + RangoNCF + SHA-256(signed XML)`.
|
|
437
|
+
*/
|
|
403
438
|
voidENCF(signedXml: string, fileName: string): Promise<Result<VoidNCFResponse, DgiiError>>;
|
|
404
439
|
}
|
|
405
440
|
|
|
406
|
-
export { type AuthToken, BaseUrl, type BaseUrlKey, type CertificateInfo, type CommercialApprovalResponse, type DgiiDocumentType, DgiiError, type DgiiErrorCode, type DgiiErrorContext, type DgiiErrorOptions, type DgiiResult, ECF, type EcfOptions, Endpoint, Environment, HttpClient, type HttpClientOptions, type IdempotencyStore, InMemoryIdempotencyStore, type InquiryInvoiceSummary, type InquiryStatus, type InquiryStatusCode, type InquiryStatusResponse, type InvoiceResponse, type InvoiceSummaryResponse, type Mensaje, P12Reader, type P12ReaderData, type RequestOptions, type ResilienceOptions, type ResiliencePolicies, SenderReceiverEndpoint, type ServiceDirectoryResponse, Signature, type SummaryTrackingStatusResponse, type TrackStatusCode, TrackStatusEnum, type TrackingStatusResponse, Transformer, type VoidNCFResponse, type XmlCertificateValidation, buildSenderReceiverUrl, buildUrl, convertECF32ToRFCE, createResiliencePolicies, defaultResilienceOptions, extractDgiiErrorMessage, generateEcfQRCodeURL, generateFcQRCodeURL, getCodeSixDigitfromSignature, getCurrentFormattedDate, getCurrentFormattedDateTime, getXmlFromBodyResponse, isRetryableError, isRetryableStatus, roundHalfUpToCents, toDgiiError, validateXMLCertificate };
|
|
441
|
+
export { type AuthToken, BaseUrl, type BaseUrlKey, type CertificateInfo, type CommercialApprovalResponse, type DgiiDocumentType, DgiiError, type DgiiErrorCode, type DgiiErrorContext, type DgiiErrorOptions, type DgiiResult, ECF, type EcfOptions, Endpoint, Environment, HttpClient, type HttpClientOptions, type IdempotencyStore, InMemoryIdempotencyStore, type InMemoryIdempotencyStoreOptions, type InquiryInvoiceSummary, type InquiryStatus, type InquiryStatusCode, type InquiryStatusResponse, type InvoiceResponse, type InvoiceSummaryResponse, type Mensaje, P12Reader, type P12ReaderData, type RequestOptions, type ResilienceOptions, type ResiliencePolicies, SenderReceiverEndpoint, type ServiceDirectoryResponse, Signature, type SummaryTrackingStatusResponse, type TrackStatusCode, TrackStatusEnum, type TrackingStatusResponse, Transformer, type VoidNCFResponse, type XmlCertificateValidation, buildSenderReceiverUrl, buildUrl, convertECF32ToRFCE, createResiliencePolicies, defaultResilienceOptions, extractDgiiErrorMessage, generateEcfQRCodeURL, generateFcQRCodeURL, getCodeSixDigitfromSignature, getCurrentFormattedDate, getCurrentFormattedDateTime, getXmlFromBodyResponse, isRetryableError, isRetryableStatus, roundHalfUpToCents, toDgiiError, validateXMLCertificate };
|
package/dist/index.d.ts
CHANGED
|
@@ -219,12 +219,31 @@ interface IdempotencyStore {
|
|
|
219
219
|
set<T>(key: string, value: T): Promise<void>;
|
|
220
220
|
delete(key: string): Promise<void>;
|
|
221
221
|
}
|
|
222
|
-
|
|
222
|
+
interface InMemoryIdempotencyStoreOptions {
|
|
223
|
+
/** How long a cached entry stays valid. Defaults to 24 hours. */
|
|
224
|
+
readonly ttlMs?: number;
|
|
225
|
+
/** Clock used for expiry, injectable for tests. Defaults to `Date.now`. */
|
|
226
|
+
readonly now?: () => number;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Process-local default. Fine for single-instance usage and tests.
|
|
230
|
+
*
|
|
231
|
+
* Entries expire after `ttlMs` so a long-running process cannot grow without
|
|
232
|
+
* bound; reads drop expired entries and the map is swept once it passes
|
|
233
|
+
* `IDEMPOTENCY_SWEEP_THRESHOLD`. For more than one instance, back the store
|
|
234
|
+
* with Redis or Postgres.
|
|
235
|
+
*/
|
|
223
236
|
declare class InMemoryIdempotencyStore implements IdempotencyStore {
|
|
224
|
-
private readonly
|
|
237
|
+
private readonly entries;
|
|
238
|
+
private readonly ttlMs;
|
|
239
|
+
private readonly now;
|
|
240
|
+
constructor(options?: InMemoryIdempotencyStoreOptions);
|
|
241
|
+
/** Number of live entries; expired ones are swept first. */
|
|
242
|
+
get size(): number;
|
|
225
243
|
get<T>(key: string): Promise<T | undefined>;
|
|
226
244
|
set<T>(key: string, value: T): Promise<void>;
|
|
227
245
|
delete(key: string): Promise<void>;
|
|
246
|
+
private sweepExpired;
|
|
228
247
|
}
|
|
229
248
|
interface HttpClientOptions {
|
|
230
249
|
baseUrl: string;
|
|
@@ -380,6 +399,14 @@ declare class ECF {
|
|
|
380
399
|
private readonly inFlight;
|
|
381
400
|
constructor(credentials: P12ReaderData, environment?: Environment, options?: EcfOptions);
|
|
382
401
|
private buildIdempotencyKey;
|
|
402
|
+
/**
|
|
403
|
+
* Run a submission through the persist-before-transmit idempotency flow.
|
|
404
|
+
*
|
|
405
|
+
* The pending marker is written first so an interrupted send can be
|
|
406
|
+
* reconciled instead of re-issued; a successful response replaces it, and
|
|
407
|
+
* a failure clears it so the caller can retry.
|
|
408
|
+
*/
|
|
409
|
+
private submitIdempotent;
|
|
383
410
|
private singleFlight;
|
|
384
411
|
/** Authenticate against DGII (or a buyer host) and store the bearer token. */
|
|
385
412
|
authenticate(buyerHost?: string): Promise<Result<AuthToken, DgiiError>>;
|
|
@@ -399,8 +426,16 @@ declare class ECF {
|
|
|
399
426
|
getCustomerDirectory(rnc: string): Promise<Result<ServiceDirectoryResponse[] | undefined, DgiiError>>;
|
|
400
427
|
/** RFCE inquiry — DGII production only. */
|
|
401
428
|
getSummaryInvoiceInquiry(rnc: string, encf: string, codSeguridad: string): Promise<Result<InquiryInvoiceSummary, DgiiError>>;
|
|
429
|
+
/**
|
|
430
|
+
* Submit a signed commercial approval (ACECF). Idempotent like submissions,
|
|
431
|
+
* keyed on `RNC + eNCF + SHA-256(signed XML)`.
|
|
432
|
+
*/
|
|
402
433
|
sendCommercialApproval(signedXml: string, fileName: string): Promise<Result<CommercialApprovalResponse, DgiiError>>;
|
|
434
|
+
/**
|
|
435
|
+
* Submit a signed range-voiding request (ANECF). Idempotent like
|
|
436
|
+
* submissions, keyed on `RNC + RangoNCF + SHA-256(signed XML)`.
|
|
437
|
+
*/
|
|
403
438
|
voidENCF(signedXml: string, fileName: string): Promise<Result<VoidNCFResponse, DgiiError>>;
|
|
404
439
|
}
|
|
405
440
|
|
|
406
|
-
export { type AuthToken, BaseUrl, type BaseUrlKey, type CertificateInfo, type CommercialApprovalResponse, type DgiiDocumentType, DgiiError, type DgiiErrorCode, type DgiiErrorContext, type DgiiErrorOptions, type DgiiResult, ECF, type EcfOptions, Endpoint, Environment, HttpClient, type HttpClientOptions, type IdempotencyStore, InMemoryIdempotencyStore, type InquiryInvoiceSummary, type InquiryStatus, type InquiryStatusCode, type InquiryStatusResponse, type InvoiceResponse, type InvoiceSummaryResponse, type Mensaje, P12Reader, type P12ReaderData, type RequestOptions, type ResilienceOptions, type ResiliencePolicies, SenderReceiverEndpoint, type ServiceDirectoryResponse, Signature, type SummaryTrackingStatusResponse, type TrackStatusCode, TrackStatusEnum, type TrackingStatusResponse, Transformer, type VoidNCFResponse, type XmlCertificateValidation, buildSenderReceiverUrl, buildUrl, convertECF32ToRFCE, createResiliencePolicies, defaultResilienceOptions, extractDgiiErrorMessage, generateEcfQRCodeURL, generateFcQRCodeURL, getCodeSixDigitfromSignature, getCurrentFormattedDate, getCurrentFormattedDateTime, getXmlFromBodyResponse, isRetryableError, isRetryableStatus, roundHalfUpToCents, toDgiiError, validateXMLCertificate };
|
|
441
|
+
export { type AuthToken, BaseUrl, type BaseUrlKey, type CertificateInfo, type CommercialApprovalResponse, type DgiiDocumentType, DgiiError, type DgiiErrorCode, type DgiiErrorContext, type DgiiErrorOptions, type DgiiResult, ECF, type EcfOptions, Endpoint, Environment, HttpClient, type HttpClientOptions, type IdempotencyStore, InMemoryIdempotencyStore, type InMemoryIdempotencyStoreOptions, type InquiryInvoiceSummary, type InquiryStatus, type InquiryStatusCode, type InquiryStatusResponse, type InvoiceResponse, type InvoiceSummaryResponse, type Mensaje, P12Reader, type P12ReaderData, type RequestOptions, type ResilienceOptions, type ResiliencePolicies, SenderReceiverEndpoint, type ServiceDirectoryResponse, Signature, type SummaryTrackingStatusResponse, type TrackStatusCode, TrackStatusEnum, type TrackingStatusResponse, Transformer, type VoidNCFResponse, type XmlCertificateValidation, buildSenderReceiverUrl, buildUrl, convertECF32ToRFCE, createResiliencePolicies, defaultResilienceOptions, extractDgiiErrorMessage, generateEcfQRCodeURL, generateFcQRCodeURL, getCodeSixDigitfromSignature, getCurrentFormattedDate, getCurrentFormattedDateTime, getXmlFromBodyResponse, isRetryableError, isRetryableStatus, roundHalfUpToCents, toDgiiError, validateXMLCertificate };
|