From 0ead240b560e6199cf18d14eec794c6c96a19863 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:12 -0500 Subject: [PATCH 01/15] chore(xml): test publish workflow --- .github/workflows/publish.yml | 76 +- packages/test-cjs/config.cjs | 4 + packages/test-cjs/package-lock.json | 1220 ++++++++++++++--- packages/test-cjs/package.json | 31 +- packages/test-cjs/routes/cfdi-2json.cjs | 52 +- packages/test-cjs/routes/cfdi-catalogos.cjs | 51 +- .../test-cjs/routes/cfdi-complementos.cjs | 63 +- packages/test-cjs/routes/cfdi-csd.cjs | 77 +- packages/test-cjs/routes/cfdi-csf.cjs | 29 +- packages/test-cjs/routes/cfdi-elements.cjs | 40 +- packages/test-cjs/routes/cfdi-expresiones.cjs | 9 - packages/test-cjs/routes/cfdi-rfc.cjs | 45 +- packages/test-cjs/routes/cfdi-transform.cjs | 32 +- packages/test-cjs/routes/cfdi-types.cjs | 9 - packages/test-cjs/routes/cfdi-utils.cjs | 27 +- packages/test-cjs/routes/cfdi-xml.cjs | 115 +- packages/test-cjs/routes/cfdi-xsd.cjs | 31 +- packages/test-cjs/routes/clir-openssl.cjs | 9 - packages/test-cjs/routes/saxon-he-cli.cjs | 9 - packages/test-cjs/server.cjs | 140 +- packages/test-esm/config.mjs | 7 + packages/test-esm/package.json | 31 +- packages/test-esm/routes/cfdi-2json.mjs | 51 +- packages/test-esm/routes/cfdi-catalogos.mjs | 51 +- .../test-esm/routes/cfdi-complementos.mjs | 59 +- packages/test-esm/routes/cfdi-csd.mjs | 74 +- packages/test-esm/routes/cfdi-csf.mjs | 29 +- packages/test-esm/routes/cfdi-elements.mjs | 47 +- packages/test-esm/routes/cfdi-expresiones.mjs | 9 - packages/test-esm/routes/cfdi-rfc.mjs | 46 +- packages/test-esm/routes/cfdi-transform.mjs | 34 +- packages/test-esm/routes/cfdi-types.mjs | 9 - packages/test-esm/routes/cfdi-utils.mjs | 28 +- packages/test-esm/routes/cfdi-xml.mjs | 126 +- packages/test-esm/routes/cfdi-xsd.mjs | 30 +- packages/test-esm/routes/clir-openssl.mjs | 9 - packages/test-esm/routes/saxon-he-cli.mjs | 9 - packages/test-esm/server.mjs | 143 +- packages/test-ts/config.ts | 7 + packages/test-ts/package.json | 33 + packages/test-ts/routes/cfdi-2json.ts | 44 + packages/test-ts/routes/cfdi-catalogos.ts | 42 + packages/test-ts/routes/cfdi-complementos.ts | 72 + packages/test-ts/routes/cfdi-csd.ts | 74 + packages/test-ts/routes/cfdi-csf.ts | 26 + packages/test-ts/routes/cfdi-elements.ts | 26 + packages/test-ts/routes/cfdi-rfc.ts | 37 + packages/test-ts/routes/cfdi-transform.ts | 28 + packages/test-ts/routes/cfdi-utils.ts | 28 + packages/test-ts/routes/cfdi-xml.ts | 192 +++ packages/test-ts/routes/cfdi-xsd.ts | 29 + packages/test-ts/server.ts | 61 + packages/test-ts/tsconfig.json | 14 + packages/test-ts/update-versions.mjs | 103 ++ 54 files changed, 2988 insertions(+), 689 deletions(-) create mode 100644 packages/test-cjs/config.cjs delete mode 100644 packages/test-cjs/routes/cfdi-expresiones.cjs delete mode 100644 packages/test-cjs/routes/cfdi-types.cjs delete mode 100644 packages/test-cjs/routes/clir-openssl.cjs delete mode 100644 packages/test-cjs/routes/saxon-he-cli.cjs create mode 100644 packages/test-esm/config.mjs delete mode 100644 packages/test-esm/routes/cfdi-expresiones.mjs delete mode 100644 packages/test-esm/routes/cfdi-types.mjs delete mode 100644 packages/test-esm/routes/clir-openssl.mjs delete mode 100644 packages/test-esm/routes/saxon-he-cli.mjs create mode 100644 packages/test-ts/config.ts create mode 100644 packages/test-ts/package.json create mode 100644 packages/test-ts/routes/cfdi-2json.ts create mode 100644 packages/test-ts/routes/cfdi-catalogos.ts create mode 100644 packages/test-ts/routes/cfdi-complementos.ts create mode 100644 packages/test-ts/routes/cfdi-csd.ts create mode 100644 packages/test-ts/routes/cfdi-csf.ts create mode 100644 packages/test-ts/routes/cfdi-elements.ts create mode 100644 packages/test-ts/routes/cfdi-rfc.ts create mode 100644 packages/test-ts/routes/cfdi-transform.ts create mode 100644 packages/test-ts/routes/cfdi-utils.ts create mode 100644 packages/test-ts/routes/cfdi-xml.ts create mode 100644 packages/test-ts/routes/cfdi-xsd.ts create mode 100644 packages/test-ts/server.ts create mode 100644 packages/test-ts/tsconfig.json create mode 100644 packages/test-ts/update-versions.mjs diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b707e1e..d8d688c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -54,35 +54,21 @@ jobs: if: steps.branch.outputs.is_main == 'true' run: | SCOPES='${{ steps.cfdi.outputs.scopes }}' - TOTAL=$(echo "$SCOPES" | jq -r '.[]' | wc -l | tr -d ' ') - PUBLISHED=0 - FAILED_COUNT=0 - FAILED="" + + # --- Fase 1: Bump de TODOS los scopes --- + echo "========== PHASE 1: VERSION BUMP ==========" for scope in $(echo "$SCOPES" | jq -r '.[]'); do - echo "=== Publishing $scope ===" + echo "=== Bumping $scope ===" rush version --version-policy "$scope" --bump - if rush publish -p -b main --version-policy "$scope" --include-all --set-access-level=public; then - git add -A - PUBLISHED=$((PUBLISHED + 1)) - echo "✓ $scope published" - else - FAILED_COUNT=$((FAILED_COUNT + 1)) - FAILED="$FAILED $scope" - git checkout -- . - echo "::warning::✗ $scope failed, reverted" - fi done - echo "" - echo "========== PUBLISH SUMMARY ==========" - echo "Total scopes: $TOTAL" - echo "Published: $PUBLISHED" - echo "Failed: $FAILED_COUNT" - if [ -n "$FAILED" ]; then - echo "Failed list: $FAILED" - fi - echo "=====================================" - if [ -n "$FAILED" ]; then - echo "::error::Failed scopes:$FAILED" + + # --- Fase 2: Un solo publish (Rush maneja orden topológico) --- + echo "========== PHASE 2: PUBLISH ==========" + if rush publish -p -b main --set-access-level=public; then + git add -A + echo "✓ Publish exitoso" + else + echo "::error::Publish falló" exit 1 fi @@ -91,35 +77,21 @@ jobs: run: | TAG="${{ steps.branch.outputs.name }}" SCOPES='${{ steps.cfdi.outputs.scopes }}' - TOTAL=$(echo "$SCOPES" | jq -r '.[]' | wc -l | tr -d ' ') - PUBLISHED=0 - FAILED_COUNT=0 - FAILED="" + + # --- Fase 1: Bump de TODOS los scopes --- + echo "========== PHASE 1: VERSION BUMP ==========" for scope in $(echo "$SCOPES" | jq -r '.[]'); do - echo "=== Publishing $scope ===" + echo "=== Bumping $scope ===" rush version --version-policy "$scope" --bump --override-bump prerelease --override-prerelease-id "$TAG" - if rush publish --publish --version-policy "$scope" --tag "$TAG" --include-all --set-access-level=public --apply; then - git add -A - PUBLISHED=$((PUBLISHED + 1)) - echo "✓ $scope published" - else - FAILED_COUNT=$((FAILED_COUNT + 1)) - FAILED="$FAILED $scope" - git checkout -- . - echo "::warning::✗ $scope failed, reverted" - fi done - echo "" - echo "========== PUBLISH SUMMARY ==========" - echo "Total scopes: $TOTAL" - echo "Published: $PUBLISHED" - echo "Failed: $FAILED_COUNT" - if [ -n "$FAILED" ]; then - echo "Failed list: $FAILED" - fi - echo "=====================================" - if [ -n "$FAILED" ]; then - echo "::error::Failed scopes:$FAILED" + + # --- Fase 2: Un solo publish (Rush maneja orden topológico) --- + echo "========== PHASE 2: PUBLISH ==========" + if rush publish --publish --tag "$TAG" --set-access-level=public --apply; then + git add -A + echo "✓ Publish exitoso" + else + echo "::error::Publish falló" exit 1 fi diff --git a/packages/test-cjs/config.cjs b/packages/test-cjs/config.cjs new file mode 100644 index 0000000..82a0347 --- /dev/null +++ b/packages/test-cjs/config.cjs @@ -0,0 +1,4 @@ +const path = require('node:path'); +const FILES_DIR = path.resolve(__dirname, '../files'); +const PORT = process.env.PORT || 3001; +module.exports = { FILES_DIR, PORT }; diff --git a/packages/test-cjs/package-lock.json b/packages/test-cjs/package-lock.json index e442422..9010db5 100644 --- a/packages/test-cjs/package-lock.json +++ b/packages/test-cjs/package-lock.json @@ -8,142 +8,217 @@ "name": "test-cjs", "version": "0.0.0", "dependencies": { - "@cfdi/2json": "4.0.13", - "@cfdi/catalogos": "4.0.15", - "@cfdi/complementos": "4.0.16", - "@cfdi/csd": "4.0.15", - "@cfdi/csf": "4.0.15", - "@cfdi/elements": "4.0.13", - "@cfdi/expresiones": "4.0.13", + "@cfdi/2json": "4.0.14-dev.2", + "@cfdi/catalogos": "4.0.16-dev.3", + "@cfdi/complementos": "4.0.17-dev.3", + "@cfdi/csd": "4.0.16-dev.3", + "@cfdi/csf": "4.0.16-dev.3", + "@cfdi/elements": "4.0.14-dev.2", + "@cfdi/expresiones": "4.0.14-dev.2", "@cfdi/rfc": "0.0.10", - "@cfdi/transform": "4.0.13", - "@cfdi/types": "4.0.13", - "@cfdi/utils": "4.0.16", - "@cfdi/xml": "4.0.17", - "@cfdi/xsd": "4.0.16", - "@clir/openssl": "0.0.16", - "@saxon-he/cli": "12.5.1" + "@cfdi/transform": "4.0.14-dev.2", + "@cfdi/types": "4.0.14-dev.2", + "@cfdi/utils": "4.0.17-dev.2", + "@cfdi/xml": "4.0.18-dev.3", + "@cfdi/xsd": "4.0.17-dev.3", + "@clir/openssl": "0.0.17-dev.2", + "@saxon-he/cli": "12.5.2-dev.2", + "express": "^4.21.0" } }, "node_modules/@cfdi/2json": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@cfdi/2json/-/2json-4.0.13.tgz", - "integrity": "sha512-Z4pKLkAmHc5q0hmiwxqRomMIn/Y7Vo0MnJDYni/tkl1t8v6omCVYYEoOVEDfYeTY8n5p7txjgKjM27xwSlje4A==", + "version": "4.0.14-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/2json/-/2json-4.0.14-dev.2.tgz", + "integrity": "sha512-bYBrSH0dpnjfl+k8SN35tn11iPugTLMoHmM1Q+zJV6gDqG0GcqMfxlAVxTSwievyZYgO8LADZZKe9KmcK+ZfzA==", "license": "MIT", "dependencies": { - "@cfdi/elements": "4.0.13", - "@cfdi/types": "4.0.13", - "@cfdi/utils": "4.0.16", + "@cfdi/elements": "4.0.14-dev.1", + "@cfdi/types": "4.0.14-dev.2", + "@cfdi/utils": "4.0.17-dev.2", "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/catalogos": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cfdi/catalogos/-/catalogos-4.0.15.tgz", - "integrity": "sha512-C+b6RXsfJpj2enU7Vgk3HMhFwSGaj/lMYwBoa1JieMOtgehE/6JOrC/WAcV8lBz+603Be7DqqZZMZoLBbu8Nkg==", + "node_modules/@cfdi/2json/node_modules/@cfdi/catalogos": { + "version": "4.0.16-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/catalogos/-/catalogos-4.0.16-dev.2.tgz", + "integrity": "sha512-x7g0iCvz23DICw8ONtOKc4cBInQkkQn44wxFKTYzofF8n4DfogntUKrA9mwRXjcmbTBUbAOg1FXyJT3nz8EACA==", "license": "MIT", "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/complementos": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@cfdi/complementos/-/complementos-4.0.16.tgz", - "integrity": "sha512-C4JdkH2TokhwWj5FxTQ7sZ8bsfsXo70OvSWGe+GdeqxEF7GnGieGvU2nrOI20HQMnv6r20HOUKEEceo5YZaNVw==", + "node_modules/@cfdi/2json/node_modules/@cfdi/complementos": { + "version": "4.0.17-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/complementos/-/complementos-4.0.17-dev.2.tgz", + "integrity": "sha512-eekyqF12TjpCkyt7aurCgjJybVqeyXZl8UZwjDAq3ID1P1O/0TicFGnuBzfWEVtoNbaL4Id7wFubJnjmQNo6mQ==", "license": "MIT", "dependencies": { "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/csd": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cfdi/csd/-/csd-4.0.15.tgz", - "integrity": "sha512-k4bfZujdhmBeL8FeJ9svp2j+qpbWd8hAQSy4fku0004cUysaUjC6yq29wAQnBE+RX6H6ai9z4fitOOyIxvhvqg==", + "node_modules/@cfdi/2json/node_modules/@cfdi/csd": { + "version": "4.0.16-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/csd/-/csd-4.0.16-dev.2.tgz", + "integrity": "sha512-8FXU0EhQW8kp7tgEgzeCoJr+ZUTC9j/M1fNKcHASSXArTeuMjap2WP9Wyhra3rpehyr2YId0A7v7jy2ztd4Xuw==", "license": "MIT", "dependencies": { - "@clir/openssl": "0.0.16", - "curp": "^1.2.0", + "@clir/openssl": "0.0.17-dev.0", "moment": "^2.29.4", - "node-forge": "^1.3.1", - "validate-rfc": "^2.0.2" + "node-forge": "^1.3.1" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/csf": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cfdi/csf/-/csf-4.0.15.tgz", - "integrity": "sha512-5lhlGdojtAnEQ9Fsss70VijIjd5ytbZCDiCiRMBZq/vsIlG2IHTN7+Ts46vU04/g8wTv23+WyPkEvs9agqH1Ig==", + "node_modules/@cfdi/2json/node_modules/@cfdi/elements": { + "version": "4.0.14-dev.1", + "resolved": "https://registry.npmjs.org/@cfdi/elements/-/elements-4.0.14-dev.1.tgz", + "integrity": "sha512-ffXlRq1UekBvR8Us0QCicGBMIZD09PBLyGIwfGMjPUgh6OAgn4jKVy6Xj6dwTi+tGoL7glutPaaVxaZAv9ZdgA==", "license": "MIT", "dependencies": { - "pdf-parse": "^1.1.1", + "@cfdi/catalogos": "4.0.16-dev.2", + "@cfdi/complementos": "4.0.17-dev.2", + "@cfdi/csd": "4.0.16-dev.2", + "@cfdi/xsd": "4.0.17-dev.2", + "@saxon-he/cli": "12.5.2-dev.1", "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/elements": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@cfdi/elements/-/elements-4.0.13.tgz", - "integrity": "sha512-2jVPPnTqu407KcWIExnXabGQNpoNn4qT+QDBIWtYX6q611wPGVA6KZjTNhPpDWURufatHMdm689t09HEHKSQXg==", + "node_modules/@cfdi/2json/node_modules/@cfdi/xsd": { + "version": "4.0.17-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/xsd/-/xsd-4.0.17-dev.2.tgz", + "integrity": "sha512-ALZuHPTKxX93OCbtKtuGF2DA9YEBDvfC2aiG1zzR1Oq+eFfftX/sdyAxPJjBsls+aypuyA+OkyDMyrW+87Djow==", "license": "MIT", "dependencies": { - "@cfdi/catalogos": "4.0.15", - "@cfdi/complementos": "4.0.15", - "@cfdi/csd": "4.0.15", - "@cfdi/xsd": "4.0.15", - "@saxon-he/cli": "12.5.1", + "ajv": "^8.12.0", "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" + } + }, + "node_modules/@cfdi/2json/node_modules/@clir/openssl": { + "version": "0.0.17-dev.0", + "resolved": "https://registry.npmjs.org/@clir/openssl/-/openssl-0.0.17-dev.0.tgz", + "integrity": "sha512-dZ2ATdQrH0SndpM0ZEoX2mclB58oVEtISBdSLYYlJbj7jRWmBsKc9VMd3oXUJ2rV98uws0FRi8oAzz2T+zAEVA==", + "license": "MIT", + "dependencies": { + "@esm2cjs/execa": "^6.1.1-cjs.1", + "node-forge": "^1.3.1" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@cfdi/2json/node_modules/@saxon-he/cli": { + "version": "12.5.2-dev.1", + "resolved": "https://registry.npmjs.org/@saxon-he/cli/-/cli-12.5.2-dev.1.tgz", + "integrity": "sha512-Og2XEqxC3r2QEU/nlZY8ysN/XxeK0LBYcPQXKaW+wpF63U/z+/FwBm7tHla8Zf5jna5L8SaeCvH2C1OsMSpCUQ==", + "license": "MIT", + "dependencies": { + "@esm2cjs/execa": "^6.1.1-cjs.1" + }, + "engines": { + "node": ">=22" } }, - "node_modules/@cfdi/elements/node_modules/@cfdi/complementos": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cfdi/complementos/-/complementos-4.0.15.tgz", - "integrity": "sha512-1wOgCoRfLwPuSEql/xhiUX8g9XqKh2LowXWRdop8Bxlxm2bW+zaOmMMr92htMOpl0q9d/vlCVIweilV9NYozdg==", + "node_modules/@cfdi/catalogos": { + "version": "4.0.16-dev.3", + "resolved": "https://registry.npmjs.org/@cfdi/catalogos/-/catalogos-4.0.16-dev.3.tgz", + "integrity": "sha512-ByNs7Z4zXxM7yZ05oIwzi6ytM3/YljSZP2ZEq1r8FWhhxVCCug6y4SrsgG0vHMBXGEwPfArao/7EE3I44nuCdg==", + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@cfdi/complementos": { + "version": "4.0.17-dev.3", + "resolved": "https://registry.npmjs.org/@cfdi/complementos/-/complementos-4.0.17-dev.3.tgz", + "integrity": "sha512-ub1aVCI2fbty8ICrhYYkT02CkJXr6vv2yHknQ+X6+1Cl7KgH7AQesLaSw4Jlp3oDsdy0F89D4hq8ktDGpdPlfA==", "license": "MIT", "dependencies": { "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/elements/node_modules/@cfdi/xsd": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cfdi/xsd/-/xsd-4.0.15.tgz", - "integrity": "sha512-AzRdA8tiDptTPfX9CzpVEcD6mwaVSd06Jhex7xoB1nuG+E9IayHrAtFEy1dmwtjOVRIYBA3VfXj5VqBtm2c2rw==", + "node_modules/@cfdi/csd": { + "version": "4.0.16-dev.3", + "resolved": "https://registry.npmjs.org/@cfdi/csd/-/csd-4.0.16-dev.3.tgz", + "integrity": "sha512-nPDYZo2MHga0tUSYsm10SP7epVP/DPKyIbBJVLfRyfVcmDyLxt9hBjVj8ejlJRZ43alqK6i1m1sWw8MuK7kU7g==", "license": "MIT", "dependencies": { - "ajv": "^8.12.0", - "xml-js": "^1.6.11", - "xslt": "^0.9.1", - "xslt-processor": "^0.11.7" + "@clir/openssl": "0.0.17-dev.1", + "moment": "^2.29.4", + "node-forge": "^1.3.1" }, "engines": { - "node": ">=10" + "node": ">=22" + } + }, + "node_modules/@cfdi/csd/node_modules/@clir/openssl": { + "version": "0.0.17-dev.1", + "resolved": "https://registry.npmjs.org/@clir/openssl/-/openssl-0.0.17-dev.1.tgz", + "integrity": "sha512-7q5cnN/DZuFBalF/eoFLqtCWCHH46r2vl1GkBuVWvYEb3H6qn5970vGQrNWe/othcwYb8gzjK1LAuhsj3Ho9PA==", + "license": "MIT", + "dependencies": { + "@esm2cjs/execa": "^6.1.1-cjs.1", + "node-forge": "^1.3.1" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@cfdi/csf": { + "version": "4.0.16-dev.3", + "resolved": "https://registry.npmjs.org/@cfdi/csf/-/csf-4.0.16-dev.3.tgz", + "integrity": "sha512-HKht9g/wQ3v7rCqHEYQ0rp+978gqCKzR/GB4pBNs53oX8Qtz4CLoqq+hWhjZk9WPSUXqyph1LwjISKskTM8C5w==", + "license": "MIT", + "dependencies": { + "pdf-parse": "^1.1.1", + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@cfdi/elements": { + "version": "4.0.14-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/elements/-/elements-4.0.14-dev.2.tgz", + "integrity": "sha512-9SAjeKBB3Kpu655do9cR/T6eKsRh22r15hbESn0wzxbjYbKa4cUrv5qsjGvmjK5UCMYEF+FPTvGnzfipM3HisA==", + "license": "MIT", + "dependencies": { + "@cfdi/catalogos": "4.0.16-dev.3", + "@cfdi/complementos": "4.0.17-dev.3", + "@cfdi/csd": "4.0.16-dev.3", + "@cfdi/xsd": "4.0.17-dev.3", + "@saxon-he/cli": "12.5.2-dev.2", + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=22" } }, "node_modules/@cfdi/expresiones": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@cfdi/expresiones/-/expresiones-4.0.13.tgz", - "integrity": "sha512-4Wqb8ii7q6igRhjVzPBijPXaOfp24LgOL6lfS7wwvZkN6a+IUd1/30/FPnqvCUUFwR9RzjgW7uBv9bx06oL5IA==", + "version": "4.0.14-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/expresiones/-/expresiones-4.0.14-dev.2.tgz", + "integrity": "sha512-k06UrdQqnw/p/EYVmjIWz+jNd1c80IN20T+pZ68z9eanOn4lHFhM7yjzLYtO4t9AZFZbmT9f+x+N4i+GO4Z+0w==", "license": "MIT", "dependencies": { "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, "node_modules/@cfdi/rfc": { @@ -156,117 +231,160 @@ } }, "node_modules/@cfdi/transform": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@cfdi/transform/-/transform-4.0.13.tgz", - "integrity": "sha512-VcyO9W9mJ80w51xcg/Eyg/M3Wnkand2db34t/KFN/XyhXaLBuGosNS2Nd1xriWAWEpX+wUwU4PI/Wf84kP1L5A==", + "version": "4.0.14-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/transform/-/transform-4.0.14-dev.2.tgz", + "integrity": "sha512-5+NA4GI2NtVWV+8562IWHJHJWjNsSXwaItcZQrc8jcUJp2JXFWl1M5p6XMHr6rIvKc1ezHmvmvSX7Jn7aaSlzg==", "license": "MIT", "dependencies": { "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, "node_modules/@cfdi/types": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@cfdi/types/-/types-4.0.13.tgz", - "integrity": "sha512-bXIXlkmZfWyGfR+EQpVejcwztE4yBfmeDURuW4c+89qjoNkBTogZ8Prggoup9IQOdAzdFOtRY1Thj9JIqigfNA==", + "version": "4.0.14-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/types/-/types-4.0.14-dev.2.tgz", + "integrity": "sha512-d+9BG81ffKunFYZe098SxnmF1zXGlCwt8iqNF3LVgxzbFb7UtEq4m4zE4Lgu7EAwNN4f022kjkUgBv2V+BNw7Q==", "license": "MIT", "dependencies": { - "@cfdi/catalogos": "4.0.15", - "@cfdi/complementos": "4.0.15", - "@cfdi/csd": "4.0.15", - "@cfdi/xsd": "4.0.15", - "@saxon-he/cli": "12.5.1", + "@cfdi/catalogos": "4.0.16-dev.3", + "@cfdi/complementos": "4.0.17-dev.3", + "@cfdi/csd": "4.0.16-dev.3", + "@cfdi/xsd": "4.0.17-dev.3", + "@saxon-he/cli": "12.5.2-dev.2", "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/types/node_modules/@cfdi/complementos": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cfdi/complementos/-/complementos-4.0.15.tgz", - "integrity": "sha512-1wOgCoRfLwPuSEql/xhiUX8g9XqKh2LowXWRdop8Bxlxm2bW+zaOmMMr92htMOpl0q9d/vlCVIweilV9NYozdg==", + "node_modules/@cfdi/utils": { + "version": "4.0.17-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/utils/-/utils-4.0.17-dev.2.tgz", + "integrity": "sha512-5gfoU8tH4P+iddcho+7CB/8eaxyy9BKjoe32uCf7yzv2H6sqTa+ndFjhQf5sb3BaDZgo+aRzNpAkJo+Y5MQ+ZQ==", "license": "MIT", "dependencies": { "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/types/node_modules/@cfdi/xsd": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cfdi/xsd/-/xsd-4.0.15.tgz", - "integrity": "sha512-AzRdA8tiDptTPfX9CzpVEcD6mwaVSd06Jhex7xoB1nuG+E9IayHrAtFEy1dmwtjOVRIYBA3VfXj5VqBtm2c2rw==", + "node_modules/@cfdi/xml": { + "version": "4.0.18-dev.3", + "resolved": "https://registry.npmjs.org/@cfdi/xml/-/xml-4.0.18-dev.3.tgz", + "integrity": "sha512-CUfmjBjolq4paPZwo/P3K+DLbQspnajA9FTKIwMnLpt2rrhRbVdU/8utp5cRc68HEOPCjtCS86AJNqA21dbcdA==", "license": "MIT", "dependencies": { - "ajv": "^8.12.0", - "xml-js": "^1.6.11", - "xslt": "^0.9.1", - "xslt-processor": "^0.11.7" + "@cfdi/catalogos": "4.0.16-dev.2", + "@cfdi/complementos": "4.0.17-dev.2", + "@cfdi/csd": "4.0.16-dev.2", + "@cfdi/xsd": "4.0.17-dev.2", + "@saxon-he/cli": "12.5.2-dev.1", + "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/utils": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@cfdi/utils/-/utils-4.0.16.tgz", - "integrity": "sha512-QYbDGK7AJcEKyZeJDiqjpt+egFuuW/5ckRp3WSznF9I3VojwbvlL2GI/3nBazRLCHYZxSMZkmm2ErEqkgI05Aw==", + "node_modules/@cfdi/xml/node_modules/@cfdi/catalogos": { + "version": "4.0.16-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/catalogos/-/catalogos-4.0.16-dev.2.tgz", + "integrity": "sha512-x7g0iCvz23DICw8ONtOKc4cBInQkkQn44wxFKTYzofF8n4DfogntUKrA9mwRXjcmbTBUbAOg1FXyJT3nz8EACA==", + "license": "MIT", + "engines": { + "node": ">=22" + } + }, + "node_modules/@cfdi/xml/node_modules/@cfdi/complementos": { + "version": "4.0.17-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/complementos/-/complementos-4.0.17-dev.2.tgz", + "integrity": "sha512-eekyqF12TjpCkyt7aurCgjJybVqeyXZl8UZwjDAq3ID1P1O/0TicFGnuBzfWEVtoNbaL4Id7wFubJnjmQNo6mQ==", "license": "MIT", "dependencies": { "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, - "node_modules/@cfdi/xml": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@cfdi/xml/-/xml-4.0.17.tgz", - "integrity": "sha512-/09ILXndVQolwluwK39uPe6jr1SFVwQToxH2BAcmhONP3BYsd0ryV9nDjNn0yclZWaiP8o7712DJFkjlXRvYLQ==", + "node_modules/@cfdi/xml/node_modules/@cfdi/csd": { + "version": "4.0.16-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/csd/-/csd-4.0.16-dev.2.tgz", + "integrity": "sha512-8FXU0EhQW8kp7tgEgzeCoJr+ZUTC9j/M1fNKcHASSXArTeuMjap2WP9Wyhra3rpehyr2YId0A7v7jy2ztd4Xuw==", + "license": "MIT", + "dependencies": { + "@clir/openssl": "0.0.17-dev.0", + "moment": "^2.29.4", + "node-forge": "^1.3.1" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@cfdi/xml/node_modules/@cfdi/xsd": { + "version": "4.0.17-dev.2", + "resolved": "https://registry.npmjs.org/@cfdi/xsd/-/xsd-4.0.17-dev.2.tgz", + "integrity": "sha512-ALZuHPTKxX93OCbtKtuGF2DA9YEBDvfC2aiG1zzR1Oq+eFfftX/sdyAxPJjBsls+aypuyA+OkyDMyrW+87Djow==", "license": "MIT", "dependencies": { - "@cfdi/catalogos": "4.0.15", - "@cfdi/complementos": "4.0.16", - "@cfdi/csd": "4.0.15", - "@cfdi/xsd": "4.0.16", - "@saxon-he/cli": "12.5.1", + "ajv": "^8.12.0", "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" + } + }, + "node_modules/@cfdi/xml/node_modules/@clir/openssl": { + "version": "0.0.17-dev.0", + "resolved": "https://registry.npmjs.org/@clir/openssl/-/openssl-0.0.17-dev.0.tgz", + "integrity": "sha512-dZ2ATdQrH0SndpM0ZEoX2mclB58oVEtISBdSLYYlJbj7jRWmBsKc9VMd3oXUJ2rV98uws0FRi8oAzz2T+zAEVA==", + "license": "MIT", + "dependencies": { + "@esm2cjs/execa": "^6.1.1-cjs.1", + "node-forge": "^1.3.1" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@cfdi/xml/node_modules/@saxon-he/cli": { + "version": "12.5.2-dev.1", + "resolved": "https://registry.npmjs.org/@saxon-he/cli/-/cli-12.5.2-dev.1.tgz", + "integrity": "sha512-Og2XEqxC3r2QEU/nlZY8ysN/XxeK0LBYcPQXKaW+wpF63U/z+/FwBm7tHla8Zf5jna5L8SaeCvH2C1OsMSpCUQ==", + "license": "MIT", + "dependencies": { + "@esm2cjs/execa": "^6.1.1-cjs.1" + }, + "engines": { + "node": ">=22" } }, "node_modules/@cfdi/xsd": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/@cfdi/xsd/-/xsd-4.0.16.tgz", - "integrity": "sha512-hi12PuGAGWEm6md5YG8ChleUipj3mYrsUVnD7Seuw/2zXeopwcRiW7F8M4oBE1qImuto+CbHzuCq6qN5ZTy9EA==", + "version": "4.0.17-dev.3", + "resolved": "https://registry.npmjs.org/@cfdi/xsd/-/xsd-4.0.17-dev.3.tgz", + "integrity": "sha512-nYjQNkbMQ9tJo1hT50xlCl4Ce5AjWFyWb9zKzZJEEAf4uPJ4CStLtbXebTpKta/8YnXtbDCTeQaa+yr6g749Dw==", "license": "MIT", "dependencies": { "ajv": "^8.12.0", - "xml-js": "^1.6.11", - "xslt": "^0.9.1", - "xslt-processor": "^0.11.7" + "xml-js": "^1.6.11" }, "engines": { - "node": ">=10" + "node": ">=22" } }, "node_modules/@clir/openssl": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/@clir/openssl/-/openssl-0.0.16.tgz", - "integrity": "sha512-LgXVIW0aLctlwJWxw6NAhNnzPNZfR0PUqXnsRb3KV/dALqI4M0GpPhwovnYN4eoy0VtWAK0BjM40greyjGVWxQ==", + "version": "0.0.17-dev.2", + "resolved": "https://registry.npmjs.org/@clir/openssl/-/openssl-0.0.17-dev.2.tgz", + "integrity": "sha512-GdV6sxsbNCdNXo8IBbjTWSPCm3TCNKigHva1MhxRyXOjIW3NMbSjE//31TaTgrNIZ0CvY5BptYk4gmQM7eoVtg==", "license": "MIT", "dependencies": { "@esm2cjs/execa": "^6.1.1-cjs.1", - "moment": "^2.29.4", "node-forge": "^1.3.1" }, "engines": { - "node": ">=10" + "node": ">=22" } }, "node_modules/@esm2cjs/execa": { @@ -383,15 +501,28 @@ } }, "node_modules/@saxon-he/cli": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/@saxon-he/cli/-/cli-12.5.1.tgz", - "integrity": "sha512-j4wZxRVlpe0v//nGMPctiW/ZQmgp1I51pOWsjZmgwzrA8Fc7gQhARI6rZojmb+ne3iWudseq896dVc1HsHqTCA==", + "version": "12.5.2-dev.2", + "resolved": "https://registry.npmjs.org/@saxon-he/cli/-/cli-12.5.2-dev.2.tgz", + "integrity": "sha512-yMM9neP6Zw/CZGwJioxEOu1LJZdz3KXRhVnrjv9t3+5soR2CYpcd9LjpNlBX7bnGqOVxxUyOmBMpONg8ukA47Q==", "license": "MIT", "dependencies": { "@esm2cjs/execa": "^6.1.1-cjs.1" }, "engines": { - "node": ">=10" + "node": ">=22" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, "node_modules/ajv": { @@ -410,6 +541,110 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -424,13 +659,152 @@ "node": ">= 8" } }, - "node_modules/curp": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/curp/-/curp-1.3.1.tgz", - "integrity": "sha512-DoUGrXK7qe6qnSgumTGa9yULrMJy/1Npsgt0LkGkjWXfL/xVyJPcAQgyEJpNaJQjOlCvdEZWJ2K9vNlTmYrHHw==", - "license": "GPL-3.0", + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { - "npm": ">= 8.0.0" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/fast-deep-equal": { @@ -455,6 +829,88 @@ ], "license": "BSD-3-Clause" }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -467,13 +923,87 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/he": { + "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "bin": { - "he": "bin/he" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" } }, "node_modules/isexe": { @@ -488,12 +1018,81 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "license": "MIT" }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -503,6 +1102,21 @@ "node": "*" } }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-ensure": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz", @@ -518,6 +1132,39 @@ "node": ">= 6.13.0" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -527,6 +1174,12 @@ "node": ">=8" } }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, "node_modules/pdf-parse": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-1.1.4.tgz", @@ -543,6 +1196,58 @@ "url": "https://github.com/sponsors/mehmet-kozan" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -552,6 +1257,32 @@ "node": ">=0.10.0" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/sax": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", @@ -561,6 +1292,57 @@ "node": ">=11.0.0" } }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -582,17 +1364,141 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, - "node_modules/validate-rfc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/validate-rfc/-/validate-rfc-2.0.3.tgz", - "integrity": "sha512-WS7CyAz/sfzx6DryOPZvprqz7uxHcQh1yhzDunNX1vidSmprfN7Og66VRpCyU21U82Vzkof5/bOIOKan3dEXLA==", - "license": "MIT" + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/which": { "version": "2.0.2", @@ -620,24 +1526,6 @@ "bin": { "xml-js": "bin/cli.js" } - }, - "node_modules/xslt": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/xslt/-/xslt-0.9.1.tgz", - "integrity": "sha512-2eFkaiFRVkVzedBKYv3MUYmvvK9103NTNFGsyFhLim0Pad0q5yXp2j9tQM2lFW1gFr9fSXV70RRrdcRM7YdRcg==", - "license": "MIT", - "engines": { - "node": ">=0.10.33" - } - }, - "node_modules/xslt-processor": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/xslt-processor/-/xslt-processor-0.11.7.tgz", - "integrity": "sha512-66vcLzwSP4dAvzm4O+Lq20Su03ckrGaYn1kbdCNDp9HaaBZgHJJNZlrVSkvfEuKNvqd4wk9XGU5Rvi+eUJqf+w==", - "license": "LGPL-3.0", - "dependencies": { - "he": "^1.2.0" - } } } } diff --git a/packages/test-cjs/package.json b/packages/test-cjs/package.json index 3f41511..22edd4f 100644 --- a/packages/test-cjs/package.json +++ b/packages/test-cjs/package.json @@ -3,24 +3,25 @@ "version": "0.0.0", "private": true, "scripts": { - "start": "node server.cjs", + "dev": "node server.cjs", "update-versions": "node update-versions.mjs" }, "dependencies": { - "@cfdi/xml": "4.0.17", - "@cfdi/complementos": "4.0.16", - "@cfdi/xsd": "4.0.16", - "@cfdi/csd": "4.0.15", - "@cfdi/csf": "4.0.15", - "@cfdi/catalogos": "4.0.15", - "@cfdi/utils": "4.0.16", + "express": "^4.21.0", + "@cfdi/xml": "4.0.18-dev.3", + "@cfdi/complementos": "4.0.17-dev.3", + "@cfdi/xsd": "4.0.17-dev.3", + "@cfdi/csd": "4.0.16-dev.3", + "@cfdi/csf": "4.0.16-dev.3", + "@cfdi/catalogos": "4.0.16-dev.3", + "@cfdi/utils": "4.0.17-dev.2", "@cfdi/rfc": "0.0.10", - "@cfdi/types": "4.0.13", - "@cfdi/transform": "4.0.13", - "@cfdi/2json": "4.0.13", - "@cfdi/expresiones": "4.0.13", - "@cfdi/elements": "4.0.13", - "@clir/openssl": "0.0.16", - "@saxon-he/cli": "12.5.1" + "@clir/openssl": "0.0.17-dev.2", + "@saxon-he/cli": "12.5.2-dev.2", + "@cfdi/types": "4.0.14-dev.2", + "@cfdi/transform": "4.0.14-dev.2", + "@cfdi/2json": "4.0.14-dev.2", + "@cfdi/expresiones": "4.0.14-dev.2", + "@cfdi/elements": "4.0.14-dev.2" } } diff --git a/packages/test-cjs/routes/cfdi-2json.cjs b/packages/test-cjs/routes/cfdi-2json.cjs index e18c4d1..f3d76e0 100644 --- a/packages/test-cjs/routes/cfdi-2json.cjs +++ b/packages/test-cjs/routes/cfdi-2json.cjs @@ -1,9 +1,43 @@ -module.exports = { - path: '/@cfdi/2json', - name: '@cfdi/2json', - test() { - const pkg = require('@cfdi/2json'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const fs = require('node:fs'); +const path = require('node:path'); +const { Router } = require('express'); +const { XmlToJson } = require('@cfdi/2json'); +const { FILES_DIR } = require('../config.cjs'); + +const router = Router(); + +router.post('/parse', (req, res) => { + try { + const { xml } = req.body; + if (!xml) { + return res.status(400).json({ error: 'Missing "xml" in request body' }); + } + const result = XmlToJson(xml); + res.json(result); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.get('/samples', (req, res) => { + try { + const xmlDir = path.join(FILES_DIR, 'xml'); + const files = fs.readdirSync(xmlDir).filter(f => f.endsWith('.xml')); + res.json({ files }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.get('/sample/:filename', (req, res) => { + try { + const filePath = path.join(FILES_DIR, 'xml', req.params.filename); + const xml = fs.readFileSync(filePath, 'utf-8'); + const result = XmlToJson(xml); + res.json(result); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-catalogos.cjs b/packages/test-cjs/routes/cfdi-catalogos.cjs index 0f4c51f..9929179 100644 --- a/packages/test-cjs/routes/cfdi-catalogos.cjs +++ b/packages/test-cjs/routes/cfdi-catalogos.cjs @@ -1,9 +1,42 @@ -module.exports = { - path: '/@cfdi/catalogos', - name: '@cfdi/catalogos', - test() { - const pkg = require('@cfdi/catalogos'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const { Router } = require('express'); +const { + FormaPago, + MetodoPago, + RegimenFiscal, + TipoComprobante, + UsoCFDI, +} = require('@cfdi/catalogos'); + +const router = Router(); + +router.get('/', (req, res) => { + res.json({ + FormaPago, + MetodoPago, + RegimenFiscal, + TipoComprobante, + UsoCFDI, + }); +}); + +router.get('/forma-pago', (req, res) => { + res.json(FormaPago); +}); + +router.get('/metodo-pago', (req, res) => { + res.json(MetodoPago); +}); + +router.get('/regimen-fiscal', (req, res) => { + res.json(RegimenFiscal); +}); + +router.get('/tipo-comprobante', (req, res) => { + res.json(TipoComprobante); +}); + +router.get('/uso-cfdi', (req, res) => { + res.json(UsoCFDI); +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-complementos.cjs b/packages/test-cjs/routes/cfdi-complementos.cjs index ace3ebe..f8776af 100644 --- a/packages/test-cjs/routes/cfdi-complementos.cjs +++ b/packages/test-cjs/routes/cfdi-complementos.cjs @@ -1,9 +1,54 @@ -module.exports = { - path: '/@cfdi/complementos', - name: '@cfdi/complementos', - test() { - const pkg = require('@cfdi/complementos'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const { Router } = require('express'); +const complementos = require('@cfdi/complementos'); + +const router = Router(); + +router.get('/', (req, res) => { + try { + const available = Object.keys(complementos).filter(name => { + try { + return ( + typeof complementos[name] === 'function' && + complementos[name].prototype + ); + } catch { + return false; + } + }); + res.json({ available }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.post('/pago20', (req, res) => { + try { + const body = req.body || {}; + const { Pagos20, Pago20, Pago20Relacionado } = complementos; + + const pagos = new Pagos20(); + const pago = new Pago20(); + + if (body.pago) { + pago.setAttributes(body.pago); + } + + if (body.relacionados && Array.isArray(body.relacionados) && Pago20Relacionado) { + for (const rel of body.relacionados) { + const relacionado = new Pago20Relacionado(); + relacionado.setAttributes(rel); + pago.addRelacionado(relacionado); + } + } + + pagos.addPago(pago); + + res.json({ + pagos: pagos.json ? pagos.json() : pagos, + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-csd.cjs b/packages/test-cjs/routes/cfdi-csd.cjs index 87c8f42..8f28685 100644 --- a/packages/test-cjs/routes/cfdi-csd.cjs +++ b/packages/test-cjs/routes/cfdi-csd.cjs @@ -1,9 +1,68 @@ -module.exports = { - path: '/@cfdi/csd', - name: '@cfdi/csd', - test() { - const pkg = require('@cfdi/csd'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const path = require('node:path'); +const { Router } = require('express'); +const { Certificate, PrivateKey } = require('@cfdi/csd'); +const { FILES_DIR } = require('../config.cjs'); + +const CERT_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.cer'); +const KEY_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.key'); +const PASSWORD = '12345678a'; + +const router = Router(); + +router.get('/info', (req, res) => { + try { + const cert = Certificate.fromFile(CERT_PATH); + res.json({ + rfc: cert.rfc(), + noCertificado: cert.noCertificado(), + serialNumber: cert.serialNumber(), + legalName: cert.legalName(), + isExpired: cert.isExpired(), + expiresAt: cert.expiresAt(), + isCsd: cert.isCsd(), + isFiel: cert.isFiel(), + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.get('/pem', (req, res) => { + try { + const cert = Certificate.fromFile(CERT_PATH); + res.set('Content-Type', 'text/plain'); + res.send(cert.toPem()); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.post('/sign', (req, res) => { + try { + const { data } = req.body; + if (!data) { + return res.status(400).json({ error: 'Missing "data" in request body' }); + } + const key = PrivateKey.fromFile(KEY_PATH, PASSWORD); + const signature = key.sign(data); + res.json({ data, signature }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.post('/verify', (req, res) => { + try { + const cert = Certificate.fromFile(CERT_PATH); + const key = PrivateKey.fromFile(KEY_PATH, PASSWORD); + const keyBelongsToCert = key.belongsToCertificate(cert); + res.json({ + certRfc: cert.rfc(), + keyBelongsToCert, + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-csf.cjs b/packages/test-cjs/routes/cfdi-csf.cjs index a86370f..ea554ff 100644 --- a/packages/test-cjs/routes/cfdi-csf.cjs +++ b/packages/test-cjs/routes/cfdi-csf.cjs @@ -1,9 +1,20 @@ -module.exports = { - path: '/@cfdi/csf', - name: '@cfdi/csf', - test() { - const pkg = require('@cfdi/csf'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const { Router } = require('express'); +const csfPkg = require('@cfdi/csf'); + +const router = Router(); + +router.post('/parse', (req, res) => { + try { + const { path } = req.body; + if (!path) { + return res.status(400).json({ error: 'Missing "path" in request body' }); + } + const csf = csfPkg.csf || csfPkg.default || csfPkg; + const result = csf(path); + res.json(result); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-elements.cjs b/packages/test-cjs/routes/cfdi-elements.cjs index 76bc9d2..cff0ecf 100644 --- a/packages/test-cjs/routes/cfdi-elements.cjs +++ b/packages/test-cjs/routes/cfdi-elements.cjs @@ -1,9 +1,31 @@ -module.exports = { - path: '/@cfdi/elements', - name: '@cfdi/elements', - test() { - const pkg = require('@cfdi/elements'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const { Router } = require('express'); +const elements = require('@cfdi/elements'); + +const router = Router(); + +router.get('/constants', (req, res) => { + const constants = [ + 'COMPROBANTE', + 'EMISOR', + 'RECEPTOR', + 'CONCEPTOS', + 'CONCEPTO', + 'IMPUESTOS', + 'TRASLADOS', + 'TRASLADO', + 'COMPLEMENTO', + ]; + const result = {}; + for (const name of constants) { + if (elements[name] !== undefined) { + result[name] = elements[name]; + } + } + res.json(result); +}); + +router.get('/', (req, res) => { + res.json({ exports: Object.keys(elements) }); +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-expresiones.cjs b/packages/test-cjs/routes/cfdi-expresiones.cjs deleted file mode 100644 index dc83124..0000000 --- a/packages/test-cjs/routes/cfdi-expresiones.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - path: '/@cfdi/expresiones', - name: '@cfdi/expresiones', - test() { - const pkg = require('@cfdi/expresiones'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; diff --git a/packages/test-cjs/routes/cfdi-rfc.cjs b/packages/test-cjs/routes/cfdi-rfc.cjs index 939c7c5..e865a83 100644 --- a/packages/test-cjs/routes/cfdi-rfc.cjs +++ b/packages/test-cjs/routes/cfdi-rfc.cjs @@ -1,9 +1,36 @@ -module.exports = { - path: '/@cfdi/rfc', - name: '@cfdi/rfc', - test() { - const pkg = require('@cfdi/rfc'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const { Router } = require('express'); +const { rfc, Rfc, RfcFaker } = require('@cfdi/rfc'); + +const router = Router(); + +router.get('/validate/:rfc', (req, res) => { + try { + const input = req.params.rfc; + const validation = rfc.validate(input); + const rfcObj = Rfc.of(input); + res.json({ + rfc: input, + validation, + isFisica: rfcObj.isFisica(), + isMoral: rfcObj.isMoral(), + isGeneric: rfcObj.isGeneric(), + isForeign: rfcObj.isForeign(), + date: rfcObj.date(), + }); + } catch (e) { + res.status(400).json({ error: e.message }); + } +}); + +router.get('/faker', (req, res) => { + try { + res.json({ + persona: RfcFaker.persona(), + moral: RfcFaker.moral(), + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-transform.cjs b/packages/test-cjs/routes/cfdi-transform.cjs index 04de427..39255e6 100644 --- a/packages/test-cjs/routes/cfdi-transform.cjs +++ b/packages/test-cjs/routes/cfdi-transform.cjs @@ -1,9 +1,23 @@ -module.exports = { - path: '/@cfdi/transform', - name: '@cfdi/transform', - test() { - const pkg = require('@cfdi/transform'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const { Router } = require('express'); +const transform = require('@cfdi/transform'); + +const router = Router(); + +router.post('/normalize', (req, res) => { + try { + const { text } = req.body; + if (!text) { + return res.status(400).json({ error: 'Missing "text" in request body' }); + } + const normalized = transform.normalizeSpace(text); + res.json({ original: text, normalized }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.get('/', (req, res) => { + res.json({ exports: Object.keys(transform) }); +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-types.cjs b/packages/test-cjs/routes/cfdi-types.cjs deleted file mode 100644 index 6b50db2..0000000 --- a/packages/test-cjs/routes/cfdi-types.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - path: '/@cfdi/types', - name: '@cfdi/types', - test() { - const pkg = require('@cfdi/types'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; diff --git a/packages/test-cjs/routes/cfdi-utils.cjs b/packages/test-cjs/routes/cfdi-utils.cjs index eda2c01..ba1cd19 100644 --- a/packages/test-cjs/routes/cfdi-utils.cjs +++ b/packages/test-cjs/routes/cfdi-utils.cjs @@ -1,9 +1,18 @@ -module.exports = { - path: '/@cfdi/utils', - name: '@cfdi/utils', - test() { - const pkg = require('@cfdi/utils'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const { Router } = require('express'); +const { NumeroALetras } = require('@cfdi/utils'); + +const router = Router(); + +router.post('/numero-a-letras', (req, res) => { + try { + const { numero, moneda } = req.body; + const converter = new NumeroALetras(); + const options = moneda ? { moneda } : undefined; + const letras = converter.Convertir(numero, options); + res.json({ numero, letras }); + } catch (e) { + res.status(400).json({ error: e.message }); + } +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-xml.cjs b/packages/test-cjs/routes/cfdi-xml.cjs index b509b7f..29d954b 100644 --- a/packages/test-cjs/routes/cfdi-xml.cjs +++ b/packages/test-cjs/routes/cfdi-xml.cjs @@ -1,9 +1,106 @@ -module.exports = { - path: '/@cfdi/xml', - name: '@cfdi/xml', - test() { - const pkg = require('@cfdi/xml'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const path = require('node:path'); +const { Router } = require('express'); +const { CFDI, Emisor, Receptor, Concepto, Impuestos } = require('@cfdi/xml'); +const { FormaPago, MetodoPago, TipoComprobante } = require('@cfdi/catalogos'); +const { FILES_DIR } = require('../config.cjs'); + +const CERT_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.cer'); +const KEY_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.key'); +const PASSWORD = '12345678a'; + +const router = Router(); + +function buildCFDI(body) { + const cfdi = new CFDI(); + + cfdi.setAttributes({ + Serie: body.serie || 'A', + Folio: body.folio || '1', + Fecha: body.fecha || new Date().toISOString().slice(0, 19), + FormaPago: body.formaPago || FormaPago['01'], + MetodoPago: body.metodoPago || MetodoPago.PUE, + TipoDeComprobante: body.tipoComprobante || TipoComprobante.I, + LugarExpedicion: body.lugarExpedicion || '06600', + Moneda: body.moneda || 'MXN', + SubTotal: body.subTotal || '1000.00', + Total: body.total || '1160.00', + }); + + const emisor = new Emisor(); + emisor.setAttributes({ + Rfc: body.emisorRfc || 'LAN7008173R5', + Nombre: body.emisorNombre || 'EMPRESA DE PRUEBA SA DE CV', + RegimenFiscal: body.emisorRegimen || '601', + }); + cfdi.comprobante(emisor); + + const receptor = new Receptor(); + receptor.setAttributes({ + Rfc: body.receptorRfc || 'XAXX010101000', + Nombre: body.receptorNombre || 'PUBLICO EN GENERAL', + UsoCFDI: body.receptorUsoCfdi || 'G03', + DomicilioFiscalReceptor: body.receptorDomicilio || '06600', + RegimenFiscalReceptor: body.receptorRegimen || '616', + }); + cfdi.comprobante(receptor); + + const conceptos = body.conceptos || [ + { + ClaveProdServ: '01010101', + Cantidad: '1', + ClaveUnidad: 'ACT', + Descripcion: 'Producto de prueba', + ValorUnitario: '1000.00', + Importe: '1000.00', + ObjetoImp: '02', + }, + ]; + + for (const c of conceptos) { + const concepto = new Concepto(); + concepto.setAttributes(c); + cfdi.comprobante(concepto); + } + + const impuestos = new Impuestos(); + impuestos.setAttributes({ + TotalImpuestosTrasladados: body.totalImpuestos || '160.00', + }); + impuestos.traslado({ + Base: body.subTotal || '1000.00', + Impuesto: '002', + TipoFactor: 'Tasa', + TasaOCuota: '0.160000', + Importe: body.totalImpuestos || '160.00', + }); + cfdi.comprobante(impuestos); + + cfdi.certificar(CERT_PATH); + cfdi.sellar(KEY_PATH, PASSWORD); + + return cfdi; +} + +router.post('/create', (req, res) => { + try { + const cfdi = buildCFDI(req.body || {}); + res.json({ + xml: cfdi.xml(), + json: cfdi.json(), + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.post('/create-xml', (req, res) => { + try { + const cfdi = buildCFDI(req.body || {}); + res.set('Content-Type', 'application/xml'); + res.send(cfdi.xml()); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/cfdi-xsd.cjs b/packages/test-cjs/routes/cfdi-xsd.cjs index c968831..c79b164 100644 --- a/packages/test-cjs/routes/cfdi-xsd.cjs +++ b/packages/test-cjs/routes/cfdi-xsd.cjs @@ -1,9 +1,22 @@ -module.exports = { - path: '/@cfdi/xsd', - name: '@cfdi/xsd', - test() { - const pkg = require('@cfdi/xsd'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +const { Router } = require('express'); +const xsd = require('@cfdi/xsd'); + +const router = Router(); + +router.get('/schema', (req, res) => { + try { + const Schema = xsd.Schema || xsd.default; + const schema = Schema.of(); + const result = { + type: typeof schema, + }; + if (schema.cfdi) { + result.cfdiValidators = Object.keys(schema.cfdi); + } + res.json(result); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +module.exports = router; diff --git a/packages/test-cjs/routes/clir-openssl.cjs b/packages/test-cjs/routes/clir-openssl.cjs deleted file mode 100644 index c45a399..0000000 --- a/packages/test-cjs/routes/clir-openssl.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - path: '/@clir/openssl', - name: '@clir/openssl', - test() { - const pkg = require('@clir/openssl'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; diff --git a/packages/test-cjs/routes/saxon-he-cli.cjs b/packages/test-cjs/routes/saxon-he-cli.cjs deleted file mode 100644 index 17f9a27..0000000 --- a/packages/test-cjs/routes/saxon-he-cli.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - path: '/@saxon-he/cli', - name: '@saxon-he/cli', - test() { - const pkg = require('@saxon-he/cli'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; diff --git a/packages/test-cjs/server.cjs b/packages/test-cjs/server.cjs index c332b4d..7981499 100644 --- a/packages/test-cjs/server.cjs +++ b/packages/test-cjs/server.cjs @@ -1,88 +1,60 @@ -const http = require('node:http'); -const fs = require('node:fs'); -const path = require('node:path'); - -const PORT = process.env.PORT || 3001; -const routesDir = path.join(__dirname, 'routes'); - -function loadRoutes() { - const routes = {}; - const files = fs.readdirSync(routesDir).filter(f => f.endsWith('.cjs')); - - for (const file of files) { - const route = require(path.join(routesDir, file)); - routes[route.path] = route; - } - - return routes; -} - -function json(res, data, status = 200) { - res.writeHead(status, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify(data, null, 2)); -} - -const routes = loadRoutes(); - -const server = http.createServer(async (req, res) => { - const url = new URL(req.url, `http://localhost:${PORT}`); - const pathname = url.pathname; - - if (pathname === '/') { - const available = Object.values(routes).map(r => ({ - name: r.name, - path: r.path, - })); - return json(res, { - type: 'cjs', - routes: available, - endpoints: { - '/': 'Lista de rutas', - '/all': 'Ejecutar todas las rutas', - '/@scope/pkg': 'Ruta individual', - }, - }); - } - - if (pathname === '/all') { - const results = []; - let ok = 0; - let failed = 0; - - for (const route of Object.values(routes)) { - try { - const result = await route.test(); - results.push({ name: route.name, status: 'ok', ...result }); - ok++; - } catch (err) { - results.push({ name: route.name, status: 'error', message: err.message }); - failed++; - } - } - - return json(res, { - type: 'cjs', - timestamp: new Date().toISOString(), - summary: { total: results.length, ok, failed }, - results, - }); - } - - const route = routes[pathname]; - if (route) { - try { - const result = await route.test(); - return json(res, { name: route.name, status: 'ok', ...result }); - } catch (err) { - return json(res, { name: route.name, status: 'error', message: err.message }, 500); - } - } - - json(res, { error: 'Not found', available: Object.keys(routes) }, 404); +const express = require('express'); +const { PORT } = require('./config.cjs'); + +const catalogosRouter = require('./routes/cfdi-catalogos.cjs'); +const rfcRouter = require('./routes/cfdi-rfc.cjs'); +const utilsRouter = require('./routes/cfdi-utils.cjs'); +const xmlRouter = require('./routes/cfdi-xml.cjs'); +const jsonRouter = require('./routes/cfdi-2json.cjs'); +const csdRouter = require('./routes/cfdi-csd.cjs'); +const complementosRouter = require('./routes/cfdi-complementos.cjs'); +const elementsRouter = require('./routes/cfdi-elements.cjs'); +const xsdRouter = require('./routes/cfdi-xsd.cjs'); +const transformRouter = require('./routes/cfdi-transform.cjs'); +const csfRouter = require('./routes/cfdi-csf.cjs'); + +const app = express(); +app.use(express.json()); + +app.get('/', (req, res) => { + res.json({ + type: 'cjs', + endpoints: { + '/catalogos': 'Catalogos del SAT (FormaPago, MetodoPago, etc.)', + '/rfc/validate/:rfc': 'Validar RFC', + '/rfc/faker': 'Generar RFC de prueba', + '/utils/numero-a-letras': 'POST { numero, moneda? }', + '/xml/create': 'POST crear CFDI XML (json + xml)', + '/xml/create-xml': 'POST crear CFDI XML (solo xml)', + '/json/parse': 'POST { xml } convertir XML a JSON', + '/json/samples': 'GET listar XMLs de ejemplo', + '/json/sample/:filename': 'GET parsear XML de ejemplo', + '/csd/info': 'GET info del certificado de prueba', + '/csd/pem': 'GET certificado en PEM', + '/csd/sign': 'POST { data } firmar con llave privada', + '/csd/verify': 'POST verificar llave pertenece al certificado', + '/complementos': 'GET listar complementos disponibles', + '/complementos/pago20': 'POST crear complemento de pago', + '/elements/constants': 'GET constantes de elementos CFDI', + '/xsd/schema': 'GET info del schema XSD', + '/transform/normalize': 'POST { text } normalizar espacios', + '/csf/parse': 'POST { path } parsear constancia fiscal', + }, + }); }); -server.listen(PORT, () => { +app.use('/catalogos', catalogosRouter); +app.use('/rfc', rfcRouter); +app.use('/utils', utilsRouter); +app.use('/xml', xmlRouter); +app.use('/json', jsonRouter); +app.use('/csd', csdRouter); +app.use('/complementos', complementosRouter); +app.use('/elements', elementsRouter); +app.use('/xsd', xsdRouter); +app.use('/transform', transformRouter); +app.use('/csf', csfRouter); + +app.listen(PORT, () => { console.log(`[CJS] Server running on http://localhost:${PORT}`); - console.log(`Routes loaded: ${Object.keys(routes).length}`); - Object.keys(routes).forEach(r => console.log(` ${r}`)); }); diff --git a/packages/test-esm/config.mjs b/packages/test-esm/config.mjs new file mode 100644 index 0000000..af5e4d7 --- /dev/null +++ b/packages/test-esm/config.mjs @@ -0,0 +1,7 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export const FILES_DIR = path.resolve(__dirname, '../files'); +export const PORT = process.env.PORT || 3002; diff --git a/packages/test-esm/package.json b/packages/test-esm/package.json index c07c12c..7763bb8 100644 --- a/packages/test-esm/package.json +++ b/packages/test-esm/package.json @@ -4,24 +4,25 @@ "private": true, "type": "module", "scripts": { - "start": "node server.mjs", + "dev": "node server.mjs", "update-versions": "node update-versions.mjs" }, "dependencies": { - "@cfdi/xml": "4.0.17", - "@cfdi/complementos": "4.0.16", - "@cfdi/xsd": "4.0.16", - "@cfdi/csd": "4.0.15", - "@cfdi/csf": "4.0.15", - "@cfdi/catalogos": "4.0.15", - "@cfdi/utils": "4.0.16", + "express": "^4.21.0", + "@cfdi/xml": "4.0.18-dev.3", + "@cfdi/complementos": "4.0.17-dev.3", + "@cfdi/xsd": "4.0.17-dev.3", + "@cfdi/csd": "4.0.16-dev.3", + "@cfdi/csf": "4.0.16-dev.3", + "@cfdi/catalogos": "4.0.16-dev.3", + "@cfdi/utils": "4.0.17-dev.2", "@cfdi/rfc": "0.0.10", - "@cfdi/types": "4.0.13", - "@cfdi/transform": "4.0.13", - "@cfdi/2json": "4.0.13", - "@cfdi/expresiones": "4.0.13", - "@cfdi/elements": "4.0.13", - "@clir/openssl": "0.0.16", - "@saxon-he/cli": "12.5.1" + "@clir/openssl": "0.0.17-dev.2", + "@saxon-he/cli": "12.5.2-dev.2", + "@cfdi/types": "4.0.14-dev.2", + "@cfdi/transform": "4.0.14-dev.2", + "@cfdi/2json": "4.0.14-dev.2", + "@cfdi/expresiones": "4.0.14-dev.2", + "@cfdi/elements": "4.0.14-dev.2" } } diff --git a/packages/test-esm/routes/cfdi-2json.mjs b/packages/test-esm/routes/cfdi-2json.mjs index 6b7edb8..4557407 100644 --- a/packages/test-esm/routes/cfdi-2json.mjs +++ b/packages/test-esm/routes/cfdi-2json.mjs @@ -1,9 +1,42 @@ -export default { - path: '/@cfdi/2json', - name: '@cfdi/2json', - async test() { - const pkg = await import('@cfdi/2json'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import fs from 'node:fs'; +import path from 'node:path'; +import { XmlToJson } from '@cfdi/2json'; +import { FILES_DIR } from '../config.mjs'; + +const router = Router(); + +router.post('/parse', (req, res) => { + try { + const { xml } = req.body; + if (!xml) { + return res.status(400).json({ error: 'xml is required' }); + } + const result = XmlToJson(xml); + res.json(result); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.get('/samples', (_req, res) => { + try { + const xmlDir = path.join(FILES_DIR, 'xml'); + const files = fs.readdirSync(xmlDir).filter(f => f.endsWith('.xml')); + res.json({ files }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.get('/sample/:filename', (req, res) => { + try { + const filePath = path.join(FILES_DIR, 'xml', req.params.filename); + const result = XmlToJson(filePath); + res.json(result); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-catalogos.mjs b/packages/test-esm/routes/cfdi-catalogos.mjs index 8a71cff..9a96f8f 100644 --- a/packages/test-esm/routes/cfdi-catalogos.mjs +++ b/packages/test-esm/routes/cfdi-catalogos.mjs @@ -1,9 +1,42 @@ -export default { - path: '/@cfdi/catalogos', - name: '@cfdi/catalogos', - async test() { - const pkg = await import('@cfdi/catalogos'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import { + FormaPago, + MetodoPago, + RegimenFiscal, + TipoComprobante, + UsoCFDI, +} from '@cfdi/catalogos'; + +const router = Router(); + +router.get('/', (_req, res) => { + res.json({ + FormaPago, + MetodoPago, + RegimenFiscal, + TipoComprobante, + UsoCFDI, + }); +}); + +router.get('/forma-pago', (_req, res) => { + res.json(FormaPago); +}); + +router.get('/metodo-pago', (_req, res) => { + res.json(MetodoPago); +}); + +router.get('/regimen-fiscal', (_req, res) => { + res.json(RegimenFiscal); +}); + +router.get('/tipo-comprobante', (_req, res) => { + res.json(TipoComprobante); +}); + +router.get('/uso-cfdi', (_req, res) => { + res.json(UsoCFDI); +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-complementos.mjs b/packages/test-esm/routes/cfdi-complementos.mjs index 9eb874b..641a6c3 100644 --- a/packages/test-esm/routes/cfdi-complementos.mjs +++ b/packages/test-esm/routes/cfdi-complementos.mjs @@ -1,9 +1,50 @@ -export default { - path: '/@cfdi/complementos', - name: '@cfdi/complementos', - async test() { - const pkg = await import('@cfdi/complementos'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import * as complementos from '@cfdi/complementos'; + +const router = Router(); + +router.get('/', (_req, res) => { + res.json({ + available: Object.keys(complementos), + }); +}); + +router.post('/pago20', (req, res) => { + try { + const body = req.body || {}; + const pagos = new complementos.Pagos20(); + const pago = new complementos.Pago20(); + + pago.setAttributes({ + FechaPago: + body.fechaPago || new Date().toISOString().slice(0, 19), + FormaDePagoP: body.formaPago || '01', + MonedaP: body.moneda || 'MXN', + Monto: body.monto || '1000.00', + }); + + if (body.relacionado) { + const relacionado = new complementos.Pago20Relacionado(); + relacionado.setAttributes({ + IdDocumento: body.relacionado.idDocumento, + MonedaDR: body.relacionado.moneda || 'MXN', + NumParcialidad: body.relacionado.numParcialidad || '1', + ImpSaldoAnt: body.relacionado.impSaldoAnt || '1000.00', + ImpPagado: body.relacionado.impPagado || '1000.00', + ImpSaldoInsoluto: + body.relacionado.impSaldoInsoluto || '0.00', + }); + pago.addRelacionado(relacionado); + } + + pagos.addPago(pago); + + res.json({ + pagos: pagos.toJSON ? pagos.toJSON() : pagos, + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-csd.mjs b/packages/test-esm/routes/cfdi-csd.mjs index 490671b..ce1daff 100644 --- a/packages/test-esm/routes/cfdi-csd.mjs +++ b/packages/test-esm/routes/cfdi-csd.mjs @@ -1,9 +1,65 @@ -export default { - path: '/@cfdi/csd', - name: '@cfdi/csd', - async test() { - const pkg = await import('@cfdi/csd'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import path from 'node:path'; +import { Certificate, PrivateKey } from '@cfdi/csd'; +import { FILES_DIR } from '../config.mjs'; + +const router = Router(); + +const CERT_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.cer'); +const KEY_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.key'); +const KEY_PASSWORD = '12345678a'; + +router.get('/info', (_req, res) => { + try { + const cert = Certificate.fromFile(CERT_PATH); + res.json({ + rfc: cert.rfc(), + noCertificado: cert.noCertificado(), + serialNumber: cert.serialNumber(), + legalName: cert.legalName(), + isExpired: cert.isExpired(), + expiresAt: cert.expiresAt(), + isCsd: cert.isCsd(), + isFiel: cert.isFiel(), + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.get('/pem', (_req, res) => { + try { + const cert = Certificate.fromFile(CERT_PATH); + res.set('Content-Type', 'text/plain'); + res.send(cert.toPem()); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.post('/sign', (req, res) => { + try { + const { data } = req.body; + if (!data) { + return res.status(400).json({ error: 'data is required' }); + } + const key = PrivateKey.fromFile(KEY_PATH, KEY_PASSWORD); + const signature = key.sign(data); + res.json({ data, signature }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.post('/verify', (_req, res) => { + try { + const cert = Certificate.fromFile(CERT_PATH); + const key = PrivateKey.fromFile(KEY_PATH, KEY_PASSWORD); + const belongs = key.belongsToCertificate(cert); + res.json({ belongs }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-csf.mjs b/packages/test-esm/routes/cfdi-csf.mjs index 44b1bcc..9a435fa 100644 --- a/packages/test-esm/routes/cfdi-csf.mjs +++ b/packages/test-esm/routes/cfdi-csf.mjs @@ -1,9 +1,20 @@ -export default { - path: '/@cfdi/csf', - name: '@cfdi/csf', - async test() { - const pkg = await import('@cfdi/csf'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import * as csfPkg from '@cfdi/csf'; + +const router = Router(); + +router.post('/parse', (req, res) => { + try { + const { path } = req.body; + if (!path) { + return res.status(400).json({ error: 'path is required' }); + } + const csf = csfPkg.default || csfPkg.csf || csfPkg; + const result = typeof csf === 'function' ? csf(path) : csf; + res.json(result); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-elements.mjs b/packages/test-esm/routes/cfdi-elements.mjs index 47a2b5b..4883914 100644 --- a/packages/test-esm/routes/cfdi-elements.mjs +++ b/packages/test-esm/routes/cfdi-elements.mjs @@ -1,9 +1,38 @@ -export default { - path: '/@cfdi/elements', - name: '@cfdi/elements', - async test() { - const pkg = await import('@cfdi/elements'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import * as elements from '@cfdi/elements'; + +const router = Router(); + +router.get('/constants', (_req, res) => { + const constants = {}; + const knownConstants = [ + 'COMPROBANTE', + 'EMISOR', + 'RECEPTOR', + 'CONCEPTO', + 'CONCEPTOS', + 'IMPUESTOS', + 'TRASLADO', + 'TRASLADOS', + 'RETENCION', + 'RETENCIONES', + 'COMPLEMENTO', + 'ADDENDA', + ]; + + for (const key of knownConstants) { + if (elements[key] !== undefined) { + constants[key] = elements[key]; + } + } + + res.json(constants); +}); + +router.get('/', (_req, res) => { + res.json({ + exports: Object.keys(elements), + }); +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-expresiones.mjs b/packages/test-esm/routes/cfdi-expresiones.mjs deleted file mode 100644 index 3544b0f..0000000 --- a/packages/test-esm/routes/cfdi-expresiones.mjs +++ /dev/null @@ -1,9 +0,0 @@ -export default { - path: '/@cfdi/expresiones', - name: '@cfdi/expresiones', - async test() { - const pkg = await import('@cfdi/expresiones'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; diff --git a/packages/test-esm/routes/cfdi-rfc.mjs b/packages/test-esm/routes/cfdi-rfc.mjs index 87cf5bf..3e328ca 100644 --- a/packages/test-esm/routes/cfdi-rfc.mjs +++ b/packages/test-esm/routes/cfdi-rfc.mjs @@ -1,9 +1,37 @@ -export default { - path: '/@cfdi/rfc', - name: '@cfdi/rfc', - async test() { - const pkg = await import('@cfdi/rfc'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import { rfc, Rfc, RfcFaker } from '@cfdi/rfc'; + +const router = Router(); + +router.get('/validate/:rfc', (req, res) => { + try { + const input = req.params.rfc; + const validation = rfc.validate(input); + const rfcInstance = Rfc.of(input); + + res.json({ + rfc: input, + validation, + isFisica: rfcInstance.isFisica(), + isMoral: rfcInstance.isMoral(), + isGeneric: rfcInstance.isGeneric(), + isForeign: rfcInstance.isForeign(), + date: rfcInstance.date(), + }); + } catch (e) { + res.status(400).json({ error: e.message }); + } +}); + +router.get('/faker', (_req, res) => { + try { + res.json({ + persona: RfcFaker.persona(), + moral: RfcFaker.moral(), + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-transform.mjs b/packages/test-esm/routes/cfdi-transform.mjs index 5c6c218..50a851f 100644 --- a/packages/test-esm/routes/cfdi-transform.mjs +++ b/packages/test-esm/routes/cfdi-transform.mjs @@ -1,9 +1,25 @@ -export default { - path: '/@cfdi/transform', - name: '@cfdi/transform', - async test() { - const pkg = await import('@cfdi/transform'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import * as transform from '@cfdi/transform'; + +const router = Router(); + +router.post('/normalize', (req, res) => { + try { + const { text } = req.body; + if (!text) { + return res.status(400).json({ error: 'text is required' }); + } + const normalized = transform.normalizeSpace(text); + res.json({ original: text, normalized }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.get('/', (_req, res) => { + res.json({ + exports: Object.keys(transform), + }); +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-types.mjs b/packages/test-esm/routes/cfdi-types.mjs deleted file mode 100644 index 293a3ea..0000000 --- a/packages/test-esm/routes/cfdi-types.mjs +++ /dev/null @@ -1,9 +0,0 @@ -export default { - path: '/@cfdi/types', - name: '@cfdi/types', - async test() { - const pkg = await import('@cfdi/types'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; diff --git a/packages/test-esm/routes/cfdi-utils.mjs b/packages/test-esm/routes/cfdi-utils.mjs index 27207de..b7db3c1 100644 --- a/packages/test-esm/routes/cfdi-utils.mjs +++ b/packages/test-esm/routes/cfdi-utils.mjs @@ -1,9 +1,19 @@ -export default { - path: '/@cfdi/utils', - name: '@cfdi/utils', - async test() { - const pkg = await import('@cfdi/utils'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import { NumeroALetras } from '@cfdi/utils'; + +const router = Router(); + +router.post('/numero-a-letras', (req, res) => { + try { + const { numero, moneda } = req.body; + const converter = new NumeroALetras(); + const options = moneda ? { moneda } : undefined; + const letras = converter.NumeroALetras(numero, options); + + res.json({ numero, letras }); + } catch (e) { + res.status(400).json({ error: e.message }); + } +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-xml.mjs b/packages/test-esm/routes/cfdi-xml.mjs index 1bab2c9..6b3c85b 100644 --- a/packages/test-esm/routes/cfdi-xml.mjs +++ b/packages/test-esm/routes/cfdi-xml.mjs @@ -1,9 +1,117 @@ -export default { - path: '/@cfdi/xml', - name: '@cfdi/xml', - async test() { - const pkg = await import('@cfdi/xml'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import path from 'node:path'; +import { + CFDI, + Emisor, + Receptor, + Concepto, + Impuestos, +} from '@cfdi/xml'; +import { + FormaPago, + MetodoPago, + TipoComprobante, +} from '@cfdi/catalogos'; +import { FILES_DIR } from '../config.mjs'; + +const router = Router(); + +const CERT_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.cer'); +const KEY_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.key'); +const KEY_PASSWORD = '12345678a'; + +function buildCFDI(body) { + const cfdi = new CFDI(); + + cfdi.setAttributes({ + Serie: body.serie || 'A', + Folio: body.folio || '1', + Fecha: body.fecha || new Date().toISOString().slice(0, 19), + FormaPago: body.formaPago || FormaPago['01'], + MetodoPago: body.metodoPago || MetodoPago.PUE, + TipoDeComprobante: body.tipoComprobante || TipoComprobante.I, + LugarExpedicion: body.lugarExpedicion || '06600', + Moneda: body.moneda || 'MXN', + SubTotal: body.subTotal || '1000.00', + Total: body.total || '1160.00', + }); + + const emisor = new Emisor(); + emisor.setAttributes({ + Rfc: body.emisorRfc || 'LAN7008173R5', + Nombre: body.emisorNombre || 'EMPRESA DE PRUEBA SA DE CV', + RegimenFiscal: body.emisorRegimen || '601', + }); + cfdi.comprobante(emisor); + + const receptor = new Receptor(); + receptor.setAttributes({ + Rfc: body.receptorRfc || 'XAXX010101000', + Nombre: body.receptorNombre || 'PUBLICO EN GENERAL', + UsoCFDI: body.receptorUsoCfdi || 'G01', + DomicilioFiscalReceptor: + body.receptorDomicilio || '06600', + RegimenFiscalReceptor: body.receptorRegimen || '616', + }); + cfdi.comprobante(receptor); + + const conceptos = body.conceptos || [ + { + ClaveProdServ: '01010101', + Cantidad: '1', + ClaveUnidad: 'ACT', + Descripcion: 'Producto de prueba', + ValorUnitario: '1000.00', + Importe: '1000.00', + ObjetoImp: '02', + }, + ]; + + for (const c of conceptos) { + const concepto = new Concepto(); + concepto.setAttributes(c); + cfdi.comprobante(concepto); + } + + const impuestos = new Impuestos(); + impuestos.setAttributes({ + TotalImpuestosTrasladados: body.totalImpuestos || '160.00', + }); + impuestos.traslado({ + Base: body.subTotal || '1000.00', + Impuesto: '002', + TipoFactor: 'Tasa', + TasaOCuota: '0.160000', + Importe: body.totalImpuestos || '160.00', + }); + cfdi.comprobante(impuestos); + + cfdi.certificar(CERT_PATH); + cfdi.sellar(KEY_PATH, KEY_PASSWORD); + + return cfdi; +} + +router.post('/create', (req, res) => { + try { + const cfdi = buildCFDI(req.body || {}); + res.json({ + xml: cfdi.xml(), + json: cfdi.json(), + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +router.post('/create-xml', (req, res) => { + try { + const cfdi = buildCFDI(req.body || {}); + res.set('Content-Type', 'application/xml'); + res.send(cfdi.xml()); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +export default router; diff --git a/packages/test-esm/routes/cfdi-xsd.mjs b/packages/test-esm/routes/cfdi-xsd.mjs index 33fd30b..ba4bee3 100644 --- a/packages/test-esm/routes/cfdi-xsd.mjs +++ b/packages/test-esm/routes/cfdi-xsd.mjs @@ -1,9 +1,21 @@ -export default { - path: '/@cfdi/xsd', - name: '@cfdi/xsd', - async test() { - const pkg = await import('@cfdi/xsd'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; +import { Router } from 'express'; +import * as xsd from '@cfdi/xsd'; + +const router = Router(); + +router.get('/schema', (_req, res) => { + try { + const schema = xsd.Schema.of(); + res.json({ + type: typeof schema, + schema: schema, + validators: schema.cfdi + ? Object.keys(schema.cfdi) + : Object.keys(schema), + }); + } catch (e) { + res.status(500).json({ error: e.message }); + } +}); + +export default router; diff --git a/packages/test-esm/routes/clir-openssl.mjs b/packages/test-esm/routes/clir-openssl.mjs deleted file mode 100644 index 61dddfd..0000000 --- a/packages/test-esm/routes/clir-openssl.mjs +++ /dev/null @@ -1,9 +0,0 @@ -export default { - path: '/@clir/openssl', - name: '@clir/openssl', - async test() { - const pkg = await import('@clir/openssl'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; diff --git a/packages/test-esm/routes/saxon-he-cli.mjs b/packages/test-esm/routes/saxon-he-cli.mjs deleted file mode 100644 index 8708375..0000000 --- a/packages/test-esm/routes/saxon-he-cli.mjs +++ /dev/null @@ -1,9 +0,0 @@ -export default { - path: '/@saxon-he/cli', - name: '@saxon-he/cli', - async test() { - const pkg = await import('@saxon-he/cli'); - const exports = Object.keys(pkg); - return { exports }; - }, -}; diff --git a/packages/test-esm/server.mjs b/packages/test-esm/server.mjs index 78310c0..43239db 100644 --- a/packages/test-esm/server.mjs +++ b/packages/test-esm/server.mjs @@ -1,91 +1,60 @@ -import http from 'node:http'; -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const PORT = process.env.PORT || 3002; -const routesDir = path.join(__dirname, 'routes'); - -async function loadRoutes() { - const routes = {}; - const files = fs.readdirSync(routesDir).filter(f => f.endsWith('.mjs')); - - for (const file of files) { - const mod = await import(path.join(routesDir, file)); - const route = mod.default; - routes[route.path] = route; - } - - return routes; -} - -function json(res, data, status = 200) { - res.writeHead(status, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify(data, null, 2)); -} - -const routes = await loadRoutes(); - -const server = http.createServer(async (req, res) => { - const url = new URL(req.url, `http://localhost:${PORT}`); - const pathname = url.pathname; - - if (pathname === '/') { - const available = Object.values(routes).map(r => ({ - name: r.name, - path: r.path, - })); - return json(res, { - type: 'esm', - routes: available, - endpoints: { - '/': 'Lista de rutas', - '/all': 'Ejecutar todas las rutas', - '/@scope/pkg': 'Ruta individual', - }, - }); - } - - if (pathname === '/all') { - const results = []; - let ok = 0; - let failed = 0; - - for (const route of Object.values(routes)) { - try { - const result = await route.test(); - results.push({ name: route.name, status: 'ok', ...result }); - ok++; - } catch (err) { - results.push({ name: route.name, status: 'error', message: err.message }); - failed++; - } - } - - return json(res, { - type: 'esm', - timestamp: new Date().toISOString(), - summary: { total: results.length, ok, failed }, - results, - }); - } - - const route = routes[pathname]; - if (route) { - try { - const result = await route.test(); - return json(res, { name: route.name, status: 'ok', ...result }); - } catch (err) { - return json(res, { name: route.name, status: 'error', message: err.message }, 500); - } - } - - json(res, { error: 'Not found', available: Object.keys(routes) }, 404); +import express from 'express'; +import { PORT } from './config.mjs'; + +import catalogosRouter from './routes/cfdi-catalogos.mjs'; +import rfcRouter from './routes/cfdi-rfc.mjs'; +import utilsRouter from './routes/cfdi-utils.mjs'; +import xmlRouter from './routes/cfdi-xml.mjs'; +import jsonRouter from './routes/cfdi-2json.mjs'; +import csdRouter from './routes/cfdi-csd.mjs'; +import complementosRouter from './routes/cfdi-complementos.mjs'; +import elementsRouter from './routes/cfdi-elements.mjs'; +import xsdRouter from './routes/cfdi-xsd.mjs'; +import transformRouter from './routes/cfdi-transform.mjs'; +import csfRouter from './routes/cfdi-csf.mjs'; + +const app = express(); +app.use(express.json()); + +app.get('/', (_req, res) => { + res.json({ + type: 'esm', + endpoints: { + '/catalogos': 'Catalogos del SAT (FormaPago, MetodoPago, etc.)', + '/rfc/validate/:rfc': 'Validar RFC', + '/rfc/faker': 'Generar RFC de prueba', + '/utils/numero-a-letras': 'POST { numero, moneda? }', + '/xml/create': 'POST crear CFDI XML (json + xml)', + '/xml/create-xml': 'POST crear CFDI XML (solo xml)', + '/json/parse': 'POST { xml } convertir XML a JSON', + '/json/samples': 'GET listar XMLs de ejemplo', + '/json/sample/:filename': 'GET parsear XML de ejemplo', + '/csd/info': 'GET info del certificado de prueba', + '/csd/pem': 'GET certificado en PEM', + '/csd/sign': 'POST { data } firmar con llave privada', + '/csd/verify': 'POST verificar llave pertenece al certificado', + '/complementos': 'GET listar complementos disponibles', + '/complementos/pago20': 'POST crear complemento de pago', + '/elements/constants': 'GET constantes de elementos CFDI', + '/xsd/schema': 'GET info del schema XSD', + '/transform/normalize': 'POST { text } normalizar espacios', + '/csf/parse': 'POST { path } parsear constancia fiscal', + }, + }); }); -server.listen(PORT, () => { +app.use('/catalogos', catalogosRouter); +app.use('/rfc', rfcRouter); +app.use('/utils', utilsRouter); +app.use('/xml', xmlRouter); +app.use('/json', jsonRouter); +app.use('/csd', csdRouter); +app.use('/complementos', complementosRouter); +app.use('/elements', elementsRouter); +app.use('/xsd', xsdRouter); +app.use('/transform', transformRouter); +app.use('/csf', csfRouter); + +app.listen(PORT, () => { console.log(`[ESM] Server running on http://localhost:${PORT}`); - console.log(`Routes loaded: ${Object.keys(routes).length}`); - Object.keys(routes).forEach(r => console.log(` ${r}`)); }); diff --git a/packages/test-ts/config.ts b/packages/test-ts/config.ts new file mode 100644 index 0000000..1a49c8d --- /dev/null +++ b/packages/test-ts/config.ts @@ -0,0 +1,7 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export const FILES_DIR = path.resolve(__dirname, '../files'); +export const PORT = process.env.PORT || 3003; diff --git a/packages/test-ts/package.json b/packages/test-ts/package.json new file mode 100644 index 0000000..ee32ca1 --- /dev/null +++ b/packages/test-ts/package.json @@ -0,0 +1,33 @@ +{ + "name": "test-ts", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "tsx server.ts", + "dev": "tsx watch server.ts", + "update-versions": "node update-versions.mjs" + }, + "dependencies": { + "@cfdi/xml": "4.0.18-dev.3", + "@cfdi/complementos": "4.0.17-dev.3", + "@cfdi/xsd": "4.0.17-dev.3", + "@cfdi/csd": "4.0.16-dev.3", + "@cfdi/csf": "4.0.16-dev.3", + "@cfdi/catalogos": "4.0.16-dev.3", + "@cfdi/utils": "4.0.17-dev.2", + "@cfdi/rfc": "0.0.10", + "@clir/openssl": "0.0.17-dev.2", + "@saxon-he/cli": "12.5.2-dev.2", + "@cfdi/types": "4.0.14-dev.2", + "@cfdi/transform": "4.0.14-dev.2", + "@cfdi/2json": "4.0.14-dev.2", + "@cfdi/expresiones": "4.0.14-dev.2", + "@cfdi/elements": "4.0.14-dev.2", + "express": "^4.21.0" + }, + "devDependencies": { + "@types/express": "^4.17.21", + "tsx": "^4.19.0", + "typescript": "^5.5.0" + } +} diff --git a/packages/test-ts/routes/cfdi-2json.ts b/packages/test-ts/routes/cfdi-2json.ts new file mode 100644 index 0000000..e6fbf1d --- /dev/null +++ b/packages/test-ts/routes/cfdi-2json.ts @@ -0,0 +1,44 @@ +import { Router } from 'express'; +import path from 'node:path'; +import { XmlToJson } from '@cfdi/2json'; +import { FILES_DIR } from '../config'; + +const router = Router(); + +router.post('/parse', (req, res) => { + try { + const { xml } = req.body as { xml: string }; + + if (!xml) { + return res.status(400).json({ error: 'Se requiere "xml" en el body (string XML)' }); + } + + const result = XmlToJson(xml); + res.json(result); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +router.get('/sample/:filename', (req, res) => { + try { + const filePath = path.join(FILES_DIR, 'xml', req.params.filename); + const result = XmlToJson(filePath); + res.json(result); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +router.get('/samples', (_req, res) => { + const fs = require('node:fs'); + const xmlDir = path.join(FILES_DIR, 'xml'); + try { + const files = fs.readdirSync(xmlDir).filter((f: string) => f.endsWith('.xml')); + res.json({ files }); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-catalogos.ts b/packages/test-ts/routes/cfdi-catalogos.ts new file mode 100644 index 0000000..c53253a --- /dev/null +++ b/packages/test-ts/routes/cfdi-catalogos.ts @@ -0,0 +1,42 @@ +import { Router } from 'express'; +import { + FormaPago, + MetodoPago, + RegimenFiscal, + TipoComprobante, + UsoCFDI, +} from '@cfdi/catalogos'; + +const router = Router(); + +router.get('/', (_req, res) => { + res.json({ + formaPago: FormaPago, + metodoPago: MetodoPago, + regimenFiscal: RegimenFiscal, + tipoComprobante: TipoComprobante, + usoCFDI: UsoCFDI, + }); +}); + +router.get('/forma-pago', (_req, res) => { + res.json(FormaPago); +}); + +router.get('/metodo-pago', (_req, res) => { + res.json(MetodoPago); +}); + +router.get('/regimen-fiscal', (_req, res) => { + res.json(RegimenFiscal); +}); + +router.get('/tipo-comprobante', (_req, res) => { + res.json(TipoComprobante); +}); + +router.get('/uso-cfdi', (_req, res) => { + res.json(UsoCFDI); +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-complementos.ts b/packages/test-ts/routes/cfdi-complementos.ts new file mode 100644 index 0000000..21e0e1f --- /dev/null +++ b/packages/test-ts/routes/cfdi-complementos.ts @@ -0,0 +1,72 @@ +import { Router } from 'express'; +import * as complementos from '@cfdi/complementos'; + +const router = Router(); + +router.get('/', (_req, res) => { + const available = Object.keys(complementos).filter(name => { + try { + return typeof (complementos as any)[name] === 'function' + && (complementos as any)[name].prototype; + } catch { + return false; + } + }); + + res.json({ available }); +}); + +router.post('/pago20', (req, res) => { + try { + const { + fechaPago, + formaPago = '03', + moneda = 'MXN', + monto, + doctoRelacionado, + } = req.body; + + const Pagos20 = (complementos as any).Pagos20; + const Pago20 = (complementos as any).Pago20; + const Pago20Relacionado = (complementos as any).Pago20Relacionado; + + if (!Pagos20 || !Pago20) { + return res.status(500).json({ error: 'Pago20/Pagos20 no disponible en @cfdi/complementos' }); + } + + const pagos = new Pagos20({ Version: '2.0' }); + + const pago = new Pago20({ + FechaPago: fechaPago || new Date().toISOString().slice(0, 19), + FormaDePagoP: formaPago, + MonedaP: moneda, + Monto: monto || '1000.00', + }); + + if (doctoRelacionado && Pago20Relacionado) { + pago.doctoRelacionado( + new Pago20Relacionado({ + IdDocumento: doctoRelacionado.uuid || '00000000-0000-0000-0000-000000000000', + MonedaDR: moneda, + NumParcialidad: doctoRelacionado.parcialidad || '1', + ImpSaldoAnt: doctoRelacionado.saldoAnt || monto || '1000.00', + ImpPagado: doctoRelacionado.pagado || monto || '1000.00', + ImpSaldoInsoluto: doctoRelacionado.saldoInsoluto || '0.00', + ObjetoImpDR: '02', + EquivalenciaDR: '1', + }) + ); + } + + pagos.setPago(pago); + + res.json({ + complemento: 'Pagos 2.0', + pagos, + }); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-csd.ts b/packages/test-ts/routes/cfdi-csd.ts new file mode 100644 index 0000000..731641c --- /dev/null +++ b/packages/test-ts/routes/cfdi-csd.ts @@ -0,0 +1,74 @@ +import { Router } from 'express'; +import path from 'node:path'; +import { Certificate, PrivateKey } from '@cfdi/csd'; +import { FILES_DIR } from '../config'; + +const router = Router(); + +const CERT_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.cer'); +const KEY_PATH = path.join(FILES_DIR, 'certificados/LAN7008173R5.key'); +const KEY_PASSWORD = '12345678a'; + +router.get('/info', async (_req, res) => { + try { + const cert = await Certificate.fromFile(CERT_PATH); + + res.json({ + rfc: cert.rfc(), + noCertificado: cert.noCertificado(), + serialNumber: cert.serialNumber(), + legalName: cert.legalName(), + isExpired: cert.isExpired(), + expiresAt: cert.expiresAt(), + isCsd: cert.isCsd(), + isFiel: cert.isFiel(), + }); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +router.get('/pem', async (_req, res) => { + try { + const cert = await Certificate.fromFile(CERT_PATH); + res.set('Content-Type', 'text/plain'); + res.send(cert.toPem()); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +router.post('/sign', async (req, res) => { + try { + const { data } = req.body as { data: string }; + + if (!data) { + return res.status(400).json({ error: 'Se requiere "data" en el body' }); + } + + const key = await PrivateKey.fromFile(KEY_PATH, KEY_PASSWORD); + const signature = key.sign(data); + + res.json({ data, signature }); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +router.post('/verify', async (req, res) => { + try { + const cert = await Certificate.fromFile(CERT_PATH); + const key = await PrivateKey.fromFile(KEY_PATH, KEY_PASSWORD); + + const belongs = key.belongsToCertificate(cert); + + res.json({ + certRfc: cert.rfc(), + keyBelongsToCert: belongs, + }); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-csf.ts b/packages/test-ts/routes/cfdi-csf.ts new file mode 100644 index 0000000..7d0321d --- /dev/null +++ b/packages/test-ts/routes/cfdi-csf.ts @@ -0,0 +1,26 @@ +import { Router } from 'express'; +import * as csfPkg from '@cfdi/csf'; + +const router = Router(); + +router.post('/parse', async (req, res) => { + try { + const { path: pdfPath } = req.body as { path: string }; + + if (!pdfPath) { + return res.status(400).json({ error: 'Se requiere "path" al PDF de la constancia' }); + } + + const csfFn = (csfPkg as any).csf || (csfPkg as any).default; + if (typeof csfFn !== 'function') { + return res.status(500).json({ error: 'csf() no disponible' }); + } + + const data = await csfFn(pdfPath); + res.json(data); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-elements.ts b/packages/test-ts/routes/cfdi-elements.ts new file mode 100644 index 0000000..fd82af6 --- /dev/null +++ b/packages/test-ts/routes/cfdi-elements.ts @@ -0,0 +1,26 @@ +import { Router } from 'express'; +import * as elements from '@cfdi/elements'; + +const router = Router(); + +router.get('/constants', (_req, res) => { + const constants = [ + 'COMPROBANTE', 'EMISOR', 'RECEPTOR', 'CONCEPTOS', + 'CONCEPTO', 'IMPUESTOS', 'TRASLADOS', 'TRASLADO', 'COMPLEMENTO', + ]; + + const result: Record = {}; + for (const name of constants) { + if ((elements as any)[name] !== undefined) { + result[name] = (elements as any)[name]; + } + } + + res.json(result); +}); + +router.get('/', (_req, res) => { + res.json({ exports: Object.keys(elements) }); +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-rfc.ts b/packages/test-ts/routes/cfdi-rfc.ts new file mode 100644 index 0000000..c31f04d --- /dev/null +++ b/packages/test-ts/routes/cfdi-rfc.ts @@ -0,0 +1,37 @@ +import { Router } from 'express'; +import { rfc, Rfc, RfcFaker } from '@cfdi/rfc'; + +const router = Router(); + +router.get('/validate/:rfc', (req, res) => { + const input = req.params.rfc; + + try { + const result = rfc.validate(input); + const rfcObj = Rfc.of(input); + + res.json({ + ...result, + isFisica: rfcObj.isFisica(), + isMoral: rfcObj.isMoral(), + isGeneric: rfcObj.isGeneric(), + isForeign: rfcObj.isForeign(), + date: rfcObj.obtainDate(), + }); + } catch (e) { + res.status(400).json({ + isValid: false, + rfc: input, + error: (e as Error).message, + }); + } +}); + +router.get('/faker', (_req, res) => { + res.json({ + personaFisica: RfcFaker.persona(), + personaMoral: RfcFaker.moral(), + }); +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-transform.ts b/packages/test-ts/routes/cfdi-transform.ts new file mode 100644 index 0000000..cb4c2bb --- /dev/null +++ b/packages/test-ts/routes/cfdi-transform.ts @@ -0,0 +1,28 @@ +import { Router } from 'express'; +import * as transform from '@cfdi/transform'; + +const router = Router(); + +router.post('/normalize', (req, res) => { + const { text } = req.body as { text: string }; + + if (!text) { + return res.status(400).json({ error: 'Se requiere "text" en el body' }); + } + + const normalizeSpace = (transform as any).normalizeSpace; + if (typeof normalizeSpace !== 'function') { + return res.status(500).json({ error: 'normalizeSpace no disponible' }); + } + + res.json({ + original: text, + normalized: normalizeSpace(text), + }); +}); + +router.get('/', (_req, res) => { + res.json({ exports: Object.keys(transform) }); +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-utils.ts b/packages/test-ts/routes/cfdi-utils.ts new file mode 100644 index 0000000..8018c8c --- /dev/null +++ b/packages/test-ts/routes/cfdi-utils.ts @@ -0,0 +1,28 @@ +import { Router } from 'express'; +import { NumeroALetras } from '@cfdi/utils'; + +const router = Router(); +const converter = new NumeroALetras(); + +router.post('/numero-a-letras', (req, res) => { + const { numero, moneda } = req.body as { + numero: number; + moneda?: { plural?: string; singular?: string; centPlural?: string; centSingular?: string }; + }; + + if (numero == null) { + return res.status(400).json({ error: 'Se requiere "numero" en el body' }); + } + + const options = moneda ?? { + plural: 'PESOS MEXICANOS', + singular: 'PESO MEXICANO', + centPlural: 'CENTAVOS', + centSingular: 'CENTAVO', + }; + + const letras = converter.NumeroALetras(numero, options); + res.json({ numero, letras }); +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-xml.ts b/packages/test-ts/routes/cfdi-xml.ts new file mode 100644 index 0000000..ef552a6 --- /dev/null +++ b/packages/test-ts/routes/cfdi-xml.ts @@ -0,0 +1,192 @@ +import { Router } from 'express'; +import path from 'node:path'; +import { CFDI, Emisor, Receptor, Concepto, Impuestos } from '@cfdi/xml'; +import { + FormaPago, + MetodoPago, + TipoComprobante, + UsoCFDI, + RegimenFiscal, +} from '@cfdi/catalogos'; +import { FILES_DIR } from '../config'; + +const router = Router(); + +router.post('/create', async (req, res) => { + try { + const { + serie = 'A', + folio = '1', + emisor: emisorData, + receptor: receptorData, + conceptos = [], + } = req.body; + + const cfdi = new CFDI(); + + cfdi.setAttributes(); + + const subtotal = conceptos.reduce( + (sum: number, c: any) => sum + Number(c.importe || 0), + 0 + ); + const iva = subtotal * 0.16; + const total = subtotal + iva; + + cfdi.comprobante({ + Serie: serie, + Folio: folio, + Fecha: new Date().toISOString().slice(0, 19), + SubTotal: subtotal.toFixed(2), + Moneda: 'MXN', + Total: total.toFixed(2), + TipoDeComprobante: TipoComprobante.INGRESO, + MetodoPago: MetodoPago.PUE, + LugarExpedicion: emisorData?.cp || '77728', + FormaPago: FormaPago['03'], + Exportacion: '01', + }); + + cfdi.emisor( + new Emisor({ + Rfc: emisorData?.rfc || 'LAN7008173R5', + Nombre: emisorData?.nombre || 'EMPRESA DE PRUEBA SA DE CV', + RegimenFiscal: emisorData?.regimen || '601', + }) + ); + + cfdi.receptor( + new Receptor({ + Rfc: receptorData?.rfc || 'XAXX010101000', + Nombre: receptorData?.nombre || 'PUBLICO EN GENERAL', + UsoCFDI: receptorData?.usoCfdi || 'G03', + DomicilioFiscalReceptor: receptorData?.cp || '77728', + RegimenFiscalReceptor: receptorData?.regimen || '616', + }) + ); + + for (const c of conceptos) { + cfdi.concepto( + new Concepto({ + ClaveProdServ: c.claveProdServ || '01010101', + Cantidad: c.cantidad || '1', + ClaveUnidad: c.claveUnidad || 'E48', + Unidad: c.unidad || 'Pieza', + Descripcion: c.descripcion || 'Producto de prueba', + ValorUnitario: c.valorUnitario || c.importe || '0', + Importe: c.importe || '0', + ObjetoImp: c.objetoImp || '02', + }) + ); + } + + cfdi.impuesto( + new Impuestos().traslados({ + Base: subtotal.toFixed(2), + Impuesto: '002', + TipoFactor: 'Tasa', + TasaOCuota: '0.160000', + Importe: iva.toFixed(2), + }) + ); + + const certPath = path.join(FILES_DIR, 'certificados/LAN7008173R5.cer'); + const keyPath = path.join(FILES_DIR, 'certificados/LAN7008173R5.key'); + + cfdi.certificar(certPath); + await cfdi.sellar(keyPath, '12345678a'); + + const xml = cfdi.getXmlCdfi(); + const json = cfdi.getJsonCdfi(); + + res.json({ xml, json }); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +router.post('/create-xml', async (req, res) => { + try { + const body = req.body; + + const cfdi = new CFDI(); + cfdi.setAttributes(); + + const subtotal = (body.conceptos || []).reduce( + (sum: number, c: any) => sum + Number(c.importe || 0), + 0 + ); + const iva = subtotal * 0.16; + const total = subtotal + iva; + + cfdi.comprobante({ + Serie: body.serie || 'A', + Folio: body.folio || '1', + Fecha: new Date().toISOString().slice(0, 19), + SubTotal: subtotal.toFixed(2), + Moneda: 'MXN', + Total: total.toFixed(2), + TipoDeComprobante: TipoComprobante.INGRESO, + MetodoPago: MetodoPago.PUE, + LugarExpedicion: body.lugarExpedicion || '77728', + FormaPago: body.formaPago || FormaPago['03'], + Exportacion: '01', + }); + + cfdi.emisor( + new Emisor({ + Rfc: body.emisor?.rfc || 'LAN7008173R5', + Nombre: body.emisor?.nombre || 'EMPRESA DE PRUEBA SA DE CV', + RegimenFiscal: body.emisor?.regimen || '601', + }) + ); + + cfdi.receptor( + new Receptor({ + Rfc: body.receptor?.rfc || 'XAXX010101000', + Nombre: body.receptor?.nombre || 'PUBLICO EN GENERAL', + UsoCFDI: body.receptor?.usoCfdi || 'G03', + DomicilioFiscalReceptor: body.receptor?.cp || '77728', + RegimenFiscalReceptor: body.receptor?.regimen || '616', + }) + ); + + for (const c of body.conceptos || []) { + cfdi.concepto( + new Concepto({ + ClaveProdServ: c.claveProdServ || '01010101', + Cantidad: c.cantidad || '1', + ClaveUnidad: c.claveUnidad || 'E48', + Unidad: c.unidad || 'Pieza', + Descripcion: c.descripcion || 'Producto', + ValorUnitario: c.valorUnitario || c.importe || '0', + Importe: c.importe || '0', + ObjetoImp: c.objetoImp || '02', + }) + ); + } + + cfdi.impuesto( + new Impuestos().traslados({ + Base: subtotal.toFixed(2), + Impuesto: '002', + TipoFactor: 'Tasa', + TasaOCuota: '0.160000', + Importe: iva.toFixed(2), + }) + ); + + const certPath = path.join(FILES_DIR, 'certificados/LAN7008173R5.cer'); + const keyPath = path.join(FILES_DIR, 'certificados/LAN7008173R5.key'); + + cfdi.certificar(certPath); + await cfdi.sellar(keyPath, '12345678a'); + + res.set('Content-Type', 'application/xml'); + res.send(cfdi.getXmlCdfi()); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +export default router; diff --git a/packages/test-ts/routes/cfdi-xsd.ts b/packages/test-ts/routes/cfdi-xsd.ts new file mode 100644 index 0000000..2378bd2 --- /dev/null +++ b/packages/test-ts/routes/cfdi-xsd.ts @@ -0,0 +1,29 @@ +import { Router } from 'express'; +import * as xsd from '@cfdi/xsd'; + +const router = Router(); + +router.get('/schema', (_req, res) => { + try { + const Schema = (xsd as any).Schema || (xsd as any).default; + + if (!Schema || typeof Schema.of !== 'function') { + return res.status(500).json({ error: 'Schema.of() no disponible' }); + } + + const schema = Schema.of(); + const info: Record = { + type: typeof schema, + }; + + if (schema.cfdi) { + info.cfdiValidators = Object.keys(schema.cfdi); + } + + res.json(info); + } catch (e) { + res.status(500).json({ error: (e as Error).message }); + } +}); + +export default router; diff --git a/packages/test-ts/server.ts b/packages/test-ts/server.ts new file mode 100644 index 0000000..e4eee4a --- /dev/null +++ b/packages/test-ts/server.ts @@ -0,0 +1,61 @@ +import express from 'express'; +import { PORT } from './config'; + +import catalogosRouter from './routes/cfdi-catalogos'; +import rfcRouter from './routes/cfdi-rfc'; +import utilsRouter from './routes/cfdi-utils'; +import xmlRouter from './routes/cfdi-xml'; +import jsonRouter from './routes/cfdi-2json'; +import csdRouter from './routes/cfdi-csd'; +import complementosRouter from './routes/cfdi-complementos'; +import elementsRouter from './routes/cfdi-elements'; +import xsdRouter from './routes/cfdi-xsd'; +import transformRouter from './routes/cfdi-transform'; +import csfRouter from './routes/cfdi-csf'; + +const app = express(); + +app.use(express.json()); + +app.get('/', (_req, res) => { + res.json({ + type: 'ts', + endpoints: { + '/catalogos': 'Catálogos del SAT (FormaPago, MetodoPago, etc.)', + '/rfc/validate/:rfc': 'Validar RFC', + '/rfc/faker': 'Generar RFC de prueba', + '/utils/numero-a-letras': 'POST { numero, moneda? }', + '/xml/create': 'POST crear CFDI XML (json + xml)', + '/xml/create-xml': 'POST crear CFDI XML (solo xml)', + '/json/parse': 'POST { xml } convertir XML a JSON', + '/json/samples': 'GET listar XMLs de ejemplo', + '/json/sample/:filename': 'GET parsear XML de ejemplo', + '/csd/info': 'GET info del certificado de prueba', + '/csd/pem': 'GET certificado en PEM', + '/csd/sign': 'POST { data } firmar con llave privada', + '/csd/verify': 'POST verificar llave pertenece al certificado', + '/complementos': 'GET listar complementos disponibles', + '/complementos/pago20': 'POST crear complemento de pago', + '/elements/constants': 'GET constantes de elementos CFDI', + '/xsd/schema': 'GET info del schema XSD', + '/transform/normalize': 'POST { text } normalizar espacios', + '/csf/parse': 'POST { path } parsear constancia fiscal', + }, + }); +}); + +app.use('/catalogos', catalogosRouter); +app.use('/rfc', rfcRouter); +app.use('/utils', utilsRouter); +app.use('/xml', xmlRouter); +app.use('/json', jsonRouter); +app.use('/csd', csdRouter); +app.use('/complementos', complementosRouter); +app.use('/elements', elementsRouter); +app.use('/xsd', xsdRouter); +app.use('/transform', transformRouter); +app.use('/csf', csfRouter); + +app.listen(PORT, () => { + console.log(`[TS] Server running on http://localhost:${PORT}`); +}); diff --git a/packages/test-ts/tsconfig.json b/packages/test-ts/tsconfig.json new file mode 100644 index 0000000..f4e0ca6 --- /dev/null +++ b/packages/test-ts/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "outDir": "dist", + "rootDir": "." + }, + "include": ["*.ts", "routes/*.ts"] +} diff --git a/packages/test-ts/update-versions.mjs b/packages/test-ts/update-versions.mjs new file mode 100644 index 0000000..9f3628c --- /dev/null +++ b/packages/test-ts/update-versions.mjs @@ -0,0 +1,103 @@ +import { dirname, resolve } from 'node:path'; +import { readFileSync, writeFileSync } from 'node:fs'; + +import { execSync } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const rushJsonPath = resolve(__dirname, '../../rush.json'); +const pkgJsonPath = resolve(__dirname, 'package.json'); + +const rush = JSON.parse(readFileSync(rushJsonPath, 'utf-8')); +const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8')); + +const publishable = rush.projects + .filter(p => p.shouldPublish) + .map(p => p.packageName); + +console.log(`Found ${publishable.length} publishable packages in rush.json\n`); + +function getVersions(name) { + try { + const raw = execSync(`npm view ${name} versions --json 2>/dev/null`, { + encoding: 'utf-8', + }); + const versions = JSON.parse(raw); + return Array.isArray(versions) ? versions : [versions]; + } catch { + return null; + } +} + +function getDeps(nameAtVersion) { + try { + const raw = execSync( + `npm view ${nameAtVersion} dependencies --json 2>/dev/null`, + { encoding: 'utf-8' } + ); + return JSON.parse(raw); + } catch { + return {}; + } +} + +// Step 1: Find latest version for each publishable package +const updated = {}; +const allVersionsCache = {}; +const errors = []; + +for (const name of publishable) { + const versions = getVersions(name); + if (versions) { + allVersionsCache[name] = versions; + updated[name] = versions[versions.length - 1]; + console.log(` ${name}: ${updated[name]}`); + } else { + errors.push(name); + console.log(` ${name}: NOT FOUND on npm (skipped)`); + } +} + +// Step 2: Check transitive deps for non-existent versions +console.log('\nChecking transitive dependencies...'); +const overrides = {}; + +for (const [name, version] of Object.entries(updated)) { + const deps = getDeps(`${name}@${version}`); + if (!deps) continue; + + for (const [depName, depVersion] of Object.entries(deps)) { + // Skip semver ranges — npm resolves those fine + if (/^[~^>=<|*]/.test(depVersion)) continue; + + const versions = allVersionsCache[depName] || getVersions(depName); + if (versions) { + allVersionsCache[depName] = versions; + if (!versions.includes(depVersion)) { + const latest = updated[depName] || versions[versions.length - 1]; + overrides[depName] = latest; + console.log( + ` ${name} -> ${depName}@${depVersion} NOT FOUND, override to ${latest}` + ); + } + } + } +} + +// Step 3: Write package.json (preserve devDependencies) +pkgJson.dependencies = updated; +if (Object.keys(overrides).length > 0) { + pkgJson.overrides = overrides; +} else { + delete pkgJson.overrides; +} +writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + '\n'); + +console.log(`\nUpdated ${Object.keys(updated).length} dependencies`); +if (Object.keys(overrides).length > 0) { + console.log(`Added ${Object.keys(overrides).length} overrides for missing transitive deps`); +} +if (errors.length) { + console.log(`Skipped ${errors.length}: ${errors.join(', ')}`); +} +console.log('\nRun "npm install" to install the updated versions.'); From 5ae15f2b99f48d033fc965c025aebdd141136f3e Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:14 -0500 Subject: [PATCH 02/15] chore(complementos): test publish workflow From 2d25fa80b960677dcdb9eba77bfefe190b9e4f33 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:15 -0500 Subject: [PATCH 03/15] chore(xsd): test publish workflow From c0698fdb15e2ccf9434f3960b68c3e8c22c108b0 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:16 -0500 Subject: [PATCH 04/15] chore(csd): test publish workflow From 95559e1ed25c66f306b306b69dd94db6c3be3f82 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:17 -0500 Subject: [PATCH 05/15] chore(csf): test publish workflow From 4722a667bcef812556dc94fccc3dd7397841a97a Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:18 -0500 Subject: [PATCH 06/15] chore(catalogs): test publish workflow From 638e2ca28a0bda9477de826bda480ab7d6dee5e6 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:19 -0500 Subject: [PATCH 07/15] chore(utils): test publish workflow From a3035c3d5324392bc0090ece3602b026d114f924 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:20 -0500 Subject: [PATCH 08/15] chore(rfc): test publish workflow From c14d9442b3683b65d88b0d5471d1df3a90644667 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:21 -0500 Subject: [PATCH 09/15] chore(openssl): test publish workflow From de75449e38fb00faf6281584604a4a918188ba84 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:22 -0500 Subject: [PATCH 10/15] chore(saxon): test publish workflow From b7d0f0fa48b18541a29eeb65993b99d24e0da1ce Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:23 -0500 Subject: [PATCH 11/15] chore(types): test publish workflow From 1102453def5932074ec6506f1b426d79070b3342 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:25 -0500 Subject: [PATCH 12/15] chore(transform): test publish workflow From 9253f9fdb2fc17462faddd0ea3829b1c943fb388 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:26 -0500 Subject: [PATCH 13/15] chore(2json): test publish workflow From b189d553bc5bf67fc3228614d3f9a97c70eb04b2 Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:27 -0500 Subject: [PATCH 14/15] chore(expresiones): test publish workflow From 314ef8ff994a5133727fa3673c72aaf04352f0eb Mon Sep 17 00:00:00 2001 From: MisaelMa Date: Tue, 7 Apr 2026 22:27:28 -0500 Subject: [PATCH 15/15] chore(elements): test publish workflow