facturas 0.6.0 → 0.7.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.mjs CHANGED
@@ -1,94 +1,29 @@
1
- // src/errors.ts
2
- var ArcaError = class extends Error {
3
- code;
4
- name = "ArcaError";
5
- constructor(message, code = "ARCA_ERROR", options) {
6
- super(message, options);
7
- this.code = code;
8
- }
9
- };
10
- var ArcaConfigurationError = class extends ArcaError {
11
- name = "ArcaConfigurationError";
12
- constructor(message, options) {
13
- super(message, "ARCA_CONFIGURATION_ERROR", options);
14
- }
15
- };
16
- var ArcaInputError = class extends ArcaError {
17
- name = "ArcaInputError";
18
- detail;
19
- constructor(message, options) {
20
- super(message, "ARCA_INPUT_ERROR", options);
21
- this.detail = options?.detail;
22
- }
23
- };
24
- var ArcaTransportError = class extends ArcaError {
25
- name = "ArcaTransportError";
26
- statusCode;
27
- contentType;
28
- responseBody;
29
- constructor(message, options) {
30
- super(message, "ARCA_TRANSPORT_ERROR", options);
31
- this.statusCode = options?.statusCode;
32
- this.contentType = options?.contentType;
33
- this.responseBody = options?.responseBody;
34
- }
35
- };
36
- var ArcaSoapFaultError = class extends ArcaError {
37
- name = "ArcaSoapFaultError";
38
- faultCode;
39
- detail;
40
- constructor(message, options) {
41
- super(message, "ARCA_SOAP_FAULT", options);
42
- this.faultCode = options?.faultCode;
43
- this.detail = options?.detail;
44
- }
45
- };
46
- var ArcaInvalidSoapResponseError = class extends ArcaError {
47
- name = "ArcaInvalidSoapResponseError";
48
- service;
49
- operation;
50
- endpointUrl;
51
- statusCode;
52
- contentType;
53
- responseBodyLength;
54
- responseBodyPreview;
55
- parsedDetail;
56
- constructor(message, options) {
57
- super(message, "ARCA_INVALID_SOAP_RESPONSE", options);
58
- this.service = options?.service;
59
- this.operation = options?.operation;
60
- this.endpointUrl = options?.endpointUrl;
61
- this.statusCode = options?.statusCode;
62
- this.contentType = options?.contentType;
63
- this.responseBodyLength = options?.responseBodyLength;
64
- this.responseBodyPreview = options?.responseBodyPreview;
65
- this.parsedDetail = options?.parsedDetail;
66
- }
67
- };
68
- var ArcaServiceError = class extends ArcaError {
69
- name = "ArcaServiceError";
70
- serviceCode;
71
- service;
72
- operation;
73
- result;
74
- resultLevel;
75
- results;
76
- cae;
77
- issues;
78
- detail;
79
- constructor(message, options) {
80
- super(message, "ARCA_SERVICE_ERROR", options);
81
- this.serviceCode = options?.serviceCode;
82
- this.service = options?.service;
83
- this.operation = options?.operation;
84
- this.result = options?.result;
85
- this.resultLevel = options?.resultLevel;
86
- this.results = options?.results;
87
- this.cae = options?.cae;
88
- this.issues = options?.issues;
89
- this.detail = options?.detail;
90
- }
91
- };
1
+ import {
2
+ createPadronService
3
+ } from "./chunk-EDY3PNKJ.mjs";
4
+ import {
5
+ buildFacturaB,
6
+ buildFacturaC,
7
+ createWsfeService
8
+ } from "./chunk-C55KOV5N.mjs";
9
+ import "./chunk-VVY2LZIZ.mjs";
10
+ import {
11
+ createWsmtxcaService
12
+ } from "./chunk-PKE4Z4GE.mjs";
13
+ import "./chunk-IOKZX6CA.mjs";
14
+ import {
15
+ ArcaAuthenticationError,
16
+ ArcaConfigurationError,
17
+ ArcaError,
18
+ ArcaInputError,
19
+ ArcaInvalidSoapResponseError,
20
+ ArcaServiceError,
21
+ ArcaSoapFaultError,
22
+ ArcaTransportError,
23
+ createResponseBodyDiagnostic,
24
+ createSafeErrorDiagnostic,
25
+ isArcaAuthenticationError
26
+ } from "./chunk-MBWOFO67.mjs";
92
27
 
93
28
  // src/config.ts
94
29
  var ARCA_ENVIRONMENTS = ["production", "test"];
@@ -100,9 +35,10 @@ var ARCA_ENV_VARIABLES = {
100
35
  };
101
36
  var PRIVATE_KEY_PEM_PREFIXES = [
102
37
  "-----BEGIN PRIVATE KEY-----",
103
- "-----BEGIN RSA PRIVATE KEY-----",
104
- "-----BEGIN ENCRYPTED PRIVATE KEY-----"
38
+ "-----BEGIN RSA PRIVATE KEY-----"
105
39
  ];
40
+ var ENCRYPTED_PRIVATE_KEY_PEM_PREFIX = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
41
+ var LEGACY_ENCRYPTED_RSA_PRIVATE_KEY_PATTERN = /^-----BEGIN RSA PRIVATE KEY-----[\s\S]*^Proc-Type:\s*4,\s*ENCRYPTED\s*$/m;
106
42
  var VALID_ARCA_LOG_LEVELS = ["debug", "info", "warn", "error"];
107
43
  var DEFAULT_ARCA_TIMEOUT_MS = 3e4;
108
44
  var DEFAULT_ARCA_RETRIES = 0;
