@dwast/verifactu-lib 0.1.0-beta.0 → 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/dist/cjs/aeat/client.d.ts +162 -0
  2. package/dist/cjs/aeat/client.d.ts.map +1 -0
  3. package/dist/cjs/aeat/client.js +267 -0
  4. package/dist/cjs/aeat/client.js.map +1 -0
  5. package/dist/cjs/aeat/index.d.ts +3 -0
  6. package/dist/cjs/aeat/index.d.ts.map +1 -0
  7. package/dist/cjs/aeat/index.js +19 -0
  8. package/dist/cjs/aeat/index.js.map +1 -0
  9. package/dist/cjs/aeat/response.d.ts +78 -0
  10. package/dist/cjs/aeat/response.d.ts.map +1 -0
  11. package/dist/cjs/aeat/response.js +117 -0
  12. package/dist/cjs/aeat/response.js.map +1 -0
  13. package/dist/{core → cjs/core}/hash/chain.d.ts +42 -0
  14. package/dist/cjs/core/hash/chain.d.ts.map +1 -0
  15. package/dist/cjs/core/hash/chain.js +167 -0
  16. package/dist/cjs/core/hash/chain.js.map +1 -0
  17. package/dist/cjs/core/hash/index.d.ts.map +1 -0
  18. package/dist/cjs/core/hash/index.js +18 -0
  19. package/dist/cjs/core/hash/index.js.map +1 -0
  20. package/dist/{core → cjs/core}/index.d.ts +2 -0
  21. package/dist/cjs/core/index.d.ts.map +1 -0
  22. package/dist/cjs/core/index.js +23 -0
  23. package/dist/cjs/core/index.js.map +1 -0
  24. package/dist/cjs/core/models/event.d.ts.map +1 -0
  25. package/dist/cjs/core/models/event.js +3 -0
  26. package/dist/{core → cjs/core}/models/event.js.map +1 -1
  27. package/dist/cjs/core/models/index.d.ts.map +1 -0
  28. package/dist/cjs/core/models/index.js +19 -0
  29. package/dist/cjs/core/models/index.js.map +1 -0
  30. package/dist/{core → cjs/core}/models/invoice.d.ts +42 -17
  31. package/dist/cjs/core/models/invoice.d.ts.map +1 -0
  32. package/dist/cjs/core/models/invoice.js +3 -0
  33. package/dist/{core → cjs/core}/models/invoice.js.map +1 -1
  34. package/dist/cjs/core/qr/index.d.ts.map +1 -0
  35. package/dist/cjs/core/qr/index.js +18 -0
  36. package/dist/cjs/core/qr/index.js.map +1 -0
  37. package/dist/cjs/core/qr/qr.d.ts.map +1 -0
  38. package/dist/cjs/core/qr/qr.js +19 -0
  39. package/dist/cjs/core/qr/qr.js.map +1 -0
  40. package/dist/cjs/core/utils/date.d.ts +16 -0
  41. package/dist/cjs/core/utils/date.d.ts.map +1 -0
  42. package/dist/cjs/core/utils/date.js +27 -0
  43. package/dist/cjs/core/utils/date.js.map +1 -0
  44. package/dist/cjs/core/utils/index.d.ts +2 -0
  45. package/dist/cjs/core/utils/index.d.ts.map +1 -0
  46. package/dist/cjs/core/utils/index.js +18 -0
  47. package/dist/cjs/core/utils/index.js.map +1 -0
  48. package/dist/cjs/core/validation/index.d.ts +2 -0
  49. package/dist/cjs/core/validation/index.d.ts.map +1 -0
  50. package/dist/cjs/core/validation/index.js +18 -0
  51. package/dist/cjs/core/validation/index.js.map +1 -0
  52. package/dist/cjs/core/validation/validate.d.ts +18 -0
  53. package/dist/cjs/core/validation/validate.d.ts.map +1 -0
  54. package/dist/cjs/core/validation/validate.js +65 -0
  55. package/dist/cjs/core/validation/validate.js.map +1 -0
  56. package/dist/cjs/core/xml/generator.d.ts +140 -0
  57. package/dist/cjs/core/xml/generator.d.ts.map +1 -0
  58. package/dist/cjs/core/xml/generator.js +269 -0
  59. package/dist/cjs/core/xml/generator.js.map +1 -0
  60. package/dist/cjs/core/xml/index.d.ts.map +1 -0
  61. package/dist/cjs/core/xml/index.js +18 -0
  62. package/dist/cjs/core/xml/index.js.map +1 -0
  63. package/dist/cjs/index.d.ts.map +1 -0
  64. package/dist/cjs/index.js +20 -0
  65. package/dist/cjs/index.js.map +1 -0
  66. package/dist/cjs/integration/accountability.d.ts +41 -0
  67. package/dist/cjs/integration/accountability.d.ts.map +1 -0
  68. package/dist/cjs/integration/accountability.js +92 -0
  69. package/dist/cjs/integration/accountability.js.map +1 -0
  70. package/dist/cjs/integration/index.d.ts +5 -0
  71. package/dist/cjs/integration/index.d.ts.map +1 -0
  72. package/dist/cjs/integration/index.js +21 -0
  73. package/dist/cjs/integration/index.js.map +1 -0
  74. package/dist/cjs/integration/p12.d.ts +58 -0
  75. package/dist/cjs/integration/p12.d.ts.map +1 -0
  76. package/dist/cjs/integration/p12.js +127 -0
  77. package/dist/cjs/integration/p12.js.map +1 -0
  78. package/dist/{integration → cjs/integration}/repository.d.ts +2 -0
  79. package/dist/cjs/integration/repository.d.ts.map +1 -0
  80. package/dist/cjs/integration/repository.js +3 -0
  81. package/dist/cjs/integration/repository.js.map +1 -0
  82. package/dist/{integration → cjs/integration}/service.d.ts +11 -2
  83. package/dist/cjs/integration/service.d.ts.map +1 -0
  84. package/dist/cjs/integration/service.js +230 -0
  85. package/dist/cjs/integration/service.js.map +1 -0
  86. package/dist/cjs/integration/tenant-credentials.d.ts +44 -0
  87. package/dist/cjs/integration/tenant-credentials.d.ts.map +1 -0
  88. package/dist/cjs/integration/tenant-credentials.js +62 -0
  89. package/dist/cjs/integration/tenant-credentials.js.map +1 -0
  90. package/dist/cjs/package.json +3 -0
  91. package/dist/esm/aeat/client.d.ts +162 -0
  92. package/dist/esm/aeat/client.d.ts.map +1 -0
  93. package/dist/esm/aeat/client.js +259 -0
  94. package/dist/esm/aeat/client.js.map +1 -0
  95. package/dist/esm/aeat/index.d.ts +3 -0
  96. package/dist/esm/aeat/index.d.ts.map +1 -0
  97. package/dist/esm/aeat/index.js +3 -0
  98. package/dist/esm/aeat/index.js.map +1 -0
  99. package/dist/esm/aeat/response.d.ts +78 -0
  100. package/dist/esm/aeat/response.d.ts.map +1 -0
  101. package/dist/esm/aeat/response.js +114 -0
  102. package/dist/esm/aeat/response.js.map +1 -0
  103. package/dist/esm/core/hash/chain.d.ts +139 -0
  104. package/dist/esm/core/hash/chain.d.ts.map +1 -0
  105. package/dist/{core → esm/core}/hash/chain.js +37 -0
  106. package/dist/esm/core/hash/chain.js.map +1 -0
  107. package/dist/esm/core/hash/index.d.ts +2 -0
  108. package/dist/esm/core/hash/index.d.ts.map +1 -0
  109. package/dist/esm/core/hash/index.js.map +1 -0
  110. package/dist/esm/core/index.d.ts +7 -0
  111. package/dist/esm/core/index.d.ts.map +1 -0
  112. package/dist/{core → esm/core}/index.js +2 -0
  113. package/dist/esm/core/index.js.map +1 -0
  114. package/dist/esm/core/models/event.d.ts +25 -0
  115. package/dist/esm/core/models/event.d.ts.map +1 -0
  116. package/dist/esm/core/models/event.js.map +1 -0
  117. package/dist/esm/core/models/index.d.ts +3 -0
  118. package/dist/esm/core/models/index.d.ts.map +1 -0
  119. package/dist/esm/core/models/index.js.map +1 -0
  120. package/dist/esm/core/models/invoice.d.ts +115 -0
  121. package/dist/esm/core/models/invoice.d.ts.map +1 -0
  122. package/dist/esm/core/models/invoice.js.map +1 -0
  123. package/dist/esm/core/qr/index.d.ts +2 -0
  124. package/dist/esm/core/qr/index.d.ts.map +1 -0
  125. package/dist/esm/core/qr/index.js.map +1 -0
  126. package/dist/esm/core/qr/qr.d.ts +13 -0
  127. package/dist/esm/core/qr/qr.d.ts.map +1 -0
  128. package/dist/esm/core/qr/qr.js.map +1 -0
  129. package/dist/esm/core/utils/date.d.ts +16 -0
  130. package/dist/esm/core/utils/date.d.ts.map +1 -0
  131. package/dist/esm/core/utils/date.js +24 -0
  132. package/dist/esm/core/utils/date.js.map +1 -0
  133. package/dist/esm/core/utils/index.d.ts +2 -0
  134. package/dist/esm/core/utils/index.d.ts.map +1 -0
  135. package/dist/esm/core/utils/index.js +2 -0
  136. package/dist/esm/core/utils/index.js.map +1 -0
  137. package/dist/esm/core/validation/index.d.ts +2 -0
  138. package/dist/esm/core/validation/index.d.ts.map +1 -0
  139. package/dist/esm/core/validation/index.js +2 -0
  140. package/dist/esm/core/validation/index.js.map +1 -0
  141. package/dist/esm/core/validation/validate.d.ts +18 -0
  142. package/dist/esm/core/validation/validate.d.ts.map +1 -0
  143. package/dist/esm/core/validation/validate.js +62 -0
  144. package/dist/esm/core/validation/validate.js.map +1 -0
  145. package/dist/esm/core/xml/generator.d.ts +140 -0
  146. package/dist/esm/core/xml/generator.d.ts.map +1 -0
  147. package/dist/esm/core/xml/generator.js +259 -0
  148. package/dist/esm/core/xml/generator.js.map +1 -0
  149. package/dist/esm/core/xml/index.d.ts +2 -0
  150. package/dist/esm/core/xml/index.d.ts.map +1 -0
  151. package/dist/esm/core/xml/index.js.map +1 -0
  152. package/dist/esm/index.d.ts +4 -0
  153. package/dist/esm/index.d.ts.map +1 -0
  154. package/dist/esm/index.js.map +1 -0
  155. package/dist/esm/integration/accountability.d.ts +41 -0
  156. package/dist/esm/integration/accountability.d.ts.map +1 -0
  157. package/dist/esm/integration/accountability.js +88 -0
  158. package/dist/esm/integration/accountability.js.map +1 -0
  159. package/dist/esm/integration/index.d.ts +5 -0
  160. package/dist/esm/integration/index.d.ts.map +1 -0
  161. package/dist/esm/integration/index.js +5 -0
  162. package/dist/esm/integration/index.js.map +1 -0
  163. package/dist/esm/integration/p12.d.ts +58 -0
  164. package/dist/esm/integration/p12.d.ts.map +1 -0
  165. package/dist/esm/integration/p12.js +119 -0
  166. package/dist/esm/integration/p12.js.map +1 -0
  167. package/dist/esm/integration/repository.d.ts +79 -0
  168. package/dist/esm/integration/repository.d.ts.map +1 -0
  169. package/dist/esm/integration/repository.js.map +1 -0
  170. package/dist/esm/integration/service.d.ts +45 -0
  171. package/dist/esm/integration/service.d.ts.map +1 -0
  172. package/dist/{integration → esm/integration}/service.js +101 -15
  173. package/dist/esm/integration/service.js.map +1 -0
  174. package/dist/esm/integration/tenant-credentials.d.ts +44 -0
  175. package/dist/esm/integration/tenant-credentials.d.ts.map +1 -0
  176. package/dist/esm/integration/tenant-credentials.js +58 -0
  177. package/dist/esm/integration/tenant-credentials.js.map +1 -0
  178. package/package.json +45 -13
  179. package/readme.md +566 -42
  180. package/src/aeat/client.ts +296 -55
  181. package/src/aeat/index.ts +1 -0
  182. package/src/aeat/response.ts +195 -0
  183. package/src/core/hash/chain.ts +68 -0
  184. package/src/core/index.ts +2 -0
  185. package/src/core/models/invoice.ts +40 -18
  186. package/src/core/utils/date.ts +27 -0
  187. package/src/core/utils/index.ts +1 -0
  188. package/src/core/validation/index.ts +1 -0
  189. package/src/core/validation/validate.ts +71 -0
  190. package/src/core/xml/generator.ts +306 -73
  191. package/src/integration/accountability.ts +125 -0
  192. package/src/integration/index.ts +2 -0
  193. package/src/integration/p12.ts +155 -0
  194. package/src/integration/repository.ts +2 -0
  195. package/src/integration/service.ts +113 -14
  196. package/dist/aeat/client.d.ts +0 -57
  197. package/dist/aeat/client.d.ts.map +0 -1
  198. package/dist/aeat/client.js +0 -87
  199. package/dist/aeat/client.js.map +0 -1
  200. package/dist/aeat/index.d.ts +0 -2
  201. package/dist/aeat/index.d.ts.map +0 -1
  202. package/dist/aeat/index.js +0 -2
  203. package/dist/aeat/index.js.map +0 -1
  204. package/dist/core/hash/chain.d.ts.map +0 -1
  205. package/dist/core/hash/chain.js.map +0 -1
  206. package/dist/core/hash/index.d.ts.map +0 -1
  207. package/dist/core/hash/index.js.map +0 -1
  208. package/dist/core/index.d.ts.map +0 -1
  209. package/dist/core/index.js.map +0 -1
  210. package/dist/core/models/event.d.ts.map +0 -1
  211. package/dist/core/models/index.d.ts.map +0 -1
  212. package/dist/core/models/index.js.map +0 -1
  213. package/dist/core/models/invoice.d.ts.map +0 -1
  214. package/dist/core/qr/index.d.ts.map +0 -1
  215. package/dist/core/qr/index.js.map +0 -1
  216. package/dist/core/qr/qr.d.ts.map +0 -1
  217. package/dist/core/qr/qr.js.map +0 -1
  218. package/dist/core/xml/generator.d.ts +0 -32
  219. package/dist/core/xml/generator.d.ts.map +0 -1
  220. package/dist/core/xml/generator.js +0 -103
  221. package/dist/core/xml/generator.js.map +0 -1
  222. package/dist/core/xml/index.d.ts.map +0 -1
  223. package/dist/core/xml/index.js.map +0 -1
  224. package/dist/index.d.ts.map +0 -1
  225. package/dist/index.js.map +0 -1
  226. package/dist/integration/index.d.ts +0 -3
  227. package/dist/integration/index.d.ts.map +0 -1
  228. package/dist/integration/index.js +0 -3
  229. package/dist/integration/index.js.map +0 -1
  230. package/dist/integration/repository.d.ts.map +0 -1
  231. package/dist/integration/repository.js.map +0 -1
  232. package/dist/integration/service.d.ts.map +0 -1
  233. package/dist/integration/service.js.map +0 -1
  234. /package/dist/{core → cjs/core}/hash/index.d.ts +0 -0
  235. /package/dist/{core → cjs/core}/models/event.d.ts +0 -0
  236. /package/dist/{core → cjs/core}/models/index.d.ts +0 -0
  237. /package/dist/{core → cjs/core}/qr/index.d.ts +0 -0
  238. /package/dist/{core → cjs/core}/qr/qr.d.ts +0 -0
  239. /package/dist/{core → cjs/core}/xml/index.d.ts +0 -0
  240. /package/dist/{index.d.ts → cjs/index.d.ts} +0 -0
  241. /package/dist/{core → esm/core}/hash/index.js +0 -0
  242. /package/dist/{core → esm/core}/models/event.js +0 -0
  243. /package/dist/{core → esm/core}/models/index.js +0 -0
  244. /package/dist/{core → esm/core}/models/invoice.js +0 -0
  245. /package/dist/{core → esm/core}/qr/index.js +0 -0
  246. /package/dist/{core → esm/core}/qr/qr.js +0 -0
  247. /package/dist/{core → esm/core}/xml/index.js +0 -0
  248. /package/dist/{index.js → esm/index.js} +0 -0
  249. /package/dist/{integration → esm/integration}/repository.js +0 -0
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Escapa caracteres especiales para XML.
3
+ */
4
+ function escapeXml(value) {
5
+ return value
6
+ .replace(/&/g, '&')
7
+ .replace(/</g, '&lt;')
8
+ .replace(/>/g, '&gt;')
9
+ .replace(/"/g, '&quot;')
10
+ .replace(/'/g, '&apos;');
11
+ }
12
+ /**
13
+ * Formatea un número con 2 decimales (formato Verifactu).
14
+ */
15
+ function formatAmount(value) {
16
+ return value.toFixed(2);
17
+ }
18
+ /**
19
+ * Genera el elemento `<RegistroAlta>` de una factura (registro de alta).
20
+ *
21
+ * Estructura según el XSD `SuministroInformacion.xsd` de la AEAT
22
+ * (`RegistroFacturacionAltaType`). NOTA: validar contra el XSD oficial
23
+ * antes de producción.
24
+ */
25
+ export function generateRegistroAltaXml(invoice, previousHash) {
26
+ const { id, emisor, desglose, tipoFactura, sistemaInformatico } = invoice;
27
+ const idVersion = invoice.idVersion ?? '1.0';
28
+ const descripcion = invoice.descripcion ?? '';
29
+ const detalles = desglose.detalles
30
+ .map((d) => ` <sf:DetalleDesglose>` +
31
+ (d.claveRegimen !== undefined
32
+ ? `<sf:ClaveRegimen>${escapeXml(d.claveRegimen)}</sf:ClaveRegimen>`
33
+ : '') +
34
+ `<sf:CalificacionOperacion>${escapeXml(d.calificacionOperacion)}</sf:CalificacionOperacion>` +
35
+ (d.tipoImpositivo !== undefined
36
+ ? `<sf:TipoImpositivo>${formatAmount(d.tipoImpositivo)}</sf:TipoImpositivo>`
37
+ : '') +
38
+ `<sf:BaseImponibleOimporteNoSujeto>${formatAmount(d.baseImponible)}</sf:BaseImponibleOimporteNoSujeto>` +
39
+ (d.cuotaRepercutida !== undefined
40
+ ? `<sf:CuotaRepercutida>${formatAmount(d.cuotaRepercutida)}</sf:CuotaRepercutida>`
41
+ : '') +
42
+ `</sf:DetalleDesglose>`)
43
+ .join('\n');
44
+ const encadenamiento = previousHash
45
+ ? ` <sf:RegistroAnterior><sf:IDEmisorFactura>${escapeXml(emisor.nif)}</sf:IDEmisorFactura><sf:NumSerieFactura>${escapeXml(id.serie ?? '')}${escapeXml(id.numero)}</sf:NumSerieFactura><sf:FechaExpedicionFactura>${id.fechaExpedicion}</sf:FechaExpedicionFactura><sf:Huella>${previousHash}</sf:Huella></sf:RegistroAnterior>`
46
+ : ` <sf:PrimerRegistro>S</sf:PrimerRegistro>`;
47
+ const xml = [
48
+ '<?xml version="1.0" encoding="UTF-8"?>',
49
+ `<sf:RegistroAlta xmlns:sf="${AEAT_INFORMACION_NAMESPACE}">`,
50
+ ` <sf:IDVersion>${idVersion}</sf:IDVersion>`,
51
+ ' <sf:IDFactura>',
52
+ ` <sf:IDEmisorFactura>${escapeXml(emisor.nif)}</sf:IDEmisorFactura>`,
53
+ ` <sf:NumSerieFactura>${escapeXml(id.serie ?? '')}${escapeXml(id.numero)}</sf:NumSerieFactura>`,
54
+ ` <sf:FechaExpedicionFactura>${id.fechaExpedicion}</sf:FechaExpedicionFactura>`,
55
+ ' </sf:IDFactura>',
56
+ ` <sf:NombreRazonEmisor>${escapeXml(emisor.nombreRazon)}</sf:NombreRazonEmisor>`,
57
+ ` <sf:TipoFactura>${tipoFactura}</sf:TipoFactura>`,
58
+ ` <sf:DescripcionOperacion>${escapeXml(descripcion)}</sf:DescripcionOperacion>`,
59
+ ...(invoice.destinatarios && invoice.destinatarios.length
60
+ ? [
61
+ ' <sf:Destinatarios>',
62
+ ...invoice.destinatarios.map((d) => ` <sf:IDDestinatario><sf:NombreRazon>${escapeXml(d.nombreRazon)}</sf:NombreRazon><sf:NIF>${escapeXml(d.nif)}</sf:NIF></sf:IDDestinatario>`),
63
+ ' </sf:Destinatarios>',
64
+ ]
65
+ : []),
66
+ ' <sf:Desglose>',
67
+ detalles,
68
+ ' </sf:Desglose>',
69
+ ` <sf:CuotaTotal>${formatAmount(desglose.cuotaTotal)}</sf:CuotaTotal>`,
70
+ ` <sf:ImporteTotal>${formatAmount(desglose.importeTotal)}</sf:ImporteTotal>`,
71
+ ' <sf:Encadenamiento>',
72
+ encadenamiento,
73
+ ' </sf:Encadenamiento>',
74
+ ' <sf:SistemaInformatico>',
75
+ ` <sf:NombreRazon>${escapeXml(sistemaInformatico.nombreRazon)}</sf:NombreRazon>`,
76
+ ` <sf:NIF>${escapeXml(sistemaInformatico.nif)}</sf:NIF>`,
77
+ ` <sf:NombreSistemaInformatico>${escapeXml(sistemaInformatico.nombreSistemaInformatico)}</sf:NombreSistemaInformatico>`,
78
+ ` <sf:IdSistemaInformatico>${escapeXml(sistemaInformatico.idSistemaInformatico)}</sf:IdSistemaInformatico>`,
79
+ ` <sf:Version>${escapeXml(sistemaInformatico.version)}</sf:Version>`,
80
+ ` <sf:NumeroInstalacion>${escapeXml(sistemaInformatico.numeroInstalacion)}</sf:NumeroInstalacion>`,
81
+ ' <sf:TipoUsoPosibleSoloVerifactu>S</sf:TipoUsoPosibleSoloVerifactu>',
82
+ ' <sf:TipoUsoPosibleMultiOT>N</sf:TipoUsoPosibleMultiOT>',
83
+ ' <sf:IndicadorMultiplesOT>N</sf:IndicadorMultiplesOT>',
84
+ ' </sf:SistemaInformatico>',
85
+ ` <sf:FechaHoraHusoGenRegistro>${invoice.fechaHoraHusoGenRegistro}</sf:FechaHoraHusoGenRegistro>`,
86
+ ' <sf:TipoHuella>01</sf:TipoHuella>',
87
+ ` <sf:Huella>${invoice.huella}</sf:Huella>`,
88
+ '</sf:RegistroAlta>',
89
+ ]
90
+ .filter((line) => line !== '')
91
+ .join('\n');
92
+ return xml;
93
+ }
94
+ /**
95
+ * Namespace del esquema `SuministroLR.xsd` de la AEAT.
96
+ */
97
+ export const AEAT_SUMINISTRO_NAMESPACE = 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd';
98
+ /**
99
+ * Namespace del esquema `SuministroInformacion.xsd` de la AEAT.
100
+ */
101
+ export const AEAT_INFORMACION_NAMESPACE = 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd';
102
+ /**
103
+ * Namespace del esquema `EventosSIF.xsd` de la AEAT (registro de eventos).
104
+ */
105
+ export const AEAT_EVENTO_NAMESPACE = 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/EventosSIF.xsd';
106
+ /**
107
+ * Genera el elemento `<RegFactuSistemaFacturacion>` completo (operación SOAP),
108
+ * con la `Cabecera` y el `RegistroFactura` que envuelve el registro.
109
+ */
110
+ export function generateSuministroXml(registroXml, cabecera) {
111
+ const body = registroXml.replace(/^<\?xml[^>]*\?>\s*/, '');
112
+ const representante = cabecera.representante
113
+ ? [
114
+ ' <sf:Representante>',
115
+ ` <sf:NombreRazon>${escapeXml(cabecera.representante.nombreRazon)}</sf:NombreRazon>`,
116
+ ` <sf:NIF>${escapeXml(cabecera.representante.nif)}</sf:NIF>`,
117
+ ' </sf:Representante>',
118
+ ].join('\n')
119
+ : '';
120
+ return [
121
+ '<?xml version="1.0" encoding="UTF-8"?>',
122
+ `<sfLR:RegFactuSistemaFacturacion xmlns:sfLR="${AEAT_SUMINISTRO_NAMESPACE}" xmlns:sf="${AEAT_INFORMACION_NAMESPACE}">`,
123
+ ' <sfLR:Cabecera>',
124
+ ' <sf:ObligadoEmision>',
125
+ ` <sf:NombreRazon>${escapeXml(cabecera.nombreRazon)}</sf:NombreRazon>`,
126
+ ` <sf:NIF>${escapeXml(cabecera.nif)}</sf:NIF>`,
127
+ ' </sf:ObligadoEmision>',
128
+ representante,
129
+ ' </sfLR:Cabecera>',
130
+ ' <sfLR:RegistroFactura>',
131
+ body,
132
+ ' </sfLR:RegistroFactura>',
133
+ '</sfLR:RegFactuSistemaFacturacion>',
134
+ ].join('\n');
135
+ }
136
+ /**
137
+ * Construye la `Cabecera` del suministro, detectando si el certificado es de
138
+ * un representante.
139
+ *
140
+ * Si se proporciona el certificado en PEM y su NIF difiere del NIF del
141
+ * obligado, se añade el bloque `Representante` (el certificado actúa como
142
+ * representante del obligado), usando el nombre del titular del certificado.
143
+ */
144
+ export function buildCabecera(obligado, certificatePem, extractInfo) {
145
+ const cabecera = { nombreRazon: obligado.nombreRazon, nif: obligado.nif };
146
+ if (certificatePem && extractInfo) {
147
+ const info = extractInfo(certificatePem);
148
+ if (info && info.nif !== obligado.nif) {
149
+ cabecera.representante = { nombreRazon: info.nombreRazon, nif: info.nif };
150
+ }
151
+ }
152
+ return cabecera;
153
+ }
154
+ /**
155
+ * Genera el XML Verifactu de una factura (registro de alta).
156
+ *
157
+ * Alias de `generateRegistroAltaXml` por compatibilidad.
158
+ */
159
+ export function generateInvoiceXml(invoice, previousHash) {
160
+ return generateRegistroAltaXml(invoice, previousHash);
161
+ }
162
+ /**
163
+ * Genera el XML Verifactu de un registro de anulación (`<sf:RegistroAnulacion>`).
164
+ *
165
+ * Referencia la factura anulada (IDFactura) y encadena con el hash anterior.
166
+ * Estructura según el XSD `SuministroInformacion.xsd` (`RegistroFacturacionAnulacionType`).
167
+ */
168
+ export function generateAnulacionXml(anulacion, previousHash) {
169
+ const idVersion = anulacion.idVersion ?? '1.0';
170
+ const si = anulacion.sistemaInformatico;
171
+ const encadenamiento = previousHash
172
+ ? ` <sf:RegistroAnterior><sf:IDEmisorFactura>${escapeXml(anulacion.idEmisorFacturaAnulada)}</sf:IDEmisorFactura><sf:NumSerieFactura>${escapeXml(anulacion.numSerieFacturaAnulada)}</sf:NumSerieFactura><sf:FechaExpedicionFactura>${anulacion.fechaExpedicionFacturaAnulada}</sf:FechaExpedicionFactura><sf:Huella>${previousHash}</sf:Huella></sf:RegistroAnterior>`
173
+ : ` <sf:PrimerRegistro>S</sf:PrimerRegistro>`;
174
+ return [
175
+ '<?xml version="1.0" encoding="UTF-8"?>',
176
+ `<sf:RegistroAnulacion xmlns:sf="${AEAT_INFORMACION_NAMESPACE}">`,
177
+ ` <sf:IDVersion>${idVersion}</sf:IDVersion>`,
178
+ ' <sf:IDFactura>',
179
+ ` <sf:IDEmisorFacturaAnulada>${escapeXml(anulacion.idEmisorFacturaAnulada)}</sf:IDEmisorFacturaAnulada>`,
180
+ ` <sf:NumSerieFacturaAnulada>${escapeXml(anulacion.numSerieFacturaAnulada)}</sf:NumSerieFacturaAnulada>`,
181
+ ` <sf:FechaExpedicionFacturaAnulada>${anulacion.fechaExpedicionFacturaAnulada}</sf:FechaExpedicionFacturaAnulada>`,
182
+ ' </sf:IDFactura>',
183
+ ' <sf:Encadenamiento>',
184
+ encadenamiento,
185
+ ' </sf:Encadenamiento>',
186
+ ' <sf:SistemaInformatico>',
187
+ ` <sf:NombreRazon>${escapeXml(si.nombreRazon)}</sf:NombreRazon>`,
188
+ ` <sf:NIF>${escapeXml(si.nif)}</sf:NIF>`,
189
+ ` <sf:NombreSistemaInformatico>${escapeXml(si.nombreSistemaInformatico)}</sf:NombreSistemaInformatico>`,
190
+ ` <sf:IdSistemaInformatico>${escapeXml(si.idSistemaInformatico)}</sf:IdSistemaInformatico>`,
191
+ ` <sf:Version>${escapeXml(si.version)}</sf:Version>`,
192
+ ` <sf:NumeroInstalacion>${escapeXml(si.numeroInstalacion)}</sf:NumeroInstalacion>`,
193
+ ' <sf:TipoUsoPosibleSoloVerifactu>S</sf:TipoUsoPosibleSoloVerifactu>',
194
+ ' <sf:TipoUsoPosibleMultiOT>N</sf:TipoUsoPosibleMultiOT>',
195
+ ' <sf:IndicadorMultiplesOT>N</sf:IndicadorMultiplesOT>',
196
+ ' </sf:SistemaInformatico>',
197
+ ` <sf:FechaHoraHusoGenRegistro>${anulacion.fechaHoraHusoGenRegistro}</sf:FechaHoraHusoGenRegistro>`,
198
+ ' <sf:TipoHuella>01</sf:TipoHuella>',
199
+ ` <sf:Huella>${anulacion.huella}</sf:Huella>`,
200
+ '</sf:RegistroAnulacion>',
201
+ ].join('\n');
202
+ }
203
+ /**
204
+ * Genera el XML Verifactu de un registro de evento (RegistroEvento).
205
+ *
206
+ * Estructura basada en `EventosSIF.xsd` (namespace `sf`). El evento se envía
207
+ * como un suministro independiente (no dentro de `RegFactuSistemaFacturacion`).
208
+ */
209
+ export function generateEventoXml(evento) {
210
+ const si = evento.sistemaInformatico;
211
+ const xml = [
212
+ '<?xml version="1.0" encoding="UTF-8"?>',
213
+ `<sf:RegistroEvento xmlns:sf="${AEAT_EVENTO_NAMESPACE}">`,
214
+ ` <sf:IDVersion>${escapeXml(evento.idVersion ?? '1.0')}</sf:IDVersion>`,
215
+ ' <sf:Evento>',
216
+ ' <sf:SistemaInformatico>',
217
+ ` <sf:NombreRazon>${escapeXml(si.nombreRazon)}</sf:NombreRazon>`,
218
+ ` <sf:NIF>${escapeXml(si.nif)}</sf:NIF>`,
219
+ ` <sf:NombreSistemaInformatico>${escapeXml(si.nombreSistemaInformatico)}</sf:NombreSistemaInformatico>`,
220
+ ` <sf:IdSistemaInformatico>${escapeXml(si.idSistemaInformatico)}</sf:IdSistemaInformatico>`,
221
+ ` <sf:Version>${escapeXml(si.version)}</sf:Version>`,
222
+ ` <sf:NumeroInstalacion>${escapeXml(si.numeroInstalacion)}</sf:NumeroInstalacion>`,
223
+ ' <sf:TipoUsoPosibleSoloVerifactu>S</sf:TipoUsoPosibleSoloVerifactu>',
224
+ ' <sf:TipoUsoPosibleMultiOT>N</sf:TipoUsoPosibleMultiOT>',
225
+ ' <sf:IndicadorMultiplesOT>N</sf:IndicadorMultiplesOT>',
226
+ ' </sf:SistemaInformatico>',
227
+ ' <sf:ObligadoEmision>',
228
+ ` <sf:NombreRazon>${escapeXml(evento.obligadoEmision.nombreRazon)}</sf:NombreRazon>`,
229
+ ` <sf:NIF>${escapeXml(evento.obligadoEmision.nif)}</sf:NIF>`,
230
+ ' </sf:ObligadoEmision>',
231
+ ` <sf:FechaHoraHusoGenEvento>${evento.fechaHoraHusoGenEvento}</sf:FechaHoraHusoGenEvento>`,
232
+ ` <sf:TipoEvento>${escapeXml(evento.tipoEvento)}</sf:TipoEvento>`,
233
+ ' <sf:Encadenamiento>',
234
+ ' <sf:PrimerEvento>S</sf:PrimerEvento>',
235
+ ' </sf:Encadenamiento>',
236
+ ' <sf:TipoHuella>01</sf:TipoHuella>',
237
+ ` <sf:HuellaEvento>${evento.huellaEvento}</sf:HuellaEvento>`,
238
+ ' </sf:Evento>',
239
+ '</sf:RegistroEvento>',
240
+ ].join('\n');
241
+ return xml;
242
+ }
243
+ /**
244
+ * Envuelve un elemento de operación Verifactu en el sobre SOAP que la AEAT
245
+ * espera en el envío. El XML de entrada DEBE ser ya el elemento de operación
246
+ * (p. ej. `<RegFactuSistemaFacturacion>` o `<ConsultaFactuSistemaFacturacion>`).
247
+ */
248
+ export function buildRemisionEnvelope(operationXml) {
249
+ const body = operationXml.replace(/^<\?xml[^>]*\?>\s*/, '');
250
+ return [
251
+ '<?xml version="1.0" encoding="UTF-8"?>',
252
+ '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">',
253
+ ' <soap:Body>',
254
+ body,
255
+ ' </soap:Body>',
256
+ '</soap:Envelope>',
257
+ ].join('\n');
258
+ }
259
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../src/core/xml/generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './generator.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/xml/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/xml/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './core/index.js';
2
+ export * from './aeat/index.js';
3
+ export * from './integration/index.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { Invoice } from '../core/models/invoice.js';
2
+ import type { VerifactuRepository, StoredRecord } from './repository.js';
3
+ /**
4
+ * Configuración de la integración de accountability (contabilidad).
5
+ *
6
+ * Se puede aportar el material TLS ya extraído (`cert`/`key`) o el `.p12`
7
+ * en bruto (`p12Buffer` + `p12Password`). El NIF del emisor se aporta
8
+ * siempre en `nif` (la librería no interpreta los campos del certificado).
9
+ */
10
+ export interface AccountabilityConfig {
11
+ /** URL base del servicio AEAT. */
12
+ baseUrl: string;
13
+ /** NIF del emisor. */
14
+ nif: string;
15
+ /** Certificado de cliente en PEM (mTLS). */
16
+ cert?: string;
17
+ /** Clave privada del cliente en PEM (mTLS). */
18
+ key?: string;
19
+ /** Contenido del `.p12` (alternativa a `cert`/`key`). */
20
+ p12Buffer?: Buffer;
21
+ /** Contraseña del `.p12`. */
22
+ p12Password?: string;
23
+ }
24
+ /**
25
+ * Integración de accountability (contabilidad) para Verifactu.
26
+ *
27
+ * Une las credenciales del certificado (`.p12`) con el cliente mTLS y la
28
+ * persistencia, para registrar facturas de forma verificable ante la AEAT.
29
+ */
30
+ export declare class AccountabilityService {
31
+ private readonly repository;
32
+ private readonly client;
33
+ private readonly nif;
34
+ constructor(repository: VerifactuRepository, config: AccountabilityConfig);
35
+ /**
36
+ * Registra una factura (alta) ante la AEAT, usando el certificado del
37
+ * emisor para autenticar el envío.
38
+ */
39
+ registerInvoice(invoice: Invoice): Promise<StoredRecord>;
40
+ }
41
+ //# sourceMappingURL=accountability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accountability.d.ts","sourceRoot":"","sources":["../../../src/integration/accountability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAOzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEzE;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,qBAAa,qBAAqB;IAK9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJ7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAGV,UAAU,EAAE,mBAAmB,EAChD,MAAM,EAAE,oBAAoB;IAwB9B;;;OAGG;IACG,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;CAqD/D"}
@@ -0,0 +1,88 @@
1
+ import { generateInvoiceXml } from '../core/xml/generator.js';
2
+ import { computeRegistroAlta } from '../core/hash/chain.js';
3
+ import { buildQrPayload } from '../core/qr/qr.js';
4
+ import { nowIsoWithOffset } from '../core/utils/date.js';
5
+ import { VerifactuClient } from '../aeat/client.js';
6
+ import { readP12 } from './p12.js';
7
+ /**
8
+ * Integración de accountability (contabilidad) para Verifactu.
9
+ *
10
+ * Une las credenciales del certificado (`.p12`) con el cliente mTLS y la
11
+ * persistencia, para registrar facturas de forma verificable ante la AEAT.
12
+ */
13
+ export class AccountabilityService {
14
+ repository;
15
+ client;
16
+ nif;
17
+ constructor(repository, config) {
18
+ this.repository = repository;
19
+ let cert;
20
+ let key;
21
+ if (config.p12Buffer && config.p12Password) {
22
+ const content = readP12(config.p12Buffer, config.p12Password);
23
+ cert = content.certificates[0];
24
+ key = content.keys[0];
25
+ }
26
+ else if (config.cert && config.key) {
27
+ cert = config.cert;
28
+ key = config.key;
29
+ }
30
+ if (!cert || !key) {
31
+ throw new Error('AccountabilityService requiere un .p12 (p12Buffer + p12Password) o cert/key PEM.');
32
+ }
33
+ this.nif = config.nif;
34
+ this.client = new VerifactuClient({ baseUrl: config.baseUrl, cert, key });
35
+ }
36
+ /**
37
+ * Registra una factura (alta) ante la AEAT, usando el certificado del
38
+ * emisor para autenticar el envío.
39
+ */
40
+ async registerInvoice(invoice) {
41
+ // El NIF del emisor se toma del certificado (o del config).
42
+ const invoiceConNif = {
43
+ ...invoice,
44
+ emisor: { ...invoice.emisor, nif: this.nif },
45
+ };
46
+ const last = await this.repository.getLastRecord();
47
+ const previousHash = last?.hash ?? null;
48
+ const xml = generateInvoiceXml(invoiceConNif, previousHash);
49
+ const fechaHoraHusoGenRegistro = nowIsoWithOffset();
50
+ const hash = computeRegistroAlta({
51
+ idEmisorFactura: this.nif,
52
+ numSerieFactura: `${invoice.id.serie ?? ''}${invoice.id.numero}`,
53
+ fechaExpedicionFactura: invoice.id.fechaExpedicion,
54
+ tipoFactura: invoice.tipoFactura,
55
+ cuotaTotal: invoice.desglose.cuotaTotal.toFixed(2),
56
+ importeTotal: invoice.desglose.importeTotal.toFixed(2),
57
+ huellaAnterior: previousHash,
58
+ fechaHoraHusoGenRegistro,
59
+ });
60
+ const now = new Date().toISOString();
61
+ const record = {
62
+ id: `${invoice.id.serie ?? ''}${invoice.id.numero}`,
63
+ invoiceId: `${invoice.id.serie ?? ''}${invoice.id.numero}`,
64
+ emisorNif: this.nif,
65
+ xml,
66
+ hash,
67
+ previousHash,
68
+ qrPayload: buildQrPayload(hash),
69
+ status: 'PENDING',
70
+ createdAt: now,
71
+ updatedAt: now,
72
+ };
73
+ await this.repository.saveRecord(record);
74
+ const result = await this.client.sendRecord(xml);
75
+ await this.repository.saveResponse({
76
+ id: `${record.id}-${Date.now()}`,
77
+ recordId: record.id,
78
+ operationId: result.operationId,
79
+ status: result.status,
80
+ message: result.message,
81
+ receivedAt: new Date().toISOString(),
82
+ });
83
+ const status = result.status === 'OK' ? 'CONFIRMED' : 'REJECTED';
84
+ await this.repository.updateRecordStatus(record.id, status);
85
+ return { ...record, status };
86
+ }
87
+ }
88
+ //# sourceMappingURL=accountability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accountability.js","sourceRoot":"","sources":["../../../src/integration/accountability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from './repository.js';
2
+ export * from './service.js';
3
+ export * from './p12.js';
4
+ export * from './accountability.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integration/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './repository.js';
2
+ export * from './service.js';
3
+ export * from './p12.js';
4
+ export * from './accountability.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/integration/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Un campo (bag) del `.p12`.
3
+ */
4
+ export interface P12Bag {
5
+ /** Tipo del bag (certBag, keyBag, pkcs8ShroudedKeyBag, ...). */
6
+ type: string;
7
+ /** Contenido en formato PEM (si es un certificado o clave). */
8
+ pem?: string;
9
+ /** Valor en bruto (si no es PEM). */
10
+ value?: unknown;
11
+ }
12
+ /**
13
+ * Contenido completo de un `.p12`, con todos sus campos.
14
+ */
15
+ export interface P12Content {
16
+ /** Todos los bags encontrados, en orden. */
17
+ bags: P12Bag[];
18
+ /** Certificados en PEM (conveniencia). */
19
+ certificates: string[];
20
+ /** Claves privadas en PEM (conveniencia). */
21
+ keys: string[];
22
+ }
23
+ /**
24
+ * Lee un certificado `.p12`/`.pfx` e itera todos sus campos (bags),
25
+ * devolviéndolos todos. La librería no interpreta qué campo es cada cosa:
26
+ * simplemente expone el contenido para que la aplicación lo use.
27
+ *
28
+ * @param buffer Contenido del archivo `.p12`/`.pfx`.
29
+ * @param password Contraseña del `.p12`.
30
+ */
31
+ export declare function readP12(buffer: Buffer, password: string): P12Content;
32
+ /**
33
+ * Extrae el NIF de un certificado en PEM.
34
+ *
35
+ * El NIF suele aparecer en el `serialNumber` (p. ej. `IDCES-74654958V`) o como
36
+ * primer token del `commonName` (p. ej. `74654958V ANTONIO JOSE RECHE`).
37
+ * Devuelve `null` si no se puede determinar.
38
+ */
39
+ export declare function extractNifFromCertificate(pem: string): string | null;
40
+ /**
41
+ * Información de un certificado en PEM: NIF y nombre/razón del titular.
42
+ */
43
+ export interface CertificateInfo {
44
+ /** NIF del titular del certificado. */
45
+ nif: string;
46
+ /** Nombre o razón social del titular. */
47
+ nombreRazon: string;
48
+ }
49
+ /**
50
+ * Extrae el NIF y el nombre/razón del titular de un certificado en PEM.
51
+ *
52
+ * El NIF se obtiene del `serialNumber` (p. ej. `IDCES-74654958V`) o del primer
53
+ * token del `commonName`. El nombre se compone de `givenName` + `surname`, o
54
+ * del `commonName` sin el prefijo de NIF. Devuelve `null` si no se puede
55
+ * determinar el NIF.
56
+ */
57
+ export declare function extractCertificateInfo(pem: string): CertificateInfo | null;
58
+ //# sourceMappingURL=p12.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"p12.d.ts","sourceRoot":"","sources":["../../../src/integration/p12.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,0CAA0C;IAC1C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CA6BpE;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuBpE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAuC1E"}
@@ -0,0 +1,119 @@
1
+ import forge from 'node-forge';
2
+ /**
3
+ * Lee un certificado `.p12`/`.pfx` e itera todos sus campos (bags),
4
+ * devolviéndolos todos. La librería no interpreta qué campo es cada cosa:
5
+ * simplemente expone el contenido para que la aplicación lo use.
6
+ *
7
+ * @param buffer Contenido del archivo `.p12`/`.pfx`.
8
+ * @param password Contraseña del `.p12`.
9
+ */
10
+ export function readP12(buffer, password) {
11
+ const asn1 = forge.asn1.fromDer(forge.util.createBuffer(new Uint8Array(buffer)));
12
+ const p12 = forge.pkcs12.pkcs12FromAsn1(asn1, password);
13
+ const bags = [];
14
+ const certificates = [];
15
+ const keys = [];
16
+ p12.safeContents.forEach((safe) => {
17
+ safe.safeBags.forEach((bag) => {
18
+ const type = bag.type ?? 'unknown';
19
+ let pem;
20
+ let value;
21
+ if (bag.cert) {
22
+ pem = forge.pki.certificateToPem(bag.cert);
23
+ certificates.push(pem);
24
+ }
25
+ else if (bag.key) {
26
+ pem = forge.pki.privateKeyToPem(bag.key);
27
+ keys.push(pem);
28
+ }
29
+ else {
30
+ value = bag.attributes;
31
+ }
32
+ bags.push({ type, pem, value });
33
+ });
34
+ });
35
+ return { bags, certificates, keys };
36
+ }
37
+ /**
38
+ * Extrae el NIF de un certificado en PEM.
39
+ *
40
+ * El NIF suele aparecer en el `serialNumber` (p. ej. `IDCES-74654958V`) o como
41
+ * primer token del `commonName` (p. ej. `74654958V ANTONIO JOSE RECHE`).
42
+ * Devuelve `null` si no se puede determinar.
43
+ */
44
+ export function extractNifFromCertificate(pem) {
45
+ try {
46
+ const cert = forge.pki.certificateFromPem(pem);
47
+ const attrs = cert.subject.attributes;
48
+ // serialNumber: "IDCES-74654958V" o directamente "B12345678"
49
+ const serial = attrs.find((a) => a.name === 'serialNumber')?.value;
50
+ if (serial) {
51
+ const m = String(serial).match(/IDCES-(\S+)/i) ?? String(serial).match(/^([A-Z0-9]{8,9})/i);
52
+ if (m && m[1])
53
+ return m[1];
54
+ }
55
+ // commonName: "74654958V ANTONIO JOSE RECHE (R: B18579458)"
56
+ const cn = attrs.find((a) => a.name === 'commonName')?.value;
57
+ if (cn) {
58
+ const m = String(cn).match(/^([A-Z0-9]{8,9})/i);
59
+ if (m && m[1])
60
+ return m[1];
61
+ }
62
+ return null;
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ /**
69
+ * Extrae el NIF y el nombre/razón del titular de un certificado en PEM.
70
+ *
71
+ * El NIF se obtiene del `serialNumber` (p. ej. `IDCES-74654958V`) o del primer
72
+ * token del `commonName`. El nombre se compone de `givenName` + `surname`, o
73
+ * del `commonName` sin el prefijo de NIF. Devuelve `null` si no se puede
74
+ * determinar el NIF.
75
+ */
76
+ export function extractCertificateInfo(pem) {
77
+ try {
78
+ const cert = forge.pki.certificateFromPem(pem);
79
+ const attrs = cert.subject.attributes;
80
+ // NIF
81
+ const serial = attrs.find((a) => a.name === 'serialNumber')?.value;
82
+ let nif = null;
83
+ if (serial) {
84
+ const m = String(serial).match(/IDCES-(\S+)/i) ?? String(serial).match(/^([A-Z0-9]{8,9})/i);
85
+ if (m && m[1])
86
+ nif = m[1];
87
+ }
88
+ if (!nif) {
89
+ const cn = attrs.find((a) => a.name === 'commonName')?.value;
90
+ if (cn) {
91
+ const m = String(cn).match(/^([A-Z0-9]{8,9})/i);
92
+ if (m && m[1])
93
+ nif = m[1];
94
+ }
95
+ }
96
+ if (!nif)
97
+ return null;
98
+ // Nombre: givenName + surname, o commonName sin el NIF.
99
+ const given = attrs.find((a) => a.name === 'givenName')?.value;
100
+ const surname = attrs.find((a) => a.name === 'surname')?.value;
101
+ let nombreRazon = '';
102
+ if (given)
103
+ nombreRazon += given;
104
+ if (surname)
105
+ nombreRazon += (nombreRazon ? ' ' : '') + surname;
106
+ nombreRazon = nombreRazon.trim();
107
+ if (!nombreRazon) {
108
+ const cn = attrs.find((a) => a.name === 'commonName')?.value;
109
+ if (cn) {
110
+ nombreRazon = String(cn).replace(/^[A-Z0-9]{8,9}\s*/, '').split(' (R:')[0]?.trim() ?? '';
111
+ }
112
+ }
113
+ return { nif, nombreRazon };
114
+ }
115
+ catch {
116
+ return null;
117
+ }
118
+ }
119
+ //# sourceMappingURL=p12.js.map