@useinvio/nfse-sdk 3.0.0 → 3.1.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/README.md +115 -56
- package/dist/agent.d.ts +86 -0
- package/dist/agent.js +235 -0
- package/dist/agent.js.map +1 -0
- package/dist/certificate.d.ts +96 -0
- package/dist/certificate.js +218 -0
- package/dist/certificate.js.map +1 -0
- package/dist/certificateValidation.d.ts +11 -6
- package/dist/certificateValidation.js +23 -12
- package/dist/certificateValidation.js.map +1 -1
- package/dist/client.d.ts +4 -2
- package/dist/client.js +5 -4
- package/dist/client.js.map +1 -1
- package/dist/dpsJsonSchema.d.ts +17 -0
- package/dist/dpsJsonSchema.js +184 -0
- package/dist/dpsJsonSchema.js.map +1 -0
- package/dist/emissaoNota.d.ts +4 -4
- package/dist/emissaoNota.js +4 -3
- package/dist/emissaoNota.js.map +1 -1
- package/dist/fiscalDomains.d.ts +22 -0
- package/dist/fiscalDomains.js +99 -0
- package/dist/fiscalDomains.js.map +1 -0
- package/dist/fiscalValidation.js +21 -53
- package/dist/fiscalValidation.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/jsonSchemaCheck.d.ts +12 -0
- package/dist/jsonSchemaCheck.js +70 -0
- package/dist/jsonSchemaCheck.js.map +1 -0
- package/dist/loadPfx.d.ts +2 -0
- package/dist/loadPfx.js +2 -1
- package/dist/loadPfx.js.map +1 -1
- package/dist/sefinClient.d.ts +10 -4
- package/dist/sefinClient.js +22 -4
- package/dist/sefinClient.js.map +1 -1
- package/dist/signXml.d.ts +3 -3
- package/dist/signXml.js +8 -6
- package/dist/signXml.js.map +1 -1
- package/dist/xmlInspection.js +10 -9
- package/dist/xmlInspection.js.map +1 -1
- package/dist/xsdValidation.d.ts +17 -5
- package/dist/xsdValidation.js +75 -67
- package/dist/xsdValidation.js.map +1 -1
- package/examples/README.md +1 -1
- package/examples/client-resource.ts +3 -5
- package/examples/emit-homologation.ts +3 -4
- package/examples/handle-errors.ts +3 -3
- package/llms.txt +15 -5
- package/package.json +9 -4
package/dist/xsdValidation.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { cpSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
4
2
|
import { join } from 'node:path';
|
|
5
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { ParseOption, XmlBufferInputProvider, XmlDocument, XmlParseError, XmlValidateError, XsdValidator, xmlRegisterInputProvider, } from 'libxml2-wasm';
|
|
6
5
|
/** The DPS XML violates the NFS-e v1.01 XSD. This is a fiscal payload problem. */
|
|
7
6
|
export class DpsXsdValidationError extends Error {
|
|
8
7
|
details;
|
|
@@ -13,87 +12,96 @@ export class DpsXsdValidationError extends Error {
|
|
|
13
12
|
}
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* The embedded XSD engine (libxml2 compiled to WebAssembly) could not load the
|
|
16
|
+
* official schemas or crashed. This is an infrastructure problem, not proof
|
|
17
|
+
* that the XML is fiscally invalid, and callers must not treat it as a
|
|
19
18
|
* permanent rejection.
|
|
20
19
|
*/
|
|
21
|
-
export class
|
|
20
|
+
export class XsdEngineUnavailableError extends Error {
|
|
22
21
|
cause;
|
|
23
22
|
constructor(message, cause) {
|
|
24
23
|
super(message);
|
|
25
24
|
this.cause = cause;
|
|
26
|
-
this.name = '
|
|
25
|
+
this.name = 'XsdEngineUnavailableError';
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
/**
|
|
29
|
+
* @deprecated Since 3.1.0 the SDK no longer runs the `xmllint` binary.
|
|
30
|
+
* Kept as an alias so existing `instanceof XmllintUnavailableError` checks still work.
|
|
31
|
+
*/
|
|
32
|
+
export const XmllintUnavailableError = XsdEngineUnavailableError;
|
|
33
|
+
/** Virtual URL scheme for the bundled schemas, so includes never touch disk or network. */
|
|
34
|
+
const SCHEMA_URL_PREFIX = 'nfse-sdk-xsd://v1.01/';
|
|
35
|
+
const ENTRY_SCHEMA = 'DPS_v1.01.xsd';
|
|
36
|
+
/** Never load DTDs, external entities or network resources while parsing. */
|
|
37
|
+
export const SAFE_PARSE_OPTIONS = ParseOption.XML_PARSE_NONET | ParseOption.XML_PARSE_NO_XXE;
|
|
38
|
+
let compiledValidator;
|
|
39
|
+
function schemaSourceDir() {
|
|
40
|
+
return fileURLToPath(new URL('../schemas/nfse/v1.01/Schemas/1.01/', import.meta.url));
|
|
31
41
|
}
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
function loadSchemaBuffers() {
|
|
43
|
+
const dir = schemaSourceDir();
|
|
44
|
+
const encoder = new TextEncoder();
|
|
45
|
+
const buffers = {};
|
|
46
|
+
for (const file of readdirSync(dir)) {
|
|
47
|
+
if (!file.endsWith('.xsd'))
|
|
48
|
+
continue;
|
|
49
|
+
let text = readFileSync(join(dir, file), 'utf8');
|
|
50
|
+
if (file === 'tiposSimples_v1.01.xsd') {
|
|
51
|
+
// libxml2 treats ^/$ literally in XSD regexes. The official package ships
|
|
52
|
+
// one JavaScript-style anchor, so normalize that expression in memory.
|
|
53
|
+
text = text.replace('<xs:pattern value="^0{0,4}\\d{1,5}$"/>', '<xs:pattern value="0{0,4}\\d{1,5}"/>');
|
|
54
|
+
}
|
|
55
|
+
buffers[`${SCHEMA_URL_PREFIX}${file}`] = encoder.encode(text);
|
|
56
|
+
}
|
|
57
|
+
return buffers;
|
|
36
58
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
/** Compiles the official schemas once per process; later calls reuse the validator. */
|
|
60
|
+
function getValidator() {
|
|
61
|
+
if (compiledValidator)
|
|
62
|
+
return compiledValidator;
|
|
63
|
+
let schemaDoc;
|
|
64
|
+
try {
|
|
65
|
+
const buffers = loadSchemaBuffers();
|
|
66
|
+
const entry = buffers[`${SCHEMA_URL_PREFIX}${ENTRY_SCHEMA}`];
|
|
67
|
+
if (!entry)
|
|
68
|
+
throw new Error(`${ENTRY_SCHEMA} nao encontrado em ${schemaSourceDir()}`);
|
|
69
|
+
xmlRegisterInputProvider(new XmlBufferInputProvider(buffers));
|
|
70
|
+
schemaDoc = XmlDocument.fromBuffer(entry, { url: `${SCHEMA_URL_PREFIX}${ENTRY_SCHEMA}`, option: SAFE_PARSE_OPTIONS });
|
|
71
|
+
compiledValidator = XsdValidator.fromDoc(schemaDoc);
|
|
72
|
+
return compiledValidator;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new XsdEngineUnavailableError(`Nao foi possivel carregar os XSD oficiais v1.01: ${error instanceof Error ? error.message : String(error)}`, error);
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
// The validator keeps its own compiled copy of the schema.
|
|
79
|
+
schemaDoc?.dispose();
|
|
80
|
+
}
|
|
54
81
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
82
|
+
function detailsOf(error) {
|
|
83
|
+
const details = error.details.map((detail) => detail.message.trim()).filter(Boolean);
|
|
84
|
+
return details.length ? details : [error.message.trim() || error.name];
|
|
57
85
|
}
|
|
58
|
-
/**
|
|
86
|
+
/**
|
|
87
|
+
* Validates a DPS against the official v1.01 schema before signing.
|
|
88
|
+
* Runs in-process (libxml2 in WebAssembly): no `xmllint`, no temp files, no network.
|
|
89
|
+
*/
|
|
59
90
|
export function validateDpsXmlAgainstXsd(xml) {
|
|
60
|
-
const
|
|
61
|
-
|
|
91
|
+
const validator = getValidator();
|
|
92
|
+
let doc;
|
|
62
93
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const xmlPath = join(workDir, 'dps.xml');
|
|
70
|
-
writeFileSync(xmlPath, xml);
|
|
71
|
-
try {
|
|
72
|
-
execFileSync('xmllint', ['--noout', '--schema', join(schemasDir, 'DPS_v1.01.xsd'), xmlPath], {
|
|
73
|
-
encoding: 'utf8',
|
|
74
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
if (!isExecFileSyncFailure(error)) {
|
|
79
|
-
throw new XmllintUnavailableError(`Falha ao executar xmllint: ${String(error)}`, error);
|
|
80
|
-
}
|
|
81
|
-
if (error.code === 'ENOENT') {
|
|
82
|
-
throw new XmllintUnavailableError(`xmllint nao encontrado no ambiente de execucao (path=${error.path ?? 'xmllint'}). ` +
|
|
83
|
-
'Instale o pacote libxml2/xmllint antes de validar o XSD.', error);
|
|
84
|
-
}
|
|
85
|
-
const stderrText = toText(error.stderr).trim();
|
|
86
|
-
if (stderrText) {
|
|
87
|
-
const details = stderrText.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
88
|
-
throw new DpsXsdValidationError(details.length ? details : [stderrText]);
|
|
89
|
-
}
|
|
90
|
-
// xmllint failed but produced no stderr: do not mask this as an XML
|
|
91
|
-
// schema violation, since we have no evidence about the XML content.
|
|
92
|
-
throw new XmllintUnavailableError(`xmllint falhou sem stderr: ${describeSpawnFailure(error)}`, error);
|
|
94
|
+
doc = XmlDocument.fromString(xml, { option: SAFE_PARSE_OPTIONS });
|
|
95
|
+
validator.validate(doc);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (error instanceof XmlValidateError || error instanceof XmlParseError) {
|
|
99
|
+
throw new DpsXsdValidationError(detailsOf(error));
|
|
93
100
|
}
|
|
101
|
+
throw new XsdEngineUnavailableError(`Falha no motor de validacao XSD: ${error instanceof Error ? error.message : String(error)}`, error);
|
|
94
102
|
}
|
|
95
103
|
finally {
|
|
96
|
-
|
|
104
|
+
doc?.dispose();
|
|
97
105
|
}
|
|
98
106
|
}
|
|
99
107
|
//# sourceMappingURL=xsdValidation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xsdValidation.js","sourceRoot":"","sources":["../xsdValidation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"xsdValidation.js","sourceRoot":"","sources":["../xsdValidation.ts"],"names":[],"mappings":"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"}
|
package/examples/README.md
CHANGED
|
@@ -12,4 +12,4 @@ The payloads in `payloads.ts` are shared by these examples and exercised by the
|
|
|
12
12
|
- [`client-resource.ts`](./client-resource.ts): use `NfseClient` with certificate and defaults configured once.
|
|
13
13
|
- [`handle-errors.ts`](./handle-errors.ts): normalize SEFIN rejection details for your application.
|
|
14
14
|
|
|
15
|
-
The examples assume Node.js 20+ and a valid A1/PFX certificate. They are intentionally explicit about fiscal fields; the SDK does not infer municipal taxation, withholding, CST or total tax burden.
|
|
15
|
+
The examples assume Node.js 20+ and a valid A1/PFX certificate, loaded with `NfseCertificate.fromEnv()` from `NFSE_CERT_PATH` (or `NFSE_CERT_BASE64`) and `NFSE_CERT_PASSWORD` (or `NFSE_CERT_PASSWORD_FILE`). They are intentionally explicit about fiscal fields; the SDK does not infer municipal taxation, withholding, CST or total tax burden.
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { NfseClient } from '@useinvio/nfse-sdk';
|
|
1
|
+
import { NfseCertificate, NfseClient } from '@useinvio/nfse-sdk';
|
|
2
2
|
import { nationalInvoice } from './payloads.js';
|
|
3
3
|
|
|
4
4
|
const client = new NfseClient({
|
|
5
5
|
environment: 'sandbox',
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
password: process.env.NFSE_CERTIFICATE_PASSWORD!,
|
|
9
|
-
},
|
|
6
|
+
// NFSE_CERT_PATH or NFSE_CERT_BASE64, plus NFSE_CERT_PASSWORD or NFSE_CERT_PASSWORD_FILE
|
|
7
|
+
certificate: NfseCertificate.fromEnv(),
|
|
10
8
|
defaults: { prestador: nationalInvoice.prestador, servico: nationalInvoice.servico },
|
|
11
9
|
});
|
|
12
10
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { EmitirNotaError, emitirNfse,
|
|
1
|
+
import { EmitirNotaError, emitirNfse, NfseCertificate } from '@useinvio/nfse-sdk';
|
|
2
2
|
import { nationalInvoice } from './payloads.js';
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const certificate = NfseCertificate.fromEnv(); // NFSE_CERT_PATH + NFSE_CERT_PASSWORD
|
|
6
5
|
|
|
7
6
|
try {
|
|
8
|
-
const resultado = await emitirNfse(nationalInvoice,
|
|
7
|
+
const resultado = await emitirNfse(nationalInvoice, certificate);
|
|
9
8
|
console.log(resultado.chaveAcesso);
|
|
10
9
|
console.log(resultado.nfseXml);
|
|
11
10
|
} catch (error) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { EmitirNotaError, emitirNfse,
|
|
1
|
+
import { EmitirNotaError, emitirNfse, NfseCertificate, type DpsJsonRequest } from '@useinvio/nfse-sdk';
|
|
2
2
|
import { nationalInvoice } from './payloads.js';
|
|
3
3
|
|
|
4
4
|
async function emitWithStructuredErrors(nota: DpsJsonRequest) {
|
|
5
|
-
const
|
|
5
|
+
const certificate = NfseCertificate.fromEnv(); // NFSE_CERT_PATH + NFSE_CERT_PASSWORD
|
|
6
6
|
|
|
7
7
|
try {
|
|
8
|
-
return await emitirNfse(nota,
|
|
8
|
+
return await emitirNfse(nota, certificate);
|
|
9
9
|
} catch (error) {
|
|
10
10
|
if (!(error instanceof EmitirNotaError)) throw error;
|
|
11
11
|
|
package/llms.txt
CHANGED
|
@@ -20,10 +20,13 @@ It is not a fiscal decision engine. Do not infer tax codes, accounting rules, te
|
|
|
20
20
|
- `emitirNfse(input, pfx, options?)`: issue an invoice from a DPS XML string or `DpsJsonRequest`.
|
|
21
21
|
- `buildDpsFromJson(input)`: build unsigned DPS XML from declarative JSON.
|
|
22
22
|
- `buildDpsId(prestador, nDPS, serie?)`: derive the 45-character DPS Id.
|
|
23
|
-
- `
|
|
23
|
+
- `NfseCertificate`: opaque A1 certificate for signing and mTLS (`fromEnv`, `fromFile`, `fromBase64`, `fromPfx`, `fromPem`). Exposes only metadata (CNPJ/CPF, validity, fingerprint); the private key lives outside the object and never appears in logs or JSON. Env convention: `NFSE_CERT_PATH` or `NFSE_CERT_BASE64`, plus `NFSE_CERT_PASSWORD` or `NFSE_CERT_PASSWORD_FILE`.
|
|
24
|
+
- `loadPfx(...)` and `loadPfxFromBuffer(...)`: legacy loaders that return the key as PEM; prefer `NfseCertificate`.
|
|
24
25
|
- `consultarNfse(...)`, `enviarEvento(...)`, `extrairErros(...)`: lower-level SEFIN helpers.
|
|
25
26
|
- `setSefinRequestObserver(...)` and `createSefinLatencyTracker(...)`: observe SEFIN round-trip latency when `NFSE_SEFIN_LATENCY_METRICS` is enabled; percentiles require `includePercentiles: true`.
|
|
26
27
|
- `gzipBase64(...)`, `gunzipBase64(...)`, `signDps(...)`, `verifyDps(...)`: protocol utilities for custom flows.
|
|
28
|
+
- `DPS_JSON_REQUEST_SCHEMA`: JSON Schema 2020-12 for the canonical `DpsJsonRequest` (formats and code domains; cross-field rules stay in `validateDpsJsonRequest`).
|
|
29
|
+
- `@useinvio/nfse-sdk/agent`: framework-neutral agent/MCP tools (`validate_dps`, `build_dps_xml`, `get_nfse`) and `toAgentIssues(error)`. Certificate and environment come from the host context, never from tool input.
|
|
27
30
|
|
|
28
31
|
## File Map
|
|
29
32
|
|
|
@@ -33,9 +36,15 @@ It is not a fiscal decision engine. Do not infer tax codes, accounting rules, te
|
|
|
33
36
|
- `fiscalValidation.ts`: structural and layout-oriented validation for the JSON input. This intentionally rejects unsupported or ambiguous fiscal shapes.
|
|
34
37
|
- `sefinClient.ts`: HTTPS mTLS requests to SEFIN, latency observation, response parsing, error normalization, invoice query, issue transport, and event transport.
|
|
35
38
|
- `config.ts`: SEFIN base URLs, environment names, and `tpAmb` mapping.
|
|
36
|
-
- `
|
|
39
|
+
- `certificate.ts`: `NfseCertificate`, ICP-Brasil CNPJ/CPF extraction, env loading, per-certificate mTLS agent, and the internal `resolveCredentials` used by signing and transport.
|
|
40
|
+
- `loadPfx.ts`: PFX/A1 certificate decoding with `node-forge` (shared parser plus legacy loaders).
|
|
41
|
+
- `xsdValidation.ts`: in-process XSD validation with libxml2 compiled to WebAssembly; schemas compiled once per process.
|
|
37
42
|
- `signXml.ts`: XMLDSIG signing and verification helpers.
|
|
38
43
|
- `gzipB64.ts`: GZip/Base64 helpers.
|
|
44
|
+
- `fiscalDomains.ts`: code domains shared by the validator and the JSON Schema.
|
|
45
|
+
- `dpsJsonSchema.ts`: JSON Schema for `DpsJsonRequest`; `satisfies` checks fail the build when a type gains a field the schema does not describe.
|
|
46
|
+
- `jsonSchemaCheck.ts`: internal validator for the portable keyword subset the schema may use.
|
|
47
|
+
- `agent.ts`: agent tool definitions, unified `NfseAgentIssue` shape, and error mapping.
|
|
39
48
|
|
|
40
49
|
## Core Data Shape
|
|
41
50
|
|
|
@@ -63,17 +72,18 @@ Keep values as strings when they represent fiscal codes, identifiers, decimals,
|
|
|
63
72
|
- Currency discrepancies are warnings; explicit values retain priority. Service amounts must remain positive after rounding; all foreign amounts are serialized with two decimals.
|
|
64
73
|
- `validateDpsJsonRequest` returns independent normalized data, errors in `issues`, and non-blocking `warnings`.
|
|
65
74
|
- `EmitirNotaError` covers SEFIN rejection and incomplete/invalid HTTP 2xx authorization responses, including missing/invalid/conflicting 50-digit access keys. Reconcile before retrying; the SDK never retries automatically.
|
|
66
|
-
- `sefinClient.ts` uses PEM key/cert
|
|
75
|
+
- `sefinClient.ts` uses a per-certificate `https.Agent` (from `NfseCertificate`) or PEM key/cert (legacy `PfxMaterial`) for mTLS, never the raw PFX in the Node TLS handshake. Access keys are validated as 50 digits before any request (`ChaveAcessoInvalidaError`).
|
|
76
|
+
- XSD validation needs no system `xmllint`; it runs in WebAssembly. `XmllintUnavailableError` is a deprecated alias of `XsdEngineUnavailableError`.
|
|
67
77
|
- SEFIN latency metrics are off by default, enabled through `NFSE_SEFIN_LATENCY_METRICS`, and emitted for the external request only; keep them separate from API route latency when integrating observability.
|
|
68
78
|
|
|
69
79
|
## Change Guidance for LLMs
|
|
70
80
|
|
|
71
81
|
- Preserve the public API names exported by `index.ts` unless the task explicitly asks for a breaking change.
|
|
72
82
|
- Prefer adding or adjusting focused tests in `test/` when changing XML generation, validation, signing, transport parsing, or client defaults.
|
|
73
|
-
- When adding support for a new NFS-e layout field, update the TypeScript interface, validation rules, builder output, docs/examples, and tests together.
|
|
83
|
+
- When adding support for a new NFS-e layout field, update the TypeScript interface, validation rules, JSON Schema (`dpsJsonSchema.ts`), builder output, docs/examples, and tests together.
|
|
74
84
|
- Do not add fiscal assumptions to make examples pass. Required fiscal choices should stay explicit in user input.
|
|
75
85
|
- Be careful with XML ordering. The generated order should follow the SEFIN schema, and tests may compare XML snippets.
|
|
76
|
-
- Do not hand-wave certificate handling.
|
|
86
|
+
- Do not hand-wave certificate handling. Accept `CertificateInput` (`NfseCertificate | PfxMaterial`) and go through `resolveCredentials`; never log, serialize, or return key material, the PFX bytes, or the password.
|
|
77
87
|
- Network calls to SEFIN should stay isolated in `sefinClient.ts` so tests can mock transport boundaries.
|
|
78
88
|
|
|
79
89
|
## Useful Commands
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinvio/nfse-sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "TypeScript SDK for Brazil's national NFS-e: JSON to DPS/XML, XMLDSIG, GZip/Base64, mTLS and SEFIN errors.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
},
|
|
13
|
+
"./agent": {
|
|
14
|
+
"types": "./dist/agent.d.ts",
|
|
15
|
+
"import": "./dist/agent.js"
|
|
16
|
+
},
|
|
13
17
|
"./package.json": "./package.json"
|
|
14
18
|
},
|
|
15
19
|
"files": [
|
|
@@ -62,9 +66,10 @@
|
|
|
62
66
|
"access": "public"
|
|
63
67
|
},
|
|
64
68
|
"dependencies": {
|
|
65
|
-
"@xmldom/xmldom": "^0.8.
|
|
66
|
-
"
|
|
67
|
-
"
|
|
69
|
+
"@xmldom/xmldom": "^0.8.15",
|
|
70
|
+
"libxml2-wasm": "^0.7.2",
|
|
71
|
+
"node-forge": "^1.4.3",
|
|
72
|
+
"xml-crypto": "^6.4.0"
|
|
68
73
|
},
|
|
69
74
|
"devDependencies": {
|
|
70
75
|
"@types/node": "^22.13.14",
|