@@ -133,6 +69,11 @@ function assertArcaClientConfig(config) {
133
69
  const timeout = normalized.timeout ?? DEFAULT_ARCA_TIMEOUT_MS;
134
70
  const retries = normalized.retries ?? DEFAULT_ARCA_RETRIES;
135
71
  const retryDelay = normalized.retryDelay ?? DEFAULT_ARCA_RETRY_DELAY_MS;
72
+ if (normalized.privateKeyPem.startsWith(ENCRYPTED_PRIVATE_KEY_PEM_PREFIX) || LEGACY_ENCRYPTED_RSA_PRIVATE_KEY_PATTERN.test(normalized.privateKeyPem)) {
73
+ throw new ArcaConfigurationError(
74
+ "Encrypted private keys are not supported. Provide an unencrypted PKCS#8 or RSA private key PEM."
75
+ );
76
+ }
136
77
  if (!/^\d{11}$/.test(normalized.taxId)) {
137
78
  invalidFields.push("taxId");
138
79
  }
@@ -235,1699 +176,115 @@ var ARCA_SERVICE_CONFIG = {
235
176
  namespace: "http://a13.soap.ws.server.puc.sr/",
236
177
  endpoint: {
237
178
  production: "https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA13",
238
- test: "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA13"
239
- },
240
- soapVersion: "1.1",
241
- soapActionBase: "",
242
- usesEmptySoapAction: true
243
- }
244
- };
245
- function getArcaServiceConfig(service) {
246
- const serviceConfig = ARCA_SERVICE_CONFIG[service];
247
- if (!serviceConfig) {
248
- throw new ArcaConfigurationError(
249
- `Unsupported ARCA service configuration: ${service}`
250
- );
251
- }
252
- return serviceConfig;
253
- }
254
- function normalizeArcaClientConfig(config) {
255
- const normalizedEnvironment = normalizeEnvironmentValue(String(config.environment)) ?? config.environment;
256
- const normalizedLoggerLevel = normalizeLogLevelValue(config.logger?.level);
257
- return {
258
- taxId: config.taxId.trim(),
259
- certificatePem: config.certificatePem.trim(),
260
- privateKeyPem: config.privateKeyPem.trim(),
261
- environment: normalizedEnvironment,
262
- timeout: config.timeout ?? DEFAULT_ARCA_TIMEOUT_MS,
263
- retries: config.retries ?? DEFAULT_ARCA_RETRIES,
264
- retryDelay: config.retryDelay ?? DEFAULT_ARCA_RETRY_DELAY_MS,
265
- ...config.logger === void 0 ? {} : {
266
- logger: {
267
- ...config.logger,
268
- ...normalizedLoggerLevel === void 0 ? {} : { level: normalizedLoggerLevel }
269
- }
270
- },
271
- ...config.wsaaSessionStore === void 0 ? {} : { wsaaSessionStore: config.wsaaSessionStore }
272
- };
273
- }
274
- function normalizeEnvironmentValue(value) {
275
- if (!value) {
276
- return void 0;
277
- }
278
- const normalized = value.trim().toLowerCase();
279
- if (ARCA_ENVIRONMENTS.includes(normalized)) {
280
- return normalized;
281
- }
282
- return void 0;
283
- }
284
- function readEnv(env, variableName) {
285
- return env[variableName]?.trim() || void 0;
286
- }
287
- function normalizeLogLevelValue(value) {
288
- if (!value) {
289
- return void 0;
290
- }
291
- const normalized = value.trim().toLowerCase();
292
- if (VALID_ARCA_LOG_LEVELS.includes(normalized)) {
293
- return normalized;
294
- }
295
- return value;
296
- }
297
-
298
- // src/internal/logger.ts
299
- var ARCA_LOG_LEVELS = ["debug", "info", "warn", "error"];
300
- function createArcaLogger(config) {
301
- const disabled = config?.disabled ?? false;
302
- const level = resolveArcaLogLevel(config?.level);
303
- const sink = config?.log ?? defaultArcaLog;
304
- const log = (messageLevel, message, ...args) => {
305
- if (disabled || !shouldLog(level, messageLevel)) {
306
- return;
307
- }
308
- sink(messageLevel, message, ...args);
309
- };
310
- return {
311
- disabled,
312
- level,
313
- log,
314
- debug(message, ...args) {
315
- log("debug", message, ...args);
316
- },
317
- info(message, ...args) {
318
- log("info", message, ...args);
319
- },
320
- warn(message, ...args) {
321
- log("warn", message, ...args);
322
- },
323
- error(message, ...args) {
324
- log("error", message, ...args);
325
- }
326
- };
327
- }
328
- function resolveArcaLogLevel(level) {
329
- if (isArcaLogLevel(level)) {
330
- return level;
331
- }
332
- const envLevel = process.env.ARCA_LOG_LEVEL?.trim().toLowerCase();
333
- if (isArcaLogLevel(envLevel)) {
334
- return envLevel;
335
- }
336
- return "warn";
337
- }
338
- function shouldLog(threshold, messageLevel) {
339
- return ARCA_LOG_LEVELS.indexOf(messageLevel) >= ARCA_LOG_LEVELS.indexOf(threshold);
340
- }
341
- function isArcaLogLevel(value) {
342
- return ARCA_LOG_LEVELS.includes(value);
343
- }
344
- function defaultArcaLog(level, message, ...args) {
345
- const method = level === "debug" ? console.debug : level === "info" ? console.info : level === "warn" ? console.warn : console.error;
346
- method(message, ...args);
347
- }
348
-
349
- // src/services/padron.ts
350
- function createPadronService(options) {
351
- return {
352
- async getTaxpayerDetails(taxId) {
353
- const raw = await executePadronOperation(
354
- options,
355
- "padron-a5",
356
- "getPersona_v2",
357
- {
358
- idPersona: Number.parseInt(String(taxId), 10)
359
- }
360
- );
361
- if (!raw) {
362
- return null;
363
- }
364
- const record = raw;
365
- const datosGenerales = record.datosGenerales;
366
- return {
367
- taxId: String(record.idPersona ?? ""),
368
- ...record.tipoPersona === void 0 ? {} : { personType: String(record.tipoPersona) },
369
- ...datosGenerales ? { name: extractPadronName(datosGenerales) } : {},
370
- raw: record
371
- };
372
- },
373
- async getTaxIdByDocument(documentNumber) {
374
- const raw = await executePadronOperation(
375
- options,
376
- "padron-a13",
377
- "getIdPersonaListByDocumento",
378
- {
379
- documento: String(documentNumber)
380
- }
381
- );
382
- if (!raw) {
383
- return null;
384
- }
385
- const record = raw;
386
- const idPersona = record.idPersona;
387
- const taxIds = Array.isArray(idPersona) ? idPersona.map(String) : idPersona === void 0 ? [] : [String(idPersona)];
388
- return {
389
- taxIds,
390
- raw: record
391
- };
392
- }
393
- };
394
- }
395
- function extractPadronName(datosGenerales) {
396
- if (typeof datosGenerales.razonSocial === "string") {
397
- return datosGenerales.razonSocial;
398
- }
399
- const nombre = datosGenerales.nombre;
400
- const apellido = datosGenerales.apellido;
401
- if (typeof apellido === "string" && typeof nombre === "string") {
402
- return `${apellido} ${nombre}`.trim();
403
- }
404
- if (typeof apellido === "string") {
405
- return apellido;
406
- }
407
- if (typeof nombre === "string") {
408
- return nombre;
409
- }
410
- return void 0;
411
- }
412
- async function executePadronOperation(options, service, operation, body) {
413
- const auth = await options.auth.login(
414
- service === "padron-a5" ? "ws_sr_constancia_inscripcion" : "ws_sr_padron_a13"
415
- );
416
- try {
417
- const response = await options.soap.execute({
418
- service,
419
- operation,
420
- bodyElementNamespaceMode: "prefix",
421
- body: {
422
- token: auth.token,
423
- sign: auth.sign,
424
- cuitRepresentada: Number.parseInt(options.config.taxId, 10),
425
- ...body
426
- }
427
- });
428
- const operationResponse = response.result;
429
- if (operation === "getPersona_v2") {
430
- return operationResponse.personaReturn ?? null;
431
- }
432
- if (operation === "getIdPersonaListByDocumento") {
433
- return operationResponse.idPersonaListReturn ?? null;
434
- }
435
- return operationResponse.return ?? null;
436
- } catch (error) {
437
- if (error instanceof ArcaSoapFaultError && // Public Padron A5/A13 WSDLs expose only a generic validation fault, so
438
- // there is no documented not-found-specific fault code to match here.
439
- // Keep the current message fallback, but treat it as fragile.
440
- error.message.toLowerCase().includes("no existe")) {
441
- return null;
442
- }
443
- throw error;
444
- }
445
- }
446
-
447
- // src/services/wsfe.ts
448
- function createWsfeService(options) {
449
- async function executeWsfeAuthenticatedRawOperation(operation, input, body = {}, retries) {
450
- const auth = await options.auth.login("wsfe", {
451
- representedTaxId: input.representedTaxId,
452
- forceRefresh: input.forceRefresh
453
- });
454
- const response = await options.soap.execute({
455
- service: "wsfe",
456
- operation,
457
- ...retries === void 0 ? {} : { retries },
458
- body: {
459
- Auth: createWsfeAuth(
460
- input.representedTaxId ?? options.config.taxId,
461
- auth.token,
462
- auth.sign
463
- ),
464
- ...body
465
- }
466
- });
467
- return unwrapWsfeOperationEnvelope(operation, response.result);
468
- }
469
- async function executeWsfeAuthenticatedOperation(operation, input, body = {}) {
470
- const result = await executeWsfeAuthenticatedRawOperation(
471
- operation,
472
- input,
473
- body
474
- );
475
- throwForWsfeOperationErrors(operation, result);
476
- return result;
477
- }
478
- async function executeWsfeOperation(operation, body = {}) {
479
- const response = await options.soap.execute({
480
- service: "wsfe",
481
- operation,
482
- body
483
- });
484
- const result = unwrapWsfeOperationEnvelope(operation, response.result);
485
- throwForWsfeOperationErrors(operation, result);
486
- return result;
487
- }
488
- async function getNextVoucherNumber({
489
- representedTaxId,
490
- salesPoint,
491
- voucherType,
492
- forceRefresh
493
- }) {
494
- const result = await executeWsfeAuthenticatedOperation(
495
- "FECompUltimoAutorizado",
496
- {
497
- representedTaxId,
498
- forceRefresh
499
- },
500
- {
501
- PtoVta: salesPoint,
502
- CbteTipo: voucherType
503
- }
504
- );
505
- return Number(result.CbteNro ?? 0) + 1;
506
- }
507
- async function getWsfeCatalog(operation, resultKey, input) {
508
- const result = await executeWsfeAuthenticatedOperation(operation, {
509
- representedTaxId: input.representedTaxId,
510
- forceRefresh: input.forceRefresh
511
- });
512
- return getWsfeResultEntries(result, resultKey).map(mapWsfeCatalogEntry);
513
- }
514
- function authorizeVoucher({
515
- representedTaxId,
516
- data,
517
- voucherNumber,
518
- forceRefresh
519
- }) {
520
- const normalizedInput = normalizeWsfeVoucherInput(data);
521
- return authorizeNormalizedVoucher({
522
- representedTaxId,
523
- data: normalizedInput,
524
- voucherNumber,
525
- forceRefresh
526
- });
527
- }
528
- function authorizeVoucherOutcome({
529
- representedTaxId,
530
- data,
531
- voucherNumber,
532
- forceRefresh
533
- }) {
534
- const normalizedInput = normalizeWsfeVoucherInput(data);
535
- return executeWsfeAuthorization({
536
- representedTaxId,
537
- data: normalizedInput,
538
- voucherNumber,
539
- forceRefresh
540
- }).then(({ outcome }) => outcome);
541
- }
542
- async function authorizeNormalizedVoucher({
543
- representedTaxId,
544
- data: normalizedInput,
545
- voucherNumber,
546
- forceRefresh
547
- }) {
548
- const execution = await executeWsfeAuthorization({
549
- representedTaxId,
550
- data: normalizedInput,
551
- voucherNumber,
552
- forceRefresh
553
- });
554
- if (execution.error) {
555
- throw execution.error;
556
- }
557
- if (execution.outcome.kind !== "authorized") {
558
- throw createWsfeOutcomeError(execution.outcome);
559
- }
560
- const { cae, caeExpiry, raw } = execution.outcome;
561
- if (!(caeExpiry && raw)) {
562
- throw new ArcaServiceError("WSFE did not return CAE authorization data", {
563
- service: "wsfe",
564
- operation: "FECAESolicitar",
565
- result: execution.outcome.result,
566
- resultLevel: execution.outcome.resultLevel,
567
- results: execution.outcome.results,
568
- cae,
569
- issues: [
570
- ...execution.outcome.errors,
571
- ...execution.outcome.observations
572
- ],
573
- detail: raw
574
- });
575
- }
576
- return {
577
- cae,
578
- caeExpiry,
579
- voucherNumber,
580
- raw
581
- };
582
- }
583
- async function executeWsfeAuthorization({
584
- representedTaxId,
585
- data: normalizedInput,
586
- voucherNumber,
587
- forceRefresh
588
- }) {
589
- const requestData = mapWsfeVoucherInput(normalizedInput, voucherNumber);
590
- try {
591
- const result = await executeWsfeAuthenticatedRawOperation(
592
- "FECAESolicitar",
593
- { representedTaxId, forceRefresh },
594
- {
595
- FeCAEReq: {
596
- FeCabReq: {
597
- CantReg: 1,
598
- PtoVta: normalizedInput.salesPoint,
599
- CbteTipo: normalizedInput.voucherType
600
- },
601
- FeDetReq: {
602
- FECAEDetRequest: requestData
603
- }
604
- }
605
- },
606
- 0
607
- );
608
- return {
609
- outcome: classifyWsfeAuthorization(result, voucherNumber)
610
- };
611
- } catch (error) {
612
- return {
613
- outcome: createWsfeIndeterminateOutcome(error),
614
- error
615
- };
616
- }
617
- }
618
- async function lookupVoucher({
619
- representedTaxId,
620
- number,
621
- salesPoint,
622
- voucherType,
623
- forceRefresh
624
- }) {
625
- const operation = "FECompConsultar";
626
- const result = await executeWsfeAuthenticatedRawOperation(
627
- operation,
628
- { representedTaxId, forceRefresh },
629
- {
630
- FeCompConsReq: {
631
- CbteNro: number,
632
- PtoVta: salesPoint,
633
- CbteTipo: voucherType
634
- }
635
- }
636
- );
637
- const errors = extractWsfeGlobalIssues(result, operation);
638
- if (errors.length > 0 && errors.every((issue) => issue.code === "602")) {
639
- return {
640
- kind: "not_found",
641
- service: "wsfe",
642
- operation,
643
- errors,
644
- observations: [],
645
- raw: result
646
- };
647
- }
648
- if (errors.length > 0) {
649
- throw createWsfeServiceError(operation, result, errors);
650
- }
651
- const raw = toWsfeRecord(result.ResultGet);
652
- if (!raw) {
653
- throw new ArcaServiceError("WSFE did not return the consulted voucher", {
654
- service: "wsfe",
655
- operation,
656
- detail: result
657
- });
658
- }
659
- return {
660
- kind: "found",
661
- service: "wsfe",
662
- operation,
663
- voucher: mapWsfeVoucherInfo(raw),
664
- observations: [],
665
- raw: result
666
- };
667
- }
668
- return {
669
- authorizeVoucherOutcome,
670
- authorizeVoucher,
671
- async createNextVoucher({ representedTaxId, data, forceRefresh }) {
672
- const normalizedInput = normalizeWsfeVoucherInput(data);
673
- const voucherNumber = await getNextVoucherNumber({
674
- representedTaxId,
675
- salesPoint: normalizedInput.salesPoint,
676
- voucherType: normalizedInput.voucherType,
677
- forceRefresh
678
- });
679
- return authorizeNormalizedVoucher({
680
- representedTaxId,
681
- data: normalizedInput,
682
- voucherNumber
683
- });
684
- },
685
- getNextVoucherNumber,
686
- getLastVoucher(input) {
687
- return getNextVoucherNumber(input);
688
- },
689
- async getSalesPoints({ representedTaxId, forceRefresh }) {
690
- const result = await executeWsfeAuthenticatedOperation(
691
- "FEParamGetPtosVenta",
692
- {
693
- representedTaxId,
694
- forceRefresh
695
- }
696
- );
697
- const rawPoints = result.ResultGet?.PtoVenta;
698
- if (!rawPoints) {
699
- return [];
700
- }
701
- const entries = Array.isArray(rawPoints) ? rawPoints : [rawPoints];
702
- return entries.map(mapWsfeSalesPoint);
703
- },
704
- getVoucherTypes(input) {
705
- return getWsfeCatalog("FEParamGetTiposCbte", "CbteTipo", input);
706
- },
707
- getDocumentTypes(input) {
708
- return getWsfeCatalog("FEParamGetTiposDoc", "DocTipo", input);
709
- },
710
- getConceptTypes(input) {
711
- return getWsfeCatalog("FEParamGetTiposConcepto", "ConceptoTipo", input);
712
- },
713
- async getCurrencyTypes({ representedTaxId, forceRefresh }) {
714
- const result = await executeWsfeAuthenticatedOperation(
715
- "FEParamGetTiposMonedas",
716
- {
717
- representedTaxId,
718
- forceRefresh
719
- }
720
- );
721
- return getWsfeResultEntries(result, "Moneda").map(mapWsfeCurrencyType);
722
- },
723
- getVatRates(input) {
724
- return getWsfeCatalog("FEParamGetTiposIva", "IvaTipo", input);
725
- },
726
- getTaxTypes(input) {
727
- return getWsfeCatalog("FEParamGetTiposTributos", "TributoTipo", input);
728
- },
729
- getOptionalTypes(input) {
730
- return getWsfeCatalog("FEParamGetTiposOpcional", "OpcionalTipo", input);
731
- },
732
- async getActivities({ representedTaxId, forceRefresh }) {
733
- const result = await executeWsfeAuthenticatedOperation(
734
- "FEParamGetActividades",
735
- {
736
- representedTaxId,
737
- forceRefresh
738
- }
739
- );
740
- return getWsfeResultEntries(result, "ActividadesTipo").map(
741
- mapWsfeActivityType
742
- );
743
- },
744
- async getReceiverVatConditions({
745
- representedTaxId,
746
- voucherClass,
747
- forceRefresh
748
- }) {
749
- const result = await executeWsfeAuthenticatedOperation(
750
- "FEParamGetCondicionIvaReceptor",
751
- {
752
- representedTaxId,
753
- forceRefresh
754
- },
755
- {
756
- ...voucherClass === void 0 ? {} : { ClaseCmp: voucherClass }
757
- }
758
- );
759
- return getWsfeResultEntries(result, "CondicionIvaReceptor").map(
760
- mapWsfeReceiverVatCondition
761
- );
762
- },
763
- async getServerStatus() {
764
- const result = await executeWsfeOperation("FEDummy");
765
- return mapWsfeServerStatus(result);
766
- },
767
- async getQuotation({ currencyId, representedTaxId, forceRefresh }) {
768
- const result = await executeWsfeAuthenticatedOperation(
769
- "FEParamGetCotizacion",
770
- {
771
- representedTaxId,
772
- forceRefresh
773
- },
774
- {
775
- MonId: currencyId
776
- }
777
- );
778
- const raw = result.ResultGet ?? {};
779
- return mapWsfeQuotation(raw);
780
- },
781
- async getVoucherInfo(input) {
782
- const lookup = await lookupVoucher(input);
783
- return lookup.kind === "found" ? lookup.voucher : null;
784
- },
785
- lookupVoucher
786
- };
787
- }
788
- function mapWsfeVoucherInput(input, voucherNumber) {
789
- const sendsSameForeignCurrencyCancellation = input.currencyId !== "PES" && input.sameCurrencyForeignCancellation === "S";
790
- if (input.exchangeRate === void 0 && !sendsSameForeignCurrencyCancellation) {
791
- throw new ArcaInputError(
792
- "exchangeRate is required unless sameCurrencyForeignCancellation is S for a foreign-currency voucher."
793
- );
794
- }
795
- const data = {
796
- Concepto: input.concept,
797
- DocTipo: input.documentType,
798
- DocNro: input.documentNumber,
799
- CbteDesde: voucherNumber,
800
- CbteHasta: voucherNumber,
801
- CbteFch: input.voucherDate,
802
- ImpTotal: input.totalAmount,
803
- ImpTotConc: input.nonTaxableAmount,
804
- ImpNeto: input.netAmount,
805
- ImpOpEx: input.exemptAmount,
806
- ImpTrib: input.taxAmount,
807
- ImpIVA: input.vatAmount,
808
- MonId: input.currencyId,
809
- PtoVta: input.salesPoint,
810
- CbteTipo: input.voucherType
811
- };
812
- if (!sendsSameForeignCurrencyCancellation) {
813
- data.MonCotiz = input.exchangeRate;
814
- }
815
- if (input.receiverVatConditionId !== void 0) {
816
- data.CondicionIVAReceptorId = input.receiverVatConditionId;
817
- }
818
- if (input.currencyId !== "PES" && input.sameCurrencyForeignCancellation !== void 0) {
819
- data.CanMisMonExt = input.sameCurrencyForeignCancellation;
820
- }
821
- if (input.serviceStartDate !== void 0) {
822
- data.FchServDesde = input.serviceStartDate;
823
- }
824
- if (input.serviceEndDate !== void 0) {
825
- data.FchServHasta = input.serviceEndDate;
826
- }
827
- if (input.paymentDueDate !== void 0) {
828
- data.FchVtoPago = input.paymentDueDate;
829
- }
830
- if (input.associatedVouchers) {
831
- data.CbtesAsoc = {
832
- CbteAsoc: input.associatedVouchers.map((v) => ({
833
- Tipo: v.type,
834
- PtoVta: v.salesPoint,
835
- Nro: v.number,
836
- ...v.taxId === void 0 ? {} : { Cuit: v.taxId },
837
- ...v.voucherDate === void 0 ? {} : { CbteFch: v.voucherDate }
838
- }))
839
- };
840
- }
841
- if (input.associatedPeriod) {
842
- data.PeriodoAsoc = {
843
- FchDesde: input.associatedPeriod.startDate,
844
- FchHasta: input.associatedPeriod.endDate
845
- };
846
- }
847
- if (input.taxes) {
848
- data.Tributos = {
849
- Tributo: input.taxes.map((t) => ({
850
- Id: t.id,
851
- ...t.description === void 0 ? {} : { Desc: t.description },
852
- BaseImp: t.baseAmount,
853
- Alic: t.rate,
854
- Importe: t.amount
855
- }))
856
- };
857
- }
858
- if (input.vatRates) {
859
- data.Iva = {
860
- AlicIva: input.vatRates.map((v) => ({
861
- Id: v.id,
862
- BaseImp: v.baseAmount,
863
- Importe: v.amount
864
- }))
865
- };
866
- }
867
- if (input.optionalFields) {
868
- data.Opcionales = {
869
- Opcional: input.optionalFields.map((o) => ({
870
- Id: o.id,
871
- Valor: o.value
872
- }))
873
- };
874
- }
875
- if (input.buyers) {
876
- data.Compradores = {
877
- Comprador: input.buyers.map((b) => ({
878
- DocTipo: b.documentType,
879
- DocNro: b.documentNumber,
880
- Porcentaje: b.percentage
881
- }))
882
- };
883
- }
884
- if (input.activities) {
885
- data.Actividades = {
886
- Actividad: input.activities.map((a) => ({
887
- Id: a.id
888
- }))
889
- };
890
- }
891
- return data;
892
- }
893
- function normalizeWsfeVoucherInput(input) {
894
- const {
895
- voucherDate,
896
- serviceStartDate,
897
- serviceEndDate,
898
- paymentDueDate,
899
- associatedVouchers,
900
- associatedPeriod,
901
- ...rest
902
- } = input;
903
- return {
904
- ...rest,
905
- voucherDate: normalizeWsfeDateInput(voucherDate, "voucherDate"),
906
- ...serviceStartDate === void 0 ? {} : {
907
- serviceStartDate: normalizeWsfeDateInput(
908
- serviceStartDate,
909
- "serviceStartDate"
910
- )
911
- },
912
- ...serviceEndDate === void 0 ? {} : {
913
- serviceEndDate: normalizeWsfeDateInput(
914
- serviceEndDate,
915
- "serviceEndDate"
916
- )
917
- },
918
- ...paymentDueDate === void 0 ? {} : {
919
- paymentDueDate: normalizeWsfeDateInput(
920
- paymentDueDate,
921
- "paymentDueDate"
922
- )
923
- },
924
- ...associatedVouchers === void 0 ? {} : {
925
- associatedVouchers: associatedVouchers.map((voucher, index) => {
926
- const { voucherDate: associatedVoucherDate, ...associatedRest } = voucher;
927
- return {
928
- ...associatedRest,
929
- ...associatedVoucherDate === void 0 ? {} : {
930
- voucherDate: normalizeWsfeDateInput(
931
- associatedVoucherDate,
932
- `associatedVouchers[${index}].voucherDate`
933
- )
934
- }
935
- };
936
- })
937
- },
938
- ...associatedPeriod === void 0 ? {} : {
939
- associatedPeriod: {
940
- startDate: normalizeWsfeDateInput(
941
- associatedPeriod.startDate,
942
- "associatedPeriod.startDate"
943
- ),
944
- endDate: normalizeWsfeDateInput(
945
- associatedPeriod.endDate,
946
- "associatedPeriod.endDate"
947
- )
948
- }
949
- }
950
- };
951
- }
952
- function normalizeWsfeDateInput(value, fieldName) {
953
- if (typeof value !== "string") {
954
- throw new ArcaInputError(
955
- `Invalid WSFE ${fieldName}: expected a YYYY-MM-DD or YYYYMMDD string`,
956
- {
957
- detail: { field: fieldName, value }
958
- }
959
- );
960
- }
961
- const normalizedValue = value.trim();
962
- const afipMatch = normalizedValue.match(/^(\d{4})(\d{2})(\d{2})$/);
963
- if (afipMatch) {
964
- const [, year, month, day] = afipMatch;
965
- assertValidCalendarDate(year, month, day, fieldName, normalizedValue);
966
- return normalizedValue;
967
- }
968
- const isoMatch = normalizedValue.match(/^(\d{4})-(\d{2})-(\d{2})$/);
969
- if (isoMatch) {
970
- const [, year, month, day] = isoMatch;
971
- assertValidCalendarDate(year, month, day, fieldName, normalizedValue);
972
- return `${year}${month}${day}`;
973
- }
974
- throw new ArcaInputError(
975
- `Invalid WSFE ${fieldName}: expected a YYYY-MM-DD or YYYYMMDD string`,
976
- {
977
- detail: { field: fieldName, value: normalizedValue }
978
- }
979
- );
980
- }
981
- function assertValidCalendarDate(yearInput, monthInput, dayInput, fieldName, value) {
982
- const year = Number(yearInput);
983
- const month = Number(monthInput);
984
- const day = Number(dayInput);
985
- const candidate = new Date(Date.UTC(year, month - 1, day));
986
- if (candidate.getUTCFullYear() !== year || candidate.getUTCMonth() !== month - 1 || candidate.getUTCDate() !== day) {
987
- throw new ArcaInputError(
988
- `Invalid WSFE ${fieldName}: received a non-existent calendar date`,
989
- {
990
- detail: { field: fieldName, value }
991
- }
992
- );
993
- }
994
- }
995
- function mapWsfeSalesPoint(raw) {
996
- const record = raw;
997
- return {
998
- number: Number(record.Nro ?? 0),
999
- ...record.EmisionTipo === void 0 ? {} : { emissionType: String(record.EmisionTipo) },
1000
- ...record.Bloqueado === void 0 ? {} : { blocked: String(record.Bloqueado) },
1001
- ...record.FchBaja === void 0 ? {} : { deletedSince: String(record.FchBaja) }
1002
- };
1003
- }
1004
- function mapWsfeCatalogEntry(raw) {
1005
- const record = raw;
1006
- return {
1007
- id: Number(record.Id ?? 0),
1008
- description: String(record.Desc ?? "")
1009
- };
1010
- }
1011
- function mapWsfeActivityType(raw) {
1012
- const record = raw;
1013
- return {
1014
- id: Number(record.Id ?? 0),
1015
- description: String(record.Desc ?? ""),
1016
- order: Number(record.Orden ?? 0)
1017
- };
1018
- }
1019
- function mapWsfeReceiverVatCondition(raw) {
1020
- const record = raw;
1021
- return {
1022
- id: Number(record.Id ?? 0),
1023
- description: String(record.Desc ?? ""),
1024
- voucherClass: String(record.Cmp_Clase ?? "")
1025
- };
1026
- }
1027
- function mapWsfeCurrencyType(raw) {
1028
- const record = raw;
1029
- return {
1030
- id: String(record.Id ?? ""),
1031
- description: String(record.Desc ?? ""),
1032
- validFrom: String(record.FchDesde ?? ""),
1033
- validTo: String(record.FchHasta ?? "")
1034
- };
1035
- }
1036
- function mapWsfeServerStatus(raw) {
1037
- return {
1038
- appServer: String(raw.AppServer ?? ""),
1039
- dbServer: String(raw.DbServer ?? ""),
1040
- authServer: String(raw.AuthServer ?? "")
1041
- };
1042
- }
1043
- function mapWsfeQuotation(raw) {
1044
- return {
1045
- currencyId: String(raw.MonId ?? ""),
1046
- rate: Number(raw.MonCotiz ?? 0),
1047
- date: String(raw.FchCotiz ?? "")
1048
- };
1049
- }
1050
- function mapWsfeVoucherInfo(raw) {
1051
- const voucher = {
1052
- voucherNumber: Number(raw.CbteDesde ?? raw.CbteHasta ?? 0),
1053
- raw
1054
- };
1055
- assignWsfeValue(voucher, "voucherDate", normalizeWsfeString(raw.CbteFch));
1056
- assignWsfeValue(voucher, "salesPoint", normalizeWsfeNumber(raw.PtoVta));
1057
- assignWsfeValue(voucher, "voucherType", normalizeWsfeNumber(raw.CbteTipo));
1058
- assignWsfeValue(voucher, "concept", normalizeWsfeNumber(raw.Concepto));
1059
- assignWsfeValue(voucher, "documentType", normalizeWsfeNumber(raw.DocTipo));
1060
- assignWsfeValue(voucher, "documentNumber", normalizeWsfeString(raw.DocNro));
1061
- assignWsfeValue(
1062
- voucher,
1063
- "receiverVatConditionId",
1064
- normalizeWsfeNumber(raw.CondicionIVAReceptorId)
1065
- );
1066
- assignWsfeValue(voucher, "totalAmount", normalizeWsfeNumber(raw.ImpTotal));
1067
- assignWsfeValue(
1068
- voucher,
1069
- "nonTaxableAmount",
1070
- normalizeWsfeNumber(raw.ImpTotConc)
1071
- );
1072
- assignWsfeValue(voucher, "netAmount", normalizeWsfeNumber(raw.ImpNeto));
1073
- assignWsfeValue(voucher, "exemptAmount", normalizeWsfeNumber(raw.ImpOpEx));
1074
- assignWsfeValue(voucher, "taxAmount", normalizeWsfeNumber(raw.ImpTrib));
1075
- assignWsfeValue(voucher, "vatAmount", normalizeWsfeNumber(raw.ImpIVA));
1076
- assignWsfeValue(voucher, "currencyId", normalizeWsfeString(raw.MonId));
1077
- assignWsfeValue(voucher, "exchangeRate", normalizeWsfeNumber(raw.MonCotiz));
1078
- assignWsfeValue(voucher, "result", normalizeWsfeString(raw.Resultado));
1079
- assignWsfeValue(
1080
- voucher,
1081
- "cae",
1082
- normalizeWsfeString(raw.CodAutorizacion ?? raw.CAE)
1083
- );
1084
- assignWsfeValue(
1085
- voucher,
1086
- "caeExpiry",
1087
- normalizeWsfeString(raw.FchVto ?? raw.CAEFchVto)
1088
- );
1089
- return voucher;
1090
- }
1091
- function createWsfeAuth(representedTaxId, token, sign) {
1092
- return {
1093
- Token: token,
1094
- Sign: sign,
1095
- Cuit: Number.parseInt(String(representedTaxId), 10)
1096
- };
1097
- }
1098
- function unwrapWsfeOperationEnvelope(operation, response) {
1099
- const operationResponse = response[`${operation}Response`];
1100
- const result = operationResponse?.[`${operation}Result`] ?? response[`${operation}Result`] ?? response;
1101
- return result;
1102
- }
1103
- function throwForWsfeOperationErrors(operation, result) {
1104
- const errors = extractWsfeGlobalIssues(result, operation);
1105
- if (errors.length > 0) {
1106
- throw createWsfeServiceError(operation, result, errors);
1107
- }
1108
- }
1109
- function normalizeWsfeDetailResponse(result) {
1110
- const detailResponse = result.FeDetResp;
1111
- const rawDetail = detailResponse?.FECAEDetResponse;
1112
- if (Array.isArray(rawDetail)) {
1113
- return rawDetail[0] ?? {};
1114
- }
1115
- return rawDetail ?? {};
1116
- }
1117
- function classifyWsfeAuthorization(result, voucherNumber) {
1118
- const operation = "FECAESolicitar";
1119
- const header = toWsfeRecord(result.FeCabResp) ?? {};
1120
- const detail = normalizeWsfeDetailResponse(result);
1121
- const headerResult = normalizeWsfeResult(header.Resultado);
1122
- const detailResult = normalizeWsfeResult(detail.Resultado);
1123
- const resultCode = detailResult ?? headerResult;
1124
- const resultLevel = getWsfeResultLevel(headerResult, detailResult);
1125
- const cae = normalizeWsfeString(detail.CAE);
1126
- const caeExpiry = normalizeWsfeString(detail.CAEFchVto);
1127
- const errors = extractWsfeGlobalIssues(result, operation, "header");
1128
- const observations = extractWsfeObservations(
1129
- detail,
1130
- detailResult === "R" ? "business" : "observation"
1131
- );
1132
- const hasInfrastructureError = errors.some(
1133
- (issue) => issue.category === "infrastructure"
1134
- );
1135
- const base = {
1136
- service: "wsfe",
1137
- operation,
1138
- results: createWsfeResults(headerResult, detailResult),
1139
- errors,
1140
- observations,
1141
- raw: result
1142
- };
1143
- const context = {
1144
- base,
1145
- headerResult,
1146
- detailResult,
1147
- resultCode,
1148
- resultLevel,
1149
- cae,
1150
- caeExpiry
1151
- };
1152
- if (hasContradictoryWsfeResults(context)) {
1153
- return createWsfeStructuredIndeterminate(context, "contradictory_response");
1154
- }
1155
- if (hasInfrastructureError) {
1156
- return createWsfeStructuredIndeterminate(context, "incomplete_response");
1157
- }
1158
- if (isAuthorizedWsfeContext(context)) {
1159
- return {
1160
- ...base,
1161
- kind: "authorized",
1162
- result: "A",
1163
- resultLevel: "detail",
1164
- cae: context.cae,
1165
- caeExpiry: context.caeExpiry,
1166
- voucherNumber
1167
- };
1168
- }
1169
- if (isRejectedWsfeDetailContext(context)) {
1170
- return {
1171
- ...base,
1172
- kind: "rejected",
1173
- result: "R",
1174
- resultLevel: "detail"
1175
- };
1176
- }
1177
- if (isRejectedWsfeHeaderContext(context)) {
1178
- return {
1179
- ...base,
1180
- kind: "rejected",
1181
- result: "R",
1182
- resultLevel: "header"
1183
- };
1184
- }
1185
- return createWsfeStructuredIndeterminate(
1186
- context,
1187
- hasWsfeCaeContradiction(context) ? "contradictory_response" : "incomplete_response"
1188
- );
1189
- }
1190
- function getWsfeResultLevel(headerResult, detailResult) {
1191
- if (detailResult) {
1192
- return "detail";
1193
- }
1194
- return headerResult ? "header" : void 0;
1195
- }
1196
- function hasContradictoryWsfeResults(context) {
1197
- return Boolean(
1198
- context.headerResult && context.detailResult && context.headerResult !== context.detailResult
1199
- );
1200
- }
1201
- function isAuthorizedWsfeContext(context) {
1202
- return Boolean(
1203
- context.detailResult === "A" && context.headerResult !== "R" && context.base.errors.length === 0 && context.cae && context.caeExpiry
1204
- );
1205
- }
1206
- function isRejectedWsfeDetailContext(context) {
1207
- return context.detailResult === "R" && context.headerResult !== "A" && !context.cae;
1208
- }
1209
- function isRejectedWsfeHeaderContext(context) {
1210
- return context.headerResult === "R" && context.detailResult === void 0 && !context.cae && context.base.errors.length > 0 && context.base.errors.every((issue) => issue.category === "business");
1211
- }
1212
- function hasWsfeCaeContradiction(context) {
1213
- return (context.resultCode === "A" || context.resultCode === "R") && Boolean(context.cae);
1214
- }
1215
- function createWsfeStructuredIndeterminate(context, reason) {
1216
- const outcome = {
1217
- ...context.base,
1218
- kind: "indeterminate",
1219
- reason
1220
- };
1221
- assignWsfeValue(outcome, "result", context.resultCode);
1222
- assignWsfeValue(outcome, "resultLevel", context.resultLevel);
1223
- assignWsfeValue(outcome, "cae", context.cae);
1224
- assignWsfeValue(outcome, "caeExpiry", context.caeExpiry);
1225
- return outcome;
1226
- }
1227
- function createWsfeResults(headerResult, detailResult) {
1228
- const results = {};
1229
- assignWsfeValue(results, "header", headerResult);
1230
- assignWsfeValue(results, "detail", detailResult);
1231
- return results;
1232
- }
1233
- function createWsfeIndeterminateOutcome(error) {
1234
- return {
1235
- kind: "indeterminate",
1236
- service: "wsfe",
1237
- operation: "FECAESolicitar",
1238
- results: {},
1239
- reason: getArcaIndeterminateReason(error),
1240
- errors: [],
1241
- observations: []
1242
- };
1243
- }
1244
- function getArcaIndeterminateReason(error) {
1245
- if (error instanceof ArcaTransportError) {
1246
- return "transport_error";
1247
- }
1248
- if (error instanceof ArcaSoapFaultError) {
1249
- return "soap_fault";
1250
- }
1251
- if (error instanceof ArcaInvalidSoapResponseError) {
1252
- return "invalid_response";
1253
- }
1254
- return "unexpected_error";
1255
- }
1256
- function createWsfeOutcomeError(outcome) {
1257
- const issues = [...outcome.errors, ...outcome.observations];
1258
- const firstIssue = issues[0];
1259
- const message = firstIssue ? formatWsfeIssue(firstIssue) : outcome.kind === "rejected" ? "WSFE rejected the voucher authorization" : outcome.result === "A" ? "WSFE did not return CAE authorization data" : "WSFE did not return conclusive voucher authorization data";
1260
- return new ArcaServiceError(message, {
1261
- service: "wsfe",
1262
- operation: outcome.operation,
1263
- ...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
1264
- ...outcome.result === void 0 ? {} : { result: outcome.result },
1265
- ...outcome.resultLevel === void 0 ? {} : { resultLevel: outcome.resultLevel },
1266
- results: outcome.results,
1267
- ...outcome.kind === "indeterminate" && outcome.cae ? { cae: outcome.cae } : {},
1268
- issues,
1269
- detail: outcome.raw
1270
- });
1271
- }
1272
- function createWsfeServiceError(operation, result, issues) {
1273
- const firstIssue = issues[0];
1274
- return new ArcaServiceError(
1275
- firstIssue ? formatWsfeIssue(firstIssue) : "WSFE returned a service error",
1276
- {
1277
- service: "wsfe",
1278
- operation,
1279
- ...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
1280
- issues,
1281
- detail: result
1282
- }
1283
- );
1284
- }
1285
- function extractWsfeGlobalIssues(result, operation, resultLevel) {
1286
- const errorsContainer = toWsfeRecord(result.Errors);
1287
- return normalizeWsfeIssueEntries(errorsContainer?.Err).map((entry) => ({
1288
- service: "wsfe",
1289
- operation,
1290
- source: "error",
1291
- category: operation === "FECAESolicitar" && WSFE_AUTHORIZATION_INFRASTRUCTURE_CODES.has(entry.code ?? "") ? "infrastructure" : operation === "FECAESolicitar" ? "business" : "unknown",
1292
- ...entry.code === void 0 ? {} : { code: entry.code },
1293
- message: entry.message,
1294
- ...resultLevel === void 0 ? {} : { resultLevel }
1295
- }));
1296
- }
1297
- function extractWsfeObservations(detail, category) {
1298
- const observationsContainer = toWsfeRecord(detail.Observaciones);
1299
- return normalizeWsfeIssueEntries(observationsContainer?.Obs).map((entry) => ({
1300
- service: "wsfe",
1301
- operation: "FECAESolicitar",
1302
- source: "observation",
1303
- category,
1304
- ...entry.code === void 0 ? {} : { code: entry.code },
1305
- message: entry.message,
1306
- resultLevel: "detail"
1307
- }));
1308
- }
1309
- function normalizeWsfeIssueEntries(rawErrors) {
1310
- const entries = Array.isArray(rawErrors) ? rawErrors : rawErrors ? [rawErrors] : [];
1311
- return entries.map((entry) => entry).map((entry) => {
1312
- const code = entry.Code ?? entry.code;
1313
- const message = entry.Msg ?? entry.msg ?? "Unknown WSFE error";
1314
- return {
1315
- ...code === void 0 ? {} : { code: String(code) },
1316
- message: String(message)
1317
- };
1318
- });
1319
- }
1320
- function formatWsfeIssue(issue) {
1321
- return issue.code ? `(${issue.code}) ${issue.message}` : issue.message;
1322
- }
1323
- function normalizeWsfeResult(value) {
1324
- if (typeof value !== "string") {
1325
- return void 0;
1326
- }
1327
- const normalized = value.trim().toUpperCase();
1328
- return normalized || void 0;
1329
- }
1330
- function normalizeWsfeString(value) {
1331
- if (value === void 0 || value === null) {
1332
- return void 0;
1333
- }
1334
- const normalized = String(value).trim();
1335
- return normalized || void 0;
1336
- }
1337
- function normalizeWsfeNumber(value) {
1338
- if (value === void 0 || value === null || value === "") {
1339
- return void 0;
1340
- }
1341
- const normalized = Number(value);
1342
- return Number.isFinite(normalized) ? normalized : void 0;
1343
- }
1344
- function assignWsfeValue(target, key, value) {
1345
- if (value !== void 0) {
1346
- target[key] = value;
1347
- }
1348
- }
1349
- function toWsfeRecord(value) {
1350
- return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1351
- }
1352
- var WSFE_AUTHORIZATION_INFRASTRUCTURE_CODES = /* @__PURE__ */ new Set([
1353
- "500",
1354
- "501",
1355
- "502",
1356
- "600",
1357
- "601"
1358
- ]);
1359
- function getWsfeResultEntries(result, key) {
1360
- const rawEntries = result.ResultGet?.[key];
1361
- if (!rawEntries) {
1362
- return [];
1363
- }
1364
- return (Array.isArray(rawEntries) ? rawEntries : [rawEntries]).map(
1365
- (entry) => entry
1366
- );
1367
- }
1368
-
1369
- // src/services/wsmtxca.ts
1370
- function createWsmtxcaService(options) {
1371
- async function executeWsmtxcaAuthenticatedOperation(operation, input, body = {}, retries) {
1372
- const auth = await options.auth.login("wsmtxca", {
1373
- representedTaxId: input.representedTaxId,
1374
- forceRefresh: input.forceRefresh
1375
- });
1376
- const response = await options.soap.execute({
1377
- service: "wsmtxca",
1378
- operation,
1379
- ...retries === void 0 ? {} : { retries },
1380
- bodyElementName: `${operation}Request`,
1381
- bodyElementNamespaceMode: "prefix",
1382
- body: {
1383
- authRequest: createWsmtxcaAuth(
1384
- input.representedTaxId ?? options.config.taxId,
1385
- auth.token,
1386
- auth.sign
1387
- ),
1388
- ...body
1389
- }
1390
- });
1391
- return unwrapWsmtxcaOperationResponse(response.result, operation);
1392
- }
1393
- async function executeWsmtxcaAuthorization({
1394
- representedTaxId,
1395
- data,
1396
- forceRefresh
1397
- }) {
1398
- try {
1399
- const raw = await executeWsmtxcaAuthenticatedOperation(
1400
- "autorizarComprobante",
1401
- { representedTaxId, forceRefresh },
1402
- data,
1403
- 0
1404
- );
1405
- return { outcome: classifyWsmtxcaAuthorization(raw) };
1406
- } catch (error) {
1407
- return {
1408
- outcome: createWsmtxcaIndeterminateOutcome(error),
1409
- error
1410
- };
1411
- }
1412
- }
1413
- async function authorizeVoucherOutcome(input) {
1414
- return (await executeWsmtxcaAuthorization(input)).outcome;
1415
- }
1416
- async function authorizeVoucher(input) {
1417
- const execution = await executeWsmtxcaAuthorization(input);
1418
- if (execution.error) {
1419
- throw execution.error;
1420
- }
1421
- if (execution.outcome.kind !== "authorized") {
1422
- throw createWsmtxcaOutcomeError(execution.outcome);
1423
- }
1424
- const { outcome } = execution;
1425
- return {
1426
- cae: outcome.cae,
1427
- ...outcome.caeExpiry === void 0 ? {} : { caeExpiry: outcome.caeExpiry },
1428
- voucherNumber: outcome.voucherNumber,
1429
- messages: formatWsmtxcaIssues([
1430
- ...outcome.errors,
1431
- ...outcome.observations
1432
- ]),
1433
- raw: outcome.raw ?? {}
1434
- };
1435
- }
1436
- async function getLastAuthorizedVoucher({
1437
- representedTaxId,
1438
- voucherType,
1439
- salesPoint,
1440
- forceRefresh
1441
- }) {
1442
- const operation = "consultarUltimoComprobanteAutorizado";
1443
- const raw = await executeWsmtxcaAuthenticatedOperation(
1444
- operation,
1445
- { representedTaxId, forceRefresh },
1446
- {
1447
- consultaUltimoComprobanteAutorizadoRequest: {
1448
- codigoTipoComprobante: voucherType,
1449
- numeroPuntoVenta: salesPoint
1450
- }
1451
- }
1452
- );
1453
- const errors = extractWsmtxcaIssues(raw, operation, "error");
1454
- if (errors.length > 0 && errors.every((issue) => issue.code === "1502")) {
1455
- return { voucherNumber: 0, raw };
1456
- }
1457
- if (errors.length > 0) {
1458
- throw createWsmtxcaServiceError(operation, raw, errors);
1459
- }
1460
- return {
1461
- voucherNumber: parseWsmtxcaVoucherNumber(
1462
- raw.numeroComprobante ?? raw.cbteNro ?? raw.nroComprobante,
1463
- "WSMTXCA did not return the last authorized voucher number",
1464
- raw,
1465
- true
1466
- ),
1467
- raw
1468
- };
1469
- }
1470
- async function getSalesPoints({
1471
- representedTaxId,
1472
- forceRefresh
1473
- }) {
1474
- const raw = await executeWsmtxcaAuthenticatedOperation(
1475
- "consultarPuntosVenta",
1476
- { representedTaxId, forceRefresh }
1477
- );
1478
- const rawSalesPoints = toRecord(raw.arrayPuntosVenta)?.puntoVenta;
1479
- const entries = Array.isArray(rawSalesPoints) ? rawSalesPoints : rawSalesPoints ? [rawSalesPoints] : [];
1480
- const salesPoints = entries.flatMap((entry) => {
1481
- const record = toRecord(entry);
1482
- const number = parseOptionalPositiveInteger(record?.numeroPuntoVenta);
1483
- if (number === void 0) {
1484
- return [];
1485
- }
1486
- const deletedAt = normalizeWsmtxcaResponseDate(record?.fechaBaja);
1487
- return [
1488
- {
1489
- number,
1490
- blocked: String(record?.bloqueado ?? "N").toUpperCase() === "S",
1491
- ...deletedAt === void 0 ? {} : { deletedAt }
1492
- }
1493
- ];
1494
- });
1495
- return { salesPoints, raw };
179
+ test: "https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA13"
180
+ },
181
+ soapVersion: "1.1",
182
+ soapActionBase: "",
183
+ usesEmptySoapAction: true
1496
184
  }
1497
- async function lookupVoucher({
1498
- representedTaxId,
1499
- voucherType,
1500
- salesPoint,
1501
- voucherNumber,
1502
- forceRefresh
1503
- }) {
1504
- const operation = "consultarComprobante";
1505
- const raw = await executeWsmtxcaAuthenticatedOperation(
1506
- operation,
1507
- { representedTaxId, forceRefresh },
1508
- {
1509
- consultaComprobanteRequest: {
1510
- codigoTipoComprobante: voucherType,
1511
- numeroPuntoVenta: salesPoint,
1512
- numeroComprobante: voucherNumber
1513
- }
1514
- }
185
+ };
186
+ function getArcaServiceConfig(service) {
187
+ const serviceConfig = ARCA_SERVICE_CONFIG[service];
188
+ if (!serviceConfig) {
189
+ throw new ArcaConfigurationError(
190
+ `Unsupported ARCA service configuration: ${service}`
1515
191
  );
1516
- const errors = extractWsmtxcaIssues(raw, operation, "error");
1517
- const observations = extractWsmtxcaIssues(raw, operation, "observation");
1518
- if (errors.length > 0 && errors.every((issue) => issue.code === "1503")) {
1519
- return {
1520
- kind: "not_found",
1521
- service: "wsmtxca",
1522
- operation,
1523
- errors,
1524
- observations,
1525
- raw
1526
- };
1527
- }
1528
- if (errors.length > 0) {
1529
- throw createWsmtxcaServiceError(operation, raw, errors);
1530
- }
1531
- const voucher = extractWsmtxcaVoucherPayload(raw);
1532
- if (voucher === raw && !toRecord(raw.comprobante)) {
1533
- throw new ArcaServiceError(
1534
- "WSMTXCA did not return the voucher issue date",
1535
- {
1536
- service: "wsmtxca",
1537
- operation,
1538
- issues: observations,
1539
- detail: raw
1540
- }
1541
- );
1542
- }
1543
- return {
1544
- kind: "found",
1545
- service: "wsmtxca",
1546
- operation,
1547
- voucher: mapWsmtxcaVoucherInfo(voucher),
1548
- observations,
1549
- raw
1550
- };
1551
- }
1552
- async function getVoucher(input) {
1553
- const lookup = await lookupVoucher(input);
1554
- if (lookup.kind === "not_found") {
1555
- throw createWsmtxcaServiceError(
1556
- lookup.operation,
1557
- lookup.raw,
1558
- lookup.errors
1559
- );
1560
- }
1561
- const invoiceDate = lookup.voucher.invoiceDate;
1562
- if (!invoiceDate) {
1563
- throw new ArcaServiceError(
1564
- formatWsmtxcaIssues(lookup.observations)[0] ?? "WSMTXCA did not return the voucher issue date",
1565
- {
1566
- service: "wsmtxca",
1567
- operation: lookup.operation,
1568
- issues: lookup.observations,
1569
- detail: lookup.raw
1570
- }
1571
- );
1572
- }
1573
- return {
1574
- invoiceDate,
1575
- voucher: lookup.voucher.raw,
1576
- messages: formatWsmtxcaIssues(lookup.observations),
1577
- raw: lookup.raw
1578
- };
1579
192
  }
1580
- return {
1581
- authorizeVoucherOutcome,
1582
- authorizeVoucher,
1583
- getLastAuthorizedVoucher,
1584
- getSalesPoints,
1585
- lookupVoucher,
1586
- getVoucher
1587
- };
193
+ return serviceConfig;
1588
194
  }
1589
- function createWsmtxcaAuth(representedTaxId, token, sign) {
195
+ function normalizeArcaClientConfig(config) {
196
+ const normalizedEnvironment = normalizeEnvironmentValue(String(config.environment)) ?? config.environment;
197
+ const normalizedLoggerLevel = normalizeLogLevelValue(config.logger?.level);
1590
198
  return {
1591
- token,
1592
- sign,
1593
- cuitRepresentada: Number.parseInt(String(representedTaxId), 10)
199
+ taxId: config.taxId.trim(),
200
+ certificatePem: config.certificatePem.trim(),
201
+ privateKeyPem: config.privateKeyPem.trim(),
202
+ environment: normalizedEnvironment,
203
+ timeout: config.timeout ?? DEFAULT_ARCA_TIMEOUT_MS,
204
+ retries: config.retries ?? DEFAULT_ARCA_RETRIES,
205
+ retryDelay: config.retryDelay ?? DEFAULT_ARCA_RETRY_DELAY_MS,
206
+ ...config.logger === void 0 ? {} : {
207
+ logger: {
208
+ ...config.logger,
209
+ ...normalizedLoggerLevel === void 0 ? {} : { level: normalizedLoggerLevel }
210
+ }
211
+ },
212
+ ...config.wsaaSessionStore === void 0 ? {} : { wsaaSessionStore: config.wsaaSessionStore }
1594
213
  };
1595
214
  }
1596
- function toRecord(value) {
1597
- return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1598
- }
1599
- function unwrapWsmtxcaOperationResponse(response, operation) {
1600
- const responseRecord = toRecord(response) ?? {};
1601
- if (operation === "autorizarComprobante") {
1602
- return toRecord(responseRecord.autorizarComprobanteResponse) ?? toRecord(responseRecord.autorizarComprobanteResult) ?? toRecord(responseRecord.comprobanteCAEResponse) ?? toRecord(responseRecord.comprobanteCAEReponse) ?? responseRecord;
1603
- }
1604
- if (operation === "consultarComprobante") {
1605
- return toRecord(responseRecord.consultarComprobanteResponse) ?? toRecord(responseRecord.consultaComprobanteResponse) ?? toRecord(responseRecord.consultarComprobanteResult) ?? responseRecord;
1606
- }
1607
- if (operation === "consultarPuntosVenta") {
1608
- return toRecord(responseRecord.consultarPuntosVentaResponse) ?? toRecord(responseRecord.consultarPuntosVentaResult) ?? responseRecord;
1609
- }
1610
- return toRecord(responseRecord.consultarUltimoComprobanteAutorizadoResponse) ?? toRecord(responseRecord.consultaUltimoComprobanteAutorizadoResponse) ?? toRecord(responseRecord.consultarUltimoComprobanteAutorizadoResult) ?? responseRecord;
1611
- }
1612
- function extractWsmtxcaAuthorizationPayload(raw) {
1613
- return toRecord(raw.comprobanteResponse) ?? toRecord(raw.comprobanteCAEResponse) ?? toRecord(raw.comprobanteCAEReponse) ?? raw;
1614
- }
1615
- function extractWsmtxcaVoucherPayload(raw) {
1616
- return toRecord(raw.comprobanteResponse) ?? toRecord(raw.comprobante) ?? toRecord(raw.cmp) ?? raw;
1617
- }
1618
- function classifyWsmtxcaAuthorization(raw) {
1619
- const operation = "autorizarComprobante";
1620
- const payload = extractWsmtxcaAuthorizationPayload(raw);
1621
- const result = normalizeWsmtxcaResult(raw.resultado ?? payload.resultado);
1622
- const cae = normalizeWsmtxcaString(
1623
- payload.CAE ?? payload.codigoAutorizacion ?? raw.codigoAutorizacion
1624
- );
1625
- const caeExpiry = normalizeWsmtxcaResponseDate(
1626
- payload.fechaVencimientoCAE ?? payload.fechaVencimiento ?? raw.fechaVencimiento
1627
- );
1628
- const voucherNumber = parseOptionalPositiveInteger(
1629
- payload.numeroComprobante ?? raw.numeroComprobante
1630
- );
1631
- const errors = extractWsmtxcaIssues(raw, operation, "error");
1632
- const observations = extractWsmtxcaIssues(raw, operation, "observation");
1633
- const base = {
1634
- service: "wsmtxca",
1635
- operation,
1636
- results: createWsmtxcaResults(result),
1637
- errors,
1638
- observations,
1639
- raw
1640
- };
1641
- if ((result === "A" || result === "O") && cae && voucherNumber !== void 0 && errors.length === 0) {
1642
- return {
1643
- ...base,
1644
- kind: "authorized",
1645
- result,
1646
- resultLevel: "operation",
1647
- cae,
1648
- ...caeExpiry === void 0 ? {} : { caeExpiry },
1649
- voucherNumber
1650
- };
215
+ function normalizeEnvironmentValue(value) {
216
+ if (!value) {
217
+ return void 0;
1651
218
  }
1652
- if (result === "R" && !cae && errors.length > 0) {
1653
- return {
1654
- ...base,
1655
- kind: "rejected",
1656
- result: "R",
1657
- resultLevel: "operation"
1658
- };
219
+ const normalized = value.trim().toLowerCase();
220
+ if (ARCA_ENVIRONMENTS.includes(normalized)) {
221
+ return normalized;
1659
222
  }
1660
- const outcome = {
1661
- ...base,
1662
- kind: "indeterminate",
1663
- reason: result === "R" && Boolean(cae) || (result === "A" || result === "O") && Boolean(errors.length) ? "contradictory_response" : "incomplete_response",
1664
- ...result === void 0 ? {} : { result },
1665
- ...result === void 0 ? {} : { resultLevel: "operation" }
1666
- };
1667
- assignWsmtxcaValue(outcome, "cae", cae);
1668
- assignWsmtxcaValue(outcome, "caeExpiry", caeExpiry);
1669
- assignWsmtxcaValue(outcome, "voucherNumber", voucherNumber);
1670
- return outcome;
223
+ return void 0;
1671
224
  }
1672
- function createWsmtxcaIndeterminateOutcome(error) {
1673
- return {
1674
- kind: "indeterminate",
1675
- service: "wsmtxca",
1676
- operation: "autorizarComprobante",
1677
- results: {},
1678
- reason: getWsmtxcaIndeterminateReason(error),
1679
- errors: [],
1680
- observations: []
1681
- };
225
+ function readEnv(env, variableName) {
226
+ return env[variableName]?.trim() || void 0;
1682
227
  }
1683
- function getWsmtxcaIndeterminateReason(error) {
1684
- if (error instanceof ArcaTransportError) {
1685
- return "transport_error";
1686
- }
1687
- if (error instanceof ArcaSoapFaultError) {
1688
- return "soap_fault";
228
+ function normalizeLogLevelValue(value) {
229
+ if (!value) {
230
+ return void 0;
1689
231
  }
1690
- if (error instanceof ArcaInvalidSoapResponseError) {
1691
- return "invalid_response";
232
+ const normalized = value.trim().toLowerCase();
233
+ if (VALID_ARCA_LOG_LEVELS.includes(normalized)) {
234
+ return normalized;
1692
235
  }
1693
- return "unexpected_error";
236
+ return value;
1694
237
  }
1695
- function createWsmtxcaOutcomeError(outcome) {
1696
- const issues = [...outcome.errors, ...outcome.observations];
1697
- const messages = formatWsmtxcaIssues(issues);
1698
- const firstIssue = issues[0];
1699
- return new ArcaServiceError(
1700
- messages.join(" | ") || (outcome.kind === "rejected" ? "WSMTXCA rejected the voucher authorization" : "WSMTXCA did not return conclusive voucher authorization data"),
1701
- {
1702
- service: "wsmtxca",
1703
- operation: outcome.operation,
1704
- ...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
1705
- ...outcome.result === void 0 ? {} : { result: outcome.result },
1706
- ...outcome.resultLevel === void 0 ? {} : { resultLevel: outcome.resultLevel },
1707
- results: outcome.results,
1708
- ...outcome.kind === "indeterminate" && outcome.cae ? { cae: outcome.cae } : {},
1709
- issues,
1710
- detail: outcome.raw
238
+
239
+ // src/internal/logger.ts
240
+ var ARCA_LOG_LEVELS = ["debug", "info", "warn", "error"];
241
+ function createArcaLogger(config) {
242
+ const disabled = config?.disabled ?? false;
243
+ const level = resolveArcaLogLevel(config?.level);
244
+ const sink = config?.log ?? defaultArcaLog;
245
+ const log = (messageLevel, message, ...args) => {
246
+ if (disabled || !shouldLog(level, messageLevel)) {
247
+ return;
1711
248
  }
1712
- );
1713
- }
1714
- function createWsmtxcaResults(operationResult) {
1715
- const results = {};
1716
- assignWsmtxcaValue(results, "operation", operationResult);
1717
- return results;
1718
- }
1719
- function createWsmtxcaServiceError(operation, raw, issues) {
1720
- const firstIssue = issues[0];
1721
- return new ArcaServiceError(
1722
- formatWsmtxcaIssues(issues).join(" | ") || "WSMTXCA returned a service error",
1723
- {
1724
- service: "wsmtxca",
1725
- operation,
1726
- ...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
1727
- issues,
1728
- detail: raw
249
+ sink(messageLevel, message, ...args);
250
+ };
251
+ return {
252
+ disabled,
253
+ level,
254
+ log,
255
+ debug(message, ...args) {
256
+ log("debug", message, ...args);
257
+ },
258
+ info(message, ...args) {
259
+ log("info", message, ...args);
260
+ },
261
+ warn(message, ...args) {
262
+ log("warn", message, ...args);
263
+ },
264
+ error(message, ...args) {
265
+ log("error", message, ...args);
1729
266
  }
1730
- );
1731
- }
1732
- function extractWsmtxcaIssues(raw, operation, source) {
1733
- const container = toRecord(
1734
- source === "error" ? raw.arrayErrores : raw.arrayObservaciones
1735
- );
1736
- return normalizeWsmtxcaIssueEntries(container?.codigoDescripcion).map(
1737
- (entry) => ({
1738
- service: "wsmtxca",
1739
- operation,
1740
- source,
1741
- category: source === "observation" ? "observation" : operation === "autorizarComprobante" ? "business" : "unknown",
1742
- ...entry.code === void 0 ? {} : { code: entry.code },
1743
- message: entry.message,
1744
- ...operation === "autorizarComprobante" ? { resultLevel: "operation" } : {}
1745
- })
1746
- );
1747
- }
1748
- function normalizeWsmtxcaIssueEntries(value) {
1749
- const entries = Array.isArray(value) ? value : value ? [value] : [];
1750
- return entries.map((entry) => {
1751
- const record = toRecord(entry) ?? {};
1752
- const code = record.codigo;
1753
- const description = record.descripcion;
1754
- return {
1755
- ...code === void 0 || code === null ? {} : { code: String(code) },
1756
- message: description === void 0 || description === null ? "Unknown WSMTXCA issue" : String(description)
1757
- };
1758
- });
1759
- }
1760
- function formatWsmtxcaIssues(issues) {
1761
- return issues.map((issue) => {
1762
- const prefix = issue.source === "error" ? "Error" : "Obs";
1763
- return `${prefix}${issue.code ? ` ${issue.code}` : ""}: ${issue.message}`;
1764
- });
1765
- }
1766
- function mapWsmtxcaVoucherInfo(raw) {
1767
- const voucher = { raw };
1768
- const invoiceDate = normalizeWsmtxcaResponseDate(
1769
- raw.fechaEmision ?? raw.fecha ?? raw.CbteFch
1770
- );
1771
- const cae = normalizeWsmtxcaString(raw.codigoAutorizacion ?? raw.CAE);
1772
- const caeExpiry = normalizeWsmtxcaResponseDate(
1773
- raw.fechaVencimiento ?? raw.fechaVencimientoCAE
1774
- );
1775
- const vatAmount = sumWsmtxcaVatAmounts(raw.arraySubtotalesIVA);
1776
- assignWsmtxcaValue(
1777
- voucher,
1778
- "voucherNumber",
1779
- parseOptionalPositiveInteger(raw.numeroComprobante)
1780
- );
1781
- assignWsmtxcaValue(voucher, "invoiceDate", invoiceDate);
1782
- assignWsmtxcaValue(
1783
- voucher,
1784
- "salesPoint",
1785
- parseOptionalPositiveInteger(raw.numeroPuntoVenta)
1786
- );
1787
- assignWsmtxcaValue(
1788
- voucher,
1789
- "voucherType",
1790
- parseOptionalPositiveInteger(raw.codigoTipoComprobante)
1791
- );
1792
- assignWsmtxcaValue(
1793
- voucher,
1794
- "concept",
1795
- parseOptionalNumber(raw.codigoConcepto)
1796
- );
1797
- assignWsmtxcaValue(
1798
- voucher,
1799
- "documentType",
1800
- parseOptionalNumber(raw.codigoTipoDocumento)
1801
- );
1802
- assignWsmtxcaValue(
1803
- voucher,
1804
- "documentNumber",
1805
- normalizeWsmtxcaString(raw.numeroDocumento)
1806
- );
1807
- assignWsmtxcaValue(
1808
- voucher,
1809
- "receiverVatConditionId",
1810
- parseOptionalNumber(raw.condicionIVAReceptor)
1811
- );
1812
- assignWsmtxcaValue(
1813
- voucher,
1814
- "totalAmount",
1815
- parseOptionalNumber(raw.importeTotal)
1816
- );
1817
- assignWsmtxcaValue(
1818
- voucher,
1819
- "subtotalAmount",
1820
- parseOptionalNumber(raw.importeSubtotal)
1821
- );
1822
- assignWsmtxcaValue(
1823
- voucher,
1824
- "taxableAmount",
1825
- parseOptionalNumber(raw.importeGravado)
1826
- );
1827
- assignWsmtxcaValue(
1828
- voucher,
1829
- "nonTaxableAmount",
1830
- parseOptionalNumber(raw.importeNoGravado)
1831
- );
1832
- assignWsmtxcaValue(
1833
- voucher,
1834
- "exemptAmount",
1835
- parseOptionalNumber(raw.importeExento)
1836
- );
1837
- assignWsmtxcaValue(
1838
- voucher,
1839
- "taxAmount",
1840
- parseOptionalNumber(raw.importeOtrosTributos)
1841
- );
1842
- assignWsmtxcaValue(voucher, "vatAmount", vatAmount);
1843
- assignWsmtxcaValue(
1844
- voucher,
1845
- "currencyId",
1846
- normalizeWsmtxcaString(raw.codigoMoneda)
1847
- );
1848
- assignWsmtxcaValue(
1849
- voucher,
1850
- "exchangeRate",
1851
- parseOptionalNumber(raw.cotizacionMoneda)
1852
- );
1853
- assignWsmtxcaValue(voucher, "cae", cae);
1854
- assignWsmtxcaValue(voucher, "caeExpiry", caeExpiry);
1855
- return voucher;
1856
- }
1857
- function sumWsmtxcaVatAmounts(value) {
1858
- const subtotals = toRecord(value)?.subtotalIVA;
1859
- const entries = Array.isArray(subtotals) ? subtotals : subtotals ? [subtotals] : [];
1860
- const amounts = entries.map((entry) => parseOptionalNumber(toRecord(entry)?.importe)).filter((amount) => amount !== void 0);
1861
- return amounts.length > 0 ? amounts.reduce((total, amount) => total + amount, 0) : void 0;
1862
- }
1863
- function parseWsmtxcaVoucherNumber(value, message, detail, allowZero = false) {
1864
- const parsed = Number.parseInt(String(value ?? ""), 10);
1865
- if (!Number.isFinite(parsed) || (allowZero ? parsed < 0 : parsed <= 0)) {
1866
- throw new ArcaServiceError(message, {
1867
- service: "wsmtxca",
1868
- detail
1869
- });
1870
- }
1871
- return parsed;
1872
- }
1873
- function parseOptionalPositiveInteger(value) {
1874
- const parsed = Number.parseInt(String(value ?? ""), 10);
1875
- return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
1876
- }
1877
- function parseOptionalNumber(value) {
1878
- if (value === void 0 || value === null || value === "") {
1879
- return void 0;
1880
- }
1881
- const parsed = Number(value);
1882
- return Number.isFinite(parsed) ? parsed : void 0;
267
+ };
1883
268
  }
1884
- function normalizeWsmtxcaResult(value) {
1885
- if (typeof value !== "string") {
1886
- return void 0;
269
+ function resolveArcaLogLevel(level) {
270
+ if (isArcaLogLevel(level)) {
271
+ return level;
1887
272
  }
1888
- const normalized = value.trim().toUpperCase();
1889
- return normalized || void 0;
1890
- }
1891
- function normalizeWsmtxcaString(value) {
1892
- if (value === void 0 || value === null) {
1893
- return void 0;
273
+ const envLevel = process.env.ARCA_LOG_LEVEL?.trim().toLowerCase();
274
+ if (isArcaLogLevel(envLevel)) {
275
+ return envLevel;
1894
276
  }
1895
- const normalized = String(value).trim();
1896
- return normalized || void 0;
277
+ return "warn";
1897
278
  }
1898
- function assignWsmtxcaValue(target, key, value) {
1899
- if (value !== void 0) {
1900
- target[key] = value;
1901
- }
279
+ function shouldLog(threshold, messageLevel) {
280
+ return ARCA_LOG_LEVELS.indexOf(messageLevel) >= ARCA_LOG_LEVELS.indexOf(threshold);
1902
281
  }
1903
- function normalizeWsmtxcaResponseDate(value) {
1904
- if (typeof value === "number" && Number.isInteger(value)) {
1905
- return formatCompactDateToIso(value);
1906
- }
1907
- if (typeof value !== "string") {
1908
- return void 0;
1909
- }
1910
- const trimmed = value.trim();
1911
- if (!trimmed) {
1912
- return void 0;
1913
- }
1914
- if (/^\d{8}$/.test(trimmed)) {
1915
- return formatCompactDateToIso(Number.parseInt(trimmed, 10));
1916
- }
1917
- if (/^\d{4}-\d{2}-\d{2}/.test(trimmed)) {
1918
- return trimmed.slice(0, 10);
1919
- }
1920
- return void 0;
282
+ function isArcaLogLevel(value) {
283
+ return ARCA_LOG_LEVELS.includes(value);
1921
284
  }
1922
- function formatCompactDateToIso(dateValue) {
1923
- if (!dateValue) {
1924
- return void 0;
1925
- }
1926
- const raw = String(dateValue);
1927
- if (raw.length !== 8) {
1928
- return void 0;
1929
- }
1930
- return `${raw.slice(0, 4)}-${raw.slice(4, 6)}-${raw.slice(6, 8)}`;
285
+ function defaultArcaLog(level, message, ...args) {
286
+ const method = level === "debug" ? console.debug : level === "info" ? console.info : level === "warn" ? console.warn : console.error;
287
+ method(message, ...args);
1931
288
  }
1932
289
 
1933
290
  // src/internal/http.ts
@@ -1974,7 +331,7 @@ async function postXmlWithMetadata({
1974
331
  url,
1975
332
  attempt,
1976
333
  attempts: totalAttempts,
1977
- error
334
+ ...createSafeErrorDiagnostic(error)
1978
335
  });
1979
336
  throw error;
1980
337
  }
@@ -1987,7 +344,7 @@ async function postXmlWithMetadata({
1987
344
  url,
1988
345
  attempt: nextAttempt,
1989
346
  attempts: totalAttempts,
1990
- error
347
+ ...createSafeErrorDiagnostic(error)
1991
348
  }
1992
349
  );
1993
350
  await delay(retryDelay);
@@ -2046,21 +403,18 @@ async function postXmlOnce({
2046
403
  });
2047
404
  response.on("error", (error) => {
2048
405
  settleReject(
2049
- new ArcaTransportError(
2050
- `ARCA HTTP response stream failed: ${error.message}`,
2051
- {
2052
- cause: error,
2053
- statusCode: response.statusCode,
2054
- responseBody: getResponseBody()
2055
- }
2056
- )
406
+ new ArcaTransportError("ARCA HTTP response stream failed", {
407
+ cause: error,
408
+ statusCode: response.statusCode,
409
+ ...createResponseBodyDiagnostic(getResponseBody())
410
+ })
2057
411
  );
2058
412
  });
2059
413
  response.on("aborted", () => {
2060
414
  settleReject(
2061
415
  new ArcaTransportError("ARCA HTTP response was aborted", {
2062
416
  statusCode: response.statusCode,
2063
- responseBody: getResponseBody()
417
+ ...createResponseBodyDiagnostic(getResponseBody())
2064
418
  })
2065
419
  );
2066
420
  });
@@ -2092,7 +446,7 @@ async function postXmlOnce({
2092
446
  {
2093
447
  statusCode,
2094
448
  contentType: responseContentType,
2095
- responseBody
449
+ ...createResponseBodyDiagnostic(responseBody)
2096
450
  }
2097
451
  )
2098
452
  );
@@ -2100,13 +454,20 @@ async function postXmlOnce({
2100
454
  }
2101
455
  );
2102
456
  request.setTimeout(timeout, () => {
2103
- request.destroy(
2104
- new Error(`ARCA HTTP request timed out after ${timeout}ms`)
457
+ const timeoutCause = new Error(
458
+ `ARCA HTTP request timed out after ${timeout}ms`
459
+ );
460
+ settleReject(
461
+ new ArcaTransportError(
462
+ `ARCA HTTP request timed out after ${timeout}ms`,
463
+ { cause: timeoutCause }
464
+ )
2105
465
  );
466
+ request.destroy(timeoutCause);
2106
467
  });
2107
468
  request.on("error", (error) => {
2108
469
  settleReject(
2109
- new ArcaTransportError(`ARCA HTTP request failed: ${error.message}`, {
470
+ new ArcaTransportError("ARCA HTTP request failed", {
2110
471
  cause: error
2111
472
  })
2112
473
  );
@@ -2174,7 +535,6 @@ function parseSoapBody(xml, context = {}) {
2174
535
  throw createInvalidSoapResponseError(
2175
536
  "Invalid SOAP response: XML parse failed",
2176
537
  context,
2177
- void 0,
2178
538
  error instanceof Error ? error : void 0
2179
539
  );
2180
540
  }
@@ -2183,8 +543,7 @@ function parseSoapBody(xml, context = {}) {
2183
543
  if (!body) {
2184
544
  throw createInvalidSoapResponseError(
2185
545
  "Invalid SOAP response: missing body",
2186
- context,
2187
- parsed
546
+ context
2188
547
  );
2189
548
  }
2190
549
  const fault = body.Fault;
@@ -2198,13 +557,12 @@ function getSingleBodyEntry(body, context = {}) {
2198
557
  if (entries.length !== 1) {
2199
558
  throw createInvalidSoapResponseError(
2200
559
  `Invalid SOAP response: expected a single body entry, got ${entries.length}`,
2201
- context,
2202
- body
560
+ context
2203
561
  );
2204
562
  }
2205
563
  return entries[0];
2206
564
  }
2207
- function createInvalidSoapResponseError(message, context, parsedDetail, cause) {
565
+ function createInvalidSoapResponseError(message, context, cause) {
2208
566
  const responseBody = context.responseBody ?? "";
2209
567
  return new ArcaInvalidSoapResponseError(message, {
2210
568
  cause,
@@ -2213,20 +571,12 @@ function createInvalidSoapResponseError(message, context, parsedDetail, cause) {
2213
571
  endpointUrl: context.endpointUrl,
2214
572
  statusCode: context.statusCode,
2215
573
  contentType: context.contentType,
2216
- responseBodyLength: responseBody.length,
2217
- responseBodyPreview: sanitizeSoapResponsePreview(
574
+ ...createResponseBodyDiagnostic(
2218
575
  responseBody,
2219
576
  context.responseBodyPreviewLength
2220
- ),
2221
- parsedDetail
577
+ )
2222
578
  });
2223
579
  }
2224
- function sanitizeSoapResponsePreview(responseBody, maxLength = 4096) {
2225
- return responseBody.replace(
2226
- /<((?:[A-Za-z_][\w.-]*:)?(?:Token|Sign))\b([^>]*)>[\s\S]*?<\/\1>/gi,
2227
- (_match, tagName, attributes) => `<${tagName}${attributes}>[REDACTED]</${tagName}>`
2228
- ).slice(0, maxLength);
2229
- }
2230
580
  function parseXmlDocument(xml) {
2231
581
  return xmlParser.parse(xml);
2232
582
  }
@@ -2244,8 +594,7 @@ function createSoapFaultError(fault) {
2244
594
  const faultCode = typeof fault.faultcode === "string" ? fault.faultcode : getNestedString(fault, ["Code", "Value"]);
2245
595
  const message = typeof fault.faultstring === "string" ? fault.faultstring : getNestedString(fault, ["Reason", "Text"]) ?? "ARCA SOAP fault response";
2246
596
  return new ArcaSoapFaultError(message, {
2247
- faultCode: faultCode ?? void 0,
2248
- detail: fault
597
+ faultCode: faultCode ?? void 0
2249
598
  });
2250
599
  }
2251
600
  function getNestedString(value, path) {
@@ -2328,8 +677,7 @@ function createSoapTransport(options) {
2328
677
  service: request.service,
2329
678
  operation: request.operation,
2330
679
  url,
2331
- faultCode: error.faultCode,
2332
- error
680
+ ...createSafeErrorDiagnostic(error)
2333
681
  });
2334
682
  }
2335
683
  if (error instanceof ArcaInvalidSoapResponseError) {
@@ -2337,10 +685,7 @@ function createSoapTransport(options) {
2337
685
  service: request.service,
2338
686
  operation: request.operation,
2339
687
  url,
2340
- statusCode: error.statusCode,
2341
- contentType: error.contentType,
2342
- responseBodyLength: error.responseBodyLength,
2343
- error
688
+ ...createSafeErrorDiagnostic(error)
2344
689
  });
2345
690
  }
2346
691
  throw error;
@@ -2405,93 +750,128 @@ function isWsaaCredentialValid(credentials) {
2405
750
  // src/wsaa/index.ts
2406
751
  function createWsaaAuthModule(options) {
2407
752
  const cache = /* @__PURE__ */ new Map();
2408
- const inFlight = /* @__PURE__ */ new Map();
2409
- return {
2410
- async login(service, authOptions = {}) {
2411
- const sessionKey = buildWsaaSessionKey(options.config, service);
2412
- const cacheKey = serializeWsaaSessionKey(sessionKey);
2413
- const running = inFlight.get(cacheKey);
2414
- if (running) {
2415
- return running;
753
+ const ordinaryInFlight = /* @__PURE__ */ new Map();
754
+ const forcedInFlight = /* @__PURE__ */ new Map();
755
+ function trackLogin(target, cacheKey, login) {
756
+ const promise = login();
757
+ target.set(cacheKey, promise);
758
+ const cleanup = () => {
759
+ if (target.get(cacheKey) === promise) {
760
+ target.delete(cacheKey);
2416
761
  }
2417
- const loginPromise = (async () => {
2418
- const reuse = await getReusableCredentials({
2419
- config: options.config,
2420
- cache,
2421
- cacheKey,
2422
- sessionKey,
2423
- logger: options.logger,
2424
- service,
2425
- allowStore: !authOptions.forceRefresh,
2426
- allowCache: !authOptions.forceRefresh
2427
- });
2428
- if (reuse) {
2429
- return reuse;
2430
- }
2431
- const refresh = () => refreshWsaaCredentials({
762
+ };
763
+ promise.then(cleanup, cleanup);
764
+ return promise;
765
+ }
766
+ async function requestOrReuseWsaaCredentials(service, sessionKey, cacheKey, forceRefresh) {
767
+ const reuse = await getReusableCredentials({
768
+ config: options.config,
769
+ cache,
770
+ cacheKey,
771
+ sessionKey,
772
+ logger: options.logger,
773
+ service,
774
+ allowStore: !forceRefresh,
775
+ allowCache: !forceRefresh
776
+ });
777
+ if (reuse) {
778
+ return reuse;
779
+ }
780
+ const refresh = () => refreshWsaaCredentials({
781
+ config: options.config,
782
+ cache,
783
+ cacheKey,
784
+ sessionKey,
785
+ logger: options.logger,
786
+ service,
787
+ forceRefresh
788
+ });
789
+ if (options.config.wsaaSessionStore?.withLock) {
790
+ return await withWsaaSessionStoreLock(
791
+ options.config,
792
+ sessionKey,
793
+ service,
794
+ refresh
795
+ );
796
+ }
797
+ return await refresh();
798
+ }
799
+ async function performLogin(service, sessionKey, cacheKey, forceRefresh) {
800
+ try {
801
+ return await requestOrReuseWsaaCredentials(
802
+ service,
803
+ sessionKey,
804
+ cacheKey,
805
+ forceRefresh
806
+ );
807
+ } catch (error) {
808
+ if (error instanceof ArcaSoapFaultError && error.faultCode === "ns1:coe.alreadyAuthenticated") {
809
+ const recovered = await getReusableCredentials({
2432
810
  config: options.config,
2433
811
  cache,
2434
812
  cacheKey,
2435
813
  sessionKey,
2436
814
  logger: options.logger,
2437
815
  service,
2438
- forceRefresh: authOptions.forceRefresh === true
816
+ allowStore: true,
817
+ allowCache: true
2439
818
  });
2440
- if (options.config.wsaaSessionStore?.withLock) {
2441
- return await withWsaaSessionStoreLock(
2442
- options.config,
2443
- sessionKey,
2444
- service,
2445
- refresh
819
+ if (recovered) {
820
+ options.logger?.warn(
821
+ "Recovered WSAA coe.alreadyAuthenticated fault",
822
+ {
823
+ service,
824
+ faultCode: error.faultCode
825
+ }
2446
826
  );
827
+ return recovered;
2447
828
  }
2448
- return await refresh();
2449
- })();
2450
- inFlight.set(cacheKey, loginPromise);
2451
- try {
2452
- return await loginPromise;
2453
- } catch (error) {
2454
- if (error instanceof ArcaSoapFaultError && error.faultCode === "ns1:coe.alreadyAuthenticated") {
2455
- const recovered = await getReusableCredentials({
2456
- config: options.config,
2457
- cache,
2458
- cacheKey,
2459
- sessionKey,
2460
- logger: options.logger,
2461
- service,
2462
- allowStore: true,
2463
- allowCache: true
2464
- });
2465
- if (recovered) {
2466
- options.logger?.warn(
2467
- "Recovered WSAA coe.alreadyAuthenticated fault",
2468
- {
2469
- service,
2470
- faultCode: error.faultCode
2471
- }
2472
- );
2473
- return recovered;
2474
- }
2475
- if (!options.config.wsaaSessionStore) {
2476
- throw new ArcaConfigurationError(
2477
- "WSAA login failed because another process likely owns a valid TA. Configure a durable wsaaSessionStore for multi-process or serverless deployments.",
2478
- { cause: error }
2479
- );
2480
- }
829
+ if (!options.config.wsaaSessionStore) {
830
+ throw new ArcaConfigurationError(
831
+ "WSAA login failed because another process likely owns a valid TA. Configure a durable wsaaSessionStore for multi-process or serverless deployments.",
832
+ { cause: error }
833
+ );
2481
834
  }
2482
- if (error instanceof ArcaSoapFaultError) {
2483
- options.logger?.error("WSAA SOAP fault response", {
2484
- service,
2485
- operation: "loginCms",
2486
- url: ARCA_WSAA_CONFIG.endpoint[options.config.environment],
2487
- faultCode: error.faultCode,
2488
- error
2489
- });
835
+ }
836
+ if (error instanceof ArcaSoapFaultError) {
837
+ options.logger?.error("WSAA SOAP fault response", {
838
+ service,
839
+ operation: "loginCms",
840
+ url: ARCA_WSAA_CONFIG.endpoint[options.config.environment],
841
+ ...createSafeErrorDiagnostic(error)
842
+ });
843
+ }
844
+ throw error;
845
+ }
846
+ }
847
+ return {
848
+ login(service, authOptions = {}) {
849
+ const sessionKey = buildWsaaSessionKey(options.config, service);
850
+ const cacheKey = serializeWsaaSessionKey(sessionKey);
851
+ if (authOptions.forceRefresh) {
852
+ const runningForced2 = forcedInFlight.get(cacheKey);
853
+ if (runningForced2) {
854
+ return runningForced2;
2490
855
  }
2491
- throw error;
2492
- } finally {
2493
- inFlight.delete(cacheKey);
856
+ const runningOrdinary2 = ordinaryInFlight.get(cacheKey);
857
+ return trackLogin(forcedInFlight, cacheKey, async () => {
858
+ await runningOrdinary2?.catch(() => void 0);
859
+ return await performLogin(service, sessionKey, cacheKey, true);
860
+ });
2494
861
  }
862
+ const runningOrdinary = ordinaryInFlight.get(cacheKey);
863
+ if (runningOrdinary) {
864
+ return runningOrdinary;
865
+ }
866
+ const runningForced = forcedInFlight.get(cacheKey);
867
+ if (runningForced) {
868
+ return runningForced;
869
+ }
870
+ return trackLogin(
871
+ ordinaryInFlight,
872
+ cacheKey,
873
+ () => performLogin(service, sessionKey, cacheKey, false)
874
+ );
2495
875
  }
2496
876
  };
2497
877
  }
@@ -2747,8 +1127,15 @@ function createArcaClient(config) {
2747
1127
  const logger = createArcaLogger(normalizedConfig.logger);
2748
1128
  const auth = createWsaaAuthModule({ config: normalizedConfig, logger });
2749
1129
  const soap = createSoapTransport({ config: normalizedConfig, logger });
1130
+ const publicConfig = Object.freeze({
1131
+ taxId: normalizedConfig.taxId,
1132
+ environment: normalizedConfig.environment,
1133
+ timeout: normalizedConfig.timeout,
1134
+ retries: normalizedConfig.retries,
1135
+ retryDelay: normalizedConfig.retryDelay
1136
+ });
2750
1137
  return {
2751
- config: normalizedConfig,
1138
+ config: publicConfig,
2752
1139
  wsfe: createWsfeService({ config: normalizedConfig, auth, soap }),
2753
1140
  wsmtxca: createWsmtxcaService({ config: normalizedConfig, auth, soap }),
2754
1141
  padron: createPadronService({ config: normalizedConfig, auth, soap })
@@ -2757,6 +1144,7 @@ function createArcaClient(config) {
2757
1144
  export {
2758
1145
  ARCA_ENVIRONMENTS,
2759
1146
  ARCA_ENV_VARIABLES,
1147
+ ArcaAuthenticationError,
2760
1148
  ArcaConfigurationError,
2761
1149
  ArcaError,
2762
1150
  ArcaInputError,
@@ -2765,12 +1153,15 @@ export {
2765
1153
  ArcaSoapFaultError,
2766
1154
  ArcaTransportError,
2767
1155
  assertArcaClientConfig,
1156
+ buildFacturaB,
1157
+ buildFacturaC,
2768
1158
  createArcaClient,
2769
1159
  createArcaClientConfigFromEnv,
2770
1160
  createMemoryWsaaSessionStore,
2771
1161
  createPadronService,
2772
1162
  createWsfeService,
2773
1163
  createWsmtxcaService,
1164
+ isArcaAuthenticationError,
2774
1165
  resolveArcaEnvironment
2775
1166
  };
2776
1167
  //# sourceMappingURL=index.mjs.map