diff --git a/.editorconfig b/.editorconfig index f67814db2..4e2d6abe8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,10 @@ insert_final_newline = false indent_style = space indent_size = 2 +[*.ts] +indent_style = space +indent_size = 2 + [*.json] indent_style = space indent_size = 2 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..3bd097333 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,23 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + ignore: + - dependency-name: "@types/node" + - dependency-name: "typedoc" + cooldown: + default-days: 14 + + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + cooldown: + default-days: 14 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 000000000..89d139ee2 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,16 @@ +name: PR Build +on: pull_request +jobs: + code-quality: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-node@v6 + with: + node-version: lts/* + - run: npm ci + - run: npm run build + - run: npm run lint + - run: npm run cover + - run: npm run format:check diff --git a/.gitignore b/.gitignore index 8b9b39975..d6f9e40d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ node_modules npm-debug.log coverage - +.nyc_output +yarn.lock +.vscode .idea *.iml +/lib +/docs diff --git a/.jshintrc b/.jshintrc index e7371228d..78130c09d 100644 --- a/.jshintrc +++ b/.jshintrc @@ -20,7 +20,7 @@ "predef": [ "describe", // Used by mocha "it", // Used by mocha - "xit", // Used by mocha + "xit", // Used by mocha "before", // Used by mocha "beforeEach", // Used by mocha "after", // Used by mocha diff --git a/.npmignore b/.npmignore index af1999293..503b5ae6d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,2 +1,9 @@ -/test/ -.idea +coverage +node_modules +test +CONTRIBUTING.md +History.md +PUBLISHING.md +.* +/src +/docs diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..f7ec3a946 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +**/*.yml +**/*.yaml +.github/ +.nyc_output/ +node_modules/ +lib/ +coverage/ +.vscode/ +.jshintrc \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..334b21e49 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,21 @@ +{ + "arrowParens": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "semi": true, + "experimentalTernaries": false, + "singleQuote": true, + "jsxSingleQuote": true, + "quoteProps": "consistent", + "trailingComma": "all", + "singleAttributePerLine": false, + "htmlWhitespaceSensitivity": "css", + "vueIndentScriptAndStyle": false, + "proseWrap": "preserve", + "insertPragma": false, + "requirePragma": false, + "tabWidth": 2, + "useTabs": false, + "embeddedLanguageFormatting": "auto", + "printWidth": 240 +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7b9b3fa50..000000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -sudo: false -language: node_js -notifications: - email: false -node_js: - - 0.10 - - 0.12 - - 4.0 - - iojs -env: - - CXX=g++-4.8 -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 -before_install: - - npm -g install npm@latest -script: - - npm run cover - - npm run coveralls diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 572ca1b9e..abdea0279 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,58 +1,55 @@ -#Contribution Guidelines - -Thank you for your support! node-soap wouldn't be where it is today without contributors like you who are willing to take the time to improve it for everyone else. - -Because SOAP Web Services can differ amongst implementations, there is high risk involved in making changes. What works for your WSDL, might not work with another. It is therefore _essential_ that contributors to node-soap adhere to these guidelines. - -##Filing issues -* Please look through the issues that are currently open in the attempt to find one that matches yours. -* If you find an issue that matches yours, please submit your documentation about it there as it will help everyone understand it more. -* If you plan on fixing the issue, please take the time to fix it first and then provide a Pull Request. -* Please be descriptive in your issue titles I.E. "Error occurs when calling client.foo on WSDL without import element." - -##Submitting a Pull Request -* Pull Requests **must be rebased to the latest version of master and _squashed to a single commit_** i.e. `git checkout master;git pull upstream master;git checkout feature-branch;git rebase -i master` -* Pull Requests **must have accompanying tests** (either Unit or Request/Response Sample tests are welcome). Your chances of getting the PR merged are very low if you don't provide any tests. -* Pull Requests must have passing travis builds. -* Pull Requests must be able to merge automatically from github. -* Please **do not close a pull request due to a request to rebase**. Git is a powerful VCS and deserves your time in learning how to rebase properly. Pull Requests are updated automatically on github when you force push to your branch after rebasing. - -Very useful articles/help on this topic: - - [GitHub Help - About Git rebase](https://help.github.com/articles/about-git-rebase/) - - [GitHub Help - Using Git rebase](https://help.github.com/articles/using-git-rebase/) - -* Please use descriptive commit messages. Commit messages are used during the creation of history and release notes. You'll make the job of maintainers much easier by doing this. - -##Making Changes -* Any and all pull requests to change documentation or typos are welcome! -* Any WSDL checked in should be as small and as generic as possible. This is to keep the size of the codebase from growing too large and to keep the reason for submitting the WSDL clear I.E. if the WSDL was submitted because attributes were not being parsed on response XML, then it would be appropriate to submit a WSDL that defines a response with attributes *and nothing else*. If you find an issue with the parser not being able to handle large WSDLs, then it would be appropriate to submit a large WSDL to recreate the issue with. -* If your issue is WSDL related: -```` - 1. Make your WSDL as generic as possible to recreate the issue - 2. Add the WSDL to the appropriate path in test/wsdl. - 3. Commit your changes to a feature branch within your fork. - 4. Issue a pull request. -```` - -* If your issue is client related: -```` - 1. Capture the request / response XML via client.lastRequest and client.lastResponse as well as the WSDL. - 2. Make the WSDL, request, and response XML as generic as possible. - 3. Only include the messages or operations that are having issues. - 4. Add the appropriate files to test/request-response-samples (see the README therein) - 5. Commit your changes to a feature branch within your fork. - 6. Issue a pull request -```` - -* If your issue is neither WSDL nor client related: -```` - 1. Provide a test of some form in an appropriate *-test.js file under test/ - 2. Commit your changes to a feature branch within your fork. - 3. Issue a pull request. -```` - -##Issue Expiration -Any pull request or issue filed is subject to an expiration date. We will close any open issue that has not received a response within a 2 week timeframe. The goal is not to sweep dirt under the rug, but to keep the focus on merging in pull requests. Please provide pull requests that meet the above criteria wherever possible. - -##Other ways you can contribute -Please add response, request, and WSDL files to test/wsdl, and test/request-response-samples (see README therein). Doing so documents behavior and reduces the likelihood that bugs will be introduced by future pull requests. +# Contribution Guidelines + +Thank you for your support! node-soap wouldn't be where it is today without contributors like you who are willing to take the time to improve it for everyone else. + +Because SOAP Web Services can differ amongst implementations, there is high risk involved in making changes. What works for your WSDL, might not work with another. It is therefore _essential_ that contributors to node-soap adhere to these guidelines. + +## Submitting a Pull Request + +- Pull Requests **must** be rebased to the latest version of `master`. If you just forked a repo for a PR it is already up to date. In case you forked some time ago you want to rebase it to avoid any merge conflicts: + ```bash + # set remote origin of your forked repo to original one + git remote set-url origin git@github.com:vpulim/node-soap.git + git fetch origin + git rebase origin/master + # set origin back to your forked repo + git remote set-url origin git@github.com:${USER_NAME}/node-soap.git + git push --force-with-lease + ``` +- Pull Requests **must have accompanying tests**. Your chances of getting the PR merged are very low if you don't provide any tests. +- Pull Requests must have passing GitHub CI/CD pipelines. +- Please use descriptive commit messages. + - Use the imperative, present tense: "change" not "changed" nor "changes" + - Do capitalize the first letter + - Do not end the description with a period (.) + +## Making Changes + +- Any and all pull requests to change (see the [documentation](https://github.com/vpulim/node-soap/blob/master/Readme.md) or typos are welcome! +- Any WSDL checked in should be as small and as generic as possible. This is to keep the size of the codebase from growing too large and to keep the reason for submitting the WSDL clear I.E. if the WSDL was submitted because attributes were not being parsed on response XML, then it would be appropriate to submit a WSDL that defines a response with attributes _and nothing else_. If you find an issue with the parser not being able to handle large WSDLs, then it would be appropriate to submit a large WSDL to recreate the issue with. +- If your Pull Request is WSDL related: + 1. Make your WSDL as generic as possible to recreate the issue + 2. Add the WSDL to the appropriate path in test/wsdl. + 3. Commit your changes to a feature branch within your fork. + 4. Issue a pull request. + +- If your Pull Request is client related: + 1. Capture the request / response XML via client.lastRequest and client.lastResponse as well as the WSDL. + 2. Make the WSDL, request, and response XML as generic as possible. + 3. Only include the messages or operations that are having issues. + 4. Add the appropriate files to test/request-response-samples (see the [README](https://github.com/vpulim/node-soap/blob/master/Readme.md) therein) + 5. Commit your changes to a feature branch within your fork. + 6. Issue a pull request + +- If your Pull Request is neither WSDL nor client related: + 1. Provide a test of some form in an appropriate \*-test.js file under test/ + 2. Commit your changes to a feature branch within your fork. + 3. Issue a pull request. + +## Issue Expiration + +Any pull request filed is subject to an expiration date. We will close any open Pull Request that has not received a response within a 2 week timeframe. The goal is not to sweep dirt under the rug, but to keep the focus on merging in pull requests. Please provide pull requests that meet the above criteria wherever possible. + +## Other ways you can contribute + +Please add response, request, and WSDL files to test/wsdl, and test/request-response-samples (see the [README](https://github.com/vpulim/node-soap/blob/master/test/request-response-samples/README.md) therein). Doing so documents behavior and reduces the likelihood that bugs will be introduced by future pull requests. diff --git a/History.md b/History.md index 242df9d48..25b3d1f74 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,524 @@ -0.14.0 / 2016-04-12 -================= +# 1.6.0 / 2025-10-25 + +- [ENHANCEMENT] Add support for multi-service and multi-port binding WSDL files (#1337) +- [ENHANCEMENT] Add new 'addElement' option to WSSE Security that adds custom xml to element (#1362) +- [MAINTENANCE] Bump actions/setup-node from 4 to 5 (#1358) +- [MAINTENANCE] Update dependencies (#1372) +- [DOC] Fix typos in Readme (#1374) + +# 1.5.0 / 2025-10-07 + +- [ENHANCEMENT] Handle different namespace prefix for the same namespace, requires to set new option `forceUseSchemaXmlns` (#1365) +- [ENHANCEMENT] Adding custom envelope key option for server and client header fix (#1208, #1170, #1330) +- [MAINTENANCE] Bump eslint to 9.36.0 (#1361) +- [MAINTENANCE] Bump mocha from 11.7.1 to 11.7.2 (#1354) +- [MAINTENANCE] Add prettier as a default formatter (#1353) + +# 1.4.2 / 2025-09-27 + +- [MAINTENANCE] Bump axios-ntlm to 1.4.6 and debug to 4.4.3 (#1351) +- [MAINTENANCE] Replace tslint with eslint (#1342) +- [FIX] Revert "Enable async methods for postProcess (#1338)" + +# 1.4.1 / 2025-09-15 + +- [MAINTENANCE] Bump axios to 1.12.2 (#1350) + +# 1.4.0 / 2025-09-15 + +- [FIX] Fix harcoded namespace prefixes in parsing (#1347) +- [ENHANCEMENT] Convert ref attributes to list (#1168) +- [ENHANCEMENT] Add option `overrideElementKey` to change the key of the wsdl (#1334) +- [ENHANCEMENT] Enable async methods for postProcess (#1338) +- [MAINTENANCE] Bump actions/checkout from 4 to 5 (#1340) +- [MAINTENANCE] Tune dependabot deps scheduling and updates (#1345) + +# 1.3.0 / 2025-08-13 + +- [ENHANCEMENT] Speed up parsing with many namespaces (#1322) +- [ENHANCEMENT] Add `*.ts` to editorconfig (#1324) +- [ENHANCEMENT] Call method using apply to enable access to it through "this" context (#1315) +- [ENHANCEMENT] Handle deeply nested messages (#1313) +- [ENHANCEMENT] Add test for redefined namespace in element (#1316) +- [MAINTENANCE] Bump express from 4.21.2 to 5.1.0 (#1327) +- [MAINTENANCE] Bump diff from 7.0.0 to 8.0.2 (#1326) +- [MAINTENANCE] Bump sinon from 20.0.0 to 21.0.0 (#1321) +- [MAINTENANCE] Bump @types/lodash from 4.17.16 to 4.17.20 (#1320) +- [MAINTENANCE] Bump mocha from 11.1.0 to 11.7.1 (#1319) +- [MAINTENANCE] Bump body-parser from 1.20.3 to 2.2.0 (#1317) +- [DOC] Update Readme to improve header + +# 1.2.1 / 2025-07-24 + +- [MAINTENANCE] Bump axios to 1.11.0 (#1314) + +# 1.2.0 / 2025-07-22 + +- [ENHANCEMENT] Remove hardcoded ID in timestamp (#1290) +- [ENHANCEMENT] Allows SchemaElement instance to use import namespace as targetNamespace (#1296) +- [ENHANCEMENT] Add optional parameter for response data encoding (#1303) +- [MAINTENANCE] Bump axios to 1.10.0 and other minor deps (#1312) +- [MAINTENANCE] Bump serve-static from 1.16.2 to 2.2.0 (#1308) +- [MAINTENANCE] Bump semver from 7.7.1 to 7.7.2 (#1310) +- [MAINTENANCE] Add dependabot workflow for deps and actions (#1301) + +# 1.1.12 / 2025-06-01 + +- [ENHANCEMENT] Add optional `excludeReferencesFromSigning` property to exclude elements (e.g., Body, Timestamp) from SOAP message signing (#1288) +- [MAINTENANCE] Bump deps axios 1.9.0, debug 4.4.1, formidable 3.5.4 and xml-crypto 6.1.2 + +# 1.1.11 / 2025-04-22 + +- [ENHANCEMENT] Allow xml key in first level for rpc (#1219) +- [ENHANCEMENT] Do not set Connection header when forever is not set (#1259) +- [MAINTENANCE] Packages updates, tsconfig changes, fix test path on Windows (#1280) +- [MAINTENANCE] Bump xml-crypto to 6.1.1 (#1283) + + # 1.1.10 / 2025-03-17 + +* [MAINTENANCE] Update axios to 1.8.3, xml-crypto to 6.0.1 and some other deps to address security issues + + # 1.1.9 / 2025-03-04 + +* [ENHANCEMENT] Use wsdl xmlns prefix mappings, so several wsdl files can be imported with different namespace prefixes (#1279) + + # 1.1.8 / 2024-12-11 + +* [ENHANCEMENT] Add option for digest algorithm, default value is sha256, update documentation (#1273) +* [MAINTENANCE] Fix minimal Node.js version in package.json (#1268) +* [MAINTENANCE] Update security.md (#1270) + + # 1.1.7 / 2024-12-11 + +* [MAINTENANCE] Update dependencies, bump axios to 1.7.9 (#1264) + + # 1.1.6 / 2024-11-04 + +* [ENHANCEMENT] Add custom cache option (#1261) +* [Fix] Fix usage of ref maxoccurs and minoccurs attributes (#1260) + + # 1.1.5 / 2024-09-29 + +* [ENHANCEMENT] Add missing KeyInfo tag around SecurityTokenReference (#1255) +* [ENHANCEMENT] Catch errors when overrideImportLocation fails (#1257) + + # 1.1.4 / 2024-09-17 + +* [ENHANCEMENT] Add feature to set signatureAlgorithm (#1254) +* [MAINTENANCE] Update dependencies, remove unused dependencies (#1256) + + # 1.1.3 / 2024-09-03 + +* [ENHANCEMENT] Allow ComplexContentElement to have a restriction as a child element and parse attributes for RestrictionElement (#1252) +* [MAINTENANCE] Bump axios to 1.7.7 and debug to 4.3.6 (#1253) + + # 1.1.2 / 2024-08-21 + +* [MAINTENANCE] Update Axios to 1.7.4 (#1248) +* [MAINTENANCE] Remove unused coveralls, replace request with Axios in tests (#1250) +* [MAINTENANCE] Speed up tests execution (#1249) +* [Fix] Add missing attributes (#1251) + + # 1.1.1 / 2024-08-04 + +* [ENHANCEMENT] Support binary data in MTOM (#1245) +* [ENHANCEMENT] Pass the error object to log (#1246) +* [Fix] Fix including xsd from another xsd while using inline xmlns (#1202) + + # 1.1.0 / 2024-07-16 + +* [ENHANCEMENT] Upgrade dependencies and refactor code to work with the xml-crypto 6.0.0, use built-in randomUUID instead of uuid (#1242) +* [ENHANCEMENT] Add express request object as parameter to the log method. (#1210) +* [ENHANCEMENT] Make error messages useful when using SOAP 1.2 (#1228) +* [ENHANCEMENT] Update Readme.md add example for xml string parameter (#1244) + + # 1.0.4 / 2024-06-18 + +* [ENHANCEMENT] Speed up WSDL parsing (#1218) +* [ENHANCEMENT] Add envelopeSoapUrl option to change the URL in xmlns:soap attribute (#1239) +* [ENHANCEMENT] Handle missing message definitions when creating SOAP client (#1241) + + # 1.0.3 / 2024-05-14 + +* [ENHANCEMENT] Add WSSecurity Protocol with user/pass token element (#1187) +* [ENHANCEMENT] Prevent mutating $type in the schema while processing requests (#1238) +* [FIX] Add space after `xmlns:wsu` to prevent xmldom warning (#1215) +* [FIX] Fix invalid multipart/related Content-Type (#1198) + + # 1.0.2 / 2024-04-29 + +* [ENHANCEMENT] Preserves leading and trailing whitespace when preserveWhitespace option is true (#1211) +* [ENHANCEMENT] Improve trim speed during XML parsing (#1216) +* [FIX] Change axios back as a dependency, bump axios to 1.6.8 (#1237) +* [FIX] Update proxy example in docs (#1220) +* [FIX] Add missing closing bracket in docs example (#1214) + + # 1.0.1 / 2024-04-18 + +* [FIX] Upgrade axios to 1.6.1 and axios-ntlm to 1.4.2 (#1212) +* [FIX] Fix build in Node.js 18 by re-encrypting test key (#1206) + + # 1.0.0 / 2022-12-09 + +* [ENHANCEMENT] allow soap.createClient to create a new SOAP client from a WSDL string (#1191) +* [FIX] Bump xml-crypto (#1200) +* [FIX] Upgrade to Formidable 3, Node 14, and audit fix (#1192) +* [FIX] Allow WSSecurity and WSSecurityCert to be used together (#1195) + + # 0.45.0 / 2022-06-15 + +* [FIX] axios peer dependency version (#1188) +* [MAINTENANCE] Upgrade formidable to v2 (#1183) + + # 0.44.0 / 2022-06-06 + +* [DOC] Readme.md: Rewrite how to get support for conciseness, update mentions of the old request module to Axios, improve documentation of several functions' arguments. (#1175) +* [ENHANCEMENT] Added override constructor to ClientSSLSecurityPFX class (#1184) +* [ENHANCEMENT] add optional targetNamespace to output message name (#1176) +* [FIX] Change axios to be a peer dependency (#1179) +* [FIX] Continuation PR #1169: change content-type-parser to whatwg-mimetype (#1177) +* [FIX] Fix missing parameter in example (#1172) +* [FIX] Fix of client events behavior (#1181) +* [FIX] correctly serialize MTOM into axios data and add Content-Encoding: gzip support in soap request (#1173) +* [FIX] double await in async and fixed response (#1185) +* [FIX] package.json: Change value of engines.node key from ">=10.0.0" to ">=12.0.0". (#1178) + + # 0.43.0 / 2021-11-12 + +* [DOC] Create SECURITY.md (#1165) +* [ENHANCEMENT] Publicly expose wsdl in Client (#1167) +* [ENHANCEMENT] add native support for long deserialization (#1160) +* [FIX] Fix typo in ISoapFault12 (#1166) +* [FIX] error when soapaction header is not set (#1171) +* [FIX] lastElapsedTime for non streaming requests (#1162) +* [FIX] minor fix for ntlm request (#1163) +* [FIX] undefined targetNamespace (#1161) +* [FIX] xsi:type currently requires a namespace, resulting in undefined if no XMLNS is defined. Making attributes working without namespace or xmlns definitions. (#1159) +* [MAINTENANCE] Bump httpntlm, doctoc as well as other dependencies (#1158) + + # 0.42.0 / 2021-08-23 + +* [FIX] check method style if exists instead of binding style (#1153) +* [FIX] update dependency vuln in xmldom via xml-cryoto/xmldom update (#1157) +* [FIX] update 7 vulnerabilities in the dependency chain (#1156) +* [FIX] SOAP faults are no longer being passed back in the error callback/promise rejection (#1155) + + # 0.41.0 / 2021-08-20 + +* [ENHANCEMENT] Support for soap attachments in response. (#1148) +* [FIX] Correctly add the https agent to axios (#1154) +* [FIX] prefer SOAPAction header over the body name to get the actual method name (#1152) +* [MAINTENANCE] Moving to github actions + + # 0.40.0 / 2021-07-06 + +* [DOC] Update Readme.md (#1150) +* [ENHANCEMENT] Allow server path to be a regex (#1149) +* [ENHANCEMENT] replace request & httpntlm with axios & axios-ntlm (#1146) + + # 0.39.0 / 2021-06-01 + +* [FIX] Fixed namespace resolution in case of complexType extension. (#1145) +* [FIX] Read length of buffer directly (#1147) + + # 0.38.0 / 2021-05-14 + +* [DOC] Remove duplicate paragraph and example code in Readme. (#1140) +* [ENHANCEMENT] Add an option to for an envelopeKey for WSSecurity (#1143) +* [FIX] Circular element references inside wsdl - assistance needed (#1142) +* [MAINTENANCE] Bump typedoc to 0.20.36, update package-lock.json (#1141) + + # 0.37.0 / 2021-04-07 + +* [ENHANCEMENT] Add native support for short deserialization (#1136) +* [FIX] Add handling for extension base without children (#1135) +* [FIX] Arrays with proper prefix and namespace (#1137) +* [MAINTENANCE] update xml-crypto version (#1138) + + # 0.36.0 / 2021-01-13 + +* [FIX] Extract required HttpClient functions to dedicated interface (#1132) +* [FIX] pass _res_ and _server_ object into header() and method() (#1130) +* [MAINTENANCE] refactor: use of Buffer.from instead of a deprecated new Buffer() (#1134) + + # 0.35.0 / 2020-11-17 + +* [MAINTENANCE] upgraded xml-crypto to latest version (#1131) + + # 0.34.0 / 2020-10-29 + +* [FIX] fix non lower case ?wsdl handling (#1129) +* [FIX] Fixing bug: if options.signatureAlgorithm = ..sha256 => will be generated two Reference to Body. (#1128) +* [MAINTENANCE] Remove constructor overload (#1127) +* [MAINTENANCE] Drop bluebird (#1125) +* [MAINTENANCE] Upgrade uuid (#1124) +* [MAINTENANCE] Avoid lodash where possible (#1122) +* [MAINTENANCE] Move static-serve to dev dependencies (#1121) +* [MAINTENANCE] Replace concat-stream with get-stream (#1123) + + # 0.33.0 / 2020-08-18 + +* [ENHANCEMENT] Added an option to directly return the underlying sax stream (#1120) +* [FIX] Convert decimals (#1118) +* [MAINTENANCE] bump lodash to 14.17.19 (#1117) + + # 0.32.0 / 2020-07-17 + +* [ENHANCEMENT] Add overrideImportLocation option (#1114) +* [FIX] Bug where no prototypical inheritence chain exists (#1110) +* [FIX] Clear http client header (#1103) +* [FIX] Escape username and password in wss (#1107) +* [FIX] replace === with startsWith (#1116) +* [MAINTENANCE] Move @types/requests dependency into devDependencies (#1111) + + # 0.31.0 / 2020-02-21 + +* [DOC] Update Readme.md (#1105) +* [ENHANCEMENT] Client.*method*Async can have options as the second argument (#1104) +* [FIX] Add WSDL xmlns header attribute (#1093) +* [FIX] Catch errors when parsing WSDL (#1102) +* [FIX] Fix min/maxOccurs parsing and handling (#1100) +* [FIX] Fixes bug when envelopeKey is changed and WSSecurityCert is set (#1106) +* [FIX] fix for circular descriptions (#1101) + + # 0.30.0 / 2019-10-16 + +* [ENHANCEMENT] Allow a fixed file path for local includes (#1089) +* [ENHANCEMENT] New XML Signing Options, extra tags to sign and small bug fix (#1091) +* [ENHANCEMENT] added forceMTOM option and updated the Readme (#1086) +* [FIX] Added undefined check in WSDL.processAttributes (#1090) +* [FIX] Fixes bug where methodName would not be included in the response event (#1087) +* [FIX] fixed MTOM removing soap12header (#1084) + + # 0.29.0 / 2019-07-26 + +* [ENHANCEMENT] Added Options object for signer.computeSignature (#1066) +* [FIX] Prototype pollution in lodash versions <=4.17.11. Hence, updating lodash version to ^4.17.15 in package.json and package-lock.json (#1085) +* [FIX] Fix known vulnerabilities found by `npm audit` (#1083) +* [FIX] Adjusts URL detection to be case insensitive (#1082) +* [FIX] Fixed issue causing error message, "TypeError: Cannot read property 'output' of undefined" (#1081) + + # 0.28.0 / 2019-06-20 + +* [ENHANCEMENT] Added support for parsing of doubles and floats. (#1065) +* [ENHANCEMENT] Adds promise server authentication (#1069) +* [ENHANCEMENT] Expose the WSDL class (#1071) +* [ENHANCEMENT] Now supporting XSI namespace overrides (#1079) +* [ENHANCEMENT] added possibility to add action to content-type header (#1073) +* [ENHANCEMENT] client.addSoapHeader() dynamic SOAP header (#1062) +* [ENHANCEMENT] emit response events allowing user override on response XML (#1070) +* [FIX] Fix description for recursive wsdl with extended element (#1078) +* [FIX] Fixes issue with unknown ReadableStream type (#1076) +* [FIX] Update types to make `options` optional for createClientAsync (#1068) +* [FIX] fix for soap 1.2 content-type header, missing action key (#1075) +* [FIX] types: move forceSoap12Headers to IWsdlBaseOptions (#1063) +* [MAINTENANCE] Updated read me to reflect changes in soap.listen (#1060) + + # 0.27.1 / 2019-04-19 + +* [FIX] Move @types/request to dependencies (#1059) + + # 0.27.0 / 2019-04-18 + +* [ENHANCEMENT] Added MTOM support for binary data (#1054) +* [ENHANCEMENT] Added callback for soap.listen (#1055) +* [ENHANCEMENT] add rsa-sha256 support for WSSecurityCert (#1052) +* [ENHANCEMENT] adding promise support for server method handlers. +* [FIX] Fixed PasswordDigest Generation (#1039) +* [FIX] Fixed some issues with xsd elements (#1057) +* [FIX] Handle response with error status code and without response body (#1053) +* [FIX] Stringify wsdl-related error messages to avoid non-descriptive [object Object] output. (#1037) +* [FIX] fix(compliance): updated the npm packages +* [FIX] fix(wsdl): array namespace override with colon(:) (#1045) +* [MAINTENANCE] adding source-map-support for ts mapping in stack trace; enabling tslint rules; added linting to travis; removing unnecessary self variables (#1047) +* [MAINTENANCE] converting the project to TypeScript (#1044) +* [MAINTENANCE] npm upgrade; removing ejs and external template files (#1046) +* [MAINTENANCE] npmignore cleanup; adding some types to Client (#1049) + + # 0.26.0 / 2019-02-11 + +* [FIX] WSDL: make merging external schema works correctly (#1023) +* [FIX] WSDL: pass error from parsing XML as-is, not only its message (#1022) +* [ENHANCEMENT] server: add option enableChunkedEncoding (#1043) +* [FIX] fix a problem about Multi-Byte character (#1042) +* [FIX] fix double transformationentries in WSSecCert +* [MAINTENANCE] Add bodyParser.json middleware test +* [FIX] processRequestXml only if req.body is not empty object +* [MAINTENANCE] Fixing v10 ssl tests and removing jshint since it sucks and doesn't support es6. (we need to migrate to eslint). +* [FIX] Arrays deserve namespace override too + + # 0.25.0 / 2018-08-19 + +* [FIX] Improved deserialization on inline `simpleType` declarations (#1015) +* [ENHANCEMENT] Added option to allow the user to dis-/enable the timestamp in `WSSecurtityCert` (defaults to "enabled" to maintain current behaviour) (#1017) +* [DOC] Updated the "\*Async" result description (#1016) +* [ENHANCEMENT] Added ability to resolve Schema-cross-reference namespaces in `client.describe()` (#1014) +* [FIX] Fixed `.npmignore` patterns in order to publish only the necessary files (#1012) +* [DOC] Removed formatting in code (#1011) +* [ENHANCEMENT] Added initial NTLM support (#887) +* [ENHANCEMENT] Added optional async authentication for the server (#1002) +* [MAINTENANCE] End of support for `node < 6.x` in our Travis CI config! +* [MAINTENANCE] Removed unnecessary `selectn` dependency (#975) +* [ENHANCEMNET] Added support for attributes in root elements (#910) +* [ENHANCEMENT] Added/updated TypeScript definitions (#991) +* [ENHANCEMENT] Change signature of `server.authorizeConnection()` to include also the `res`ponse param. (#1006) +* [FIX] WSSE Template - fix behaviour for template compilation in `__dirname` "unsafe" environments (e.g. `webpack` with target `node`) (#1008) + + # 0.24.0 / 2018-04-05 + +* [DOC] Error on custom deserializer example (#1000) +* [DOC] Fix broken link +* [DOC] adding bullets to separate each option +* [DOC] changed ClientSSLSecurity to ClientSSLSecurityPFX in the readme file +* [DOC] clarify section on client events in Readme.md (#989) +* [ENHANCEMENT] Added one-way response configuration options +* [ENHANCEMENT] Adding support for SOAP 1.2 Envelope Headers in the server side (#1003) +* [ENHANCEMENT] Enable multiArgs during promisification +* [ENHANCEMENT] add Client.wsdl for accessing client.wsdl during soap.createClient() (#990) +* [ENHANCEMENT] add option to remove element-by-element namespacing of json arrays (#994) +* [ENHANCEMENT] add rawRequest to callback arguments (#992) +* [FIX] Fixed checking for empty obj.Body before further actions (#986) +* [FIX] Lookup definitions in child element first (#958) +* [FIX] only detect xsi:nil if its value is `true` (#983) +* [MAINTENANCE] Updating the coverage to use the new version of Istanbul framework, the nyc. +* [MAINTENANCE] Upgrade Lodash to 4.17.5 (#1001) + + # 0.23.0 / 2017-10-18 + +* [FIX] Fixing tests broken by #979 +* [FEATURE] replace non identifier chars to underscore (#978) +* [FEATURE] Pool keep alive connections if forever option is used (#979) +* [MAINTENANCE] Use assert.ifError function in tests (#976) +* [FEATURE] Add function support for server addSoapHeader (#977) + + # 0.22.0 / 2017-10-02 + +* [ENHANCEMENT] Added `forever` option to `ClientSSLSecurity` in order to allow `keep-alive` connections. (#974) +* [ENHANCEMENT] Added `preserveWhitespace` option to prevent the client from trimming resolved `String` values. (#972) +* [MAINTENANCE] Removed `compres` dependency in favor of `zlib`. (#971) +* [MAINTENANCE] (Security) Updated `debug` dependency to avoid possible vulnerability. (#973) +* [FIX] Updated `.travis.yml` to test against latest `node.js 4.8.x` release to avoid Travis CI error. +* [FIX] Fix performance bug at POJO to XML conversion. (#968) +* [ENHANCEMENT] Added possibility to override the `bluebird.js` suffix (default: "async"). (#961) +* [DOC] Updated the `Security` section by listing all available optional methods. (#966) + + # 0.21.0 / 2017-08-28 + +* [DOC] Removed issues from Contributing Readme (#963) +* [DOC] Add server option details to readme.md (#965) +* [DOC] Added details to clientSSLSecurity (#960) +* [ENHANCEMENT] Added 'useEmptyTag' wsdlOption, which if set, creates instead of if no body is present (#962) +* [ENHANCEMENT] Add typescript support (#955) +* [FIX] `path.resolve` cannot resolve a null path (#959) +* [MAINTENANCE] Updated minimum node version to 4.0.0 (#964) +* [MAINTENANCE] Update `uuid` library to latest release (`3.1.0`) and use their newly introduced "modules" instead of the outdated/deprecated direct method calls. +* [MAINTENANCE] Fixed JSHint indentation errors in `test/client-test.js`. + + # 0.20.0 / 2017-08-08 + +* [ENHANCEMENT] Added `bluebird.js` promise library in order to provide `[methodName]Asyc` in `Client` (#956) +* [ENHANCEMENT] Added `option` to handle `nilAsNull` in `SOAP` responses (#952) +* [ENHANCEMENT] Added `option` to return a `SOAP Fault` instead of `stack` (error) on bad request (#951) +* [MAINTENANCE] Removed uneccessary variable declaration in `http.js` (#948) +* [ENHANCEMENT] Added possibiltiy to alter `XML` before it is sent (#943) +* [FIX] Updated vulnerable module `finalhandler` to version `^1.0.3` (#946) +* [ENHANCEMENT] Added possibility to submit `XML`-Strings to SOAP Client API (#918) + + # 0.19.2 / 2017-06-12 + +* [FIX] Recursive types cause infinite loop (#940) +* [DOC] Adding a note about consulting in the README. (#939) +* [MAINTENANCE] Add yarn.lock to gitignore (#938) +* [MAINTENANCE] Remove dependency to ursa (#928) + + # 0.19.1 / 2017-05-30 + +* [FIX] Reverting #914. It broke existing behavior and prevented array type arguments. (#937) +* [FIX] Add test for accepting array as parameter based on wsdl (#933) +* [DOC] readme.md clarifications, examples and typos (#930) +* [MAINTENANCE] Fix build by satisfying jshint indentation (#931) +* [MAINTENANCE] Drop `travis-ci` test support for `node.js` < `4.x` (LTS) (#932) +* [DOC] Update CONTRIBUTING.md +* [DOC] typo in server example (#925) + + # 0.19.0 / 2017-03-16 + +* [FIX] Fixed missing namespace declaration on `Array` if the namespace is already declared with another prefix. (#923) +* [DOC] Fix spelling error (#917) +* [FIX] Add `sequence` to field if it's defined within the `complextType` (#914) +* [MAINTENANCE] Drop deprecated `node-uuid` package and use the `uuid` (successor) instead (#913) +* [FIX] Only add references for the soap:Body and wsse:Security/Timestamp elements in WSSecurityCert (#911) +* [MAINTENANCE] Updated `ejs` package version in `package.json` (#908) +* [ENHANCEMENT] Added possiblity to pass your own "custom deserializer" within the `wsdlOptions` in `createClient()` method (#901) +* [ENHANCEMENT] Added possibility to use your own "exchange ID" (#907) +* [ENHANCEMENT] Added "exchange ID" (`eid`) in emitted client events (#903) +* [ENHANCEMENT] Added option to suppress error stack in server response (#904) +* [FIX] Set namespace prefix for first element if `elementFormDefault=unqualified` (#905) +* [FIX] Fixed test (use `assert` instead of `should()` chain) in `test/server-test.js` (#906) +* [DOC] Fix documentation in `test/request-response-samples/README.md` (#900) + + # 0.18.0 / 2016-11-25 + +* [DOC] Added documentation for adding custom http header (#890) +* [DOC] Update soap stub example (#883) +* [ENHANCEMENT] Add body parameter to soap responding stub. (#897) +* [ENHANCEMENT] Added Stream support. (#837) +* [ENHANCEMENT] Avoid matching tags inside comments (#877) +* [FIX] Ensure that supplied request-object is passed through. (#894) +* [FIX] Fix exception 'Parameter 'url' must be a string, not object' (#870) +* [FIX] Handle empty SOAP Body properly. (#891) +* [FIX] Set lodash dependency version to ^3.10.1 (#895) +* [MAINTENANCE] Fix test case description (#886) +* [MAINTENANCE] Fixed request-response-samples-test so that tests with only request.xml and request.json actually get run (#878) +* [MAINTENANCE] Fixing minor jshint issues. (#884) + + # 0.17.0 / 2016-06-23 + +* [ENHANCEMENT] Add option for disabling the WSDL cache (#876) +* [DOC] Add `escapeXML` option to README file (#874) +* [DOC] updated readme for express support (#873) +* [ENHANCEMENT] express server support (#872) +* [ENHANCEMENT] better error 1. SOAP message missing evelope and body 2. request/response tests (#869) +* [FIX] Fix possible crash when send empty post using postman (#861) +* [FIX] fix ExtensionElement description to match order (#866) +* [DOC] Added descriptions for actor, hasNonce & mustUndertand options (#865) +* [FIX] Fix namespaces in client soap requests (#863) +* [FIX] Always submit valid XML from the client. (#862) +* [MAINTENANCE] mustUnderstand must be 0 or 1.. with tests (#850) +* [MAINTENANCE] Remove special handling of methods only taking a string paramter (#854) + + # 0.16.0 / 2016-06-23 + +* [ENHANCEMENT] Add nonce and soap:actor support for WSSecurity (#851) +* [MAINTENANCE] Fix typo in readme (#853) +* [FIX fixes and issue that causes the module to break if no re or req.headers present in client (#852) +* [FIX] fixed the soap request envelop generation part when request has complex Type as root. (#849) +* [FIX] Gracefully handle errors while parsing xml in xmlToObject and resume the parser with p.resume() (#842) +* [FIX] XSD import in WSDL files and relative path (server creation) - resubmit (#846) +* [ENHANCEMENT] Support array of certs for ClientSSLSecurity ca. (#841) +* [MAINTENANCE] Attribute value of body id in double quotes (#843) +* [MAINTENANCE] Bumping ursa to 0.9.4 (#836) +* [ENHANCEMENT] Optionally add Created to wssecurity header (#833) +* [MAINTENANCE] Clean up brace style (#835) +* [FIX] Fix custom http client not being used when fetching related resources (#834) + + # 0.15.0 / 2016-05-09 + +* [FIX] Make `ursa` an optional dependency since it's currently nearly impossible to install `soap` on a windows machine otherwise (#832) +* [FIX] Fixed issue of referencing element in another namespace (#831) +* [FIX] Fixed incorrect WSDL in `CDATA` tests (#830) +* [FIX] Added mocks for node.js streams `cork`/`uncork` in tests (for `node >= 4.x`) (#829) +* [ENHANCEMENT] Added basic `CDATA` support (#787) +* [DOC] Added missing documentation about `Client.setEndpoint(url)` (#827) +* [ENHANCEMENT] Added `toc` node-module in order to generate TOC in README.md via `npm run toc` command (#826) +* [FIX] Fix `elementFormDefault` handling (#822) +* [FIX] Added missing `compress` node-module to `package.json` dependencies (#823) +* [ENHANCEMENT] The client `response` event is now triggered with the "raw" `IncomingMessage` object as second parameter (#816) +* [DOC] Added note about the `keep-alive` workaround to prevent truncation of longer chunked reponses in `node > 0.10.x` (#818) +* [ENHANCEMENT] Make it possible to overwrite the request module, e.g. for using `multipart-body` for file up- and downloads (#817) + + # 0.14.0 / 2016-04-12 + * [ENHANCEMENT] Allow to call methods with `callback` as last param in order to align with node.js `callback last` pattern (#814) * [ENHANCEMENT] Re-enabled `ignoreBaseNameSpaces` option (#809) * [FIX] Avoid overwriting request headers with options in client method invocation (#813) @@ -12,77 +531,77 @@ * [ENHANCEMENT] Added support for WSSecurity XML signing with x509 certificats. Dropped support for node.js < 0.10.x (#801) * [ENHANCEMENT] Remove assertions/checkin of certificates in `ClientSSLSecurity` (#800) -0.13.0 / 2016-02-16 -================= + # 0.13.0 / 2016-02-16 + * [FIX] Maintain `ignoredNamespaces` option when processing WSDL includes (#796) -* [ENHANCEMENT] SOAP Headers for server response & `changeSoapHeader()` method for client & server (#792) +* [ENHANCEMENT] SOAP Headers for server response & `changeSoapHeader()` method for client & server (#792) * [ENHANCEMENT] Added XML declaration (version & encoding) to client requests (#797) * [DOC] Added example for `server.options` to README, fixed typos in CONTRIBUTING (#798) * [FIX] Keep `nsContext` stack consistent even on recursive calls (#799) * [FIX] Prevent NPE when processing an empty children array (#789) -0.12.0 / 2016-02-02 -================= + # 0.12.0 / 2016-02-02 + * [MAINTENANCE] updating lodash to 3.x.x * [FIX] Schema overwrite when include a xsd with (#788) -0.11.4 / 2016-01-09 -================= + # 0.11.4 / 2016-01-09 + * [MAINTENANCE] Adding coverage to project. -0.11.3 / 2016-01-09 -================= + # 0.11.3 / 2016-01-09 + * [ENHANCEMENT] Overriding the namespace prefix with empty prefix. (#779) * [FIX] Wrong namespace on elements when complexType has same name. (#781) * [FIX] Improved 'https' pattern matching for local files with name starting with 'http'. (#780) * [FIX] Handles SOAP result null output. (#778) -0.11.2 / 2016-01-08 -================= + # 0.11.2 / 2016-01-08 + * [FIX] Return null instead of empty object. (#733, #707, #784) * [DOC] Adds commas and semicolons to listen(...) example. (#782) * [MAINTENANCE] Temporarily skiping test from #768. -0.11.1 / 2015-12-15 -================= + # 0.11.1 / 2015-12-15 + * [ENHANCEMENT] Adding ClientSSLSecurityPFX for use in requests (#768) * [FIX] Remove SOAPAction http header in SOAP 1.2, extra header was causing some servers to trip. (#775) * [FIX] When an error occur, send HTTP 500 status code. (#774) * [FIX] Fixed issue when an error was undefined: undefined. (#771) * [FIX] Add missing type attribute for PasswordText in WSSecurity and update related tests. (#754) -0.11.0 / 2015-10-31 -================= + # 0.11.0 / 2015-10-31 + * [ENHANCEMENT] Now passing request to services in server.js. (#769) * [ENHANCEMENT] Adding the ability to add headers in client requests. (#770) * [MAINTENANCE] Adding gitter badge to README and disabling issues. (#731) * [FIX] Stop sending Object prototype methods as XML. (#699) -0.10.3 / 2015-10-23 -================= + # 0.10.3 / 2015-10-23 + * [ENHANCEMENT] Adding createErroringStub to soap-stub. (#765) * [ENHANCEMENT] `forceSoap12Headers` option to add SOAP v1.2 request headers. (#755) -0.10.2 / 2015-10-22 -================= + # 0.10.2 / 2015-10-22 + * [ENHANCEMENT] Adding security to soap-stub. (#764) -0.10.1 / 2015-10-22 -================= + # 0.10.1 / 2015-10-22 + * [ENHANCEMENT] Adding soap-stub. (#763) -0.10.0 / 2015-10-21 -================= + # 0.10.0 / 2015-10-21 + * [FIX] xml namespace/element/type handling. (#756) -0.9.5 / 2015-10-15 -================= + # 0.9.5 / 2015-10-15 + * [FIX] Allow circular XSD files to be loaded. (#745) * [ENHANCEMENT] Timestamp is now optional. (#735) * [DOC] Formatting History.md 0.9.4 notes. -0.9.4 / 2015-09-28 -================= + # 0.9.4 / 2015-09-28 + * [MAINTENANCE] Adding node v4.0 to .travis.yml. (#729) * [MAINTENANCE] Increasing mocha test timeout to 10 seconds. (#732) * [FIX] Resolve element references when other types are referenced. (#725) @@ -92,13 +611,13 @@ * [FIX] Fix for wsdl retrieval using soap.createClient with special options.httpClient. Before this, the specified client was not used when fetching the wsdl file. This fix will force the wsdl to use the specified httpClient. (#714) * [FIX] Allow WSDL to be loaded from HTTPS sites. (#694) -0.9.3 / 2015-09-08 -================= + # 0.9.3 / 2015-09-08 + * [ENHANCEMENT] Allow namespace overriding for elements. (#709) * [MAINTENANCE] Disable travis emails. -0.9.2 / 2015-09-08 -================= + # 0.9.2 / 2015-09-08 + * [ENHANCEMENT] Add support for xsd element ref. (#700) * [MAINTENANCE] Moving travis build to containers. * [MAINTENANCE] Add request sample for an operation without any parameters. (#703) @@ -108,13 +627,13 @@ * [FIX] Fixed SOAP Fault errors not being raised as errors. (#676) * [FIX] Use diffrent namespace styles for soap fault 1.1 and 1.2. (#674) -0.9.1 / 2015-05-30 -================= + # 0.9.1 / 2015-05-30 + * [FIX] Received empty Strings are now returned as empty String rather than an empty Object. (#637) * [FIX] Get current namespace when parent namespace is an empty String. Fixes #533. (#661) -* [DOC] Update README.md with documentation for #660 introduced customization of `httpClient` and `request` libs in `client.options`. (#664) +* [DOC] Update README.md with documentation for #660 introduced customization of `httpClient` and `request` libs in `client.options`. (#664) * [FIX] Take configured "ignored namespaces" into account when processing `objectToXml()`. Fixes #537. (#662) @@ -126,8 +645,8 @@ * [FIX] Make parsing of recursive Elements in `wsdl` work. (#658) -0.9.0 / 2015-05-18 -================= + # 0.9.0 / 2015-05-18 + * [FIX] Fix to allow request options and headers to persist for all includes. Fix to properly handle when an import/include starts with a schema element. (#608) * [FIX] Do not end request for keep-alive connections (#600) @@ -158,15 +677,14 @@ * [FIX] Respond with security timestamp if request had one (#579) + # 0.8.0 / 2015-02-17 -0.8.0 / 2015-02-17 -================= * [ENHANCEMENT] `node-soap` is now also compatible (and tested) with `node v0.12.0` and `io.js` too. (#571) * [FIX] Adds support for attributes in the `SOAP Body` Element (fixes #386). (#574) -0.7.0 / 2015-02-10 -================= + # 0.7.0 / 2015-02-10 + * [ENHANCEMENT] Server emits a `headers` event to globally handle SOAP Headers. (#564 ) * [ENHANCEMENT] A service method can send back a SOAP Fault response to a client by throwing an object that contains a `Fault` property. (#563) @@ -177,14 +695,14 @@ * [FIX] Respect empty SOAP actions in operations. (#554) -* [ENHANCEMENT] The client now emits `message`, `request` and `soapError` events. (#547, #559) +* [ENHANCEMENT] The client now emits `message`, `request` and `soapError` events. (#547, #559) * [ENHANCEMENT] The server is now aware of the SOAP header(s) from incoming request. (#551) * [ENHANCEMENT] Until now, only the SOAP Body was returned from the invoked client method. With this PR also the SOAP Header(s) will be returned. (#539) -0.6.1 / 2014-12-20 -================== + # 0.6.1 / 2014-12-20 + * [ENHANCEMENT] Allow logging of received `XML` prior to parsing and processing it, which allows better debugging of incoming`XML`. (#524) * [ENHANCEMENT] Add support for importing external `wsdl`. (#523) @@ -204,32 +722,32 @@ * [FIX] Ignore default `tns` and disabled default `tns` specification in first element of the body. (#506) * [ENHANCEMENT] Define `$xml` to pass plain `XML` object. (#485) -The `$xml` key is used to pass an `XML` Object to the request without adding a namespace or parsing the string. + The `$xml` key is used to pass an `XML` Object to the request without adding a namespace or parsing the string. * [FIX] Updated '#extend' method to avoid overriding properties and ensure the 'inheritance' of `` usage. (#493) -0.6.0 / 2014-10-29 -================= + # 0.6.0 / 2014-10-29 + * [ENHANCEMENT] Adding bearer security type Exporting security type for usage. * [ENHANCEMENT] The qualified elementFormQualified must be respected only when the current element is not a global element. The namespace attribute is only needed if it's not included in the xmlns. * [FIX] Remove automatic port appending to "Host" header. * [FIX] Avoid creating soap:Header container when there are no children. * [FIX] Allowing a 'null' argument for WSDL methods that take no arguments. * [FIX] Wrong initialization of xmlns array when handling rpc stype wsdl. -* [FIX] Fault handling. err should be used less frequently now. +* [FIX] Fault handling. err should be used less frequently now. * [FIX] Added checking if there is input and output for operations under bindings section. * [FIX] XSD conflict with same namespace. -0.5.1 / 2014-07-11 -================= + # 0.5.1 / 2014-07-11 + * [ENHANCEMENT] Add "defaults" parameter to BasicAuthSecurity's constructor -* [ENHANCEMENT] Added possibility to set a custom `valueKey` for the parsed values from XML SOAP Response -* [FIX] don't append port 80 to Host if not needed -* [FIX] Remove possible existing BOM characters from XML String before passing it to `WSDL#_fromXML()` and parsing it. -* [FIX] Handling nil attributes in response xml +* [ENHANCEMENT] Added possibility to set a custom `valueKey` for the parsed values from XML SOAP Response +* [FIX] don't append port 80 to Host if not needed +* [FIX] Remove possible existing BOM characters from XML String before passing it to `WSDL#_fromXML()` and parsing it. +* [FIX] Handling nil attributes in response xml + + # 0.5.0 / 2014-07-11 -0.5.0 / 2014-07-11 -================= * [ENHANCEMENT] Allowing namespace prefixes to be ignored via config. * [ENHANCEMENT] wsdl should handle more types * [FIX] Handle defined messages ending with "Response", "Out", or "Output" @@ -240,12 +758,12 @@ The `$xml` key is used to pass an `XML` Object to the request without adding a n * [FIX] Keep ns from top-level * [FIX] Check status code of invocation response -0.4.7 / 2014-06-16 -================= + # 0.4.7 / 2014-06-16 + * [ENHANCEMENT] Allow request elements to have both content and attributes. -0.4.6 / 2014-06-16 -================= + # 0.4.6 / 2014-06-16 + * Fix for the `elementFormDefault` functionality. * Fix determining the namespace for complex elements. * Add support for the `elementFormDefault` schema attribute. @@ -260,15 +778,15 @@ The `$xml` key is used to pass an `XML` Object to the request without adding a n * Added some documentation on options object when calling createClient. * Fix for namespaces in headers not being added appropriately. -0.4.5 / 2014-05-13 -================= + # 0.4.5 / 2014-05-13 + * Fixed: Unspecified binding style defaults to 'document' (#346, #208) * Fixed: WSDL parse errors bubble up (#344) * Fixed: AssertionError: Invalid child type when WSDL contains imports (#322, #337) * Fixed: TargetNamespace not loaded when import in schema (#327, #325) -0.4.4 / 2014-04-16 -================= + # 0.4.4 / 2014-04-16 + * Added namespace prefixes to SOAP headers. #307 * Provided more documentation around security protocols in the README. #321 * Added lodash. #321 @@ -276,9 +794,9 @@ The `$xml` key is used to pass an `XML` Object to the request without adding a n * Fix to reset the generated namespace number. #308 * Fixed maximum callstack errors on certain responses. #257 -0.4.3 / 2014-04-07 -================= -* Refactored WS-security. small modifications to pull #275 + # 0.4.3 / 2014-04-07 + +* Refactored WS-security. small modifications to pull #275 * Updated readme to add documentation for passing options to a client request * Added null check for portType and methods[methodname].output * Fixed issue where requests that included compex types led to invalid request XML. @@ -286,42 +804,41 @@ The `$xml` key is used to pass an `XML` Object to the request without adding a n * Make sure callback is done asynchronously for a cached wsdl * Added WSDL inheritance support (#133). -0.4.2 / 2014-03-13 -================= + # 0.4.2 / 2014-03-13 + * Added the ability to inspect and clear soap headers. * Reducing test wsdl size. * No longer prefixing elements with a default namespace prefix i.e. xmlns. -0.4.1 / 2014-03-04 -================= -Note: an error occurred publishing this version to npm. This version was tagged, so it can be referrenced via git. - * package; increased minor version to 0.4.1 - * Adding an npmignore on test/ - * Tests are linted - * Attributes may be added to requests and parsed from responses - * Tests were added for ssl and client authentication - * Support for import elements in WSDL documents. - * Version in server response matches package.json - * Describe errors fixed on OutputElements. - * Support for Fault handling. - -0.4.0 / 2014-02-15 -================== - - * package; increased minor version to 0.4 (xml parser change, tests) - * remove execute privileges on files #216 - * add travis #219 - * add jshint for index.js #220 - * remove execute permissions on .gitignore #227 - * fixed; fix requests if SOAP service is not on port 80, do not crash on errors #228 - * fixed; undefined value for json in client method when message names end with Out or Output. #243 - * add non xmlns attributes to elements during response parsing #241 - * package; replace expat dependency with sax #246 - * fixed; "Uncaught TypeError: Cannot read property '0' of undefined" #248 - -0.3.2 / 2014-01-21 -================== - - * fixed; http request callback fires twice on error #120 - * fixed; handle connection errors #192 - * package; include mocha in devDependencies + # 0.4.1 / 2014-03-04 + + Note: an error occurred publishing this version to npm. This version was tagged, so it can be referrenced via git. + +* package; increased minor version to 0.4.1 +* Adding an npmignore on test/ +* Tests are linted +* Attributes may be added to requests and parsed from responses +* Tests were added for ssl and client authentication +* Support for import elements in WSDL documents. +* Version in server response matches package.json +* Describe errors fixed on OutputElements. +* Support for Fault handling. + +# 0.4.0 / 2014-02-15 + +- package; increased minor version to 0.4 (xml parser change, tests) +- remove execute privileges on files #216 +- add travis #219 +- add jshint for index.js #220 +- remove execute permissions on .gitignore #227 +- fixed; fix requests if SOAP service is not on port 80, do not crash on errors #228 +- fixed; undefined value for json in client method when message names end with Out or Output. #243 +- add non xmlns attributes to elements during response parsing #241 +- package; replace expat dependency with sax #246 +- fixed; "Uncaught TypeError: Cannot read property '0' of undefined" #248 + +# 0.3.2 / 2014-01-21 + +- fixed; http request callback fires twice on error #120 +- fixed; handle connection errors #192 +- package; include mocha in devDependencies diff --git a/PUBLISHING.md b/PUBLISHING.md index abf976c34..05d55f312 100644 --- a/PUBLISHING.md +++ b/PUBLISHING.md @@ -1,28 +1,33 @@ -Publishing -=================== +# Publishing This document describes the steps a maintainer of this project generally takes in order to publish a newer version of `node-soap`. ## Ideals -* Pull Requests that alter, add, or correct functionality have a single commit. -* All commit messages are descriptive. -* Maintainers spend little time looking at git history to update HISTORY.md. + +- Pull Requests that alter, add, or correct functionality have a single commit. +- All commit messages are descriptive. +- Maintainers spend little time looking at git history to update HISTORY.md. ## Process -1. Checkout the commit that you would like to publish. This is usually accomplished + +1. Checkout the commit that you would like to publish. This is usually accomplished with `git checkout master`. 2. Run `git log --oneline` 3. Copy the commit messages above the last release commit message into History.md. 4. Consolidate the commit messages: - * Remove any futile commits I.E. "Removing white space" - * Remove Pull Request merge commits. In some cases, you may need to reference the issue in - order to get the commit message for that Pull Request. - * Prefix commit messages with "Enhancement", "Fixed", "Deprecated" and so forth - accordingly. - * Reword line items as necessary. + +- Remove any futile commits I.E. "Removing white space" +- Remove Pull Request merge commits. In some cases, you may need to reference the issue in + order to get the commit message for that Pull Request. +- Prefix commit messages with "Enhancement", "Fixed", "Deprecated" and so forth + accordingly. +- Reword line items as necessary. + 5. Update package.json to the appropriate version for the release. 6. Commit your changes to master and push them up to github. 7. Use the github interface to create a tag. - * Use existing release notes as a reference when adding the release notes to github. + +- Use existing release notes as a reference when adding the release notes to github. + 8. `npm publish`. diff --git a/Readme.md b/Readme.md index 3163878c9..c884e222a 100644 --- a/Readme.md +++ b/Readme.md @@ -1,23 +1,26 @@ -# Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url] +[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Coveralls Status][coveralls-image]][coveralls-url] -> A SOAP client and server for node.js. +[![Support][buy-me-a-coffee-image]][buy-me-a-coffee-url] -This module lets you connect to web services using SOAP. It also provides a server that allows you to run your own SOAP services. +# SOAP client and server for node.js. + +This module lets you connect to web services using SOAP. It also provides a server that allows you to run your own SOAP services. - -- [Features:](#features) +- [Features](#features) - [Install](#install) -- [Where can I file an issue?](#where-can-i-file-an-issue) +- [Support](#support) - [Module](#module) - [soap.createClient(url[, options], callback) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclienturl-options-callback---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path) - - [soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.](#soaplistenserver-path-services-wsdl---create-a-new-soap-server-that-listens-on-path-and-provides-services) - - [Options](#options) + - [soap.createClientAsync(url[, options]) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclientasyncurl-options---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path) + - [soap.listen(_server_, _path_, _services_, _wsdl_, _callback_) - create a new SOAP server that listens on _path_ and provides _services_.](#soaplistenserver-path-services-wsdl-callback---create-a-new-soap-server-that-listens-on-path-and-provides-services) + - [soap.listen(_server_, _options_) - create a new SOAP server that listens on _path_ and provides _services_.](#soaplistenserver-options---create-a-new-soap-server-that-listens-on-path-and-provides-services) - [Server Logging](#server-logging) - [Server Events](#server-events) + - [Server Response on one-way calls](#server-response-on-one-way-calls) - [SOAP Fault](#soap-fault) - [Server security example using PasswordDigest](#server-security-example-using-passworddigest) - [Server connection authorization](#server-connection-authorization) @@ -27,151 +30,324 @@ This module lets you connect to web services using SOAP. It also provides a ser - [Client](#client) - [Client.describe() - description of services, ports and methods as a JavaScript object](#clientdescribe---description-of-services-ports-and-methods-as-a-javascript-object) - [Client.setSecurity(security) - use the specified security protocol](#clientsetsecuritysecurity---use-the-specified-security-protocol) - - [Client.*method*(args, callback) - call *method* on the SOAP service.](#clientmethodargs-callback---call-method-on-the-soap-service) - - [Client.*service*.*port*.*method*(args, callback[, options[, extraHeaders]]) - call a *method* using a specific *service* and *port*](#clientserviceportmethodargs-callback-options-extraheaders---call-a-method-using-a-specific-service-and-port) - - [Client.*lastRequest* - the property that contains last full soap request for client logging](#clientlastrequest---the-property-that-contains-last-full-soap-request-for-client-logging) + - [Client._method_(args, callback, options) - call _method_ on the SOAP service.](#clientmethodargs-callback-options---call-method-on-the-soap-service) + - [Client.*method*Async(args, options) - call _method_ on the SOAP service.](#clientmethodasyncargs-options---call-method-on-the-soap-service) + - [Client._service_._port_._method_(args, callback[, options[, extraHeaders]]) - call a _method_ using a specific _service_ and _port_](#clientserviceportmethodargs-callback-options-extraheaders---call-a-method-using-a-specific-service-and-port) + - [Overriding the namespace prefix](#overriding-the-namespace-prefix) + - [Client._lastRequest_ - the property that contains last full soap request for client logging](#clientlastrequest---the-property-that-contains-last-full-soap-request-for-client-logging) + - [Client.setEndpoint(url) - overwrite the SOAP service endpoint address](#clientsetendpointurl---overwrite-the-soap-service-endpoint-address) - [Client Events](#client-events) -- [WSSecurity](#wssecurity) + - [_request_](#request) + - [_message_](#message) + - [_soapError_](#soaperror) + - [_response_](#response) +- [WSDL](#wsdl) +- [WSDL.constructor(wsdl, baseURL, options):](#wsdlconstructorwsdl-baseurl-options) + - [wsdl.xmlToObject(xml):](#wsdlxmltoobjectxml) + - [wsdl.objectToXML(object, typeName, namespacePrefix, namespaceURI, ...):](#wsdlobjecttoxmlobject-typename-namespaceprefix-namespaceuri-) +- [Security](#security) + - [BasicAuthSecurity](#basicauthsecurity) + - [BearerSecurity](#bearersecurity) + - [ClientSSLSecurity](#clientsslsecurity) + - [ClientSSLSecurityPFX](#clientsslsecuritypfx) + - [WSSecurity](#wssecurity) + - [WSSecurityCert](#wssecuritycert) + - [WSSecurityPlusCert](#wssecuritypluscert) + - [WSSecurityCertWithToken](#wssecuritycertwithtoken) + - [NTLMSecurity](#ntlmsecurity) - [Handling XML Attributes, Value and XML (wsdlOptions).](#handling-xml-attributes-value-and-xml-wsdloptions) + - [Overriding the `value` key](#overriding-the-value-key) + - [Overriding the `xml` key](#overriding-the-xml-key) + - [Overriding the `attributes` key](#overriding-the-attributes-key) + - [Overriding imports relative paths](#overriding-imports-relative-paths) + - [Overriding import locations](#overriding-import-locations) - [Specifying the exact namespace definition of the root element](#specifying-the-exact-namespace-definition-of-the-root-element) + - [Overriding element key specification in XML](#overriding-element-key-specification-in-xml) + - [Custom Deserializer](#custom-deserializer) + - [Changing the tag formats to use self-closing (empty element) tags](#changing-the-tag-formats-to-use-self-closing-empty-element-tags) - [Handling "ignored" namespaces](#handling-ignored-namespaces) - [Handling "ignoreBaseNameSpaces" attribute](#handling-ignorebasenamespaces-attribute) -- [soap-stub](#soap-stub) - - [Example](#example) - [Contributors](#contributors) -## Features: +## Features -* Very simple API -* Handles both RPC and Document schema types -* Supports multiRef SOAP messages (thanks to [@kaven276](https://github.com/kaven276)) -* Support for both synchronous and asynchronous method handlers -* WS-Security (currently only UsernameToken and PasswordText encoding is supported) +- Very simple API +- Handles both RPC and Document schema types +- Supports multiRef SOAP messages (thanks to [@kaven276](https://github.com/kaven276)) +- Support for both synchronous and asynchronous method handlers +- WS-Security UsernameToken Profile 1.0 +- Supports [Express](http://expressjs.com/) based web server (body parser middleware can be used) ## Install -Install with [npm](http://github.com/isaacs/npm): - ``` npm install soap ``` -## Where can I file an issue? - -We've disabled issues in the repository and are now solely reviewing pull requests. The reasons why we disabled issues can be found here [#731](https://github.com/vpulim/node-soap/pull/731). +## Support -If you're in need of support we encourage you to join us and other `node-soap` users on gitter: - -[![Gitter chat][gitter-image]][gitter-url] +Community support is available through GitHub issues tab. +Paid support can be provided as well, please contact one of the active maintainers. ## Module ### soap.createClient(url[, options], callback) - create a new SOAP client from a WSDL url. Also supports a local filesystem path. -``` javascript - var soap = require('soap'); - var url = 'http://example.com/wsdl?wsdl'; - var args = {name: 'value'}; - soap.createClient(url, function(err, client) { - client.MyFunction(args, function(err, result) { - console.log(result); - }); +- `url` (_string_): A HTTP/HTTPS URL, XML or a local filesystem path. +- `options` (_Object_): + - `endpoint` (_string_): Override the host specified by the SOAP service in the WSDL file. + - `envelopeKey` (_string_): Set a custom envelope key. (**Default:** `'soap'`) + - `preserveWhitespace` (_boolean_): Preserve any leading and trailing whitespace characters in text and cdata. + - `escapeXML` (_boolean_): Escape special XML characters (e.g. `&`, `>`, `<` etc) in SOAP messages. (**Default:** `true`) + - `suppressStack` (_boolean_): Suppress the full stack trace for error messages. + - `returnFault` (_boolean_): Return an `Invalid XML` SOAP fault upon a bad request. (**Default:** `false`) + - `forceSoap12Headers` (_boolean_): Enable SOAP 1.2 compliance. + - `httpClient` (_Object_): Override the built-in HttpClient object with your own. Must implement `request(rurl, data, callback, exheaders, exoptions)`. + - `request` (_Object_): Override the default request module ([Axios](https://axios-http.com/) as of `v0.40.0`). + - `wsdl_headers` (_Object_): Set HTTP headers with values to be sent on WSDL requests. + - `wsdl_options` (_Object_): Set options for the request module on WSDL requests. If using the default request module, see [Request Config | Axios Docs](https://axios-http.com/docs/req_config). + - `disableCache` (_boolean_): Prevents caching WSDL files and option objects. + - `wsdlCache` (_IWSDLCache_): Custom cache implementation. If not provided, defaults to caching WSDLs indefinitely. + - `overridePromiseSuffix` (_string_): Override the default method name suffix of WSDL operations for Promise-based methods. If any WSDL operation name ends with `Async', you must use this option. (**Default:** `Async`) + - `normalizeNames` (_boolean_): Replace non-identifier characters (`[^a-z$_0-9]`) with `_` in WSDL operation names. Note: Clients using WSDLs with two operations like `soap:method` and `soap-method` will be overwritten. In this case, you must use bracket notation instead (`client['soap:method']()`). + - `namespaceArrayElements` (_boolean_): Support non-standard array semantics. JSON arrays of the form `{list: [{elem: 1}, {elem: 2}]}` will be marshalled into XML as `1 2`. If `false`, it would be marshalled into ` 1 2 `. (**Default:** `true`) + - `stream` (_boolean_): Use streams to parse the XML SOAP responses. (**Default:** `false`) + - `returnSaxStream` (_boolean_): Return the SAX stream, transferring responsibility of parsing XML to the end user. Only valid when the _stream_ option is set to `true`. (**Default:** `false`) + - `parseReponseAttachments` (_boolean_): Treat response as multipart/related response with MTOM attachment. Reach attachments on the `lastResponseAttachments` property of SoapClient. (**Default:** `false`) + - `encoding` (_string_): Response data enconding, used with `parseReponseAttachments`. (**Default:** `utf8`) + - `forceUseSchemaXmlns` (_boolean_): Force to use schema xmlns when schema prefix not found, this is needed when schema prefix is different for the same namespace in different files, for example wsdl and in imported xsd file fir complex types (**Default** `false`) +- `callback` (_Function_): + - `err` (_Error_ | _\_) + - `result` (_Any_) +- Returns: `Client` + +#### Example + +HTTP/HTTPS: + +```javascript +var soap = require('soap'); +var url = 'http://example.com/wsdl?wsdl'; +var args = { name: 'value' }; + +soap.createClient(url, {}, function (err, client) { + client.MyFunction(args, function (err, result) { + console.log(result); }); +}); ``` -#### Options - -The `options` argument allows you to customize the client with the following properties: +XML string format: -- endpoint: to override the SOAP service's host specified in the `.wsdl` file. -- request: to override the [request](https://github.com/request/request) module. -- httpClient: to provide your own http client that implements `request(rurl, data, callback, exheaders, exoptions)`. -- forceSoap12Headers: to set proper headers for SOAP v1.2 -- envelopeKey: to set specific key instead of
<soap:Body>soap:Body>
-- wsdl_options: custom options for the request module on WSDL requests. -- wsdl_headers: custom HTTP headers to be sent on WSDL requests. +```javascript +var soap = require('soap'); +var xml = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + `; +var args = { name: 'value' }; + +soap.createClient(xml, {}, function (err, client) { + client.MyFunction(args, function (err, result) { + console.log(result); + }); +}); +``` Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses. -### soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*. -*wsdl* is an xml string that defines the service. - -``` javascript - var myService = { - MyService: { - MyPort: { - MyFunction: function(args) { - return { - name: args.name - }; - }, - - // This is how to define an asynchronous function. - MyAsyncFunction: function(args, callback) { - // do some work - callback({ - name: args.name - }); - }, - - // This is how to receive incoming headers - HeadersAwareFunction: function(args, cb, headers) { - return { - name: headers.Token - }; - }, - - // You can also inspect the original `req` - reallyDeatailedFunction: function(args, cb, headers, req) { - console.log('SOAP `reallyDeatailedFunction` request from ' + req.connection.remoteAddress); - return { - name: headers.Token - }; - } - } - } - }; +### soap.createClientAsync(url[, options]) - create a new SOAP client from a WSDL url. Also supports a local filesystem path. + +Construct a `Promise` with the given WSDL file. - var xml = require('fs').readFileSync('myservice.wsdl', 'utf8'), - server = http.createServer(function(request,response) { - response.end("404: Not Found: " + request.url); - }); +- `url` (_string_): A HTTP/HTTPS URL, XML or a local filesystem path. +- `options` (_Object_): See [soap.createClient(url[, options], callback)](#soapcreateclienturl-options-callback---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path) for a description. +- Returns: `Promise` - server.listen(8000); - soap.listen(server, '/wsdl', myService, xml); +#### Example + +```javascript +var soap = require('soap'); +var url = 'http://example.com/wsdl?wsdl'; +var args = { name: 'value' }; + +// then/catch +soap + .createClientAsync(url) + .then((client) => { + return client.MyFunctionAsync(args); + }) + .then((result) => { + console.log(result); + }); + +// async/await +var client = await soap.createClientAsync(url); +var result = await client.MyFunctionAsync(args); +console.log(result[0]); ``` -### Options -You can pass in server and [WSDL Options](#handling-xml-attributes-value-and-xml-wsdloptions) -using an options hash. +Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses. + +### soap.listen(_server_, _path_, _services_, _wsdl_, _callback_) - create a new SOAP server that listens on _path_ and provides _services_. + +### soap.listen(_server_, _options_) - create a new SOAP server that listens on _path_ and provides _services_. + +- `server` (_Object_): A [http](https://nodejs.org/api/http.html) server or [Express](http://expressjs.com/) framework based server. +- `path` (_string_) +- `options` (_Object_): An object containing _server options_ and [WSDL Options](#handling-xml-attributes-value-and-xml-wsdloptions) + - `path` (_string_) + - `services` (_Object_) + - `xml` (_string_) + - `uri` (_string_) + - `pfx` (_string_ | _Buffer_): The private key, certificate and CA certs of the server in PFX or PKCS12 format. (Mutually exclusive with the key, cert and ca options.) + - `key` (_string_ | _Buffer_): The private key of the server in PEM format. (Could be an array of keys). (Required) + - `passphrase` (_string_): The passphrase for the private key or pfx. + - `cert` (_string_ | _Buffer_): The certificate key of the server in PEM format. (Could be an array of certs). (Required) + - `ca` (_string[]_ | _Buffer[]_): Trusted certificates in PEM format. If this is omitted several well known "root" CAs will be used, like VeriSign. These are used to authorize connections. + - `crl` (_string_ | _string[]_: PEM encoded CRLs (Certificate Revocation List) + - `ciphers` (_string_): A description of the ciphers to use or exclude, separated by `:`. The default cipher suite is: + - `enableChunkedEncoding` (_boolean_): Controls chunked transfer encoding in response. Some clients (such as Windows 10's MDM enrollment SOAP client) are sensitive to transfer-encoding mode and can't accept chunked response. This option lets users disable chunked transfer encoding for such clients. (**Default:** `true`) +- `services` (_Object_) +- `wsdl` (_string_): An XML string that defines the service. +- `callback` (_Function_): A function to run after the server has been initialized. +- Returns: `Server` + +#### Example + +```javascript +var myService = { + MyService: { + MyPort: { + MyFunction: function (args) { + return { + name: args.name, + }; + }, + + // This is how to define an asynchronous function with a callback. + MyAsyncFunction: function (args, callback) { + // do some work + callback({ + name: args.name, + }); + }, + + // This is how to define an asynchronous function with a Promise. + MyPromiseFunction: function (args) { + return new Promise((resolve) => { + // do some work + resolve({ + name: args.name, + }); + }); + }, + + // This is how to receive incoming headers + HeadersAwareFunction: function (args, cb, headers) { + return { + name: headers.Token, + }; + }, + + // You can also inspect the original `req` + reallyDetailedFunction: function (args, cb, headers, req) { + console.log('SOAP `reallyDetailedFunction` request from ' + req.connection.remoteAddress); + return { + name: headers.Token, + }; + }, + }, + }, +}; + +var xml = require('fs').readFileSync('myservice.wsdl', 'utf8'); + +//http server example +var server = http.createServer(function (request, response) { + response.end('404: Not Found: ' + request.url); +}); + +server.listen(8000); +soap.listen(server, '/wsdl', myService, xml, function () { + console.log('server initialized'); +}); + +//express server example +var app = express(); +//body parser middleware are supported (optional) +app.use( + bodyParser.raw({ + type: function () { + return true; + }, + limit: '5mb', + }), +); +app.listen(8001, function () { + //Note: /wsdl route will be handled by soap module + //and all other routes & middleware will continue to work + soap.listen(app, '/wsdl', myService, xml, function () { + console.log('server initialized'); + }); +}); +``` -``` javascript +```javascript var xml = require('fs').readFileSync('myservice.wsdl', 'utf8'); soap.listen(server, { - // Server options. - path: '/wsdl', - services: myService, - xml: xml, - - // WSDL options. - attributesKey: 'theAttrs', - valueKey: 'theVal', - xmlKey: 'theXml' + // Server options. + path: '/wsdl', + services: myService, + xml: xml, + + // WSDL options. + attributesKey: 'theAttrs', + valueKey: 'theVal', + xmlKey: 'theXml', }); ``` ### Server Logging -If the `log` method is defined it will be called with 'received' and 'replied' -along with data. +If the `log` method is defined, it will be called with: + +- `type`: 'received', 'replied', 'info' or 'error'. +- `data`: The data to be logged which will be an XML for 'received' and 'replied' or a message for the other types. +- `req`: The original request object -``` javascript +```javascript server = soap.listen(...) - server.log = function(type, data) { - // type is 'received' or 'replied' + server.log = function(type, data, req) { + // type is 'received', 'replied', 'info' or 'error' }; ``` @@ -179,51 +355,85 @@ along with data. Server instances emit the following events: -* request - Emitted for every received messages. +- request - Emitted for every received messages. The signature of the callback is `function(request, methodName)`. -* headers - Emitted when the SOAP Headers are not empty. +- response - Emitted before sending SOAP response. + The signature of the callback is `function(response, methodName)`. +- headers - Emitted when the SOAP Headers are not empty. The signature of the callback is `function(headers, methodName)`. The sequence order of the calls is `request`, `headers` and then the dedicated service method. +### Server Response on one-way calls + +The so called one-way (or asynchronous) calls occur when an operation is called with no output defined in WSDL. +The server sends a response (defaults to status code 200 with no body) to the client disregarding the result of the operation. + +You can configure the response to match the appropriate client expectation to the SOAP standard implementation. +Pass in `oneWay` object in server options. Use the following keys: +`emptyBody`: if true, returns an empty body, otherwise no content at all (default is false) +`responseCode`: default statusCode is 200, override it with this options (for example 202 for SAP standard compliant response) + ### SOAP Fault A service method can reply with a SOAP Fault to a client by `throw`ing an object with a `Fault` property. -``` javascript - throw { - Fault: { - Code: { - Value: "soap:Sender", - Subcode: { value: "rpc:BadArguments" } - }, - Reason: { Text: "Processing Error" } - } - }; +```javascript +throw { + Fault: { + Code: { + Value: 'soap:Sender', + Subcode: { value: 'rpc:BadArguments' }, + }, + Reason: { Text: 'Processing Error' }, + }, +}; ``` -To change the HTTP statusCode of the response include it on the fault. The statusCode property will not be put on the xml message. +To change the HTTP statusCode of the response include it on the fault. The statusCode property will not be put on the xml message. -``` javascript - throw { - Fault: { - Code: { - Value: "soap:Sender", - Subcode: { value: "rpc:BadArguments" } - }, - Reason: { Text: "Processing Error" }, - statusCode: 500 - } - }; +```javascript +throw { + Fault: { + Code: { + Value: 'soap:Sender', + Subcode: { value: 'rpc:BadArguments' }, + }, + Reason: { Text: 'Processing Error' }, + statusCode: 500, + }, +}; ``` ### Server security example using PasswordDigest If `server.authenticate` is not defined then no authentication will take place. -``` javascript +Asynchronous authentication: + +```javascript + server = soap.listen(...) + server.authenticate = function(security, callback) { + var created, nonce, password, user, token; + token = security.UsernameToken, user = token.Username, + password = token.Password, nonce = token.Nonce, created = token.Created; + + myDatabase.getUser(user, function (err, dbUser) { + if (err || !dbUser) { + callback(false); + return; + } + + callback(password === soap.passwordDigest(nonce, created, dbUser.password)); + }); + }; +``` + +Synchronous authentication: + +```javascript server = soap.listen(...) server.authenticate = function(security) { var created, nonce, password, user, token; @@ -239,21 +449,20 @@ The `server.authorizeConnection` method is called prior to the soap service meth If the method is defined and returns `false` then the incoming connection is terminated. -``` javascript +```javascript server = soap.listen(...) server.authorizeConnection = function(req) { return true; // or false }; ``` - ## SOAP Headers ### Received SOAP Headers A service method can look at the SOAP headers by providing a 3rd arguments. -``` javascript +```javascript { HeadersAwareFunction: function(args, cb, headers) { return { @@ -267,7 +476,7 @@ It is also possible to subscribe to the 'headers' event. The event is triggered before the service method is called, and only when the SOAP Headers are not empty. -``` javascript +```javascript server = soap.listen(...) server.on('headers', function(headers, methodName) { // It is possible to change the value of the headers @@ -285,219 +494,789 @@ second parameter is the name of the SOAP method that will called Both client & server can define SOAP headers that will be added to what they send. They provide the following methods to manage the headers. +#### _addSoapHeader_(soapHeader[, name, namespace, xmlns]) - add soapHeader to soap:Header node -#### *addSoapHeader*(soapHeader[, name, namespace, xmlns]) - add soapHeader to soap:Header node ##### Parameters - - `soapHeader` Object({rootName: {name: "value"}}) or strict xml-string + +- `soapHeader` Object({rootName: {name: 'value'}}), strict xml-string, + or function (server only) + +For servers only, `soapHeader` can be a function, which allows headers to be +dynamically generated from information in the request. This function will be +called with the following arguments for each received request: + +- `methodName` The name of the request method +- `args` The arguments of the request +- `headers` The headers in the request +- `req` The original request object + +The return value of the function must be an Object({rootName: {name: 'value'}}) +or strict xml-string, which will be inserted as an outgoing header of the +response to that request. + +For example: + +```javascript + server = soap.listen(...); + server.addSoapHeader(function(methodName, args, headers, req) { + console.log('Adding headers for method', methodName); + return { + MyHeader1: args.SomeValueFromArgs, + MyHeader2: headers.SomeRequestHeader + }; + // or you can return "SomeValue" + }); +``` ##### Returns + The index where the header is inserted. ##### Optional parameters when first arg is object : - - `name` Unknown parameter (it could just a empty string) - - `namespace` prefix of xml namespace - - `xmlns` URI -#### *changeSoapHeader*(index, soapHeader[, name, namespace, xmlns]) - change an already existing soapHeader +- `name` Unknown parameter (it could just a empty string) +- `namespace` prefix of xml namespace +- `xmlns` URI + +#### _changeSoapHeader_(index, soapHeader[, name, namespace, xmlns]) - change an already existing soapHeader + ##### Parameters - - `index` index of the header to replace with provided new value - - `soapHeader` Object({rootName: {name: "value"}}) or strict xml-string -#### *getSoapHeaders*() - return all defined headers +- `index` index of the header to replace with provided new value +- `soapHeader` Object({rootName: {name: 'value'}}), strict xml-string + or function (server only) + +See `addSoapHeader` for how to pass a function into `soapHeader`. -#### *clearSoapHeaders*() - remove all defined headers +#### _getSoapHeaders_() - return all defined headers +#### _clearSoapHeaders_() - remove all defined headers ## Client -An instance of `Client` is passed to the `soap.createClient` callback. It is used to execute methods on the soap service. +An instance of `Client` is passed to the `soap.createClient` callback. It is used to execute methods on the soap service. ### Client.describe() - description of services, ports and methods as a JavaScript object -``` javascript - client.describe() // returns - { - MyService: { - MyPort: { - MyFunction: { - input: { - name: 'string' - } - } +```javascript +client.describe(); // returns +{ + MyService: { + MyPort: { + MyFunction: { + input: { + name: 'string'; } } } + } +} ``` ### Client.setSecurity(security) - use the specified security protocol -`node-soap` has several default security protocols. You can easily add your own -as well. The interface is quite simple. Each protocol defines 2 methods: -* `addOptions` - a method that accepts an options arg that is eventually passed directly to `request` -* `toXML` - a method that returns a string of XML. -By default there are 3 protocols: +See [Security](#security) for example usage. -####BasicAuthSecurity +### Client._method_(args, callback, options) - call _method_ on the SOAP service. -``` javascript - client.setSecurity(new soap.BasicAuthSecurity('username', 'password')); -``` +- `args` (_Object_): Arguments that generate an XML document inside of the SOAP Body section. +- `callback` (_Function_) +- `options` (_Object_): Set options for the request module on WSDL requests. If using the default request module, see [Request Config | Axios Docs](https://axios-http.com/docs/req_config). Additional options supported by `node-soap` are documented below: + - `forever` (_boolean_): Enables keep-alive connections and pools them + - `attachments` (_Array_): array of attachment objects. This converts the request into MTOM: _headers['Content-Type']='multipart/related; type="application/xop+xml"; start= ... '_ -####ClientSSLSecurity -_Note_: If you run into issues using this protocol, consider passing these options -as default request options to the constructor: -* `rejectUnauthorized: false` -* `strictSSL: false` -* `secureOptions: constants.SSL_OP_NO_TLSv1_2` (this is likely needed for node >= 10.0) + ``` + [{ + mimetype: content mimetype, + contentId: part id, + name: file name, + body: binary data + }, + ... + ] + ``` -``` javascript - client.setSecurity(new soap.ClientSSLSecurity( - '/path/to/key' - , '/path/to/cert' - , {/*default request options*/} - )); -``` + - `forceMTOM` (_boolean_): Send the request as MTOM even if you don't have attachments. + - `forceGzip` (_boolean_): Force transfer-encoding in gzip. (**Default:** `false`) -####WSSecurity +#### Example -``` javascript - client.setSecurity(new soap.WSSecurity('username', 'password')) +```javascript +client.MyFunction({ name: 'value' }, function (err, result, rawResponse, soapHeader, rawRequest) { + // result is a javascript object + // rawResponse is the raw xml response string + // soapHeader is the response soap header as a javascript object + // rawRequest is the raw xml request string +}); ``` -####WSSecurity with X509 Certificate +### Client.*method*Async(args, options) - call _method_ on the SOAP service. + +- `args` (_Object_): Arguments that generate an XML document inside of the SOAP Body section. +- `options` (_Object_): See [Client._method_(args, callback, options) - call _method_ on the SOAP service.](#clientmethodargs-callback-options---call-method-on-the-soap-service) for a description. + +#### Example -``` javascript - var privateKey = fs.readFileSync(privateKeyPath); - var publicKey = fs.readFileSync(publicKeyPath); - var password = ''; // optional password - var wsSecurity = new soap.WSSecurityCert(privateKey, publicKey, password, 'utf8'); - client.setSecurity(wsSecurity); +```javascript +client.MyFunctionAsync({ name: 'value' }).then((result) => { + // result is a javascript array containing result, rawResponse, soapheader, and rawRequest + // result is a javascript object + // rawResponse is the raw xml response string + // soapHeader is the response soap header as a javascript object + // rawRequest is the raw xml request string +}); ``` -####BearerSecurity +##### Example with JSON for the `args` -``` javascript - client.setSecurity(new soap.BearerSecurity('token')); +The example above uses `{name: 'value'}` as the args. This may generate a SOAP messages such as: + +```javascript + + + + + value + + + ``` -### Client.*method*(args, callback) - call *method* on the SOAP service. +Note that the "Request" element in the output above comes from the WSDL. If an element in `args` contains no namespace prefix, the default namespace is assumed. Otherwise, you must add the namespace prefixes to the element names as necessary (e.g., `ns1:name`). -``` javascript - client.MyFunction({name: 'value'}, function(err, result, raw, soapHeader) { - // result is a javascript object - // raw is the raw response - // soapHeader is the response soap header as a javascript object - }) +Currently, when supplying JSON args, elements may not contain both child elements and a text value, even though that is allowed in the XML specification. + +##### Example with XML String for the `args` + +You may pass in a fully-formed XML string instead the individual elements in JSON `args` and attributes that make up the XML. The XML string should not contain an XML declaration (e.g., ``) or a document type declaration (e.g., ``). + +``` + var args = { _xml: " + elementvalue + " + }; ``` -### Client.*service*.*port*.*method*(args, callback[, options[, extraHeaders]]) - call a *method* using a specific *service* and *port* -``` javascript - client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) { - // result is a javascript object - }) +You must specify all of the namespaces and namespace prefixes yourself. The element(s) from the WSDL are not utilized as they were in the "Example with JSON as the `args`" example above, which automatically populated the "Request" element. + +### Client._service_._port_._method_(args, callback[, options[, extraHeaders]]) - call a _method_ using a specific _service_ and _port_ + +- `args` (_Object_): Arguments that generate an XML document inside of the SOAP Body section. +- `callback` (_Function_) +- `options` (_Object_): See [Client._method_(args, callback, options) - call _method_ on the SOAP service.](#clientmethodargs-callback-options---call-method-on-the-soap-service) for a description. +- `extraHeaders` (_Object_): Sets HTTP headers for the WSDL request. + +#### Example + +```javascript +client.MyService.MyPort.MyFunction({ name: 'value' }, function (err, result) { + // result is a javascript object +}); ``` #### Options (optional) - - Accepts any option that the request module accepts, see [here.](https://github.com/mikeal/request) - - For example, you could set a timeout of 5 seconds on the request like this: -``` javascript - client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) { - // result is a javascript object - }, {timeout: 5000}) + +- Accepts any option that the request module accepts, see [here.](https://github.com/mikeal/request) +- For example, you could set a timeout of 5 seconds on the request like this: + +```javascript +client.MyService.MyPort.MyFunction( + { name: 'value' }, + function (err, result) { + // result is a javascript object + }, + { timeout: 5000 }, +); ``` - You can measure the elapsed time on the request by passing the time option: -``` javascript - client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) { - // client.lastElapsedTime - the elapsed time of the last request in milliseconds - }, {time: true}) + +```javascript +client.MyService.MyPort.MyFunction( + { name: 'value' }, + function (err, result) { + // client.lastElapsedTime - the elapsed time of the last request in milliseconds + }, + { time: true }, +); +``` + +- Also, you could pass your soap request through a debugging proxy such as [Fiddler](http://www.telerik.com/fiddler) or [Betwixt](https://github.com/kdzwinel/betwixt). + +```javascript +client.MyService.MyPort.MyFunction( + { name: 'value' }, + function (err, result) { + // client.lastElapsedTime - the elapsed time of the last request in milliseconds + }, + { + proxy: { + protocol: 'https', + host: '127.0.0.1', + port: 9000, + auth: { + username: 'mikeymike', + password: 'rapunz3l', + }, + }, + }, +); +``` + +- You can modify xml (string) before call: + +```javascript +client.MyService.MyPort.MyFunction( + { name: 'value' }, + function (err, result) { + // client.lastElapsedTime - the elapsed time of the last request in milliseconds + }, + { + postProcess: function (_xml) { + return _xml.replace('text', 'newtext'); + }, + }, +); ``` #### Extra Headers (optional) Object properties define extra HTTP headers to be sent on the request. +- Add custom User-Agent: + +```javascript +client.addHttpHeader('User-Agent', `CustomUserAgent`); +``` + #### Alternative method call using callback-last pattern To align method call signature with node' standard callback-last patter and event allow promisification of method calls, the following method signatures are also supported: ```javascript -client.MyService.MyPort.MyFunction({name: 'value'}, options, function (err, result) { +client.MyService.MyPort.MyFunction({ name: 'value' }, options, function (err, result) { // result is a javascript object -}) +}); -client.MyService.MyPort.MyFunction({name: 'value'}, options, extraHeaders, function (err, result) { +client.MyService.MyPort.MyFunction({ name: 'value' }, options, extraHeaders, function (err, result) { // result is a javascript object -}) +}); ``` -###Overriding the namespace prefix -`node-soap` is still working out some kinks regarding namespaces. If you find that an element is given the wrong namespace prefix in the request body, you can add the prefix to it's name in the containing object. I.E.: +### Overriding the namespace prefix + +`node-soap` is still working out some kinks regarding namespaces. If you find that an element is given the wrong namespace prefix in the request body, you can add the prefix to it's name in the containing object. I.E.: ```javascript - client.MyService.MyPort.MyFunction({'ns1:name': 'value'}, function(err, result) { - // request body sent with `${body}`; + + const res = await httpClient.post(`${baseURL}/ProcessProspect`, data); + // Optionally, deserialize request and return response status. +} +``` + +## Security + +`node-soap` has several default security protocols. You can easily add your own +as well. The interface is quite simple. Each protocol defines these optional methods: + +- `addOptions(options)` - a method that accepts an options arg that is eventually passed directly to `request`. +- `addHeaders(headers)` - a method that accepts an argument with HTTP headers, to add new ones. +- `toXML()` - a method that returns a string of XML to be appended to the SOAP headers. Not executed if `postProcess` is also defined. +- `postProcess(xml, envelopeKey)` - a method that receives the the assembled request XML plus envelope key, and returns a processed string of XML. Executed before `options.postProcess`. + +### BasicAuthSecurity + +```javascript +client.setSecurity(new soap.BasicAuthSecurity('username', 'password')); +``` + +### BearerSecurity + +```javascript +client.setSecurity(new soap.BearerSecurity('token')); +``` + +### ClientSSLSecurity + +_Note_: If you run into issues using this protocol, consider passing these options +as default request options to the constructor: + +- `rejectUnauthorized: false` +- `strictSSL: false` +- `secureOptions: constants.SSL_OP_NO_TLSv1_2` (this is likely needed for node >= 10.0) + +If you want to reuse tls sessions, you can use the option `forever: true`. + +```javascript +client.setSecurity( + new soap.ClientSSLSecurity( + '/path/to/key', + 'path/to/cert', + '/path/to/ca-cert' /*or an array of buffer: [fs.readFileSync('/path/to/ca-cert/1', 'utf8'), + 'fs.readFileSync('/path/to/ca-cert/2', 'utf8')], */, + { + /*default request options like */ + // strictSSL: true, + // rejectUnauthorized: false, + // hostname: 'some-hostname' + // secureOptions: constants.SSL_OP_NO_TLSv1_2, + // forever: true, + }, + ), +); +``` + +### ClientSSLSecurityPFX + +_Note_: If you run into issues using this protocol, consider passing these options +as default request options to the constructor: + +- `rejectUnauthorized: false` +- `strictSSL: false` +- `secureOptions: constants.SSL_OP_NO_TLSv1_2` (this is likely needed for node >= 10.0) + +If you want to reuse tls sessions, you can use the option `forever: true`. + +```javascript +client.setSecurity( + new soap.ClientSSLSecurityPFX( + '/path/to/pfx/cert', // or a buffer: [fs.readFileSync('/path/to/pfx/cert', 'utf8'), + 'path/to/optional/passphrase', + { + /*default request options like */ + // strictSSL: true, + // rejectUnauthorized: false, + // hostname: 'some-hostname' + // secureOptions: constants.SSL_OP_NO_TLSv1_2, + // forever: true, + }, + ), +); +``` + +### WSSecurity + +`WSSecurity` implements WS-Security. UsernameToken and PasswordText/PasswordDigest is supported. + +```javascript +var options = { + hasNonce: true, + actor: 'actor', +}; +var wsSecurity = new soap.WSSecurity('username', 'password', options); +client.setSecurity(wsSecurity); +``` + +the `options` object is optional and can contain the following properties: + +- `passwordType`: 'PasswordDigest' or 'PasswordText' (default: `'PasswordText'`) +- `hasTimeStamp`: adds Timestamp element (default: `true`) +- `hasTokenCreated`: adds Created element (default: `true`) +- `hasNonce`: adds Nonce element (default: `false`) +- `mustUnderstand`: adds mustUnderstand=1 attribute to security tag (default: `false`) +- `actor`: if set, adds Actor attribute with given value to security tag (default: `''`) +- `appendElement`: A string containing XML element to append to the end of the WSSecurity element. This can be used to add custom elements like certificates or other security tokens (default: `''`) + +### WSSecurityCert + +WS-Security X509 Certificate support. + +```javascript +var privateKey = fs.readFileSync(privateKeyPath); +var publicKey = fs.readFileSync(publicKeyPath); +var password = ''; // optional password +var options = { + hasTimeStamp: true, + additionalReferences: ['wsa:Action', 'wsa:ReplyTo', 'wsa:To'], + signerOptions: { + prefix: 'ds', + attrs: { Id: 'Signature' }, + existingPrefixes: { + wsse: 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', + }, + }, +}; +var wsSecurity = new soap.WSSecurityCert(privateKey, publicKey, password, options); +client.setSecurity(wsSecurity); +``` + +The `options` object is optional and can contain the following properties: + +- `hasTimeStamp`: Includes Timestamp tags (default: `true`) +- `signatureTransformations`: sets the Reference Transforms Algorithm (default ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#']). Type is a string array +- `signatureAlgorithm`: set to `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256` to use sha256 +- `digestAlgorithm`: set to `http://www.w3.org/2000/09/xmldsig#sha1` to use sha1 (default `http://www.w3.org/2001/04/xmlenc#sha256`) +- `additionalReferences` : (optional) Array of Soap headers that need to be signed. This need to be added using `client.addSoapHeader('header')` +- `excludeReferencesFromSigning`: (Optional) An array of SOAP element names to exclude from signing (e.g., `Body`, `Timestamp`, `To`, `Action`). +- `signerOptions`: (optional) passes options to the XML Signer package - from (https://github.com/yaronn/xml-crypto) + - `existingPrefixes`: (optional) A hash of prefixes and namespaces prefix: namespace that shouldn't be in the signature because they already exist in the xml (default: `{ 'wsse': 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' }`) + - `prefix`: (optional) Adds this value as a prefix for the generated signature tags. + - `attrs`: (optional) A hash of attributes and values attrName: value to add to the signature root node + - `idMode`: (optional) either 'wssecurity' to generate wsse-scoped reference Id on or undefined for an unscoped reference Id +- `appendElement`: (optional) A string containing XML element to append to the end of the WSSecurity element. This can be used to add custom elements like certificates or other security tokens. + +### WSSecurityPlusCert + +Use WSSecurity and WSSecurityCert together. + +```javascript +var wsSecurity = new soap.WSSecurity(/* see WSSecurity above */); +var wsSecurityCert = new soap.WSSecurityCert(/* see WSSecurityCert above */); +var wsSecurityPlusCert = new soap.WSSecurityPlusCert(wsSecurity, wsSecurityCert); +client.setSecurity(wsSecurityPlusCert); +``` + +#### Option examples + +`hasTimeStamp:true` + +```xml + + + XXX + + + 2019-10-01T08:17:50Z + 2019-10-01T08:27:50Z + + + + ... + + + + + + + XyZ= + + + + + +``` + +`additionalReferences: ['To']` + +```XML + + localhost.com + + XXX + + + + + + + + + + + + XYZ + + + + Rf6M4F4puQuQHJIPtJz1CZIVvF3qOdpEEcuAiooWkX5ecnAHSf3RW3sOIzFUWW7VOOncJcts/3xr8DuN4+8Wm9hx1MoOcWJ6kyRIdVNbQWLseIcAhxYCntRY57T2TBXzpb0UPA56pry1+TEcnIQXhdIzG5YT+tTVTp+SZHHcnlP5Y+yqnIOH9wzgRvAovbydTYPCODF7Ana9K/7CSGDe7vpVT85CUYUcJE4DfTxaRa9gKkKrBdPN9vFVi0WfxtMF4kv23cZRCZzS5+CoLfPlx3mq65gVXsqH01RLbktNJq9VaQKcZUgapmUCMzrYhqyzUQJ8HrSHqe+ya2GsjlB0VQ== + + + + + + + + + +``` + +`signerOptions.prefix:'ds'` + +```XML + + localhost.com + + XXX + + + + + + + + + + + + XYZ + + + + Rf6M4F4puQuQHJIPtJz1CZIVvF3qOdpEEcuAiooWkX5ecnAHSf3RW3sOIzFUWW7VOOncJcts/3xr8DuN4+8Wm9hx1MoOcWJ6kyRIdVNbQWLseIcAhxYCntRY57T2TBXzpb0UPA56pry1+TEcnIQXhdIzG5YT+tTVTp+SZHHcnlP5Y+yqnIOH9wzgRvAovbydTYPCODF7Ana9K/7CSGDe7vpVT85CUYUcJE4DfTxaRa9gKkKrBdPN9vFVi0WfxtMF4kv23cZRCZzS5+CoLfPlx3mq65gVXsqH01RLbktNJq9VaQKcZUgapmUCMzrYhqyzUQJ8HrSHqe+ya2GsjlB0VQ== + + + + + + + + + +``` + +`signerOptions.attrs:{ Id: 'signature-100', foo:'bar'}` + +```xml + + + XXX + + + 2019-10-01T08:17:50Z + 2019-10-01T08:27:50Z + + + + ... + + + + + + + XyZ= + + + + + +``` + +`appendElement: 'test'` + +```xml + + + XXX + + + ... + + + + + foo + + + +``` + +### WSSecurityCertWithToken + +WS-Security X509 Certificate support. Just like WSSecurityCert, except that it accepts the input properties as a single object, with two properties added `username` and `password`. Which if added, will add a UsernameToken Element to the xml security element. + +```xml + + someusername + someusername's password + +``` + +### NTLMSecurity + +Parameter invocation: + +```javascript +client.setSecurity(new soap.NTLMSecurity('username', 'password', 'domain', 'workstation')); +``` + +This can also be set up with a JSON object, substituting values as appropriate, for example: + +```javascript +var loginData = { username: 'username', password: 'password', domain: 'domain', workstation: 'workstation' }; +client.setSecurity(new soap.NTLMSecurity(loginData)); ``` ## Handling XML Attributes, Value and XML (wsdlOptions). + Sometimes it is necessary to override the default behaviour of `node-soap` in order to deal with the special requirements of your code base or a third library you use. Therefore you can use the `wsdlOptions` Object, which is passed in the `#createClient()` method and could have any (or all) of the following contents: + ```javascript var wsdlOptions = { attributesKey: 'theAttrs', valueKey: 'theVal', - xmlKey: 'theXml' -} + xmlKey: 'theXml', +}; ``` + If nothing (or an empty Object `{}`) is passed to the `#createClient()` method, the `node-soap` defaults (`attributesKey: 'attributes'`, `valueKey: '$value'` and `xmlKey: '$xml'`) are used. -###Overriding the `value` key -By default, `node-soap` uses `$value` as key for any parsed XML value which may interfere with your other code as it +### Overriding the `value` key + +By default, `node-soap` uses `$value` as the key for any parsed XML value which may interfere with your other code as it could be some reserved word, or the `$` in general cannot be used for a key to start with. -You can define your own `valueKey` by passing it in the `wsdl_options` to the createClient call like so: +You can define your own `valueKey` by passing it in the `wsdl_options` to the createClient call: + ```javascript var wsdlOptions = { - valueKey: 'theVal' + valueKey: 'theVal', }; soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) { @@ -505,29 +1284,53 @@ soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, funct }); ``` -###Overriding the `xml` key -As `valueKey`, `node-soap` uses `$xml` as key. The xml key is used to pass XML Object without adding namespace or parsing the string. +### Overriding the `xml` key -Example : +By default, `node-soap` uses `$xml` as the key to pass through an XML string as is; without parsing or namespacing it. It overrides all the other content that the node might have otherwise had. + +For example : ```javascript -dom = { - $xml: '' +{ + dom: { + nodeone: { + $xml: '', + siblingnode: 'Cant see me.' + }, + nodetwo: { + parentnode: { + attributes: { + type: 'type' + }, + childnode: '' + } + } + } }; ``` +could become + ```xml + - + + + + + + + ``` -You can define your own `xmlKey` by passing it in the `wsdl_options` to the createClient call like so: +You can define your own `xmlKey` by passing it in the `wsdl_options` object to the createClient call: + ```javascript var wsdlOptions = { - xmlKey: 'theXml' + xmlKey: 'theXml', }; soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) { @@ -535,199 +1338,259 @@ soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, funct }); ``` -###Overriding the `attributes` key -You can achieve attributes like: -``` xml - - - - -``` -By attaching an attributes object to a node. -``` javascript +### Overriding the `attributes` key + +By default, `node-soap` uses `attributes` as the key to define a nodes attributes. + +```javascript { parentnode: { childnode: { attributes: { name: 'childsname' - } + }, + $value: 'Value' } } } ``` -However, "attributes" may be a reserved key for some systems that actually want a node + +could become + +```xml + + Value + +``` + +However, `attributes` may be a reserved key for some systems that actually want a node called `attributes` + ```xml ``` -In this case you can configure the attributes key in the `wsdlOptions` like so. +You can define your own `attributesKey` by passing it in the `wsdl_options` object to the createClient call: + ```javascript var wsdlOptions = { - attributesKey: '$attributes' + attributesKey: '$attributes', }; soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) { - client.*method*({ + client.method({ parentnode: { childnode: { $attributes: { - name: 'childsname' + name: 'childsname', + }, + $value: 'Value', + }, + }, + }); +}); +``` + +### Overriding imports relative paths + +By default, WSDL and schema files import other schemas and types using relative paths. + +However in some systems (i.e. NetSuite) when the wsdl is downloaded for offline caching, all files are flattened under a single directory and all the imports fail. +Passing this option allows `node-soap` to correctly load all files. + +```javascript +var options ={ + wsdl_options = { fixedPath: true } +}; +soap.createClient(__dirname+'/wsdl/fixedPath/netsuite.wsdl', options, function(err, client) { + // your code +}); +``` + +### Overriding import locations + +You can override the URIs or paths of imports in the WSDL by specifying a `overrideImportLocation` function in the WSDL options. + +```javascript +const options ={ + wsdl_options = { + overrideImportLocation: (location) => { + return 'https://127.0.0.1/imported-service.wsdl'; } - } } - }); +}; +soap.createClient('https://127.0.0.1/service.wsdl', options, function(err, client) { + // your code }); ``` + ### Specifying the exact namespace definition of the root element + In rare cases, you may want to precisely control the namespace definition that is included in the root element. -You can specify the namespace definitions by setting the overrideRootElement key in the `wsdlOptions` like so: +You can specify the namespace definitions by setting the `overrideRootElement` key in the `wsdlOptions` like so: + ```javascript var wsdlOptions = { - "overrideRootElement": { - "namespace": "xmlns:tns", - "xmlnsAttributes": [{ - "name": "xmlns:ns2", - "value": "http://tempuri.org/" - }, { - "name": "xmlns:ns3", - "value": "http://sillypets.com/xsd" - }] - } + overrideRootElement: { + namespace: 'xmlns:tns', + xmlnsAttributes: [ + { + name: 'xmlns:ns2', + value: 'http://tempuri.org/', + }, + { + name: 'xmlns:ns3', + value: 'http://sillypets.com/xsd', + }, + ], + }, +}; +``` + +To see it in practice, have a look at the sample files in: [test/request-response-samples/addPets\_\_force_namespaces](https://github.com/vpulim/node-soap/tree/master/test/request-response-samples/addPets__force_namespaces) + +### Overriding element key specification in XML + +In very rare cases ([external implementation isn't matching exactly the WSDL spec?](https://github.com/vpulim/node-soap/pull/1189)), +you may want to override element XML keys in requests and/or responses. + +You can specify the key definitions by setting the `overrideElementKey` key in the `wsdlOptions` like so: + +```javascript +var wsdlOptions = { + overrideElementKey: { + Nom: 'Name', + Commande: 'Order', + SillyResponse: 'DummyResponse' + }; }; ``` -To see it in practice, consider the sample files in: [test/request-response-samples/addPets__force_namespaces](https://github.com/vpulim/node-soap/tree/master/test/request-response-samples/addPets__force_namespaces) +Test sample files covering this are in [test/request-response-samples/Dummy\_\_ref_element_should_have_correct_namespace_with_overrideElementKey](https://github.com/vpulim/node-soap/tree/master/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey) + +### Custom Deserializer + +Sometimes it's useful to handle deserialization in your code instead of letting node-soap do it. +For example if the soap response contains dates that are not in a format recognized by javascript, you might want to use your own function to handle them. + +To do so, you can pass a `customDeserializer` object in `options`. The properties of this object are the types that your deserializer handles itself. + +Example : +```javascript + + var wsdlOptions = { + customDeserializer: { + + // this function will be used to any date found in soap responses + date: function (text, context) { + /* text is the value of the xml element. + context contains the name of the xml element and other infos : + { + name: 'lastUpdatedDate', + object: {}, + schema: 'xsd:date', + id: undefined, + nil: false + } + + */ + return text; + } + } + }; + + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', wsdlOptions, function (err, client) { + ... + }); + +``` + +### Changing the tag formats to use self-closing (empty element) tags + +The XML specification specifies that there is no semantic difference between `` and ``, and node-soap defaults to using the `` format. But if your web service is particular, or if there is a stylistic preference, the `useEmptyTag` option causes tags with no contents to use the `` format instead. + +```javascript +var wsdlOptions = { + useEmptyTag: true, +}; +``` + +For example: `{ MyTag: { attributes: { MyAttr: 'value' } } }` is: + +- **Without useEmptyTag**: `` +- **With useEmptyTag set to true**: `` ## Handling "ignored" namespaces + If an Element in a `schema` definition depends on an Element which is present in the same namespace, normally the `tns:` namespace prefix is used to identify this Element. This is not much of a problem as long as you have just one `schema` defined (inline or in a separate file). If there are more `schema` files, the `tns:` in the generated `soap` file resolved mostly to the parent `wsdl` file, - which was obviously wrong. - - `node-soap` now handles namespace prefixes which shouldn't be resolved (because it's not necessary) as so called `ignoredNamespaces` - which default to an Array of 3 Strings (`['tns', 'targetNamespace', 'typedNamespace']`). - - If this is not sufficient for your purpose you can easily add more namespace prefixes to this Array, or override it in its entirety - by passing an `ignoredNamespaces` object within the `options` you pass in `soap.createClient()` method. - - A simple `ignoredNamespaces` object, which only adds certain namespaces could look like this: - ``` - var options = { - ignoredNamespaces: { - namespaces: ['namespaceToIgnore', 'someOtherNamespace'] - } - } - ``` - This would extend the `ignoredNamespaces` of the `WSDL` processor to `['tns', 'targetNamespace', 'typedNamespace', 'namespaceToIgnore', 'someOtherNamespace']`. - - If you want to override the default ignored namespaces you would simply pass the following `ignoredNamespaces` object within the `options`: - ``` - var options = { - ignoredNamespaces: { - namespaces: ['namespaceToIgnore', 'someOtherNamespace'], - override: true - } - } - ``` - This would override the default `ignoredNamespaces` of the `WSDL` processor to `['namespaceToIgnore', 'someOtherNamespace']`. (This shouldn't be necessary, anyways). - - If you want to override the default ignored namespaces you would simply pass the following `ignoredNamespaces` object within the `options`: - ``` - var options = { - ignoredNamespaces: { - namespaces: ['namespaceToIgnore', 'someOtherNamespace'], - override: true - } - } - ``` - This would override the default `ignoredNamespaces` of the `WSDL` processor to `['namespaceToIgnore', 'someOtherNamespace']`. (This shouldn't be necessary, anyways). +which was obviously wrong. -## Handling "ignoreBaseNameSpaces" attribute -If an Element in a `schema` definition depends has a basenamespace defined but the request does not need that value, for example you have a "sentJob" with basenamespace "v20" -but the request need only: set in the tree structure, you need to set the ignoreBaseNameSpaces to true. This is set because in a lot of workaround the wsdl structure is not correctly -set or the webservice bring errors. +`node-soap` now handles namespace prefixes which shouldn't be resolved (because it's not necessary) as so called `ignoredNamespaces` +which default to an Array of 3 Strings (`['tns', 'targetNamespace', 'typedNamespace']`). -By default the attribute is set to true. -An example to use: +If this is not sufficient for your purpose you can easily add more namespace prefixes to this Array, or override it in its entirety +by passing an `ignoredNamespaces` object within the `options` you pass in `soap.createClient()` method. A simple `ignoredNamespaces` object, which only adds certain namespaces could look like this: + ``` var options = { -ignoredNamespaces: true + ignoredNamespaces: { + namespaces: ['namespaceToIgnore', 'someOtherNamespace'] + } } ``` -## soap-stub - -Unit testing services that use soap clients can be very cumbersome. In order to get -around this you can use `soap-stub` in conjunction with `sinon` to stub soap with -your clients. - -### Example +This would extend the `ignoredNamespaces` of the `WSDL` processor to `['tns', 'targetNamespace', 'typedNamespace', 'namespaceToIgnore', 'someOtherNamespace']`. -```javascript -// test-initialization-script.js -var sinon = require('sinon'); -var soapStub = require('soap/soap-stub'); - -var urlMyApplicationWillUseWithCreateClient = 'http://path-to-my-wsdl'; -var clientStub = { - SomeOperation: sinon.stub() -}; +If you want to override the default ignored namespaces you would simply pass the following `ignoredNamespaces` object within the `options`: -clientStub.SomeOperation.respondWithError = soapStub.createRespondingStub({..error json...}); -clientStub.SomeOperation.respondWithSuccess = soapStub.createRespondingStub({..success json...}); +``` +var options = { + ignoredNamespaces: { + namespaces: ['namespaceToIgnore', 'someOtherNamespace'], + override: true + } + } +``` -soapStub.registerClient('my client alias', urlMyApplicationWillUseWithCreateClient, clientStub); +This would override the default `ignoredNamespaces` of the `WSDL` processor to `['namespaceToIgnore', 'someOtherNamespace']`. (This shouldn't be necessary, anyways). -// test.js -var soapStub = require('soap/soap-stub'); +## Handling "ignoreBaseNameSpaces" attribute -describe('myService', function() { - var clientStub; - var myService; +If an Element in a `schema` definition depends has a basenamespace defined but the request does not need that value, for example you have a "sentJob" with basenamespace "v20" +but the request need only: set in the tree structure, you need to set the ignoreBaseNameSpaces to true. This is set because in a lot of workaround the wsdl structure is not correctly +set or the webservice bring errors. - beforeEach(function() { - clientStub = soapStub.getStub('my client alias'); - soapStub.reset(); - myService.init(clientStub); - }); +By default the attribute is set to true. +An example to use: - describe('failures', function() { - beforeEach(function() { - clientStub.SomeOperation.respondWithError(); - }); +A simple `ignoredNamespaces` object, which only adds certain namespaces could look like this: - it('should handle error responses', function() { - myService.somethingThatCallsSomeOperation(function(err, response) { - // handle the error response. - }); - }); - }); -}); ``` - +var options = { +ignoredNamespaces: true +} +``` ## Contributors - * Author: [Vinay Pulim](https://github.com/vpulim) - * Maintainers: - - [Joe Spencer](https://github.com/jsdevel) - - [Heinz Romirer](https://github.com/herom) - * [All Contributors](https://github.com/vpulim/node-soap/graphs/contributors) +- Author: [Vinay Pulim](https://github.com/vpulim) +- Active maintainers: + - [Vasily Martynov](https://github.com/w666) +- Previous maintainers (not active for a long time): + - [Joe Spencer](https://github.com/jsdevel) + - [Heinz Romirer](https://github.com/herom) +- [All Contributors](https://github.com/vpulim/node-soap/graphs/contributors) [downloads-image]: http://img.shields.io/npm/dm/soap.svg [npm-url]: https://npmjs.org/package/soap [npm-image]: http://img.shields.io/npm/v/soap.svg - -[travis-url]: https://travis-ci.org/vpulim/node-soap -[travis-image]: http://img.shields.io/travis/vpulim/node-soap.svg - -[gitter-url]: https://gitter.im/vpulim/node-soap -[gitter-image]: https://badges.gitter.im/vpulim/node-soap.png - [coveralls-url]: https://coveralls.io/r/vpulim/node-soap [coveralls-image]: http://img.shields.io/coveralls/vpulim/node-soap/master.svg +[buy-me-a-coffee-url]: https://coff.ee/vasily.m +[buy-me-a-coffee-image]: https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..600f0e9e8 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Reporting a Vulnerability + +If you discover a security vulnerability, please report it to current maintainer [Vasily Martynov](https://github.com/w666). We will respond as quickly as possible to address the issue. + +## Security Updates + +We will notify users about security updates through our [GitHub repository](https://github.com/node-soap/releases). diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..f30e6532e --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,15 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.recommended, + { + ignores: ['lib/', 'node_modules/', 'test/'], + }, + { + rules: { + '@typescript-eslint/no-explicit-any': 'off', + }, + }, +); diff --git a/index.js b/index.js deleted file mode 100644 index a1f02521a..000000000 --- a/index.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; - -module.exports = require('./lib/soap'); diff --git a/lib/client.js b/lib/client.js deleted file mode 100644 index f2d4a9ee4..000000000 --- a/lib/client.js +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (c) 2011 Vinay Pulim - * MIT Licensed - */ - -"use strict"; - - -var HttpClient = require('./http'), - assert = require('assert'), - events = require('events'), - util = require('util'), - debug = require('debug')('node-soap'), - findPrefix = require('./utils').findPrefix, - _ = require('lodash'); - -var Client = function(wsdl, endpoint, options) { - events.EventEmitter.call(this); - - options = options || {}; - this.wsdl = wsdl; - this._initializeOptions(options); - this._initializeServices(endpoint); - this.httpClient = options.httpClient || new HttpClient(options); -}; -util.inherits(Client, events.EventEmitter); - -Client.prototype.addSoapHeader = function(soapHeader, name, namespace, xmlns) { - if (!this.soapHeaders) { - this.soapHeaders = []; - } - if (typeof soapHeader === 'object') { - soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); - } - return this.soapHeaders.push(soapHeader) - 1; -}; - -Client.prototype.changeSoapHeader = function(index, soapHeader, name, namespace, xmlns) { - if (!this.soapHeaders) { - this.soapHeaders = []; - } - if (typeof soapHeader === 'object') { - soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); - } - this.soapHeaders[index] = soapHeader; -}; - -Client.prototype.getSoapHeaders = function() { - return this.soapHeaders; -}; - -Client.prototype.clearSoapHeaders = function() { - this.soapHeaders = null; -}; - -Client.prototype.addHttpHeader = function(name, value) { - if (!this.httpHeaders) { - this.httpHeaders = {}; - } - this.httpHeaders[name] = value; -}; - -Client.prototype.getHttpHeaders = function() { - return this.httpHeaders; -}; - -Client.prototype.clearHttpHeaders = function() { - this.httpHeaders = {}; -}; - - -Client.prototype.addBodyAttribute = function(bodyAttribute, name, namespace, xmlns) { - if (!this.bodyAttributes) { - this.bodyAttributes = []; - } - if (typeof bodyAttribute === 'object') { - var composition = ''; - Object.getOwnPropertyNames(bodyAttribute).forEach(function(prop, idx, array) { - composition += ' ' + prop + '="' + bodyAttribute[prop] + '"'; - }); - bodyAttribute = composition; - } - if (bodyAttribute.substr(0, 1) !== ' ') bodyAttribute = ' ' + bodyAttribute; - this.bodyAttributes.push(bodyAttribute); -}; - -Client.prototype.getBodyAttributes = function() { - return this.bodyAttributes; -}; - -Client.prototype.clearBodyAttributes = function() { - this.bodyAttributes = null; -}; - -Client.prototype.setEndpoint = function(endpoint) { - this.endpoint = endpoint; - this._initializeServices(endpoint); -}; - -Client.prototype.describe = function() { - var types = this.wsdl.definitions.types; - return this.wsdl.describeServices(); -}; - -Client.prototype.setSecurity = function(security) { - this.security = security; -}; - -Client.prototype.setSOAPAction = function(SOAPAction) { - this.SOAPAction = SOAPAction; -}; - -Client.prototype._initializeServices = function(endpoint) { - var definitions = this.wsdl.definitions, - services = definitions.services; - for (var name in services) { - this[name] = this._defineService(services[name], endpoint); - } -}; - -Client.prototype._initializeOptions = function(options) { - this.wsdl.options.attributesKey = options.attributesKey || 'attributes'; - this.wsdl.options.envelopeKey = options.envelopeKey || 'soap'; - this.wsdl.options.forceSoap12Headers = !!options.forceSoap12Headers; -}; - -Client.prototype._defineService = function(service, endpoint) { - var ports = service.ports, - def = {}; - for (var name in ports) { - def[name] = this._definePort(ports[name], endpoint ? endpoint : ports[name].location); - } - return def; -}; - -Client.prototype._definePort = function(port, endpoint) { - var location = endpoint, - binding = port.binding, - methods = binding.methods, - def = {}; - for (var name in methods) { - def[name] = this._defineMethod(methods[name], location); - this[name] = def[name]; - } - return def; -}; - -Client.prototype._defineMethod = function(method, location) { - var self = this; - var temp; - return function(args, callback, options, extraHeaders) { - if (typeof args === 'function') { - callback = args; - args = {}; - } else if (typeof options === 'function') { - temp = callback; - callback = options; - options = temp; - } else if (typeof extraHeaders === 'function') { - temp = callback; - callback = extraHeaders; - extraHeaders = options; - options = temp; - } - self._invoke(method, args, location, function(error, result, raw, soapHeader) { - callback(error, result, raw, soapHeader); - }, options, extraHeaders); - }; -}; - -Client.prototype._invoke = function(method, args, location, callback, options, extraHeaders) { - var self = this, - name = method.$name, - input = method.input, - output = method.output, - style = method.style, - defs = this.wsdl.definitions, - envelopeKey = this.wsdl.options.envelopeKey, - ns = defs.$targetNamespace, - encoding = '', - message = '', - xml = null, - req = null, - soapAction, - alias = findPrefix(defs.xmlns, ns), - headers = { - "Content-Type": "text/xml; charset=utf-8" - }, - xmlnsSoap = "xmlns:" + envelopeKey + "=\"http://schemas.xmlsoap.org/soap/envelope/\""; - - if (this.wsdl.options.forceSoap12Headers) { - headers["Content-Type"] = "application/soap+xml; charset=utf-8"; - xmlnsSoap = "xmlns:" + envelopeKey + "=\"http://www.w3.org/2003/05/soap-envelope\""; - } - - if (this.SOAPAction) { - soapAction = this.SOAPAction; - } else if (method.soapAction !== undefined && method.soapAction !== null) { - soapAction = method.soapAction; - } else { - soapAction = ((ns.lastIndexOf("/") !== ns.length - 1) ? ns + "/" : ns) + name; - } - - if (!this.wsdl.options.forceSoap12Headers) { - headers.SOAPAction = '"' + soapAction + '"'; - } - - options = options || {}; - - //Add extra headers - for (var header in this.httpHeaders ) { headers[header] = this.httpHeaders[header]; } - for (var attr in extraHeaders) { headers[attr] = extraHeaders[attr]; } - - // Allow the security object to add headers - if (self.security && self.security.addHeaders) - self.security.addHeaders(headers); - if (self.security && self.security.addOptions) - self.security.addOptions(options); - - if (input.parts || args === null) { - assert.ok(!style || style === 'rpc', 'invalid message definition for document style binding'); - message = self.wsdl.objectToRpcXML(name, args, alias, ns); - (method.inputSoap === 'encoded') && (encoding = 'soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" '); - } else if (typeof (args) === 'string') { - message = args; - } else { - assert.ok(!style || style === 'document', 'invalid message definition for rpc style binding'); - // pass `input.$lookupType` if `input.$type` could not be found - message = self.wsdl.objectToDocumentXML(input.$name, args, input.targetNSAlias, input.targetNamespace, (input.$type || input.$lookupType)); - } - xml = "" + - "<" + envelopeKey + ":Envelope " + - xmlnsSoap + " " + - "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + - encoding + - this.wsdl.xmlnsInEnvelope + '>' + - ((self.soapHeaders || self.security) ? - ( - "<" + envelopeKey + ":Header>" + - (self.soapHeaders ? self.soapHeaders.join("\n") : "") + - (self.security && !self.security.postProcess ? self.security.toXML() : "") + - "" - ) - : - '' - ) + - "<" + envelopeKey + ":Body" + - (self.bodyAttributes ? self.bodyAttributes.join(' ') : '') + - (self.security && self.security.postProcess ? " Id='_0'" : '') + - ">" + - message + - "" + - ""; - - if(self.security && self.security.postProcess){ - xml = self.security.postProcess(xml); - } - - self.lastMessage = message; - self.lastRequest = xml; - self.lastEndpoint = location; - - self.emit('message', message); - self.emit('request', xml); - - var tryJSONparse = function(body) { - try { - return JSON.parse(body); - } - catch(err) { - return undefined; - } - }; - - req = self.httpClient.request(location, xml, function(err, response, body) { - var result; - var obj; - self.lastResponse = body; - self.lastResponseHeaders = response && response.headers; - self.lastElapsedTime = response && response.elapsedTime; - self.emit('response', body, response); - - if (err) { - callback(err); - } else { - - try { - obj = self.wsdl.xmlToObject(body); - } catch (error) { - // When the output element cannot be looked up in the wsdl and the body is JSON - // instead of sending the error, we pass the body in the response. - if(!output || !output.$lookupTypes) { - debug('Response element is not present. Unable to convert response xml to json.'); - // If the response is JSON then return it as-is. - var json = _.isObject(body) ? body : tryJSONparse(body); - if (json) { - return callback(null, response, json); - } - } - error.response = response; - error.body = body; - self.emit('soapError', error); - return callback(error, response, body); - } - - if (!output){ - // one-way, no output expected - return callback(null, null, body, obj.Header); - } - - if( typeof obj.Body !== 'object' ) { - var error = new Error('Cannot parse response'); - error.response = response; - error.body = body; - return callback(error, obj, body); - } - - result = obj.Body[output.$name]; - // RPC/literal response body may contain elements with added suffixes I.E. - // 'Response', or 'Output', or 'Out' - // This doesn't necessarily equal the ouput message name. See WSDL 1.1 Section 2.4.5 - if(!result){ - result = obj.Body[output.$name.replace(/(?:Out(?:put)?|Response)$/, '')]; - } - if (!result) { - ['Response', 'Out', 'Output'].forEach(function (term) { - if (obj.Body.hasOwnProperty(name + term)) { - return result = obj.Body[name + term]; - } - }); - } - - callback(null, result, body, obj.Header); - } - }, headers, options, self); - - // Added mostly for testability, but possibly useful for debugging - self.lastRequestHeaders = req.headers; -}; - -exports.Client = Client; diff --git a/lib/http.js b/lib/http.js deleted file mode 100644 index 3adcb4682..000000000 --- a/lib/http.js +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2011 Vinay Pulim - * MIT Licensed - */ - -'use strict'; - -var url = require('url'); -var req = require('request'); -var debug = require('debug')('node-soap'); - -var VERSION = require('../package.json').version; - -/** - * A class representing the http client - * @param {Object} [options] Options object. It allows the customization of - * `request` module - * - * @constructor - */ -function HttpClient(options) { - options = options || {}; - this._request = options.request || req; -} - -/** - * Build the HTTP request (method, uri, headers, ...) - * @param {String} rurl The resource url - * @param {Object|String} data The payload - * @param {Object} exheaders Extra http headers - * @param {Object} exoptions Extra options - * @returns {Object} The http request object for the `request` module - */ -HttpClient.prototype.buildRequest = function(rurl, data, exheaders, exoptions) { - var curl = url.parse(rurl); - var secure = curl.protocol === 'https:'; - var host = curl.hostname; - var port = parseInt(curl.port, 10); - var path = [curl.pathname || '/', curl.search || '', curl.hash || ''].join(''); - var method = data ? 'POST' : 'GET'; - var headers = { - 'User-Agent': 'node-soap/' + VERSION, - 'Accept': 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8', - 'Accept-Encoding': 'none', - 'Accept-Charset': 'utf-8', - 'Connection': 'close', - 'Host': host + (isNaN(port) ? '' : ':' + port) - }; - var attr; - var header; - var mergeOptions = ['headers']; - - if (typeof data === 'string') { - headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - } - - exheaders = exheaders || {}; - for (attr in exheaders) { - headers[attr] = exheaders[attr]; - } - - var options = { - uri: curl, - method: method, - headers: headers, - followAllRedirects: true - }; - - - options.body = data; - - - exoptions = exoptions || {}; - for (attr in exoptions) { - if (mergeOptions.indexOf(attr) !== -1) { - for (header in exoptions[attr]) { - options[attr][header] = exoptions[attr][header]; - } - } else { - options[attr] = exoptions[attr]; - } - } - debug('Http request: %j', options); - return options; -}; - -/** - * Handle the http response - * @param {Object} The req object - * @param {Object} res The res object - * @param {Object} body The http body - * @param {Object} The parsed body - */ -HttpClient.prototype.handleResponse = function(req, res, body) { - debug('Http response body: %j', body); - if (typeof body === 'string') { - // Remove any extra characters that appear before or after the SOAP - // envelope. - var match = body.match(/(?:<\?[^?]*\?>[\s]*)?<([^:]*):Envelope([\S\s]*)<\/\1:Envelope>/i); - if (match) { - body = match[0]; - } - } - return body; -}; - -HttpClient.prototype.request = function(rurl, data, callback, exheaders, exoptions) { - var self = this; - var options = self.buildRequest(rurl, data, exheaders, exoptions); - var headers = options.headers; - var req = self._request(options, function(err, res, body) { - if (err) { - return callback(err); - } - body = self.handleResponse(req, res, body); - callback(null, res, body); - }); - - return req; -}; - -module.exports = HttpClient; diff --git a/lib/nscontext.js b/lib/nscontext.js deleted file mode 100644 index c58171f12..000000000 --- a/lib/nscontext.js +++ /dev/null @@ -1,223 +0,0 @@ -'use strict'; - -module.exports = NamespaceContext; - -/** - * Scope for XML namespaces - * @param {NamespaceScope} [parent] Parent scope - * @returns {NamespaceScope} - * @constructor - */ -function NamespaceScope(parent) { - if (!(this instanceof NamespaceScope)) { - return new NamespaceScope(parent); - } - this.parent = parent; - this.namespaces = {}; -} - -/** - * Namespace context that manages hierarchical scopes - * @returns {NamespaceContext} - * @constructor - */ -function NamespaceContext() { - if (!(this instanceof NamespaceContext)) { - return new NamespaceContext(); - } - this.scopes = []; - this.pushContext(); - this.prefixCount = 0; -} - -/** - * Look up the namespace URI by prefix - * @param {String} prefix Namespace prefix - * @param {Boolean} [localOnly] Search current scope only - * @returns {String} Namespace URI - */ -NamespaceScope.prototype.getNamespaceURI = function(prefix, localOnly) { - switch (prefix) { - case 'xml': - return 'http://www.w3.org/XML/1998/namespace'; - case 'xmlns': - return 'http://www.w3.org/2000/xmlns/'; - default: - var nsUri = this.namespaces[prefix]; - /*jshint -W116 */ - if (nsUri != null) { - return nsUri.uri; - } else if (!localOnly && this.parent) { - return this.parent.getNamespaceURI(prefix); - } else { - return null; - } - } -}; - -NamespaceScope.prototype.getNamespaceMapping = function(prefix) { - switch (prefix) { - case 'xml': - return { - uri: 'http://www.w3.org/XML/1998/namespace', - prefix: 'xml', - declared: true - }; - case 'xmlns': - return { - uri: 'http://www.w3.org/2000/xmlns/', - prefix: 'xmlns', - declared: true - }; - default: - var mapping = this.namespaces[prefix]; - /*jshint -W116 */ - if (mapping != null) { - return mapping; - } else if (this.parent) { - return this.parent.getNamespaceMapping(prefix); - } else { - return null; - } - } -}; - -/** - * Look up the namespace prefix by URI - * @param {String} nsUri Namespace URI - * @param {Boolean} [localOnly] Search current scope only - * @returns {String} Namespace prefix - */ -NamespaceScope.prototype.getPrefix = function(nsUri, localOnly) { - switch (nsUri) { - case 'http://www.w3.org/XML/1998/namespace': - return 'xml'; - case 'http://www.w3.org/2000/xmlns/': - return 'xmlns'; - default: - for (var p in this.namespaces) { - if (this.namespaces[p].uri === nsUri) { - return p; - } - } - if (!localOnly && this.parent) { - return this.parent.getPrefix(nsUri); - } else { - return null; - } - } -}; - -/** - * Add a prefix/URI namespace mapping - * @param {String} prefix Namespace prefix - * @param {String} nsUri Namespace URI - * @param {Boolean} [localOnly] Search current scope only - * @returns {boolean} true if the mapping is added or false if the mapping - * already exists - */ -NamespaceContext.prototype.addNamespace = function(prefix, nsUri, localOnly) { - if (this.getNamespaceURI(prefix, localOnly) === nsUri) { - return false; - } - if (this.currentScope) { - this.currentScope.namespaces[prefix] = { - uri: nsUri, - prefix: prefix, - declared: false - }; - return true; - } - return false; -}; - -/** - * Push a scope into the context - * @returns {NamespaceScope} The current scope - */ -NamespaceContext.prototype.pushContext = function() { - var scope = new NamespaceScope(this.currentScope); - this.scopes.push(scope); - this.currentScope = scope; - return scope; -}; - -/** - * Pop a scope out of the context - * @returns {NamespaceScope} The removed scope - */ -NamespaceContext.prototype.popContext = function() { - var scope = this.scopes.pop(); - if (scope) { - this.currentScope = scope.parent; - } else { - this.currentScope = null; - } - return scope; -}; - -/** - * Look up the namespace URI by prefix - * @param {String} prefix Namespace prefix - * @param {Boolean} [localOnly] Search current scope only - * @returns {String} Namespace URI - */ -NamespaceContext.prototype.getNamespaceURI = function(prefix, localOnly) { - return this.currentScope && this.currentScope.getNamespaceURI(prefix, localOnly); -}; - -/** - * Look up the namespace prefix by URI - * @param {String} nsURI Namespace URI - * @param {Boolean} [localOnly] Search current scope only - * @returns {String} Namespace prefix - */ -NamespaceContext.prototype.getPrefix = function(nsUri, localOnly) { - return this.currentScope && this.currentScope.getPrefix(nsUri, localOnly); -}; - -/** - * Register a namespace - * @param {String} nsUri Namespace URI - * @returns {String} The matching or generated namespace prefix - */ -NamespaceContext.prototype.registerNamespace = function(nsUri) { - var prefix = this.getPrefix(nsUri); - if (prefix) { - // If the namespace has already mapped to a prefix - return prefix; - } else { - // Try to generate a unique namespace - while (true) { - prefix = 'ns' + (++this.prefixCount); - if (!this.getNamespaceURI(prefix)) { - // The prefix is not used - break; - } - } - } - this.addNamespace(prefix, nsUri, true); - return prefix; -}; - -/** - * Declare a namespace prefix/uri mapping - * @param {String} prefix Namespace prefix - * @param {String} nsUri Namespace URI - * @returns {Boolean} true if the declaration is created - */ -NamespaceContext.prototype.declareNamespace = function(prefix, nsUri) { - if (this.currentScope) { - var mapping = this.currentScope.getNamespaceMapping(prefix); - if (mapping && mapping.uri === nsUri && mapping.declared) { - return false; - } - this.currentScope.namespaces[prefix] = { - uri: nsUri, - prefix: prefix, - declared: true - }; - return true; - } - return false; -}; diff --git a/lib/security/BasicAuthSecurity.js b/lib/security/BasicAuthSecurity.js deleted file mode 100644 index 5c954be72..000000000 --- a/lib/security/BasicAuthSecurity.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; - -var _ = require('lodash'); - -function BasicAuthSecurity(username, password, defaults) { - this._username = username; - this._password = password; - this.defaults = {}; - _.merge(this.defaults, defaults); -} - -BasicAuthSecurity.prototype.addHeaders = function(headers) { - headers.Authorization = 'Basic ' + new Buffer((this._username + ':' + this._password) || '').toString('base64'); -}; - -BasicAuthSecurity.prototype.toXML = function() { - return ''; -}; - -BasicAuthSecurity.prototype.addOptions = function(options) { - _.merge(options, this.defaults); -}; - -module.exports = BasicAuthSecurity; diff --git a/lib/security/BearerSecurity.js b/lib/security/BearerSecurity.js deleted file mode 100644 index 66e6f0fd5..000000000 --- a/lib/security/BearerSecurity.js +++ /dev/null @@ -1,23 +0,0 @@ -"use strict"; - -var _ = require('lodash'); - -function BearerSecurity(token, defaults) { - this._token = token; - this.defaults = {}; - _.merge(this.defaults, defaults); -} - -BearerSecurity.prototype.addHeaders = function(headers) { - headers.Authorization = "Bearer " + this._token; -}; - -BearerSecurity.prototype.toXML = function() { - return ''; -}; - -BearerSecurity.prototype.addOptions = function(options) { - _.merge(options, this.defaults); -}; - -module.exports = BearerSecurity; diff --git a/lib/security/ClientSSLSecurity.js b/lib/security/ClientSSLSecurity.js deleted file mode 100644 index f8f0573e5..000000000 --- a/lib/security/ClientSSLSecurity.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -var fs = require('fs') - , https = require('https') - , _ = require('lodash'); - -/** - * activates SSL for an already existing client - * - * @module ClientSSLSecurity - * @param {Buffer|String} key - * @param {Buffer|String} cert - * @param {Buffer|String} [ca] - * @param {Object} [defaults] - * @constructor - */ -function ClientSSLSecurity(key, cert, ca, defaults) { - if (key) { - if(Buffer.isBuffer(key)) { - this.key = key; - } else if (typeof key === 'string') { - this.key = fs.readFileSync(key); - } else { - throw new Error('key should be a buffer or a string!'); - } - } - - if (cert) { - if(Buffer.isBuffer(cert)) { - this.cert = cert; - } else if (typeof cert === 'string') { - this.cert = fs.readFileSync(cert); - } else { - throw new Error('cert should be a buffer or a string!'); - } - } - - if (ca) { - if(Buffer.isBuffer(ca)) { - this.ca = ca; - } else if (typeof ca === 'string') { - this.ca = fs.readFileSync(ca); - } else { - defaults = ca; - this.ca = null; - } - } - - this.defaults = {}; - _.merge(this.defaults, defaults); -} - -ClientSSLSecurity.prototype.toXML = function(headers) { - return ''; -}; - -ClientSSLSecurity.prototype.addOptions = function(options) { - options.key = this.key; - options.cert = this.cert; - options.ca = this.ca; - _.merge(options, this.defaults); - options.agent = new https.Agent(options); -}; - -module.exports = ClientSSLSecurity; diff --git a/lib/security/ClientSSLSecurityPFX.js b/lib/security/ClientSSLSecurityPFX.js deleted file mode 100644 index 3ce7af535..000000000 --- a/lib/security/ClientSSLSecurityPFX.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -var fs = require('fs') - , https = require('https') - , _ = require('lodash'); - -/** - * activates SSL for an already existing client using a PFX cert - * - * @module ClientSSLSecurityPFX - * @param {Buffer|String} pfx - * @param {String} passphrase - * @constructor - */ -function ClientSSLSecurityPFX(pfx, passphrase, defaults) { - if (typeof passphrase === 'object') { - defaults = passphrase; - } - if (pfx) { - if (Buffer.isBuffer(pfx)) { - this.pfx = pfx; - } else if (typeof pfx === 'string') { - this.pfx = fs.readFileSync(pfx); - } else { - throw new Error('supplied pfx file should be a buffer or a file location'); - } - } - - if (passphrase) { - if (typeof passphrase === 'string') { - this.passphrase = passphrase; - } - } - this.defaults = {}; - _.merge(this.defaults, defaults); -} - -ClientSSLSecurityPFX.prototype.toXML = function(headers) { - return ''; -}; - -ClientSSLSecurityPFX.prototype.addOptions = function(options) { - options.pfx = this.pfx; - if (this.passphrase) { - options.passphrase = this.passphrase; - } - _.merge(options, this.defaults); - options.agent = new https.Agent(options); -}; - -module.exports = ClientSSLSecurityPFX; diff --git a/lib/security/WSSecurity.js b/lib/security/WSSecurity.js deleted file mode 100644 index d860c08ad..000000000 --- a/lib/security/WSSecurity.js +++ /dev/null @@ -1,71 +0,0 @@ -"use strict"; - -var crypto = require('crypto'); -var passwordDigest = require('../utils').passwordDigest; -var validPasswordTypes = ['PasswordDigest', 'PasswordText']; - -function WSSecurity(username, password, options) { - options = options || {}; - this._username = username; - this._password = password; - //must account for backward compatibility for passwordType String param as well as object options defaults: passwordType = 'PasswordText', hasTimeStamp = true - if (typeof options === 'string') { - this._passwordType = options ? options : 'PasswordText'; - } else { - this._passwordType = options.passwordType ? options.passwordType : 'PasswordText'; - } - - if (validPasswordTypes.indexOf(this._passwordType) === -1) { - this._passwordType = 'PasswordText'; - } - - this._hasTimeStamp = options.hasTimeStamp || typeof options.hasTimeStamp === 'boolean' ? !!options.hasTimeStamp : true; -} - -WSSecurity.prototype.toXML = function() { - // avoid dependency on date formatting libraries - function getDate(d) { - function pad(n) { - return n < 10 ? '0' + n : n; - } - return d.getUTCFullYear() + '-' - + pad(d.getUTCMonth() + 1) + '-' - + pad(d.getUTCDate()) + 'T' - + pad(d.getUTCHours()) + ':' - + pad(d.getUTCMinutes()) + ':' - + pad(d.getUTCSeconds()) + 'Z'; - } - var now = new Date(); - var created = getDate(now); - var timeStampXml = ''; - if (this._hasTimeStamp) { - var expires = getDate( new Date(now.getTime() + (1000 * 600)) ); - timeStampXml = "" + - ""+created+"" + - ""+expires+"" + - ""; - } - - var password; - if(this._passwordType === 'PasswordText') { - password = "" + this._password + ""; - } else { - // nonce = base64 ( sha1 ( created + random ) ) - var nHash = crypto.createHash('sha1'); - nHash.update(created + Math.random()); - var nonce = nHash.digest('base64'); - password = "" + passwordDigest(nonce, created, this._password) + "" + - "" + nonce + ""; - } - - return "" + - timeStampXml + - "" + - "" + this._username + "" + - password + - "" + created + "" + - "" + - ""; -}; - -module.exports = WSSecurity; diff --git a/lib/security/WSSecurityCert.js b/lib/security/WSSecurityCert.js deleted file mode 100644 index 11f8430ea..000000000 --- a/lib/security/WSSecurityCert.js +++ /dev/null @@ -1,78 +0,0 @@ -"use strict"; - -var ursa = require('ursa'); -var fs = require('fs'); -var path = require('path'); -var ejs = require('ejs'); -var SignedXml = require('xml-crypto').SignedXml; -var uuid = require('node-uuid'); -var wsseSecurityHeaderTemplate = ejs.compile(fs.readFileSync(path.join(__dirname, 'templates', 'wsse-security-header.ejs')).toString()); -var wsseSecurityTokenTemplate = ejs.compile(fs.readFileSync(path.join(__dirname, 'templates', 'wsse-security-token.ejs')).toString()); - -function addMinutes(date, minutes) { - return new Date(date.getTime() + minutes * 60000); -} - -function dateStringForSOAP(date) { - return date.getUTCFullYear() + '-' + ('0' + (date.getUTCMonth() + 1)).slice(-2) + '-' + - ('0' + date.getUTCDate()).slice(-2) + 'T' + ('0' + date.getUTCHours()).slice(-2) + ":" + - ('0' + date.getUTCMinutes()).slice(-2) + ":" + ('0' + date.getUTCSeconds()).slice(-2) + "Z"; -} - -function generateCreated() { - return dateStringForSOAP(new Date()); -} - -function generateExpires() { - return dateStringForSOAP(addMinutes(new Date(), 10)); -} - -function insertStr(src, dst, pos) { - return [dst.slice(0, pos), src, dst.slice(pos)].join(''); -} - -function generateId() { - return uuid.v4().replace(/-/gm, ''); -} - -function WSSecurityCert(privatePEM, publicP12PEM, password, encoding) { - - this.privateKey = ursa.createPrivateKey(privatePEM, password, encoding); - this.publicP12PEM = publicP12PEM.toString().replace('-----BEGIN CERTIFICATE-----', '').replace('-----END CERTIFICATE-----', '').replace(/(\r\n|\n|\r)/gm, ''); - - this.signer = new SignedXml(); - this.signer.signingKey = this.privateKey.toPrivatePem(); - this.x509Id = "x509-" + generateId(); - - var references = ["http://www.w3.org/2000/09/xmldsig#enveloped-signature", - "http://www.w3.org/2001/10/xml-exc-c14n#"]; - - this.signer.addReference("//*[local-name(.)='Body']", references); - this.signer.addReference("//*[local-name(.)='Timestamp']", references); - - var _this = this; - this.signer.keyInfoProvider = {}; - this.signer.keyInfoProvider.getKeyInfo = function (key) { - return wsseSecurityTokenTemplate({ x509Id: _this.x509Id }); - }; -} - -WSSecurityCert.prototype.postProcess = function (xml) { - this.created = generateCreated(); - this.expires = generateExpires(); - - var secHeader = wsseSecurityHeaderTemplate({ - binaryToken: this.publicP12PEM, - created: this.created, - expires: this.expires, - id: this.x509Id - }); - - var xmlWithSec = insertStr(secHeader, xml, xml.indexOf('')); - - this.signer.computeSignature(xmlWithSec); - - return insertStr(this.signer.getSignatureXml(), xmlWithSec, xmlWithSec.indexOf('')); -}; - -module.exports = WSSecurityCert; diff --git a/lib/security/index.js b/lib/security/index.js deleted file mode 100644 index af9220096..000000000 --- a/lib/security/index.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; - -module.exports = { - BasicAuthSecurity: require('./BasicAuthSecurity') -, ClientSSLSecurity: require('./ClientSSLSecurity') -, ClientSSLSecurityPFX: require('./ClientSSLSecurityPFX') -, WSSecurity: require('./WSSecurity') -, BearerSecurity: require('./BearerSecurity') -, WSSecurityCert: require('./WSSecurityCert') -}; diff --git a/lib/security/templates/wsse-security-header.ejs b/lib/security/templates/wsse-security-header.ejs deleted file mode 100644 index d137b4442..000000000 --- a/lib/security/templates/wsse-security-header.ejs +++ /dev/null @@ -1,12 +0,0 @@ - - <%-binaryToken%> - - <%-created%> - <%-expires%> - - diff --git a/lib/security/templates/wsse-security-token.ejs b/lib/security/templates/wsse-security-token.ejs deleted file mode 100644 index 59134cfb9..000000000 --- a/lib/security/templates/wsse-security-token.ejs +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/lib/server.js b/lib/server.js deleted file mode 100644 index 9ee2a438f..000000000 --- a/lib/server.js +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (c) 2011 Vinay Pulim - * MIT Licensed - */ - -"use strict"; - -function getDateString(d) { - function pad(n) { - return n < 10 ? '0' + n : n; - } - return d.getUTCFullYear() + '-' - + pad(d.getUTCMonth() + 1) + '-' - + pad(d.getUTCDate()) + 'T' - + pad(d.getUTCHours()) + ':' - + pad(d.getUTCMinutes()) + ':' - + pad(d.getUTCSeconds()) + 'Z'; -} - -var url = require('url'), - compress = null, - events = require('events'), - util = require('util'), - findPrefix = require('./utils').findPrefix; - -try { - compress = require("compress"); -} catch (error) { -} - -var Server = function(server, path, services, wsdl, options) { - var self = this; - - events.EventEmitter.call(this); - - options = options || {}; - this.path = path; - this.services = services; - this.wsdl = wsdl; - - if (path[path.length - 1] !== '/') - path += '/'; - wsdl.onReady(function(err) { - var listeners = server.listeners('request').slice(); - - server.removeAllListeners('request'); - server.addListener('request', function(req, res) { - if (typeof self.authorizeConnection === 'function') { - if (!self.authorizeConnection(req.connection.remoteAddress)) { - res.end(); - return; - } - } - var reqPath = url.parse(req.url).pathname; - if (reqPath[reqPath.length - 1] !== '/') - reqPath += '/'; - if (path === reqPath) { - self._requestListener(req, res); - } else { - for (var i = 0, len = listeners.length; i < len; i++) { - listeners[i].call(this, req, res); - } - } - }); - }); - - this._initializeOptions(options); -}; -util.inherits(Server, events.EventEmitter); - -Server.prototype.addSoapHeader = function(soapHeader, name, namespace, xmlns) { - if (!this.soapHeaders) { - this.soapHeaders = []; - } - if (typeof soapHeader === 'object') { - soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); - } - return this.soapHeaders.push(soapHeader) - 1; -}; - -Server.prototype.changeSoapHeader = function(index, soapHeader, name, namespace, xmlns) { - if (!this.soapHeaders) { - this.soapHeaders = []; - } - if (typeof soapHeader === 'object') { - soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); - } - this.soapHeaders[index] = soapHeader; -}; - -Server.prototype.getSoapHeaders = function() { - return this.soapHeaders; -}; - -Server.prototype.clearSoapHeaders = function() { - this.soapHeaders = null; -}; - -Server.prototype._initializeOptions = function(options) { - this.wsdl.options.attributesKey = options.attributesKey || 'attributes'; -}; - -Server.prototype._requestListener = function(req, res) { - var self = this; - var reqParse = url.parse(req.url); - var reqPath = reqParse.pathname; - var reqQuery = reqParse.search; - - if (typeof self.log === 'function') { - self.log("info", "Handling " + req.method + " on " + req.url); - } - - if (req.method === 'GET') { - if (reqQuery && reqQuery.toLowerCase() === '?wsdl') { - if (typeof self.log === 'function') { - self.log("info", "Wants the WSDL"); - } - res.setHeader("Content-Type", "application/xml"); - res.write(self.wsdl.toXML()); - } - res.end(); - } else if (req.method === 'POST') { - res.setHeader('Content-Type', req.headers['content-type']); - var chunks = [], gunzip; - if (compress && req.headers["content-encoding"] === "gzip") { - gunzip = new compress.Gunzip(); - gunzip.init(); - } - req.on('data', function(chunk) { - if (gunzip) - chunk = gunzip.inflate(chunk, "binary"); - chunks.push(chunk); - }); - req.on('end', function() { - var xml = chunks.join(''); - var result; - var error; - if (gunzip) { - gunzip.end(); - gunzip = null; - } - try { - if (typeof self.log === 'function') { - self.log("received", xml); - } - self._process(xml, req, function(result, statusCode) { - if(statusCode) { - res.statusCode = statusCode; - } - res.write(result); - res.end(); - if (typeof self.log === 'function') { - self.log("replied", result); - } - }); - } - catch (err) { - error = err.stack || err; - res.statusCode = 500; - res.write(error); - res.end(); - if (typeof self.log === 'function') { - self.log("error", error); - } - } - }); - } - else { - res.end(); - } -}; - -Server.prototype._process = function(input, req, callback) { - var self = this, - pathname = url.parse(req.url).pathname.replace(/\/$/, ''), - obj = this.wsdl.xmlToObject(input), - body = obj.Body, - headers = obj.Header, - bindings = this.wsdl.definitions.bindings, binding, - method, methodName, - serviceName, portName, - includeTimestamp = obj.Header && obj.Header.Security && obj.Header.Security.Timestamp; - - if (typeof self.authenticate === 'function') { - if (!obj.Header || !obj.Header.Security) { - throw new Error('No security header'); - } - if (!self.authenticate(obj.Header.Security)) { - throw new Error('Invalid username or password'); - } - } - - if (typeof self.log === 'function') { - self.log("info", "Attempting to bind to " + pathname); - } - - // use port.location and current url to find the right binding - binding = (function(self) { - var services = self.wsdl.definitions.services; - var firstPort; - var name; - for (name in services) { - serviceName = name; - var service = services[serviceName]; - var ports = service.ports; - for (name in ports) { - portName = name; - var port = ports[portName]; - var portPathname = url.parse(port.location).pathname.replace(/\/$/, ''); - - if (typeof self.log === 'function') { - self.log("info", "Trying " + portName + " from path " + portPathname); - } - - if (portPathname === pathname) - return port.binding; - - // The port path is almost always wrong for generated WSDLs - if (!firstPort) { - firstPort = port; - } - } - } - return !firstPort ? void 0 : firstPort.binding; - })(this); - - if (!binding) { - throw new Error('Failed to bind to WSDL'); - } - - try { - if (binding.style === 'rpc') { - methodName = Object.keys(body)[0]; - - self.emit('request', obj, methodName); - if (headers) - self.emit('headers', headers, methodName); - - self._executeMethod({ - serviceName: serviceName, - portName: portName, - methodName: methodName, - outputName: methodName + 'Response', - args: body[methodName], - headers: headers, - style: 'rpc' - }, req, callback); - } else { - var messageElemName = (Object.keys(body)[0] === 'attributes' ? Object.keys(body)[1] : Object.keys(body)[0]); - var pair = binding.topElements[messageElemName]; - - self.emit('request', obj, pair.methodName); - if (headers) - self.emit('headers', headers, pair.methodName); - - self._executeMethod({ - serviceName: serviceName, - portName: portName, - methodName: pair.methodName, - outputName: pair.outputName, - args: body[messageElemName], - headers: headers, - style: 'document' - }, req, callback, includeTimestamp); - } - } - catch (error) { - if (error.Fault !== undefined) { - return self._sendError(error.Fault, callback, includeTimestamp); - } - - throw error; - } -}; - -Server.prototype._executeMethod = function(options, req, callback, includeTimestamp) { - options = options || {}; - var self = this, - method, body, - serviceName = options.serviceName, - portName = options.portName, - methodName = options.methodName, - outputName = options.outputName, - args = options.args, - style = options.style, - handled = false; - - try { - method = this.services[serviceName][portName][methodName]; - } catch (error) { - return callback(this._envelope('', includeTimestamp)); - } - - function handleResult(error, result) { - if (handled) - return; - handled = true; - - if (error && error.Fault !== undefined) { - return self._sendError(error.Fault, callback, includeTimestamp); - } - else if (result === undefined) { - // Backward compatibility to support one argument callback style - result = error; - } - - if (style === 'rpc') { - body = self.wsdl.objectToRpcXML(outputName, result, '', self.wsdl.definitions.$targetNamespace); - } else { - var element = self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output; - body = self.wsdl.objectToDocumentXML(outputName, result, element.targetNSAlias, element.targetNamespace); - } - callback(self._envelope(body, includeTimestamp)); - } - - if(!self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output){ - // no output defined = one-way operation so return empty response - handled = true; - callback(''); - } - - var result = method(args, handleResult, options.headers, req); - if (typeof result !== 'undefined') { - handleResult(result); - } -}; - -Server.prototype._envelope = function(body, includeTimestamp) { - var defs = this.wsdl.definitions, - ns = defs.$targetNamespace, - encoding = '', - alias = findPrefix(defs.xmlns, ns); - var xml = "" + - "'; - var headers = ''; - - if (includeTimestamp) { - var now = new Date(); - var created = getDateString(now); - var expires = getDateString(new Date(now.getTime() + (1000 * 600))); - - headers += "" + - " " + - " " + created + "" + - " " + expires + "" + - " " + - " \n"; - } - - if(this.soapHeaders) { - headers += this.soapHeaders.join("\n"); - } - - if(headers !== '') { - xml += "" + headers + ""; - } - - xml += "" + - body + - "" + - ""; - return xml; -}; - -Server.prototype._sendError = function(soapFault, callback, includeTimestamp) { - var self = this, - fault; - - var statusCode; - if(soapFault.statusCode) { - statusCode = soapFault.statusCode; - soapFault.statusCode = undefined; - } - - if (soapFault.faultcode) { - // Soap 1.1 error style - // Root element will be prependend with the soap NS - // It must match the NS defined in the Envelope (set by the _envelope method) - fault = self.wsdl.objectToDocumentXML("soap:Fault", soapFault, undefined); - } - else { - // Soap 1.2 error style. - // 3rd param is the NS prepended to all elements - // It must match the NS defined in the Envelope (set by the _envelope method) - fault = self.wsdl.objectToDocumentXML("Fault", soapFault, "soap"); - } - - return callback(self._envelope(fault, includeTimestamp), statusCode); -}; - -exports.Server = Server; diff --git a/lib/soap.js b/lib/soap.js deleted file mode 100644 index d2bf99eec..000000000 --- a/lib/soap.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2011 Vinay Pulim - * MIT Licensed - */ - -"use strict"; - -var Client = require('./client').Client, - Server = require('./server').Server, - HttpClient = require('./http'), - security = require('./security'), - passwordDigest = require('./utils').passwordDigest, - open_wsdl = require('./wsdl').open_wsdl, - WSDL = require('./wsdl').WSDL; - -var _wsdlCache = {}; - -function _requestWSDL(url, options, callback) { - if (typeof options === 'function') { - callback = options; - options = {}; - } - - var wsdl = _wsdlCache[url]; - if (wsdl) { - process.nextTick(function() { - callback(null, wsdl); - }); - } - else { - open_wsdl(url, options, function(err, wsdl) { - if (err) - return callback(err); - else - _wsdlCache[url] = wsdl; - callback(null, wsdl); - }); - } -} - -function createClient(url, options, callback, endpoint) { - if (typeof options === 'function') { - endpoint = callback; - callback = options; - options = {}; - } - endpoint = options.endpoint || endpoint; - _requestWSDL(url, options, function(err, wsdl) { - callback(err, wsdl && new Client(wsdl, endpoint, options)); - }); -} - -function listen(server, pathOrOptions, services, xml) { - var options = {}, - path = pathOrOptions; - - if (typeof pathOrOptions === 'object') { - options = pathOrOptions; - path = options.path; - services = options.services; - xml = options.xml; - } - - var wsdl = new WSDL(xml || services, null, options); - return new Server(server, path, services, wsdl); -} - -exports.security = security; -exports.BasicAuthSecurity = security.BasicAuthSecurity; -exports.WSSecurity = security.WSSecurity; -exports.WSSecurityCert = security.WSSecurityCert; -exports.ClientSSLSecurity = security.ClientSSLSecurity; -exports.ClientSSLSecurityPFX = security.ClientSSLSecurityPFX; -exports.BearerSecurity = security.BearerSecurity; -exports.createClient = createClient; -exports.passwordDigest = passwordDigest; -exports.listen = listen; -exports.WSDL = WSDL; - -// Export Client and Server to allow customization -exports.Server = Server; -exports.Client = Client; -exports.HttpClient = HttpClient; diff --git a/lib/utils.js b/lib/utils.js deleted file mode 100644 index 2e233cee3..000000000 --- a/lib/utils.js +++ /dev/null @@ -1,32 +0,0 @@ - -"use strict"; -var crypto = require('crypto'); -exports.passwordDigest = function passwordDigest(nonce, created, password) { - // digest = base64 ( sha1 ( nonce + created + password ) ) - var pwHash = crypto.createHash('sha1'); - var rawNonce = new Buffer(nonce || '', 'base64').toString('binary'); - pwHash.update(rawNonce + created + password); - return pwHash.digest('base64'); -}; - - -var TNS_PREFIX = '__tns__'; // Prefix for targetNamespace - -exports.TNS_PREFIX = TNS_PREFIX; - -/** - * Find a key from an object based on the value - * @param {Object} Namespace prefix/uri mapping - * @param {*} nsURI value - * @returns {String} The matching key - */ -exports.findPrefix = function(xmlnsMapping, nsURI) { - for (var n in xmlnsMapping) { - if (n === TNS_PREFIX) continue; - if (xmlnsMapping[n] === nsURI) - return n; - } -}; - - - diff --git a/lib/wsdl.js b/lib/wsdl.js deleted file mode 100644 index 1cce687d8..000000000 --- a/lib/wsdl.js +++ /dev/null @@ -1,2124 +0,0 @@ -/* - * Copyright (c) 2011 Vinay Pulim - * MIT Licensed - * - */ -/*jshint proto:true*/ - -"use strict"; - -var sax = require('sax'); -var inherits = require('util').inherits; -var HttpClient = require('./http'); -var NamespaceContext = require('./nscontext'); -var fs = require('fs'); -var url = require('url'); -var path = require('path'); -var assert = require('assert').ok; -var stripBom = require('strip-bom'); -var debug = require('debug')('node-soap'); -var _ = require('lodash'); -var selectn = require('selectn'); -var utils = require('./utils'); -var TNS_PREFIX = utils.TNS_PREFIX; -var findPrefix = utils.findPrefix; - -var Primitives = { - string: 1, - boolean: 1, - decimal: 1, - float: 1, - double: 1, - anyType: 1, - byte: 1, - int: 1, - long: 1, - short: 1, - negativeInteger: 1, - nonNegativeInteger: 1, - positiveInteger: 1, - nonPositiveInteger:1, - unsignedByte: 1, - unsignedInt: 1, - unsignedLong: 1, - unsignedShort: 1, - duration: 0, - dateTime: 0, - time: 0, - date: 0, - gYearMonth: 0, - gYear: 0, - gMonthDay: 0, - gDay: 0, - gMonth: 0, - hexBinary: 0, - base64Binary: 0, - anyURI: 0, - QName: 0, - NOTATION: 0 -}; - -function splitQName(nsName) { - var i = typeof nsName === 'string' ? nsName.indexOf(':') : -1; - return i < 0 ? {prefix: TNS_PREFIX, name: nsName} : - {prefix: nsName.substring(0, i), name: nsName.substring(i + 1)}; -} - -function xmlEscape(obj) { - if (typeof (obj) === 'string') { - if (obj.substr(0,9) === '") { - return obj; - } - return obj - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); - } - - return obj; -} - -var trimLeft = /^[\s\xA0]+/; -var trimRight = /[\s\xA0]+$/; - -function trim(text) { - return text.replace(trimLeft, '').replace(trimRight, ''); -} - -/** - * What we want is to copy properties from one object to another one and avoid - * properties overriding. This way we ensure the 'inheritance' of - * usage. - * - * NB: 'Element' (and subtypes) don't have any prototyped properties: there's - * no need to process a 'hasOwnProperties' call, we should just iterate over the - * keys. - */ -function extend(base, obj) { - if(base !== null && typeof base === "object" && obj !== null && typeof obj === "object"){ - Object.keys(obj).forEach(function(key) { - if(!base.hasOwnProperty(key)) - base[key] = obj[key]; - }); - } - return base; -} - -function deepMerge(destination, source) { - return _.merge(destination || {}, source, function(a, b) { - return _.isArray(a) ? a.concat(b) : undefined; - }); -} - -var Element = function(nsName, attrs, options) { - var parts = splitQName(nsName); - - this.nsName = nsName; - this.prefix = parts.prefix; - this.name = parts.name; - this.children = []; - this.xmlns = {}; - - this._initializeOptions(options); - - for (var key in attrs) { - var match = /^xmlns:?(.*)$/.exec(key); - if (match) { - this.xmlns[match[1] ? match[1] : TNS_PREFIX] = attrs[key]; - } - else { - if(key === 'value') { - this[this.valueKey] = attrs[key]; - } else { - this['$' + key] = attrs[key]; - } - } - } - if (this.$targetNamespace !== undefined) { - // Add targetNamespace to the mapping - this.xmlns[TNS_PREFIX] = this.$targetNamespace; - } -}; - -Element.prototype._initializeOptions = function (options) { - if(options) { - this.valueKey = options.valueKey || '$value'; - this.xmlKey = options.xmlKey || '$xml'; - this.ignoredNamespaces = options.ignoredNamespaces || []; - } else { - this.valueKey = '$value'; - this.xmlKey = '$xml'; - this.ignoredNamespaces = []; - } -}; - -Element.prototype.deleteFixedAttrs = function() { - this.children && this.children.length === 0 && delete this.children; - this.xmlns && Object.keys(this.xmlns).length === 0 && delete this.xmlns; - delete this.nsName; - delete this.prefix; - delete this.name; -}; - -Element.prototype.allowedChildren = []; - -Element.prototype.startElement = function(stack, nsName, attrs, options) { - if (!this.allowedChildren) - return; - - var ChildClass = this.allowedChildren[splitQName(nsName).name], - element = null; - - if (ChildClass) { - stack.push(new ChildClass(nsName, attrs, options)); - } - else { - this.unexpected(nsName); - } - -}; - -Element.prototype.endElement = function(stack, nsName) { - if (this.nsName === nsName) { - if (stack.length < 2) - return; - var parent = stack[stack.length - 2]; - if (this !== stack[0]) { - extend(stack[0].xmlns, this.xmlns); - // delete this.xmlns; - parent.children.push(this); - parent.addChild(this); - } - stack.pop(); - } -}; - -Element.prototype.addChild = function(child) { - return; -}; - -Element.prototype.unexpected = function(name) { - throw new Error('Found unexpected element (' + name + ') inside ' + this.nsName); -}; - -Element.prototype.description = function(definitions) { - return this.$name || this.name; -}; - -Element.prototype.init = function() { -}; - -Element.createSubClass = function() { - var root = this; - var subElement = function() { - root.apply(this, arguments); - this.init(); - }; - // inherits(subElement, root); - subElement.prototype.__proto__ = root.prototype; - return subElement; -}; - - -var ElementElement = Element.createSubClass(); -var AnyElement = Element.createSubClass(); -var InputElement = Element.createSubClass(); -var OutputElement = Element.createSubClass(); -var SimpleTypeElement = Element.createSubClass(); -var RestrictionElement = Element.createSubClass(); -var ExtensionElement = Element.createSubClass(); -var ChoiceElement = Element.createSubClass(); -var EnumerationElement = Element.createSubClass(); -var ComplexTypeElement = Element.createSubClass(); -var ComplexContentElement = Element.createSubClass(); -var SimpleContentElement = Element.createSubClass(); -var SequenceElement = Element.createSubClass(); -var AllElement = Element.createSubClass(); -var MessageElement = Element.createSubClass(); -var DocumentationElement = Element.createSubClass(); - -var SchemaElement = Element.createSubClass(); -var TypesElement = Element.createSubClass(); -var OperationElement = Element.createSubClass(); -var PortTypeElement = Element.createSubClass(); -var BindingElement = Element.createSubClass(); -var PortElement = Element.createSubClass(); -var ServiceElement = Element.createSubClass(); -var DefinitionsElement = Element.createSubClass(); - -var ElementTypeMap = { - types: [TypesElement, 'schema documentation'], - schema: [SchemaElement, 'element complexType simpleType include import'], - element: [ElementElement, 'annotation complexType'], - any: [AnyElement, ''], - simpleType: [SimpleTypeElement, 'restriction'], - restriction: [RestrictionElement, 'enumeration all choice sequence'], - extension: [ExtensionElement, 'all sequence choice'], - choice: [ChoiceElement, 'element sequence choice any'], - // group: [GroupElement, 'element group'], - enumeration: [EnumerationElement, ''], - complexType: [ComplexTypeElement, 'annotation sequence all complexContent simpleContent choice'], - complexContent: [ComplexContentElement, 'extension'], - simpleContent: [SimpleContentElement, 'extension'], - sequence: [SequenceElement, 'element sequence choice any'], - all: [AllElement, 'element choice'], - - service: [ServiceElement, 'port documentation'], - port: [PortElement, 'address documentation'], - binding: [BindingElement, '_binding SecuritySpec operation documentation'], - portType: [PortTypeElement, 'operation documentation'], - message: [MessageElement, 'part documentation'], - operation: [OperationElement, 'documentation input output fault _operation'], - input: [InputElement, 'body SecuritySpecRef documentation header'], - output: [OutputElement, 'body SecuritySpecRef documentation header'], - fault: [Element, '_fault documentation'], - definitions: [DefinitionsElement, 'types message portType binding service import documentation'], - documentation: [DocumentationElement, ''] -}; - -function mapElementTypes(types) { - var rtn = {}; - types = types.split(' '); - types.forEach(function(type) { - rtn[type.replace(/^_/, '')] = (ElementTypeMap[type] || [Element]) [0]; - }); - return rtn; -} - -for (var n in ElementTypeMap) { - var v = ElementTypeMap[n]; - v[0].prototype.allowedChildren = mapElementTypes(v[1]); -} - -MessageElement.prototype.init = function() { - this.element = null; - this.parts = null; -}; - -SchemaElement.prototype.init = function() { - this.complexTypes = {}; - this.types = {}; - this.elements = {}; - this.includes = []; -}; - -TypesElement.prototype.init = function() { - this.schemas = {}; -}; - -OperationElement.prototype.init = function() { - this.input = null; - this.output = null; - this.inputSoap = null; - this.outputSoap = null; - this.style = ''; - this.soapAction = ''; -}; - -PortTypeElement.prototype.init = function() { - this.methods = {}; -}; - -BindingElement.prototype.init = function() { - this.transport = ''; - this.style = ''; - this.methods = {}; -}; - -PortElement.prototype.init = function() { - this.location = null; -}; - -ServiceElement.prototype.init = function() { - this.ports = {}; -}; - -DefinitionsElement.prototype.init = function() { - if (this.name !== 'definitions')this.unexpected(this.nsName); - this.messages = {}; - this.portTypes = {}; - this.bindings = {}; - this.services = {}; - this.schemas = {}; -}; - -DocumentationElement.prototype.init = function() { -}; - -SchemaElement.prototype.merge = function(source) { - assert(source instanceof SchemaElement); - if (this.$targetNamespace === source.$targetNamespace) { - _.merge(this.complexTypes, source.complexTypes); - _.merge(this.types, source.types); - _.merge(this.elements, source.elements); - _.merge(this.xmlns, source.xmlns); - } - return this; -}; - - -SchemaElement.prototype.addChild = function(child) { - if (child.$name in Primitives) - return; - if (child.name === 'include' || child.name === 'import') { - var location = child.$schemaLocation || child.$location; - if (location) { - this.includes.push({ - namespace: child.$namespace || child.$targetNamespace || this.$targetNamespace, - location: location - }); - } - } - else if (child.name === 'complexType') { - this.complexTypes[child.$name] = child; - } - else if (child.name === 'element') { - this.elements[child.$name] = child; - } - else if (child.$name) { - this.types[child.$name] = child; - } - this.children.pop(); - // child.deleteFixedAttrs(); -}; -//fix#325 -TypesElement.prototype.addChild = function (child) { - assert(child instanceof SchemaElement); - - var targetNamespace = child.$targetNamespace; - - if(!this.schemas.hasOwnProperty(targetNamespace)) { - this.schemas[targetNamespace] = child; - } else { - console.error('Target-Namespace "'+ targetNamespace +'" already in use by another Schema!'); - } -}; - -InputElement.prototype.addChild = function(child) { - if (child.name === 'body') { - this.use = child.$use; - if (this.use === 'encoded') { - this.encodingStyle = child.$encodingStyle; - } - this.children.pop(); - } -}; - -OutputElement.prototype.addChild = function(child) { - if (child.name === 'body') { - this.use = child.$use; - if (this.use === 'encoded') { - this.encodingStyle = child.$encodingStyle; - } - this.children.pop(); - } -}; - -OperationElement.prototype.addChild = function(child) { - if (child.name === 'operation') { - this.soapAction = child.$soapAction || ''; - this.style = child.$style || ''; - this.children.pop(); - } -}; - -BindingElement.prototype.addChild = function(child) { - if (child.name === 'binding') { - this.transport = child.$transport; - this.style = child.$style; - this.children.pop(); - } -}; - -PortElement.prototype.addChild = function(child) { - if (child.name === 'address' && typeof (child.$location) !== 'undefined') { - this.location = child.$location; - } -}; - -DefinitionsElement.prototype.addChild = function(child) { - var self = this; - if (child instanceof TypesElement) { - // Merge types.schemas into definitions.schemas - _.merge(self.schemas, child.schemas); - } - else if (child instanceof MessageElement) { - self.messages[child.$name] = child; - } - else if (child.name === 'import') { - self.schemas[child.$namespace] = new SchemaElement(child.$namespace, {}); - self.schemas[child.$namespace].addChild(child); - } - else if (child instanceof PortTypeElement) { - self.portTypes[child.$name] = child; - } - else if (child instanceof BindingElement) { - if (child.transport === 'http://schemas.xmlsoap.org/soap/http' || - child.transport === 'http://www.w3.org/2003/05/soap/bindings/HTTP/') - self.bindings[child.$name] = child; - } - else if (child instanceof ServiceElement) { - self.services[child.$name] = child; - } - else if (child instanceof DocumentationElement) { - } - this.children.pop(); -}; - -MessageElement.prototype.postProcess = function(definitions) { - var part = null; - var child; - var children = this.children || []; - var ns; - var nsName; - var i; - var type; - - for (i in children) { - if ((child = children[i]).name === 'part') { - part = child; - break; - } - } - - if (!part) { - return; - } - - if (part.$element) { - var lookupTypes = [], - elementChildren ; - - delete this.parts; - - nsName = splitQName(part.$element); - ns = nsName.prefix; - var schema = definitions.schemas[definitions.xmlns[ns]]; - this.element = schema.elements[nsName.name]; - if(!this.element) { - debug(nsName.name + " is not present in wsdl and cannot be processed correctly."); - return; - } - this.element.targetNSAlias = ns; - this.element.targetNamespace = definitions.xmlns[ns]; - - // set the optional $lookupType to be used within `client#_invoke()` when - // calling `wsdl#objectToDocumentXML() - this.element.$lookupType = part.$name; - - elementChildren = this.element.children; - - // get all nested lookup types (only complex types are followed) - if (elementChildren.length > 0) { - for (i = 0; i < elementChildren.length; i++) { - lookupTypes.push(this._getNestedLookupTypeString(elementChildren[i])); - } - } - - // if nested lookup types where found, prepare them for furter usage - if (lookupTypes.length > 0) { - lookupTypes = lookupTypes. - join('_'). - split('_'). - filter(function removeEmptyLookupTypes (type) { - return type !== '^'; - }); - - var schemaXmlns = definitions.schemas[this.element.targetNamespace].xmlns; - - for (i = 0; i < lookupTypes.length; i++) { - lookupTypes[i] = this._createLookupTypeObject(lookupTypes[i], schemaXmlns); - } - } - - this.element.$lookupTypes = lookupTypes; - - if (this.element.$type) { - type = splitQName(this.element.$type); - var typeNs = schema.xmlns && schema.xmlns[type.prefix] || definitions.xmlns[type.prefix]; - - if (typeNs) { - if (type.name in Primitives) { - // this.element = this.element.$type; - } - else { - // first check local mapping of ns alias to namespace - schema = definitions.schemas[typeNs]; - var ctype = schema.complexTypes[type.name] || schema.types[type.name] || schema.elements[type.name]; - - - if (ctype) { - this.parts = ctype.description(definitions, schema.xmlns); - } - } - } - } - else { - var method = this.element.description(definitions, schema.xmlns); - this.parts = method[nsName.name]; - } - - - this.children.splice(0, 1); - } else { - // rpc encoding - this.parts = {}; - delete this.element; - for (i = 0; part = this.children[i]; i++) { - if (part.name === 'documentation') { - // - continue; - } - assert(part.name === 'part', 'Expected part element'); - nsName = splitQName(part.$type); - ns = definitions.xmlns[nsName.prefix]; - type = nsName.name; - var schemaDefinition = definitions.schemas[ns]; - if (typeof schemaDefinition !== 'undefined') { - this.parts[part.$name] = definitions.schemas[ns].types[type] || definitions.schemas[ns].complexTypes[type]; - } else { - this.parts[part.$name] = part.$type; - } - - if (typeof this.parts[part.$name] === 'object') { - this.parts[part.$name].prefix = nsName.prefix; - this.parts[part.$name].xmlns = ns; - } - - this.children.splice(i--, 1); - } - } - this.deleteFixedAttrs(); -}; - -/** - * Takes a given namespaced String(for example: 'alias:property') and creates a lookupType - * object for further use in as first (lookup) `parameterTypeObj` within the `objectToXML` - * method and provides an entry point for the already existing code in `findChildSchemaObject`. - * - * @method _createLookupTypeObject - * @param {String} nsString The NS String (for example "alias:type"). - * @param {Object} xmlns The fully parsed `wsdl` definitions object (including all schemas). - * @returns {Object} - * @private - */ -MessageElement.prototype._createLookupTypeObject = function (nsString, xmlns) { - var splittedNSString = splitQName(nsString), - nsAlias = splittedNSString.prefix, - splittedName = splittedNSString.name.split('#'), - type = splittedName[0], - name = splittedName[1], - lookupTypeObj = {}; - - lookupTypeObj.$namespace = xmlns[nsAlias]; - lookupTypeObj.$type = nsAlias + ':' + type; - lookupTypeObj.$name = name; - - return lookupTypeObj; -}; - -/** - * Iterates through the element and every nested child to find any defined `$type` - * property and returns it in a underscore ('_') separated String (using '^' as default - * value if no `$type` property was found). - * - * @method _getNestedLookupTypeString - * @param {Object} element The element which (probably) contains nested `$type` values. - * @returns {String} - * @private - */ -MessageElement.prototype._getNestedLookupTypeString = function (element) { - var resolvedType = '^', - excluded = this.ignoredNamespaces.concat('xs'); // do not process $type values wich start with - - if (element.hasOwnProperty('$type') && typeof element.$type === 'string') { - if (excluded.indexOf(element.$type.split(':')[0]) === -1) { - resolvedType += ('_' + element.$type + '#' + element.$name); - } - } - - if (element.children.length > 0) { - var self = this; - - element.children.forEach(function (child) { - var resolvedChildType = self._getNestedLookupTypeString(child).replace(/\^_/, ''); - - if (resolvedChildType && typeof resolvedChildType === 'string') { - resolvedType += ('_' + resolvedChildType); - } - }); - } - - return resolvedType; -}; - -OperationElement.prototype.postProcess = function(definitions, tag) { - var children = this.children; - for (var i = 0, child; child = children[i]; i++) { - if (child.name !== 'input' && child.name !== 'output') - continue; - if (tag === 'binding') { - this[child.name] = child; - children.splice(i--, 1); - continue; - } - var messageName = splitQName(child.$message).name; - var message = definitions.messages[messageName]; - message.postProcess(definitions); - if (message.element) { - definitions.messages[message.element.$name] = message; - this[child.name] = message.element; - } - else { - this[child.name] = message; - } - children.splice(i--, 1); - } - this.deleteFixedAttrs(); -}; - -PortTypeElement.prototype.postProcess = function(definitions) { - var children = this.children; - if (typeof children === 'undefined') - return; - for (var i = 0, child; child = children[i]; i++) { - if (child.name !== 'operation') - continue; - child.postProcess(definitions, 'portType'); - this.methods[child.$name] = child; - children.splice(i--, 1); - } - delete this.$name; - this.deleteFixedAttrs(); -}; - -BindingElement.prototype.postProcess = function(definitions) { - var type = splitQName(this.$type).name, - portType = definitions.portTypes[type], - style = this.style, - children = this.children; - if (portType){ - portType.postProcess(definitions); - this.methods = portType.methods; - - for (var i = 0, child; child = children[i]; i++) { - if (child.name !== 'operation') - continue; - child.postProcess(definitions, 'binding'); - children.splice(i--, 1); - child.style || (child.style = style); - var method = this.methods[child.$name]; - - if (method) { - method.style = child.style; - method.soapAction = child.soapAction; - method.inputSoap = child.input || null; - method.outputSoap = child.output || null; - method.inputSoap && method.inputSoap.deleteFixedAttrs(); - method.outputSoap && method.outputSoap.deleteFixedAttrs(); - } - } - } - delete this.$name; - delete this.$type; - this.deleteFixedAttrs(); -}; - -ServiceElement.prototype.postProcess = function(definitions) { - var children = this.children, - bindings = definitions.bindings; - if (children && children.length > 0) { - for (var i = 0, child; child = children[i]; i++) { - if (child.name !== 'port') - continue; - var bindingName = splitQName(child.$binding).name; - var binding = bindings[bindingName]; - if (binding) { - binding.postProcess(definitions); - this.ports[child.$name] = { - location: child.location, - binding: binding - }; - children.splice(i--, 1); - } - } - } - delete this.$name; - this.deleteFixedAttrs(); -}; - - -SimpleTypeElement.prototype.description = function(definitions) { - var children = this.children; - for (var i = 0, child; child = children[i]; i++) { - if (child instanceof RestrictionElement) - return this.$name + "|" + child.description(); - } - return {}; -}; - -RestrictionElement.prototype.description = function(definitions, xmlns) { - var children = this.children; - var desc; - for (var i=0, child; child=children[i]; i++) { - if (child instanceof SequenceElement || - child instanceof ChoiceElement) { - desc = child.description(definitions, xmlns); - break; - } - } - if (desc && this.$base) { - var type = splitQName(this.$base), - typeName = type.name, - ns = xmlns && xmlns[type.prefix] || definitions.xmlns[type.prefix], - schema = definitions.schemas[ns], - typeElement = schema && ( schema.complexTypes[typeName] || schema.types[typeName] || schema.elements[typeName] ); - - desc.getBase = function() { - return typeElement.description(definitions, schema.xmlns); - }; - return desc; - } - - // then simple element - var base = this.$base ? this.$base + "|" : ""; - return base + this.children.map(function(child) { - return child.description(); - }).join(","); -}; - -ExtensionElement.prototype.description = function(definitions, xmlns) { - var children = this.children; - var desc = {}; - for (var i=0, child; child=children[i]; i++) { - if (child instanceof SequenceElement || - child instanceof ChoiceElement) { - desc = child.description(definitions, xmlns); - } - } - if (this.$base) { - var type = splitQName(this.$base), - typeName = type.name, - ns = xmlns && xmlns[type.prefix] || definitions.xmlns[type.prefix], - schema = definitions.schemas[ns]; - - if (typeName in Primitives) { - return this.$base; - } - else { - var typeElement = schema && ( schema.complexTypes[typeName] || - schema.types[typeName] || schema.elements[typeName] ); - - if (typeElement) { - var base = typeElement.description(definitions, schema.xmlns); - extend(desc, base); - } - } - } - return desc; -}; - -EnumerationElement.prototype.description = function() { - return this[this.valueKey]; -}; - -ComplexTypeElement.prototype.description = function(definitions, xmlns) { - var children = this.children || []; - for (var i=0, child; child=children[i]; i++) { - if (child instanceof ChoiceElement || - child instanceof SequenceElement || - child instanceof AllElement || - child instanceof SimpleContentElement || - child instanceof ComplexContentElement) { - - return child.description(definitions, xmlns); - } - } - return {}; -}; - -ComplexContentElement.prototype.description = function(definitions, xmlns) { - var children = this.children; - for (var i = 0, child; child = children[i]; i++) { - if (child instanceof ExtensionElement) { - return child.description(definitions, xmlns); - } - } - return {}; -}; - -SimpleContentElement.prototype.description = function(definitions, xmlns) { - var children = this.children; - for (var i = 0, child; child = children[i]; i++) { - if (child instanceof ExtensionElement) { - return child.description(definitions, xmlns); - } - } - return {}; -}; - -ElementElement.prototype.description = function(definitions, xmlns) { - var element = {}, - name = this.$name; - var isMany = !this.$maxOccurs ? false : (isNaN(this.$maxOccurs) ? (this.$maxOccurs === 'unbounded') : (this.$maxOccurs > 1)); - if (this.$minOccurs !== this.$maxOccurs && isMany) { - name += '[]'; - } - - if (xmlns && xmlns[TNS_PREFIX]) { - this.$targetNamespace = xmlns[TNS_PREFIX]; - } - var type = this.$type || this.$ref; - if (type) { - type = splitQName(type); - var typeName = type.name, - ns = xmlns && xmlns[type.prefix] || definitions.xmlns[type.prefix], - schema = definitions.schemas[ns], - typeElement = schema && ( this.$type? schema.complexTypes[typeName] || schema.types[typeName] : schema.elements[typeName] ); - - if (ns && definitions.schemas[ns]) { - xmlns = definitions.schemas[ns].xmlns; - } - - if (typeElement && !(typeName in Primitives)) { - - if (!(typeName in definitions.descriptions.types)) { - - var elem = {}; - definitions.descriptions.types[typeName] = elem; - var description = typeElement.description(definitions, xmlns); - if (typeof description === 'string') { - elem = description; - } - else { - Object.keys(description).forEach(function (key) { - elem[key] = description[key]; - }); - } - - if (this.$ref) { - element = elem; - } - else { - element[name] = elem; - } - - if (typeof elem === 'object') { - elem.targetNSAlias = type.prefix; - elem.targetNamespace = ns; - } - - definitions.descriptions.types[typeName] = elem; - } - else { - if (this.$ref) { - element = definitions.descriptions.types[typeName]; - } - else { - element[name] = definitions.descriptions.types[typeName]; - } - } - - } - else { - element[name] = this.$type; - } - } - else { - var children = this.children; - element[name] = {}; - for (var i = 0, child; child = children[i]; i++) { - if (child instanceof ComplexTypeElement) { - element[name] = child.description(definitions, xmlns); - } - } - } - return element; -}; - -AllElement.prototype.description = -SequenceElement.prototype.description = function(definitions, xmlns) { - var children = this.children; - var sequence = {}; - for (var i = 0, child; child = children[i]; i++) { - if (child instanceof AnyElement) { - continue; - } - var description = child.description(definitions, xmlns); - for (var key in description) { - sequence[key] = description[key]; - } - } - return sequence; -}; - -ChoiceElement.prototype.description = function(definitions, xmlns) { - var children = this.children; - var choice = {}; - for (var i=0, child; child=children[i]; i++) { - var description = child.description(definitions, xmlns); - for (var key in description) { - choice[key] = description[key]; - } - } - return choice; -}; - -MessageElement.prototype.description = function(definitions) { - if (this.element) { - return this.element && this.element.description(definitions); - } - var desc = {}; - desc[this.$name] = this.parts; - return desc; -}; - -PortTypeElement.prototype.description = function(definitions) { - var methods = {}; - for (var name in this.methods) { - var method = this.methods[name]; - methods[name] = method.description(definitions); - } - return methods; -}; - -OperationElement.prototype.description = function(definitions) { - var inputDesc = this.input ? this.input.description(definitions) : null; - var outputDesc = this.output ? this.output.description(definitions) : null; - return { - input: inputDesc && inputDesc[Object.keys(inputDesc)[0]], - output: outputDesc && outputDesc[Object.keys(outputDesc)[0]] - }; -}; - -BindingElement.prototype.description = function(definitions) { - var methods = {}; - for (var name in this.methods) { - var method = this.methods[name]; - methods[name] = method.description(definitions); - } - return methods; -}; - -ServiceElement.prototype.description = function(definitions) { - var ports = {}; - for (var name in this.ports) { - var port = this.ports[name]; - ports[name] = port.binding.description(definitions); - } - return ports; -}; - -var WSDL = function(definition, uri, options) { - var self = this, - fromFunc; - - this.uri = uri; - this.callback = function() { - }; - this._includesWsdl = []; - - // initialize WSDL cache - this.WSDL_CACHE = (options || {}).WSDL_CACHE || {}; - - this._initializeOptions(options); - - if (typeof definition === 'string') { - definition = stripBom(definition); - fromFunc = this._fromXML; - } - else if (typeof definition === 'object') { - fromFunc = this._fromServices; - } - else { - throw new Error('WSDL constructor takes either an XML string or service definition'); - } - - process.nextTick(function() { - try { - fromFunc.call(self, definition); - } catch (e) { - return self.callback(e.message); - } - - self.processIncludes(function(err) { - var name; - if (err) { - return self.callback(err); - } - - self.definitions.deleteFixedAttrs(); - var services = self.services = self.definitions.services; - if (services) { - for (name in services) { - services[name].postProcess(self.definitions); - } - } - var complexTypes = self.definitions.complexTypes; - if (complexTypes) { - for (name in complexTypes) { - complexTypes[name].deleteFixedAttrs(); - } - } - - // for document style, for every binding, prepare input message element name to (methodName, output message element name) mapping - var bindings = self.definitions.bindings; - for (var bindingName in bindings) { - var binding = bindings[bindingName]; - if (typeof binding.style === 'undefined') { - binding.style = 'document'; - } - if (binding.style !== 'document') - continue; - var methods = binding.methods; - var topEls = binding.topElements = {}; - for (var methodName in methods) { - if (methods[methodName].input) { - var inputName = methods[methodName].input.$name; - var outputName=""; - if(methods[methodName].output ) - outputName = methods[methodName].output.$name; - topEls[inputName] = {"methodName": methodName, "outputName": outputName}; - } - } - } - - // prepare soap envelope xmlns definition string - self.xmlnsInEnvelope = self._xmlnsMap(); - - self.callback(err, self); - }); - - }); -}; - -WSDL.prototype.ignoredNamespaces = ['tns', 'targetNamespace', 'typedNamespace']; - -WSDL.prototype.ignoreBaseNameSpaces = false; - -WSDL.prototype.valueKey = '$value'; -WSDL.prototype.xmlKey = '$xml'; - -WSDL.prototype._initializeOptions = function (options) { - this._originalIgnoredNamespaces = (options || {}).ignoredNamespaces; - this.options = {}; - - var ignoredNamespaces = options ? options.ignoredNamespaces : null; - - if (ignoredNamespaces && - (Array.isArray(ignoredNamespaces.namespaces) || typeof ignoredNamespaces.namespaces === 'string')) { - if (ignoredNamespaces.override) { - this.options.ignoredNamespaces = ignoredNamespaces.namespaces; - } else { - this.options.ignoredNamespaces = this.ignoredNamespaces.concat(ignoredNamespaces.namespaces); - } - } else { - this.options.ignoredNamespaces = this.ignoredNamespaces; - } - - this.options.valueKey = options.valueKey || this.valueKey; - this.options.xmlKey = options.xmlKey || this.xmlKey; - - // Allow any request headers to keep passing through - this.options.wsdl_headers = options.wsdl_headers; - this.options.wsdl_options = options.wsdl_options; - - var ignoreBaseNameSpaces = options ? options.ignoreBaseNameSpaces : null; - if(ignoreBaseNameSpaces !== null && typeof ignoreBaseNameSpaces !== 'undefined' ) - this.options.ignoreBaseNameSpaces = ignoreBaseNameSpaces; - else - this.options.ignoreBaseNameSpaces = this.ignoreBaseNameSpaces; - - // Works only in client - this.options.forceSoap12Headers = options.forceSoap12Headers; - - if(options.overrideRootElement !== undefined) { - this.options.overrideRootElement = options.overrideRootElement; - } -}; - -WSDL.prototype.onReady = function(callback) { - if (callback) - this.callback = callback; -}; - -WSDL.prototype._processNextInclude = function(includes, callback) { - var self = this, - include = includes.shift(), - options; - - if (!include) - return callback(); - - var includePath; - if (!/^https?:/.test(self.uri) && !/^https?:/.test(include.location)) { - includePath = path.resolve(path.dirname(self.uri), include.location); - } else { - includePath = url.resolve(self.uri, include.location); - } - - options = _.assign({}, this.options); - // follow supplied ignoredNamespaces option - options.ignoredNamespaces = this._originalIgnoredNamespaces || this.options.ignoredNamespaces; - options.WSDL_CACHE = this.WSDL_CACHE; - - open_wsdl_recursive(includePath, options, function(err, wsdl) { - if (err) { - return callback(err); - } - - self._includesWsdl.push(wsdl); - - if(wsdl.definitions instanceof DefinitionsElement){ - _.merge(self.definitions, wsdl.definitions, function(a,b) { - return (a instanceof SchemaElement) ? a.merge(b) : undefined; - }); - }else{ - self.definitions.schemas[include.namespace || wsdl.definitions.$targetNamespace] = deepMerge(self.definitions.schemas[include.namespace || wsdl.definitions.$targetNamespace], wsdl.definitions); - } - self._processNextInclude(includes, function(err) { - callback(err); - }); - }); -}; - -WSDL.prototype.processIncludes = function(callback) { - var schemas = this.definitions.schemas, - includes = []; - - for (var ns in schemas) { - var schema = schemas[ns]; - includes = includes.concat(schema.includes || []); - } - - this._processNextInclude(includes, callback); -}; - -WSDL.prototype.describeServices = function() { - var services = {}; - for (var name in this.services) { - var service = this.services[name]; - services[name] = service.description(this.definitions); - } - return services; -}; - -WSDL.prototype.toXML = function() { - return this.xml || ''; -}; - -WSDL.prototype.xmlToObject = function(xml) { - var self = this; - var p = sax.parser(true); - var objectName = null; - var root = {}; - var schema = { - Envelope: { - Header: { - Security: { - UsernameToken: { - Username: 'string', - Password: 'string' - } - } - }, - Body: { - Fault: { - faultcode: 'string', - faultstring: 'string', - detail: 'string' - } - } - } - }; - var stack = [{name: null, object: root, schema: schema}]; - var xmlns = {}; - - var refs = {}, id; // {id:{hrefs:[],obj:}, ...} - - p.onopentag = function(node) { - var nsName = node.name; - var attrs = node.attributes; - - var name = splitQName(nsName).name, - attributeName, - top = stack[stack.length - 1], - topSchema = top.schema, - elementAttributes = {}, - hasNonXmlnsAttribute = false, - hasNilAttribute = false, - obj = {}; - var originalName = name; - - if (!objectName && top.name === 'Body' && name !== 'Fault') { - var message = self.definitions.messages[name]; - // Support RPC/literal messages where response body contains one element named - // after the operation + 'Response'. See http://www.w3.org/TR/wsdl#_names - if (!message) { - // Determine if this is request or response - var isInput = false; - var isOutput = false; - if ((/Response$/).test(name)) { - isOutput = true; - name = name.replace(/Response$/, ''); - } else if ((/Request$/).test(name)) { - isInput = true; - name = name.replace(/Request$/, ''); - } else if ((/Solicit$/).test(name)) { - isInput = true; - name = name.replace(/Solicit$/, ''); - } - // Look up the appropriate message as given in the portType's operations - var portTypes = self.definitions.portTypes; - var portTypeNames = Object.keys(portTypes); - // Currently this supports only one portType definition. - var portType = portTypes[portTypeNames[0]]; - if (isInput) - name = portType.methods[name].input.$name; - else - name = portType.methods[name].output.$name; - message = self.definitions.messages[name]; - // 'cache' this alias to speed future lookups - self.definitions.messages[originalName] = self.definitions.messages[name]; - } - - topSchema = message.description(self.definitions); - objectName = originalName; - } - - if (attrs.href) { - id = attrs.href.substr(1); - if (!refs[id]) - refs[id] = {hrefs: [], obj: null}; - refs[id].hrefs.push({par: top.object, key: name, obj: obj}); - } - if (id = attrs.id) { - if (!refs[id]) - refs[id] = {hrefs: [], obj: null}; - } - - //Handle element attributes - for(attributeName in attrs){ - if(/^xmlns:|^xmlns$/.test(attributeName)){ - xmlns[splitQName(attributeName).name] = attrs[attributeName]; - continue; - } - hasNonXmlnsAttribute = true; - elementAttributes[attributeName] = attrs[attributeName]; - } - - for(attributeName in elementAttributes){ - var res = splitQName(attributeName); - if(res.name === 'nil' && xmlns[res.prefix] === 'http://www.w3.org/2001/XMLSchema-instance'){ - hasNilAttribute = true; - break; - } - } - - if(hasNonXmlnsAttribute)obj[self.options.attributesKey] = elementAttributes; - - // Pick up the schema for the type specified in element's xsi:type attribute. - var xsiTypeSchema; - var xsiType = elementAttributes['xsi:type']; - if (xsiType) { - var type = splitQName(xsiType); - var typeURI; - if (type.prefix === TNS_PREFIX) { - // In case of xsi:type = "MyType" - typeURI = xmlns[type.prefix] || xmlns.xmlns; - } else { - typeURI = xmlns[type.prefix]; - } - var typeDef = self.findSchemaObject(typeURI, type.name); - if (typeDef) { - xsiTypeSchema = typeDef.description(self.definitions); - } - } - - if (topSchema && topSchema[name + '[]']) - name = name + '[]'; - stack.push({name: originalName, object: obj, schema: (xsiTypeSchema || (topSchema && topSchema[name])), id: attrs.id, nil: hasNilAttribute}); - }; - - p.onclosetag = function(nsName) { - var cur = stack.pop(), - obj = cur.object, - top = stack[stack.length - 1], - topObject = top.object, - topSchema = top.schema, - name = splitQName(nsName).name; - - if (typeof cur.schema === 'string' && (cur.schema === 'string' || cur.schema.split(':')[1] === 'string')) { - if (typeof obj === 'object' && Object.keys(obj).length === 0) obj = cur.object = ''; - } - - if(cur.nil === true) { - return; - } - - if (_.isPlainObject(obj) && !Object.keys(obj).length) { - obj = null; - } - - if (topSchema && topSchema[name + '[]']) { - if (!topObject[name]) - topObject[name] = []; - topObject[name].push(obj); - } else if (name in topObject) { - if (!Array.isArray(topObject[name])) { - topObject[name] = [topObject[name]]; - } - topObject[name].push(obj); - } else { - topObject[name] = obj; - } - - if (cur.id) { - refs[cur.id].obj = obj; - } - }; - - p.oncdata = function (text) { - text = trim(text); - if (!text.length) - return; - - if (/<\?xml[\s\S]+\?>/.test(text)) { - var top = stack[stack.length - 1]; - var value = self.xmlToObject(text); - if (top.object[self.options.attributesKey]) { - top.object[self.options.valueKey] = value; - } else { - top.object = value; - } - } else { - p.ontext(text); - } - }; - - p.ontext = function(text) { - text = trim(text); - if (!text.length) - return; - - var top = stack[stack.length - 1]; - var name = splitQName(top.schema).name, - value; - if (name === 'int' || name === 'integer') { - value = parseInt(text, 10); - } else if (name === 'bool' || name === 'boolean') { - value = text.toLowerCase() === 'true' || text === '1'; - } else if (name === 'dateTime' || name === 'date') { - value = new Date(text); - } else { - // handle string or other types - if (typeof top.object !== 'string') { - value = text; - } else { - value = top.object + text; - } - } - - if(top.object[self.options.attributesKey]) { - top.object[self.options.valueKey] = value; - } else { - top.object = value; - } - }; - - p.write(xml).close(); - - // merge obj with href - var merge = function(href, obj) { - for (var j in obj) { - if (obj.hasOwnProperty(j)) { - href.obj[j] = obj[j]; - } - } - }; - - // MultiRef support: merge objects instead of replacing - for (var n in refs) { - var ref = refs[n]; - for (var i = 0; i < ref.hrefs.length; i++) { - merge(ref.hrefs[i], ref.obj); - } - } - - if (root.Envelope) { - var body = root.Envelope.Body; - if (body.Fault) { - var code = selectn('faultcode.$value', body.Fault) || selectn('faultcode', body.Fault); - var string = selectn('faultstring.$value', body.Fault) || selectn('faultstring', body.Fault); - var detail = selectn('detail.$value', body.Fault) || selectn('detail.message', body.Fault); - var error = new Error(code + ': ' + string + (detail ? ': ' + detail : '')); - error.root = root; - throw error; - } - return root.Envelope; - } - return root; -}; - -/** - * Look up a XSD type or element by namespace URI and name - * @param {String} nsURI Namespace URI - * @param {String} qname Local or qualified name - * @returns {*} The XSD type/element definition - */ -WSDL.prototype.findSchemaObject = function(nsURI, qname) { - if (!nsURI || !qname) { - return null; - } - - var def = null; - - if (this.definitions.schemas) { - var schema = this.definitions.schemas[nsURI]; - if (schema) { - if (qname.indexOf(':') !== -1) { - qname = qname.substring(qname.indexOf(':') + 1, qname.length); - } - - // if the client passed an input element which has a `$lookupType` property instead of `$type` - // the `def` is found in `schema.elements`. - def = schema.complexTypes[qname] || schema.types[qname] || schema.elements[qname]; - } - } - - return def; -}; - -/** - * Create document style xml string from the parameters - * @param {String} name - * @param {*} params - * @param {String} nsPrefix - * @param {String} nsURI - * @param {String} type - */ -WSDL.prototype.objectToDocumentXML = function(name, params, nsPrefix, nsURI, type) { - var args = {}; - args[name] = params; - var parameterTypeObj = type ? this.findSchemaObject(nsURI, type) : null; - return this.objectToXML(args, null, nsPrefix, nsURI, true, null, parameterTypeObj); -}; - -/** - * Create RPC style xml string from the parameters - * @param {String} name - * @param {*} params - * @param {String} nsPrefix - * @param {String} nsURI - * @returns {string} - */ -WSDL.prototype.objectToRpcXML = function(name, params, nsPrefix, nsURI) { - var parts = []; - var defs = this.definitions; - var nsAttrName = '_xmlns'; - - nsPrefix = nsPrefix || findPrefix(defs.xmlns, nsURI); - nsURI = nsURI || defs.xmlns[nsPrefix]; - nsPrefix = nsPrefix === TNS_PREFIX ? '' : (nsPrefix + ':'); - parts.push(['<', nsPrefix, name, '>'].join('')); - - for (var key in params) { - if (!params.hasOwnProperty(key)) continue; - if (key !== nsAttrName) { - var value = params[key]; - parts.push(['<', key, '>'].join('')); - parts.push((typeof value === 'object') ? this.objectToXML(value, key, nsPrefix, nsURI) : xmlEscape(value)); - parts.push([''].join('')); - } - } - parts.push([''].join('')); - - return parts.join(''); -}; - -/** - * Convert an object to XML. This is a recursive method as it calls itself. - * - * @param {Object} obj the object to convert. - * @param {String} name the name of the element (if the object being traversed is - * an element). - * @param {String} nsPrefix the namespace prefix of the object I.E. xsd. - * @param {String} nsURI the full namespace of the object I.E. http://w3.org/schema. - * @param {Boolean} isFirst whether or not this is the first item being traversed. - * @param {?} xmlnsAttr - * @param {?} parameterTypeObject - * @param {NamespaceContext} nsContext Namespace context - */ -WSDL.prototype.objectToXML = function(obj, name, nsPrefix, nsURI, isFirst, xmlnsAttr, schemaObject, nsContext) { - var self = this; - var schema = this.definitions.schemas[nsURI]; - - var parentNsPrefix = nsPrefix ? nsPrefix.parent : undefined; - if(typeof parentNsPrefix !== 'undefined') { - //we got the parentNsPrefix for our array. setting the namespace-variable back to the current namespace string - nsPrefix = nsPrefix.current; - } - - var soapHeader = !schema; - var qualified = schema && schema.$elementFormDefault === 'qualified'; - var parts = []; - var prefixNamespace = (nsPrefix || qualified) && nsPrefix !== TNS_PREFIX; - - var xmlnsAttrib = ''; - if (nsURI && isFirst) { - if(self.options.overrideRootElement && self.options.overrideRootElement.xmlnsAttributes) { - self.options.overrideRootElement.xmlnsAttributes.forEach(function(attribute) { - xmlnsAttrib += ' ' + attribute.name + '="' + attribute.value + '"'; - }); - } else { - if (prefixNamespace && this.options.ignoredNamespaces.indexOf(nsPrefix) === -1) { - // resolve the prefix namespace - xmlnsAttrib += ' xmlns:' + nsPrefix + '="' + nsURI + '"'; - } - // only add default namespace if the schema elementFormDefault is qualified - if (qualified || soapHeader) xmlnsAttrib += ' xmlns="' + nsURI + '"'; - } - } - - if (!nsContext) { - nsContext = new NamespaceContext(); - nsContext.declareNamespace(nsPrefix, nsURI); - } else { - nsContext.pushContext(); - } - - // explicitly use xmlns attribute if available - if (xmlnsAttr && !(self.options.overrideRootElement && self.options.overrideRootElement.xmlnsAttributes)) { - xmlnsAttrib = xmlnsAttr; - } - - var ns = ''; - - if(self.options.overrideRootElement && isFirst) { - ns = self.options.overrideRootElement.namespace + ':'; - } else if (prefixNamespace && ((qualified || isFirst) || soapHeader) && this.options.ignoredNamespaces.indexOf(nsPrefix) === -1) { - // prefix element - ns = nsPrefix.indexOf(":") === -1 ? nsPrefix + ':' : nsPrefix; - } - - var i, n; - // start building out XML string. - if (Array.isArray(obj)) { - for (i = 0, n = obj.length; i < n; i++) { - var item = obj[i]; - var arrayAttr = self.processAttributes(item, nsContext), - correctOuterNsPrefix = parentNsPrefix || ns; //using the parent namespace prefix if given - - parts.push(['<', correctOuterNsPrefix, name, arrayAttr, xmlnsAttrib, '>'].join('')); - parts.push(self.objectToXML(item, name, nsPrefix, nsURI, false, null, schemaObject, nsContext)); - parts.push([''].join('')); - } - } else if (typeof obj === 'object') { - for (name in obj) { - if (!obj.hasOwnProperty(name)) continue; - //don't process attributes as element - if (name === self.options.attributesKey) { - continue; - } - //Its the value of a xml object. Return it directly. - if (name === self.options.xmlKey){ - nsContext.popContext(); - return obj[name]; - } - //Its the value of an item. Return it directly. - if (name === self.options.valueKey) { - nsContext.popContext(); - return xmlEscape(obj[name]); - } - - var child = obj[name]; - if (typeof child === 'undefined') - continue; - - var attr = self.processAttributes(child, nsContext); - - var value = ''; - var nonSubNameSpace = ''; - var emptyNonSubNameSpace = false; - - var nameWithNsRegex = /^([^:]+):([^:]+)$/.exec(name); - if (nameWithNsRegex) { - nonSubNameSpace = nameWithNsRegex[1] + ':'; - name = nameWithNsRegex[2]; - } else if(name[0] === ':'){ - emptyNonSubNameSpace = true; - name = name.substr(1); - } - - if (isFirst) { - value = self.objectToXML(child, name, nsPrefix, nsURI, false, null, schemaObject, nsContext); - } else { - - if (self.definitions.schemas) { - if (schema) { - var childSchemaObject = self.findChildSchemaObject(schemaObject, name); - //find sub namespace if not a primitive - if (childSchemaObject && - ((childSchemaObject.$type && (childSchemaObject.$type.indexOf('xsd:') === -1)) || - childSchemaObject.$ref || childSchemaObject.$name)) { - /*if the base name space of the children is not in the ingoredSchemaNamspaces we use it. - This is because in some services the child nodes do not need the baseNameSpace. - */ - - var childNsPrefix = ''; - var childName = ''; - var childNsURI; - var childXmlnsAttrib = ''; - - var elementQName = childSchemaObject.$ref || childSchemaObject.$name; - if (elementQName) { - elementQName = splitQName(elementQName); - childName = elementQName.name; - if (elementQName.prefix === TNS_PREFIX) { - // Local element - childNsURI = childSchemaObject.$targetNamespace; - childNsPrefix = nsContext.registerNamespace(childNsURI); - for (i = 0, n = this.ignoredNamespaces.length; i < n; i++) { - if (this.ignoredNamespaces[i] === childNsPrefix) { - childNsPrefix = nsPrefix; - break; - } - } - } else { - childNsPrefix = elementQName.prefix; - for (i = 0, n = this.ignoredNamespaces.length; i < n; i++) { - if (this.ignoredNamespaces[i] === childNsPrefix) { - childNsPrefix = nsPrefix; - break; - } - } - childNsURI = schema.xmlns[childNsPrefix] || self.definitions.xmlns[childNsPrefix]; - } - - var unqualified = false; - // Check qualification form for local elements - if (childSchemaObject.$name && childSchemaObject.targetNamespace === undefined) { - if (childSchemaObject.$form === 'unqualified') { - unqualified = true; - } else if (childSchemaObject.$form === 'qualified') { - unqualified = false; - } else { - unqualified = schema.$elementFormDefault !== 'qualified'; - } - } - if (unqualified) { - childNsPrefix = ''; - } - - if (childNsURI && childNsPrefix) { - if (nsContext.declareNamespace(childNsPrefix, childNsURI)) { - childXmlnsAttrib = ' xmlns:' + childNsPrefix + '="' + childNsURI + '"'; - xmlnsAttrib += childXmlnsAttrib; - } - } - } - - var resolvedChildSchemaObject; - if (childSchemaObject.$type) { - var typeQName = splitQName(childSchemaObject.$type); - var typePrefix = typeQName.prefix; - var typeURI = schema.xmlns[typePrefix] || self.definitions.xmlns[typePrefix]; - childNsURI = typeURI; - if (typeURI !== 'http://www.w3.org/2001/XMLSchema') { - // Add the prefix/namespace mapping, but not declare it - nsContext.addNamespace(typeQName.prefix, typeURI); - } - resolvedChildSchemaObject = - self.findSchemaType(typeQName.name, typeURI) || childSchemaObject; - } else { - resolvedChildSchemaObject = - self.findSchemaObject(childNsURI, childName) || childSchemaObject; - } - - if (childSchemaObject.$baseNameSpace && this.options.ignoreBaseNameSpaces) { - childNsPrefix = nsPrefix; - childNsURI = nsURI; - } - - if (this.options.ignoreBaseNameSpaces) { - childNsPrefix = ''; - childNsURI = ''; - } - - ns = childNsPrefix ? childNsPrefix + ':' : ''; - - if(Array.isArray(child)) { - //for arrays, we need to remember the current namespace - childNsPrefix = { - current: childNsPrefix, - parent: ns - }; - } - - value = self.objectToXML(child, name, childNsPrefix, childNsURI, - false, null, resolvedChildSchemaObject, nsContext); - } else if (obj[self.options.attributesKey] && obj[self.options.attributesKey].xsi_type) { - //if parent object has complex type defined and child not found in parent - var completeChildParamTypeObject = self.findChildSchemaObject( - obj[self.options.attributesKey].xsi_type.type, - obj[self.options.attributesKey].xsi_type.xmlns); - - nonSubNameSpace = obj[self.options.attributesKey].xsi_type.prefix + ':'; - nsContext.addNamespace(obj[self.options.attributesKey].xsi_type.prefix, - obj[self.options.attributesKey].xsi_type.xmlns); - value = self.objectToXML(child, name, obj[self.options.attributesKey].xsi_type.prefix, - obj[self.options.attributesKey].xsi_type.xmlns, false, null, null, nsContext); - } else { - if(Array.isArray(child)) { - name = nonSubNameSpace + name; - } - - value = self.objectToXML(child, name, nsPrefix, nsURI, false, null, null, nsContext); - } - } else { - value = self.objectToXML(child, name, nsPrefix, nsURI, false, null, null, nsContext); - } - } - } - - if (!Array.isArray(child)) { - parts.push(['<', emptyNonSubNameSpace ? '' : nonSubNameSpace || ns, name, attr, xmlnsAttrib, - (child === null ? ' xsi:nil="true"' : ''), '>'].join('')); - } - - parts.push(value); - if (!Array.isArray(child)) { - parts.push([''].join('')); - } - } - } else if (obj !== undefined) { - parts.push(xmlEscape(obj)); - } - nsContext.popContext(); - return parts.join(''); -}; - -WSDL.prototype.processAttributes = function(child, nsContext) { - var attr = ''; - - if(child === null) { - child = []; - } - - var attrObj = child[this.options.attributesKey]; - if (attrObj && attrObj.xsi_type) { - var xsiType = attrObj.xsi_type; - - var prefix = xsiType.prefix || xsiType.namespace; - // Generate a new namespace for complex extension if one not provided - if (!prefix) { - prefix = nsContext.registerNamespace(xsiType.xmlns); - } else { - nsContext.declareNamespace(prefix, xsiType.xmlns); - } - xsiType.prefix = prefix; - } - - - if (attrObj) { - for (var attrKey in attrObj) { - //handle complex extension separately - if (attrKey === 'xsi_type') { - var attrValue = attrObj[attrKey]; - attr += ' xsi:type="' + attrValue.prefix + ':' + attrValue.type + '"'; - attr += ' xmlns:' + attrValue.prefix + '="' + attrValue.xmlns + '"'; - - continue; - } else { - attr += ' ' + attrKey + '="' + xmlEscape(attrObj[attrKey]) + '"'; - } - } - } - - return attr; -}; - -/** - * Look up a schema type definition - * @param name - * @param nsURI - * @returns {*} - */ -WSDL.prototype.findSchemaType = function(name, nsURI) { - if (!this.definitions.schemas || !name || !nsURI) { - return null; - } - - var schema = this.definitions.schemas[nsURI]; - if (!schema || !schema.complexTypes) { - return null; - } - - return schema.complexTypes[name]; -}; - -WSDL.prototype.findChildSchemaObject = function(parameterTypeObj, childName) { - if (!parameterTypeObj || !childName) { - return null; - } - var found = null, - i = 0, - child, - ref; - - if(Array.isArray(parameterTypeObj.$lookupTypes) && parameterTypeObj.$lookupTypes.length) { - var types = parameterTypeObj.$lookupTypes; - - for(i = 0; i < types.length; i++) { - var typeObj = types[i]; - - if(typeObj.$name === childName) { - found = typeObj; - break; - } - } - } - - var object = parameterTypeObj; - if (object.$name === childName && object.name === 'element') { - return object; - } - if (object.$ref) { - ref = splitQName(object.$ref); - if (ref.name === childName) { - return object; - } - } - - var childNsURI; - if (object.$type) { - var typeInfo = splitQName(object.$type); - if (typeInfo.prefix === TNS_PREFIX) { - childNsURI = parameterTypeObj.$targetNamespace; - } else { - childNsURI = this.definitions.xmlns[typeInfo.prefix]; - } - var typeDef = this.findSchemaType(typeInfo.name, childNsURI); - if (typeDef) { - return this.findChildSchemaObject(typeDef, childName); - } - } - - if (object.children) { - for (i = 0, child; child = object.children[i]; i++) { - found = this.findChildSchemaObject(child, childName); - if (found) { - break; - } - - if (child.$base) { - var baseQName = splitQName(child.$base); - var childNameSpace = baseQName.prefix === TNS_PREFIX ? '' : baseQName.prefix; - childNsURI = this.definitions.xmlns[baseQName.prefix]; - - var foundBase = this.findSchemaType(baseQName.name, childNsURI); - - if (foundBase) { - found = this.findChildSchemaObject(foundBase, childName); - - if (found) { - found.$baseNameSpace = childNameSpace; - found.$type = childNameSpace + ':' + childName; - break; - } - } - } - } - - } - - if (!found && object.$name === childName) { - return object; - } - - return found; -}; - -WSDL.prototype._parse = function(xml) { - var self = this, - p = sax.parser(true), - stack = [], - root = null, - types = null, - schema = null, - options = self.options; - - p.onopentag = function(node) { - var nsName = node.name; - var attrs = node.attributes; - - var top = stack[stack.length - 1]; - var name; - if (top) { - try { - top.startElement(stack, nsName, attrs, options); - } catch (e) { - if (self.options.strict) { - throw e; - } else { - stack.push(new Element(nsName, attrs, options)); - } - } - } else { - name = splitQName(nsName).name; - if (name === 'definitions') { - root = new DefinitionsElement(nsName, attrs, options); - stack.push(root); - } else if (name === 'schema') { - // Shim a structure in here to allow the proper objects to be created when merging back. - root = new DefinitionsElement('definitions', {}, {}); - types = new TypesElement('types', {}, {}); - schema = new SchemaElement(nsName, attrs, options); - types.addChild(schema); - root.addChild(types); - stack.push(schema); - } else { - throw new Error('Unexpected root element of WSDL or include'); - } - } - }; - - p.onclosetag = function(name) { - var top = stack[stack.length - 1]; - assert(top, 'Unmatched close tag: ' + name); - - top.endElement(stack, name); - }; - - p.write(xml).close(); - - return root; -}; - -WSDL.prototype._fromXML = function(xml) { - this.definitions = this._parse(xml); - this.definitions.descriptions = { - types:{} - }; - this.xml = xml; -}; - -WSDL.prototype._fromServices = function(services) { - -}; - - - -WSDL.prototype._xmlnsMap = function() { - var xmlns = this.definitions.xmlns; - var str = ''; - for (var alias in xmlns) { - if (alias === '' || alias === TNS_PREFIX) - continue; - var ns = xmlns[alias]; - switch (ns) { - case "http://xml.apache.org/xml-soap" : // apachesoap - case "http://schemas.xmlsoap.org/wsdl/" : // wsdl - case "http://schemas.xmlsoap.org/wsdl/soap/" : // wsdlsoap - case "http://schemas.xmlsoap.org/wsdl/soap12/": // wsdlsoap12 - case "http://schemas.xmlsoap.org/soap/encoding/" : // soapenc - case "http://www.w3.org/2001/XMLSchema" : // xsd - continue; - } - if (~ns.indexOf('http://schemas.xmlsoap.org/')) - continue; - if (~ns.indexOf('http://www.w3.org/')) - continue; - if (~ns.indexOf('http://xml.apache.org/')) - continue; - str += ' xmlns:' + alias + '="' + ns + '"'; - } - return str; -}; - -/* - * Have another function to load previous WSDLs as we - * don't want this to be invoked externally (expect for tests) - * This will attempt to fix circular dependencies with XSD files, - * Given - * - file.wsdl - * - xs:import namespace="A" schemaLocation: A.xsd - * - A.xsd - * - xs:import namespace="B" schemaLocation: B.xsd - * - B.xsd - * - xs:import namespace="A" schemaLocation: A.xsd - * file.wsdl will start loading, import A, then A will import B, which will then import A - * Because A has already started to load previously it will be returned right away and - * have an internal circular reference - * B would then complete loading, then A, then file.wsdl - * By the time file A starts processing its includes its definitions will be already loaded, - * this is the only thing that B will depend on when "opening" A - */ -function open_wsdl_recursive(uri, options, callback) { - var fromCache, - WSDL_CACHE; - - if (typeof options === 'function') { - callback = options; - options = {}; - } - - WSDL_CACHE = options.WSDL_CACHE; - - if (fromCache = WSDL_CACHE[ uri ]) { - return callback.call(fromCache, null, fromCache); - } - - return open_wsdl(uri, options, callback); -} - -function open_wsdl(uri, options, callback) { - if (typeof options === 'function') { - callback = options; - options = {}; - } - - // initialize cache when calling open_wsdl directly - var WSDL_CACHE = options.WSDL_CACHE || {}; - var request_headers = options.wsdl_headers; - var request_options = options.wsdl_options; - - var wsdl; - if (!/^https?:/.test(uri)) { - debug('Reading file: %s', uri); - fs.readFile(uri, 'utf8', function(err, definition) { - if (err) { - callback(err); - } - else { - wsdl = new WSDL(definition, uri, options); - WSDL_CACHE[ uri ] = wsdl; - wsdl.WSDL_CACHE = WSDL_CACHE; - wsdl.onReady(callback); - } - }); - } - else { - debug('Reading url: %s', uri); - var httpClient = options.httpClient || new HttpClient(options); - httpClient.request(uri, null /* options */, function(err, response, definition) { - if (err) { - callback(err); - } else if (response && response.statusCode === 200) { - wsdl = new WSDL(definition, uri, options); - WSDL_CACHE[ uri ] = wsdl; - wsdl.WSDL_CACHE = WSDL_CACHE; - wsdl.onReady(callback); - } else { - callback(new Error('Invalid WSDL URL: ' + uri + "\n\n\r Code: " + response.statusCode + "\n\n\r Response Body: " + response.body)); - } - }, request_headers, request_options); - } - - return wsdl; -} - -exports.open_wsdl = open_wsdl; -exports.WSDL = WSDL; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..401542b35 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8231 @@ +{ + "name": "soap", + "version": "1.6.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "soap", + "version": "1.6.0", + "license": "MIT", + "dependencies": { + "axios": "^1.12.2", + "axios-ntlm": "^1.4.6", + "debug": "^4.4.3", + "formidable": "^3.5.4", + "get-stream": "^6.0.1", + "lodash": "^4.17.21", + "sax": "^1.4.1", + "strip-bom": "^3.0.0", + "whatwg-mimetype": "4.0.0", + "xml-crypto": "^6.1.2" + }, + "devDependencies": { + "@eslint/js": "^9.38.0", + "@types/debug": "^4.1.12", + "@types/formidable": "^3.4.6", + "@types/lodash": "^4.17.20", + "@types/node": "^14.0.0", + "@types/sax": "^1.2.7", + "@types/whatwg-mimetype": "^3.0.2", + "body-parser": "^2.2.0", + "colors": "^1.4.0", + "diff": "^8.0.2", + "doctoc": "^2.2.1", + "duplexer": "~0.1.2", + "eslint": "^9.38.0", + "express": "^5.1.0", + "finalhandler": "^2.1.0", + "glob": "^11.0.3", + "mocha": "^11.7.4", + "nyc": "^17.1.0", + "prettier": "^3.6.2", + "readable-stream": "^4.7.0", + "semver": "^7.7.3", + "serve-static": "^2.2.0", + "should": "^13.2.3", + "sinon": "^21.0.0", + "source-map-support": "^0.5.21", + "timekeeper": "^2.3.1", + "typedoc": "^0.28.14", + "typescript": "^5.9.3", + "typescript-eslint": "^8.46.1" + }, + "engines": { + "node": ">=14.17.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", + "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.1.tgz", + "integrity": "sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", + "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.38.0.tgz", + "integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", + "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@gerrit0/mini-shiki": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.13.1.tgz", + "integrity": "sha512-fDWM5QQc70jwBIt/WYMybdyXdyBmoJe7r1hpM+V/bHnyla79sygVDK2/LlVxIPc4n5FA3B5Wzt7AQH2+psNphg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-oniguruma": "^3.13.0", + "@shikijs/langs": "^3.13.0", + "@shikijs/themes": "^3.13.0", + "@shikijs/types": "^3.13.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", + "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.13.0.tgz", + "integrity": "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.13.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.13.0.tgz", + "integrity": "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.13.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.13.0.tgz", + "integrity": "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.13.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.13.0.tgz", + "integrity": "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", + "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "lodash.get": "^4.4.2", + "type-detect": "^4.1.0" + } + }, + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@textlint/ast-node-types": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-12.6.1.tgz", + "integrity": "sha512-uzlJ+ZsCAyJm+lBi7j0UeBbj+Oy6w/VWoGJ3iHRHE5eZ8Z4iK66mq+PG/spupmbllLtz77OJbY89BYqgFyjXmA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/markdown-to-ast": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/@textlint/markdown-to-ast/-/markdown-to-ast-12.6.1.tgz", + "integrity": "sha512-T0HO+VrU9VbLRiEx/kH4+gwGMHNMIGkp0Pok+p0I33saOOLyhfGvwOKQgvt2qkxzQEV2L5MtGB8EnW4r5d3CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "^12.6.1", + "debug": "^4.3.4", + "mdast-util-gfm-autolink-literal": "^0.1.3", + "remark-footnotes": "^3.0.0", + "remark-frontmatter": "^3.0.0", + "remark-gfm": "^1.0.0", + "remark-parse": "^9.0.0", + "traverse": "^0.6.7", + "unified": "^9.2.2" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/formidable": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/@types/formidable/-/formidable-3.4.6.tgz", + "integrity": "sha512-LI4Hk+KNsM5q7br4oMVoaWeb+gUqJpz1N8+Y2Q6Cz9cVH33ybahRKUWaRmMboVlkwSbOUGgwc/pEkS7yMSzoWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", + "dev": true + }, + "node_modules/@types/mdast": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "14.18.63", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", + "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/whatwg-mimetype": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", + "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", + "integrity": "sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/type-utils": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.46.2", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", + "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.2.tgz", + "integrity": "sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.2", + "@typescript-eslint/types": "^8.46.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.2.tgz", + "integrity": "sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.2.tgz", + "integrity": "sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.2.tgz", + "integrity": "sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", + "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.2.tgz", + "integrity": "sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.46.2", + "@typescript-eslint/tsconfig-utils": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/visitor-keys": "8.46.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.2.tgz", + "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.2", + "@typescript-eslint/types": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.2.tgz", + "integrity": "sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@xmldom/is-dom-node": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@xmldom/is-dom-node/-/is-dom-node-1.0.1.tgz", + "integrity": "sha512-CJDxIgE5I0FH+ttq/Fxy6nRpxP70+e2O048EPe85J2use3XKdatVM7dDVvFNjQudd9B49NPoZ+8PG49zj4Er8Q==", + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/anchor-markdown-header": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/anchor-markdown-header/-/anchor-markdown-header-0.6.0.tgz", + "integrity": "sha512-v7HJMtE1X7wTpNFseRhxsY/pivP4uAJbidVhPT+yhz4i/vV1+qx371IXuV9V7bN6KjFtheLJxqaSm0Y/8neJTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "~10.1.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios-ntlm": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/axios-ntlm/-/axios-ntlm-1.4.6.tgz", + "integrity": "sha512-4nR5cbVEBfPMTFkd77FEDpDuaR205JKibmrkaQyNwGcCx0szWNpRZaL0jZyMx4+mVY2PXHjRHuJafv9Oipl0Kg==", + "license": "MIT", + "dependencies": { + "axios": "^1.12.2", + "des.js": "^1.1.0", + "dev-null": "^0.1.1", + "js-md4": "^0.3.2" + } + }, + "node_modules/bail": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", + "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "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/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "dev": true, + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "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", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "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/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", + "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-require-extensions/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/dev-null": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", + "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==", + "license": "MIT" + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctoc": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/doctoc/-/doctoc-2.2.1.tgz", + "integrity": "sha512-qNJ1gsuo7hH40vlXTVVrADm6pdg30bns/Mo7Nv1SxuXSM1bwF9b4xQ40a6EFT/L1cI+Yylbyi8MPI4G4y7XJzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/markdown-to-ast": "^12.1.1", + "anchor-markdown-header": "^0.6.0", + "htmlparser2": "^7.2.0", + "minimist": "^1.2.6", + "underscore": "^1.13.2", + "update-section": "^0.3.3" + }, + "bin": { + "doctoc": "doctoc.js" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "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/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.190", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.190.tgz", + "integrity": "sha512-k4McmnB2091YIsdCgkS0fMVMPOJgxl93ltFzaryXqwip1AaxeDqKCGLxkXODDA5Ab/D+tV5EL5+aTx76RvLRxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.1.0.tgz", + "integrity": "sha512-xAEnNCT3w2Tg6MA7ly6QqYJvEoY1tm9iIjJ3yMKK9JPlWuRHAMoe5iETwQnx3M9TVbFMfsrBgWKR+IsmswwNjg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.38.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", + "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.1", + "@eslint/core": "^0.16.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.38.0", + "@eslint/plugin-kit": "^0.4.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "dev": true, + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "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/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "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/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "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-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "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", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "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/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "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": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "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/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "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", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "license": "ISC", + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/longest-streak": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz", + "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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/mdast-util-find-and-replace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz", + "integrity": "sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^4.0.0", + "unist-util-is": "^4.0.0", + "unist-util-visit-parents": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-footnote": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/mdast-util-footnote/-/mdast-util-footnote-0.1.7.tgz", + "integrity": "sha512-QxNdO8qSxqbO2e3m09KwDKfWiLgqyCurdWTQ198NpbZ2hxntdc+VKS4fDJCmNWbAroUdYnSthu+XbZ8ovh8C3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-to-markdown": "^0.6.0", + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", + "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-string": "^2.0.0", + "micromark": "~2.11.0", + "parse-entities": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-0.2.0.tgz", + "integrity": "sha512-FHKL4w4S5fdt1KjJCwB0178WJ0evnyyQr5kXTM3wrOVpytD0hrkvd+AOOjU9Td8onOejCkmZ+HQRT3CZ3coHHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-extension-frontmatter": "^0.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz", + "integrity": "sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-gfm-autolink-literal": "^0.1.0", + "mdast-util-gfm-strikethrough": "^0.2.0", + "mdast-util-gfm-table": "^0.1.0", + "mdast-util-gfm-task-list-item": "^0.1.0", + "mdast-util-to-markdown": "^0.6.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz", + "integrity": "sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ccount": "^1.0.0", + "mdast-util-find-and-replace": "^1.1.0", + "micromark": "^2.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz", + "integrity": "sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-to-markdown": "^0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz", + "integrity": "sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "markdown-table": "^2.0.0", + "mdast-util-to-markdown": "~0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz", + "integrity": "sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-to-markdown": "~0.6.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", + "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, + "node_modules/micromark-extension-footnote": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/micromark-extension-footnote/-/micromark-extension-footnote-0.3.2.tgz", + "integrity": "sha512-gr/BeIxbIWQoUm02cIfK7mdMZ/fbroRpLsck4kvFtjbzP4yi+OPVbnukTc/zy0i7spC2xYE/dbX1Sur8BEDJsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-0.2.2.tgz", + "integrity": "sha512-q6nPLFCMTLtfsctAuS0Xh4vaolxSFUWUWR6PZSrXXiRy+SANGllpcqdXFv2z07l0Xz/6Hl40hK0ffNCJPH2n1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fault": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz", + "integrity": "sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0", + "micromark-extension-gfm-autolink-literal": "~0.5.0", + "micromark-extension-gfm-strikethrough": "~0.6.5", + "micromark-extension-gfm-table": "~0.4.0", + "micromark-extension-gfm-tagfilter": "~0.3.0", + "micromark-extension-gfm-task-list-item": "~0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz", + "integrity": "sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "~2.11.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz", + "integrity": "sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz", + "integrity": "sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz", + "integrity": "sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz", + "integrity": "sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "~2.11.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mocha": { + "version": "11.7.4", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.4.tgz", + "integrity": "sha512-1jYAaY8x0kAZ0XszLWu14pzsf4KV740Gld4HXkhNTXwcHx4AUEDkPzgEHg9CM5dVcW+zv036tjpsEbLraPJj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/mocha/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/mocha/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/mocha/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", + "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^3.3.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^6.0.2", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nyc/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/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==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-on-spawn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/remark-footnotes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-3.0.0.tgz", + "integrity": "sha512-ZssAvH9FjGYlJ/PBVKdSmfyPc3Cz4rTWgZLI4iE/SX8Nt5l3o3oEjv3wwG5VD7xOjktzdwp5coac+kJV9l4jgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-footnote": "^0.1.0", + "micromark-extension-footnote": "^0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-frontmatter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-3.0.0.tgz", + "integrity": "sha512-mSuDd3svCHs+2PyO29h7iijIZx4plX0fheacJcAoYAASfgzgVIcXGYSq9GFyYocFLftQs8IOmmkgtOovs6d4oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-frontmatter": "^0.2.0", + "micromark-extension-frontmatter": "^0.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-1.0.0.tgz", + "integrity": "sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-gfm": "^0.1.0", + "micromark-extension-gfm": "^0.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", + "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "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", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "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/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", + "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sinon": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.0.tgz", + "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.5", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/spawn-wrap/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==", + "dev": true, + "license": "ISC" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/timekeeper": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/timekeeper/-/timekeeper-2.3.1.tgz", + "integrity": "sha512-LeQRS7/4JcC0PgdSFnfUiStQEdiuySlCj/5SJ18D+T1n9BoY7PxKFfCwLulpHXoLUFr67HxBddQdEX47lDGx1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/traverse": { + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.11.tgz", + "integrity": "sha512-vxXDZg8/+p3gblxB6BhhG5yWVn1kGRlaL8O78UDXc3wRnPizB5g83dcvWV1jpDMIPnjZjOFuxlMmE82XJ4407w==", + "dev": true, + "license": "MIT", + "dependencies": { + "gopd": "^1.2.0", + "typedarray.prototype.slice": "^1.0.5", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/trough": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", + "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typedarray.prototype.slice": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz", + "integrity": "sha512-q7QNVDGTdl702bVFiI5eY4l/HkgCM6at9KhcFbgUAzezHFbOVy4+0O/lCjsABEQwbZPravVfBIiBVGo89yzHFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "math-intrinsics": "^1.1.0", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-offset": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedoc": { + "version": "0.28.14", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.14.tgz", + "integrity": "sha512-ftJYPvpVfQvFzpkoSfHLkJybdA/geDJ8BGQt/ZnkkhnBYoYW6lBgPQXu6vqLxO4X75dA55hX8Af847H5KXlEFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@gerrit0/mini-shiki": "^3.12.0", + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "yaml": "^2.8.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 18", + "pnpm": ">= 10" + }, + "peerDependencies": { + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.46.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.2.tgz", + "integrity": "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.46.2", + "@typescript-eslint/parser": "8.46.2", + "@typescript-eslint/typescript-estree": "8.46.2", + "@typescript-eslint/utils": "8.46.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/unified": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", + "integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bail": "^1.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^2.0.0", + "trough": "^1.0.0", + "vfile": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", + "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", + "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-section": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/update-section/-/update-section-0.3.3.tgz", + "integrity": "sha512-BpRZMZpgXLuTiKeiu7kK0nIPwGdyrqrs6EDSaXtjD/aQ2T+qVo9a5hRC3HN3iJjCMxNT/VxoLGQ7E/OzE5ucnw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", + "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^2.0.0", + "vfile-message": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.3.tgz", + "integrity": "sha512-slxCaKbYjEdFT/o2rH9xS1hf4uRDch1w7Uo+apxhZ+sf/1d9e0ZVkn42kPNGP2dgjIx6YFvSevj0zHvbWe2jdw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-file-atomic/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==", + "dev": true, + "license": "ISC" + }, + "node_modules/xml-crypto": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-6.1.2.tgz", + "integrity": "sha512-leBOVQdVi8FvPJrMYoum7Ici9qyxfE4kVi+AkpUoYCSXaQF4IlBm1cneTK9oAxR61LpYxTx7lNcsnBIeRpGW2w==", + "license": "MIT", + "dependencies": { + "@xmldom/is-dom-node": "^1.0.1", + "@xmldom/xmldom": "^0.8.10", + "xpath": "^0.0.33" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/xpath": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.33.tgz", + "integrity": "sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA==", + "license": "MIT", + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", + "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json index 25c9e8950..c070c8dce 100644 --- a/package.json +++ b/package.json @@ -1,56 +1,78 @@ { "name": "soap", - "version": "0.14.0", + "version": "1.6.0", "description": "A minimal node SOAP client", "engines": { - "node": ">=0.10.0" + "node": ">=14.17.0" }, "author": "Vinay Pulim ", "dependencies": { - "compress": "^0.99.0", - "debug": "~0.7.4", - "lodash": "3.x.x", - "request": ">=2.9.0", - "sax": ">=0.6", - "selectn": "^0.9.6", - "strip-bom": "~0.3.1", - "ursa": "0.8.5 || >=0.9.3", - "node-uuid": "~1.4.3", - "ejs": "~2.3.4", - "xml-crypto": "~0.8.0" + "axios": "^1.12.2", + "axios-ntlm": "^1.4.6", + "debug": "^4.4.3", + "formidable": "^3.5.4", + "get-stream": "^6.0.1", + "lodash": "^4.17.21", + "sax": "^1.4.1", + "strip-bom": "^3.0.0", + "whatwg-mimetype": "4.0.0", + "xml-crypto": "^6.1.2" }, "repository": { "type": "git", - "url": "https://github.com/milewise/node-soap.git" + "url": "https://github.com/vpulim/node-soap.git" }, - "main": "./index.js", + "main": "./lib/soap.js", + "types": "./lib/soap.d.ts", "directories": { - "lib": "./lib" + "lib": "./lib", + "test": "./test" }, "scripts": { + "build": "tsc -p .", + "watch": "tsc -w -p .", + "lint": "eslint .", + "format": "prettier --write .", + "format:check": "prettier --check .", "toc": "./node_modules/.bin/doctoc Readme.md --github --maxlevel 3", - "pretest": "jshint index.js lib test", - "cover": "istanbul cover _mocha -- --timeout 10000 test/*-test.js test/security/*.js", - "coveralls": "cat ./coverage/lcov.info | coveralls -v", - "test": "mocha --timeout 10000 test/*-test.js test/security/*.js" + "cover": "OPENSSL_ENABLE_SHA1_SIGNATURES=1 nyc --extension=.ts --reporter=lcov --reporter=html --reporter=text mocha --no-parallel --timeout 30000 --exit test/*-test.js test/security/*.js", + "coveralls": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js -v", + "docs": "typedoc --out docs", + "test": "mocha --timeout 15000 --bail --exit test/*-test.js test/security/*.js" }, "keywords": [ "soap" ], "license": "MIT", "devDependencies": { - "colors": "^1.1.2", - "coveralls": "^2.11.6", - "diff": "^2.2.1", - "doctoc": "^1.0.0", - "duplexer": "~0.1.1", - "glob": "~3.2.8", - "istanbul": "^0.4.1", - "jshint": "2.3.0", - "mocha": "~1.17.0", - "readable-stream": "~2.0.2", - "semver": "~5.0.3", - "should": "~3.3.0", - "timekeeper": "~0.0.4" + "@eslint/js": "^9.38.0", + "@types/debug": "^4.1.12", + "@types/formidable": "^3.4.6", + "@types/lodash": "^4.17.20", + "@types/node": "^14.0.0", + "@types/sax": "^1.2.7", + "@types/whatwg-mimetype": "^3.0.2", + "body-parser": "^2.2.0", + "colors": "^1.4.0", + "diff": "^8.0.2", + "doctoc": "^2.2.1", + "duplexer": "~0.1.2", + "eslint": "^9.38.0", + "express": "^5.1.0", + "finalhandler": "^2.1.0", + "glob": "^11.0.3", + "mocha": "^11.7.4", + "nyc": "^17.1.0", + "prettier": "^3.6.2", + "readable-stream": "^4.7.0", + "semver": "^7.7.3", + "serve-static": "^2.2.0", + "should": "^13.2.3", + "sinon": "^21.0.0", + "source-map-support": "^0.5.21", + "timekeeper": "^2.3.1", + "typedoc": "^0.28.14", + "typescript": "^5.9.3", + "typescript-eslint": "^8.46.1" } } diff --git a/soap-stub.js b/soap-stub.js deleted file mode 100644 index 36000c133..000000000 --- a/soap-stub.js +++ /dev/null @@ -1,148 +0,0 @@ -var _ = require('lodash'); - -var aliasedClientStubs = {}; -var clientStubs = {}; - -/** - * This module stubs the soap module to allow for offline - * testing and stubbed clients. All clients' methods are stubbed with sinon and have - * additional functionality: - * - *
    - *
  • .respondWithError() - Responds with the mocked client's sample error response.
  • - *
  • .respondWithSuccess() - Responds with the mocked client's sample success response.
  • - *
- * - * Register a client by calling `.registerClient(urlToWsdl, clientStub)`. For an - * example client stub, see ./soap-stub-client-example.js. - * - * @property {Boolean} errOnCreateClient returns an error to the createClient method when set to true. - */ -module.exports = { - createClient: createClient, - createErroringStub: createErroringStub, - createRespondingStub: createRespondingStub, - errOnCreateClient: false, - getStub: getStub, - registerClient: registerClient, - reset: reset, - security: require('./lib/security') -}; - -/** - * Return a stubbed client based on the value of wsdlUrl. - * - * @throws if wsdlUrl is unknown. - * - * @param {String} wsdlUrl - * @param {Object} options - * @param {Function} cb - * @return {Object} - */ -function createClient(wsdlUrl, options, cb) { - if (!cb) { - cb = options; - options = {}; - } - - if (this.errOnCreateClient) { - return setTimeout(cb.bind(null, new Error('forced error on createClient'))); - } - - var client = getStub(wsdlUrl); - - if (client) { - resetStubbedMethods(client); - setTimeout(cb.bind(null, null, client)); - } else { - setTimeout(cb.bind(null, new Error('no client stubbed for ' + wsdlUrl))); - } -} - -/** - * Returns a method that calls all callbacks given to the method it is attached - * to with the given error. - * - *
- * myClientStub.someMethod.errorOnCall = createErroringStub(error);
- *
- * // elsewhere
- *
- * myClientStub.someMethod.errorOnCall();
- * 
- * - * @param {?} object anything - * @return {Function} - */ -function createErroringStub(err) { - return function() { - this.args.forEach(function(argSet) { - setTimeout(argSet[1].bind(null, err)); - }); - this.yields(err); - }; -} - -/** - * Returns a method that calls all callbacks given to the method it is attached - * to with the given response. - * - *
- * myClientStub.someMethod.respondWithError = createRespondingStub(errorResponse);
- *
- * // elsewhere
- *
- * myClientStub.someMethod.respondWithError();
- * 
- * - * @param {?} object anything - * @return {Function} - */ -function createRespondingStub(object) { - return function() { - this.args.forEach(function(argSet) { - setTimeout(argSet[1].bind(null, null, object)); - }); - this.yields(null, object); - }; -} - -/** - * Registers a stubbed client with soap-stub. urlToWsdl is the path you will use - * in your app. - * - * @param {String} alias A simple name to refer to the clientStub as. - * @param {String} urlToWsdl May be file system URL or http URL. - * @param {Object} clientStub A client with stubbed methods. - */ -function registerClient(alias, urlToWsdl, clientStub) { - aliasedClientStubs[alias] = clientStub; - clientStubs[urlToWsdl] = clientStub; -} - -/** - * Resets state associated with clientStubs. - */ -function reset() { - _.forEach(clientStubs, resetStubbedMethods); - this.errOnCreateClient = false; -} - -/** - * Returns a previously registered client stub. - * - * @param {String} aliasOrWsdlUrl - * @return {Object} clientStub - */ -function getStub(aliasOrWsdlUrl) { - return aliasedClientStubs[aliasOrWsdlUrl] || clientStubs[aliasOrWsdlUrl]; -} - -function resetStubbedMethods(client) { - Object.keys(client).forEach(function(method) { - method = client[method]; - if (typeof method === 'function' && typeof method.reset === 'function') { - method.reset(); - } - }); -} diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 000000000..a35a78cde --- /dev/null +++ b/src/client.ts @@ -0,0 +1,610 @@ +/* + * Copyright (c) 2011 Vinay Pulim + * MIT Licensed + */ + +import * as assert from 'assert'; +import { AxiosResponseHeaders, RawAxiosResponseHeaders } from 'axios'; +import { randomUUID } from 'crypto'; +import debugBuilder from 'debug'; +import { EventEmitter } from 'events'; +import getStream from 'get-stream'; +import * as _ from 'lodash'; +import { HttpClient } from './http'; +import { IHeaders, IHttpClient, IMTOMAttachments, IOptions, ISecurity, SoapMethod, SoapMethodAsync } from './types'; +import { findPrefix } from './utils'; +import { WSDL } from './wsdl'; +import { IPort, OperationElement, ServiceElement } from './wsdl/elements'; + +const debug = debugBuilder('node-soap'); + +const nonIdentifierChars = /[^a-z$_0-9]/i; + +export interface ISoapError extends Error { + response?; + body?; +} + +//eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging +export interface Client { + emit(event: 'request', xml: string, eid: string): boolean; + emit(event: 'message', message: string, eid: string): boolean; + emit(event: 'soapError', error: any, eid: string): boolean; + emit(event: 'response', body: any, response: any, eid: string): boolean; + + /** Emitted before a request is sent. */ + on(event: 'request', listener: (xml: string, eid: string) => void): this; + /** Emitted before a request is sent, but only the body is passed to the event handler. Useful if you don't want to log /store Soap headers. */ + on(event: 'message', listener: (message: string, eid: string) => void): this; + /** Emitted when an erroneous response is received. */ + on(event: 'soapError', listener: (error, eid: string) => void): this; + /** Emitted after a response is received. This is emitted for all responses (both success and errors). */ + on(event: 'response', listener: (body: any, response: any, eid: string) => void): this; +} + +//eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging +export class Client extends EventEmitter { + [method: string]: any; + /** contains last full soap request for client logging */ + public lastRequest?: string; + public lastMessage?: string; + public lastEndpoint?: string; + public lastRequestHeaders?: any; + public lastResponse?: any; + public lastResponseHeaders?: AxiosResponseHeaders | RawAxiosResponseHeaders; + public lastElapsedTime?: number; + public lastResponseAttachments: IMTOMAttachments; + + public wsdl: WSDL; + private httpClient: IHttpClient; + private soapHeaders: any[]; + private httpHeaders: IHeaders; + private bodyAttributes: string[]; + private endpoint: string; + private security: ISecurity; + private SOAPAction: string; + private streamAllowed: boolean; + private returnSaxStream: boolean; + private normalizeNames: boolean; + private overridePromiseSuffix: string; + + constructor(wsdl: WSDL, endpoint?: string, options?: IOptions) { + super(); + options = options || {}; + this.wsdl = wsdl; + this._initializeOptions(options); + this._initializeServices(endpoint); + this.httpClient = options.httpClient || new HttpClient(options); + } + + /** add soapHeader to soap:Header node */ + public addSoapHeader(soapHeader: any, name?: string, namespace?: any, xmlns?: string): number { + if (!this.soapHeaders) { + this.soapHeaders = []; + } + soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns); + return this.soapHeaders.push(soapHeader) - 1; + } + + public changeSoapHeader(index: any, soapHeader: any, name?: any, namespace?: any, xmlns?: any): void { + if (!this.soapHeaders) { + this.soapHeaders = []; + } + soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns); + this.soapHeaders[index] = soapHeader; + } + + /** return all defined headers */ + public getSoapHeaders(): string[] { + return this.soapHeaders; + } + + /** remove all defined headers */ + public clearSoapHeaders(): void { + this.soapHeaders = null; + } + + public addHttpHeader(name: string, value: any): void { + if (!this.httpHeaders) { + this.httpHeaders = {}; + } + this.httpHeaders[name] = value; + } + + public getHttpHeaders(): IHeaders { + return this.httpHeaders; + } + + public clearHttpHeaders(): void { + this.httpHeaders = null; + } + + public addBodyAttribute(bodyAttribute: any): void { + if (!this.bodyAttributes) { + this.bodyAttributes = []; + } + if (typeof bodyAttribute === 'object') { + let composition = ''; + Object.getOwnPropertyNames(bodyAttribute).forEach((prop) => { + composition += ' ' + prop + '="' + bodyAttribute[prop] + '"'; + }); + bodyAttribute = composition; + } + if (bodyAttribute.substr(0, 1) !== ' ') { + bodyAttribute = ' ' + bodyAttribute; + } + this.bodyAttributes.push(bodyAttribute); + } + + public getBodyAttributes(): any[] { + return this.bodyAttributes; + } + + public clearBodyAttributes(): void { + this.bodyAttributes = null; + } + + /** overwrite the SOAP service endpoint address */ + public setEndpoint(endpoint: string): void { + this.endpoint = endpoint; + this._initializeServices(endpoint); + } + + /** description of services, ports and methods as a JavaScript object */ + public describe(): any { + return this.wsdl.describeServices(); + } + + /** use the specified security protocol */ + public setSecurity(security: ISecurity): void { + this.security = security; + } + + public setSOAPAction(SOAPAction: string): void { + this.SOAPAction = SOAPAction; + } + + private _initializeServices(endpoint: string) { + const definitions = this.wsdl.definitions; + const services = definitions.services; + for (const name in services) { + this[name] = this._defineService(services[name], endpoint); + } + } + + private _initializeOptions(options: IOptions) { + this.streamAllowed = options.stream; + this.returnSaxStream = options.returnSaxStream; + this.normalizeNames = options.normalizeNames; + this.overridePromiseSuffix = options.overridePromiseSuffix || 'Async'; + this.wsdl.options.attributesKey = options.attributesKey || 'attributes'; + this.wsdl.options.envelopeKey = options.envelopeKey || 'soap'; + this.wsdl.options.envelopeSoapUrl = options.envelopeSoapUrl || 'http://schemas.xmlsoap.org/soap/envelope/'; + this.wsdl.options.preserveWhitespace = !!options.preserveWhitespace; + this.wsdl.options.forceUseSchemaXmlns = !!options.forceUseSchemaXmlns; + + const igNs = options.ignoredNamespaces; + if (igNs !== undefined && typeof igNs === 'object') { + if ('override' in igNs) { + if (igNs.override === true) { + if (igNs.namespaces !== undefined) { + this.wsdl.options.ignoredNamespaces = igNs.namespaces; + } + } + } + } + + if (options.overrideElementKey !== undefined) { + this.wsdl.options.overrideElementKey = options.overrideElementKey; + } + if (options.overrideRootElement !== undefined) { + this.wsdl.options.overrideRootElement = options.overrideRootElement; + } + this.wsdl.options.forceSoap12Headers = !!options.forceSoap12Headers; + } + + private _defineService(service: ServiceElement, endpoint?: string) { + const ports = service.ports; + const def = {}; + for (const name in ports) { + def[name] = this._definePort(ports[name], endpoint ? endpoint : ports[name].location); + } + return def; + } + + private _definePort(port: IPort, endpoint: string) { + const location = endpoint; + const binding = port.binding; + const methods = binding.methods; + const def: { + [methodName: string]: SoapMethod; + } = {}; + for (const name in methods) { + def[name] = this._defineMethod(methods[name], location); + const methodName = this.normalizeNames ? name.replace(nonIdentifierChars, '_') : name; + this[methodName] = def[name]; + if (!nonIdentifierChars.test(methodName)) { + const suffix = this.overridePromiseSuffix; + this[methodName + suffix] = this._promisifyMethod(def[name]); + } + } + return def; + } + + private _promisifyMethod(method: SoapMethod): SoapMethodAsync { + return (args: any, options?: any, extraHeaders?: any) => { + return new Promise((resolve, reject) => { + const callback = (err: any, result: any, rawResponse: any, soapHeader: any, rawRequest: any, mtomAttachments: any) => { + if (err) { + reject(err); + } else { + resolve([result, rawResponse, soapHeader, rawRequest, mtomAttachments]); + } + }; + method(args, callback, options, extraHeaders); + }); + }; + } + + private _defineMethod(method: OperationElement, location: string): SoapMethod { + let temp; + return (args, callback, options, extraHeaders) => { + if (typeof args === 'function') { + callback = args; + args = {}; + } else if (typeof options === 'function') { + temp = callback; + callback = options; + options = temp; + } else if (typeof extraHeaders === 'function') { + temp = callback; + callback = extraHeaders; + extraHeaders = options; + options = temp; + } + this._invoke( + method, + args, + location, + (error, result, rawResponse, soapHeader, rawRequest, mtomAttachments) => { + callback(error, result, rawResponse, soapHeader, rawRequest, mtomAttachments); + }, + options, + extraHeaders, + ); + }; + } + + private _processSoapHeader(soapHeader, name, namespace, xmlns) { + switch (typeof soapHeader) { + case 'object': + return this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); + case 'function': { + //eslint-disable-next-line @typescript-eslint/no-this-alias + const _this = this; + return (...args: any) => { + const result = soapHeader.apply(null, [...args]); + + if (typeof result === 'object') { + return _this.wsdl.objectToXML(result, name, namespace, xmlns, true); + } else { + return result; + } + }; + } + default: + return soapHeader; + } + } + + private _invoke(method: OperationElement, args, location: string, callback, options, extraHeaders) { + const name = method.$name; + const input = method.input; + const output = method.output; + const style = method.style; + const defs = this.wsdl.definitions; + const envelopeKey = this.wsdl.options.envelopeKey; + const envelopeSoapUrl = this.wsdl.options.envelopeSoapUrl; + const ns: string = defs.$targetNamespace; + let encoding = ''; + let message = ''; + let xml: string = null; + let soapAction: string; + const alias = findPrefix(defs.xmlns, ns); + let headers: any = { + 'Content-Type': 'text/xml; charset=utf-8', + }; + let xmlnsSoap = 'xmlns:' + envelopeKey + '="' + envelopeSoapUrl + '"'; + + const finish = (obj, body, response) => { + let result; + + if (!output) { + // one-way, no output expected + return callback(null, null, body, obj.Header, xml, response.mtomResponseAttachments); + } + + // If it's not HTML and Soap Body is empty + if (!obj.html && !obj.Body) { + if (response.status >= 400) { + const error: ISoapError = new Error('Error http status codes'); + error.response = response; + error.body = body; + this.emit('soapError', error, eid); + return callback(error, obj, body, obj.Header); + } + return callback(null, obj, body, obj.Header); + } + + if (typeof obj.Body !== 'object') { + const error: ISoapError = new Error('Cannot parse response'); + error.response = response; + error.body = body; + return callback(error, obj, body, undefined, xml); + } + + result = obj.Body[output.$name]; + // RPC/literal response body may contain elements with added suffixes I.E. + // 'Response', or 'Output', or 'Out' + // This doesn't necessarily equal the ouput message name. See WSDL 1.1 Section 2.4.5 + if (!result) { + result = obj.Body[output.$name.replace(/(?:Out(?:put)?|Response)$/, '')]; + } + if (!result) { + ['Response', 'Out', 'Output'].forEach((term) => { + if (Object.hasOwnProperty.call(obj.Body, name + term)) { + return (result = obj.Body[name + term]); + } + }); + } + callback(null, result, body, obj.Header, xml, response.mtomResponseAttachments); + }; + + const parseSync = (body, response) => { + let obj; + try { + obj = this.wsdl.xmlToObject(body); + } catch (error) { + // When the output element cannot be looked up in the wsdl and the body is JSON + // instead of sending the error, we pass the body in the response. + if (!output || !output.$lookupTypes) { + debug('Response element is not present. Unable to convert response xml to json.'); + // If the response is JSON then return it as-is. + const json = _.isObject(body) ? body : tryJSONparse(body); + if (json) { + return callback(null, response, json, undefined, xml); + } + } + error.response = response; + error.body = body; + this.emit('soapError', error, eid); + return callback(error, response, body, undefined, xml, response.mtomResponseAttachments); + } + return finish(obj, body, response); + }; + + if (this.SOAPAction) { + soapAction = this.SOAPAction; + } else if (method.soapAction !== undefined && method.soapAction !== null) { + soapAction = method.soapAction; + } else { + soapAction = (ns.lastIndexOf('/') !== ns.length - 1 ? ns + '/' : ns) + name; + } + + if (this.wsdl.options.forceSoap12Headers) { + headers['Content-Type'] = `application/soap+xml; charset=utf-8; action="${soapAction}"`; + xmlnsSoap = 'xmlns:' + envelopeKey + '="http://www.w3.org/2003/05/soap-envelope"'; + } else { + headers.SOAPAction = '"' + soapAction + '"'; + } + + options = options || {}; + + // Allow the security object to add headers + if (this.security && this.security.addHeaders) { + this.security.addHeaders(headers); + } + if (this.security && this.security.addOptions) { + this.security.addOptions(options); + } + + if (style === 'rpc' && (input.parts || input.name === 'element' || args === null)) { + assert.ok(!style || style === 'rpc', 'invalid message definition for document style binding'); + message = this.wsdl.objectToRpcXML(name, args, alias, ns, input.name !== 'element'); + if (method.inputSoap === 'encoded') encoding = 'soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" '; + } else { + assert.ok(!style || style === 'document', 'invalid message definition for rpc style binding'); + // pass `input.$lookupType` if `input.$type` could not be found + message = this.wsdl.objectToDocumentXML(input.$name, args, input.targetNSAlias, input.targetNamespace, input.$type || input.$lookupType); + } + + let decodedHeaders; + if (this.soapHeaders) { + decodedHeaders = this.soapHeaders + .map((header) => { + if (typeof header === 'function') { + return header(method, location, soapAction, args); + } else { + return header; + } + }) + .join(' '); + } + + xml = + '' + + '<' + + envelopeKey + + ':Envelope ' + + xmlnsSoap + + ' ' + + 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + + encoding + + this.wsdl.xmlnsInEnvelope + + '>' + + (decodedHeaders || (this.security && this.security.toXML()) + ? '<' + + envelopeKey + + ':Header' + + (this.wsdl.xmlnsInHeader ? ' ' + this.wsdl.xmlnsInHeader : '') + + '>' + + (decodedHeaders ? decodedHeaders : '') + + (this.security && !this.security.postProcess ? this.security.toXML() : '') + + '' + : '') + + '<' + + envelopeKey + + ':Body' + + (this.bodyAttributes ? this.bodyAttributes.join(' ') : '') + + '>' + + message + + '' + + ''; + + if (this.security && this.security.postProcess) { + xml = this.security.postProcess(xml, envelopeKey); + } + + if (options && options.postProcess) { + xml = options.postProcess(xml); + } + + this.lastMessage = message; + this.lastRequest = xml; + this.lastEndpoint = location; + + const eid: string = options.exchangeId || randomUUID(); + + this.emit('message', message, eid); + this.emit('request', xml, eid); + + // Add extra headers + if (this.httpHeaders === null) { + headers = {}; + } else { + for (const header in this.httpHeaders) { + headers[header] = this.httpHeaders[header]; + } + for (const attr in extraHeaders) { + headers[attr] = extraHeaders[attr]; + } + } + + const tryJSONparse = (body) => { + try { + return JSON.parse(body); + } catch { + return undefined; + } + }; + + if (this.streamAllowed && typeof this.httpClient.requestStream === 'function') { + callback = _.once(callback); + const startTime = Date.now(); + const onError = (err) => { + this.lastResponse = null; + this.lastResponseHeaders = null; + this.lastElapsedTime = null; + this.lastRequestHeaders = err.config && err.config.headers; + this.emit('response', null, null, eid); + if (this.returnSaxStream || !err.response || !err.response.data) { + callback(err, undefined, undefined, undefined, xml); + } else { + err.response.data.on('close', () => { + callback(err, undefined, undefined, undefined, xml); + }); + err.response.data.on('data', (e) => { + err.response.data = e.toString(); + }); + } + }; + + this.httpClient.requestStream(location, xml, headers, options, this).then((res) => { + this.lastRequestHeaders = res.headers; + if (res.data.on) { + res.data.on('error', (err) => onError(err)); + } + // When the output element cannot be looked up in the wsdl, + // play it safe and don't stream + if (res.status !== 200 || !output || !output.$lookupTypes) { + getStream(res.data).then((body) => { + this.lastResponse = body; + this.lastElapsedTime = Date.now() - startTime; + this.lastResponseHeaders = res && res.headers; + // Added mostly for testability, but possibly useful for debugging + this.lastRequestHeaders = (res.config && res.config.headers) || res.headers; + this.emit('response', body, res, eid); + + return parseSync(body, res); + }); + return; + } + if (this.returnSaxStream) { + // directly return the saxStream allowing the end user to define + // the parsing logics and corresponding errors managements + const saxStream = this.wsdl.getSaxStream(res.data); + return finish({ saxStream }, '', res.data); + } else { + this.wsdl.xmlToObject(res.data, (error, obj) => { + this.lastResponse = res; + this.lastElapsedTime = Date.now() - startTime; + this.lastResponseHeaders = res && res.headers; + // Added mostly for testability, but possibly useful for debugging + this.lastRequestHeaders = res.config.headers; + this.emit('response', '', res.data, eid); + + if (error) { + error.response = res; + error.body = ''; + this.emit('soapError', error, eid); + return callback(error, res, undefined, undefined, xml); + } + + return finish(obj, '', res); + }); + } + }, onError); + return; + } + + const startTime = Date.now(); + return this.httpClient.request( + location, + xml, + (err, response, body) => { + this.lastResponse = body; + if (response) { + this.lastResponseHeaders = response.headers; + this.lastElapsedTime = Date.now() - startTime; + this.lastResponseAttachments = response.mtomResponseAttachments; + // Added mostly for testability, but possibly useful for debugging + this.lastRequestHeaders = response.config && response.config.headers; + } + this.emit('response', body, response, eid); + + if (err) { + this.lastRequestHeaders = err.config && err.config.headers; + try { + if (err.response && err.response.data) { + this.wsdl.xmlToObject(err.response.data); + } + } catch (error) { + err.root = error.root || error; + } + callback(err, undefined, undefined, undefined, xml); + } else { + return parseSync(body, response); + } + }, + headers, + options, + this, + ); + } +} diff --git a/src/http.ts b/src/http.ts new file mode 100644 index 000000000..961b620d9 --- /dev/null +++ b/src/http.ts @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2011 Vinay Pulim + * MIT Licensed + */ + +import * as req from 'axios'; +import { NtlmClient } from 'axios-ntlm'; +import { randomUUID } from 'crypto'; +import debugBuilder from 'debug'; +import { ReadStream } from 'fs'; +import * as url from 'url'; +import MIMEType from 'whatwg-mimetype'; +import { gzipSync } from 'zlib'; +import { IExOptions, IHeaders, IHttpClient, IOptions } from './types'; +import { parseMTOMResp } from './utils'; + +const debug = debugBuilder('node-soap'); +import { version } from '../package.json'; + +export interface IAttachment { + name: string; + contentId: string; + mimetype: string; + body: NodeJS.ReadableStream; +} + +/** + * A class representing the http client + * @param {Object} [options] Options object. It allows the customization of + * `request` module + * + * @constructor + */ +export class HttpClient implements IHttpClient { + private _request: req.AxiosInstance; + private options: IOptions; + + constructor(options?: IOptions) { + options = options || {}; + this.options = options; + this._request = options.request || req.create(); + } + + /** + * Build the HTTP request (method, uri, headers, ...) + * @param {String} rurl The resource url + * @param {Object|String} data The payload + * @param {Object} exheaders Extra http headers + * @param {Object} exoptions Extra options + * @returns {Object} The http request object for the `request` module + */ + public buildRequest(rurl: string, data: any, exheaders?: IHeaders, exoptions: IExOptions = {}): any { + const curl = url.parse(rurl); + const method = data ? 'POST' : 'GET'; + + const host = curl.hostname; + const port = parseInt(curl.port, 10); + const headers: IHeaders = { + 'User-Agent': 'node-soap/' + version, + 'Accept': 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8', + 'Accept-Encoding': 'none', + 'Accept-Charset': 'utf-8', + ...(exoptions.forever && { Connection: 'keep-alive' }), + 'Host': host + (isNaN(port) ? '' : ':' + port), + }; + const mergeOptions = ['headers']; + + const { attachments: _attachments, ...newExoptions } = exoptions; + const attachments: IAttachment[] = _attachments || []; + + if (typeof data === 'string' && attachments.length === 0 && !exoptions.forceMTOM) { + headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + + exheaders = exheaders || {}; + for (const attr in exheaders) { + headers[attr] = exheaders[attr]; + } + + const options: req.AxiosRequestConfig = { + url: curl.href, + method: method, + headers: headers, + transformResponse: (data) => data, + }; + if (!exoptions.ntlm) { + options.validateStatus = null; + } + if (exoptions.forceMTOM || attachments.length > 0) { + const start = randomUUID(); + let action = null; + if (headers['Content-Type'].indexOf('action') > -1) { + for (const ct of headers['Content-Type'].split('; ')) { + if (ct.indexOf('action') > -1) { + action = ct; + } + } + } + const boundary = randomUUID(); + headers['Content-Type'] = 'multipart/related; type="application/xop+xml"; start="<' + start + '>"; start-info="text/xml"; boundary=' + boundary; + if (action) { + headers['Content-Type'] = headers['Content-Type'] + '; ' + action; + } + const multipart: any[] = [ + { + 'Content-Type': 'application/xop+xml; charset=UTF-8; type="text/xml"', + 'Content-ID': '<' + start + '>', + 'body': data, + }, + ]; + + attachments.forEach((attachment) => { + multipart.push({ + 'Content-Type': attachment.mimetype, + 'Content-Transfer-Encoding': 'binary', + 'Content-ID': '<' + attachment.contentId + '>', + 'Content-Disposition': 'attachment; filename="' + attachment.name + '"', + 'body': attachment.body, + }); + }); + options.data = [Buffer.from(`--${boundary}\r\n`)]; + + let multipartCount = 0; + multipart.forEach((part) => { + Object.keys(part).forEach((key) => { + if (key !== 'body') { + options.data.push(Buffer.from(`${key}: ${part[key]}\r\n`)); + } + }); + options.data.push(Buffer.from('\r\n'), Buffer.from(part.body), Buffer.from(`\r\n--${boundary}${multipartCount === multipart.length - 1 ? '--' : ''}\r\n`)); + multipartCount++; + }); + options.data = Buffer.concat(options.data); + } else { + options.data = data; + } + + if (exoptions.forceGzip) { + options.decompress = true; + options.data = gzipSync(options.data); + options.headers['Accept-Encoding'] = 'gzip,deflate'; + options.headers['Content-Encoding'] = 'gzip'; + } + + for (const attr in newExoptions) { + if (mergeOptions.indexOf(attr) !== -1) { + for (const header in exoptions[attr]) { + options[attr][header] = exoptions[attr][header]; + } + } else { + options[attr] = exoptions[attr]; + } + } + debug('Http request: %j', options); + return options; + } + + /** + * Handle the http response + * @param {Object} The req object + * @param {Object} res The res object + * @param {Object} body The http body + * @param {Object} The parsed body + */ + public handleResponse(req: req.AxiosPromise, res: req.AxiosResponse, body: any) { + debug('Http response body: %j', body); + if (typeof body === 'string') { + // Remove any extra characters that appear before or after the SOAP envelope. + const regex = /(?:<\?[^?]*\?>[\s]*)?<([^:]*):Envelope([\S\s]*)<\/\1:Envelope>/i; + const match = body.replace(//, '').match(regex); + if (match) { + body = match[0]; + } + } + return body; + } + + public request(rurl: string, data: any, callback: (error: any, res?: any, body?: any) => any, exheaders?: IHeaders, exoptions?: IExOptions) { + const options = this.buildRequest(rurl, data, exheaders, exoptions); + let req: req.AxiosPromise; + if (exoptions !== undefined && exoptions.ntlm) { + const ntlmReq = NtlmClient({ + username: exoptions.username, + password: exoptions.password, + workstation: exoptions.workstation || '', + domain: exoptions.domain || '', + }); + req = ntlmReq(options); + } else { + if (this.options.parseReponseAttachments) { + options.responseType = 'arraybuffer'; + options.responseEncoding = 'binary'; + } + req = this._request(options); + } + //eslint-disable-next-line @typescript-eslint/no-this-alias + const _this = this; + req.then( + (res) => { + const handleBody = (body?: string) => { + res.data = this.handleResponse(req, res, body || res.data); + callback(null, res, res.data); + return res; + }; + + if (_this.options.parseReponseAttachments) { + const isMultipartResp = res.headers['content-type'] && res.headers['content-type'].toLowerCase().indexOf('multipart/related') > -1; + if (isMultipartResp) { + let boundary; + const parsedContentType = MIMEType.parse(res.headers['content-type']); + if (parsedContentType) { + boundary = parsedContentType.parameters.get('boundary'); + } + if (!boundary) { + return callback(new Error('Missing boundary from content-type')); + } + return parseMTOMResp(res.data, boundary, (err, multipartResponse) => { + if (err) { + return callback(err); + } + // first part is the soap response + const firstPart = multipartResponse.parts.shift(); + if (!firstPart || !firstPart.body) { + return callback(new Error('Cannot parse multipart response')); + } + (res as any).mtomResponseAttachments = multipartResponse; + return handleBody(firstPart.body.toString(_this.options.encoding || 'utf8')); + }); + } else { + return handleBody(res.data.toString(_this.options.encoding || 'utf8')); + } + } else { + return handleBody(); + } + }, + (err) => { + return callback(err); + }, + ); + return req; + } + + public requestStream(rurl: string, data: any, exheaders?: IHeaders, exoptions?: IExOptions): req.AxiosPromise { + const options = this.buildRequest(rurl, data, exheaders, exoptions); + options.responseType = 'stream'; + const req = this._request(options).then((res) => { + res.data = this.handleResponse(req, res, res.data); + return res; + }); + return req; + } +} diff --git a/src/nscontext.ts b/src/nscontext.ts new file mode 100644 index 000000000..a4ff87f31 --- /dev/null +++ b/src/nscontext.ts @@ -0,0 +1,232 @@ +interface INamespace { + declared: boolean; + prefix: string; + uri: string; +} + +/** + * Scope for XML namespaces + * @param {NamespaceScope} [parent] Parent scope + * @returns {NamespaceScope} + * @constructor + */ +class NamespaceScope { + public parent: NamespaceScope; + public namespaces: { [key: string]: INamespace }; + + constructor(parent: NamespaceScope) { + this.parent = parent; + this.namespaces = {}; + } + + /** + * Look up the namespace URI by prefix + * @param {String} prefix Namespace prefix + * @param {Boolean} [localOnly] Search current scope only + * @returns {String} Namespace URI + */ + public getNamespaceURI(prefix: string, localOnly?: boolean): string { + switch (prefix) { + case 'xml': + return 'http://www.w3.org/XML/1998/namespace'; + case 'xmlns': + return 'http://www.w3.org/2000/xmlns/'; + default: { + const nsUri = this.namespaces[prefix]; + /*jshint -W116 */ + if (nsUri != null) { + return nsUri.uri; + } else if (!localOnly && this.parent) { + return this.parent.getNamespaceURI(prefix); + } else { + return null; + } + } + } + } + + public getNamespaceMapping(prefix: string): INamespace { + switch (prefix) { + case 'xml': + return { + uri: 'http://www.w3.org/XML/1998/namespace', + prefix: 'xml', + declared: true, + }; + case 'xmlns': + return { + uri: 'http://www.w3.org/2000/xmlns/', + prefix: 'xmlns', + declared: true, + }; + default: { + const mapping = this.namespaces[prefix]; + /*jshint -W116 */ + if (mapping != null) { + return mapping; + } else if (this.parent) { + return this.parent.getNamespaceMapping(prefix); + } else { + return null; + } + } + } + } + + /** + * Look up the namespace prefix by URI + * @param {String} nsUri Namespace URI + * @param {Boolean} [localOnly] Search current scope only + * @returns {String} Namespace prefix + */ + public getPrefix(nsUri: string, localOnly?: boolean): string { + switch (nsUri) { + case 'http://www.w3.org/XML/1998/namespace': + return 'xml'; + case 'http://www.w3.org/2000/xmlns/': + return 'xmlns'; + default: + for (const p in this.namespaces) { + if (this.namespaces[p].uri === nsUri) { + return p; + } + } + if (!localOnly && this.parent) { + return this.parent.getPrefix(nsUri); + } else { + return null; + } + } + } +} + +/** + * Namespace context that manages hierarchical scopes + * @returns {NamespaceContext} + * @constructor + */ +export class NamespaceContext { + public scopes: NamespaceScope[]; + public prefixCount: number; + public currentScope?: NamespaceScope; + + constructor() { + this.scopes = []; + this.pushContext(); + this.prefixCount = 0; + } + + /** + * Add a prefix/URI namespace mapping + * @param {String} prefix Namespace prefix + * @param {String} nsUri Namespace URI + * @param {Boolean} [localOnly] Search current scope only + * @returns {boolean} true if the mapping is added or false if the mapping + * already exists + */ + public addNamespace(prefix: string, nsUri: string, localOnly?: boolean): boolean { + if (this.getNamespaceURI(prefix, localOnly) === nsUri) { + return false; + } + if (this.currentScope) { + this.currentScope.namespaces[prefix] = { + uri: nsUri, + prefix: prefix, + declared: false, + }; + return true; + } + return false; + } + + /** + * Push a scope into the context + * @returns {NamespaceScope} The current scope + */ + public pushContext(): NamespaceScope { + const scope = new NamespaceScope(this.currentScope); + this.scopes.push(scope); + this.currentScope = scope; + return scope; + } + + /** + * Pop a scope out of the context + * @returns {NamespaceScope} The removed scope + */ + public popContext(): NamespaceScope { + const scope = this.scopes.pop(); + if (scope) { + this.currentScope = scope.parent; + } else { + this.currentScope = null; + } + return scope; + } + + /** + * Look up the namespace URI by prefix + * @param {String} prefix Namespace prefix + * @param {Boolean} [localOnly] Search current scope only + * @returns {String} Namespace URI + */ + public getNamespaceURI(prefix: string, localOnly?: boolean): string { + return this.currentScope && this.currentScope.getNamespaceURI(prefix, localOnly); + } + + /** + * Look up the namespace prefix by URI + * @param {String} nsURI Namespace URI + * @param {Boolean} [localOnly] Search current scope only + * @returns {String} Namespace prefix + */ + public getPrefix(nsUri: string, localOnly?: boolean): string { + return this.currentScope && this.currentScope.getPrefix(nsUri, localOnly); + } + + /** + * Register a namespace + * @param {String} nsUri Namespace URI + * @returns {String} The matching or generated namespace prefix + */ + public registerNamespace(nsUri: string): string { + let prefix = this.getPrefix(nsUri); + if (prefix) { + // If the namespace has already mapped to a prefix + return prefix; + } else { + // Try to generate a unique namespace + while (true) { + prefix = 'ns' + ++this.prefixCount; + if (!this.getNamespaceURI(prefix)) { + // The prefix is not used + break; + } + } + } + this.addNamespace(prefix, nsUri, true); + return prefix; + } + + /** + * Declare a namespace prefix/uri mapping + * @param {String} prefix Namespace prefix + * @param {String} nsUri Namespace URI + * @returns {Boolean} true if the declaration is created + */ + public declareNamespace(prefix: string, nsUri: string): boolean { + if (this.currentScope) { + const mapping = this.currentScope.getNamespaceMapping(prefix); + if (mapping && mapping.uri === nsUri && mapping.declared) { + return false; + } + this.currentScope.namespaces[prefix] = { + uri: nsUri, + prefix: prefix, + declared: true, + }; + return true; + } + return false; + } +} diff --git a/src/security/BasicAuthSecurity.ts b/src/security/BasicAuthSecurity.ts new file mode 100644 index 000000000..dfbdab47a --- /dev/null +++ b/src/security/BasicAuthSecurity.ts @@ -0,0 +1,27 @@ +import * as _ from 'lodash'; +import { IHeaders, ISecurity } from '../types'; + +export class BasicAuthSecurity implements ISecurity { + private _username: string; + private _password: string; + private defaults; + + constructor(username: string, password: string, defaults?: any) { + this._username = username; + this._password = password; + this.defaults = {}; + _.merge(this.defaults, defaults); + } + + public addHeaders(headers: IHeaders): void { + headers.Authorization = 'Basic ' + Buffer.from(this._username + ':' + this._password || '').toString('base64'); + } + + public toXML(): string { + return ''; + } + + public addOptions(options: any): void { + _.merge(options, this.defaults); + } +} diff --git a/src/security/BearerSecurity.ts b/src/security/BearerSecurity.ts new file mode 100644 index 000000000..8a12ddee2 --- /dev/null +++ b/src/security/BearerSecurity.ts @@ -0,0 +1,25 @@ +import * as _ from 'lodash'; +import { IHeaders, ISecurity } from '../types'; + +export class BearerSecurity implements ISecurity { + private defaults; + private _token: string; + + constructor(token: string, defaults?: any) { + this._token = token; + this.defaults = {}; + _.merge(this.defaults, defaults); + } + + public addHeaders(headers: IHeaders): void { + headers.Authorization = 'Bearer ' + this._token; + } + + public toXML(): string { + return ''; + } + + public addOptions(options: any): void { + _.merge(options, this.defaults); + } +} diff --git a/src/security/ClientSSLSecurity.ts b/src/security/ClientSSLSecurity.ts new file mode 100644 index 000000000..3294855bf --- /dev/null +++ b/src/security/ClientSSLSecurity.ts @@ -0,0 +1,87 @@ +import * as fs from 'fs'; +import * as https from 'https'; +import * as _ from 'lodash'; +import { ISecurity } from '../types'; + +/** + * activates SSL for an already existing client + * + * @module ClientSSLSecurity + * @param {Buffer|String} key + * @param {Buffer|String} cert + * @param {Buffer|String|Array} [ca] + * @param {Object} [defaults] + * @constructor + */ +export class ClientSSLSecurity implements ISecurity { + private key: Buffer; + private cert: Buffer; + private ca; + private defaults; + private agent: https.Agent; + + constructor(key: string | Buffer, cert: string | Buffer, ca?: Buffer | string | any[] | any, defaults?: any) { + if (key) { + if (Buffer.isBuffer(key)) { + this.key = key; + } else if (typeof key === 'string') { + this.key = fs.readFileSync(key); + } else { + throw new Error('key should be a buffer or a string!'); + } + } + + if (cert) { + if (Buffer.isBuffer(cert)) { + this.cert = cert; + } else if (typeof cert === 'string') { + this.cert = fs.readFileSync(cert); + } else { + throw new Error('cert should be a buffer or a string!'); + } + } + + if (ca) { + if (Buffer.isBuffer(ca) || Array.isArray(ca)) { + this.ca = ca; + } else if (typeof ca === 'string') { + this.ca = fs.readFileSync(ca); + } else { + defaults = ca; + this.ca = null; + } + } + + this.defaults = {}; + _.merge(this.defaults, defaults); + + this.agent = null; + } + + public toXML(): string { + return ''; + } + + public addOptions(options: any): void { + let httpsAgent = null; + + options.key = this.key; + options.cert = this.cert; + options.ca = this.ca; + _.merge(options, this.defaults); + + if (options.forever) { + if (!this.agent) { + options.keepAlive = true; + + this.agent = new https.Agent(options); + } + + httpsAgent = this.agent; + } else { + httpsAgent = new https.Agent(options); + } + + options.httpsAgent = httpsAgent; + } +} diff --git a/src/security/ClientSSLSecurityPFX.ts b/src/security/ClientSSLSecurityPFX.ts new file mode 100644 index 000000000..bc31816eb --- /dev/null +++ b/src/security/ClientSSLSecurityPFX.ts @@ -0,0 +1,56 @@ +import * as fs from 'fs'; +import * as https from 'https'; +import * as _ from 'lodash'; +import { ISecurity } from '../types'; + +/** + * activates SSL for an already existing client using a PFX cert + * + * @module ClientSSLSecurityPFX + * @param {Buffer|String} pfx + * @param {String} passphrase + * @constructor + */ +export class ClientSSLSecurityPFX implements ISecurity { + private pfx: Buffer; + private defaults; + private passphrase: string; + + constructor(pfx: string | Buffer, defaults?: any); + constructor(pfx: string | Buffer, passphrase: string, defaults?: any); + constructor(pfx: string | Buffer, passphrase: string, defaults?: any) { + if (typeof passphrase === 'object') { + defaults = passphrase; + } + if (pfx) { + if (Buffer.isBuffer(pfx)) { + this.pfx = pfx; + } else if (typeof pfx === 'string') { + this.pfx = fs.readFileSync(pfx); + } else { + throw new Error('supplied pfx file should be a buffer or a file location'); + } + } + + if (passphrase) { + if (typeof passphrase === 'string') { + this.passphrase = passphrase; + } + } + this.defaults = {}; + _.merge(this.defaults, defaults); + } + + public toXML(): string { + return ''; + } + + public addOptions(options: any): void { + options.pfx = this.pfx; + if (this.passphrase) { + options.passphrase = this.passphrase; + } + _.merge(options, this.defaults); + options.httpsAgent = new https.Agent(options); + } +} diff --git a/src/security/NTLMSecurity.ts b/src/security/NTLMSecurity.ts new file mode 100644 index 000000000..2422bbbf0 --- /dev/null +++ b/src/security/NTLMSecurity.ts @@ -0,0 +1,34 @@ +import * as _ from 'lodash'; +import { IHeaders, ISecurity } from '../types'; + +export class NTLMSecurity implements ISecurity { + private defaults; + + constructor(defaults: any); + constructor(username: any, password?: string, domain?: string, workstation?: string) { + if (typeof username === 'object') { + this.defaults = username; + this.defaults.ntlm = true; + } else { + this.defaults = { + ntlm: true, + username: username, + password: password, + domain: domain, + workstation: workstation, + }; + } + } + + public addHeaders(headers: IHeaders): void { + headers.Connection = 'keep-alive'; + } + + public toXML(): string { + return ''; + } + + public addOptions(options: any): void { + _.merge(options, this.defaults); + } +} diff --git a/src/security/WSSecurity.ts b/src/security/WSSecurity.ts new file mode 100644 index 000000000..2915e0c44 --- /dev/null +++ b/src/security/WSSecurity.ts @@ -0,0 +1,128 @@ +import * as crypto from 'crypto'; +import { ISecurity } from '../types'; +import { passwordDigest, xmlEscape } from '../utils'; + +const validPasswordTypes = ['PasswordDigest', 'PasswordText']; + +export interface IWSSecurityOptions { + passwordType?: string; + hasTimeStamp?: boolean; + hasNonce?: boolean; + hasTokenCreated?: boolean; + actor?: string; + mustUnderstand?; + envelopeKey?: string; + appendElement?: string; +} + +export class WSSecurity implements ISecurity { + private _username: string; + private _password: string; + private _passwordType: string; + private _hasTimeStamp: boolean; + private _hasNonce: boolean; + private _hasTokenCreated: boolean; + private _actor: string; + private _mustUnderstand: boolean; + private _envelopeKey: string; + private _appendElement: string; + + constructor(username: string, password: string, options?: string | IWSSecurityOptions) { + options = options || {}; + this._username = username; + this._password = password; + this._envelopeKey = 'soap'; + this._appendElement = ''; + // must account for backward compatibility for passwordType String param as well as object options defaults: passwordType = 'PasswordText', hasTimeStamp = true + if (typeof options === 'string') { + this._passwordType = options ? options : 'PasswordText'; + options = {}; + } else { + this._passwordType = options.passwordType ? options.passwordType : 'PasswordText'; + } + + if (validPasswordTypes.indexOf(this._passwordType) === -1) { + this._passwordType = 'PasswordText'; + } + + this._hasTimeStamp = options.hasTimeStamp || typeof options.hasTimeStamp === 'boolean' ? !!options.hasTimeStamp : true; + /*jshint eqnull:true */ + if (options.hasNonce != null) { + this._hasNonce = !!options.hasNonce; + } + this._hasTokenCreated = options.hasTokenCreated || typeof options.hasTokenCreated === 'boolean' ? !!options.hasTokenCreated : true; + if (options.actor != null) { + this._actor = options.actor; + } + if (options.mustUnderstand != null) { + this._mustUnderstand = !!options.mustUnderstand; + } + if (options.envelopeKey) { + this._envelopeKey = options.envelopeKey; + } + if (options.appendElement) { + this._appendElement = options.appendElement; + } + } + + public toXML(): string { + // avoid dependency on date formatting libraries + function getDate(d) { + function pad(n) { + return n < 10 ? '0' + n : n; + } + return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + 'Z'; + } + const now = new Date(); + const created = getDate(now); + let timeStampXml = ''; + if (this._hasTimeStamp) { + const expires = getDate(new Date(now.getTime() + 1000 * 600)); + timeStampXml = '' + '' + created + '' + '' + expires + '' + ''; + } + + let password; + let nonce; + if (this._hasNonce || this._passwordType !== 'PasswordText') { + // nonce = base64 ( sha1 ( created + random ) ) + const nHash = crypto.createHash('sha1'); + nHash.update(created + Math.random()); + nonce = nHash.digest('base64'); + } + if (this._passwordType === 'PasswordText') { + password = '' + xmlEscape(this._password) + ''; + if (nonce) { + password += '' + nonce + ''; + } + } else { + /* Specific Testcase for passwordDigest calculation cover this code + /* istanbul ignore next */ + password = + '' + + passwordDigest(nonce, created, this._password) + + '' + + '' + + nonce + + ''; + } + + return ( + '' + + timeStampXml + + '' + + '' + + xmlEscape(this._username) + + '' + + password + + (this._hasTokenCreated ? '' + created + '' : '') + + '' + + this._appendElement + + '' + ); + } +} diff --git a/src/security/WSSecurityCert.ts b/src/security/WSSecurityCert.ts new file mode 100644 index 000000000..d466a3755 --- /dev/null +++ b/src/security/WSSecurityCert.ts @@ -0,0 +1,221 @@ +import { randomUUID } from 'crypto'; +import { SignedXml } from 'xml-crypto'; +import { ISecurity } from '../types'; + +function addMinutes(date: Date, minutes: number) { + return new Date(date.getTime() + minutes * 60000); +} + +function dateStringForSOAP(date: Date): string { + return ( + date.getUTCFullYear() + + '-' + + ('0' + (date.getUTCMonth() + 1)).slice(-2) + + '-' + + ('0' + date.getUTCDate()).slice(-2) + + 'T' + + ('0' + date.getUTCHours()).slice(-2) + + ':' + + ('0' + date.getUTCMinutes()).slice(-2) + + ':' + + ('0' + date.getUTCSeconds()).slice(-2) + + 'Z' + ); +} + +function generateCreated(): string { + return dateStringForSOAP(new Date()); +} + +function generateExpires(): string { + return dateStringForSOAP(addMinutes(new Date(), 10)); +} + +function insertStr(src: string, dst: string, pos: number): string { + return [dst.slice(0, pos), src, dst.slice(pos)].join(''); +} + +function generateId(): string { + return randomUUID().replace(/-/gm, ''); +} + +function resolvePlaceholderInReferences(references: any[], bodyXpath: string) { + for (const ref of references) { + if (ref.xpath === bodyXpathPlaceholder) { + ref.xpath = bodyXpath; + } + } +} + +const oasisBaseUri = 'http://docs.oasis-open.org/wss/2004/01'; +const bodyXpathPlaceholder = '[[bodyXpath]]'; + +export interface IWSSecurityCertOptions { + hasTimeStamp?: boolean; + signatureTransformations?: string[]; + signatureAlgorithm?: string; + digestAlgorithm?: string; + additionalReferences?: string[]; + signerOptions?: IXmlSignerOptions; + excludeReferencesFromSigning?: string[]; + appendElement?: string; +} + +export interface IXmlSignerOptions { + prefix?: string; + attrs?: { [key: string]: string }; + existingPrefixes?: { [key: string]: string }; + idMode?: 'wssecurity'; +} + +export class WSSecurityCert implements ISecurity { + private publicP12PEM: string; + private signer: any; + private signerOptions: IXmlSignerOptions = {}; + private x509Id: string; + private hasTimeStamp: boolean; + private signatureTransformations: string[]; + private created: string; + private expires: string; + private additionalReferences: string[] = []; + private excludeReferencesFromSigning: string[] = []; + private appendElement: string; + + constructor(privatePEM: any, publicP12PEM: any, password: any, options: IWSSecurityCertOptions = {}) { + this.publicP12PEM = publicP12PEM + .toString() + .replace('-----BEGIN CERTIFICATE-----', '') + .replace('-----END CERTIFICATE-----', '') + .replace(/(\r\n|\n|\r)/gm, ''); + + this.signer = new SignedXml({ + idMode: options?.signerOptions?.idMode, + signatureAlgorithm: options?.signatureAlgorithm, + }); + + this.signer.digestAlgorithm = options.digestAlgorithm ?? 'http://www.w3.org/2001/04/xmlenc#sha256'; + this.appendElement = ''; + if (options.appendElement) { + this.appendElement = options.appendElement; + } + if (options.signatureAlgorithm === 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256') { + this.signer.signatureAlgorithm = options.signatureAlgorithm; + this.signer.addReference({ + xpath: bodyXpathPlaceholder, + transforms: ['http://www.w3.org/2001/10/xml-exc-c14n#'], + digestAlgorithm: 'http://www.w3.org/2001/04/xmlenc#sha256', + }); + } + + if (!options.signatureAlgorithm) { + this.signer.signatureAlgorithm = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; + } + + this.signer.canonicalizationAlgorithm = 'http://www.w3.org/2001/10/xml-exc-c14n#'; + + if (options.additionalReferences && options.additionalReferences.length > 0) { + this.additionalReferences = options.additionalReferences; + } + + if (options.excludeReferencesFromSigning && options.excludeReferencesFromSigning.length > 0) { + this.excludeReferencesFromSigning = options.excludeReferencesFromSigning; + } + + if (options.signerOptions) { + const { signerOptions } = options; + this.signerOptions = signerOptions; + if (!this.signerOptions.existingPrefixes) { + this.signerOptions.existingPrefixes = {}; + } + if (this.signerOptions.existingPrefixes && !this.signerOptions.existingPrefixes.wsse) { + this.signerOptions.existingPrefixes.wsse = `${oasisBaseUri}/oasis-200401-wss-wssecurity-secext-1.0.xsd`; + } + } else { + this.signerOptions = { existingPrefixes: { wsse: `${oasisBaseUri}/oasis-200401-wss-wssecurity-secext-1.0.xsd` } }; + } + + this.signer.privateKey = { + key: privatePEM, + passphrase: password, + }; + this.x509Id = `x509-${generateId()}`; + this.hasTimeStamp = typeof options.hasTimeStamp === 'undefined' ? true : !!options.hasTimeStamp; + this.signatureTransformations = Array.isArray(options.signatureTransformations) ? options.signatureTransformations : ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#']; + + this.signer.getKeyInfoContent = () => { + return `` + `` + ``; + }; + } + + public postProcess(xml: string, envelopeKey: string) { + this.created = generateCreated(); + this.expires = generateExpires(); + + let timestampStr = ''; + if (this.hasTimeStamp) { + timestampStr = `` + `${this.created}` + `${this.expires}` + ``; + } + + const binarySecurityToken = + `${this.publicP12PEM}` + + timestampStr + + this.appendElement; + + let xmlWithSec: string; + const secExt = `xmlns:wsse="${oasisBaseUri}/oasis-200401-wss-wssecurity-secext-1.0.xsd"`; + const secUtility = `xmlns:wsu="${oasisBaseUri}/oasis-200401-wss-wssecurity-utility-1.0.xsd"`; + const endOfSecurityHeader = xml.indexOf(''); + if (endOfSecurityHeader > -1) { + const securityHeaderRegexp = /]*)?>/; + const match = xml.match(securityHeaderRegexp); + let insertHeaderAttributes = ''; + if (!match[0].includes(` ${envelopeKey}:mustUnderstand="`)) { + insertHeaderAttributes += `${envelopeKey}:mustUnderstand="1" `; + } + if (!match[0].includes(secExt.substring(0, secExt.indexOf('=')))) { + insertHeaderAttributes += `${secExt} `; + } + if (!match[0].includes(secUtility.substring(0, secExt.indexOf('=')))) { + insertHeaderAttributes += `${secUtility} `; + } + const headerMarker = '` + binarySecurityToken + ``; + + xmlWithSec = insertStr(secHeader, xml, xml.indexOf(``)); + } + + const references = this.signatureTransformations; + + const bodyXpath = `//*[name(.)='${envelopeKey}:Body']`; + resolvePlaceholderInReferences(this.signer.references, bodyXpath); + + if (!this.excludeReferencesFromSigning.some((ref) => ref === 'Body') && !(this.signer.references.filter((ref: { xpath: string }) => ref.xpath === bodyXpath).length > 0)) { + this.signer.addReference({ xpath: bodyXpath, transforms: references, digestAlgorithm: this.signer.digestAlgorithm }); + } + + for (const name of this.additionalReferences) { + const xpath = `//*[name(.)='${name}']`; + if (!this.excludeReferencesFromSigning.some((ref) => ref === name) && !(this.signer.references.filter((ref: { xpath: string }) => ref.xpath === xpath).length > 0)) { + this.signer.addReference({ xpath: xpath, transforms: references, digestAlgorithm: this.signer.digestAlgorithm }); + } + } + + const timestampXpath = `//*[name(.)='wsse:Security']/*[local-name(.)='Timestamp']`; + if (!this.excludeReferencesFromSigning.some((ref) => ref === 'Timestamp') && this.hasTimeStamp && !(this.signer.references.filter((ref: { xpath: string }) => ref.xpath === timestampXpath).length > 0)) { + this.signer.addReference({ xpath: timestampXpath, transforms: references, digestAlgorithm: this.signer.digestAlgorithm }); + } + + this.signer.computeSignature(xmlWithSec, this.signerOptions); + + const originalXmlWithIds = this.signer.getOriginalXmlWithIds(); + const signatureXml = this.signer.getSignatureXml(); + return insertStr(signatureXml, originalXmlWithIds, originalXmlWithIds.indexOf('')); + } +} diff --git a/src/security/WSSecurityCertWithToken.ts b/src/security/WSSecurityCertWithToken.ts new file mode 100644 index 000000000..7f93f7e66 --- /dev/null +++ b/src/security/WSSecurityCertWithToken.ts @@ -0,0 +1,188 @@ +import { randomUUID } from 'crypto'; +import { SignedXml } from 'xml-crypto'; +import { ISecurity } from '../types'; +import { IWSSecurityCertOptions, IXmlSignerOptions } from './WSSecurityCert'; + +function addMinutes(date: Date, minutes: number) { + return new Date(date.getTime() + minutes * 60000); +} + +function dateStringForSOAP(date: Date): string { + return ( + date.getUTCFullYear() + + '-' + + ('0' + (date.getUTCMonth() + 1)).slice(-2) + + '-' + + ('0' + date.getUTCDate()).slice(-2) + + 'T' + + ('0' + date.getUTCHours()).slice(-2) + + ':' + + ('0' + date.getUTCMinutes()).slice(-2) + + ':' + + ('0' + date.getUTCSeconds()).slice(-2) + + 'Z' + ); +} + +function generateCreated(): string { + return dateStringForSOAP(new Date()); +} + +function generateExpires(): string { + return dateStringForSOAP(addMinutes(new Date(), 10)); +} + +function insertStr(src: string, dst: string, pos: number): string { + return [dst.slice(0, pos), src, dst.slice(pos)].join(''); +} + +function generateId(): string { + return randomUUID().replace(/-/gm, ''); +} + +function resolvePlaceholderInReferences(references: any[], bodyXpath: string) { + for (const ref of references) { + if (ref.xpath === bodyXpathPlaceholder) { + ref.xpath = bodyXpath; + } + } +} + +const oasisBaseUri = 'http://docs.oasis-open.org/wss/2004/01'; +const bodyXpathPlaceholder = '[[bodyXpath]]'; + +export class WSSecurityCertWithToken implements ISecurity { + private publicP12PEM: string; + private signer: any; + private signerOptions: IXmlSignerOptions = {}; + private x509Id: string; + private hasTimeStamp: boolean; + private signatureTransformations: string[]; + private created: string; + private expires: string; + private additionalReferences: string[] = []; + private username: string; + private password: string; + private appendElement: string; + + constructor(props: { privateKey: Buffer; publicKey: string; keyPassword?: string; username: string; password: string; options?: IWSSecurityCertOptions }) { + this.publicP12PEM = props.publicKey + .toString() + .replace('-----BEGIN CERTIFICATE-----', '') + .replace('-----END CERTIFICATE-----', '') + .replace(/(\r\n|\n|\r)/gm, ''); + this.username = props.username; + this.password = props.password; + + this.signer = new SignedXml(); + const opts = props.options || {}; + + this.appendElement = ''; + if (opts.appendElement) { + this.appendElement = opts.appendElement; + } + + if (opts.signatureAlgorithm === 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256') { + this.signer.signatureAlgorithm = opts.signatureAlgorithm; + this.signer.addReference({ + xpath: bodyXpathPlaceholder, + transforms: ['http://www.w3.org/2001/10/xml-exc-c14n#'], + digestAlgorithm: 'http://www.w3.org/2001/04/xmlenc#sha256', + }); + } + + if (!opts.signatureAlgorithm) { + this.signer.signatureAlgorithm = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; + } + + this.signer.canonicalizationAlgorithm = 'http://www.w3.org/2001/10/xml-exc-c14n#'; + + if (opts.additionalReferences && opts.additionalReferences.length > 0) { + this.additionalReferences = opts.additionalReferences; + } + + if (opts.signerOptions) { + const { signerOptions } = props.options; + this.signerOptions = signerOptions; + if (!this.signerOptions.existingPrefixes) { + this.signerOptions.existingPrefixes = {}; + } + if (this.signerOptions.existingPrefixes && !this.signerOptions.existingPrefixes.wsse) { + this.signerOptions.existingPrefixes.wsse = `${oasisBaseUri}/oasis-200401-wss-wssecurity-secext-1.0.xsd`; + } + } else { + this.signerOptions = { existingPrefixes: { wsse: `${oasisBaseUri}/oasis-200401-wss-wssecurity-secext-1.0.xsd` } }; + } + + this.signer.privateKey = { + key: props.privateKey, + passphrase: props.keyPassword, + }; + + this.x509Id = `x509-${generateId()}`; + this.hasTimeStamp = typeof opts.hasTimeStamp === 'undefined' ? true : !!opts.hasTimeStamp; + this.signatureTransformations = Array.isArray(opts.signatureTransformations) ? opts.signatureTransformations : ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#']; + + this.signer.keyInfoProvider = {}; + this.signer.getKeyInfo = () => { + return `` + `` + ``; + }; + } + + public postProcess(xml, envelopeKey) { + this.created = generateCreated(); + this.expires = generateExpires(); + + let timestampStr = ''; + if (this.hasTimeStamp) { + timestampStr = `` + `${this.created}` + `${this.expires}` + ``; + } + let usernameToken = ''; + if (this.username) { + usernameToken = + `` + + `${this.username} ` + + `${this.password} ` + + ``; + } + const secHeader = + `` + + `${this.publicP12PEM}` + + usernameToken + + timestampStr + + this.appendElement + + ``; + + const xmlWithSec = insertStr(secHeader, xml, xml.indexOf(``)); + + const references = this.signatureTransformations; + + const bodyXpath = `//*[name(.)='${envelopeKey}:Body']`; + resolvePlaceholderInReferences(this.signer.references, bodyXpath); + + if (!(this.signer.references.filter((ref) => ref.xpath === bodyXpath).length > 0)) { + this.signer.addReference({ xpath: bodyXpath, transforms: references, digestAlgorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' }); + } + + for (const name of this.additionalReferences) { + const xpath = `//*[name(.)='${name}']`; + if (!(this.signer.references.filter((ref) => ref.xpath === xpath).length > 0)) { + this.signer.addReference({ xpath: xpath, transforms: references, digestAlgorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' }); + } + } + + const timestampXpath = `//*[name(.)='wsse:Security']/*[local-name(.)='Timestamp']`; + if (this.hasTimeStamp && !(this.signer.references.filter((ref) => ref.xpath === timestampXpath).length > 0)) { + this.signer.addReference({ xpath: timestampXpath, transforms: references, digestAlgorithm: 'http://www.w3.org/2001/04/xmlenc#sha256' }); + } + + this.signer.computeSignature(xmlWithSec, this.signerOptions); + + return insertStr(this.signer.getSignatureXml(), xmlWithSec, xmlWithSec.indexOf('')); + } +} diff --git a/src/security/WSSecurityPlusCert.ts b/src/security/WSSecurityPlusCert.ts new file mode 100644 index 000000000..03a29bab2 --- /dev/null +++ b/src/security/WSSecurityPlusCert.ts @@ -0,0 +1,18 @@ +import { ISecurity } from '../types'; +import { WSSecurity } from './WSSecurity'; +import { WSSecurityCert } from './WSSecurityCert'; + +export class WSSecurityPlusCert implements ISecurity { + constructor( + private readonly wsSecurity: WSSecurity, + private readonly wsSecurityCert: WSSecurityCert, + ) {} + + public postProcess(xml: string, envelopeKey: string) { + const securityXml = this.wsSecurity.toXML(); + const endOfHeader = xml.indexOf(``); + xml = [xml.slice(0, endOfHeader), securityXml, xml.slice(endOfHeader)].join(''); + + return this.wsSecurityCert.postProcess(xml, envelopeKey); + } +} diff --git a/src/security/index.ts b/src/security/index.ts new file mode 100644 index 000000000..d20952223 --- /dev/null +++ b/src/security/index.ts @@ -0,0 +1,9 @@ +export * from './BasicAuthSecurity'; +export * from './BearerSecurity'; +export * from './ClientSSLSecurity'; +export * from './ClientSSLSecurityPFX'; +export * from './NTLMSecurity'; +export * from './WSSecurity'; +export * from './WSSecurityCert'; +export * from './WSSecurityCertWithToken'; +export * from './WSSecurityPlusCert'; diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 000000000..87e87fcc5 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2011 Vinay Pulim + * MIT Licensed + */ + +import { EventEmitter } from 'events'; +import * as http from 'http'; +import * as url from 'url'; +import { IOneWayOptions, IServerOptions, IServices, ISoapFault, ISoapServiceMethod } from './types'; +import { WSDL } from './wsdl'; +import { BindingElement, IPort } from './wsdl/elements'; +import zlib from 'zlib'; + +interface IExpressApp { + route; + use; +} + +export type ServerType = http.Server | IExpressApp; +type Request = http.IncomingMessage & { body?: any }; +type Response = http.ServerResponse; + +function isExpress(server): server is IExpressApp { + return typeof server.route === 'function' && typeof server.use === 'function'; +} + +function isPromiseLike(obj): obj is PromiseLike { + return !!obj && typeof obj.then === 'function'; +} + +function getDateString(d) { + function pad(n) { + return n < 10 ? '0' + n : n; + } + return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + 'Z'; +} + +//eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging +export interface Server { + emit(event: 'request', request: any, methodName: string): boolean; + emit(event: 'headers', headers: any, methodName: string): boolean; + emit(event: 'response', headers: any, methodName: string): boolean; + + /** Emitted for every received messages. */ + on(event: 'request', listener: (request: any, methodName: string) => void): this; + /** Emitted when the SOAP Headers are not empty. */ + on(event: 'headers', listener: (headers: any, methodName: string) => void): this; + /** Emitted before sending SOAP response. */ + on(event: 'response', listener: (response: any, methodName: string) => void): this; +} + +interface IExecuteMethodOptions { + serviceName?: string; + portName?: string; + methodName?: string; + outputName?: string; + args?: any; + headers?: any; + style?: 'document' | 'rpc'; +} + +//eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging +export class Server extends EventEmitter { + public path: string | RegExp; + public services: IServices; + public log: (type: string, data: any, req: Request) => any; + public authorizeConnection: (req: Request, res?: Response) => boolean; + public authenticate: (security: any, processAuthResult?: (result: boolean) => void, req?: Request, obj?: any) => boolean | void | Promise; + + private wsdl: WSDL; + private suppressStack: boolean; + private returnFault: boolean; + private onewayOptions: IOneWayOptions & { statusCode?: number }; + private enableChunkedEncoding: boolean; + private soapHeaders: any[]; + private callback?: (err: any, res: any) => void; + + constructor(server: ServerType, path: string | RegExp, services: IServices, wsdl: WSDL, options?: IServerOptions) { + super(); + + options = options || { + path: path, + services: services, + }; + this.path = path; + this.services = services; + this.wsdl = wsdl; + this.suppressStack = options && options.suppressStack; + this.returnFault = options && options.returnFault; + this.onewayOptions = (options && options.oneWay) || {}; + this.enableChunkedEncoding = options.enableChunkedEncoding === undefined ? true : !!options.enableChunkedEncoding; + this.callback = options.callback ? options.callback : () => {}; + if (typeof path === 'string' && path[path.length - 1] !== '/') { + path += '/'; + } else if (path instanceof RegExp && path.source[path.source.length - 1] !== '/') { + path = new RegExp(path.source + '(?:\\/|)'); + } + wsdl.onReady((err) => { + if (isExpress(server)) { + // handle only the required URL path for express server + server.route(path).all((req, res) => { + if (typeof this.authorizeConnection === 'function') { + if (!this.authorizeConnection(req, res)) { + res.end(); + return; + } + } + this._requestListener(req, res); + }); + this.callback(err, this); + } else { + const listeners = server.listeners('request').slice(); + server.removeAllListeners('request'); + server.addListener('request', (req, res) => { + if (typeof this.authorizeConnection === 'function') { + if (!this.authorizeConnection(req, res)) { + res.end(); + return; + } + } + let reqPath = url.parse(req.url).pathname; + if (reqPath[reqPath.length - 1] !== '/') { + reqPath += '/'; + } + if (path === reqPath || (path instanceof RegExp && reqPath.match(path))) { + this._requestListener(req, res); + } else { + for (let i = 0, len = listeners.length; i < len; i++) { + listeners[i].call(this, req, res); + } + } + }); + this.callback(err, this); + } + }); + + this._initializeOptions(options); + } + + public addSoapHeader(soapHeader: any, name?: string, namespace?: any, xmlns?: string): number { + if (!this.soapHeaders) { + this.soapHeaders = []; + } + soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns); + return this.soapHeaders.push(soapHeader) - 1; + } + + public changeSoapHeader(index: any, soapHeader: any, name?: any, namespace?: any, xmlns?: any): void { + if (!this.soapHeaders) { + this.soapHeaders = []; + } + soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns); + this.soapHeaders[index] = soapHeader; + } + + public getSoapHeaders(): string[] { + return this.soapHeaders; + } + + public clearSoapHeaders(): void { + this.soapHeaders = null; + } + + private _processSoapHeader(soapHeader, name, namespace, xmlns) { + switch (typeof soapHeader) { + case 'object': + return this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); + case 'function': { + //eslint-disable-next-line @typescript-eslint/no-this-alias + const _this = this; + return (...args: any) => { + const result = soapHeader.apply(null, [...args]); + + if (typeof result === 'object') { + return _this.wsdl.objectToXML(result, name, namespace, xmlns, true); + } else { + return result; + } + }; + } + default: + return soapHeader; + } + } + + private _initializeOptions(options: IServerOptions) { + this.wsdl.options.attributesKey = options.attributesKey || 'attributes'; + this.onewayOptions.statusCode = this.onewayOptions.responseCode || 200; + this.onewayOptions.emptyBody = !!this.onewayOptions.emptyBody; + this.wsdl.options.envelopeKey = options.envelopeKey || 'soap'; + } + + private _processRequestXml(req: Request, res: Response, xml) { + let error; + try { + if (typeof this.log === 'function') { + this.log('received', xml, req); + } + this._process(xml, req, res, (result, statusCode) => { + this._sendHttpResponse(res, statusCode, result); + if (typeof this.log === 'function') { + this.log('replied', result, req); + } + }); + } catch (err) { + if (err.Fault !== undefined) { + return this._sendError( + err.Fault, + (result, statusCode) => { + this._sendHttpResponse(res, statusCode || 500, result); + if (typeof this.log === 'function') { + this.log('error', err, req); + } + }, + new Date().toISOString(), + ); + } else { + error = err.stack ? (this.suppressStack === true ? err.message : err.stack) : err; + this._sendHttpResponse(res, /* statusCode */ 500, error); + if (typeof this.log === 'function') { + this.log('error', err, req); + } + } + } + } + + private _requestListener(req: Request, res: Response) { + const reqParse = url.parse(req.url); + const reqQuery = reqParse.search; + + if (typeof this.log === 'function') { + this.log('info', 'Handling ' + req.method + ' on ' + req.url, req); + } + + if (req.method === 'GET') { + if (reqQuery && reqQuery.toLowerCase().startsWith('?wsdl')) { + if (typeof this.log === 'function') { + this.log('info', 'Wants the WSDL', req); + } + res.setHeader('Content-Type', 'application/xml'); + res.write(this.wsdl.toXML()); + } + res.end(); + } else if (req.method === 'POST') { + if (typeof req.headers['content-type'] !== 'undefined') { + res.setHeader('Content-Type', req.headers['content-type']); + } else { + res.setHeader('Content-Type', 'application/xml'); + } + + // request body is already provided by an express middleware + // in this case unzipping should also be done by the express middleware itself + if (req.body && req.body.length > 0) { + return this._processRequestXml(req, res, req.body.toString()); + } + + const chunks = []; + let gunzip; + let source = req; + if (req.headers['content-encoding'] === 'gzip') { + gunzip = zlib.createGunzip(); + req.pipe(gunzip); + source = gunzip; + } + source.on('data', (chunk) => { + chunks.push(chunk); + }); + source.on('end', () => { + const xml = Buffer.concat(chunks).toString(); + this._processRequestXml(req, res, xml); + }); + } else { + res.end(); + } + } + + private _getSoapAction(req: Request) { + if (typeof req.headers.soapaction === 'undefined') { + return; + } + const soapAction: string = req.headers.soapaction as string; + return soapAction.indexOf('"') === 0 ? soapAction.slice(1, -1) : soapAction; + } + + private _process(input, req: Request, res: Response, cb: (result: any, statusCode?: number) => any) { + const pathname = url.parse(req.url).pathname.replace(/\/$/, ''); + const obj = this.wsdl.xmlToObject(input); + const body = obj.Body; + const headers = obj.Header; + let binding: BindingElement; + let methodName: string; + let serviceName: string; + let portName: string; + const includeTimestamp = obj.Header && obj.Header.Security && obj.Header.Security.Timestamp; + const authenticate = + this.authenticate || + function defaultAuthenticate() { + return true; + }; + + const callback = (result, statusCode) => { + const response = { result: result }; + this.emit('response', response, methodName); + cb(response.result, statusCode); + }; + + const process = () => { + if (typeof this.log === 'function') { + this.log('info', 'Attempting to bind to ' + pathname, req); + } + + // Avoid Cannot convert undefined or null to object due to Object.keys(body) + // and throw more meaningful error + if (!body) { + throw new Error('Failed to parse the SOAP Message body'); + } + + // use port.location and current url to find the right binding + binding = (() => { + const services = this.wsdl.definitions.services; + let firstPort: IPort; + let name; + for (name in services) { + serviceName = name; + const service = services[serviceName]; + const ports = service.ports; + for (name in ports) { + portName = name; + const port = ports[portName]; + const portPathname = url.parse(port.location).pathname.replace(/\/$/, ''); + + if (typeof this.log === 'function') { + this.log('info', 'Trying ' + portName + ' from path ' + portPathname, req); + } + + if (portPathname === pathname) { + return port.binding; + } + + // The port path is almost always wrong for generated WSDLs + if (!firstPort) { + firstPort = port; + } + } + } + return !firstPort ? void 0 : firstPort.binding; + })(); + + if (!binding) { + throw new Error('Failed to bind to WSDL'); + } + + try { + const soapAction = this._getSoapAction(req); + const messageElemName = Object.keys(body)[0] === 'attributes' ? Object.keys(body)[1] : Object.keys(body)[0]; + const pair = binding.topElements[messageElemName]; + if (soapAction) { + methodName = this._getMethodNameBySoapAction(binding, soapAction); + } else { + methodName = pair ? pair.methodName : messageElemName; + } + /** Style can be defined in method. If method has no style then look in binding */ + const style = binding.methods[methodName].style || binding.style; + + this.emit('request', obj, methodName); + if (headers) { + this.emit('headers', headers, methodName); + } + + if (style === 'rpc') { + this._executeMethod( + { + serviceName: serviceName, + portName: portName, + methodName: methodName, + outputName: messageElemName + 'Response', + args: body[messageElemName], + headers: headers, + style: 'rpc', + }, + req, + res, + callback, + ); + } else { + this._executeMethod( + { + serviceName: serviceName, + portName: portName, + methodName: methodName, + outputName: pair.outputName, + args: body[messageElemName], + headers: headers, + style: 'document', + }, + req, + res, + callback, + includeTimestamp, + ); + } + } catch (error) { + if (error.Fault !== undefined) { + return this._sendError(error.Fault, callback, includeTimestamp); + } + + throw error; + } + }; + + // Authentication + if (typeof authenticate === 'function') { + let authResultProcessed = false; + const processAuthResult = (authResult: boolean | Error) => { + if (authResultProcessed) { + return; + } + + authResultProcessed = true; + // Handle errors + if (authResult instanceof Error) { + return this._sendError( + { + Code: { + Value: 'SOAP-ENV:Server', + Subcode: { Value: 'InternalServerError' }, + }, + Reason: { Text: authResult.toString() }, + statusCode: 500, + }, + callback, + includeTimestamp, + ); + } + + // Handle actual results + if (typeof authResult === 'boolean') { + if (authResult === true) { + try { + process(); + } catch (error) { + if (error.Fault !== undefined) { + return this._sendError(error.Fault, callback, includeTimestamp); + } + return this._sendError( + { + Code: { + Value: 'SOAP-ENV:Server', + Subcode: { Value: 'InternalServerError' }, + }, + Reason: { Text: error.toString() }, + statusCode: 500, + }, + callback, + includeTimestamp, + ); + } + } else { + return this._sendError( + { + Code: { + Value: 'SOAP-ENV:Client', + Subcode: { Value: 'AuthenticationFailure' }, + }, + Reason: { Text: 'Invalid username or password' }, + statusCode: 401, + }, + callback, + includeTimestamp, + ); + } + } + }; + + const functionResult = authenticate(obj.Header && obj.Header.Security, processAuthResult, req, obj); + if (isPromiseLike(functionResult)) { + functionResult.then( + (result: boolean) => { + processAuthResult(result); + }, + (err: any) => { + processAuthResult(err); + }, + ); + } + if (typeof functionResult === 'boolean') { + processAuthResult(functionResult); + } + } else { + throw new Error('Invalid authenticate function (not a function)'); + } + } + + private _getMethodNameBySoapAction(binding: BindingElement, soapAction: string) { + for (const methodName in binding.methods) { + if (binding.methods[methodName].soapAction === soapAction) { + return methodName; + } + } + } + + private _executeMethod(options: IExecuteMethodOptions, req: Request, res: Response, callback: (result: any, statusCode?: number) => any, includeTimestamp?) { + options = options || {}; + let method: ISoapServiceMethod; + let body; + let headers; + const serviceName = options.serviceName; + const portName = options.portName; + const binding = this.wsdl.definitions.services[serviceName].ports[portName].binding; + const methodName = options.methodName; + const outputName = options.outputName; + const args = options.args; + const style = options.style; + + if (this.soapHeaders) { + headers = this.soapHeaders + .map((header) => { + if (typeof header === 'function') { + return header(methodName, args, options.headers, req, res, this); + } else { + return header; + } + }) + .join('\n'); + } + + try { + method = this.services[serviceName][portName][methodName]; + } catch { + return callback(this._envelope('', headers, includeTimestamp)); + } + + let handled = false; + const handleResult = (error, result?) => { + if (handled) { + return; + } + handled = true; + + if (error) { + if (error.Fault !== undefined) { + return this._sendError(error.Fault, callback, includeTimestamp); + } else { + return this._sendError( + { + Code: { + Value: 'SOAP-ENV:Server', + Subcode: { Value: 'InternalServerError' }, + }, + Reason: { Text: error.toString() }, + statusCode: 500, + }, + callback, + includeTimestamp, + ); + } + } + + if (style === 'rpc') { + body = this.wsdl.objectToRpcXML(outputName, result, '', this.wsdl.definitions.$targetNamespace); + } else if (style === 'document') { + const element = binding.methods[methodName].output; + body = this.wsdl.objectToDocumentXML(outputName, result, element.targetNSAlias, element.targetNamespace); + } else { + const element = binding.methods[methodName].output; + // Check for targetNamespace on the element + const elementTargetNamespace = element.$targetNamespace; + let outputNameWithNamespace = outputName; + + if (elementTargetNamespace) { + // if targetNamespace is set on the element concatinate it with the outputName + outputNameWithNamespace = `${elementTargetNamespace}:${outputNameWithNamespace}`; + } + + body = this.wsdl.objectToDocumentXML(outputNameWithNamespace, result, element.targetNSAlias, element.targetNamespace); + } + callback(this._envelope(body, headers, includeTimestamp)); + }; + + if (!binding.methods[methodName].output) { + // no output defined = one-way operation so return empty response + handled = true; + body = ''; + if (this.onewayOptions.emptyBody) { + body = this._envelope('', headers, includeTimestamp); + } + callback(body, this.onewayOptions.responseCode); + } + + const methodCallback = (error, result?) => { + if (error && error.Fault !== undefined) { + // do nothing + } else if (result === undefined) { + // Backward compatibility to support one argument callback style + result = error; + error = null; + } + handleResult(error, result); + }; + + const result = method.apply(this, [args, methodCallback, options.headers, req, res]); + if (typeof result !== 'undefined') { + if (isPromiseLike(result)) { + result.then( + (value) => { + handleResult(null, value); + }, + (err) => { + handleResult(err); + }, + ); + } else { + handleResult(null, result); + } + } + } + + private _envelope(body, headers, includeTimestamp) { + const encoding = ''; + const envelopeKey = this.wsdl.options.envelopeKey; + + const envelopeDefinition = this.wsdl.options.forceSoap12Headers ? 'http://www.w3.org/2003/05/soap-envelope' : 'http://schemas.xmlsoap.org/soap/envelope/'; + + let xml = '' + '<' + envelopeKey + ':Envelope' + ' xmlns:' + envelopeKey + '=' + '"' + envelopeDefinition + '" ' + encoding + this.wsdl.xmlnsInEnvelope + '>'; + + headers = headers || ''; + + if (includeTimestamp) { + const now = new Date(); + const created = getDateString(now); + const expires = getDateString(new Date(now.getTime() + 1000 * 600)); + + headers += + '' + + ' ' + + ' ' + + created + + '' + + ' ' + + expires + + '' + + ' ' + + ' \n'; + } + + if (headers !== '') { + xml += '<' + envelopeKey + ':Header>' + headers + ''; + } + xml += body ? '<' + envelopeKey + ':Body>' + body + '' : '<' + envelopeKey + ':Body/>'; + xml += ''; + return xml; + } + + private _sendError(soapFault: ISoapFault, callback: (result: any, statusCode?: number) => any, includeTimestamp) { + let fault; + const envelopeKey = this.wsdl.options.envelopeKey; + + let statusCode: number; + if (soapFault.statusCode) { + statusCode = soapFault.statusCode; + soapFault.statusCode = undefined; + } + + if ('faultcode' in soapFault) { + // Soap 1.1 error style + // Root element will be prependend with the soap NS + // It must match the NS defined in the Envelope (set by the _envelope method) + fault = this.wsdl.objectToDocumentXML(envelopeKey + ':Fault', soapFault, undefined); + } else { + // Soap 1.2 error style. + // 3rd param is the NS prepended to all elements + // It must match the NS defined in the Envelope (set by the _envelope method) + fault = this.wsdl.objectToDocumentXML('Fault', soapFault, envelopeKey); + } + + return callback(this._envelope(fault, '', includeTimestamp), statusCode); + } + + private _sendHttpResponse(res: Response, statusCode: number, result) { + if (statusCode) { + res.statusCode = statusCode; + } + + /* + * Calling res.write(result) follow by res.end() will cause Node.js to use + * chunked encoding, while calling res.end(result) directly will cause + * Node.js to calculate and send Content-Length header. See + * nodejs/node#26005. + */ + + if (this.enableChunkedEncoding) { + res.write(result); + res.end(); + } else { + res.end(result); + } + } +} diff --git a/src/soap.ts b/src/soap.ts new file mode 100644 index 000000000..9cdbe9ea0 --- /dev/null +++ b/src/soap.ts @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011 Vinay Pulim + * MIT Licensed + */ + +import { Client } from './client'; +import * as _security from './security'; +import { Server, ServerType } from './server'; +import { IOptions, IServerOptions, IServices, IWSDLCache } from './types'; +import { wsdlCacheSingleton } from './utils'; +import { open_wsdl, WSDL } from './wsdl'; + +export const security = _security; +export { Client } from './client'; +export { HttpClient } from './http'; +export { BasicAuthSecurity, BearerSecurity, ClientSSLSecurity, ClientSSLSecurityPFX, NTLMSecurity, WSSecurity, WSSecurityCert, WSSecurityPlusCert, WSSecurityCertWithToken } from './security'; +export { Server } from './server'; +export { passwordDigest } from './utils'; +export * from './types'; +export { WSDL } from './wsdl'; + +type WSDLCallback = (error: any, result?: WSDL) => any; + +function getFromCache(key: string, cache: IWSDLCache, load: (cb: WSDLCallback) => any, callback: WSDLCallback) { + if (!cache.has(key)) { + load((err, result) => { + if (err) { + return callback(err); + } + cache.set(key, result); + callback(null, result); + }); + } else { + process.nextTick(() => { + callback(null, cache.get(key)); + }); + } +} + +function _requestWSDL(url: string, options: IOptions, callback: WSDLCallback) { + if (typeof options === 'function') { + callback = options; + options = {}; + } + const openWsdl = (callback: WSDLCallback) => { + open_wsdl(url, options, callback); + }; + + if (options.disableCache === true) { + openWsdl(callback); + } else { + let cache: IWSDLCache; + if (options.wsdlCache) { + cache = options.wsdlCache; + } else { + cache = wsdlCacheSingleton; + } + getFromCache(url, cache, openWsdl, callback); + } +} + +export type CreateClientCallback = (err: any, client: Client) => void; + +export function createClient(url: string, callback: CreateClientCallback, endpoint?: string): void; +export function createClient(url: string, options: IOptions, callback: CreateClientCallback, endpoint?: string): void; +export function createClient(url: string, p2: CreateClientCallback | IOptions, p3?: CreateClientCallback | string, p4?: string): void { + let endpoint: string = p4; + let callback: CreateClientCallback; + let options: IOptions; + if (typeof p2 === 'function') { + callback = p2; + endpoint = p3 as string; + options = {}; + } else if (typeof p3 === 'function') { + options = p2; + callback = p3; + endpoint = p4; + } + endpoint = options.endpoint || endpoint; + _requestWSDL(url, options, (err, wsdl) => { + callback(err, wsdl && new Client(wsdl, endpoint, options)); + }); +} + +export function createClientAsync(url: string, options?: IOptions, endpoint?: string): Promise { + if (typeof options === 'undefined') { + options = {}; + } + return new Promise((resolve, reject) => { + createClient( + url, + options, + (err, client) => { + if (err) { + reject(err); + } + resolve(client); + }, + endpoint, + ); + }); +} + +export function listen(server: ServerType, path: string | RegExp, services: IServices, wsdl: string, callback?: (err: any, res: any) => void): Server; +export function listen(server: ServerType, options: IServerOptions): Server; +export function listen(server: ServerType, p2: string | RegExp | IServerOptions, services?: IServices, xml?: string, callback?: (err: any, res: any) => void): Server { + let options: IServerOptions; + let path: string | RegExp; + let uri = ''; + + if (typeof p2 === 'object' && !(p2 instanceof RegExp)) { + // p2 is options + // server, options + options = p2; + path = options.path; + services = options.services; + xml = options.xml; + uri = options.uri; + } else { + // p2 is path + // server, path, services, wsdl + path = p2; + options = { + path: p2, + services: services, + callback: callback, + }; + } + + const wsdl = new WSDL(xml || services, uri, options); + return new Server(server, path, services, wsdl, options); +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 000000000..1fe0b89a5 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,176 @@ +import * as req from 'axios'; +import { ReadStream } from 'fs'; +import { WSDL } from './wsdl'; + +export interface IHeaders { + [k: string]: any; +} + +export interface IExOptions { + [key: string]: any; +} + +export interface IHttpClient { + request(rurl: string, data: any, callback: (error: any, res?: any, body?: any) => any, exheaders?: IHeaders, exoptions?: IExOptions, caller?): req.AxiosPromise; + requestStream?(rurl: string, data: any, exheaders?: IHeaders, exoptions?: IExOptions, caller?): req.AxiosPromise; +} + +/** @deprecated use SoapMethod */ +export type ISoapMethod = SoapMethod; +export type SoapMethod = ( + args: any, + callback: (err: any, result: any, rawResponse: any, soapHeader: any, rawRequest: any, mtomAttachments?: IMTOMAttachments) => void, + options?: any, + extraHeaders?: any, + mtomAttachments?: IMTOMAttachments, +) => void; + +export type SoapMethodAsync = (args: any, options?: any, extraHeaders?: any) => Promise<[any, any, any, any, IMTOMAttachments?]>; + +export type ISoapServiceMethod = (args: any, callback?: (data: any) => void, headers?: any, req?: any, res?: any, sender?: any) => any; + +// SOAP Fault 1.1 & 1.2 +export interface ISoapFaultError { + Fault: ISoapFault; +} + +export type ISoapFault = ISoapFault11 | ISoapFault12; + +// SOAP Fault 1.1 +export interface ISoapFault11 { + faultcode: number | string; + faultstring: string; + detail?: string; + statusCode?: number; +} + +// SOAP Fault 1.2 +// 1.2 also supports additional, optional elements: +// Role, Node, Detail. Should be added when soap module implements them +// https://www.w3.org/TR/soap12/#soapfault +export interface ISoapFault12 { + Code: { Value: string; Subcode?: { Value: string } }; + Reason: { Text: string }; + statusCode?: number; +} + +/** @deprecated use ISecurity */ +export type Security = ISecurity; +export interface ISecurity { + addOptions?(options: any): void; + toXML?(): string; + addHeaders?(headers: IHeaders): void; + postProcess?(xml, envelopeKey): string; +} + +export interface IServicePort { + [methodName: string]: ISoapServiceMethod; +} + +export interface IService { + [portName: string]: IServicePort; +} + +export interface IServices { + [serviceName: string]: IService; +} + +export interface IXmlAttribute { + name: string; + value: string; +} + +export interface IWsdlBaseOptions { + attributesKey?: string; + valueKey?: string; + xmlKey?: string; + overrideRootElement?: { namespace: string; xmlnsAttributes?: IXmlAttribute[] }; + overrideElementKey?: object; + ignoredNamespaces?: boolean | string[] | { namespaces?: string[]; override?: boolean }; + ignoreBaseNameSpaces?: boolean; + /** escape special XML characters in SOAP message (e.g. &, >, < etc), default: true. */ + escapeXML?: boolean; + /** return an Invalid XML SOAP fault on a bad request, default: false. */ + returnFault?: boolean; + handleNilAsNull?: boolean; + /** if your wsdl operations contains names with non identifier characters ([^a-z$_0-9]), replace them with _. Note: if using this option, clients using wsdls with two operations like soap:method and soap-method will be overwritten. Then, use bracket notation instead (client['soap:method']()). */ + normalizeNames?: boolean; + /** to preserve leading and trailing whitespace characters in text and cdata. */ + preserveWhitespace?: boolean; + /** provides support for nonstandard array semantics. If true, JSON arrays of the form {list: [{elem: 1}, {elem: 2}]} are marshalled into xml as 1 2. If false, marshalls into 1 2 . Default: true. */ + namespaceArrayElements?: boolean; + useEmptyTag?: boolean; + strict?: boolean; + /** custom HTTP headers to be sent on WSDL requests. */ + wsdl_headers?: { [key: string]: any }; + /** custom options for the request module on WSDL requests. */ + wsdl_options?: { [key: string]: any }; + /** set proper headers for SOAP v1.2. */ + forceSoap12Headers?: boolean; + /** Force to use schema xmlns when schema prefix not found, this is needed when schema prefix is different for the same namespace in different files, for example wsdl and in imported xsd file fir complex types*/ + forceUseSchemaXmlns?: boolean; +} + +/** @deprecated use IOptions */ +export type Option = IOptions; +export interface IOptions extends IWsdlBaseOptions { + /** don't cache WSDL files, request them every time. */ + disableCache?: boolean; + /** Custom cache implementation. If not provided, defaults to caching WSDLs indefinitely. */ + wsdlCache?: IWSDLCache; + /** override the SOAP service's host specified in the .wsdl file. */ + endpoint?: string; + /** set specific key instead of
. */ + envelopeKey?: string; + /** set specific SOAP Schema Url; will not be used with forceSoap12Headers option */ + envelopeSoapUrl?: string; + /** provide your own http client that implements request(rurl, data, callback, exheaders, exoptions) */ + httpClient?: IHttpClient; + /** override the request module. */ + request?: req.AxiosInstance; + stream?: boolean; + // allows returning the underlying saxStream that parse the SOAP XML response + returnSaxStream?: boolean; + // wsdl options that only work for client + customDeserializer?: any; + /** if your wsdl operations contains names with Async suffix, you will need to override the default promise suffix to a custom one, default: Async. */ + overridePromiseSuffix?: string; + /** @internal */ + WSDL_CACHE?; + /** handle MTOM soapAttachments in response */ + parseReponseAttachments?: boolean; + /** handle endpoint response.data enconding when using parseReponseAttachments */ + encoding?: BufferEncoding; +} + +export interface IOneWayOptions { + responseCode?: number; + emptyBody?: boolean; +} + +export interface IServerOptions extends IWsdlBaseOptions { + path: string | RegExp; + services: IServices; + xml?: string; + uri?: string; + callback?: (err: any, res: any) => void; + /** suppress the full stack trace for error messages. */ + suppressStack?: boolean; + oneWay?: IOneWayOptions; + /** A boolean for controlling chunked transfer encoding in response. Some client (such as Windows 10's MDM enrollment SOAP client) is sensitive to transfer-encoding mode and can't accept chunked response. This option let user disable chunked transfer encoding for such a client. Default to true for backward compatibility. */ + enableChunkedEncoding?: boolean; + envelopeKey?: string; +} + +export interface IMTOMAttachments { + parts: Array<{ + body: Buffer; + headers: { [key: string]: string }; + }>; +} + +export interface IWSDLCache { + has(key: string): boolean; + get(key: string): WSDL; + set(key: string, wsdl: WSDL): void; +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 000000000..9399a5559 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,138 @@ +import * as crypto from 'crypto'; +import { IMTOMAttachments, IWSDLCache } from './types'; +import { WSDL } from './wsdl'; + +export function passwordDigest(nonce: string, created: string, password: string): string { + // digest = base64 ( sha1 ( nonce + created + password ) ) + const pwHash = crypto.createHash('sha1'); + + const NonceBytes = Buffer.from(nonce || '', 'base64'); + const CreatedBytes = Buffer.from(created || '', 'utf8'); + const PasswordBytes = Buffer.from(password || '', 'utf8'); + const FullBytes = Buffer.concat([NonceBytes, CreatedBytes, PasswordBytes]); + + pwHash.update(FullBytes); + return pwHash.digest('base64'); +} + +export const TNS_PREFIX = '__tns__'; // Prefix for targetNamespace + +/** + * Find a key from an object based on the value + * @param {Object} Namespace prefix/uri mapping + * @param {*} nsURI value + * @returns {String} The matching key + */ +export function findPrefix(xmlnsMapping, nsURI) { + for (const n in xmlnsMapping) { + if (n === TNS_PREFIX) { + continue; + } + if (xmlnsMapping[n] === nsURI) { + return n; + } + } +} + +export function splitQName(nsName: T) { + if (typeof nsName !== 'string') { + return { + prefix: TNS_PREFIX, + name: nsName, + }; + } + + const [topLevelName] = nsName.split('|', 1); + + const prefixOffset = topLevelName.indexOf(':'); + + return { + prefix: topLevelName.substring(0, prefixOffset) || TNS_PREFIX, + name: topLevelName.substring(prefixOffset + 1), + }; +} + +export function xmlEscape(obj) { + if (typeof obj === 'string') { + if (obj.substr(0, 9) === '') { + return obj; + } + return obj.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); + } + + return obj; +} + +export function parseMTOMResp(payload: Buffer, boundary: string, callback: (err?: Error, resp?: IMTOMAttachments) => void) { + return import('formidable') + .then(({ MultipartParser }) => { + const resp: IMTOMAttachments = { + parts: [], + }; + let headerName = ''; + let headerValue = ''; + let data: Buffer; + let partIndex = 0; + const parser = new MultipartParser(); + + parser.initWithBoundary(boundary); + parser.on('data', ({ name, buffer, start, end }) => { + switch (name) { + case 'partBegin': + resp.parts[partIndex] = { + body: null, + headers: {}, + }; + data = Buffer.from(''); + break; + case 'headerField': + headerName = buffer.slice(start, end).toString(); + break; + case 'headerValue': + headerValue = buffer.slice(start, end).toString(); + break; + case 'headerEnd': + resp.parts[partIndex].headers[headerName.toLowerCase()] = headerValue; + break; + case 'partData': + data = Buffer.concat([data, buffer.slice(start, end)]); + break; + case 'partEnd': + resp.parts[partIndex].body = data; + partIndex++; + break; + } + }); + + parser.write(payload); + + return callback(null, resp); + }) + .catch(callback); +} + +class DefaultWSDLCache implements IWSDLCache { + private cache: { + [key: string]: WSDL; + }; + constructor() { + this.cache = {}; + } + + public has(key: string): boolean { + return !!this.cache[key]; + } + + public get(key: string): WSDL { + return this.cache[key]; + } + + public set(key: string, wsdl: WSDL) { + this.cache[key] = wsdl; + } + + public clear() { + this.cache = {}; + } +} +export const wsdlCacheSingleton = new DefaultWSDLCache(); diff --git a/src/wsdl/elements.ts b/src/wsdl/elements.ts new file mode 100644 index 000000000..73f147071 --- /dev/null +++ b/src/wsdl/elements.ts @@ -0,0 +1,1199 @@ +import { ok as assert } from 'assert'; +import debugBuilder from 'debug'; +import * as _ from 'lodash'; +import { IWsdlBaseOptions } from '../types'; +import { splitQName, TNS_PREFIX } from '../utils'; + +const debug = debugBuilder('node-soap'); + +const Primitives: { + [type: string]: number; +} = { + string: 1, + boolean: 1, + decimal: 1, + float: 1, + double: 1, + anyType: 1, + byte: 1, + int: 1, + long: 1, + short: 1, + negativeInteger: 1, + nonNegativeInteger: 1, + positiveInteger: 1, + nonPositiveInteger: 1, + unsignedByte: 1, + unsignedInt: 1, + unsignedLong: 1, + unsignedShort: 1, + duration: 0, + dateTime: 0, + time: 0, + date: 0, + gYearMonth: 0, + gYear: 0, + gMonthDay: 0, + gDay: 0, + gMonth: 0, + hexBinary: 0, + base64Binary: 0, + anyURI: 0, + QName: 0, + NOTATION: 0, +}; + +export interface IWsdlXmlns { + wsu?: string; + wsp?: string; + wsam?: string; + soap?: string; + tns?: string; + xsd?: string; + __tns__?: string; + [prop: string]: string | void; +} + +export interface IXmlNs { + [key: string]: string; +} + +export class Element { + public readonly allowedChildren?: { [k: string]: typeof Element } = {}; + public $name?: string; + public $targetNamespace?; + public children: Element[] = []; + public ignoredNamespaces; + public strict: boolean; + public name?: string; + public nsName?; + public prefix?: string; + public schemaXmlns?; + public definitionsXmlns?: IXmlNs; + public valueKey: string; + public xmlKey; + public xmlns?: IXmlNs; + public forceUseSchemaXmlns?: boolean; + + constructor(nsName: string, attrs, options?: IWsdlBaseOptions, schemaAttrs?) { + const parts = splitQName(nsName); + + this.nsName = nsName; + this.prefix = parts.prefix; + this.name = parts.name; + this.children = []; + this.xmlns = {}; + this.schemaXmlns = {}; + + this._initializeOptions(options); + + for (const key in attrs) { + const match = /^xmlns:?(.*)$/.exec(key); + if (match) { + this.xmlns[match[1] ? match[1] : TNS_PREFIX] = attrs[key]; + } else { + if (key === 'value') { + this[this.valueKey] = attrs[key]; + } else { + this['$' + key] = attrs[key]; + } + } + } + for (const schemaKey in schemaAttrs) { + const schemaMatch = /^xmlns:?(.*)$/.exec(schemaKey); + if (schemaMatch && schemaMatch[1]) { + this.schemaXmlns[schemaMatch[1]] = schemaAttrs[schemaKey]; + } + } + if (this.$targetNamespace !== undefined) { + // Add targetNamespace to the mapping + this.xmlns[TNS_PREFIX] = this.$targetNamespace; + } + + this.init(); + } + + public deleteFixedAttrs() { + if (this.children && this.children.length === 0) delete this.children; + if (this.xmlns && Object.keys(this.xmlns).length === 0) delete this.xmlns; + delete this.nsName; + delete this.prefix; + delete this.name; + } + + public startElement(stack: Element[], nsName: string, attrs, options: IWsdlBaseOptions, schemaXmlns) { + if (!this.allowedChildren) { + return; + } + + let ChildClass = this.allowedChildren[splitQName(nsName).name]; + if (ChildClass == null && !this.strict) { + ChildClass = UnexpectedElement; + } + if (ChildClass) { + const child = new ChildClass(nsName, attrs, options, schemaXmlns); + child.init(); + const root = stack[0]; + if (root instanceof DefinitionsElement) { + child.definitionsXmlns = root.xmlns; + } + stack.push(child); + } else { + this.unexpected(nsName); + } + } + + public endElement(stack: Element[], nsName: string) { + if (this.nsName === nsName) { + if (stack.length < 2) { + return; + } + const parent = stack[stack.length - 2]; + if (this !== stack[0]) { + _.defaultsDeep(stack[0].xmlns, this.xmlns); + // delete this.xmlns; + parent.children.push(this); + parent.addChild(this); + } + stack.pop(); + } + } + + //eslint-disable-next-line @typescript-eslint/no-unused-vars + public addChild(child: Element) { + return; + } + + public unexpected(name: string) { + throw new Error('Found unexpected element (' + name + ') inside ' + this.nsName); + } + + //eslint-disable-next-line @typescript-eslint/no-unused-vars + public description(definitions?: DefinitionsElement, xmlns?: IXmlNs): any { + return this.$name || this.name; + } + + public init(): void {} + + private _initializeOptions(options: IWsdlBaseOptions) { + if (options) { + this.valueKey = options.valueKey || '$value'; + this.xmlKey = options.xmlKey || '$xml'; + this.ignoredNamespaces = options.ignoredNamespaces || []; + this.strict = options.strict || false; + this.forceUseSchemaXmlns = options.forceUseSchemaXmlns || false; + } else { + this.valueKey = '$value'; + this.xmlKey = '$xml'; + this.ignoredNamespaces = []; + this.strict = false; + this.forceUseSchemaXmlns = false; + } + } +} + +export class UnexpectedElement extends Element { + public startElement(stack: Element[], nsName: string, attrs, options: IWsdlBaseOptions, schemaXmlns) { + const child = new UnexpectedElement(nsName, attrs, options, schemaXmlns); + child.init(); + stack.push(child); + } +} + +export class ElementElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['annotation', 'complexType', 'simpleType']); + public $minOccurs?: string; + public $maxOccurs?: string; + public $type?: string; + public $ref?: string; + public targetNSAlias?: string; + public targetNamespace?: string; + public $lookupType?: string; + public $lookupTypes?: any[]; + + public description(definitions: DefinitionsElement, xmlns?: IXmlNs) { + let element = {}; + let name = this.$name; + + // Check minOccurs / maxOccurs attributes to see if this element is a list + // These are default values for an element + let minOccurs = 1; + let maxOccurs = 1; + + if (this.$maxOccurs === 'unbounded') { + maxOccurs = Infinity; + } else if (this.$maxOccurs) { + maxOccurs = parseInt(this.$maxOccurs, 10); + } + + if (this.$minOccurs) { + //eslint-disable-next-line @typescript-eslint/no-unused-vars + minOccurs = parseInt(this.$minOccurs, 10); + } + + const isMany = maxOccurs > 1; + + if (isMany && name) { + name += '[]'; + } + + if (xmlns && xmlns[TNS_PREFIX]) { + this.$targetNamespace = xmlns[TNS_PREFIX]; + } + let type: any = this.$type || this.$ref; + if (type) { + type = splitQName(type); + const typeName: string = type.name; + const useSchemaXmlns = !!findNs(type.prefix, this.definitionsXmlns, definitions.xmlns) || !!findNs(this.targetNSAlias, this.definitionsXmlns, definitions.xmlns) || this.forceUseSchemaXmlns; + const ns = findNs(type.prefix, xmlns, this.xmlns, useSchemaXmlns ? this.schemaXmlns : undefined, this.definitionsXmlns, definitions.xmlns); + const schema = definitions.schemas[ns]; + const typeElement = schema && (this.$type ? schema.complexTypes[typeName] || schema.types[typeName] : schema.elements[typeName]); + const typeStorage = this.$type ? definitions.descriptions.types : definitions.descriptions.elements; + + if (ns && definitions.schemas[ns]) { + xmlns = definitions.schemas[ns].xmlns; + } + + if (typeElement && !(typeName in Primitives)) { + if (!(typeName in typeStorage)) { + let elem: any = {}; + typeStorage[typeName] = elem; + + if (isMany && 'maxOccurs' in typeElement) { + typeElement.maxOccurs = this.$maxOccurs; + } + if (Boolean(this.$minOccurs) && 'minOccurs' in typeElement) { + typeElement.minOccurs = this.$minOccurs; + } + + const description = typeElement.description(definitions, xmlns); + if (typeof description === 'string') { + elem = description; + } else { + Object.keys(description).forEach((key) => { + elem[key] = description[key]; + }); + + const $attributes = description[AttributeElement.Symbol]; + if ($attributes) { + elem[AttributeElement.Symbol] = $attributes; + } + } + + if (this.$ref) { + element = elem; + } else { + element[name] = elem; + } + + if (typeof elem === 'object') { + elem.targetNSAlias = type.prefix; + elem.targetNamespace = ns; + } + + typeStorage[typeName] = elem; + } else { + if (this.$ref) { + // Differentiate between a ref for an array of elements and a ref for a single element + if (isMany) { + const refTypeName = typeName + '[]'; + typeStorage[refTypeName] = typeStorage[typeName]; + element[refTypeName] = typeStorage[refTypeName]; + } else { + element = typeStorage[typeName]; + } + } else { + element[name] = typeStorage[typeName]; + } + } + } else { + element[name] = this.$type; + } + } else { + const children = this.children; + element[name] = {}; + for (const child of children) { + if (child instanceof ComplexTypeElement || child instanceof SimpleTypeElement) { + element[name] = child.description(definitions, xmlns); + } + } + } + return element; + } +} + +export class AnyElement extends Element {} + +export class InputElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['body', 'documentation', 'header', 'SecuritySpecRef']); + public use: string; + public encodingStyle: string; + public $type: string; + public $lookupType: string; + public targetNSAlias?: string; + public targetNamespace?: string; + public parts?; + + public addChild(child: Element) { + if (child instanceof BodyElement) { + this.use = child.$use; + if (this.use === 'encoded') { + this.encodingStyle = child.$encodingStyle; + } + this.children.pop(); + } + } +} + +export class OutputElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['body', 'documentation', 'header', 'SecuritySpecRef']); + public targetNSAlias?: string; + public targetNamespace?: string; + public use?: string; + public encodingStyle?: string; + public $lookupTypes; + + public addChild(child: Element) { + if (child instanceof BodyElement) { + this.use = child.$use; + if (this.use === 'encoded') { + this.encodingStyle = child.$encodingStyle; + } + this.children.pop(); + } + } +} + +export class SimpleTypeElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['restriction']); + + //eslint-disable-next-line @typescript-eslint/no-unused-vars + public description(definitions: DefinitionsElement) { + for (const child of this.children) { + if (child instanceof RestrictionElement) { + return [this.$name, child.description()].filter(Boolean).join('|'); + } + } + return {}; + } +} + +export class RestrictionElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['all', 'choice', 'enumeration', 'sequence', 'attribute']); + public $base: string; + + public description(definitions?: DefinitionsElement, xmlns?: IXmlNs) { + const children = this.children; + let desc; + let isFirstChild = false; + const $attributes = {}; + + for (const child of children) { + if (child instanceof AttributeElement) { + $attributes[child.$name] = child.description(definitions); + continue; + } + if (!isFirstChild && (child instanceof SequenceElement || child instanceof ChoiceElement)) { + isFirstChild = true; + desc = child.description(definitions, xmlns); + } + } + + if (Object.keys($attributes).length > 0) { + desc = desc ?? {}; + desc[AttributeElement.Symbol] = $attributes; + } + + if (desc && this.$base) { + const type = splitQName(this.$base); + const typeName = type.name; + const ns = findNs(type.prefix, xmlns, this.definitionsXmlns, definitions.xmlns); + const schema = definitions.schemas[ns]; + const typeElement = schema && (schema.complexTypes[typeName] || schema.types[typeName] || schema.elements[typeName]); + + desc.getBase = () => { + return typeElement.description(definitions, schema.xmlns); + }; + if (typeElement) { + const baseDescription = typeElement.description(definitions, schema.xmlns); + if (baseDescription[AttributeElement.Symbol]) { + _.defaults($attributes, baseDescription[AttributeElement.Symbol]); + } + desc = _.defaults(desc, baseDescription); + } + return desc; + } + + const restrictions = this.children + .map((child) => { + return child.description(); + }) + .join(','); + + return [this.$base, restrictions].filter(Boolean).join('|'); + } +} + +export class ExtensionElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['all', 'choice', 'sequence']); + public $base: string; + + public description(definitions: DefinitionsElement, xmlns?: IXmlNs) { + let desc = {}; + for (const child of this.children) { + if (child instanceof SequenceElement || child instanceof ChoiceElement) { + desc = child.description(definitions, xmlns); + } + } + if (this.$base) { + const type = splitQName(this.$base); + const typeName = type.name; + const ns = findNs(type.prefix, xmlns, this.definitionsXmlns, definitions.xmlns); + const schema = definitions.schemas[ns]; + + if (typeName in Primitives) { + return this.$base; + } else { + const typeElement = schema && (schema.complexTypes[typeName] || schema.types[typeName] || schema.elements[typeName]); + if (typeElement) { + const base = typeElement.description(definitions, schema.xmlns); + desc = typeof base === 'string' ? base : _.defaults(base, desc); + } + } + } + return desc; + } +} + +export class ChoiceElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['any', 'choice', 'element', 'sequence']); + public description(definitions: DefinitionsElement, xmlns: IXmlNs) { + const choice = {}; + for (const child of this.children) { + const description = child.description(definitions, xmlns); + for (const key in description) { + choice[key] = description[key]; + } + } + return choice; + } +} + +export class EnumerationElement extends Element { + // no children + public description(): string { + return this[this.valueKey]; + } +} + +export class ComplexTypeElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['all', 'annotation', 'choice', 'complexContent', 'sequence', 'simpleContent', 'attribute']); + public description(definitions: DefinitionsElement, xmlns: IXmlNs) { + let ret = {}; + let isFirstChild = false; + const $attributes = {}; + const children = this.children || []; + for (const child of children) { + if (child instanceof AttributeElement) { + $attributes[child.$name] = child.description(definitions); + continue; + } + + if (!isFirstChild && (child instanceof ChoiceElement || child instanceof SequenceElement || child instanceof AllElement || child instanceof SimpleContentElement || child instanceof ComplexContentElement)) { + isFirstChild = true; + ret = child.description(definitions, xmlns); + } + } + + if (Object.keys($attributes).length > 0) { + ret[AttributeElement.Symbol] = $attributes; + } + + return ret; + } +} + +export class ComplexContentElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['extension', 'restriction']); + + public description(definitions: DefinitionsElement, xmlns: IXmlNs) { + for (const child of this.children) { + if (child instanceof ExtensionElement || child instanceof RestrictionElement) { + return child.description(definitions, xmlns); + } + } + return {}; + } +} + +export class SimpleContentElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['extension']); + public description(definitions: DefinitionsElement, xmlns: IXmlNs) { + for (const child of this.children) { + if (child instanceof ExtensionElement) { + return child.description(definitions, xmlns); + } + } + return {}; + } +} + +export class SequenceElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['any', 'choice', 'element', 'sequence']); + public description(definitions: DefinitionsElement, xmlns: IXmlNs) { + const sequence = {}; + for (const child of this.children) { + if (child instanceof AnyElement) { + continue; + } + const description = child.description(definitions, xmlns); + for (const key in description) { + sequence[key] = description[key]; + } + } + return sequence; + } +} + +export class AttributeElement extends Element { + public static Symbol = Symbol('$attributes'); + public $type?: string; + public $use?: string; + + //eslint-disable-next-line @typescript-eslint/no-unused-vars + public description(definitions: DefinitionsElement) { + return { + type: this.$type, + required: this.$use === 'required', + }; + } +} + +export class AllElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['choice', 'element']); + public description(definitions: DefinitionsElement, xmlns: IXmlNs) { + const sequence = {}; + for (const child of this.children) { + if (child instanceof AnyElement) { + continue; + } + const description = child.description(definitions, xmlns); + for (const key in description) { + sequence[key] = description[key]; + } + } + return sequence; + } +} + +export class MessageElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['part', 'documentation']); + public element: ElementElement = null; + public parts = null; + + public postProcess(definitions: DefinitionsElement) { + let part: any = null; + const children = this.children || []; + + for (const child of children) { + if (child.name === 'part') { + part = child; + break; + } + } + + if (!part) { + return; + } + + if (part.$element) { + let lookupTypes: any[] = []; + + delete this.parts; + + const nsName = splitQName(part.$element); + const ns = findNs(nsName.prefix, this.definitionsXmlns, definitions.xmlns); + let schema = definitions.schemas[ns]; + this.element = schema.elements[nsName.name]; + if (!this.element) { + debug(nsName.name + ' is not present in wsdl and cannot be processed correctly.'); + return; + } + this.element.targetNSAlias = nsName.prefix; + this.element.targetNamespace = ns; + + // set the optional $lookupType to be used within `client#_invoke()` when + // calling `wsdl#objectToDocumentXML() + this.element.$lookupType = part.$element; + + const elementChildren = this.element.children; + + // get all nested lookup types (only complex types are followed) + if (elementChildren.length > 0) { + for (const child of elementChildren) { + lookupTypes.push(this._getNestedLookupTypeString(child)); + } + } + + // if nested lookup types where found, prepare them for furter usage + if (lookupTypes.length > 0) { + lookupTypes = lookupTypes + .join('_') + .split('_') + .filter(function removeEmptyLookupTypes(type) { + return type !== '^'; + }); + + const schemaXmlns = definitions.schemas[this.element.targetNamespace].xmlns; + + for (let i = 0; i < lookupTypes.length; i++) { + lookupTypes[i] = this._createLookupTypeObject(lookupTypes[i], schemaXmlns); + } + } + + this.element.$lookupTypes = lookupTypes; + + if (this.element.$type) { + const type = splitQName(this.element.$type); + const typeNs = findNs(type.prefix, schema.xmlns, this.definitionsXmlns, definitions.xmlns); + + if (typeNs) { + if (type.name in Primitives) { + // this.element = this.element.$type; + } else { + // first check local mapping of ns alias to namespace + schema = definitions.schemas[typeNs]; + const ctype = schema.complexTypes[type.name] || schema.types[type.name] || schema.elements[type.name]; + + if (ctype) { + this.parts = ctype.description(definitions, schema.xmlns); + } + } + } + } else { + const method = this.element.description(definitions, schema.xmlns); + this.parts = method[nsName.name]; + } + + this.children.splice(0, 1); + } else { + // rpc encoding + this.parts = {}; + delete this.element; + for (let i = 0; i < this.children.length; i++) { + const part = this.children[i] as any; + if (part.name === 'documentation') { + // + continue; + } + assert(part.name === 'part', 'Expected part element'); + const nsName = splitQName(part.$type); + const ns = findNs(nsName.prefix, this.definitionsXmlns, definitions.xmlns); + const type = nsName.name; + const schemaDefinition = definitions.schemas[ns]; + if (typeof schemaDefinition !== 'undefined') { + this.parts[part.$name] = definitions.schemas[ns].types[type] || definitions.schemas[ns].complexTypes[type]; + } else { + this.parts[part.$name] = part.$type; + } + + if (typeof this.parts[part.$name] === 'object') { + this.parts[part.$name].prefix = nsName.prefix; + this.parts[part.$name].xmlns = ns; + } + + this.children.splice(i--, 1); + } + } + this.deleteFixedAttrs(); + } + + public description(definitions: DefinitionsElement) { + if (this.element) { + return this.element && this.element.description(definitions); + } + const desc = {}; + desc[this.$name] = this.parts; + return desc; + } + + /** + * Takes a given namespaced String(for example: 'alias:property') and creates a lookupType + * object for further use in as first (lookup) `parameterTypeObj` within the `objectToXML` + * method and provides an entry point for the already existing code in `findChildSchemaObject`. + * + * @method _createLookupTypeObject + * @param {String} nsString The NS String (for example "alias:type"). + * @param {Object} xmlns The fully parsed `wsdl` definitions object (including all schemas). + * @returns {Object} + * @private + */ + private _createLookupTypeObject(nsString: string, xmlns: IXmlNs) { + const splittedNSString = splitQName(nsString); + const nsAlias = splittedNSString.prefix; + const splittedName = splittedNSString.name.split('#'); + const type = splittedName[0]; + const name = splittedName[1]; + + return { + $namespace: xmlns[nsAlias], + $type: nsAlias + ':' + type, + $name: name, + }; + } + + /** + * Iterates through the element and every nested child to find any defined `$type` + * property and returns it in a underscore ('_') separated String (using '^' as default + * value if no `$type` property was found). + * + * @method _getNestedLookupTypeString + * @param {Object} element The element which (probably) contains nested `$type` values. + * @returns {String} + * @private + */ + private _getNestedLookupTypeString(element): string { + let resolvedType = '^'; + const excluded = this.ignoredNamespaces.concat('xs'); // do not process $type values wich start with + + if (Object.hasOwnProperty.call(element, '$type') && typeof element.$type === 'string') { + if (excluded.indexOf(element.$type.split(':')[0]) === -1) { + resolvedType += '_' + element.$type + '#' + element.$name; + } + } + + if (element.children.length > 0) { + element.children.forEach((child) => { + const resolvedChildType = this._getNestedLookupTypeString(child).replace(/\^_/, ''); + + if (resolvedChildType && typeof resolvedChildType === 'string') { + resolvedType += '_' + resolvedChildType; + } + }); + } + + return resolvedType; + } +} + +export class DocumentationElement extends Element { + // no children +} + +export interface IInclude { + namespace: string; + location: string; +} + +export class SchemaElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['complexType', 'element', 'import', 'include', 'simpleType']); + public complexTypes: { [name: string]: ComplexTypeElement } = {}; + public types: { [name: string]: SimpleTypeElement } = {}; + public elements: { [name: string]: ElementElement } = {}; + public includes: IInclude[] = []; + public $elementFormDefault; + + public merge(source: SchemaElement) { + assert(source instanceof SchemaElement); + + _.merge(this.complexTypes, source.complexTypes); + _.merge(this.types, source.types); + _.merge(this.elements, source.elements); + _.merge(this.xmlns, source.xmlns); + + // Merge attributes from source without overwriting our's + _.merge( + this, + _.pickBy(source, (value, key) => { + return key.startsWith('$') && !Object.hasOwnProperty.call(this, key); + }), + ); + + return this; + } + + public addChild(child: Element) { + if (child.$name in Primitives) { + return; + } + if (child instanceof IncludeElement || child instanceof ImportElement) { + const location = child.$schemaLocation || child.$location; + if (location) { + this.includes.push({ + namespace: child.$namespace || child.$targetNamespace || this.$targetNamespace, + location: location, + }); + } + } else if (child instanceof ComplexTypeElement) { + this.complexTypes[child.$name] = child; + } else if (child instanceof ElementElement) { + this.elements[child.$name] = child; + } else if (child instanceof SimpleTypeElement) { + this.types[child.$name] = child; + } + this.children.pop(); + // child.deleteFixedAttrs(); + } +} + +export class TypesElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['documentation', 'schema']); + public schemas: { [name: string]: SchemaElement } = {}; + + // fix#325 + public addChild(child) { + assert(child instanceof SchemaElement); + + const childInclude = child.includes.find((e: object) => { + return Object.hasOwnProperty.call(e, 'namespace'); + }); + const childIncludeNs: string = typeof childInclude !== 'undefined' && Object.hasOwnProperty.call(childInclude, 'namespace') && child instanceof SchemaElement ? childInclude.namespace : undefined; + const targetNamespace = child.$targetNamespace || child.includes[0]?.namespace || childIncludeNs; + + if (!Object.hasOwnProperty.call(this.schemas, targetNamespace)) { + this.schemas[targetNamespace] = child; + } else { + if (targetNamespace === child.$targetNamespace) { + this.schemas[targetNamespace] = child; + } else { + console.error('Target-Namespace "' + targetNamespace + '" already in use by another Schema!'); + } + } + } +} + +export class OperationElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['documentation', 'fault', 'input', 'operation', 'output']); + public input: InputElement = null; + public output: OutputElement = null; + public inputSoap = null; + public outputSoap = null; + public style = ''; + public soapAction = ''; + public $soapAction?: string; + public $style?: string; + + public addChild(child) { + if (child instanceof OperationElement) { + this.soapAction = child.$soapAction || ''; + this.style = child.$style || ''; + this.children.pop(); + } + } + + public postProcess(definitions: DefinitionsElement, tag: string) { + const children = this.children; + for (let i = 0; i < children.length; i++) { + const child = children[i] as any; + if (child.name !== 'input' && child.name !== 'output') { + continue; + } + if (tag === 'binding') { + this[child.name] = child; + children.splice(i--, 1); + continue; + } + const messageName = splitQName(child.$message).name; + const message = definitions.messages[messageName]; + if (message) { + message.postProcess(definitions); + if (message.element) { + definitions.messages[message.element.$name] = message; + this[child.name] = message.element; + } else { + this[child.name] = message; + } + children.splice(i--, 1); + } + } + this.deleteFixedAttrs(); + } + + public description(definitions: DefinitionsElement) { + const inputDesc = this.input ? this.input.description(definitions) : null; + const outputDesc = this.output ? this.output.description(definitions) : null; + return { + input: inputDesc && inputDesc[Object.keys(inputDesc)[0]], + output: outputDesc && outputDesc[Object.keys(outputDesc)[0]], + }; + } +} + +export class PortTypeElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['documentation', 'operation']); + public methods: { + [name: string]: OperationElement; + } = {}; + + public postProcess(definitions: DefinitionsElement) { + const children = this.children; + if (typeof children === 'undefined') { + return; + } + for (let i = 0; i < children.length; i++) { + const child = children[i] as any; + if (child.name !== 'operation') { + continue; + } + child.postProcess(definitions, 'portType'); + this.methods[child.$name] = child; + children.splice(i--, 1); + } + delete this.$name; + this.deleteFixedAttrs(); + } + + public description(definitions: DefinitionsElement) { + const methods = {}; + for (const name in this.methods) { + const method = this.methods[name]; + methods[name] = method.description(definitions); + } + return methods; + } +} + +export interface ITopElement { + methodName: string; + outputName: string; +} + +export interface ITopElements { + [name: string]: ITopElement; +} + +export class BindingElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['binding', 'documentation', 'operation', 'SecuritySpec']); + public topElements?: ITopElements; + public transport = ''; + public style = ''; + public methods: { [name: string]: OperationElement } = {}; + public $type?: string; + + public addChild(child) { + if (child.name === 'binding') { + this.transport = child.$transport; + this.style = child.$style; + this.children.pop(); + } + } + + public postProcess(definitions: DefinitionsElement) { + const type = splitQName(this.$type).name; + const portType = definitions.portTypes[type]; + const style = this.style; + const children = this.children; + if (portType) { + portType.postProcess(definitions); + this.methods = portType.methods; + + for (let i = 0; i < children.length; i++) { + const child = children[i] as any; + if (child.name !== 'operation') { + continue; + } + child.postProcess(definitions, 'binding'); + children.splice(i--, 1); + if (!child.style) child.style = style; + const method = this.methods[child.$name]; + + if (method) { + method.style = child.style; + method.soapAction = child.soapAction; + method.inputSoap = child.input || null; + method.outputSoap = child.output || null; + if (method.inputSoap) method.inputSoap.deleteFixedAttrs(); + if (method.outputSoap) method.outputSoap.deleteFixedAttrs(); + } + } + } + delete this.$name; + delete this.$type; + this.deleteFixedAttrs(); + } + + public description(definitions: DefinitionsElement) { + const methods = {}; + for (const name in this.methods) { + const method = this.methods[name]; + methods[name] = method.description(definitions); + } + return methods; + } +} + +export class PortElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['address', 'documentation']); + public location = null; + + public addChild(child) { + if (child.name === 'address' && typeof child.$location !== 'undefined') { + this.location = child.$location; + } + } +} + +export interface IPort { + location: string; + binding: BindingElement; +} + +export class ServiceElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['documentation', 'port']); + public ports: { [name: string]: IPort } = {}; + + public postProcess(definitions: DefinitionsElement) { + const children = this.children; + const bindings = definitions.bindings; + if (children && children.length > 0) { + for (let i = 0; i < children.length; i++) { + const child = children[i] as any; + if (child.name !== 'port') { + continue; + } + const bindingName = splitQName(child.$binding).name; + const binding = bindings[bindingName]; + if (binding) { + binding.postProcess(definitions); + this.ports[child.$name] = { + location: child.location, + binding: binding, + }; + children.splice(i--, 1); + } + } + } + delete this.$name; + this.deleteFixedAttrs(); + } + + public description(definitions: DefinitionsElement) { + const ports = {}; + for (const name in this.ports) { + const port = this.ports[name]; + ports[name] = port.binding.description(definitions); + } + return ports; + } +} + +export class DefinitionsElement extends Element { + public readonly allowedChildren = buildAllowedChildren(['binding', 'documentation', 'import', 'message', 'portType', 'service', 'types']); + public complexTypes; + public messages: { [name: string]: MessageElement } = {}; + public portTypes: { [name: string]: PortTypeElement } = {}; + public bindings: { [name: string]: BindingElement } = {}; + public services: { [name: string]: ServiceElement } = {}; + public schemas: { [name: string]: SchemaElement } = {}; + public descriptions: { + types: { + [key: string]: Element; + }; + elements: { + [key: string]: Element; + }; + } = { + types: {}, + elements: {}, + }; + + public init() { + if (this.name !== 'definitions') { + this.unexpected(this.nsName); + } + } + + public addChild(child) { + if (child instanceof TypesElement) { + // Merge types.schemas into definitions.schemas + _.merge(this.schemas, child.schemas); + } else if (child instanceof MessageElement) { + this.messages[child.$name] = child; + } else if (child.name === 'import') { + const schemaElement = new SchemaElement(child.$namespace, {}); + schemaElement.init(); + this.schemas[child.$namespace] = schemaElement; + this.schemas[child.$namespace].addChild(child); + } else if (child instanceof PortTypeElement) { + this.portTypes[child.$name] = child; + } else if (child instanceof BindingElement) { + if (child.transport === 'http://schemas.xmlsoap.org/soap/http' || child.transport === 'http://www.w3.org/2003/05/soap/bindings/HTTP/') { + this.bindings[child.$name] = child; + } + } else if (child instanceof ServiceElement) { + this.services[child.$name] = child; + } + this.children.pop(); + } +} + +export class BodyElement extends Element { + public $use?: string; + public $encodingStyle?: string; +} + +export class IncludeElement extends Element { + public $schemaLocation?; + public $location?; + public $namespace?; +} + +export class ImportElement extends Element { + public $schemaLocation?; + public $location?; + public $namespace?; +} + +const ElementTypeMap: { + [k: string]: typeof Element; +} = { + // group: [GroupElement, 'element group'], + all: AllElement, + any: AnyElement, + binding: BindingElement, + body: BodyElement, + choice: ChoiceElement, + complexContent: ComplexContentElement, + complexType: ComplexTypeElement, + definitions: DefinitionsElement, + documentation: DocumentationElement, + element: ElementElement, + enumeration: EnumerationElement, + extension: ExtensionElement, + fault: Element, + import: ImportElement, + include: IncludeElement, + input: InputElement, + message: MessageElement, + operation: OperationElement, + output: OutputElement, + port: PortElement, + portType: PortTypeElement, + restriction: RestrictionElement, + schema: SchemaElement, + sequence: SequenceElement, + service: ServiceElement, + simpleContent: SimpleContentElement, + simpleType: SimpleTypeElement, + types: TypesElement, + attribute: AttributeElement, +}; + +function buildAllowedChildren(elementList: string[]): { [k: string]: typeof Element } { + const rtn = {}; + for (const element of elementList) { + rtn[element.replace(/^_/, '')] = ElementTypeMap[element] || Element; + } + return rtn; +} + +/** + * Return the first matching namespace for the provided prefix. + */ +function findNs(prefix: string, ...xmlnss: Array): string | undefined { + for (const xmlns of xmlnss) { + if (xmlns?.[prefix]) { + return xmlns[prefix]; + } + } +} diff --git a/src/wsdl/index.ts b/src/wsdl/index.ts new file mode 100644 index 000000000..42b9d8e28 --- /dev/null +++ b/src/wsdl/index.ts @@ -0,0 +1,1473 @@ +/* + * Copyright (c) 2011 Vinay Pulim + * MIT Licensed + * + */ +/*jshint proto:true*/ + +import { ok as assert } from 'assert'; +import debugBuilder from 'debug'; +import * as fs from 'fs'; +import * as _ from 'lodash'; +import * as path from 'path'; +import * as sax from 'sax'; +import stripBom from 'strip-bom'; +import * as url from 'url'; +import { HttpClient } from '../http'; +import { NamespaceContext } from '../nscontext'; +import { IOptions } from '../types'; +import { findPrefix, splitQName, TNS_PREFIX, xmlEscape } from '../utils'; +import * as elements from './elements'; + +const debug = debugBuilder('node-soap'); + +const XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance'; +const ENV_URI = 'http://schemas.xmlsoap.org/soap/envelope/'; + +export function trim(text) { + return text.trim(); +} + +function appendColon(ns: string): string { + return ns && ns.charAt(ns.length - 1) !== ':' ? ns + ':' : ns; +} + +function noColonNameSpace(ns: string): string { + return ns && ns.charAt(ns.length - 1) === ':' ? ns.substring(0, ns.length - 1) : ns; +} + +interface IInitializedOptions extends IOptions { + ignoredNamespaces?: string[]; +} + +export class WSDL { + public ignoredNamespaces = ['tns', 'targetNamespace', 'typedNamespace']; + public ignoreBaseNameSpaces = false; + public valueKey = '$value'; + public xmlKey = '$xml'; + public xmlnsInEnvelope: string; + public xmlnsInHeader: string; + public uri: string; + public definitions: elements.DefinitionsElement; + public options: IInitializedOptions; + /** @internal */ + public WSDL_CACHE; + + private callback: (err: Error, caller?) => void; + private services: { [name: string]: elements.ServiceElement }; + private xml: string; + private _includesWsdl; + private _originalIgnoredNamespaces; + + constructor(definition: any, uri: string, options: IOptions) { + let fromFunc; + + this.uri = uri; + this.callback = () => {}; + this._includesWsdl = []; + + // initialize WSDL cache + this.WSDL_CACHE = {}; + if (options && options.WSDL_CACHE) { + this.WSDL_CACHE = options.WSDL_CACHE; + } + + this._initializeOptions(options); + + if (typeof definition === 'string') { + definition = stripBom(definition); + fromFunc = this._fromXML; + } else if (typeof definition === 'object') { + fromFunc = this._fromServices; + } else { + throw new Error('WSDL constructor takes either an XML string or service definition'); + } + + process.nextTick(() => { + try { + fromFunc.call(this, definition); + } catch (e) { + return this.callback(e); + } + + this.processIncludes((err) => { + let name; + if (err) { + return this.callback(err); + } + + try { + this.definitions.deleteFixedAttrs(); + const services = (this.services = this.definitions.services); + if (services) { + for (name in services) { + services[name].postProcess(this.definitions); + } + } + const complexTypes = this.definitions.complexTypes; + if (complexTypes) { + for (name in complexTypes) { + complexTypes[name].deleteFixedAttrs(); + } + } + + // for document style, for every binding, prepare input message element name to (methodName, output message element name) mapping + const bindings = this.definitions.bindings; + for (const bindingName in bindings) { + const binding = bindings[bindingName]; + if (typeof binding.style === 'undefined') { + binding.style = 'document'; + } + const methods = binding.methods; + const topEls: elements.ITopElements = (binding.topElements = {}); + for (const methodName in methods) { + if ((methods[methodName].style || binding.style) !== 'document') { + continue; + } + if (methods[methodName].input) { + const inputName = methods[methodName].input.$name; + let outputName = ''; + if (methods[methodName].output) { + outputName = methods[methodName].output.$name; + } + topEls[inputName] = { methodName: methodName, outputName: outputName }; + } + } + } + + // prepare soap envelope xmlns definition string + this.xmlnsInEnvelope = this._xmlnsMap(); + + this.callback(err, this); + } catch (e) { + this.callback(e); + } + }); + }); + } + + public onReady(callback: (err: Error) => void): void { + if (callback) { + this.callback = callback; + } + } + + public processIncludes(callback) { + const schemas = this.definitions.schemas; + let includes: elements.IInclude[] = []; + + for (const ns in schemas) { + const schema = schemas[ns]; + includes = includes.concat(schema.includes || []); + } + + this._processNextInclude(includes, callback); + } + + public describeServices() { + const services = {}; + for (const name in this.services) { + const service = this.services[name]; + services[name] = service.description(this.definitions); + } + return services; + } + + public toXML() { + return this.xml || ''; + } + + public getSaxStream(xml) { + const saxStream = sax.createStream(true, null); + xml.pipe(saxStream); + + return saxStream; + } + + public xmlToObject(xml, callback?) { + const p: any = typeof callback === 'function' ? {} : sax.parser(true, null); + let objectName = null; + const root: any = {}; + const schema = { + Envelope: { + Header: { + Security: { + UsernameToken: { + Username: 'string', + Password: 'string', + }, + }, + }, + Body: { + Fault: { + faultcode: 'string', + faultstring: 'string', + detail: 'string', + }, + }, + }, + }; + const stack: any[] = [{ name: null, object: root, schema: schema }]; + const xsiPrefixes: Map = new Map(); + let envPrefix: string = 'soap'; + const xmlns: any = {}; + + const refs = {}; + + p.onopentag = (node) => { + const nsName = node.name; + const attrs: any = node.attributes; + let name = splitQName(nsName).name; + let attributeName; + const top = stack[stack.length - 1]; + let topSchema = top.schema; + const elementAttributes = {}; + let hasNonXmlnsAttribute = false; + let hasNilAttribute = false; + const obj = {}; + const originalName = name; + + if (attrs.href) { + const id = attrs.href.substr(1); + if (!refs[id]) { + refs[id] = { hrefs: [], obj: null }; + } + refs[id].hrefs.push({ par: top.object, key: name, obj: obj }); + } + if (attrs.id) { + if (!refs[attrs.id]) { + refs[attrs.id] = { hrefs: [], obj: null }; + } + } + + // Handle element attributes + for (attributeName in attrs) { + const value = attrs[attributeName]; + if (/^xmlns:|^xmlns$/.test(attributeName)) { + const name = splitQName(attributeName).name; + xmlns[name] = value; + if (value === XSI_URI) { + xsiPrefixes.set(name, value); + } + if (value === ENV_URI) { + envPrefix = name; + } + continue; + } + hasNonXmlnsAttribute = true; + elementAttributes[attributeName] = value; + } + + for (attributeName in elementAttributes) { + const res = splitQName(attributeName); + if (res.name === 'nil' && xmlns[res.prefix] === XSI_URI && elementAttributes[attributeName] && (elementAttributes[attributeName].toLowerCase() === 'true' || elementAttributes[attributeName] === '1')) { + hasNilAttribute = true; + break; + } + } + + if (hasNonXmlnsAttribute) { + obj[this.options.attributesKey] = elementAttributes; + } + + if (!objectName && xmlns[envPrefix] && top.name === 'Body' && name !== 'Fault') { + let message = this.definitions.messages[name]; + // Support RPC/literal messages where response body contains one element named + // after the operation + 'Response'. See http://www.w3.org/TR/wsdl#_names + if (!message) { + try { + // Determine if this is request or response + let isInput = false; + if (/Response$/.test(name)) { + name = name.replace(/Response$/, ''); + } else if (/Request$/.test(name)) { + isInput = true; + name = name.replace(/Request$/, ''); + } else if (/Solicit$/.test(name)) { + isInput = true; + name = name.replace(/Solicit$/, ''); + } + // Look up the appropriate message as given in the portType's operations + const portTypes = this.definitions.portTypes; + const portTypeNames = Object.keys(portTypes); + + for (const portTypeName of portTypeNames) { + const portType = portTypes[portTypeName]; + const method = portType.methods[name]; + + if (!method) { + continue; + } + + try { + if (isInput) { + name = portType.methods[name].input.$name; + } else { + name = portType.methods[name].output.$name; + } + message = this.definitions.messages[name]; + break; + } catch { + throw new Error(`Failed to lookup message ${name} in methods`); + } + } + if (!message) { + throw new Error(`Could not find message ${name}`); + } + // 'cache' this alias to speed future lookups + this.definitions.messages[originalName] = message; + } catch (e) { + if (this.options.returnFault) { + p.onerror(e); + } + } + } + + topSchema = message.description(this.definitions); + objectName = originalName; + } + + // Pick up the schema for the type specified in element's xsi:type attribute. + let xsiTypeSchema; + let xsiType; + + for (const prefix of xsiPrefixes.keys()) { + if (`${prefix}:type` in elementAttributes) { + xsiType = elementAttributes[`${prefix}:type`]; + break; + } + } + + if (xsiType) { + const type = splitQName(xsiType); + let typeURI; + if (type.prefix === TNS_PREFIX) { + // In case of xsi:type = "MyType" + typeURI = xmlns[type.prefix] || xmlns.xmlns; + } else { + typeURI = xmlns[type.prefix]; + } + const typeDef = this.findSchemaObject(typeURI, type.name); + if (typeDef) { + xsiTypeSchema = typeDef.description(this.definitions); + } + } + + if (topSchema && topSchema[name + '[]']) { + name = name + '[]'; + } + stack.push({ name: originalName, object: obj, schema: xsiTypeSchema || (topSchema && topSchema[name]), id: attrs.id, nil: hasNilAttribute }); + }; + + p.onclosetag = (nsName) => { + const cur: any = stack.pop(); + let obj = cur.object; + const top = stack[stack.length - 1]; + const topObject = top.object; + const topSchema = top.schema; + const name = splitQName(nsName).name; + + if (typeof cur.schema === 'string' && (cur.schema === 'string' || cur.schema.split(':')[1] === 'string')) { + if (typeof obj === 'object' && Object.keys(obj).length === 0) { + obj = cur.object = this.options.preserveWhitespace ? cur.text || '' : ''; + } + } + + if (cur.nil === true) { + if (this.options.handleNilAsNull) { + obj = null; + } else { + return; + } + } + + if (_.isPlainObject(obj) && !Object.keys(obj).length) { + obj = null; + } + + if (topSchema && topSchema[name + '[]']) { + if (!topObject[name]) { + topObject[name] = []; + } + topObject[name].push(obj); + } else if (name in topObject) { + if (!Array.isArray(topObject[name])) { + topObject[name] = [topObject[name]]; + } + topObject[name].push(obj); + } else { + topObject[name] = obj; + } + + if (cur.id) { + refs[cur.id].obj = obj; + } + }; + + p.oncdata = (text) => { + const originalText = text; + text = trim(text); + if (!text.length) { + return; + } + + if (/<\?xml[\s\S]+\?>/.test(text)) { + const top = stack[stack.length - 1]; + const value = this.xmlToObject(text); + if (top.object[this.options.attributesKey]) { + top.object[this.options.valueKey] = value; + } else { + top.object = value; + } + } else { + p.ontext(originalText); + } + }; + + p.onerror = (e) => { + p.resume(); + throw { + Fault: { + faultcode: 500, + faultstring: 'Invalid XML', + detail: new Error(e).message, + statusCode: 500, + }, + }; + }; + + p.ontext = (text) => { + const top = stack[stack.length - 1]; + + const originalText = text; + text = trim(text); + if (!text.length) { + if (this.options.preserveWhitespace) { + top.text = (top.text || '') + originalText; + } + return; + } + + const name = splitQName(top.schema).name; + let value; + + if (this.options && this.options.customDeserializer && this.options.customDeserializer[name]) { + value = this.options.customDeserializer[name](text, top); + } else { + if (name === 'int' || name === 'integer' || name === 'short' || name === 'long') { + value = parseInt(text, 10); + } else if (name === 'double' || name === 'float' || name === 'decimal') { + value = Number(text); + } else if (name === 'bool' || name === 'boolean') { + value = text.toLowerCase() === 'true' || text === '1'; + } else if (name === 'dateTime' || name === 'date') { + value = new Date(text); + } else { + if (this.options.preserveWhitespace) { + text = originalText; + } + // handle string or other types + if (typeof top.object !== 'string') { + value = text; + } else { + value = top.object + text; + } + } + } + + if (top.object[this.options.attributesKey]) { + top.object[this.options.valueKey] = value; + } else { + top.object = value; + } + }; + + if (typeof callback === 'function') { + // we be streaming + const saxStream = sax.createStream(true, null); + saxStream.on('opentag', p.onopentag); + saxStream.on('closetag', p.onclosetag); + saxStream.on('cdata', p.oncdata); + saxStream.on('text', p.ontext); + xml + .pipe(saxStream) + .on('error', (err) => { + callback(err); + }) + .on('end', () => { + let r; + try { + r = finish(); + } catch (e) { + return callback(e); + } + callback(null, r); + }); + return; + } + p.write(xml).close(); + + return finish(); + + function finish() { + // MultiRef support: merge objects instead of replacing + for (const n in refs) { + const ref = refs[n]; + for (const href of ref.hrefs) { + Object.assign(href.obj, ref.obj); + } + } + + if (root.Envelope) { + const body = root.Envelope.Body; + if (body && body.Fault) { + const fault = body.Fault; + let code = fault.faultcode && fault.faultcode.$value; + let string = fault.faultstring && fault.faultstring.$value; + let detail = fault.detail && fault.detail.$value; + + code = code || fault.faultcode; + string = string || fault.faultstring; + detail = detail || fault.detail; + // SOAP 1.2 + code = code || (fault.Code && `${fault.Code.Value}: ${fault.Code.Subcode && fault.Code.Subcode.Value}`); + string = string || (fault.Reason && fault.Reason.Text.$value); + string = string || (fault.Reason && fault.Reason.Text); + detail = detail || fault.Detail; + + const error: any = new Error(code + ': ' + string + (detail ? ': ' + JSON.stringify(detail) : '')); + + error.root = root; + throw error; + } + return root.Envelope; + } + return root; + } + } + + /** + * Look up a XSD type or element by namespace URI and name + * @param {String} nsURI Namespace URI + * @param {String} qname Local or qualified name + * @returns {*} The XSD type/element definition + */ + public findSchemaObject(nsURI: string, qname: string) { + if (!nsURI || !qname) { + return null; + } + + let def = null; + + if (this.definitions.schemas) { + const schema = this.definitions.schemas[nsURI]; + if (schema) { + if (qname.indexOf(':') !== -1) { + qname = qname.substring(qname.indexOf(':') + 1, qname.length); + } + + // if the client passed an input element which has a `$lookupType` property instead of `$type` + // the `def` is found in `schema.elements`. + def = schema.complexTypes[qname] || schema.types[qname] || schema.elements[qname]; + } + } + + return def; + } + + /** + * Create document style xml string from the parameters + * @param {String} name + * @param {*} params + * @param {String} nsPrefix + * @param {String} nsURI + * @param {String} type + */ + public objectToDocumentXML(name: string, params, nsPrefix: string, nsURI?: string, type?: string) { + // If user supplies XML already, just use that. XML Declaration should not be present. + if (params && params._xml) { + return params._xml; + } + const args = {}; + args[name] = params; + const parameterTypeObj = type ? this.findSchemaObject(nsURI, type) : null; + return this.objectToXML(args, null, nsPrefix, nsURI, true, null, parameterTypeObj); + } + + /** + * Create RPC style xml string from the parameters + * @param {String} name + * @param {*} params + * @param {String} nsPrefix + * @param {String} nsURI + * @returns {string} + */ + public objectToRpcXML(name: string, params, nsPrefix: string, nsURI: string, isParts?: boolean) { + const parts = []; + const defs = this.definitions; + const nsAttrName = '_xmlns'; + + nsPrefix = nsPrefix || findPrefix(defs.xmlns, nsURI); + + nsURI = nsURI || defs.xmlns[nsPrefix]; + nsPrefix = nsPrefix === TNS_PREFIX ? '' : nsPrefix + ':'; + + parts.push(['<', nsPrefix, name, '>'].join('')); + + for (const key in params) { + if (!Object.prototype.hasOwnProperty.call(params, key)) { + continue; + } + if (key !== nsAttrName) { + const value = params[key]; + if (key === this.options.xmlKey) { + parts.push(this.objectToXML({ [key]: value }, null, nsPrefix, nsURI)); + } else { + const prefixedKey = (isParts ? '' : nsPrefix) + key; + const attributes = []; + if (typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, this.options.attributesKey)) { + const attrs = value[this.options.attributesKey]; + for (const n in attrs) { + attributes.push(' ' + n + '=' + '"' + attrs[n] + '"'); + } + } + parts.push(['<', prefixedKey].concat(attributes).concat('>').join('')); + parts.push(typeof value === 'object' ? this.objectToXML(value, key, nsPrefix, nsURI) : xmlEscape(value)); + parts.push([''].join('')); + } + } + } + parts.push([''].join('')); + return parts.join(''); + } + + public isIgnoredNameSpace(ns: string): boolean { + return this.options.ignoredNamespaces.indexOf(ns) > -1; + } + + public filterOutIgnoredNameSpace(ns: string): string { + const namespace = noColonNameSpace(ns); + return this.isIgnoredNameSpace(namespace) ? '' : namespace; + } + + /** + * Convert an object to XML. This is a recursive method as it calls itself. + * + * @param {Object} obj the object to convert. + * @param {String} name the name of the element (if the object being traversed is + * an element). + * @param {String} nsPrefix the namespace prefix of the object I.E. xsd. + * @param {String} nsURI the full namespace of the object I.E. http://w3.org/schema. + * @param {Boolean} isFirst whether or not this is the first item being traversed. + * @param {?} xmlnsAttr + * @param {?} parameterTypeObject + * @param {NamespaceContext} nsContext Namespace context + */ + public objectToXML(obj, name: string, nsPrefix: any, nsURI: string, isFirst?: boolean, xmlnsAttr?, schemaObject?, nsContext?: NamespaceContext) { + const schema = this.definitions.schemas[nsURI]; + + if (this.options.overrideElementKey && Object.keys(this.options.overrideElementKey).length > 0) { + for (const key in this.options.overrideElementKey) { + const overrideKey = this.options.overrideElementKey[key]; + if (obj && obj[key]) { + Object.defineProperty(obj, overrideKey, Object.getOwnPropertyDescriptor(obj, key)); + delete obj[key]; + } + } + } + + let parentNsPrefix = nsPrefix ? nsPrefix.parent : undefined; + if (typeof parentNsPrefix !== 'undefined') { + // we got the parentNsPrefix for our array. setting the namespace-variable back to the current namespace string + nsPrefix = nsPrefix.current; + } + + parentNsPrefix = noColonNameSpace(parentNsPrefix); + if (this.isIgnoredNameSpace(parentNsPrefix)) { + parentNsPrefix = ''; + } + + const soapHeader = !schema; + const qualified = schema && schema.$elementFormDefault === 'qualified'; + const parts = []; + const prefixNamespace = (nsPrefix || qualified) && nsPrefix !== TNS_PREFIX; + + let xmlnsAttrib = ''; + if (nsURI && isFirst) { + if (this.options.overrideRootElement && this.options.overrideRootElement.xmlnsAttributes) { + this.options.overrideRootElement.xmlnsAttributes.forEach((attribute) => { + xmlnsAttrib += ' ' + attribute.name + '="' + attribute.value + '"'; + }); + } else { + if (prefixNamespace && !this.isIgnoredNameSpace(nsPrefix)) { + // resolve the prefix namespace + xmlnsAttrib += ' xmlns:' + nsPrefix + '="' + nsURI + '"'; + } + // only add default namespace if the schema elementFormDefault is qualified + if (qualified || soapHeader) { + xmlnsAttrib += ' xmlns="' + nsURI + '"'; + } + } + } + + if (!nsContext) { + nsContext = new NamespaceContext(); + nsContext.declareNamespace(nsPrefix, nsURI); + } else { + nsContext.pushContext(); + } + + // explicitly use xmlns attribute if available + if (xmlnsAttr && !(this.options.overrideRootElement && this.options.overrideRootElement.xmlnsAttributes)) { + xmlnsAttrib = xmlnsAttr; + } + + let ns = ''; + + if (this.options.overrideRootElement && isFirst) { + ns = this.options.overrideRootElement.namespace; + } else if (prefixNamespace && (qualified || isFirst || soapHeader) && !this.isIgnoredNameSpace(nsPrefix)) { + ns = nsPrefix; + } + + let i; + let n; + // start building out XML string. + if (Array.isArray(obj)) { + let nonSubNameSpace = ''; + let emptyNonSubNameSpaceForArray = false; + const nameWithNsRegex = /^([^:]+):([^:]+)$/.exec(name); + if (nameWithNsRegex) { + nonSubNameSpace = nameWithNsRegex[1]; + name = nameWithNsRegex[2]; + } else if (name[0] === ':') { + emptyNonSubNameSpaceForArray = true; + name = name.substr(1); + } + + for (i = 0, n = obj.length; i < n; i++) { + const item = obj[i]; + const arrayAttr = this.processAttributes(item, nsContext); + const correctOuterNsPrefix = nonSubNameSpace || parentNsPrefix || ns; // using the parent namespace prefix if given + + const body = this.objectToXML(item, name, nsPrefix, nsURI, false, null, schemaObject, nsContext); + + let openingTagParts = ['<', name, arrayAttr, xmlnsAttrib]; + if (!emptyNonSubNameSpaceForArray) { + openingTagParts = ['<', appendColon(correctOuterNsPrefix), name, arrayAttr, xmlnsAttrib]; + } + + if (body === '' && this.options.useEmptyTag) { + // Use empty (self-closing) tags if no contents + openingTagParts.push(' />'); + parts.push(openingTagParts.join('')); + } else { + openingTagParts.push('>'); + if (this.options.namespaceArrayElements || i === 0) { + parts.push(openingTagParts.join('')); + } + parts.push(body); + if (this.options.namespaceArrayElements || i === n - 1) { + if (emptyNonSubNameSpaceForArray) { + parts.push([''].join('')); + } else { + parts.push([''].join('')); + } + } + } + } + } else if (typeof obj === 'object') { + let currentChildXmlnsAttrib = ''; + for (name in obj) { + // Happens when Object.create(null) is used, it will not inherit the Object prototype + if (!obj.hasOwnProperty) { + obj = Object.assign({}, obj); + } + if (!Object.prototype.hasOwnProperty.call(obj, name)) { + continue; + } + // don't process attributes as element + if (name === this.options.attributesKey) { + continue; + } + // Its the value of a xml object. Return it directly. + if (name === this.options.xmlKey) { + nsContext.popContext(); + return obj[name]; + } + // Its the value of an item. Return it directly. + if (name === this.options.valueKey) { + nsContext.popContext(); + return xmlEscape(obj[name]); + } + + const child = obj[name]; + if (typeof child === 'undefined') { + continue; + } + + const attr = this.processAttributes(child, nsContext); + + let value = ''; + let nonSubNameSpace = ''; + let emptyNonSubNameSpace = false; + + const nameWithNsRegex = /^([^:]+):([^:]+)$/.exec(name); + if (nameWithNsRegex) { + nonSubNameSpace = nameWithNsRegex[1] + ':'; + name = nameWithNsRegex[2]; + } else if (name[0] === ':') { + emptyNonSubNameSpace = true; + name = name.substr(1); + } + + if (isFirst) { + value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, schemaObject, nsContext); + } else { + if (this.definitions.schemas) { + if (schema) { + const childSchemaObject = this.findChildSchemaObject(schemaObject, name); + // find sub namespace if not a primitive + if (childSchemaObject && ((childSchemaObject.$type && childSchemaObject.$type.indexOf('xsd:') === -1) || childSchemaObject.$ref || childSchemaObject.$name)) { + /*if the base name space of the children is not in the ingoredSchemaNamspaces we use it. + This is because in some services the child nodes do not need the baseNameSpace. + */ + + let childNsPrefix: any = ''; + let childName = ''; + let childNsURI; + let childXmlnsAttrib = ''; + + let elementQName = childSchemaObject.$ref || childSchemaObject.$name; + if (elementQName) { + elementQName = splitQName(elementQName); + childName = elementQName.name; + if (elementQName.prefix === TNS_PREFIX) { + // Local element + childNsURI = childSchemaObject.$targetNamespace; + childNsPrefix = nsContext.registerNamespace(childNsURI); + if (this.isIgnoredNameSpace(childNsPrefix)) { + childNsPrefix = nsPrefix; + } + } else { + childNsPrefix = elementQName.prefix; + if (this.isIgnoredNameSpace(childNsPrefix)) { + childNsPrefix = nsPrefix; + } + childNsURI = schema.xmlns[childNsPrefix] || this.definitions.xmlns[childNsPrefix]; + } + + let unqualified = false; + // Check qualification form for local elements + if (childSchemaObject.$name && childSchemaObject.targetNamespace === undefined) { + if (childSchemaObject.$form === 'unqualified') { + unqualified = true; + } else if (childSchemaObject.$form === 'qualified') { + unqualified = false; + } else { + unqualified = schema.$elementFormDefault !== 'qualified'; + } + } + if (unqualified) { + childNsPrefix = ''; + } + + if (childNsURI && childNsPrefix) { + if (nsContext.declareNamespace(childNsPrefix, childNsURI)) { + childXmlnsAttrib = ' xmlns:' + childNsPrefix + '="' + childNsURI + '"'; + if (!xmlnsAttrib.includes(childNsPrefix)) { + currentChildXmlnsAttrib = childXmlnsAttrib; + xmlnsAttrib += childXmlnsAttrib; + } + } + } + } + + let resolvedChildSchemaObject; + if (childSchemaObject.$type) { + const typeQName = splitQName(childSchemaObject.$type); + const typePrefix = childSchemaObject.$baseNameSpace || typeQName.prefix; + const typeURI = schema.xmlns[typePrefix] || this.definitions.xmlns[typePrefix]; + childNsURI = typeURI; + if (typeURI !== 'http://www.w3.org/2001/XMLSchema' && typePrefix !== TNS_PREFIX) { + // Add the prefix/namespace mapping, but not declare it + nsContext.addNamespace(typePrefix, typeURI); + } + resolvedChildSchemaObject = this.findSchemaType(typeQName.name, typeURI) || childSchemaObject; + } else { + resolvedChildSchemaObject = this.findSchemaObject(childNsURI, childName) || childSchemaObject; + } + + if (childSchemaObject.$baseNameSpace && this.options.ignoreBaseNameSpaces) { + childNsPrefix = nsPrefix; + childNsURI = nsURI; + } + + if (this.options.ignoreBaseNameSpaces) { + childNsPrefix = ''; + childNsURI = ''; + } + + ns = childNsPrefix; + + if (Array.isArray(child)) { + // for arrays, we need to remember the current namespace + childNsPrefix = { + current: childNsPrefix, + parent: ns, + }; + childXmlnsAttrib = childXmlnsAttrib && childXmlnsAttrib.length ? childXmlnsAttrib : currentChildXmlnsAttrib; + } else { + // parent (array) already got the namespace + childXmlnsAttrib = null; + } + + value = this.objectToXML(child, name, childNsPrefix, childNsURI, false, childXmlnsAttrib, resolvedChildSchemaObject, nsContext); + } else if (obj[this.options.attributesKey] && obj[this.options.attributesKey].xsi_type) { + nonSubNameSpace = obj[this.options.attributesKey].xsi_type.prefix; + nsContext.addNamespace(obj[this.options.attributesKey].xsi_type.prefix, obj[this.options.attributesKey].xsi_type.xmlns); + value = this.objectToXML(child, name, obj[this.options.attributesKey].xsi_type.prefix, obj[this.options.attributesKey].xsi_type.xmlns, false, null, null, nsContext); + } else { + if (Array.isArray(child)) { + if (emptyNonSubNameSpace) { + name = ':' + name; + } else { + name = nonSubNameSpace + name; + } + } + + value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, null, nsContext); + } + } else { + value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, null, nsContext); + } + } + } + + ns = noColonNameSpace(ns); + if (prefixNamespace && !qualified && isFirst && !this.options.overrideRootElement) { + ns = nsPrefix; + } else if (this.isIgnoredNameSpace(ns)) { + ns = ''; + } + + const useEmptyTag = !value && this.options.useEmptyTag; + if (!Array.isArray(child)) { + // start tag + parts.push(['<', emptyNonSubNameSpace ? '' : appendColon(nonSubNameSpace || ns), name, attr, xmlnsAttrib, child === null ? ' xsi:nil="true"' : '', useEmptyTag ? ' />' : '>'].join('')); + } + + if (!useEmptyTag) { + parts.push(value); + if (!Array.isArray(child)) { + // end tag + parts.push([''].join('')); + } + } + } + } else if (obj !== undefined) { + parts.push(this.options.escapeXML ? xmlEscape(obj) : obj); + } + nsContext.popContext(); + return parts.join(''); + } + + public processAttributes(child: any, nsContext: NamespaceContext): string { + let attr = ''; + + if (child === null || child === undefined) { + child = []; + } + + const attrObj = child[this.options.attributesKey] || {}; + if (attrObj && attrObj.xsi_type) { + const xsiType = attrObj.xsi_type; + + let prefix = xsiType.prefix || xsiType.namespace; + if (xsiType.xmlns) { + // Generate a new namespace for complex extension if one not provided + if (!prefix) { + prefix = nsContext.registerNamespace(xsiType.xmlns); + } else { + nsContext.declareNamespace(prefix, xsiType.xmlns); + } + xsiType.prefix = prefix; + } + } + + Object.keys(attrObj).forEach((k) => { + const v = attrObj[k]; + if (k === 'xsi_type') { + let name = v.type; + if (v.prefix) { + name = `${v.prefix}:${name}`; + } + attr += ` xsi:type="${name}"`; + if (v.xmlns) { + attr += ` xmlns:${v.prefix}="${v.xmlns}"`; + } + } else { + attr += ` ${k}="${xmlEscape(v)}"`; + } + }); + + return attr; + } + + /** + * Look up a schema type definition + * @param name + * @param nsURI + * @returns {*} + */ + public findSchemaType(name: any, nsURI: any): any { + if (!this.definitions.schemas || !name || !nsURI) { + return null; + } + + const schema = this.definitions.schemas[nsURI]; + if (!schema || !schema.complexTypes) { + return null; + } + + return schema.complexTypes[name]; + } + + public findChildSchemaObject(parameterTypeObj: any, childName: any, backtrace?: any): any { + if (!parameterTypeObj || !childName) { + return null; + } + + if (!backtrace) { + backtrace = []; + } + + if (backtrace.indexOf(parameterTypeObj) >= 0) { + // We've recursed back to ourselves; break. + return null; + } else { + backtrace = backtrace.concat([parameterTypeObj]); + } + + let found = null; + let i = 0; + let ref; + + if (Array.isArray(parameterTypeObj.$lookupTypes) && parameterTypeObj.$lookupTypes.length) { + const types = parameterTypeObj.$lookupTypes; + + for (i = 0; i < types.length; i++) { + const typeObj = types[i]; + + if (typeObj.$name === childName) { + found = typeObj; + break; + } + } + } + + const object = parameterTypeObj; + if (object.$name === childName && object.name === 'element') { + return object; + } + if (object.$ref) { + ref = splitQName(object.$ref); + if (ref.name === childName) { + return object; + } + } + + let childNsURI; + + // want to avoid unecessary recursion to improve performance + if (object.$type && backtrace.length === 1) { + const typeInfo = splitQName(object.$type); + if (typeInfo.prefix === TNS_PREFIX) { + childNsURI = parameterTypeObj.$targetNamespace; + } else { + childNsURI = this.definitions.xmlns[typeInfo.prefix]; + } + const typeDef = this.findSchemaType(typeInfo.name, childNsURI); + if (typeDef) { + return this.findChildSchemaObject(typeDef, childName, backtrace); + } + } + + // handle $base (e.g. for ExtensionElement) like $type + if (object.$base && (!Array.isArray(object.children) || !object.children.length)) { + const baseInfo = splitQName(object.$base); + childNsURI = parameterTypeObj.$targetNamespace; + if (baseInfo.prefix !== TNS_PREFIX) { + childNsURI = this.definitions.xmlns[baseInfo.prefix]; + } + const baseDef = this.findSchemaType(baseInfo.name, childNsURI); + if (baseDef) { + return this.findChildSchemaObject(baseDef, childName, backtrace); + } + } + + if (Array.isArray(object.children) && object.children.length > 0) { + for (const child of object.children) { + found = this.findChildSchemaObject(child, childName, backtrace); + if (found) { + break; + } + + if (child.$base) { + const baseQName = splitQName(child.$base); + const childNameSpace = baseQName.prefix === TNS_PREFIX ? '' : baseQName.prefix; + childNsURI = child.xmlns[baseQName.prefix] || child.schemaXmlns[baseQName.prefix]; + + const foundBase = this.findSchemaType(baseQName.name, childNsURI); + + if (foundBase) { + found = this.findChildSchemaObject(foundBase, childName, backtrace); + + if (found) { + found.$baseNameSpace = childNameSpace; + break; + } + } + } + } + } + + if (!found && object.$name === childName) { + return object; + } + + return found; + } + + private _initializeOptions(options: any) { + this._originalIgnoredNamespaces = (options || {}).ignoredNamespaces; + this.options = {}; + + const ignoredNamespaces = options ? options.ignoredNamespaces : null; + + if (ignoredNamespaces && (Array.isArray(ignoredNamespaces.namespaces) || typeof ignoredNamespaces.namespaces === 'string')) { + if (ignoredNamespaces.override) { + this.options.ignoredNamespaces = ignoredNamespaces.namespaces; + } else { + this.options.ignoredNamespaces = this.ignoredNamespaces.concat(ignoredNamespaces.namespaces); + } + } else { + this.options.ignoredNamespaces = this.ignoredNamespaces; + } + + this.options.valueKey = options.valueKey || this.valueKey; + this.options.xmlKey = options.xmlKey || this.xmlKey; + if (options.escapeXML !== undefined) { + this.options.escapeXML = options.escapeXML; + } else { + this.options.escapeXML = true; + } + if (options.returnFault !== undefined) { + this.options.returnFault = options.returnFault; + } else { + this.options.returnFault = false; + } + this.options.handleNilAsNull = !!options.handleNilAsNull; + + if (options.namespaceArrayElements !== undefined) { + this.options.namespaceArrayElements = options.namespaceArrayElements; + } else { + this.options.namespaceArrayElements = true; + } + + // Allow any request headers to keep passing through + this.options.wsdl_headers = options.wsdl_headers; + this.options.wsdl_options = options.wsdl_options; + if (options.httpClient) { + this.options.httpClient = options.httpClient; + } + + // The supplied request-object should be passed through + if (options.request) { + this.options.request = options.request; + } + + const ignoreBaseNameSpaces = options ? options.ignoreBaseNameSpaces : null; + if (ignoreBaseNameSpaces !== null && typeof ignoreBaseNameSpaces !== 'undefined') { + this.options.ignoreBaseNameSpaces = ignoreBaseNameSpaces; + } else { + this.options.ignoreBaseNameSpaces = this.ignoreBaseNameSpaces; + } + + // Works only in client + this.options.forceSoap12Headers = options.forceSoap12Headers; + this.options.customDeserializer = options.customDeserializer; + this.options.forceUseSchemaXmlns = options.forceUseSchemaXmlns; + + if (options.overrideElementKey !== undefined) { + this.options.overrideElementKey = options.overrideElementKey; + } + if (options.overrideRootElement !== undefined) { + this.options.overrideRootElement = options.overrideRootElement; + } + + this.options.useEmptyTag = !!options.useEmptyTag; + } + + private _processNextInclude(includes: elements.IInclude[], callback) { + const include = includes.shift(); + + if (!include) { + return callback(); + } + + let includePath: string; + if (!/^https?:/i.test(this.uri) && !/^https?:/i.test(include.location)) { + const isFixed = this.options.wsdl_options !== undefined && Object.prototype.hasOwnProperty.call(this.options.wsdl_options, 'fixedPath') ? this.options.wsdl_options.fixedPath : false; + if (isFixed) { + includePath = path.resolve(path.dirname(this.uri), path.parse(include.location).base); + } else { + includePath = path.resolve(path.dirname(this.uri), include.location); + } + } else { + includePath = url.resolve(this.uri || '', include.location); + } + + const options = Object.assign({}, this.options); + // follow supplied ignoredNamespaces option + options.ignoredNamespaces = this._originalIgnoredNamespaces || this.options.ignoredNamespaces; + options.WSDL_CACHE = this.WSDL_CACHE; + + if (this.options.wsdl_options !== undefined && typeof this.options.wsdl_options.overrideImportLocation === 'function') { + try { + includePath = this.options.wsdl_options.overrideImportLocation(includePath, this.uri, include.location, options); + } catch (e) { + return callback(e); + } + } + + open_wsdl_recursive(includePath, options, (err, wsdl) => { + if (err) { + return callback(err); + } + + this._includesWsdl.push(wsdl); + + if (wsdl.definitions instanceof elements.DefinitionsElement) { + _.mergeWith(this.definitions, wsdl.definitions, (a, b) => { + return a instanceof elements.SchemaElement ? a.merge(b) : undefined; + }); + } else { + return callback(new Error('wsdl.defintions is not an instance of elements.DefinitionsElement')); + } + + this._processNextInclude(includes, (err) => { + callback(err); + }); + }); + } + + private _parse(xml): elements.DefinitionsElement { + const p = sax.parser(true, null); + const stack: elements.Element[] = []; + let root: elements.DefinitionsElement = null; + let types: elements.TypesElement = null; + let schema: elements.SchemaElement = null; + let schemaAttrs = null; + const options = this.options; + + p.onopentag = (node) => { + const nsName = node.name; + const attrs = node.attributes; + + const top = stack[stack.length - 1]; + const name = splitQName(nsName).name; + + if (name === 'schema') { + schemaAttrs = attrs; + } + if (top) { + try { + top.startElement(stack, nsName, attrs, options, schemaAttrs); + } catch (e) { + if (this.options.strict) { + throw e; + } else { + stack.push(new elements.Element(nsName, attrs, options, schemaAttrs)); + } + } + } else { + if (name === 'definitions') { + root = new elements.DefinitionsElement(nsName, attrs, options); + stack.push(root); + } else if (name === 'schema') { + // Shim a structure in here to allow the proper objects to be created when merging back. + root = new elements.DefinitionsElement('definitions', {}, {}); + types = new elements.TypesElement('types', {}, {}); + schema = new elements.SchemaElement(nsName, attrs, options); + types.addChild(schema); + root.addChild(types); + stack.push(schema); + } else if (name === 'html') { + throw new Error(`Root element of WSDL was . This is likely an authentication issue.`); + } else { + throw new Error('Unexpected root element of WSDL or include'); + } + } + }; + + p.onclosetag = (name) => { + const top = stack[stack.length - 1]; + assert(top, 'Unmatched close tag: ' + name); + + top.endElement(stack, name); + }; + + p.write(xml).close(); + + return root; + } + + private _fromXML(xml: string): void { + this.definitions = this._parse(xml); + this.definitions.descriptions = { + types: {}, + elements: {}, + }; + this.xml = xml; + } + + //eslint-disable-next-line @typescript-eslint/no-unused-vars + private _fromServices(services): void {} + + private _xmlnsMap(): string { + const xmlns = this.definitions.xmlns; + let str = ''; + for (const alias in xmlns) { + if (alias === '' || alias === TNS_PREFIX) { + continue; + } + const ns = xmlns[alias]; + switch (ns) { + case 'http://xml.apache.org/xml-soap': // apachesoap + case 'http://schemas.xmlsoap.org/wsdl/': // wsdl + case 'http://schemas.xmlsoap.org/wsdl/soap/': // wsdlsoap + case 'http://schemas.xmlsoap.org/wsdl/soap12/': // wsdlsoap12 + case 'http://schemas.xmlsoap.org/soap/encoding/': // soapenc + case 'http://www.w3.org/2001/XMLSchema': // xsd + continue; + } + if (~ns.indexOf('http://schemas.xmlsoap.org/')) { + continue; + } + if (~ns.indexOf('http://www.w3.org/')) { + continue; + } + if (~ns.indexOf('http://xml.apache.org/')) { + continue; + } + str += ' xmlns:' + alias + '="' + ns + '"'; + } + return str; + } +} + +type WSDLCallback = (error: any, result?: WSDL) => any; + +/* + * Have another function to load previous WSDLs as we + * don't want this to be invoked externally (expect for tests) + * This will attempt to fix circular dependencies with XSD files, + * Given + * - file.wsdl + * - xs:import namespace="A" schemaLocation: A.xsd + * - A.xsd + * - xs:import namespace="B" schemaLocation: B.xsd + * - B.xsd + * - xs:import namespace="A" schemaLocation: A.xsd + * file.wsdl will start loading, import A, then A will import B, which will then import A + * Because A has already started to load previously it will be returned right away and + * have an internal circular reference + * B would then complete loading, then A, then file.wsdl + * By the time file A starts processing its includes its definitions will be already loaded, + * this is the only thing that B will depend on when "opening" A + */ +function open_wsdl_recursive(uri: any, callback: WSDLCallback); +function open_wsdl_recursive(uri: any, options: IOptions, callback: WSDLCallback); +function open_wsdl_recursive(uri: any, p2: WSDLCallback | IOptions, p3?: WSDLCallback) { + let options: IOptions; + let callback: WSDLCallback; + + if (typeof p2 === 'function') { + options = {}; + callback = p2; + } else { + options = p2; + callback = p3; + } + + const fromCache = options.WSDL_CACHE[uri]; + + if (fromCache) { + return callback.call(fromCache, null, fromCache); + } + + return open_wsdl(uri, options, callback); +} + +export function open_wsdl(uri: any, callback: WSDLCallback); +export function open_wsdl(uri: any, options: IOptions, callback: WSDLCallback); +export function open_wsdl(uri: any, p2: WSDLCallback | IOptions, p3?: WSDLCallback) { + let options: IOptions; + let callback: WSDLCallback; + if (typeof p2 === 'function') { + options = {}; + callback = p2; + } else if (typeof p3 === 'function') { + options = p2; + callback = p3; + } + + // initialize cache when calling open_wsdl directly + const WSDL_CACHE = options.WSDL_CACHE || {}; + const request_headers = options.wsdl_headers; + const request_options = options.wsdl_options; + + let wsdl: WSDL; + if (/^<\?xml[^>]*?>/i.test(uri)) { + wsdl = new WSDL(uri, uri, options); + WSDL_CACHE[uri] = wsdl; + wsdl.WSDL_CACHE = WSDL_CACHE; + wsdl.onReady(callback); + } else if (!/^https?:/i.test(uri)) { + debug('Reading file: %s', uri); + fs.readFile(uri, 'utf8', (err, definition) => { + if (err) { + callback(err); + } else { + wsdl = new WSDL(definition, uri, options); + WSDL_CACHE[uri] = wsdl; + wsdl.WSDL_CACHE = WSDL_CACHE; + wsdl.onReady(callback); + } + }); + } else { + debug('Reading url: %s', uri); + const httpClient = options.httpClient || new HttpClient(options); + httpClient.request( + uri, + null /* options */, + (err, response, definition) => { + if (err) { + callback(err); + } else if (response && response.status === 200) { + wsdl = new WSDL(definition, uri, options); + WSDL_CACHE[uri] = wsdl; + wsdl.WSDL_CACHE = WSDL_CACHE; + wsdl.onReady(callback); + } else { + callback(new Error('Invalid WSDL URL: ' + uri + '\n\n\r Code: ' + response.status + '\n\n\r Response Body: ' + response.data)); + } + }, + request_headers, + request_options, + ); + } + + return wsdl; +} diff --git a/test/_socketStream.js b/test/_socketStream.js new file mode 100644 index 000000000..802c6a53e --- /dev/null +++ b/test/_socketStream.js @@ -0,0 +1,50 @@ +'use strict'; + +var fs = require('fs'), + duplexer = require('duplexer'), + semver = require('semver'), + should = require('should'), + // stream = require('stream'), + stream = require('readable-stream'); + +module.exports = function createSocketStream(file, length) { + //Create a duplex stream + + var httpReqStream = new stream.PassThrough(); + var httpResStream = new stream.PassThrough(); + var socketStream = duplexer(httpReqStream, httpResStream); + + // Node 4.x requires cork/uncork + socketStream.cork = function () {}; + + socketStream.uncork = function () {}; + + socketStream.destroy = function () {}; + + // axios calls this + socketStream.setKeepAlive = function () {}; + + socketStream.req = httpReqStream; + socketStream.res = httpResStream; + + var wsdl = fs.readFileSync(file).toString('utf8'); + //Should be able to read from stream the request + socketStream.req.once('readable', function readRequest() { + var chunk = socketStream.req.read(); + should.exist(chunk); + + var header = 'HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\nContent-Length: ' + (!length ? wsdl.length : length) + '\r\n\r\n'; + + //This is for compatibility with old node releases <= 0.10 + //Hackish + if (semver.lt(process.version, '0.11.0')) { + socketStream.on('data', function (data) { + socketStream.ondata(data, 0, length + header.length); + }); + } + //Now write the response with the wsdl + var state = socketStream.res.write(header + wsdl); + }); + + return socketStream; +}; diff --git a/test/certs/agent2-cert.pem b/test/certs/agent2-cert.pem index 8e4354db4..845ed7e05 100644 --- a/test/certs/agent2-cert.pem +++ b/test/certs/agent2-cert.pem @@ -1,13 +1,24 @@ -----BEGIN CERTIFICATE----- -MIIB7DCCAZYCCQC7gs0MDNn6MTANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJV -UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO -BgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEgMB4GCSqGSIb3DQEJARYR -cnlAdGlueWNsb3Vkcy5vcmcwHhcNMTEwMzE0MTgyOTEyWhcNMzgwNzI5MTgyOTEy -WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYD -VQQKEwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEg -MB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwXDANBgkqhkiG9w0BAQEF -AANLADBIAkEAyXb8FrRdKbhrKLgLSsn61i1C7w7fVVVd7OQsmV/7p9WB2lWFiDlC -WKGU9SiIz/A6wNZDUAuc2E+VwtpCT561AQIDAQABMA0GCSqGSIb3DQEBBQUAA0EA -C8HzpuNhFLCI3A5KkBS5zHAQax6TFUOhbpBCR0aTDbJ6F1liDTK1lmU/BjvPoj+9 -1LHwrmh29rK8kBPEjmymCQ== +MIID8zCCAtugAwIBAgIUfaJJaqBa7P+81aiqjFdwled4g3EwDQYJKoZIhvcNAQEL +BQAwgYgxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdBcml6b25hMRIwEAYDVQQHDAlG +bGFnc3RhZmYxDTALBgNVBAoMBEFDTUUxCzAJBgNVBAsMAklUMRIwEAYDVQQDDAlu +b2RlLXNvYXAxIzAhBgkqhkiG9w0BCQEWFHNvYXBtYXN0ZXJzQGFjbWUuY29tMB4X +DTE5MDEyNDE3MDUxMFoXDTIwMDEyNDE3MDUxMFowgYgxCzAJBgNVBAYTAlVTMRAw +DgYDVQQIDAdBcml6b25hMRIwEAYDVQQHDAlGbGFnc3RhZmYxDTALBgNVBAoMBEFD +TUUxCzAJBgNVBAsMAklUMRIwEAYDVQQDDAlub2RlLXNvYXAxIzAhBgkqhkiG9w0B +CQEWFHNvYXBtYXN0ZXJzQGFjbWUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA1AmnP/IPSpocMHYJQ5FE1an5eQmfkg+4QyaKq6ECXCv4VhK5N2aD +71OL7IKKnW5qqxzXGAGy1vQjCGyUGmPa4/LnXBvM67ED5irFy00djXqc/pNn7FCA +Cxgrg9+6bIWlItSkVkGn/D4VPGiA8xTC05FxJkUXp8be/hYs9EQ0+9WqZ7ZM6W5S +MFYNW0CE9G9dQK9b0NrS9Rx7wrNTzwMZp9u1PdY4HtYsS5WHVMOOGXN+ds4v3dP8 +Ym6sW1rbe2LeYfTB7dM8aZyS4Zn38vpCiMzrqO1/govPgz/6Bw4DhW0FoXLtDgx0 +giTGEy5GBqZf6+U6z5ZCosKKdD8KZoxrNwIDAQABo1MwUTAdBgNVHQ4EFgQUxbsT +aT+279hFiJmplXfBwAfUGy0wHwYDVR0jBBgwFoAUxbsTaT+279hFiJmplXfBwAfU +Gy0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAO04vm1mWY1Ia +gQ+fxH8HGxE8OOwxSVTmmkNz+DZVXG4/8wwMJxCEoLY2CvJH5o/ZdeZPTd9MhmMx +TwBNHAM9vmj3AmbD65EukMV76RIATBzavEb6NzTLugar2xco3MMHR945kLJmk1uE +yusCJXgxzK0lzk6oGp2OAtlRUT7DvR3AkMvEYia3AHSY1M0Dtsf3r7DsoFIpWvVj +9+WDeeoxI19ZIuJ6fzFQnEIX4M4hcfmCTtOlICowqpMCg1JIWryBBUr3KizDrq2A +d5I2i8E4WanGz4pDVShd6Y1XTNLR1xv3Is3Jlhusk9UpTbATyMxOVnfj9OgS1/BK +41xRmasgPg== -----END CERTIFICATE----- diff --git a/test/certs/agent2-key-with-password.pem b/test/certs/agent2-key-with-password.pem new file mode 100644 index 000000000..573a3e5dd --- /dev/null +++ b/test/certs/agent2-key-with-password.pem @@ -0,0 +1,12 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBvTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIeCPjj50AYmgCAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCEkXowWEmMgYbOpWWJSoaKBIIB +YKP5Gj6LiydCZmU+leC8obpeaJMKllmtwh48TZzDvA52bBFqPIsahmRRfwDiTOSp +akc8VqxBIb4jYa71fIjKeserYZn+1hxbj3Cr6HcSPQZmCfQCFCDY52JF/44iaZqx +Yioh0XEacW+RZeLFf05sYZu/isoTKpANlbEc3fLds+CwM9lGCOgwOdkzO5CdvnoN +F3sq24CsZOKUT1fhfqAGhkv2zPyzC3lOQ8j8IsI8m1T/qC5/m4cJhu8roDvxTxRS +PhsONSuBUznYOeXnuY+9cTjaKDYLiFsbCCzncgp7xF22hNl5unMvDPk7ZARIPMC5 +0TQDiqbr4FRUPA4TbziRZixuzsMupkUoQe5mS0EmHfNbjOMIllj8BQFIXLIugX3h +eGua84R2u/Yh4SO/S8NkjNEH24Unvl+dn9u7rSaEC1acG41aKR3RYJYW4P02QCmN +QzVvyBz4irCA+6h3fNVXd6Q= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/certs/agent2-key.pem b/test/certs/agent2-key.pem index 522903c63..6ec7c0b3e 100644 --- a/test/certs/agent2-key.pem +++ b/test/certs/agent2-key.pem @@ -1,9 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOgIBAAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf+6fVgdpVhYg5 -QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAQJBAMT6Bf34+UHKY1ObpsbH -9u2jsVblFq1rWvs8GPMY6oertzvwm3DpuSUp7PTgOB1nLTLYtCERbQ4ovtN8tn3p -OHUCIQDzIEGsoCr5vlxXvy2zJwu+fxYuhTZWMVuo1397L0VyhwIhANQh+yzqUgaf -WRtSB4T2W7ADtJI35ET61jKBty3CqJY3AiAIwju7dVW3A5WeD6Qc1SZGKZvp9yCb -AFI2BfVwwaY11wIgXF3PeGcvACMyMWsuSv7aPXHfliswAbkWuzcwA4TW01ECIGWa -cgsDvVFxmfM5NPSuT/UDTa6R5BFISB5ea0N0AR3I ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDUCac/8g9Kmhww +dglDkUTVqfl5CZ+SD7hDJoqroQJcK/hWErk3ZoPvU4vsgoqdbmqrHNcYAbLW9CMI +bJQaY9rj8udcG8zrsQPmKsXLTR2Nepz+k2fsUIALGCuD37pshaUi1KRWQaf8PhU8 +aIDzFMLTkXEmRRenxt7+Fiz0RDT71apntkzpblIwVg1bQIT0b11Ar1vQ2tL1HHvC +s1PPAxmn27U91jge1ixLlYdUw44Zc352zi/d0/xibqxbWtt7Yt5h9MHt0zxpnJLh +mffy+kKIzOuo7X+Ci8+DP/oHDgOFbQWhcu0ODHSCJMYTLkYGpl/r5TrPlkKiwop0 +PwpmjGs3AgMBAAECggEAPYl/rKNHpNMNE1NuZNmoLIpkCKiuUumVBIgO/rh/wthP +/kr4zgdGixKoLT/FkuMUugxosGLt0EySTkOUyAPq5vT8CFNZKZ36D7aiKNp8lS7c +mVWWd5L1VkLxfhhUNmKjBnTILPBpHF+4MgvyQJnp4RT4za6Hqv2gggVVjp6s8dkN +SA7N4QXEjoZM7bGQLxvW2qrj+qy0xbXoTwzZxSD2wrc0qduSPoqu+Q7xATKRYo9i +22ka+kv7hkWuuvxIIY96M2lsI5gfP0jxRiO9zeoP9EV4qBYLCyk0q9lT42rNuSC3 +hvuc+uI+pJtWwm6oLRyM4xGmmpLjsGUK5GbjP1HDQQKBgQD5u60JNIa6DLzOWxO6 +PdAflkVSmzTaTzKmG9/Iq8Qe+eInuNfSG6RJqdVzsx8hBzqO6NVhH4WCjPYEqXoa +W1F2bwqKXhGI0UE1xBK8AmIkRd+2K3kU7at6BkZZwa+S7+jsG9qGgyvFuvloa2Jc +NU2HCcorgPo0XsRedvnJK8FvPwKBgQDZW9D6RhxVl12nm636WdvWDCkgH56MkATj +UEr/xzMwrvilWv80ZjDJwxqoi66e2zCEmDOe1ebQKOdwt5kbmi2RCtL3DMPe45Ds +0k2FPrcMyVdPsDANv57QtZX5r5voUiG6jjiRvahLMWtHuDK1fYLr8nA1h3FHINOm +PHPUVuH+CQKBgFpHqopFXt8rc6X17u/JINAKdw0h5r11HA5IzWGyFrhMBaHuhLcE +HyQyLWQiQQKjplu7eEggKRfE9btBuU6F7LEv+1OCJjybyUMymsM06V3LlNA6bw9N +zEvUsOIJzvsDl+SjPSCbkttseHVzPJ+w9VH4DAomGk2MZNjxkeNT2h3pAoGBAKv2 +GRI4L6iDlWPKJc2AFA13F35DpcMdGdDhMETFyzkD5NGleWxyQL0PL2MTB3bEgNEW +PRi3r+EVy20AxA/zXYN3pcowfjIzpe/Gve/h2x4xmHMCODJYXIRQdTPR/C3D9M1M +QXMEMkYy9eYK04uEnfSfnKis3DDixq+o+haPGkJJAoGBAO2l0ZhGMaP7ikwGd2A3 +OazQtwwQ/lGOLxm1hpccCt10NZPLMDAr3pqHViXXufFKl1KpPFOk6rNasetINhV+ +4/Ckip0tiWxxcRINekP0svgnn4Gw50/kvwJyJOx1i24FUXE2KKhNDHGmK/4GkH75 +q8zJ5bfrmMHyDgwxGp0kXI/3 +-----END PRIVATE KEY----- diff --git a/test/client-customHttp-test.js b/test/client-customHttp-test.js index d00233f4b..a04b4af02 100644 --- a/test/client-customHttp-test.js +++ b/test/client-customHttp-test.js @@ -1,23 +1,19 @@ 'use strict'; var fs = require('fs'), - soap = require('..'), - http = require('http'), - assert = require('assert'), + soap = require('..'), + assert = require('assert'), duplexer = require('duplexer'), - req = require('request'), - httpClient = require('../lib/http.js'), - // stream = require('stream'), + httpClient = require('../lib/http.js').HttpClient, stream = require('readable-stream'), util = require('util'), events = require('events'), semver = require('semver'), should = require('should'); -it('should allow customization of httpClient and the wsdl file download should pass through it', function(done) { - -//Make a custom http agent to use streams instead on net socket - function CustomAgent(options, socket){ +it('should allow customization of httpClient and the wsdl file download should pass through it', function (done) { + //Make a custom http agent to use streams instead on net socket + function CustomAgent(options, socket) { var self = this; events.EventEmitter.call(this); self.requests = []; @@ -26,92 +22,92 @@ it('should allow customization of httpClient and the wsdl file download should p self.options = options || {}; self.proxyOptions = {}; } - + util.inherits(CustomAgent, events.EventEmitter); - - CustomAgent.prototype.addRequest = function(req, options) { + + CustomAgent.prototype.addRequest = function (req, options) { req.onSocket(this.proxyStream); }; - //Create a duplex stream - + //Create a duplex stream + var httpReqStream = new stream.PassThrough(); var httpResStream = new stream.PassThrough(); var socketStream = duplexer(httpReqStream, httpResStream); // Node 4.x requires cork/uncork - socketStream.cork = function() { - }; + socketStream.cork = function () {}; - socketStream.uncork = function() { - }; + socketStream.uncork = function () {}; - //Custom httpClient - function MyHttpClient (options, socket){ - httpClient.call(this,options); - this.agent = new CustomAgent(options, socket); + socketStream.destroy = function () {}; + + // axios calls this + socketStream.setKeepAlive = function () {}; + + //Custom httpClient + class MyHttpClient extends httpClient { + constructor(options, socket) { + super(options); + this.agent = new CustomAgent(options, socket); + } } - - util.inherits(MyHttpClient, httpClient); - - MyHttpClient.prototype.request = function(rurl, data, callback, exheaders, exoptions) { + + MyHttpClient.prototype.request = function (rurl, data, callback, exheaders, exoptions) { var self = this; var options = self.buildRequest(rurl, data, exheaders, exoptions); //Specify agent to use - options.agent = this.agent; + options.httpAgent = this.agent; var headers = options.headers; - var req = self._request(options, function(err, res, body) { - if (err) { + var req = self._request(options).then( + function (res) { + res.data = self.handleResponse(req, res, res.data); + callback(null, res, res.data); + if (headers.Connection !== 'keep-alive') { + res.request.end(data); + } + }, + (err) => { return callback(err); - } - body = self.handleResponse(req, res, body); - callback(null, res, body); - }); - if (headers.Connection !== 'keep-alive') { - req.end(data); - } + }, + ); return req; }; - + var wsdl = fs.readFileSync('./test/wsdl/default_namespace.wsdl').toString('utf8'); - //Should be able to read from stream the request + //Should be able to read from stream the request httpReqStream.once('readable', function readRequest() { var chunk = httpReqStream.read(); should.exist(chunk); - + //This is for compatibility with old node releases <= 0.10 //Hackish - if(semver.lt(process.version, '0.11.0')) - { - socketStream.on('data', function(data) { - socketStream.ondata(data,0,1984); + if (semver.lt(process.version, '0.11.0')) { + socketStream.on('data', function (data) { + socketStream.ondata(data, 0, 1984); }); } //Now write the response with the wsdl - var state = httpResStream.write('HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\nContent-Length: 1904\r\n\r\n'+wsdl); + var state = httpResStream.write('HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\nContent-Length: ' + wsdl.length + '\r\n\r\n' + wsdl); }); var httpCustomClient = new MyHttpClient({}, socketStream); var url = 'http://localhost:50000/Platform.asmx?wsdl'; - soap.createClient(url, - {httpClient: httpCustomClient}, - function(err, client) { - assert.ok(client); - assert.ok(!err); - assert.equal(client.httpClient, httpCustomClient); - var description = (client.describe()); - assert.deepEqual(client.describe(), { - MyService: { - MyServicePort: { - MyOperation: { - input: { - }, - output: { - } - } - } - } - }); - done(); + soap.createClient(url, { httpClient: httpCustomClient }, function (err, client) { + assert.ok(client); + assert.ifError(err); + assert.equal(client.httpClient, httpCustomClient); + var description = client.describe(); + assert.deepEqual(client.describe(), { + MyService: { + MyServicePort: { + MyOperation: { + input: {}, + output: {}, + }, + }, + }, }); + done(); + }); }); diff --git a/test/client-customHttp-xsdinclude-test.js b/test/client-customHttp-xsdinclude-test.js new file mode 100644 index 000000000..00bb63b3a --- /dev/null +++ b/test/client-customHttp-xsdinclude-test.js @@ -0,0 +1,86 @@ +'use strict'; + +var soap = require('..'), + assert = require('assert'), + httpClient = require('../lib/http.js').HttpClient, + util = require('util'), + events = require('events'), + createSocketStream = require('./_socketStream'); + +it('should allow customization of httpClient, the wsdl file, and associated data download should pass through it', function (done) { + //Make a custom http agent to use streams instead of a real net socket + function CustomAgent(options, wsdl, xsd) { + var self = this; + events.EventEmitter.call(this); + self.requests = []; + self.maxSockets = 1; + self.wsdlStream = wsdl; + self.xsdStream = xsd; + self.options = options || {}; + self.proxyOptions = {}; + } + + util.inherits(CustomAgent, events.EventEmitter); + + CustomAgent.prototype.addRequest = function (req, options) { + if (/\?xsd$/.test(req.path)) { + req.onSocket(this.xsdStream); + } else { + req.onSocket(this.wsdlStream); + } + }; + + //Custom httpClient + class MyHttpClient extends httpClient { + constructor(options, wsdlSocket, xsdSocket) { + super(options); + this.agent = new CustomAgent(options, wsdlSocket, xsdSocket); + } + } + + MyHttpClient.prototype.request = function (rurl, data, callback, exheaders, exoptions) { + var self = this; + var options = self.buildRequest(rurl, data, exheaders, exoptions); + //Specify agent to use + options.httpAgent = this.agent; + var headers = options.headers; + var req = self._request(options).then( + function (res) { + res.data = self.handleResponse(req, res, res.data); + callback(null, res, res.data); + if (headers.Connection !== 'keep-alive') { + res.request.end(data); + } + }, + (err) => { + return callback(err); + }, + ); + return req; + }; + + var httpCustomClient = new MyHttpClient({}, createSocketStream(__dirname + '/wsdl/xsdinclude/xsd_include_http.wsdl'), createSocketStream(__dirname + '/wsdl/xsdinclude/types.xsd')); + var url = 'http://localhost:50000/Dummy.asmx?wsdl'; + soap.createClient(url, { httpClient: httpCustomClient }, function (err, client) { + assert.ok(client); + assert.ifError(err); + assert.equal(client.httpClient, httpCustomClient); + var description = client.describe(); + assert.deepEqual(client.describe(), { + DummyService: { + DummyPortType: { + Dummy: { + input: { + ID: 'IdType|xs:string|pattern', + Name: 'NameType|xs:string|minLength,maxLength', + }, + output: { + Result: 'dummy:DummyList', + }, + }, + }, + }, + }); + done(); + }); +}); diff --git a/test/client-options-fixpath-test.js b/test/client-options-fixpath-test.js new file mode 100644 index 000000000..722d39310 --- /dev/null +++ b/test/client-options-fixpath-test.js @@ -0,0 +1,24 @@ +'use strict'; + +var soap = require('..'), + assert = require('assert'); + +describe('SOAP Client', function () { + var options = { + attributesKey: '$attributes', + namespaceArrayElements: false, + wsdl_options: { + fixedPath: true, + }, + }; + + it('should ignore relative paths from wsdl imports and use a single fixed directory', function (done) { + soap.createClient(__dirname + '/wsdl/fixedPath/netsuite.wsdl', options, function (err, client) { + assert.ok(client); + assert.ifError(err); + + assert.ok(client.wsdl.options.wsdl_options.fixedPath === true); + done(); + }); + }); +}); diff --git a/test/client-options-test.js b/test/client-options-test.js new file mode 100644 index 000000000..50e7c9793 --- /dev/null +++ b/test/client-options-test.js @@ -0,0 +1,33 @@ +'use strict'; + +var soap = require('..'), + assert = require('assert'); + +describe('SOAP Client', function () { + var options = { + ignoredNamespaces: { + namespaces: ['ignoreThisNS'], + override: true, + }, + overrideRootElement: { + namespace: 'tns', + }, + overridePromiseSuffix: 'Test', + request: 'customRequest', + namespaceArrayElements: true, + }; + + it('should set WSDL options to those specified in createClient', function (done) { + soap.createClient(__dirname + '/wsdl/json_response.wsdl', options, function (err, client) { + assert.ok(client); + assert.ifError(err); + + assert.ok(client.wsdl.options.ignoredNamespaces[0] === 'ignoreThisNS'); + assert.ok(client.wsdl.options.overrideRootElement.namespace === 'tns'); + assert.ok(typeof client.MyOperationTest === 'function'); + assert.ok(client.wsdl.options.request, 'customRequest'); + assert.ok(client.wsdl.options.namespaceArrayElements === true); + done(); + }); + }); +}); diff --git a/test/client-options-wsdlcache-test.js b/test/client-options-wsdlcache-test.js new file mode 100644 index 000000000..66d410a8b --- /dev/null +++ b/test/client-options-wsdlcache-test.js @@ -0,0 +1,86 @@ +'use strict'; +var soap = require('..'), + assert = require('assert'), + sinon = require('sinon'), + utils = require('../lib/utils'), + wsdl = require('../lib/wsdl'); +describe('SOAP Client - WSDL Cache', function () { + var sandbox = sinon.createSandbox(); + var wsdlUri = __dirname + '/wsdl/Dummy.wsdl'; + beforeEach(function () { + sandbox.spy(wsdl, 'open_wsdl'); + }); + afterEach(function () { + sandbox.restore(); + }); + + it('should use default cache if not provided', function (done) { + // ensure cache is empty to prevent impacts to this case + // if other test already loaded this WSDL + utils.wsdlCacheSingleton.clear(); + + // cache miss + soap.createClient(wsdlUri, {}, function (err, clientFirstCall) { + if (err) return done(err); + assert.strictEqual(wsdl.open_wsdl.callCount, 1); + + // hits cache + soap.createClient(wsdlUri, {}, function (err, clientSecondCall) { + if (err) return done(err); + assert.strictEqual(wsdl.open_wsdl.callCount, 1); + + // disabled cache + soap.createClient(wsdlUri, { disableCache: true }, function (err, clientSecondCall) { + if (err) return done(err); + assert.strictEqual(wsdl.open_wsdl.callCount, 2); + done(); + }); + }); + }); + }); + + it('should use the provided WSDL cache', function (done) { + /** @type {IWSDLCache} */ + var dummyCache = { + has: function () {}, + get: function () {}, + set: function () {}, + }; + sandbox.stub(dummyCache, 'has'); + sandbox.stub(dummyCache, 'get'); + sandbox.stub(dummyCache, 'set'); + dummyCache.has.returns(false); + var options = { + wsdlCache: dummyCache, + }; + soap.createClient(wsdlUri, options, function (err, clientFirstCall) { + assert.strictEqual(dummyCache.has.callCount, 1); + assert.strictEqual(dummyCache.get.callCount, 0); + assert.strictEqual(dummyCache.set.callCount, 1); + // cache miss + assert.strictEqual(wsdl.open_wsdl.callCount, 1); + + var cacheEntry = dummyCache.set.firstCall.args; + assert.deepStrictEqual(cacheEntry[0], wsdlUri); + + var cachedWSDL = cacheEntry[1]; + assert.ok(cachedWSDL instanceof wsdl.WSDL); + assert.deepStrictEqual(clientFirstCall.wsdl, cachedWSDL); + + sandbox.reset(); + dummyCache.has.returns(true); + dummyCache.get.returns(cachedWSDL); + + soap.createClient(wsdlUri, options, function (err, clientSecondCall) { + // hits cache + assert.strictEqual(wsdl.open_wsdl.callCount, 0); + assert.strictEqual(dummyCache.has.callCount, 1); + assert.strictEqual(dummyCache.get.callCount, 1); + assert.deepStrictEqual(dummyCache.get.firstCall.args, [wsdlUri]); + assert.strictEqual(dummyCache.set.callCount, 0); + assert.deepStrictEqual(clientSecondCall.wsdl, cachedWSDL); + done(); + }); + }); + }); +}); diff --git a/test/client-response-options-test.js b/test/client-response-options-test.js new file mode 100644 index 000000000..3f93d750e --- /dev/null +++ b/test/client-response-options-test.js @@ -0,0 +1,66 @@ +'use strict'; + +const fs = require('fs'), + soap = require('../lib/soap'), + http = require('http'), + assert = require('assert'); + +let server; +const servicePath = '/SayHello'; +let url; +const wsdl = fs.readFileSync(__dirname + '/wsdl/hello.wsdl', 'utf-8'); +const serviceImplementation = { + Hello_Service: { + Hello_Port: { + sayHello: function (args) { + return { + greeting: args.firstName, + }; + }, + }, + }, +}; + +describe('SOAP Client', function () { + before(function (done) { + // start test soap server (hello.wsdl) + server = http.createServer(function (request, response) { + response.end('404: Not Found: ' + request.url); + }); + console.log('test server is created'); + + server.listen(54454, function () { + soap.listen(server, servicePath, serviceImplementation, wsdl); + url = 'http://' + server.address().address + ':' + server.address().port; + if (server.address().address === '0.0.0.0' || server.address().address === '::') { + url = 'http://127.0.0.1:' + server.address().port; + } + console.log('test server is listening in', url); + done(); + }); + }); + + after(function () { + server.close(); + console.log('server is closed'); + }); + + it('lastElapsedTime is computed', function (done) { + soap.createClientAsync(__dirname + '/wsdl/hello.wsdl', { endpoint: `${url}${servicePath}` }).then(function (client) { + try { + assert.ok(client); + console.log('client created:', client.describe()); + client.sayHelloAsync({ firstName: 'LastElapsedTime Tester' }, { time: true }).then(() => { + assert.ok(Object.prototype.hasOwnProperty.call(client, 'lastElapsedTime')); + assert.ok(typeof client.lastElapsedTime === 'number'); + console.log('api finished in ms:', client.lastElapsedTime); + assert.ok(client.lastElapsedTime > 0); + }); + } catch (err) { + done(err); + throw err; + } + done(); + }); + }); +}); diff --git a/test/client-schema-does-not-change-on-request-test.js b/test/client-schema-does-not-change-on-request-test.js new file mode 100644 index 000000000..56c7152d4 --- /dev/null +++ b/test/client-schema-does-not-change-on-request-test.js @@ -0,0 +1,133 @@ +const fs = require('fs'); +const soap = require('../'); +const path = require('path'); +var http = require('http'); +var jsdiff = require('diff'); +var assert = require('assert'); + +let server; +let port; + +function normalizeWhiteSpace(raw) { + var normalized = raw.replace(/\r\n|\r|\n/g, ''); // strip line endings + normalized = normalized.replace(/\s\s+/g, ' '); // convert whitespace to spaces + normalized = normalized.replace(/> <'); // get rid of spaces between elements + return normalized; +} + +var requestContext = { + //set these two within each test + expectedRequest: null, + responseToSend: null, + doneHandler: null, + requestHandler: function (req, res) { + var chunks = []; + req.on('data', function (chunk) { + // ignore eol on sample files. + chunks.push(chunk.toString().replace(/\r?\n$/m, '')); + }); + req.on('end', function () { + if (!requestContext.expectedRequest) return res.end(requestContext.responseToSend); + + var actualRequest = normalizeWhiteSpace(chunks.join('')); + var expectedRequest = normalizeWhiteSpace(requestContext.expectedRequest); + + if (actualRequest !== expectedRequest) { + var diff = jsdiff.diffChars(actualRequest, expectedRequest); + var comparison = ''; + diff.forEach(function (part) { + var color = 'grey'; + if (part.added) { + color = 'green'; + } + if (part.removed) { + color = 'red'; + } + comparison += part.value[color]; + }); + console.log(comparison); + } + + assert.equal(actualRequest, expectedRequest); + + if (!requestContext.responseToSend) return requestContext.doneHandler(); + if (requestContext.responseHttpHeaders) { + for (const headerKey in requestContext.responseHttpHeaders) { + res.setHeader(headerKey, requestContext.responseHttpHeaders[headerKey]); + } + } + res.end(requestContext.responseToSend); + + requestContext.expectedRequest = null; + requestContext.responseToSend = null; + }); + }, +}; + +describe('SOAP Client schema does not change', () => { + before(function (done) { + server = http.createServer(requestContext.requestHandler); + server.listen(0, function (e) { + if (e) return done(e); + port = server.address().port; + done(); + }); + }); + it('should not change the schema', (done) => { + const tpath = path.join(__dirname, 'request-response-samples', 'RetrieveFareQuoteDateRange__should_handle_child_namespaces'); + const wsdlPath = path.resolve(tpath, 'soap.wsdl'); + const requestJSON = require(path.resolve(tpath, 'request.json')); + const requestXML = fs.readFileSync(path.resolve(tpath, 'request.xml'), { encoding: 'utf8' }); + const responseJSON = require(path.resolve(tpath, 'response.json')); + const responseXML = fs.readFileSync(path.resolve(tpath, 'response.xml'), { encoding: 'utf8' }); + const methodName = 'RetrieveFareQuoteDateRange'; + + requestContext.expectedRequest = requestXML; + requestContext.responseToSend = responseXML; + soap.createClient( + wsdlPath, + { disableCache: true }, + function (err, client) { + if (err) { + throw err; + } + //throw more meaningful error + if (typeof client[methodName] !== 'function') { + throw new Error('method ' + methodName + ' does not exists in wsdl specified in test wsdl: ' + wsdlPath); + } + const typeBefore = client?.wsdl?.definitions?.schemas?.['http://tempuri.org/Service/Request']?.complexTypes?.TransactionInfo?.children?.[0]?.children?.[2]?.$type; + + cbCaller(client, methodName, requestJSON, responseJSON, null, {}, null, done); + + const typeAfter = client?.wsdl?.definitions?.schemas?.['http://tempuri.org/Service/Request']?.complexTypes?.TransactionInfo?.children?.[0]?.children?.[2]?.$type; + assert.equal(typeBefore, typeAfter); + }, + 'http://localhost:' + port + '/Message/Message.dll?Handler=Default', + ); + }); +}); + +function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done) { + client[methodName]( + requestJSON, + function (err, json, body, soapHeader) { + if (requestJSON) { + if (err) { + assert.notEqual('undefined: undefined', err.message); + assert.deepEqual(err.root, responseJSON); + } else { + // assert.deepEqual(json, responseJSON); + assert.deepEqual(json ?? null, responseJSON); + if (responseSoapHeaderJSON) { + assert.deepEqual(soapHeader, responseSoapHeaderJSON); + } + if (client.lastResponseAttachments) { + assert.deepEqual(client.lastResponseAttachments.parts, attachmentParts); + } + } + } + done(); + }, + options, + ); +} diff --git a/test/client-test.js b/test/client-test.js index 61759cf97..82872880c 100644 --- a/test/client-test.js +++ b/test/client-test.js @@ -1,698 +1,2346 @@ 'use strict'; var fs = require('fs'), - soap = require('..'), - http = require('http'), - assert = require('assert'); - -describe('SOAP Client', function() { - it('should error on invalid host', function(done) { - soap.createClient('http://localhost:1', function(err, client) { - assert.ok(err); - done(); + soap = require('..'), + http = require('http'), + stream = require('stream'), + assert = require('assert'), + _ = require('lodash'), + sinon = require('sinon'), + wsdl = require('../lib/wsdl'); + +[ + { suffix: '', options: { useEmptyTag: false } }, + { suffix: ' (with streaming)', options: { stream: true, useEmptyTag: false } }, +].forEach(function (meta) { + describe('SOAP Client' + meta.suffix, function () { + var baseUrl = 'http://127.0.0.1:80'; + + it('should error on invalid host', function (done) { + soap.createClient('http://localhost:1', meta.options, function (err, client) { + assert.ok(err); + done(); + }); }); - }); - it('should add and clear soap headers', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!client.getSoapHeaders()); + it('should detect uppercase schemas as urls', function (done) { + soap.createClient('HTTP://localhost:1', function (err, client) { + assert.ok(err); + // ECONNREFUSED indicates that the WSDL path is being evaluated as a URL + // If instead ENOENT is returned, the WSDL path is being evaluated (incorrectly) + // as a file system path + assert.equal(err.code, 'ECONNREFUSED'); + + done(); + }); + }); - var i1 = client.addSoapHeader('about-to-change-1'); - var i2 = client.addSoapHeader('about-to-change-2'); + it('should add and clear soap headers', function (done) { + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', meta.options, function (err, client) { + assert.ok(client); + assert.ok(!client.getSoapHeaders()); - assert.ok(i1 === 0); - assert.ok(i2 === 1); - assert.ok(client.getSoapHeaders().length === 2); + var i1 = client.addSoapHeader('about-to-change-1'); + var i2 = client.addSoapHeader('about-to-change-2'); - client.changeSoapHeader(0, 'header1'); - client.changeSoapHeader(1, 'header2'); - assert.ok(client.getSoapHeaders()[0] === 'header1'); - assert.ok(client.getSoapHeaders()[1] === 'header2'); + assert.ok(i1 === 0); + assert.ok(i2 === 1); + assert.ok(client.getSoapHeaders().length === 2); - client.clearSoapHeaders(); - assert.ok(!client.getSoapHeaders()); - done(); + client.changeSoapHeader(0, 'header1'); + client.changeSoapHeader(1, 'header2'); + assert.ok(client.getSoapHeaders()[0] === 'header1'); + assert.ok(client.getSoapHeaders()[1] === 'header2'); + + client.clearSoapHeaders(); + assert.ok(!client.getSoapHeaders()); + done(); + }); }); - }); - it('should issue async callback for cached wsdl', function(done) { - var called = false; - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); - called = true; - done(); + it('should issue async callback for cached wsdl', function (done) { + var called = false; + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', meta.options, function (err, client) { + assert.ok(client); + assert.ifError(err); + called = true; + done(); + }); + assert(!called); }); - assert(!called); - }); - it('should allow customization of httpClient', function(done) { - var myHttpClient = { - request: function() {} - }; - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', - {httpClient: myHttpClient}, - function(err, client) { + it('should allow customization of httpClient', function (done) { + var myHttpClient = { + request: function () {}, + }; + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', Object.assign({ httpClient: myHttpClient }, meta.options), function (err, client) { assert.ok(client); - assert.ok(!err); + assert.ifError(err); assert.equal(client.httpClient, myHttpClient); done(); }); - }); + }); - it('should allow customization of request for http client', function(done) { - var myRequest = function() { - }; - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', - {request: myRequest}, - function(err, client) { + it('should allow customization of request for http client', function (done) { + var myRequest = function () {}; + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', Object.assign({ request: myRequest }, meta.options), function (err, client) { assert.ok(client); - assert.ok(!err); + assert.ifError(err); assert.equal(client.httpClient._request, myRequest); done(); }); - }); + }); - it('should allow customization of envelope', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', {envelopeKey: 'soapenv'}, function(err, client) { - assert.ok(client); - assert.ok(!err); + it('should allow customization of client envelope key', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + Object.assign({ envelopeKey: 'soapenv' }, meta.options), + function (err, client) { + assert.ok(client); + assert.ifError(err); - client.MyOperation({}, function(err, result) { - assert.notEqual(client.lastRequest.indexOf('xmlns:soapenv='), -1); - done(); - }); + client.MyOperation({}, function (err, result) { + assert.notEqual(client.lastRequest.indexOf('xmlns:soapenv='), -1); + done(); + }); + }, + baseUrl, + ); }); - }); - it('should set binding style to "document" by default if not explicitly set in WSDL, per SOAP spec', function (done) { - soap.createClient(__dirname+'/wsdl/binding_document.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + it('should skip creating header XML on empty
and security when toXML is empty', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + Object.assign({ envelopeKey: 'soapenv', useEmptyTag: true, wsdl_headers: '' }, meta.options), + function (err, client) { + var join = require('path').join; + var ClientSSLSecurity = require('../').ClientSSLSecurity; + var certBuffer = fs.readFileSync(join(__dirname, '.', 'certs', 'agent2-cert.pem')), + keyBuffer = fs.readFileSync(join(__dirname, '.', 'certs', 'agent2-key.pem')), + instance; + + // Creates a Security instance that has no toXML() (empty string) + instance = new ClientSSLSecurity(keyBuffer, certBuffer, certBuffer); + var xml = instance.toXML(); + xml.should.be.exactly(''); + + client.setSecurity(instance); + client.addSoapHeader(''); + + assert.ok(client); + assert.ifError(err); + + client.MyOperation({}, function (err, result) { + assert.equal(client.lastRequest.indexOf('soapenv:Header'), -1); + assert.notEqual(client.lastRequest.indexOf('xmlns:soapenv='), -1); + done(); + }); + }, + baseUrl, + ); + }); - assert.ok(client.wsdl.definitions.bindings.mySoapBinding.style === 'document'); - done(); + it('should allow passing in XML strings', function (done) { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + server = http + .createServer(function (req, res) { + res.statusCode = 200; + res.write(""); + res.end(); + }) + .listen(port, hostname, function () { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + Object.assign({ envelopeKey: 'soapenv' }, meta.options), + function (err, client) { + assert.ok(client); + assert.ifError(err); + + var xmlStr = + '\n\t\n\t\t404 - Not Found\n\t\n\t\n\t\t

404 - Not Found

\n\t\t\n\t\n'; + client.MyOperation({ _xml: xmlStr }, function (err, result, raw, soapHeader) { + assert.ok(err); + assert.notEqual(raw.indexOf('html'), -1); + done(); + }); + }, + baseUrl, + ); + }) + .close(() => { + done(); + }); }); - }); - describe('Headers in request and last response', function() { - var server = null; - var hostname = '127.0.0.1'; - var port = 15099; - var baseUrl = 'http://' + hostname + ':' + port; + it('should set binding style to "document" by default if not explicitly set in WSDL, per SOAP spec', function (done) { + soap.createClient(__dirname + '/wsdl/binding_document.wsdl', meta.options, function (err, client) { + assert.ok(client); + assert.ifError(err); - before(function(done) { - server = http.createServer(function (req, res) { - var status_value = (req.headers['test-header'] === 'test') ? 'pass' : 'fail'; + assert.ok(client.wsdl.definitions.bindings.mySoapBinding.style === 'document'); + done(); + }); + }); - res.setHeader('status', status_value); - res.statusCode = 200; - res.write(JSON.stringify({tempResponse: 'temp'}), 'utf8'); - res.end(); - }).listen(port, hostname, done); + it('should allow disabling the wsdl cache', function (done) { + var spy = sinon.spy(wsdl, 'open_wsdl'); + var options = Object.assign({ disableCache: true }, meta.options); + soap.createClient(__dirname + '/wsdl/binding_document.wsdl', options, function (err1, client1) { + assert.ok(client1); + assert.ok(!err1); + soap.createClient(__dirname + '/wsdl/binding_document.wsdl', options, function (err2, client2) { + assert.ok(client2); + assert.ok(!err2); + assert.ok(spy.calledTwice); + wsdl.open_wsdl.restore(); + done(); + }); + }); }); - after(function(done) { - server.close(); - server = null; - done(); + describe('Binary attachments handling', function () { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + var attachment = { + mimetype: 'image/png', + contentId: 'file_0', + name: 'nodejs.png', + body: fs.readFileSync(__dirname + '/static/nodejs.png'), + }; + + function parsePartHeaders(part) { + const headersAndBody = part.split(/\r\n\r\n/); + const headersParts = headersAndBody[0].split(/\r\n/); + const headers = {}; + headersParts.forEach((header) => { + let index; + if ((index = header.indexOf(':')) > -1) { + headers[header.substring(0, index)] = header.substring(index + 1).trim(); + } + }); + return headers; + } + + it('should send binary attachments using XOP + MTOM', function (done) { + server = http + .createServer((req, res) => { + const bufs = []; + req.on('data', function (chunk) { + bufs.push(chunk); + }); + req.on('end', function () { + const body = Buffer.concat(bufs).toString().trim(); + const headers = req.headers; + const boundary = headers['content-type'].match(/boundary="?([^"]*"?)/)[1]; + + assert.ok(body.includes(`PNG\r\n\u001a\n\u0000\u0000\u0000\rIHDR`), `Body does not contain part of binary data`); + + const parts = body + .split(new RegExp('--' + boundary + '-{0,2}')) + .filter((part) => part) + .map(parsePartHeaders); + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ contentType: headers['content-type'], parts: parts }), 'utf8'); + }); + }) + .listen(port, hostname, function () { + soap.createClient( + __dirname + '/wsdl/attachments.wsdl', + meta.options, + function (initError, client) { + assert.ifError(initError); + + client.MyOperation( + {}, + function (error, response, body) { + assert.ifError(error); + const contentType = {}; + body.contentType.split(/;\s?/).forEach((dir) => { + const keyValue = dir.match(/(.*)="?([^"]*)?/); + if (keyValue && keyValue.length > 2) { + contentType[keyValue[1].trim()] = keyValue[2].trim(); + } else { + contentType.rootType = dir; + } + }); + assert.equal(contentType.rootType, 'multipart/related'); + + assert.equal(body.parts.length, 2); + + const dataHeaders = body.parts[0]; + assert(dataHeaders['Content-Type'].indexOf('application/xop+xml') > -1); + assert.equal(dataHeaders['Content-ID'], contentType.start); + + const attachmentHeaders = body.parts[1]; + assert.equal(attachmentHeaders['Content-Type'], attachment.mimetype); + assert.equal(attachmentHeaders['Content-Transfer-Encoding'], 'binary'); + assert.equal(attachmentHeaders['Content-ID'], '<' + attachment.contentId + '>'); + assert(attachmentHeaders['Content-Disposition'].indexOf(attachment.name) > -1); + + server.close(); + done(); + }, + { attachments: [attachment] }, + ); + }, + baseUrl, + ); + }); + }); }); - it('should append `:' + port + '` to the Host header on for a request to a service on that port', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + describe('SOAP 1.2 and MTOM binary data', function () { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + var attachment = { + mimetype: 'image/png', + contentId: 'file_0', + name: 'nodejs.png', + body: fs.readFileSync(__dirname + '/static/nodejs.png'), + }; + + function parsePartHeaders(part) { + const headersAndBody = part.split(/\r\n\r\n/); + const headersParts = headersAndBody[0].split(/\r\n/); + const headers = {}; + headersParts.forEach((header) => { + let index; + if ((index = header.indexOf(':')) > -1) { + headers[header.substring(0, index)] = header.substring(index + 1).trim(); + } + }); + return headers; + } + + before(function (done) { + server = http + .createServer(function (req, res) { + var bufs = []; + req.on('data', function (chunk) { + bufs.push(chunk); + }); + req.on('end', function () { + const body = Buffer.concat(bufs).toString().trim(); + const headers = req.headers; + const boundary = headers['content-type'].match(/boundary="?([^"]*"?)/)[1]; + const parts = body + .split(new RegExp('--' + boundary + '-{0,2}')) + .filter((part) => part) + .map(parsePartHeaders); + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ contentType: headers['content-type'], parts: parts }), 'utf8'); + }); + }) + .listen(port, hostname, done); + }); - client.MyOperation({}, function(err, result) { - assert.notEqual(client.lastRequestHeaders.Host.indexOf(':' + port), -1); + after(function (done) { + server.close(); + server = null; + done(); + }); - done(); - }, null, {'test-header': 'test'}); - }, baseUrl); + it('Should preserve SOAP 1.2 "action" header when sending MTOM request', function (done) { + soap.createClient( + __dirname + '/wsdl/attachments.wsdl', + Object.assign({ forceSoap12Headers: true }, meta.options), + function (initError, client) { + assert.ifError(initError); + + client.MyOperation( + {}, + function (error, response, body, soapHeader, rawRequest) { + assert.ifError(error); + assert(body.contentType.indexOf('action') > -1); + done(); + }, + { attachments: [attachment] }, + ); + }, + baseUrl, + ); + }); + + it('Should send MTOM request even without attachment', function (done) { + soap.createClient( + __dirname + '/wsdl/attachments.wsdl', + Object.assign({ forceSoap12Headers: true }, meta.options), + function (initError, client) { + assert.ifError(initError); + + client.MyOperation( + {}, + function (error, response, body, soapHeader, rawRequest) { + assert.ifError(error); + const contentType = {}; + body.contentType.split(/;\s?/).forEach((dir) => { + const keyValue = dir.match(/(.*)="?([^"]*)?/); + if (keyValue && keyValue.length > 2) { + contentType[keyValue[1].trim()] = keyValue[2].trim(); + } else { + contentType.rootType = dir; + } + }); + assert.equal(contentType.rootType, 'multipart/related'); + assert.equal(body.parts.length, 1); + + const dataHeaders = body.parts[0]; + assert(dataHeaders['Content-Type'].indexOf('application/xop+xml') > -1); + assert.equal(dataHeaders['Content-ID'], contentType.start); + done(); + }, + { forceMTOM: true }, + ); + }, + baseUrl, + ); + }); }); - it('should not append `:80` to the Host header on for a request to a service without a port explicitly defined', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + describe('Headers in request and last response', function () { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; - client.MyOperation({}, function(err, result) { - assert.equal(client.lastRequestHeaders.Host.indexOf(':80'), -1); + before(function (done) { + server = http + .createServer(function (req, res) { + var status_value = req.headers['test-header'] === 'test' ? 'pass' : 'fail'; - done(); - }, null, {'test-header': 'test'}); - }, 'http://127.0.0.1'); - }); + res.setHeader('status', status_value); + res.statusCode = 200; + res.write(JSON.stringify({ tempResponse: 'temp' }), 'utf8'); + res.end(); + }) + .listen(port, hostname, done); + }); - it('should not append `:443` to the Host header if endpoints runs on `https`', function (done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + after(function (done) { + server.close(); + server = null; + done(); + }); - client.MyOperation({}, function() { - assert.equal(client.lastRequestHeaders.Host.indexOf(':443'), -1); - done(); - }, null, {'test-header': 'test'}); - }, 'https://127.0.0.1'); - }); + it('should append `:' + port + '` to the Host header on for a request to a service on that port', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function () { + assert.notEqual(client.lastRequestHeaders.Host.indexOf(':' + port), -1); + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); - it('should append a port to the Host header if explicitly defined', function (done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + it('should not append `:80` to the Host header on for a request to a service without a port explicitly defined', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function () { + assert.equal(client.lastRequestHeaders.Host.indexOf(':80'), -1); + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); - client.MyOperation({}, function() { - assert.ok(client.lastRequestHeaders.Host.indexOf(':443') > -1); - done(); - }, null, {'test-header': 'test'}); - }, 'https://127.0.0.1:443'); + it('should not append `:443` to the Host header if endpoints runs on `https`', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function () { + assert.equal(client.lastRequestHeaders.Host.indexOf(':443'), -1); + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should append a port to the Host header if explicitly defined', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function () { + assert.ok(client.lastRequestHeaders.Host.indexOf(':443') > -1); + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + 'https://127.0.0.1:443', + ); + }); + + it('should have xml request modified', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result) { + assert.ok(result); + assert.ok(client.lastResponse); + assert.ok(client.lastResponseHeaders); + + done(); + }, + { + postProcess: function (_xml) { + return _xml.replace('soap', 'SOAP'); + }, + }, + ); + }, + baseUrl, + ); + }); + + it('should have the correct extra header in the request', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result) { + assert.ok(result); + assert.ok(client.lastResponseHeaders); + assert.equal(client.lastResponseHeaders.status, 'pass'); + + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should have the wrong extra header in the request', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result) { + assert.ok(result); + assert.ok(client.lastResponseHeaders); + assert.equal(client.lastResponseHeaders.status, 'fail'); + + done(); + }, + null, + { 'test-header': 'testBad' }, + ); + }, + baseUrl, + ); + }); + + it('should have lastResponse and lastResponseHeaders after the call', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result) { + assert.ok(result); + assert.ok(client.lastResponse); + assert.ok(client.lastResponseHeaders); + + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should remove add httpHeaders after the call', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.addHttpHeader('foo', 'bar'); + assert.equal(client.getHttpHeaders().foo, 'bar'); + + client.clearHttpHeaders(); + assert.equal(client.getHttpHeaders(), null); + + client.MyOperation({}, function (err, result) { + assert.ok(result); + assert.equal(client.lastRequestHeaders.foo, undefined); + + done(); + }); + }, + baseUrl, + ); + }); + + it('should have rawRequest available in the callback', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result, rawResponse, headers, rawRequest) { + assert.ok(rawRequest); + assert.ok(typeof rawRequest === 'string'); + + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should have lastElapsedTime after a call with the time option passed', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result) { + assert.ok(result); + assert.ok(client.lastResponse); + assert.ok(client.lastResponseHeaders); + assert.ok(client.lastElapsedTime !== undefined); + + done(); + }, + { time: true }, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should add http headers in method call options', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result) { + assert.ok(result); + assert.ok(client.lastRequestHeaders['test-header']); + assert.ok(client.lastRequestHeaders['options-test-header']); + + done(); + }, + { headers: { 'options-test-header': 'test' } }, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should not return error in the call and return the json in body', function (done) { + soap.createClient( + __dirname + '/wsdl/json_response.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result, body) { + assert.ok(result); + assert.ifError(err); + assert.ok(body); + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should add proper headers for soap12', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace_soap12.wsdl', + Object.assign({ forceSoap12Headers: true }, meta.options), + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result) { + assert.ok(result); + assert.ok(client.lastRequestHeaders); + assert.ok(client.lastRequest); + assert.equal(client.lastRequestHeaders['Content-Type'], 'application/soap+xml; charset=utf-8; action="MyOperation"'); + assert.notEqual(client.lastRequest.indexOf('xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\"'), -1); + assert(!client.lastRequestHeaders.SOAPAction); + done(); + }, + null, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should allow calling the method with args, callback, options and extra headers', function (done) { + soap.createClient( + __dirname + '/wsdl/json_response.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function (err, result, body) { + assert.ifError(err); + assert.ok(result); + assert.ok(body.tempResponse === 'temp'); + assert.ok(client.lastResponseHeaders.status === 'pass'); + assert.ok(client.lastRequestHeaders['options-test-header'] === 'test'); + + done(); + }, + { headers: { 'options-test-header': 'test' } }, + { 'test-header': 'test' }, + ); + }, + baseUrl, + ); + }); + + it('should allow calling the method with only a callback', function (done) { + soap.createClient( + __dirname + '/wsdl/json_response.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation(function (err, result, body) { + assert.ifError(err); + assert.ok(result); + assert.ok(body.tempResponse === 'temp'); + assert.ok(client.lastResponseHeaders.status === 'fail'); + + done(); + }); + }, + baseUrl, + ); + }); + + it('should allow calling the method with args, options and callback last', function (done) { + soap.createClient( + __dirname + '/wsdl/json_response.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation({}, { headers: { 'options-test-header': 'test' } }, function (err, result, body) { + assert.ifError(err); + assert.ok(result); + assert.ok(body.tempResponse === 'temp'); + assert.ok(client.lastResponseHeaders.status === 'fail'); + assert.ok(client.lastRequestHeaders['options-test-header'] === 'test'); + + done(); + }); + }, + baseUrl, + ); + }); + + it('should allow calling the method with args, options, extra headers and callback last', function (done) { + soap.createClient( + __dirname + '/wsdl/json_response.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation({}, { headers: { 'options-test-header': 'test' } }, { 'test-header': 'test' }, function (err, result, body) { + assert.ifError(err); + assert.ok(result); + assert.ok(body.tempResponse === 'temp'); + assert.ok(client.lastResponseHeaders.status === 'pass'); + assert.ok(client.lastRequestHeaders['options-test-header'] === 'test'); + + done(); + }); + }, + baseUrl, + ); + }); + + it('should have exactly 1 type parameter when the request uses MTOM', function (done) { + soap.createClient( + __dirname + '/wsdl/attachments.wsdl', + meta.options, + function (err, client) { + assert.ifError(err); + + client.MyOperation( + {}, + function (error, response, body, soapHeader, rawRequest) { + assert.ifError(error); + + const contentTypeSplit = client.lastRequestHeaders['Content-Type'].split(';'); + + assert.equal(contentTypeSplit[0], 'multipart/related'); + assert.ok( + contentTypeSplit.filter(function (e) { + return e.trim().startsWith('type='); + }).length === 1, + ); + + done(); + }, + { forceMTOM: true }, + ); + }, + baseUrl, + ); + }); }); - it('should have the correct extra header in the request', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { + it('should add soap headers', function (done) { + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', meta.options, function (err, client) { assert.ok(client); - assert.ok(!err); + assert.ok(!client.getSoapHeaders()); + var soapheader = { + esnext: false, + moz: true, + boss: true, + node: true, + validthis: true, + globals: { + EventEmitter: true, + Promise: true, + }, + }; - client.MyOperation({}, function(err, result) { - assert.ok(result); - assert.ok(client.lastResponseHeaders); - assert.equal(client.lastResponseHeaders.status, 'pass'); + client.addSoapHeader(soapheader); - done(); - }, null, {'test-header': 'test'}); - }, baseUrl); + assert.ok(client.getSoapHeaders()[0] === 'falsetruetruetruetruetruetrue'); + done(); + }); }); - it('should have the wrong extra header in the request', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + it('should add dynamic soap headers', function (done) { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; - client.MyOperation({}, function(err, result) { - assert.ok(result); - assert.ok(client.lastResponseHeaders); - assert.equal(client.lastResponseHeaders.status, 'fail'); + server = http + .createServer(function (req, res) { + res.statusCode = 200; + res.write(""); + res.end(); + }) + .listen(port, hostname, function () { + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', meta.options, function (err, client) { + assert.ok(client); + assert.ok(!client.getSoapHeaders()); + let random; + function dynamicHeader(method, location, soapAction, args) { + random = Math.floor(Math.random() * 65536); + return { + TeSt_location: location, + TeSt_action: soapAction, + TeSt_random: random, + }; + } + client.addSoapHeader(dynamicHeader); + assert.ok(typeof client.getSoapHeaders()[0] === 'function'); + client.MyOperation( + {}, + function (err, result) { + assert.notEqual(client.lastRequest.indexOf('http://www.example.com/v1'), -1); + assert.notEqual(client.lastRequest.indexOf('MyOperation'), -1); + assert.notEqual(client.lastRequest.indexOf(`${random}`), -1); + done(); + }, + baseUrl, + ); + }); + }) + .close(() => { done(); - }, null, {'test-header': 'testBad'}); - }, baseUrl); + }); }); - it('should have lastResponse and lastResponseHeaders after the call', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { + it('should add soap headers with a namespace', function (done) { + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', meta.options, function (err, client) { assert.ok(client); - assert.ok(!err); + assert.ok(!client.getSoapHeaders()); - client.MyOperation({}, function(err, result) { - assert.ok(result); - assert.ok(client.lastResponse); - assert.ok(client.lastResponseHeaders); + client.addSoapHeader({ header1: 'content' }, null, null, 'http://example.com'); - done(); - }, null, {'test-header': 'test'}); - }, baseUrl); + assert.ok(client.getSoapHeaders().length === 1); + assert.ok(client.getSoapHeaders()[0] === 'content'); + + client.clearSoapHeaders(); + assert.ok(!client.getSoapHeaders()); + done(); + }); }); - it('should have lastElapsedTime after a call with the time option passed', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { + it('should add http headers', function (done) { + soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', meta.options, function (err, client) { assert.ok(client); - assert.ok(!err); + assert.ok(!client.getHttpHeaders()); - client.MyOperation({}, function(err, result) { - assert.ok(result); - assert.ok(client.lastResponse); - assert.ok(client.lastResponseHeaders); - assert.ok(client.lastElapsedTime); + client.addHttpHeader('foo', 'bar'); - done(); - }, {time: true}, {'test-header': 'test'}); - }, baseUrl); + assert.ok(client.getHttpHeaders()); + assert.equal(client.getHttpHeaders().foo, 'bar'); + + client.clearHttpHeaders(); + assert.equal(client.getHttpHeaders(), null); + done(); + }); }); - it('should add http headers in method call options', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + describe('Namespace number', function () { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 200; + res.write(JSON.stringify({ tempResponse: 'temp' }), 'utf8'); + res.end(); + }) + .listen(port, hostname, done); + }); + + after(function (done) { + server.close(); + server = null; + done(); + }); - client.MyOperation({}, function(err, result) { - assert.ok(result); - assert.ok(client.lastRequestHeaders['test-header']); - assert.ok(client.lastRequestHeaders['options-test-header']); + it('should reset the namespace number', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + + var data = { + attributes: { + xsi_type: { + type: 'Ty', + xmlns: 'xmlnsTy', + }, + }, + }; + + var message = ''; + client.MyOperation(data, function (err, result) { + assert.ok(client.lastRequest); + assert.ok(client.lastMessage); + assert.ok(client.lastEndpoint); + assert.equal(client.lastMessage, message); + + delete data.attributes.xsi_type.namespace; + client.MyOperation(data, function (err, result) { + assert.ok(client.lastRequest); + assert.ok(client.lastMessage); + assert.ok(client.lastEndpoint); + assert.equal(client.lastMessage, message); + + done(); + }); + }); + }, + baseUrl, + ); + }); - done(); - }, {headers: {'options-test-header': 'test'}}, {'test-header': 'test'}); - }, baseUrl); + it('should handle xsi:type without xmlns', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + + var data = { + element: { + attributes: { + xsi_type: { + type: 'Ty', + }, + }, + $value: 'Hello World', + }, + }; + + var message = 'Hello World'; + + client.MyOperation(data, function (err, result) { + assert.ok(client.lastRequest); + assert.ok(client.lastMessage); + assert.ok(client.lastEndpoint); + // Commented out for production test due to verbosity. + //console.log(client.lastMessage) + assert.strictEqual(client.lastMessage, message); + done(); + }); + }, + baseUrl, + ); + }); }); - it('should not return error in the call and return the json in body', function(done) { - soap.createClient(__dirname+'/wsdl/json_response.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + describe('Follow even non-standard redirects', function () { + var server1 = null; + var server2 = null; + var server3 = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + before(function (done) { + server1 = http + .createServer(function (req, res) { + res.statusCode = 301; + res.setHeader('Location', 'http://' + hostname + ':' + (port + 1)); + res.end(); + }) + .listen(port, hostname, function () { + server2 = http + .createServer(function (req, res) { + res.statusCode = 302; + res.setHeader('Location', 'http://' + hostname + ':' + (port + 2)); + res.end(); + }) + .listen(port + 1, hostname, function () { + server3 = http + .createServer(function (req, res) { + res.statusCode = 401; + res.write(JSON.stringify({ tempResponse: 'temp' }), 'utf8'); + res.end(); + }) + .listen(port + 2, hostname, done); + }); + }); + }); - client.MyOperation({}, function(err, result, body) { - assert.ok(result); - assert.ok(!err); - assert.ok(body); - done(); - }, null, {"test-header": 'test'}); - }, baseUrl); + after(function (done) { + server1.close(); + server2.close(); + server3.close(); + server1 = null; + server2 = null; + server3 = null; + done(); + }); + + it('should return an error', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + client.MyOperation({}, function (err, result) { + assert.ok(err); + assert.ok(err.response); + assert.equal(err.body, '{"tempResponse":"temp"}'); + done(); + }); + }, + baseUrl, + ); + }); }); - it('should add proper headers for soap12', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace_soap12.wsdl', {forceSoap12Headers: true}, function(err, client) { - assert.ok(client); - assert.ok(!err); + // TODO: + // It seems to be an invalid test case that should be removed. + // It verifies that error should be returned when receiving incorrect response and it's irrelevant to http status code. + describe('Handle invalid http response', function () { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 401; // This test case is nothing to do with status code. Set to 200 doesn't break test. + res.write(JSON.stringify({ tempResponse: 'temp' }), 'utf8'); + res.end(); + }) + .listen(port, hostname, done); + }); - client.MyOperation({}, function(err, result) { - assert.ok(result); - assert.ok(client.lastRequestHeaders); - assert.ok(client.lastRequest); - assert.equal(client.lastRequestHeaders['Content-Type'], 'application/soap+xml; charset=utf-8'); - assert.notEqual(client.lastRequest.indexOf('xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\"'), -1); - assert( !client.lastRequestHeaders.SOAPAction ); - done(); - }, null, {'test-header': 'test'}); - }, baseUrl); + after(function (done) { + server.close(); + server = null; + done(); + }); + + it('should return an error', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + client.MyOperation({}, function (err, result) { + assert.ok(err); + assert.ok(err.response); + assert.ok(err.response.data); + done(); + }); + }, + baseUrl, + ); + }); + + it("should emit a 'soapError' event", function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + client.on('soapError', function (err) { + assert.ok(err); + }); + client.MyOperation({}, function (err, result) { + done(); + }); + }, + baseUrl, + ); + }); }); - it('should allow calling the method with args, callback, options and extra headers', function(done) { - soap.createClient(__dirname+'/wsdl/json_response.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + describe('Handle non-success http status codes without response body', function () { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = `http://${hostname}:${port}`; - client.MyOperation({}, function(err, result, body) { - assert.ok(!err); - assert.ok(result); - assert.ok(body.tempResponse === 'temp'); - assert.ok(client.lastResponseHeaders.status === 'pass'); - assert.ok(client.lastRequestHeaders['options-test-header'] === 'test'); + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 404; + res.end(); + }) + .listen(port, hostname, done); + }); - done(); - }, {headers: {'options-test-header': 'test'}}, {'test-header': 'test'}); - }, baseUrl); + after(function (done) { + server.close(); + server = null; + done(); + }); + + it('should return an error', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + client.MyOperation({}, function (err, result) { + assert.ok(err); + assert.ok(err.response); + done(); + }); + }, + baseUrl, + ); + }); + + it("should emit a 'soapError' event", function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + client.on('soapError', function (err) { + assert.ok(err); + }); + client.MyOperation({}, function (err, result) { + done(); + }); + }, + baseUrl, + ); + }); }); - it('should allow calling the method with only a callback', function(done) { - soap.createClient(__dirname+'/wsdl/json_response.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + describe('Handle HTML answer from non-SOAP server', function () { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 200; + res.write('', 'utf8'); + res.end(); + }) + .listen(port, hostname, done); + }); - client.MyOperation(function(err, result, body) { - assert.ok(!err); - assert.ok(result); - assert.ok(body.tempResponse === 'temp'); - assert.ok(client.lastResponseHeaders.status === 'fail'); + after(function (done) { + server.close(); + server = null; + done(); + }); - done(); - }); - }, baseUrl); + it('should return an error', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + client.MyOperation({}, function (err, result) { + assert.ok(err); + assert.ok(err.response); + assert.ok(err.body); + done(); + }); + }, + baseUrl, + ); + }); }); - it('should allow calling the method with args, options and callback last', function(done) { - soap.createClient(__dirname+'/wsdl/json_response.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + describe('Client Events', function () { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 200; + fs.createReadStream(__dirname + '/soap-failure.xml').pipe(res); + }) + .listen(port, hostname, done); + }); + + after(function (done) { + server.close(); + server = null; + done(); + }); - client.MyOperation({}, {headers: {'options-test-header': 'test'}}, function(err, result, body) { - assert.ok(!err); - assert.ok(result); - assert.ok(body.tempResponse === 'temp'); - assert.ok(client.lastResponseHeaders.status === 'fail'); - assert.ok(client.lastRequestHeaders['options-test-header'] === 'test'); + it('Should emit the "message" event with Soap Body string and an exchange id', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + var didEmitEvent = false; + client.on('message', function (xml, eid) { + didEmitEvent = true; + // Should contain only message body + assert.equal(typeof xml, 'string'); + assert.equal(xml.indexOf('soap:Envelope'), -1); + assert.ok(eid); + }); + + client.MyOperation({}, function () { + assert.ok(didEmitEvent); + done(); + }); + }, + baseUrl, + ); + }); - done(); - }); - }, baseUrl); + it('Should emit the "request" event with entire XML message and an exchange id', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + var didEmitEvent = false; + client.on('request', function (xml, eid) { + didEmitEvent = true; + // Should contain entire soap message + assert.equal(typeof xml, 'string'); + assert.notEqual(xml.indexOf('soap:Envelope'), -1); + assert.ok(eid); + }); + + client.MyOperation({}, function () { + assert.ok(didEmitEvent); + done(); + }); + }, + baseUrl, + ); + }); + + it('Should emit the "response" event with Soap Body string and Response object and an exchange id', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + var didEmitEvent = false; + client.on('response', function (xml, response, eid) { + didEmitEvent = true; + // Should contain entire soap message + assert.equal(typeof xml, 'string'); + assert.equal(xml.indexOf('soap:Envelope'), -1); + assert.ok(response); + assert.ok(eid); + }); + + client.MyOperation({}, function () { + assert.ok(didEmitEvent); + done(); + }); + }, + baseUrl, + ); + }); + + it('Should emit the "request" and "response" events with the same generated exchange id if none is given', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + var didEmitRequestEvent = false; + var didEmitResponseEvent = false; + var requestEid, responseEid; + + client.on('request', function (xml, eid) { + didEmitRequestEvent = true; + requestEid = eid; + assert.ok(eid); + }); + + client.on('response', function (xml, response, eid) { + didEmitResponseEvent = true; + responseEid = eid; + assert.ok(eid); + }); + + client.MyOperation({}, function () { + assert.ok(didEmitRequestEvent); + assert.ok(didEmitResponseEvent); + assert.equal(responseEid, requestEid); + done(); + }); + }, + baseUrl, + ); + }); + + it('Should emit the "request" and "response" events with the given exchange id', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + var didEmitRequestEvent = false; + var didEmitResponseEvent = false; + var requestEid, responseEid; + + client.on('request', function (xml, eid) { + didEmitRequestEvent = true; + requestEid = eid; + assert.ok(eid); + }); + + client.on('response', function (xml, response, eid) { + didEmitResponseEvent = true; + responseEid = eid; + assert.ok(eid); + }); + + client.MyOperation( + {}, + function () { + assert.ok(didEmitRequestEvent); + assert.ok(didEmitResponseEvent); + assert.equal('unit', requestEid); + assert.equal(responseEid, requestEid); + done(); + }, + { exchangeId: 'unit' }, + ); + }, + baseUrl, + ); + }); + + it("should emit a 'soapError' event with an exchange id", function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + meta.options, + function (err, client) { + var didEmitEvent = false; + client.on('soapError', function (err, eid) { + didEmitEvent = true; + assert.ok(err.root.Envelope.Body.Fault); + assert.ok(eid); + }); + client.MyOperation({}, function (err, result) { + assert.ok(didEmitEvent); + done(); + }); + }, + baseUrl, + ); + }); }); - it('should allow calling the method with args, options, extra headers and callback last', function(done) { - soap.createClient(__dirname+'/wsdl/json_response.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!err); + [200, 500].forEach((statusCode) => { + it('should return error in the call when Fault was returned (status code ' + statusCode + ')', function (done) { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + server = http + .createServer(function (req, res) { + res.statusCode = statusCode; + res.write( + '\nTesttest errortest detail', + ); + res.end(); + }) + .listen(port, hostname, function () { + soap.createClient( + __dirname + '/wsdl/json_response.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation({}, function (err, result, body) { + server.close(); + server = null; + assert.ok(err); + assert.strictEqual(err.message, 'Test: test error: "test detail"'); + assert.ok(result); + assert.ok(body); + done(); + }); + }, + baseUrl, + ); + }); + }); + }); - client.MyOperation({}, {headers: {'options-test-header': 'test'}}, {'test-header': 'test'}, function(err, result, body) { - assert.ok(!err); - assert.ok(result); - assert.ok(body.tempResponse === 'temp'); - assert.ok(client.lastResponseHeaders.status === 'pass'); - assert.ok(client.lastRequestHeaders['options-test-header'] === 'test'); + it('should return error in the call when Body was returned empty', function (done) { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; - done(); + server = http + .createServer(function (req, res) { + res.statusCode = 200; + res.write(""); + res.end(); + }) + .listen(port, hostname, function () { + soap.createClient( + __dirname + '/wsdl/empty_body.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation({}, function (err, result, body, responseSoapHeaders) { + server.close(); + server = null; + assert.ifError(err); + assert.ok(!responseSoapHeaders); + assert.ok(result); + assert.ok(body); + done(); + }); + }, + baseUrl, + ); }); - }, baseUrl); }); - }); - it('should add soap headers', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - assert.ok(client); - assert.ok(!client.getSoapHeaders()); - var soapheader = { - 'esnext': false, - 'moz': true, - 'boss': true, - 'node': true, - 'validthis': true, - 'globals': { - 'EventEmitter': true, - 'Promise': true - } + describe('Method invocation', function () { + const baseUrl = 'http://localhost:80'; + + it('shall generate correct payload for methods with string parameter', function (done) { + // Mock the http post function in order to easy be able to validate the generated payload + var stringParameterValue = 'MY_STRING_PARAMETER_VALUE'; + var expectedSoapBody = '' + stringParameterValue + ''; + var request = null; + var mockRequestHandler = function (_request) { + request = _request; + return Promise.resolve(request); }; + var options = Object.assign({ request: mockRequestHandler }, meta.options); + soap.createClient(__dirname + '/wsdl/builtin_types.wsdl', options, function (err, client) { + assert.ok(client); - client.addSoapHeader(soapheader); + // Call the method + client.StringOperation(stringParameterValue, () => {}); - assert.ok(client.getSoapHeaders()[0] === 'falsetruetruetruetruetruetrue'); - done(); + // Analyse and validate the generated soap body + var requestBody = request.data; + var soapBody = requestBody.match(/(.*)<\/soap:Body>/)[1]; + assert.ok(soapBody === expectedSoapBody); + done(); + }); }); - }); - it('should add soap headers with a namespace', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!client.getSoapHeaders()); + it('shall generate correct payload for methods with array parameter', function (done) { + soap.createClient( + __dirname + '/wsdl/list_parameter.wsdl', + function (err, client) { + assert.ok(client); + var pathToArrayContainer = 'TimesheetV201511Mobile.TimesheetV201511MobileSoap.AddTimesheet.input.input.PeriodList'; + var arrayParameter = _.get(client.describe(), pathToArrayContainer)['PeriodType[]']; + assert.ok(arrayParameter); + client.AddTimesheet({ input: { PeriodList: { PeriodType: [{ PeriodId: '1' }] } } }, function () { + var sentInputContent = client.lastRequest.substring(client.lastRequest.indexOf('') + ''.length, client.lastRequest.indexOf('')); + assert.equal(sentInputContent, '1'); + done(); + }); + }, + baseUrl, + ); + }); - client.addSoapHeader({header1: 'content'}, null, null, 'http://example.com'); + it('shall generate correct payload for methods with array parameter with colon override', function (done) { + soap.createClient( + __dirname + '/wsdl/array_namespace_override.wsdl', + function (err, client) { + assert.ok(client); + var pathToArrayContainer = 'SampleArrayServiceImplService.SampleArrayServiceImplPort.createWebOrder.input.order'; + var arrayParameter = _.get(client.describe(), pathToArrayContainer)['orderDetails[]']; + assert.ok(arrayParameter); + const input = { + ':clientId': 'test', + ':order': { + ':orderDetails': { + ':unitNo': 1234, + ':items': [{ ':itemDesc': 'item1' }, { ':itemDesc': 'item2' }], + }, + }, + }; + client.createWebOrder(input, function () { + var sentInputContent = client.lastRequest.substring(client.lastRequest.indexOf(''), client.lastRequest.lastIndexOf('') + ''.length); + assert.equal(sentInputContent, 'item1item2'); + done(); + }); + }, + baseUrl, + ); + }); - assert.ok(client.getSoapHeaders().length === 1); - assert.ok(client.getSoapHeaders()[0] === 'content'); + it('shall generate correct payload for methods with array parameter with parent namespace', function (done) { + soap.createClient( + __dirname + '/wsdl/array_namespace_override.wsdl', + function (err, client) { + assert.ok(client); + var pathToArrayContainer = 'SampleArrayServiceImplService.SampleArrayServiceImplPort.createWebOrder.input.order'; + var arrayParameter = _.get(client.describe(), pathToArrayContainer)['orderDetails[]']; + assert.ok(arrayParameter); + const input = { + ':clientId': 'test', + ':order': { + orderDetails: { + ':unitNo': 1234, + 'items': [{ ':itemDesc': 'item1' }, { ':itemDesc': 'item2' }], + }, + }, + }; + client.createWebOrder(input, function () { + var sentInputContent = client.lastRequest.substring(client.lastRequest.indexOf(''), client.lastRequest.lastIndexOf('') + ''.length); + assert.equal(sentInputContent, 'item1item2'); + done(); + }); + }, + baseUrl, + ); + }); - client.clearSoapHeaders(); - assert.ok(!client.getSoapHeaders()); - done(); - }); - }); + it('shall generate correct payload for methods with array parameter when individual array elements are not namespaced', function (done) { + // used for servers that cannot aggregate individually namespaced array elements + soap.createClient( + __dirname + '/wsdl/list_parameter.wsdl', + { disableCache: true, namespaceArrayElements: false }, + function (err, client) { + assert.ok(client); + var pathToArrayContainer = 'TimesheetV201511Mobile.TimesheetV201511MobileSoap.AddTimesheet.input.input.PeriodList'; + var arrayParameter = _.get(client.describe(), pathToArrayContainer)['PeriodType[]']; + assert.ok(arrayParameter); + client.AddTimesheet({ input: { PeriodList: { PeriodType: [{ PeriodId: '1' }, { PeriodId: '2' }] } } }, function () { + var sentInputContent = client.lastRequest.substring(client.lastRequest.indexOf('') + ''.length, client.lastRequest.indexOf('')); + assert.equal(sentInputContent, '12'); + done(); + }); + }, + baseUrl, + ); + }); - it('should add http headers', function(done) { - soap.createClient(__dirname+'/wsdl/default_namespace.wsdl', function(err, client) { - assert.ok(client); - assert.ok(!client.getHttpHeaders()); + it('shall generate correct payload for methods with array parameter when individual array elements are namespaced', function (done) { + // this is the default behavior for array element namespacing + soap.createClient( + __dirname + '/wsdl/list_parameter.wsdl', + { disableCache: true, namespaceArrayElements: true }, + function (err, client) { + assert.ok(client); + assert.ok(client.wsdl.options.namespaceArrayElements === true); + var pathToArrayContainer = 'TimesheetV201511Mobile.TimesheetV201511MobileSoap.AddTimesheet.input.input.PeriodList'; + var arrayParameter = _.get(client.describe(), pathToArrayContainer)['PeriodType[]']; + assert.ok(arrayParameter); + client.AddTimesheet({ input: { PeriodList: { PeriodType: [{ PeriodId: '1' }, { PeriodId: '2' }] } } }, function () { + var sentInputContent = client.lastRequest.substring(client.lastRequest.indexOf('') + ''.length, client.lastRequest.indexOf('')); + assert.equal(sentInputContent, '12'); + done(); + }); + }, + baseUrl, + ); + }); - client.addHttpHeader('foo', 'bar'); + it('shall generate correct payload for recursively-defined types', function (done) { + soap.createClient( + __dirname + '/wsdl/recursive2.wsdl', + function (err, client) { + if (err) { + return void done(err); + } - assert.ok(client.getHttpHeaders()); - assert.equal(client.getHttpHeaders().foo, 'bar'); + assert.ok(client); + client.AddAttribute( + { + Requests: { + AddAttributeRequest: [ + { + RequestIdx: 1, + Identifier: { + SystemNamespace: 'bugrepro', + ResellerId: 1, + CustomerNum: '860692', + AccountUid: '80a6e559-4d65-11e7-bd5b-0050569a12d7', + }, + Attr: { + AttributeId: 716, + IsTemplateAttribute: 0, + ReadOnly: 0, + CanBeModified: 1, + Name: 'domain', + AccountElements: { + AccountElement: [ + { + ElementId: 1693, + Name: 'domain', + Value: 'foo', + ReadOnly: 0, + CanBeModified: 1, + }, + ], + }, + }, + RequestedBy: 'blah', + RequestedByLogin: 'system', + }, + ], + }, + }, + function () { + var sentInputContent = client.lastRequest.substring(client.lastRequest.indexOf('') + ''.length, client.lastRequest.indexOf('')); + assert.equal( + sentInputContent, + '1bugrepro186069280a6e559-4d65-11e7-bd5b-0050569a12d7716001domain1693domainfoo01blahsystem', + ); + done(); + }, + ); + }, + baseUrl, + ); + }); - client.clearHttpHeaders(); - assert.equal(Object.keys(client.getHttpHeaders()).length, 0); - done(); + it('should resolve cross schema references', function () { + return soap.createClientAsync(__dirname + '/wsdl/cross_schema.wsdl').then(function (client) { + return assert.deepStrictEqual(client.describe().Service.Service.Operation.output, { + OperationReturn: { + result: 'xs:string', + targetNSAlias: 'ns1', + targetNamespace: 'http://response.ws2.example.it', + }, + }); + }); + }); }); - }); - describe('Namespace number', function() { - var server = null; - var hostname = '127.0.0.1'; - var port = 15099; - var baseUrl = 'http://' + hostname + ':' + port; + describe('Client created with createClientAsync', function () { + it('should error on invalid host', function (done) { + soap + .createClientAsync('http://localhost:1', meta.options) + .then(function (client) {}) + .catch(function (err) { + assert.ok(err); + done(); + }); + }); - before(function(done) { - server = http.createServer(function (req, res) { - res.statusCode = 200; - res.write(JSON.stringify({tempResponse: 'temp'}), 'utf8'); - res.end(); - }).listen(port, hostname, done); - }); + it('should add and clear soap headers', function (done) { + soap.createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', meta.options).then(function (client) { + assert.ok(client); + assert.ok(!client.getSoapHeaders()); - after(function(done) { - server.close(); - server = null; - done(); - }); + var i1 = client.addSoapHeader('about-to-change-1'); + var i2 = client.addSoapHeader('about-to-change-2'); - it('should reset the namespace number', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - assert.ok(client); + assert.ok(i1 === 0); + assert.ok(i2 === 1); + assert.ok(client.getSoapHeaders().length === 2); - var data = { - attributes: { - xsi_type: { - type: 'Ty', - xmlns: 'xmlnsTy' - } - } + client.changeSoapHeader(0, 'header1'); + client.changeSoapHeader(1, 'header2'); + assert.ok(client.getSoapHeaders()[0] === 'header1'); + assert.ok(client.getSoapHeaders()[1] === 'header2'); + + client.clearSoapHeaders(); + assert.ok(!client.getSoapHeaders()); + done(); + }); + }); + + it('should issue async promise for cached wsdl', function (done) { + var called = false; + soap.createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', meta.options).then(function (client) { + assert.ok(client); + called = true; + done(); + }); + assert(!called); + }); + + it('should allow customization of httpClient', function (done) { + var myHttpClient = { + request: function () {}, }; + soap.createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', Object.assign({ httpClient: myHttpClient }, meta.options)).then(function (client) { + assert.ok(client); + assert.equal(client.httpClient, myHttpClient); + done(); + }); + }); - var message = ''; - client.MyOperation(data, function(err, result) { - assert.ok(client.lastRequest); - assert.ok(client.lastMessage); - assert.ok(client.lastEndpoint); - assert.equal(client.lastMessage, message); + it('should allow customization of request for http client', function (done) { + var myRequest = function () {}; + soap.createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', Object.assign({ request: myRequest }, meta.options)).then(function (client) { + assert.ok(client); + assert.equal(client.httpClient._request, myRequest); + done(); + }); + }); - delete data.attributes.xsi_type.namespace; - client.MyOperation(data, function(err, result) { - assert.ok(client.lastRequest); - assert.ok(client.lastMessage); - assert.ok(client.lastEndpoint); - assert.equal(client.lastMessage, message); + it('should set binding style to "document" by default if not explicitly set in WSDL, per SOAP spec', function (done) { + soap.createClientAsync(__dirname + '/wsdl/binding_document.wsdl', meta.options).then(function (client) { + assert.ok(client); + assert.ok(client.wsdl.definitions.bindings.mySoapBinding.style === 'document'); + done(); + }); + }); + it('should allow passing in XML strings', function (done) { + soap + .createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', Object.assign({ envelopeKey: 'soapenv' }, meta.options), baseUrl) + .then(function (client) { + assert.ok(client); + var xmlStr = + '\n\t\n\t\t404 - Not Found\n\t\n\t\n\t\t

404 - Not Found

\n\t\t\n\t\n'; + return client.MyOperationAsync({ _xml: xmlStr }); + }) + .then(function ([result, raw, soapHeader]) {}) + .catch(function (err) { done(); }); - }); - }, baseUrl); - }); - }); + }); - describe('Follow even non-standard redirects', function() { - var server1 = null; - var server2 = null; - var server3 = null; - var hostname = '127.0.0.1'; - var port = 15099; - var baseUrl = 'http://' + hostname + ':' + port; - - before(function(done) { - server1 = http.createServer(function (req, res) { - res.statusCode = 301; - res.setHeader('Location', 'http://' + hostname + ':' + (port+1)); - res.end(); - }).listen(port, hostname, function() { - server2 = http.createServer(function (req, res) { - res.statusCode = 302; - res.setHeader('Location', 'http://' + hostname + ':' + (port+2)); - res.end(); - }).listen((port+1), hostname, function() { - server3 = http.createServer(function (req, res) { - res.statusCode = 401; - res.write(JSON.stringify({tempResponse: 'temp'}), 'utf8'); - res.end(); - }).listen((port+2), hostname, done); - }); + it('should allow customization of envelope', function (done) { + var client; + soap + .createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', Object.assign({ envelopeKey: 'soapenv' }, meta.options), baseUrl) + .then(function (createdClient) { + assert.ok(createdClient); + client = createdClient; + return client.MyOperationAsync({}); + }) + .then(function (response) {}) + .catch(function (err) { + assert.notEqual(client.lastRequest.indexOf('xmlns:soapenv='), -1); + done(); + }); }); - }); - after(function(done) { - server1.close(); - server2.close(); - server3.close(); - server1 = null; - server2 = null; - server3 = null; - done(); - }); + it('should allow customization of envelope Soap Url', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + Object.assign({ envelopeSoapUrl: 'http://example.com/v1' }, meta.options), + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation({}, function (err, result) { + assert.notEqual(client.lastRequest.indexOf('xmlns:soap=\"http://example.com/v1\"'), -1); + done(); + }); + }, + baseUrl, + ); + }); - it('should return an error', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - client.MyOperation({}, function(err, result) { - assert.ok(err); - assert.ok(err.response); - assert.equal(err.body, '{"tempResponse":"temp"}'); + it('should add soap headers', function (done) { + soap.createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', meta.options).then(function (client) { + assert.ok(client); + assert.ok(!client.getSoapHeaders()); + var soapheader = { + esnext: false, + moz: true, + boss: true, + node: true, + validthis: true, + globals: { + EventEmitter: true, + Promise: true, + }, + }; + + client.addSoapHeader(soapheader); + + assert.ok(client.getSoapHeaders()[0] === 'falsetruetruetruetruetruetrue'); done(); }); - }, baseUrl); - }); - }); + }); + + it('should allow disabling the wsdl cache', function (done) { + var spy = sinon.spy(wsdl, 'open_wsdl'); + var options = Object.assign({ disableCache: true }, meta.options); + soap + .createClientAsync(__dirname + '/wsdl/binding_document.wsdl', options) + .then(function (client) { + assert.ok(client); + return soap.createClientAsync(__dirname + '/wsdl/binding_document.wsdl', options); + }) + .then(function (client) { + assert.ok(client); + assert.ok(spy.calledTwice); + wsdl.open_wsdl.restore(); + done(); + }); + }); - describe('Handle non-success http status codes', function() { - var server = null; - var hostname = '127.0.0.1'; - var port = 15099; - var baseUrl = 'http://' + hostname + ':' + port; + it('should add http headers', function (done) { + soap.createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', meta.options).then(function (client) { + assert.ok(client); + assert.ok(!client.getHttpHeaders()); - before(function(done) { - server = http.createServer(function (req, res) { - res.statusCode = 401; - res.write(JSON.stringify({tempResponse: 'temp'}), 'utf8'); - res.end(); - }).listen(port, hostname, done); - }); + client.addHttpHeader('foo', 'bar'); - after(function(done) { - server.close(); - server = null; - done(); - }); + assert.ok(client.getHttpHeaders()); + assert.equal(client.getHttpHeaders().foo, 'bar'); - it('should return an error', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - client.MyOperation({}, function(err, result) { - assert.ok(err); - assert.ok(err.response); - assert.ok(err.body); + client.clearHttpHeaders(); + assert.equal(client.getHttpHeaders(), null); done(); }); - }, baseUrl); + }); }); - it('should emit a \'soapError\' event', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - client.on('soapError', function(err) { - assert.ok(err); + describe('Client created with option normalizeNames', function () { + it('should create node-style method with normalized name (a valid Javascript identifier)', function (done) { + soap.createClient( + __dirname + '/wsdl/non_identifier_chars_in_operation.wsdl', + Object.assign({ normalizeNames: true }, meta.options), + function (err, client) { + assert.ok(client); + assert.ifError(err); + client.prefixed_MyOperation({}, function (err, result) { + // only need to check that a valid request is generated, response isn't needed + assert.ok(client.lastRequest); + done(); + }); + }, + baseUrl, + ); + }); + + it('should create node-style method with non-normalized name on Client.service.port.method style invocation', function (done) { + soap.createClient( + __dirname + '/wsdl/non_identifier_chars_in_operation.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + /*jshint -W069 */ + assert.throws(function () { + client.MyService.MyServicePort['prefixed_MyOperation']({}); + }, TypeError); + /*jshint +W069 */ + client.MyService.MyServicePort['prefixed-MyOperation']({}, function (err, result) { + // only need to check that a valid request is generated, response isn't needed + assert.ok(client.lastRequest); + done(); + }); + }, + baseUrl, + ); + }); + + it('should create promise-style method with normalized name (a valid Javascript identifier)', function (done) { + soap.createClient( + __dirname + '/wsdl/non_identifier_chars_in_operation.wsdl', + Object.assign({ normalizeNames: true }, meta.options), + function (err, client) { + assert.ok(client); + assert.ifError(err); + client + .prefixed_MyOperationAsync({}) + .then(function (result) {}) + .catch(function (err) { + // only need to check that a valid request is generated, response isn't needed + assert.ok(client.lastRequest); + done(); + }); + }, + baseUrl, + ); + }); + + it('should not create methods with invalid Javascript identifier', function (done) { + soap.createClient(__dirname + '/wsdl/non_identifier_chars_in_operation.wsdl', Object.assign({ normalizeNames: true }, meta.options), function (err, client) { + assert.ok(client); + assert.ifError(err); + assert.throws(function () { + client['prefixed-MyOperationAsync']({}); + }, TypeError); + assert.throws(function () { + client['prefixed-MyOperation']({}); + }, TypeError); + done(); }); - client.MyOperation({}, function(err, result) { + }); + + it('should create node-style method with invalid Javascript identifier if option normalizeNames is not used', function (done) { + soap.createClient( + __dirname + '/wsdl/non_identifier_chars_in_operation.wsdl', + meta.options, + function (err, client) { + assert.ok(client); + assert.ifError(err); + client['prefixed-MyOperation']({}, function (err, result) { + // only need to check that a valid request is generated, response isn't needed + assert.ok(client.lastRequest); + done(); + }); + }, + baseUrl, + ); + }); + + it('does not create a promise-style method with invalid Javascript identifier if option normalizeNames is not used', function (done) { + soap.createClient(__dirname + '/wsdl/non_identifier_chars_in_operation.wsdl', meta.options, function (err, client) { + assert.ok(client); + assert.ifError(err); + assert.throws(function () { + client['prefixed-MyOperationAsync']({}); + }, TypeError); done(); }); - }, baseUrl); + }); }); }); +}); - describe('Handle HTML answer from non-SOAP server', function() { - var server = null; - var hostname = '127.0.0.1'; - var port = 15099; - var baseUrl = 'http://' + hostname + ':' + port; +describe('Uncategorised', function () { + const baseUrl = 'http://localhost:80'; - before(function(done) { - server = http.createServer(function (req, res) { - res.statusCode = 200; - res.write('', 'utf8'); - res.end(); - }).listen(port, hostname, done); + it('shall generate correct header for custom defined header arguments', function (done) { + soap.createClientAsync(__dirname + '/wsdl/default_namespace.wsdl', {}, baseUrl).then(function (client) { + client.addSoapHeader('test-header-namespace'); + client.wsdl.xmlnsInHeader = 'xmlns="https://example.com/v1"'; + var expectedDefinedHeader = ''; + + client.MyOperation(function (err, result, rawResponse, soapHeader, rawRequest) { + var definedSoapHeader = client.lastRequest.match(/)/)[0]; + assert.ok(definedSoapHeader === expectedDefinedHeader); + done(); + }); }); + }); - after(function(done) { - server.close(); - server = null; + it('should create async client without options', function (done) { + soap.createClientAsync(__dirname + '/wsdl/default_namespace.wsdl').then(function (client) { + assert.ok(client); done(); }); + }); - it('should return an error', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - client.MyOperation({}, function(err, result) { - assert.ok(err); - assert.ok(err.response); - assert.ok(err.body); + xit('should add namespace to array of objects', function (done) { + soap + .createClientAsync(__dirname + '/wsdl/PurchaseRequestService.wsdl') + .then(function (client) { + const input = { + errorProcessingLevel: 'ALL', + groupBy: 'SUPPLIER', + initiateApprovalAfterRequisitionImport: 'N', + interfaceSourceCode: 'ABC', + purchaseRequestPayload: { + ApproverEmail: 'abc@gmail.com', + ApproverId: 'idname', + PurchaseRequestInputReqLineInterface: [ + { + Amount: '600.00', + GroupCode: 'supplier', + ItemDescription: 'test1', + LineTypeId: 6, + ProductType: 'SERVICES', + RequestedDeliveryDate: '2021-02-26', + }, + { + Amount: '400.00', + GroupCode: 'supplier', + ItemDescription: 'test2', + LineTypeId: 7, + ProductType: 'SERVICES', + RequestedDeliveryDate: '2021-02-28', + }, + ], + }, + RequisitioningBUName: 'BU', + requisitioningBUName: 'BU', + }; + client.setSecurity(new soap.BasicAuthSecurity('username', 'password')); + client.createRequisition(input, function (err, result, rawResponse, soapHeader, rawRequest) { + const match = rawRequest.match(//); + if (match && match.length) { + assert.ok(match[0]); + } else { + assert.ok(null, `Array object don't have namesapce`); + } done(); }); - }, baseUrl); - }); + }) + .catch(function (err) { + assert.equal(err.message, 'Root element of WSDL was . This is likely an authentication issue.'); + done(); + }); }); +}); - describe('Client Events', function () { - var server = null; - var hostname = '127.0.0.1'; - var port = 15099; - var baseUrl = 'http://' + hostname + ":" + port; - - before(function(done) { - server = http.createServer(function (req, res) { +describe('Client using stream and returnSaxStream', () => { + let server = null; + let hostname = '127.0.0.1'; + let port = 15099; + let baseUrl = 'http://' + hostname + ':' + port; + const envelope = + '' + + 'Hello'; + + before(function (done) { + server = http + .createServer(function (req, res) { res.statusCode = 200; - fs.createReadStream(__dirname + '/soap-failure.xml').pipe(res); - }).listen(port, hostname, done); - }); + res.write(envelope, 'utf8'); + res.end(); + }) + .listen(port, hostname, done); + }); - after(function(done) { - server.close(); - server = null; - done(); - }); + after(function (done) { + server.close(); + server = null; + done(); + }); + + it('should return the saxStream', (done) => { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + { stream: true, returnSaxStream: true }, + (err, client) => { + assert.ok(client); + assert.ifError(err); + client.MyOperation( + {}, + (err, result) => { + const { saxStream } = result; + assert.ok(saxStream instanceof stream.Stream); + assert.ok(typeof saxStream.on === 'function'); + assert.ok(typeof saxStream.pipe === 'function'); - it('Should emit the "message" event with Soap Body string', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - var didEmitEvent = false; - client.on('message', function (xml) { - didEmitEvent = true; - // Should contain only message body - assert.equal(typeof xml, 'string'); - assert.equal(xml.indexOf('soap:Envelope'), -1); - }); + saxStream.on('text', (text) => { + assert.ok(text === 'Hello'); + }); - client.MyOperation({}, function() { - assert.ok(didEmitEvent); - done(); - }); - }, baseUrl); - }); + done(); + }, + null, + null, + ); + }, + baseUrl, + ); + }); +}); - it('Should emit the "request" event with entire XML message', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - var didEmitEvent = false; - client.on('request', function (xml) { - didEmitEvent = true; - // Should contain entire soap message - assert.equal(typeof xml, 'string'); - assert.notEqual(xml.indexOf('soap:Envelope'), -1); - }); +describe('Client posting complex body', () => { + let server = null; + let hostname = '127.0.0.1'; + let port = 15099; + let baseUrl = 'http://' + hostname + ':' + port; + const envelope = + '' + + 'Hello'; + + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 200; + res.write(envelope, 'utf8'); + res.end(); + }) + .listen(port, hostname, done); + }); - client.MyOperation({}, function() { - assert.ok(didEmitEvent); - done(); - }); - }, baseUrl); - }); + after(function (done) { + server.close(); + server = null; + done(); + }); - it('Should emit the "response" event with Soap Body string and Response object', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - var didEmitEvent = false; - client.on('response', function (xml, response) { - didEmitEvent = true; - // Should contain entire soap message - assert.equal(typeof xml, 'string'); - assert.equal(xml.indexOf('soap:Envelope'), -1); - assert.ok(response); - }); + it('should serialize complex body', function (done) { + soap.createClient( + __dirname + '/wsdl/complex/registration-common.wsdl', + function (err, client) { + if (err) { + return void done(err); + } + assert.ok(client); - client.MyOperation({}, function() { - assert.ok(didEmitEvent); - done(); - }); - }, baseUrl); - }); + var requestBody = { + id: 'ID00000000000000000000000000000000', + lastName: 'Doe', + firstName: 'John', + dateOfBirth: '1970-01-01', + correspondenceLanguage: 'ENG', + emailAddress: 'jdoe@doe.com', + lookupPermission: 'ALLOWED', + companyAddress: { + address: { + streetName: 'Street', + postalCode: 'Code', + city: 'City', + countryCode: 'US', + }, + companyName: 'ACME', + }, + }; + + client.registerUser(requestBody, function (err, result) { + assert.ok(client.lastRequest); + assert.ok(client.lastMessage); + assert.ok(client.lastEndpoint); + + // Commented out for production test due to verbosity. + //console.log(client.lastMessage); + const expectedBody = + 'ID00000000000000000000000000000000DoeJohn1970-01-01ENGjdoe@doe.comALLOWEDStreetCodeCityUSACME'; + assert.strictEqual(client.lastMessage, expectedBody); - it('should emit a \'soapError\' event', function (done) { - soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', function (err, client) { - var didEmitEvent = false; - client.on('soapError', function(err) { - didEmitEvent = true; - assert.ok(err.root.Envelope.Body.Fault); - }); - client.MyOperation({}, function(err, result) { - assert.ok(didEmitEvent); done(); }); - }, baseUrl); - }); + }, + baseUrl, + ); + }); +}); + +describe('Connection header', () => { + var server = null; + var hostname = '127.0.0.1'; + var port = 15099; + var baseUrl = 'http://' + hostname + ':' + port; + + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 200; + res.write(JSON.stringify({ tempResponse: 'temp' }), 'utf8'); + res.end(); + }) + .listen(port, hostname, done); + }); + after(function (done) { + server.close(); + server = null; + done(); }); - it('should return error in the call when Fault was returned', function(done) { - var server = null; - var hostname = '127.0.0.1'; - var port = 15099; - var baseUrl = 'http://' + hostname + ':' + port; - - server = http.createServer(function (req, res) { - res.statusCode = 200; - res.write("\nTesttest errortest detail"); - res.end(); - }).listen(port, hostname, function() { - soap.createClient(__dirname+'/wsdl/json_response.wsdl', function(err, client) { + it('should set Connection header to keep-alive when forever option is true', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + function (err, client) { assert.ok(client); - assert.ok(!err); - - client.MyOperation({}, function(err, result, body) { - server.close(); - server = null; - assert.ok(err); - assert.strictEqual(err.message, 'Test: test error: test detail'); - assert.ok(result); - assert.ok(body); - done(); - }); - }, baseUrl); - }); + assert.ifError(err); + client.MyOperation( + {}, + { forever: true }, + function () { + assert.strictEqual(client.lastRequestHeaders.Connection, 'keep-alive'); + done(); + }, + null, + null, + ); + }, + baseUrl, + ); + }); + it('should not set Connection header when forever option is false', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + function (err, client) { + assert.ok(client); + assert.ifError(err); + client.MyOperation( + {}, + { forever: false }, + function () { + assert.strictEqual(client.lastRequestHeaders.Connection, undefined); + done(); + }, + null, + null, + ); + }, + baseUrl, + ); }); + it('should not set Connection header when forever option is not set', function (done) { + soap.createClient( + __dirname + '/wsdl/default_namespace.wsdl', + function (err, client) { + assert.ok(client); + assert.ifError(err); + + client.MyOperation( + {}, + function () { + assert.strictEqual(client.lastRequestHeaders.Connection, undefined); + done(); + }, + null, + null, + ); + }, + baseUrl, + ); + }); }); diff --git a/test/express-server-test.js b/test/express-server-test.js new file mode 100644 index 000000000..54b0f87d4 --- /dev/null +++ b/test/express-server-test.js @@ -0,0 +1,219 @@ +'use strict'; + +var assert = require('assert'); +var express = require('express'); +var bodyParser = require('body-parser'); +var soap = require('../'); +const axios = require('axios'); +var expressServer; +var server; +var port; +var url; +var wsdl = + 'WSDL File for HelloService'; +var requestXML = '' + '' + '' + 'tarun' + '' + '' + ''; +var responseXML = + '' + + '' + + '' + + '' + + 'tarun' + + '' + + '' + + ''; + +describe('Express server without middleware', function () { + before(function (done) { + var service = { + Hello_Service: { + Hello_Port: { + sayHello: function (args) { + return { + greeting: args.firstName, + }; + }, + }, + }, + }; + + expressServer = express(); + server = expressServer.listen(51515, function () { + var soapServer = soap.listen(expressServer, '/SayHello', service, wsdl); + url = 'http://' + server.address().address + ':' + server.address().port; + if (server.address().address === '0.0.0.0' || server.address().address === '::') { + url = 'http://127.0.0.1:' + server.address().port; + } + done(); + }); + }); + + after(function () { + server.close(); + }); + + it('should handle body without middleware', function (done) { + axios + .post(url + '/SayHello', requestXML, { + headers: { + 'SOAPAction': 'sayHello', + 'Content-Type': 'text/xml; charset="utf-8"', + }, + }) + .then((res) => { + assert.equal(res.data, responseXML); + done(); + }) + .catch((err) => { + throw err; + }); + }); + + it('should serve wsdl', function (done) { + axios + .get(url + '/SayHello?wsdl', { + headers: { + 'Content-Type': 'text/xml; charset="utf-8"', + }, + }) + .then((res) => { + assert.equal(res.data, wsdl); + done(); + }) + .catch((err) => { + throw err; + }); + }); + + it('should handle other routes as usual', function (done) { + expressServer.route('/test/r1').get( + function (req, res, next) { + //make sure next() works as well + return next(); + }, + function (req, res) { + return res.status(200).send('test passed'); + }, + ); + + axios + .get(url + '/test/r1') + .then((res) => { + assert.equal(res.data, 'test passed'); + done(); + }) + .catch((err) => { + throw err; + }); + }); +}); + +describe('Express server with middleware', function () { + before(function (done) { + var wsdl = + 'WSDL File for HelloService'; + var service = { + Hello_Service: { + Hello_Port: { + sayHello: function (args) { + return { + greeting: args.firstName, + }; + }, + }, + }, + }; + expressServer = express(); + expressServer.use( + bodyParser.raw({ + type: function () { + return true; + }, + limit: '5mb', + }), + ); + + server = expressServer.listen(51515, function () { + var soapServer = soap.listen(expressServer, '/SayHello', service, wsdl); + url = 'http://' + server.address().address + ':' + server.address().port; + + if (server.address().address === '0.0.0.0' || server.address().address === '::') { + url = 'http://127.0.0.1:' + server.address().port; + } + + done(); + }); + }); + + after(function () { + server.close(); + }); + + it('should allow parsing body via express middleware', function (done) { + axios + .post(url + '/SayHello', requestXML, { + headers: { + 'SOAPAction': 'sayHello', + 'Content-Type': 'text/xml; charset="utf-8"', + }, + }) + .then((res) => { + assert.equal(res.data, responseXML); + done(); + }) + .catch((err) => { + throw err; + }); + }); +}); + +describe('Express server with bodyParser.json middleware', function () { + before(function (done) { + var wsdl = + 'WSDL File for HelloService'; + var service = { + Hello_Service: { + Hello_Port: { + sayHello: function (args) { + return { + greeting: args.firstName, + }; + }, + }, + }, + }; + expressServer = express(); + expressServer.use(bodyParser.json()); + + server = expressServer.listen(51515, function () { + var soapServer = soap.listen(expressServer, '/SayHello', service, wsdl); + url = 'http://' + server.address().address + ':' + server.address().port; + + if (server.address().address === '0.0.0.0' || server.address().address === '::') { + url = 'http://127.0.0.1:' + server.address().port; + } + + done(); + }); + }); + + after(function () { + server.close(); + }); + + it('should not parse body on bodyParser.json middleware', function (done) { + axios + .post(url + '/SayHello', requestXML, { + headers: { + 'SOAPAction': 'sayHello', + 'Content-Type': 'text/xml; charset="utf-8"', + }, + }) + .then((res) => { + assert.equal(res.data, responseXML); + done(); + }) + .catch((err) => { + throw err; + }); + }); +}); diff --git a/test/header-rely-on-xml-test.js b/test/header-rely-on-xml-test.js new file mode 100644 index 000000000..5cc47c4d4 --- /dev/null +++ b/test/header-rely-on-xml-test.js @@ -0,0 +1,64 @@ +'use strict'; + +var soap = require('..'), + http = require('http'), + assert = require('assert'); + +describe('testing adding header rely on completed xml', () => { + let server = null; + let hostname = '127.0.0.1'; + let port = 15099; + let baseUrl = 'http://' + hostname + ':' + port; + const envelope = + '' + + 'Hello'; + + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 200; + res.write(envelope, 'utf8'); + res.end(); + }) + .listen(port, hostname, done); + }); + + after(function (done) { + server.close(); + server = null; + done(); + }); + + it('should add header to request, which created from xml before request', function (done) { + soap.createClient( + __dirname + '/wsdl/complex/registration-common.wsdl', + function (err, client) { + if (err) { + return void done(err); + } + assert.ok(client); + + const testHeaderKey = 'testHeader'; + let testHeaderValue; + + client.on('request', (xml) => { + testHeaderValue = xml; + client.addHttpHeader(testHeaderKey, xml); + }); + + client.registerUser('', function (err, result) { + const header = result.request._header; + const headerKey = header.includes(testHeaderKey); + const headerValue = header.includes(testHeaderValue); + + assert.equal(headerKey, true); + assert.equal(headerValue, true); + done(); + }); + }, + baseUrl, + ); + }); +}); diff --git a/test/mocha.opts b/test/mocha.opts index 2da27607a..0466b212e 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,3 +1,4 @@ --R spec --u exports --r should +--reporter spec +--ui bdd +--require should +--require source-map-support/register diff --git a/test/post-data-concat-test.js b/test/post-data-concat-test.js new file mode 100644 index 000000000..69200f3e9 --- /dev/null +++ b/test/post-data-concat-test.js @@ -0,0 +1,60 @@ +'use strict'; + +var fs = require('fs'); +var soap = require('..'); +var assert = require('assert'); +var http = require('http'); + +describe('post data concat test', function () { + var server = http.createServer(function (req, res) {}); + + before(function () { + server.listen(51515); + }); + + after(function () { + server.close(); + }); + + it('should consider the situation about multi-byte character between two tcp packets', function (done) { + var check = function (a, b) { + if (a && b) { + assert(a === b); + done(); + } + }; + + var wsdl = 'test/wsdl/default_namespace.wsdl'; + var xml = fs.readFileSync(wsdl, 'utf8'); + var service = { + MyService: { + MyServicePort: { + MyOperation: function (arg) { + check(arg, postdata); + return '0'; + }, + }, + }, + }; + + soap.listen(server, '/wsdl', service, xml); + + var postdata = ''; + for (var i = 0; i < 20000; i++) { + postdata += '测试'; + } + + soap.createClient( + wsdl, + { + endpoint: 'http://localhost:51515/wsdl', + }, + function (error, client) { + assert(!error); + client.MyOperation(postdata, function (error, response) { + assert(!error); + }); + }, + ); + }); +}); diff --git a/test/request-no-envelope-body-test.js b/test/request-no-envelope-body-test.js new file mode 100644 index 000000000..b47ff0905 --- /dev/null +++ b/test/request-no-envelope-body-test.js @@ -0,0 +1,67 @@ +'use strict'; + +var assert = require('assert'); +var http = require('http'); +var soap = require('../'); +const { default: axios } = require('axios'); +var server; +var port; + +describe('No envelope and body elements', function () { + var wsdl = + 'WSDL File for HelloService'; + before(function (done) { + server = http + .createServer(function (req, res) { + res.statusCode = 404; + res.end(); + }) + .listen(51515, function () { + var soapServer = soap.listen( + server, + '/SayHello', + { + Hello_Service: { + Hello_Port: { + sayHello: function (args) { + return { + greeting: args.firstName, + }; + }, + }, + }, + }, + wsdl, + ); + done(); + }); + }); + + after(function () { + server.close(); + }); + + it('should throw an error when Body and Envelope are missing', function (done) { + var requestXML = 'tarun'; + var url = 'http://' + server.address().address + ':' + server.address().port; + + if (server.address().address === '0.0.0.0' || server.address().address === '::') { + url = 'http://127.0.0.1:' + server.address().port; + } + + axios + .post(url + '/SayHello', requestXML, { + headers: { + 'SOAPAction': 'sayHello', + 'Content-Type': 'text/xml; charset="utf-8"', + }, + }) + .then((res) => { + throw new Error(`Request must fail`); + }) + .catch((err) => { + assert.equal(err?.response?.data.indexOf('Failed to parse the SOAP Message body') !== -1, true); + done(); + }); + }); +}); diff --git a/test/request-response-samples-test.js b/test/request-response-samples-test.js index 584bddc65..07d4a907d 100644 --- a/test/request-response-samples-test.js +++ b/test/request-response-samples-test.js @@ -1,44 +1,47 @@ 'use strict'; var assert = require('assert'); -var fs = require('fs'); -var glob = require('glob'); +var fs = require('fs'); +var glob = require('glob'); var http = require('http'); var path = require('path'); var timekeeper = require('timekeeper'); var jsdiff = require('diff'); require('colors'); var soap = require('../'); -var WSSecurity = require('../lib/security/WSSecurity'); +var WSSecurity = require('../lib/security').WSSecurity; var server; var port; -var tests = glob.sync('./request-response-samples/*', {cwd:__dirname}) - .map(function(node){return path.resolve(__dirname, node);}) - .filter(function(node){return fs.statSync(node).isDirectory();}); +var tests = glob + .sync('./request-response-samples/*', { cwd: __dirname }) + .map(function (node) { + return path.resolve(__dirname, node); + }) + .filter(function (node) { + return fs.statSync(node).isDirectory(); + }); var suite = {}; -function normalizeWhiteSpace(raw) -{ - var normalized = raw.replace(/\r\n|\r|\n/g, ''); // strip line endings +function normalizeWhiteSpace(raw) { + var normalized = raw.replace(/\r\n|\r|\n/g, ''); // strip line endings normalized = normalized.replace(/\s\s+/g, ' '); // convert whitespace to spaces - normalized = normalized.replace(/> <'); // get rid of spaces between elements + normalized = normalized.replace(/> <'); // get rid of spaces between elements return normalized; } var requestContext = { //set these two within each test - expectedRequest:null, - responseToSend:null, - doneHandler:null, - requestHandler:function(req, res){ + expectedRequest: null, + responseToSend: null, + doneHandler: null, + requestHandler: function (req, res) { var chunks = []; - req.on('data', function(chunk){ + req.on('data', function (chunk) { // ignore eol on sample files. chunks.push(chunk.toString().replace(/\r?\n$/m, '')); }); - req.on('end', function(){ - if(!requestContext.expectedRequest)return res.end(requestContext.responseToSend); - if(!requestContext.responseToSend)return requestContext.doneHandler(); + req.on('end', function () { + if (!requestContext.expectedRequest) return res.end(requestContext.responseToSend); var actualRequest = normalizeWhiteSpace(chunks.join('')); var expectedRequest = normalizeWhiteSpace(requestContext.expectedRequest); @@ -46,24 +49,36 @@ var requestContext = { if (actualRequest !== expectedRequest) { var diff = jsdiff.diffChars(actualRequest, expectedRequest); var comparison = ''; - diff.forEach(function(part) { + diff.forEach(function (part) { var color = 'grey'; - if (part.added) { color = 'green'; } - if (part.removed) { color = 'red'; } + if (part.added) { + color = 'green'; + } + if (part.removed) { + color = 'red'; + } comparison += part.value[color]; }); console.log(comparison); } assert.equal(actualRequest, expectedRequest); + + if (!requestContext.responseToSend) return requestContext.doneHandler(); + if (requestContext.responseHttpHeaders) { + for (const headerKey in requestContext.responseHttpHeaders) { + res.setHeader(headerKey, requestContext.responseHttpHeaders[headerKey]); + } + } res.end(requestContext.responseToSend); + requestContext.expectedRequest = null; requestContext.responseToSend = null; }); - } + }, }; -tests.forEach(function(test){ +tests.forEach(function (test) { var nameParts = path.basename(test).split('__'); var name = nameParts[1].replace(/_/g, ' '); var methodName = nameParts[0]; @@ -78,107 +93,207 @@ tests.forEach(function(test){ var responseXML = path.resolve(test, 'response.xml'); var options = path.resolve(test, 'options.json'); var wsdlOptionsFile = path.resolve(test, 'wsdl_options.json'); + var wsdlJSOptionsFile = path.resolve(test, 'wsdl_options.js'); + var responseHttpHeaders = path.resolve(test, 'responseHttpHeader.json'); + var attachmentParts = path.resolve(test, 'attachmentParts.js'); var wsdlOptions = {}; //headerJSON is optional - if(fs.existsSync(headerJSON))headerJSON = require(headerJSON); + if (fs.existsSync(headerJSON)) headerJSON = require(headerJSON); else headerJSON = {}; //securityJSON is optional - if(fs.existsSync(securityJSON))securityJSON = require(securityJSON); + if (fs.existsSync(securityJSON)) securityJSON = require(securityJSON); else securityJSON = {}; //responseJSON is optional - if (fs.existsSync(responseJSON))responseJSON = require(responseJSON); - else if(fs.existsSync(responseJSONError))responseJSON = require(responseJSONError); + if (fs.existsSync(responseJSON)) responseJSON = require(responseJSON); + else if (fs.existsSync(responseJSONError)) responseJSON = require(responseJSONError); else responseJSON = null; //responseSoapHeaderJSON is optional - if (fs.existsSync(responseSoapHeaderJSON))responseSoapHeaderJSON = require(responseSoapHeaderJSON); + if (fs.existsSync(responseSoapHeaderJSON)) responseSoapHeaderJSON = require(responseSoapHeaderJSON); else responseSoapHeaderJSON = null; //requestXML is optional - if(fs.existsSync(requestXML))requestXML = ''+fs.readFileSync(requestXML); + if (fs.existsSync(requestXML)) requestXML = '' + fs.readFileSync(requestXML); else requestXML = null; //responseXML is optional - if(fs.existsSync(responseXML))responseXML = ''+fs.readFileSync(responseXML); + if (fs.existsSync(responseXML)) responseXML = '' + fs.readFileSync(responseXML); else responseXML = null; //requestJSON is required as node-soap will expect a request object anyway requestJSON = require(requestJSON); //options is optional - if (fs.existsSync(options))options = require(options); + if (fs.existsSync(options)) options = require(options); else options = {}; //wsdlOptions is optional - if(fs.existsSync(wsdlOptionsFile)) wsdlOptions = require(wsdlOptionsFile); + if (fs.existsSync(wsdlOptionsFile)) wsdlOptions = require(wsdlOptionsFile); + else if (fs.existsSync(wsdlJSOptionsFile)) wsdlOptions = require(wsdlJSOptionsFile); else wsdlOptions = {}; - generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options); + //responseHttpHeaders + if (fs.existsSync(responseHttpHeaders)) responseHttpHeaders = require(responseHttpHeaders); + else responseHttpHeaders = null; + + //attachmentParts + if (fs.existsSync(attachmentParts)) attachmentParts = require(attachmentParts); + else attachmentParts = null; + + generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, false); + generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, true); }); -function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options){ - suite[name] = function(done){ - if(requestXML) requestContext.expectedRequest = requestXML; - if(responseXML) requestContext.responseToSend = responseXML; - requestContext.doneHandler = done; - soap.createClient(wsdlPath, wsdlOptions, function(err, client){ - if (headerJSON) { - for (var headerKey in headerJSON) { - client.addSoapHeader(headerJSON[headerKey], headerKey); - } +function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, usePromises) { + var methodCaller = cbCaller; + + if (usePromises) { + name += ' (promisified)'; + methodName += 'Async'; + methodCaller = promiseCaller; + } + + suite[name] = function (done) { + if (requestXML) { + // Override the expect request's keys to match + if (wsdlOptions.overrideElementKey) { + requestXML = requestXML.replace(/:Commande/g, ':Order'); + requestXML = requestXML.replace(/:Nom/g, ':Name'); } - if (securityJSON && securityJSON.type === 'ws') { - client.setSecurity(new WSSecurity(securityJSON.username, securityJSON.password, securityJSON.options)); + requestContext.expectedRequest = requestXML; + } + + if (responseXML) { + if (wsdlOptions.parseReponseAttachments) { + //all LF to CRLF + responseXML = responseXML.replace(/\r\n/g, '\n'); + responseXML = responseXML.replace(/\n/g, '\r\n'); + } + // Override the expect request's keys to match + if (wsdlOptions.overrideElementKey) { + responseXML = responseXML.replace(/SillyResponse/g, 'DummyResponse'); } - client[methodName](requestJSON, function(err, json, body, soapHeader){ - if(requestJSON){ + requestContext.responseToSend = responseXML; + } + requestContext.doneHandler = done; + requestContext.responseHttpHeaders = responseHttpHeaders; + soap.createClient( + wsdlPath, + wsdlOptions, + function (err, client) { + if (headerJSON) { + for (var headerKey in headerJSON) { + client.addSoapHeader(headerJSON[headerKey], headerKey); + } + } + if (securityJSON && securityJSON.type === 'ws') { + client.setSecurity(new WSSecurity(securityJSON.username, securityJSON.password, securityJSON.options)); + } + + //throw more meaningful error + if (typeof client[methodName] !== 'function') { + throw new Error('method ' + methodName + ' does not exists in wsdl specified in test wsdl: ' + wsdlPath); + } + + methodCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done); + }, + 'http://localhost:' + port + '/Message/Message.dll?Handler=Default', + ); + }; +} + +function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done) { + client[methodName]( + requestJSON, + function (err, json, body, soapHeader) { + try { + if (requestJSON) { if (err) { assert.notEqual('undefined: undefined', err.message); assert.deepEqual(err.root, responseJSON); } else { // assert.deepEqual(json, responseJSON); assert.equal(JSON.stringify(typeof json === 'undefined' ? null : json), JSON.stringify(responseJSON)); - if(responseSoapHeaderJSON){ + if (responseSoapHeaderJSON) { assert.equal(JSON.stringify(soapHeader), JSON.stringify(responseSoapHeaderJSON)); } + if (client.lastResponseAttachments) { + assert.deepEqual(client.lastResponseAttachments.parts, attachmentParts); + } } } - done(); - }, options); - }, 'http://localhost:'+port+'/Message/Message.dll?Handler=Default'); - }; + } catch (err) { + done(err); + throw err; + } + done(); + }, + options, + ); +} + +function promiseCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done) { + client[methodName](requestJSON) + .then(function (responseArr) { + const respAttachments = client.lastResponseAttachments; + var json = responseArr[0]; + var body = responseArr[1]; + var soapHeader = responseArr[2]; + + if (requestJSON) { + // assert.deepEqual(json, responseJSON); + assert.equal(JSON.stringify(typeof json === 'undefined' ? null : json), JSON.stringify(responseJSON)); + if (responseSoapHeaderJSON) { + assert.equal(JSON.stringify(soapHeader), JSON.stringify(responseSoapHeaderJSON)); + } + if (client.lastResponseAttachments) { + assert.deepEqual(client.lastResponseAttachments.parts, attachmentParts); + } + } + }) + .catch(function (err) { + if (requestJSON) { + assert.notEqual('undefined: undefined', err.message); + assert.deepEqual(err.root, responseJSON); + } + }) + .finally(function () { + done(); + }); } -describe('Request Response Sampling', function() { +describe('Request Response Sampling', function () { var origRandom = Math.random; - before(function(done){ + before(function (done) { timekeeper.freeze(Date.parse('2014-10-12T01:02:03Z')); - Math.random = function() { return 1; }; + Math.random = function () { + return 1; + }; server = http.createServer(requestContext.requestHandler); - server.listen(0, function(e){ - if(e)return done(e); + server.listen(0, function (e) { + if (e) return done(e); port = server.address().port; done(); }); }); - beforeEach(function(){ + beforeEach(function () { requestContext.expectedRequest = null; requestContext.responseToSend = null; requestContext.doneHandler = null; }); - after(function(){ + after(function () { timekeeper.reset(); Math.random = origRandom; server.close(); }); - Object.keys(suite).map(function(key) { + Object.keys(suite).map(function (key) { it(key, suite[key]); }); }); diff --git a/test/request-response-samples/DefaultNamespace__no_xmlns_prefix_used_for_default_namespace/request.json b/test/request-response-samples/DefaultNamespace__no_xmlns_prefix_used_for_default_namespace/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/DefaultNamespace__no_xmlns_prefix_used_for_default_namespace/request.json +++ b/test/request-response-samples/DefaultNamespace__no_xmlns_prefix_used_for_default_namespace/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/common.xsd b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/common.xsd new file mode 100644 index 000000000..72eea4e7e --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/request.json b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/request.json new file mode 100644 index 000000000..cef130963 --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/request.json @@ -0,0 +1,6 @@ +{ + "Order": { + "Id": 1, + "Name": "foo" + } +} diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/request.xml b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/request.xml new file mode 100644 index 000000000..7742c3cd1 --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/request.xml @@ -0,0 +1,19 @@ + + + + + + 1 + foo + + + + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/response.json b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/response.json new file mode 100644 index 000000000..12245a38c --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/response.json @@ -0,0 +1,6 @@ +{ + "Result": { + "Status": 200, + "Message": "OK" + } +} diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/response.xml b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/response.xml new file mode 100644 index 000000000..22040a55a --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/response.xml @@ -0,0 +1,17 @@ +--MIMEBoundary_2af39b87d6c9f2ba6d1c13d73db88d0bfdf9414786fcc315 +Content-Type: application/xop+xml; charset=UTF-8; type="text/xml" +Content-Transfer-Encoding: binary +Content-ID: <0.3af39b87d6c9f2ba6d1c13d73db88d0bfdf9414786fcc315@apache.org> + + + + + + + 200 + OK + + + + +--MIMEBoundary_2af39b87d6c9f2ba6d1c13d73db88d0bfdf9414786fcc315-- \ No newline at end of file diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/soap.wsdl b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/soap.wsdl new file mode 100644 index 000000000..66007ff90 --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace/soap.wsdl @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/common.xsd b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/common.xsd new file mode 100644 index 000000000..72eea4e7e --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/request.json b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/request.json new file mode 100644 index 000000000..64b4c0bcf --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/request.json @@ -0,0 +1,6 @@ +{ + "Commande": { + "Id": 1, + "Nom": "foo" + } +} diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/request.xml b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/request.xml new file mode 100644 index 000000000..00c756037 --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/request.xml @@ -0,0 +1,19 @@ + + + + + + 1 + foo + + + + diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/response.json b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/response.json new file mode 100644 index 000000000..12245a38c --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/response.json @@ -0,0 +1,6 @@ +{ + "Result": { + "Status": 200, + "Message": "OK" + } +} diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/response.xml b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/response.xml new file mode 100644 index 000000000..cf4c5d14d --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/response.xml @@ -0,0 +1,17 @@ +--MIMEBoundary_2af39b87d6c9f2ba6d1c13d73db88d0bfdf9414786fcc315 +Content-Type: application/xop+xml; charset=UTF-8; type="text/xml" +Content-Transfer-Encoding: binary +Content-ID: <0.3af39b87d6c9f2ba6d1c13d73db88d0bfdf9414786fcc315@apache.org> + + + + + + + 200 + OK + + + + +--MIMEBoundary_2af39b87d6c9f2ba6d1c13d73db88d0bfdf9414786fcc315-- diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/soap.wsdl b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/soap.wsdl new file mode 100644 index 000000000..66007ff90 --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/soap.wsdl @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/wsdl_options.js b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/wsdl_options.js new file mode 100644 index 000000000..a6e492f26 --- /dev/null +++ b/test/request-response-samples/Dummy__ref_element_should_have_correct_namespace_with_overrideElementKey/wsdl_options.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.overrideElementKey = { Nom: 'Name', Commande: 'Order', SillyResponse: 'DummyResponse' }; diff --git a/test/request-response-samples/Dummy__should_add_prefix_for_unqualified_global_elements/request.json b/test/request-response-samples/Dummy__should_add_prefix_for_unqualified_global_elements/request.json index 21af9df45..ad71ebab1 100644 --- a/test/request-response-samples/Dummy__should_add_prefix_for_unqualified_global_elements/request.json +++ b/test/request-response-samples/Dummy__should_add_prefix_for_unqualified_global_elements/request.json @@ -1,6 +1,6 @@ { "DummyField1": { - "$value": "Humpty", + "$value": "Humpty", "attributes": { "language": "en-US" } diff --git a/test/request-response-samples/Dummy__should_deserialize_basic_types/common.xsd b/test/request-response-samples/Dummy__should_deserialize_basic_types/common.xsd new file mode 100644 index 000000000..e04c0710b --- /dev/null +++ b/test/request-response-samples/Dummy__should_deserialize_basic_types/common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_deserialize_basic_types/name.xsd b/test/request-response-samples/Dummy__should_deserialize_basic_types/name.xsd new file mode 100644 index 000000000..4701b66a8 --- /dev/null +++ b/test/request-response-samples/Dummy__should_deserialize_basic_types/name.xsd @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_deserialize_basic_types/request.json b/test/request-response-samples/Dummy__should_deserialize_basic_types/request.json new file mode 100644 index 000000000..3833eb5ce --- /dev/null +++ b/test/request-response-samples/Dummy__should_deserialize_basic_types/request.json @@ -0,0 +1,3 @@ +{ + "DummyField1": "foo & bar" +} diff --git a/test/request-response-samples/Dummy__should_deserialize_basic_types/request.xml b/test/request-response-samples/Dummy__should_deserialize_basic_types/request.xml new file mode 100644 index 000000000..8f783b787 --- /dev/null +++ b/test/request-response-samples/Dummy__should_deserialize_basic_types/request.xml @@ -0,0 +1,8 @@ + + + + + foo & bar + + + diff --git a/test/request-response-samples/Dummy__should_deserialize_basic_types/response.json b/test/request-response-samples/Dummy__should_deserialize_basic_types/response.json new file mode 100644 index 000000000..fdcedc910 --- /dev/null +++ b/test/request-response-samples/Dummy__should_deserialize_basic_types/response.json @@ -0,0 +1,10 @@ +{ + "boolean": true, + "decimal": 1.1, + "double": 1.21, + "float": 1.321, + "int": 1, + "short": 3, + "long": 60000000000, + "string": "foo" +} diff --git a/test/request-response-samples/Dummy__should_deserialize_basic_types/response.xml b/test/request-response-samples/Dummy__should_deserialize_basic_types/response.xml new file mode 100644 index 000000000..40b8400d6 --- /dev/null +++ b/test/request-response-samples/Dummy__should_deserialize_basic_types/response.xml @@ -0,0 +1,15 @@ + + + + + true + 1.1 + 1.21 + 1.321 + 1 + 3 + 60000000000 + foo + + + diff --git a/test/request-response-samples/Dummy__should_deserialize_basic_types/soap.wsdl b/test/request-response-samples/Dummy__should_deserialize_basic_types/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_deserialize_basic_types/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_escape_xml/common.xsd b/test/request-response-samples/Dummy__should_escape_xml/common.xsd new file mode 100644 index 000000000..e04c0710b --- /dev/null +++ b/test/request-response-samples/Dummy__should_escape_xml/common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_escape_xml/name.xsd b/test/request-response-samples/Dummy__should_escape_xml/name.xsd new file mode 100644 index 000000000..a515b88c3 --- /dev/null +++ b/test/request-response-samples/Dummy__should_escape_xml/name.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_escape_xml/request.json b/test/request-response-samples/Dummy__should_escape_xml/request.json new file mode 100644 index 000000000..1fa70bbfc --- /dev/null +++ b/test/request-response-samples/Dummy__should_escape_xml/request.json @@ -0,0 +1,6 @@ +{ + "DummyField1": "foo & bar", + "DummyFilter": { + "DummyStringFilter": null + } +} diff --git a/test/request-response-samples/Dummy__should_escape_xml/request.xml b/test/request-response-samples/Dummy__should_escape_xml/request.xml new file mode 100644 index 000000000..8c1c16dbe --- /dev/null +++ b/test/request-response-samples/Dummy__should_escape_xml/request.xml @@ -0,0 +1,12 @@ + + + + + foo & bar + + + + + + + diff --git a/test/request-response-samples/Dummy__should_escape_xml/response.json b/test/request-response-samples/Dummy__should_escape_xml/response.json new file mode 100644 index 000000000..72d022f25 --- /dev/null +++ b/test/request-response-samples/Dummy__should_escape_xml/response.json @@ -0,0 +1,5 @@ +{ + "DummyResult": { + "DummyList": null + } +} diff --git a/test/request-response-samples/Dummy__should_escape_xml/response.xml b/test/request-response-samples/Dummy__should_escape_xml/response.xml new file mode 100644 index 000000000..5417014e2 --- /dev/null +++ b/test/request-response-samples/Dummy__should_escape_xml/response.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_escape_xml/soap.wsdl b/test/request-response-samples/Dummy__should_escape_xml/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_escape_xml/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_extract_envelope_from_response/response.json b/test/request-response-samples/Dummy__should_extract_envelope_from_response/response.json index a82eeb23f..46466b717 100644 --- a/test/request-response-samples/Dummy__should_extract_envelope_from_response/response.json +++ b/test/request-response-samples/Dummy__should_extract_envelope_from_response/response.json @@ -9,4 +9,4 @@ } } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_handle_attributes_in_request/request.json b/test/request-response-samples/Dummy__should_handle_attributes_in_request/request.json index 21af9df45..ad71ebab1 100644 --- a/test/request-response-samples/Dummy__should_handle_attributes_in_request/request.json +++ b/test/request-response-samples/Dummy__should_handle_attributes_in_request/request.json @@ -1,6 +1,6 @@ { "DummyField1": { - "$value": "Humpty", + "$value": "Humpty", "attributes": { "language": "en-US" } diff --git a/test/request-response-samples/Dummy__should_handle_attributes_in_response/response.json b/test/request-response-samples/Dummy__should_handle_attributes_in_response/response.json index a82eeb23f..46466b717 100644 --- a/test/request-response-samples/Dummy__should_handle_attributes_in_response/response.json +++ b/test/request-response-samples/Dummy__should_handle_attributes_in_response/response.json @@ -9,4 +9,4 @@ } } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_handle_cdata_xml_in_response/response.json b/test/request-response-samples/Dummy__should_handle_cdata_xml_in_response/response.json index 49aa39869..4d71962fb 100644 --- a/test/request-response-samples/Dummy__should_handle_cdata_xml_in_response/response.json +++ b/test/request-response-samples/Dummy__should_handle_cdata_xml_in_response/response.json @@ -6,20 +6,20 @@ "language": "en-US" }, "$value": { - "response": { - "forms": { - "form": { - "attributes": { - "ObjectId": "1234", - "Form_Name": "Dummy Form" - }, - "First_Name": "Humpty", - "Last_Name": "Dumpty" - } - } - } - } - } + "response": { + "forms": { + "form": { + "attributes": { + "ObjectId": "1234", + "Form_Name": "Dummy Form" + }, + "First_Name": "Humpty", + "Last_Name": "Dumpty" + } + } + } + } + } } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_handle_inline_types/name.xsd b/test/request-response-samples/Dummy__should_handle_inline_types/name.xsd new file mode 100644 index 000000000..b333da739 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_inline_types/name.xsd @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_inline_types/request.json b/test/request-response-samples/Dummy__should_handle_inline_types/request.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_inline_types/request.json @@ -0,0 +1 @@ +{} diff --git a/test/request-response-samples/Dummy__should_handle_inline_types/request.xml b/test/request-response-samples/Dummy__should_handle_inline_types/request.xml new file mode 100644 index 000000000..f683df500 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_inline_types/request.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_inline_types/response.json b/test/request-response-samples/Dummy__should_handle_inline_types/response.json new file mode 100644 index 000000000..554b9c994 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_inline_types/response.json @@ -0,0 +1,11 @@ +{ + "SimpleBoolean": true, + "InlineBoolean": true, + "SimpleInt": 4, + "InlineInt": 4, + "SimpleDate": "2018-07-21T00:00:00.000Z", + "SimpleDateTime": "2018-07-21T00:00:00.000Z", + "SimpleTimeHourMinute": 150, + "NamedNestedSimpleType": 240, + "SimpleEnum": 2 +} diff --git a/test/request-response-samples/Dummy__should_handle_inline_types/response.xml b/test/request-response-samples/Dummy__should_handle_inline_types/response.xml new file mode 100644 index 000000000..353c4285f --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_inline_types/response.xml @@ -0,0 +1,20 @@ + + + + + true + true + 4 + 4 + 2018-07-21 + 2018-07-21 + 02:30 + 04:00 + 2 + + + diff --git a/test/request-response-samples/Dummy__should_handle_inline_types/soap.wsdl b/test/request-response-samples/Dummy__should_handle_inline_types/soap.wsdl new file mode 100644 index 000000000..21b58a1b9 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_inline_types/soap.wsdl @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_inline_types/wsdl_options.js b/test/request-response-samples/Dummy__should_handle_inline_types/wsdl_options.js new file mode 100644 index 000000000..d055cdb20 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_inline_types/wsdl_options.js @@ -0,0 +1,13 @@ +exports.customDeserializer = { + DateTime: (text) => new Date(text), + TimeHourMinute: (text) => { + // Return number of minutes since midnight + const results = text.split(':').map((t) => parseInt(t, 10)); + return results[0] * 60 + results[1]; + }, + NestedSimpleType: (text) => { + // Return number of minutes since midnight + const results = text.split(':').map((t) => parseInt(t, 10)); + return results[0] * 60 + results[1]; + }, +}; diff --git a/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/name.xsd b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/name.xsd new file mode 100644 index 000000000..2e7042b2f --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/name.xsd @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/request.json b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/request.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/request.json @@ -0,0 +1 @@ +{} diff --git a/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/request.xml b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/request.xml new file mode 100644 index 000000000..d0b974100 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/request.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/response.json b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/response.json new file mode 100644 index 000000000..a3f3147aa --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/response.json @@ -0,0 +1,14 @@ +{ + "DummyList_MaxUnbounded": [ + { + "DummyFirst": "foo", + "DummySecond": "foo" + } + ], + "DummyList_MaxInt": [ + { + "DummyFirst": "foo", + "DummySecond": "foo" + } + ] +} diff --git a/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/response.xml b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/response.xml new file mode 100644 index 000000000..a0b964b44 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/response.xml @@ -0,0 +1,15 @@ + + + + + + foo + foo + + + foo + foo + + + + diff --git a/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/soap.wsdl b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/soap.wsdl new file mode 100644 index 000000000..b3df596fc --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_minOccurs_and_maxOccurs/soap.wsdl @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_nil_as_null/common.xsd b/test/request-response-samples/Dummy__should_handle_nil_as_null/common.xsd new file mode 100644 index 000000000..e04c0710b --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_as_null/common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_nil_as_null/name.xsd b/test/request-response-samples/Dummy__should_handle_nil_as_null/name.xsd new file mode 100644 index 000000000..a515b88c3 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_as_null/name.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_nil_as_null/request.json b/test/request-response-samples/Dummy__should_handle_nil_as_null/request.json new file mode 100644 index 000000000..52d6f57f7 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_as_null/request.json @@ -0,0 +1,6 @@ +{ + "DummyField1": "Humpty", + "DummyFilter": { + "DummyStringFilter": "Dumpty" + } +} diff --git a/test/request-response-samples/Dummy__should_handle_nil_as_null/request.xml b/test/request-response-samples/Dummy__should_handle_nil_as_null/request.xml new file mode 100644 index 000000000..b4ceed77f --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_as_null/request.xml @@ -0,0 +1 @@ +HumptyDumpty \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_handle_nil_as_null/response.json b/test/request-response-samples/Dummy__should_handle_nil_as_null/response.json new file mode 100644 index 000000000..ebdf90ab6 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_as_null/response.json @@ -0,0 +1,7 @@ +{ + "DummyResult": { + "DummyList": { + "DummyElement": null + } + } +} diff --git a/test/request-response-samples/Dummy__should_handle_nil_as_null/response.xml b/test/request-response-samples/Dummy__should_handle_nil_as_null/response.xml new file mode 100644 index 000000000..5417014e2 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_as_null/response.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_nil_as_null/soap.wsdl b/test/request-response-samples/Dummy__should_handle_nil_as_null/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_as_null/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_nil_as_null/wsdl_options.json b/test/request-response-samples/Dummy__should_handle_nil_as_null/wsdl_options.json new file mode 100644 index 000000000..7b3d64f2f --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_as_null/wsdl_options.json @@ -0,0 +1,3 @@ +{ + "handleNilAsNull": true +} diff --git a/test/request-response-samples/Dummy__should_handle_nil_false/common.xsd b/test/request-response-samples/Dummy__should_handle_nil_false/common.xsd new file mode 100644 index 000000000..e04c0710b --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_false/common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_nil_false/name.xsd b/test/request-response-samples/Dummy__should_handle_nil_false/name.xsd new file mode 100644 index 000000000..a515b88c3 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_false/name.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_nil_false/request.json b/test/request-response-samples/Dummy__should_handle_nil_false/request.json new file mode 100644 index 000000000..52d6f57f7 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_false/request.json @@ -0,0 +1,6 @@ +{ + "DummyField1": "Humpty", + "DummyFilter": { + "DummyStringFilter": "Dumpty" + } +} diff --git a/test/request-response-samples/Dummy__should_handle_nil_false/request.xml b/test/request-response-samples/Dummy__should_handle_nil_false/request.xml new file mode 100644 index 000000000..b4ceed77f --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_false/request.xml @@ -0,0 +1 @@ +HumptyDumpty \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_handle_nil_false/response.json b/test/request-response-samples/Dummy__should_handle_nil_false/response.json new file mode 100644 index 000000000..66a11c394 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_false/response.json @@ -0,0 +1,12 @@ +{ + "DummyResult": { + "DummyList": { + "DummyElement": { + "attributes": { + "xsi:nil": "false" + }, + "$value": "Dummy Element Entry" + } + } + } +} diff --git a/test/request-response-samples/Dummy__should_handle_nil_false/response.xml b/test/request-response-samples/Dummy__should_handle_nil_false/response.xml new file mode 100644 index 000000000..d60ee3c43 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_false/response.xml @@ -0,0 +1,14 @@ + + + + + + + + Dummy Element Entry + + + + + + diff --git a/test/request-response-samples/Dummy__should_handle_nil_false/soap.wsdl b/test/request-response-samples/Dummy__should_handle_nil_false/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_handle_nil_false/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/common.xsd b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/common.xsd new file mode 100644 index 000000000..e04c0710b --- /dev/null +++ b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/name.xsd b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/name.xsd new file mode 100644 index 000000000..a515b88c3 --- /dev/null +++ b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/name.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/request.json b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/request.json new file mode 100644 index 000000000..52d6f57f7 --- /dev/null +++ b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/request.json @@ -0,0 +1,6 @@ +{ + "DummyField1": "Humpty", + "DummyFilter": { + "DummyStringFilter": "Dumpty" + } +} diff --git a/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/request.xml b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/request.xml new file mode 100644 index 000000000..b4ceed77f --- /dev/null +++ b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/request.xml @@ -0,0 +1 @@ +HumptyDumpty \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/response.json b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/response.json new file mode 100644 index 000000000..46466b717 --- /dev/null +++ b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/response.json @@ -0,0 +1,12 @@ +{ + "DummyResult": { + "DummyList": { + "DummyElement": { + "attributes": { + "language": "en-US" + }, + "$value": "Dummy Element Entry" + } + } + } +} diff --git a/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/response.xml b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/response.xml new file mode 100644 index 000000000..d300590d7 --- /dev/null +++ b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/response.xml @@ -0,0 +1,21 @@ + + + + + + + + + Dummy Element Entry + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/soap.wsdl b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_ignore_commented_envelope_in_response/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/options.json b/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/options.json index 31fc7b10b..a788ee62f 100644 --- a/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/options.json +++ b/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/options.json @@ -1,4 +1,4 @@ { "namespaces": ["someIgnoredNamespace"], "override": false -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/request.json b/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/request.json index 1a89d6b8a..1e6ce52d2 100644 --- a/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/request.json +++ b/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/request.json @@ -7,5 +7,4 @@ "DummyName": "Dummy", "DummyPassword": "1234" } - } diff --git a/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/response.json b/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/response.json index a82eeb23f..46466b717 100644 --- a/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/response.json +++ b/test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/response.json @@ -9,4 +9,4 @@ } } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_ignore_defined_namespaces/request.json b/test/request-response-samples/Dummy__should_ignore_defined_namespaces/request.json index 1a89d6b8a..1e6ce52d2 100644 --- a/test/request-response-samples/Dummy__should_ignore_defined_namespaces/request.json +++ b/test/request-response-samples/Dummy__should_ignore_defined_namespaces/request.json @@ -7,5 +7,4 @@ "DummyName": "Dummy", "DummyPassword": "1234" } - } diff --git a/test/request-response-samples/Dummy__should_ignore_defined_namespaces/response.json b/test/request-response-samples/Dummy__should_ignore_defined_namespaces/response.json index 86abb9c9f..4b6d5db9a 100644 --- a/test/request-response-samples/Dummy__should_ignore_defined_namespaces/response.json +++ b/test/request-response-samples/Dummy__should_ignore_defined_namespaces/response.json @@ -9,4 +9,4 @@ } } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_ignore_defined_namespaces/wsdl_options.json b/test/request-response-samples/Dummy__should_ignore_defined_namespaces/wsdl_options.json index 9980f2c8b..4421c06a4 100644 --- a/test/request-response-samples/Dummy__should_ignore_defined_namespaces/wsdl_options.json +++ b/test/request-response-samples/Dummy__should_ignore_defined_namespaces/wsdl_options.json @@ -1,3 +1,3 @@ { "valueKey": "theValue" -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/common.xsd b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/common.xsd new file mode 100644 index 000000000..77375c964 --- /dev/null +++ b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/common.xsd @@ -0,0 +1,4 @@ + + + + diff --git a/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/name.xsd b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/name.xsd new file mode 100644 index 000000000..4a3c81b0c --- /dev/null +++ b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/name.xsd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/request.json b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/request.json new file mode 100644 index 000000000..3ccafed69 --- /dev/null +++ b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/request.json @@ -0,0 +1,3 @@ +{ + "DummyField1": " foobar " +} diff --git a/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/request.xml b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/request.xml new file mode 100644 index 000000000..4bd4e914c --- /dev/null +++ b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/request.xml @@ -0,0 +1,8 @@ + + + + + foobar + + + diff --git a/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/response.json b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/response.json new file mode 100644 index 000000000..9e241c312 --- /dev/null +++ b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/response.json @@ -0,0 +1,3 @@ +{ + "DummyResult": " foobar " +} diff --git a/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/response.xml b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/response.xml new file mode 100644 index 000000000..c916a3341 --- /dev/null +++ b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/response.xml @@ -0,0 +1,8 @@ + + + + + foobar + + + diff --git a/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/soap.wsdl b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/wsdl_options.json b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/wsdl_options.json new file mode 100644 index 000000000..f7c3ab17d --- /dev/null +++ b/test/request-response-samples/Dummy__should_preserve_leading_and_trailing_whitespace_when_preserveWhitespace_is_true/wsdl_options.json @@ -0,0 +1,3 @@ +{ + "preserveWhitespace": true +} diff --git a/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/common.xsd b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/common.xsd new file mode 100644 index 000000000..77375c964 --- /dev/null +++ b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/common.xsd @@ -0,0 +1,4 @@ + + + + diff --git a/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/name.xsd b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/name.xsd new file mode 100644 index 000000000..4a3c81b0c --- /dev/null +++ b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/name.xsd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/request.json b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/request.json new file mode 100644 index 000000000..3ccafed69 --- /dev/null +++ b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/request.json @@ -0,0 +1,3 @@ +{ + "DummyField1": " foobar " +} diff --git a/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/request.xml b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/request.xml new file mode 100644 index 000000000..4bd4e914c --- /dev/null +++ b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/request.xml @@ -0,0 +1,8 @@ + + + + + foobar + + + diff --git a/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/response.json b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/response.json new file mode 100644 index 000000000..0a630807b --- /dev/null +++ b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/response.json @@ -0,0 +1,3 @@ +{ + "DummyResult": "foobar" +} diff --git a/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/response.xml b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/response.xml new file mode 100644 index 000000000..5235fba3a --- /dev/null +++ b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/response.xml @@ -0,0 +1,8 @@ + + + + + foobar + + + diff --git a/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/soap.wsdl b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_remove_leading_and_trailing_whitespace_by_default/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_use_defined_value_key/request.json b/test/request-response-samples/Dummy__should_use_defined_value_key/request.json index 1a89d6b8a..1e6ce52d2 100644 --- a/test/request-response-samples/Dummy__should_use_defined_value_key/request.json +++ b/test/request-response-samples/Dummy__should_use_defined_value_key/request.json @@ -7,5 +7,4 @@ "DummyName": "Dummy", "DummyPassword": "1234" } - } diff --git a/test/request-response-samples/Dummy__should_use_defined_value_key/response.json b/test/request-response-samples/Dummy__should_use_defined_value_key/response.json index a82eeb23f..46466b717 100644 --- a/test/request-response-samples/Dummy__should_use_defined_value_key/response.json +++ b/test/request-response-samples/Dummy__should_use_defined_value_key/response.json @@ -9,4 +9,4 @@ } } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key/request.json b/test/request-response-samples/Dummy__should_use_defined_xml_key/request.json index c10aa3e66..e8a5c289a 100644 --- a/test/request-response-samples/Dummy__should_use_defined_xml_key/request.json +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key/request.json @@ -1,5 +1,5 @@ { "DummyXML": { - "$xml": "" + "$xml": "" } -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key/response.json b/test/request-response-samples/Dummy__should_use_defined_xml_key/response.json index a82eeb23f..46466b717 100644 --- a/test/request-response-samples/Dummy__should_use_defined_xml_key/response.json +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key/response.json @@ -9,4 +9,4 @@ } } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/common.xsd b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/common.xsd new file mode 100644 index 000000000..2422dece4 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/common.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/name.xsd b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/name.xsd new file mode 100644 index 000000000..1aaa406da --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/name.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/request.json b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/request.json new file mode 100644 index 000000000..b20a6feac --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/request.json @@ -0,0 +1,3 @@ +{ + "$xml": "" +} diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/request.xml b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/request.xml new file mode 100644 index 000000000..a9e772a58 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/request.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/response.json b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/response.json new file mode 100644 index 000000000..46466b717 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/response.json @@ -0,0 +1,12 @@ +{ + "DummyResult": { + "DummyList": { + "DummyElement": { + "attributes": { + "language": "en-US" + }, + "$value": "Dummy Element Entry" + } + } + } +} diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/response.xml b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/response.xml new file mode 100644 index 000000000..d5c9b1faf --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/response.xml @@ -0,0 +1,14 @@ + + + + + + + + Dummy Element Entry + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/soap.wsdl b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/soap.wsdl new file mode 100644 index 000000000..35747f328 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_defined_xml_key_in_first_level_for_rpc/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/common.xsd b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/common.xsd new file mode 100644 index 000000000..5a582c4cd --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/common.xsd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/name.xsd b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/name.xsd new file mode 100644 index 000000000..a515b88c3 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/name.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/request.json b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/request.json new file mode 100644 index 000000000..c7ea1478d --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/request.json @@ -0,0 +1,6 @@ +{ + "DummyField1": "", + "DummyFilter": { + "DummyStringFilter": "" + } +} diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/request.xml b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/request.xml new file mode 100644 index 000000000..2db34ae26 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/request.xml @@ -0,0 +1 @@ + diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/soap.wsdl b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_only_when_directed/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/common.xsd b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/common.xsd new file mode 100644 index 000000000..5a582c4cd --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/common.xsd @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/name.xsd b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/name.xsd new file mode 100644 index 000000000..a515b88c3 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/name.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/request.json b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/request.json new file mode 100644 index 000000000..c7ea1478d --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/request.json @@ -0,0 +1,6 @@ +{ + "DummyField1": "", + "DummyFilter": { + "DummyStringFilter": "" + } +} diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/request.xml b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/request.xml new file mode 100644 index 000000000..db47f2dc3 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/request.xml @@ -0,0 +1 @@ + diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/soap.wsdl b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/wsdl_options.json b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/wsdl_options.json new file mode 100644 index 000000000..98955c8e1 --- /dev/null +++ b/test/request-response-samples/Dummy__should_use_empty_tags_when_directed/wsdl_options.json @@ -0,0 +1,3 @@ +{ + "useEmptyTag": true +} diff --git a/test/request-response-samples/Dummy__should_work_with_imported_schemas/request.xml b/test/request-response-samples/Dummy__should_work_with_imported_schemas/request.xml index e377aaa35..20cb7f546 100644 --- a/test/request-response-samples/Dummy__should_work_with_imported_schemas/request.xml +++ b/test/request-response-samples/Dummy__should_work_with_imported_schemas/request.xml @@ -1 +1 @@ -HumptyDumpty \ No newline at end of file +HumptyDumpty diff --git a/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/common.xsd b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/common.xsd new file mode 100644 index 000000000..e04c0710b --- /dev/null +++ b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/common.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/name.xsd b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/name.xsd new file mode 100644 index 000000000..9a4728146 --- /dev/null +++ b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/name.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/request.json b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/request.json new file mode 100644 index 000000000..52d6f57f7 --- /dev/null +++ b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/request.json @@ -0,0 +1,6 @@ +{ + "DummyField1": "Humpty", + "DummyFilter": { + "DummyStringFilter": "Dumpty" + } +} diff --git a/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/request.xml b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/request.xml new file mode 100644 index 000000000..20cb7f546 --- /dev/null +++ b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/request.xml @@ -0,0 +1 @@ +HumptyDumpty diff --git a/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/soap.wsdl b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/soap.wsdl new file mode 100644 index 000000000..814ba1bf5 --- /dev/null +++ b/test/request-response-samples/Dummy__should_work_with_imported_schemas_that_have_aliases/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/request.json b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/request.json new file mode 100644 index 000000000..e8eb9c573 --- /dev/null +++ b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/request.json @@ -0,0 +1,3 @@ +{ + "IV_REQUESTER": "REQUSER1" +} diff --git a/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/request.xml b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/request.xml new file mode 100644 index 000000000..d76e87567 --- /dev/null +++ b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/request.xml @@ -0,0 +1,29 @@ + + + + + + 2014-10-12T01:02:03Z + 2014-10-12T01:12:03Z + + + basicuser + basicpass + 2014-10-12T01:02:03Z + + + + + REQUSER1 + + + diff --git a/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/response.json b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/response.json new file mode 100644 index 000000000..93361402a --- /dev/null +++ b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/response.json @@ -0,0 +1,15 @@ +{ + "ET_ALL_STORES": { + "item": [{ "STORE_ID": "1001" }, { "STORE_ID": "1002" }] + }, + "ET_RETURN": { + "item": [ + { + "TYPE": "S", + "ID": "MSG001", + "NUMBER": "000", + "MESSAGE": "Request processed successfully" + } + ] + } +} diff --git a/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/response.xml b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/response.xml new file mode 100644 index 000000000..9f3d692d5 --- /dev/null +++ b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/response.xml @@ -0,0 +1,24 @@ + + + + + + + 1001 + + + 1002 + + + + + S + MSG001 + 000 + Request processed successfully + + + + + diff --git a/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/security.json b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/security.json new file mode 100644 index 000000000..03aa6643c --- /dev/null +++ b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/security.json @@ -0,0 +1,5 @@ +{ + "type": "ws", + "username": "basicuser", + "password": "basicpass" +} diff --git a/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/soap.wsdl b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/soap.wsdl new file mode 100644 index 000000000..3540dc3cf --- /dev/null +++ b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/soap.wsdl @@ -0,0 +1,523 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/wsdl_options.js b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/wsdl_options.js new file mode 100644 index 000000000..987ac6f4a --- /dev/null +++ b/test/request-response-samples/GET_ALL_STORE_NUMBERS__should_work_with_more_deeply_nested_XML_messages_and_security/wsdl_options.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.ignoreBaseNameSpaces = false; diff --git a/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/request.json b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/request.json new file mode 100644 index 000000000..7070f5aec --- /dev/null +++ b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/request.json @@ -0,0 +1,6 @@ +{ + "IT_STORE_NUMBERS": { + "item": [{ "STORE_ID": "1001" }, { "STORE_ID": "1002" }] + }, + "IV_REQUESTER": "REQUSER1" +} diff --git a/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/request.xml b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/request.xml new file mode 100644 index 000000000..eb0e1d769 --- /dev/null +++ b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/request.xml @@ -0,0 +1,21 @@ + + + + + + + 1001 + + + 1002 + + + REQUSER1 + + + diff --git a/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/response.json b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/response.json new file mode 100644 index 000000000..a9a1ffcec --- /dev/null +++ b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/response.json @@ -0,0 +1,40 @@ +{ + "ET_STORE_DATA": { + "item": [ + { + "STORE_ID": "1001", + "COMPANY_CODE": "C001", + "STORE_CUSTOMER_ID": "CUST1234", + "NAME1": "Downtown Store", + "POSTAL_CODE": "12345", + "CITY": "Metropolis", + "STREET": "Main St 1", + "PHONE_NUMBER": "+1-555-1111", + "OPENING_DATE": "2020-01-01", + "COUNTRY_CODE": "US" + }, + { + "STORE_ID": "1002", + "COMPANY_CODE": "C002", + "STORE_CUSTOMER_ID": "CUST5678", + "NAME1": "Uptown Store", + "POSTAL_CODE": "67890", + "CITY": "Gotham", + "STREET": "High St 99", + "PHONE_NUMBER": "+1-555-2222", + "OPENING_DATE": "2021-06-15", + "COUNTRY_CODE": "US" + } + ] + }, + "ET_RETURN": { + "item": [ + { + "TYPE": "S", + "ID": "MSG001", + "NUMBER": "000", + "MESSAGE": "Data retrieved successfully" + } + ] + } +} diff --git a/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/response.xml b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/response.xml new file mode 100644 index 000000000..5f0e3fa9c --- /dev/null +++ b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/response.xml @@ -0,0 +1,42 @@ + + + + + + + 1001 + C001 + CUST1234 + Downtown Store + 12345 + Metropolis + Main St 1 + +1-555-1111 + 2020-01-01 + US + + + 1002 + C002 + CUST5678 + Uptown Store + 67890 + Gotham + High St 99 + +1-555-2222 + 2021-06-15 + US + + + + + S + MSG001 + 000 + Data retrieved successfully + + + + + diff --git a/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/soap.wsdl b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/soap.wsdl new file mode 100644 index 000000000..3540dc3cf --- /dev/null +++ b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/soap.wsdl @@ -0,0 +1,523 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/wsdl_options.js b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/wsdl_options.js new file mode 100644 index 000000000..7b353cad8 --- /dev/null +++ b/test/request-response-samples/GET_DATA__should_work_with_more_deeply_nested_XML_messages_and_without_security/wsdl_options.js @@ -0,0 +1,19 @@ +'use strict'; + +exports.ignoreBaseNameSpaces = true; +exports.envelopeKey = 'soapenv'; + +exports.ignoredNamespaces = { + namespaces: ['targetNamespace', 'typedNamespace'], + override: 'true', +}; + +exports.overrideRootElement = { + namespace: 'xmlns:ns0', + xmlnsAttributes: [ + { + name: 'xmlns:urn', + value: 'urn:company-com:document:company:rfc:functions', + }, + ], +}; diff --git a/test/request-response-samples/GetAccountXml__non_xmlns_attributes_should_be_returned/request.json b/test/request-response-samples/GetAccountXml__non_xmlns_attributes_should_be_returned/request.json index 3f6609a9c..8a619a266 100644 --- a/test/request-response-samples/GetAccountXml__non_xmlns_attributes_should_be_returned/request.json +++ b/test/request-response-samples/GetAccountXml__non_xmlns_attributes_should_be_returned/request.json @@ -1,7 +1,7 @@ { - "ResourceID":"234", - "ResourceType":"foo", - "IDType":"more foo", - "TreeID":43, - "PrivateLabelID":34 + "ResourceID": "234", + "ResourceType": "foo", + "IDType": "more foo", + "TreeID": 43, + "PrivateLabelID": 34 } diff --git a/test/request-response-samples/GetItemInformation__should_ignore_default_namespace_from_schema/request.json b/test/request-response-samples/GetItemInformation__should_ignore_default_namespace_from_schema/request.json index 1e3318865..c03cd0b2b 100644 --- a/test/request-response-samples/GetItemInformation__should_ignore_default_namespace_from_schema/request.json +++ b/test/request-response-samples/GetItemInformation__should_ignore_default_namespace_from_schema/request.json @@ -1,10 +1,12 @@ { - "Items": { - "Item": [{ - "ItemNumber": "1234", - "RequestedQuantity": { - "Value": "1.00" - } - }] - } -} \ No newline at end of file + "Items": { + "Item": [ + { + "ItemNumber": "1234", + "RequestedQuantity": { + "Value": "1.00" + } + } + ] + } +} diff --git a/test/request-response-samples/GetItemInformation__should_ignore_default_namespace_from_schema/response.json b/test/request-response-samples/GetItemInformation__should_ignore_default_namespace_from_schema/response.json index e0fd98daf..e7b441fd4 100644 --- a/test/request-response-samples/GetItemInformation__should_ignore_default_namespace_from_schema/response.json +++ b/test/request-response-samples/GetItemInformation__should_ignore_default_namespace_from_schema/response.json @@ -1,10 +1,10 @@ { - "Items": { - "Item": { - "ItemNumber": "1234", - "RequestedQuantity": { - "Value": "1.00" - } - } - } -} \ No newline at end of file + "Items": { + "Item": { + "ItemNumber": "1234", + "RequestedQuantity": { + "Value": "1.00" + } + } + } +} diff --git a/test/request-response-samples/GetNodes__complex_self_referencing/request.json b/test/request-response-samples/GetNodes__complex_self_referencing/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/GetNodes__complex_self_referencing/request.json +++ b/test/request-response-samples/GetNodes__complex_self_referencing/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/GetNodes__complex_self_referencing/response.json b/test/request-response-samples/GetNodes__complex_self_referencing/response.json index de74ef568..df96505c0 100644 --- a/test/request-response-samples/GetNodes__complex_self_referencing/response.json +++ b/test/request-response-samples/GetNodes__complex_self_referencing/response.json @@ -1,10 +1,11 @@ { - "GetNodesResult": { - "Name": "Parent", - "Children": { - "Node": [ - {"Name":"Child1","Children": null}, - {"Name":"Child2","Children": null} - ]} - } + "GetNodesResult": { + "Name": "Parent", + "Children": { + "Node": [ + { "Name": "Child1", "Children": null }, + { "Name": "Child2", "Children": null } + ] + } + } } diff --git a/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/EventService.xsd b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/EventService.xsd new file mode 100644 index 000000000..eae311d1d --- /dev/null +++ b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/EventService.xsd @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/request.json b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/request.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/request.json @@ -0,0 +1 @@ +{} diff --git a/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/request.xml b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/request.xml new file mode 100644 index 000000000..02313ff73 --- /dev/null +++ b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/request.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/response.json b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/response.json new file mode 100644 index 000000000..b5563ce40 --- /dev/null +++ b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/response.json @@ -0,0 +1,13 @@ +{ + "Status": { + "Result": "OK" + }, + "Subscriptions": { + "Subscription": [ + { + "SubscriptionID": "a24610ec-4069-4efc-a87e-5ab1d944ec5f", + "TerminationTime": "2024-10-31T20:00:27.567+01:00" + } + ] + } +} diff --git a/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/response.xml b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/response.xml new file mode 100644 index 000000000..940faeff1 --- /dev/null +++ b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/response.xml @@ -0,0 +1,18 @@ + + + + + + OK + + + + a24610ec-4069-4efc-a87e-5ab1d944ec5f + 2024-10-31T20:00:27.567+01:00 + + + + + diff --git a/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/soap.wsdl b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/soap.wsdl new file mode 100644 index 000000000..d82d8a4ee --- /dev/null +++ b/test/request-response-samples/GetSubscription__should_handle_ref_minOccurs_and_maxOccurs/soap.wsdl @@ -0,0 +1,77 @@ + + + + Copyright (c) 2014, gematik - Gesellschaft für Telematikanwendungen der Gesundheitskarte mbH. + Alle Rechte + vorbehalten. + Beschreibung: Konnektor Ereignisdienst + version=7.2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Header.V3.xsd b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Header.V3.xsd new file mode 100644 index 000000000..16aab2b05 --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Header.V3.xsd @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Messages.V3.xsd b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Messages.V3.xsd new file mode 100644 index 000000000..9695231d2 --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Messages.V3.xsd @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Types.V3.xsd b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Types.V3.xsd new file mode 100644 index 000000000..91512d36c --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/Vecozo.Berichtuitwisseling.Push.Types.V3.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/request.json b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/request.json new file mode 100644 index 000000000..05261808c --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/request.json @@ -0,0 +1,5 @@ +{ + "tns:Request": { + "messages:BerichtInfo": {} + } +} diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/request.xml b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/request.xml new file mode 100644 index 000000000..ea395f918 --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/request.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/response.json b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/response.json new file mode 100644 index 000000000..9ace8b273 --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/response.json @@ -0,0 +1,6 @@ +{ + "IndienenBerichtResult": { + "ConversatieId": "12345", + "TraceerId": "56789" + } +} diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/response.xml b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/response.xml new file mode 100644 index 000000000..51e806c07 --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/response.xml @@ -0,0 +1,14 @@ + + + + + + + 12345 + 56789 + + + + \ No newline at end of file diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/soap.wsdl b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/soap.wsdl new file mode 100644 index 000000000..95212ac31 --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/soap.wsdl @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/wsdl_options.js b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/wsdl_options.js new file mode 100644 index 000000000..987ac6f4a --- /dev/null +++ b/test/request-response-samples/IndienenBericht__should_work_with_deeply_nested_XML_messages/wsdl_options.js @@ -0,0 +1,3 @@ +'use strict'; + +exports.ignoreBaseNameSpaces = false; diff --git a/test/request-response-samples/Login__unsupported_response_name_returned_and_local_xs_schema_missed/request.json b/test/request-response-samples/Login__unsupported_response_name_returned_and_local_xs_schema_missed/request.json index 4b8805f1a..dbb06cbc7 100644 --- a/test/request-response-samples/Login__unsupported_response_name_returned_and_local_xs_schema_missed/request.json +++ b/test/request-response-samples/Login__unsupported_response_name_returned_and_local_xs_schema_missed/request.json @@ -1,4 +1,4 @@ { - "UserAlias": "test", - "Password": "testik" -} \ No newline at end of file + "UserAlias": "test", + "Password": "testik" +} diff --git a/test/request-response-samples/Login__unsupported_response_name_returned_and_local_xs_schema_missed/response.json b/test/request-response-samples/Login__unsupported_response_name_returned_and_local_xs_schema_missed/response.json index 9c1975ddd..e78fe154c 100644 --- a/test/request-response-samples/Login__unsupported_response_name_returned_and_local_xs_schema_missed/response.json +++ b/test/request-response-samples/Login__unsupported_response_name_returned_and_local_xs_schema_missed/response.json @@ -1 +1 @@ -{"return":{"attributes":{"xsi:type":"NS2:TewsLoginResult"},"$value":"lrSuccess"},"SessionID":{"attributes":{"xsi:type":"xsd:string"},"$value":"{B26106C6-1F0A-416E-B8EB-B66BBA2A450A}"}} \ No newline at end of file +{ "return": { "attributes": { "xsi:type": "NS2:TewsLoginResult" }, "$value": "lrSuccess" }, "SessionID": { "attributes": { "xsi:type": "xsd:string" }, "$value": "{B26106C6-1F0A-416E-B8EB-B66BBA2A450A}" } } diff --git a/test/request-response-samples/Message__Messages_suffixed_with_In_Out/response.json b/test/request-response-samples/Message__Messages_suffixed_with_In_Out/response.json index 79fdba308..f7693689d 100644 --- a/test/request-response-samples/Message__Messages_suffixed_with_In_Out/response.json +++ b/test/request-response-samples/Message__Messages_suffixed_with_In_Out/response.json @@ -1,4 +1,4 @@ { - "return":"-1", - "bstrError":"" + "return": "-1", + "bstrError": "1" } diff --git a/test/request-response-samples/Message__Messages_suffixed_with_In_Out/response.xml b/test/request-response-samples/Message__Messages_suffixed_with_In_Out/response.xml index 17169f0b0..a3b4127b0 100644 --- a/test/request-response-samples/Message__Messages_suffixed_with_In_Out/response.xml +++ b/test/request-response-samples/Message__Messages_suffixed_with_In_Out/response.xml @@ -1 +1 @@ --1 \ No newline at end of file +-11 \ No newline at end of file diff --git a/test/request-response-samples/Message__Messages_suffixed_with_Input_Output/response.json b/test/request-response-samples/Message__Messages_suffixed_with_Input_Output/response.json index 79fdba308..f7693689d 100644 --- a/test/request-response-samples/Message__Messages_suffixed_with_Input_Output/response.json +++ b/test/request-response-samples/Message__Messages_suffixed_with_Input_Output/response.json @@ -1,4 +1,4 @@ { - "return":"-1", - "bstrError":"" + "return": "-1", + "bstrError": "1" } diff --git a/test/request-response-samples/Message__Messages_suffixed_with_Input_Output/response.xml b/test/request-response-samples/Message__Messages_suffixed_with_Input_Output/response.xml index 17169f0b0..a3b4127b0 100644 --- a/test/request-response-samples/Message__Messages_suffixed_with_Input_Output/response.xml +++ b/test/request-response-samples/Message__Messages_suffixed_with_Input_Output/response.xml @@ -1 +1 @@ --1 \ No newline at end of file +-11 \ No newline at end of file diff --git a/test/request-response-samples/Message__Messages_suffixed_with_Request_Response/response.json b/test/request-response-samples/Message__Messages_suffixed_with_Request_Response/response.json index 79fdba308..f7693689d 100644 --- a/test/request-response-samples/Message__Messages_suffixed_with_Request_Response/response.json +++ b/test/request-response-samples/Message__Messages_suffixed_with_Request_Response/response.json @@ -1,4 +1,4 @@ { - "return":"-1", - "bstrError":"" + "return": "-1", + "bstrError": "1" } diff --git a/test/request-response-samples/Message__Messages_suffixed_with_Request_Response/response.xml b/test/request-response-samples/Message__Messages_suffixed_with_Request_Response/response.xml index 17169f0b0..a3b4127b0 100644 --- a/test/request-response-samples/Message__Messages_suffixed_with_Request_Response/response.xml +++ b/test/request-response-samples/Message__Messages_suffixed_with_Request_Response/response.xml @@ -1 +1 @@ --1 \ No newline at end of file +-11 \ No newline at end of file diff --git a/test/request-response-samples/Message__overriding_namespace_prefix/response.json b/test/request-response-samples/Message__overriding_namespace_prefix/response.json index 79fdba308..f7693689d 100644 --- a/test/request-response-samples/Message__overriding_namespace_prefix/response.json +++ b/test/request-response-samples/Message__overriding_namespace_prefix/response.json @@ -1,4 +1,4 @@ { - "return":"-1", - "bstrError":"" + "return": "-1", + "bstrError": "1" } diff --git a/test/request-response-samples/Message__overriding_namespace_prefix/response.xml b/test/request-response-samples/Message__overriding_namespace_prefix/response.xml index 17169f0b0..a3b4127b0 100644 --- a/test/request-response-samples/Message__overriding_namespace_prefix/response.xml +++ b/test/request-response-samples/Message__overriding_namespace_prefix/response.xml @@ -1 +1 @@ --1 \ No newline at end of file +-11 \ No newline at end of file diff --git a/test/request-response-samples/NoParams__add_correct_namespace_for_operations_without_parameters/request.xml b/test/request-response-samples/NoParams__add_correct_namespace_for_operations_without_parameters/request.xml index b198acbc3..4507af162 100644 --- a/test/request-response-samples/NoParams__add_correct_namespace_for_operations_without_parameters/request.xml +++ b/test/request-response-samples/NoParams__add_correct_namespace_for_operations_without_parameters/request.xml @@ -1 +1 @@ - \ No newline at end of file + diff --git a/test/request-response-samples/OneWay__should_handle_one_way_operation/request.xml b/test/request-response-samples/OneWay__should_handle_one_way_operation/request.xml index 72a05e918..1d7494a22 100644 --- a/test/request-response-samples/OneWay__should_handle_one_way_operation/request.xml +++ b/test/request-response-samples/OneWay__should_handle_one_way_operation/request.xml @@ -1 +1 @@ -never coming back \ No newline at end of file +never coming back diff --git a/test/request-response-samples/OneWay__should_handle_one_way_operation/soap.wsdl b/test/request-response-samples/OneWay__should_handle_one_way_operation/soap.wsdl index fb1818c54..781538631 100644 --- a/test/request-response-samples/OneWay__should_handle_one_way_operation/soap.wsdl +++ b/test/request-response-samples/OneWay__should_handle_one_way_operation/soap.wsdl @@ -4,7 +4,7 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.OneWay.com" xmlns:n="http://www.OneWay.com/Name/Types" xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://www.OneWay.com"> - + @@ -42,4 +42,3 @@ - diff --git a/test/request-response-samples/README.md b/test/request-response-samples/README.md index 74f03ce67..e9678a8ff 100644 --- a/test/request-response-samples/README.md +++ b/test/request-response-samples/README.md @@ -1,21 +1,22 @@ #request-response-samples -This directory contains request / response samples. This is the fastest way to +This directory contains request / response samples. This is the fastest way to add tests, and it allows us to focus on higher level interfaces that should never -change. We can change the guts of node-soap with more confidence as more samples +change. We can change the guts of node-soap with more confidence as more samples are added herein. Follow this process to add samples: 1. Create a directory that combines the client method to invoke along with the - test case name i.e. `Operation__make_sure_short_is_returned_as_number`. This + test case name i.e. `Operation__make_sure_short_is_returned_as_number`. This would invoke `client.Operation` under a `"make sure short is returned as number"` test case. 2. Add the following files within the directory just created: - * `request.json` - This is the data fed to the client method being invoked - * `request.xml` - This is the expected XML that should be sent to the server - * `response.xml` - This is the XMl that the server responds with - * `response.json` - This is the expected JSON from parsing the response XML - * `error_response.json` - This is the expected JSON root attached to the error object when a fault occurs - * `soap.wsdl` - This is the WSDL that defines the operation and messages - * `wsdl_options.wsdl` - This is the wsdl options to create request. (ignorenamespacers, ignoredbasednamespaces). + +- `request.json` - This is the data fed to the client method being invoked +- `request.xml` - This is the expected XML that should be sent to the server +- `response.xml` - This is the XMl that the server responds with +- `response.json` - This is the expected JSON from parsing the response XML +- `error_response.json` - This is the expected JSON root attached to the error object when a fault occurs +- `soap.wsdl` - This is the WSDL that defines the operation and messages +- `wsdl_options.json` - This is the wsdl options to create request. (ignorenamespacers, ignoredbasednamespaces). diff --git a/test/request-response-samples/RequestHeaders__omit_element_when_empty/request.json b/test/request-response-samples/RequestHeaders__omit_element_when_empty/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/RequestHeaders__omit_element_when_empty/request.json +++ b/test/request-response-samples/RequestHeaders__omit_element_when_empty/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security backward compatible check/request.json b/test/request-response-samples/RequestHeaders__propogate_basic_security backward compatible check/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/RequestHeaders__propogate_basic_security backward compatible check/request.json +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security backward compatible check/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security/request.json b/test/request-response-samples/RequestHeaders__propogate_basic_security/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/RequestHeaders__propogate_basic_security/request.json +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_invalid_options/request.json b/test/request-response-samples/RequestHeaders__propogate_basic_security_invalid_options/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/RequestHeaders__propogate_basic_security_invalid_options/request.json +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_invalid_options/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_invalid_options/security.json b/test/request-response-samples/RequestHeaders__propogate_basic_security_invalid_options/security.json index e4cd00427..3278a210a 100644 --- a/test/request-response-samples/RequestHeaders__propogate_basic_security_invalid_options/security.json +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_invalid_options/security.json @@ -2,8 +2,8 @@ "type": "ws", "username": "basicuser", "password": "basicpass", - "options": { - "passwordType": "invalid", - "hasTimeStamp": "" - } + "options": { + "passwordType": "invalid", + "hasTimeStamp": "" + } } diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_timestamp/request.json b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_timestamp/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_timestamp/request.json +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_timestamp/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_timestamp/security.json b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_timestamp/security.json index 2d7e2cc40..7fb4b0a91 100644 --- a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_timestamp/security.json +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_timestamp/security.json @@ -2,7 +2,7 @@ "type": "ws", "username": "basicuser", "password": "basicpass", - "options": { - "hasTimeStamp": false - } + "options": { + "hasTimeStamp": false + } } diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/request.json b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/request.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/request.json @@ -0,0 +1 @@ +{} diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/request.xml b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/request.xml new file mode 100644 index 000000000..fe002a7b5 --- /dev/null +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/request.xml @@ -0,0 +1 @@ +2014-10-12T01:02:03Z2014-10-12T01:12:03Zbasicuserbasicpass diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/response.json b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/response.json new file mode 100644 index 000000000..19765bd50 --- /dev/null +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/response.json @@ -0,0 +1 @@ +null diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/response.xml b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/response.xml new file mode 100644 index 000000000..43591321a --- /dev/null +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/response.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/security.json b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/security.json new file mode 100644 index 000000000..f01fa2a48 --- /dev/null +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/security.json @@ -0,0 +1,8 @@ +{ + "type": "ws", + "username": "basicuser", + "password": "basicpass", + "options": { + "hasTokenCreated": false + } +} diff --git a/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/soap.wsdl b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/soap.wsdl new file mode 100644 index 000000000..809710161 --- /dev/null +++ b/test/request-response-samples/RequestHeaders__propogate_basic_security_no_token_created/soap.wsdl @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/RequestHeaders__propogate_custom_header/request.json b/test/request-response-samples/RequestHeaders__propogate_custom_header/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/RequestHeaders__propogate_custom_header/request.json +++ b/test/request-response-samples/RequestHeaders__propogate_custom_header/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/ResponseHeaders__return_soap_headers/request.json b/test/request-response-samples/ResponseHeaders__return_soap_headers/request.json index 6f31cf5a2..0967ef424 100644 --- a/test/request-response-samples/ResponseHeaders__return_soap_headers/request.json +++ b/test/request-response-samples/ResponseHeaders__return_soap_headers/request.json @@ -1 +1 @@ -{ } \ No newline at end of file +{} diff --git a/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/request.json b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/request.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/request.json @@ -0,0 +1 @@ +{} diff --git a/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/request.xml b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/request.xml new file mode 100644 index 000000000..7defdf9d7 --- /dev/null +++ b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/request.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/response.json b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/response.json new file mode 100644 index 000000000..7f69c5379 --- /dev/null +++ b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/response.json @@ -0,0 +1,4 @@ +{ + "accountNumber": "8272600234806371", + "lastUpdatedDate": "2017-12-01-05:00" +} diff --git a/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/response.xml b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/response.xml new file mode 100644 index 000000000..7a014f4ef --- /dev/null +++ b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/response.xml @@ -0,0 +1,13 @@ + + + + + + 8272600234806371 + 2017-12-01-05:00 + + + \ No newline at end of file diff --git a/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/soap.wsdl b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/soap.wsdl new file mode 100644 index 000000000..acdeaa35e --- /dev/null +++ b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/soap.wsdl @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Responsible for retrieving the details associated with a customer. + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/wsdl_options.js b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/wsdl_options.js new file mode 100644 index 000000000..8fa538518 --- /dev/null +++ b/test/request-response-samples/RetrieveCustomerDetails__returning_a_date_should_parse_the_date/wsdl_options.js @@ -0,0 +1,9 @@ +'use strict'; + +exports.customDeserializer = { + date: function (text, context) { + return text; + }, +}; + +exports.ignoreBaseNameSpaces = false; diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs0.wsdl b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs0.wsdl new file mode 100644 index 000000000..1739eff8a --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs0.wsdl @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs3.wsdl b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs3.wsdl new file mode 100644 index 000000000..8a544e891 --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs3.wsdl @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs7.wsdl b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs7.wsdl new file mode 100644 index 000000000..fd3f0a4c5 --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs7.wsdl @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs9.wsdl b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs9.wsdl new file mode 100644 index 000000000..f48af89da --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/childs/childxs9.wsdl @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/request.json b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/request.json new file mode 100644 index 000000000..faa4f51c7 --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/request.json @@ -0,0 +1,45 @@ +{ + "RetrieveFareQuoteDateRangeRequest": { + "CarrierCodes": { + "CarrierCode": { "AccessibleCarrierCode": "DUMMY" } + }, + "ClientIPAddress": "?", + "HistoricUserName": "?", + "CurrencyOfFareQuote": "ARS", + "PromotionalCode": null, + "IataNumberOfRequestor": null, + "CorporationID": 1, + "FareFilterMethod": "NoComb", + "FareGroupMethod": "FareType", + "InventoryFilterMethod": "Available", + "FareQuoteDetails": { + "FareQuoteDetailDateRange": [ + { + "Origin": "A", + "Destination": "B", + "UseAirportsNotMetroGroups": "false", + "UseAirportsNotMetroGroupsAsRule": "false", + "UseAirportsNotMetroGroupsForFrom": "false", + "UseAirportsNotMetroGroupsForTo": "false", + "DateOfDepartureStart": "2017-10-27", + "DateOfDepartureEnd": "2017-10-27", + "FareTypeCategory": 1, + "FareClass": null, + "FareBasisCode": null, + "Cabin": null, + "LFID": 0, + "OperatingCarrierCode": null, + "MarketingCarrierCode": null, + "LanguageCode": "en", + "TicketPackageID": 1, + "FareQuoteRequestInfos": { + "FareQuoteRequestInfo": { + "PassengerTypeID": 1, + "TotalSeatsRequired": 1 + } + } + } + ] + } + } +} diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/request.xml b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/request.xml new file mode 100644 index 000000000..f07a172ef --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/request.xml @@ -0,0 +1,60 @@ + + + + + + + + DUMMY + + + ? + ? + ARS + + + 1 + NoComb + FareType + Available + + + A + B + false + false + false + false + 2017-10-27 + 2017-10-27 + 1 + + + + 0 + + + en + 1 + + + 1 + 1 + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/response.json b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/response.json new file mode 100644 index 000000000..4806d3429 --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/response.json @@ -0,0 +1,24 @@ +{ + "RetrieveFareQuoteDateRangeResult": { + "CommissionIncluded": "false", + "Exceptions": { + "ExceptionInformation.Exception": { + "ExceptionCode": "0", + "ExceptionDescription": "Successful Transaction", + "ExceptionSource": "RetrieveFareQuoteDateRange", + "ExceptionLevel": "Success" + } + }, + "FlightSegments": null, + "LegDetails": null, + "RequestedCorporationID": "0", + "RequestedCurrencyOfFareQuote": "ARS", + "RequestedFareFilterMethod": "102", + "RequestedGroupMethod": "0", + "RequestedIataNumber": null, + "RequestedInventoryFilterMethod": "0", + "RequestedReservationChannel": "8", + "SegmentDetails": null, + "TaxDetails": null + } +} diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/response.xml b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/response.xml new file mode 100644 index 000000000..2e4c3cbb8 --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/response.xml @@ -0,0 +1,30 @@ + + + + + false + + + 0 + Successful Transaction + RetrieveFareQuoteDateRange + Success + + + + + 0 + ARS + 102 + 0 + + 0 + + 8 + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/soap.wsdl b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/soap.wsdl new file mode 100644 index 000000000..e367a2b6f --- /dev/null +++ b/test/request-response-samples/RetrieveFareQuoteDateRange__should_handle_child_namespaces/soap.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/request.json b/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/request.json index 31a31f6ff..1f50f11e9 100644 --- a/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/request.json +++ b/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/request.json @@ -1,5 +1,3 @@ { - "TestMessage":{ - "message": "" - } + "message": "" } diff --git a/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/request.xml b/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/request.xml index 399fa448d..714fa574e 100644 --- a/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/request.xml +++ b/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/request.xml @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/response.json b/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/response.json index 53b14a991..6c20dcf4d 100644 --- a/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/response.json +++ b/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/response.json @@ -1,3 +1,3 @@ { - "TestResult":"Hello World! & Hello Me!" + "TestResult": "Hello World! & Hello Me!" } diff --git a/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/soap.wsdl b/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/soap.wsdl index 4bed4abe6..04c9c84be 100644 --- a/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/soap.wsdl +++ b/test/request-response-samples/SendCDATA__cdata_is_handled_correctly/soap.wsdl @@ -8,18 +8,22 @@ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/request.json b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/request.json new file mode 100644 index 000000000..f42ad4b39 --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/request.json @@ -0,0 +1,3 @@ +{ + "message": "" +} diff --git a/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/request.xml b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/request.xml new file mode 100644 index 000000000..d51ae7512 --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/request.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/response.json b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/response.json new file mode 100644 index 000000000..8630599a0 --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/response.json @@ -0,0 +1,3 @@ +{ + "TestResult": " Hello World! & Hello Me! " +} diff --git a/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/response.xml b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/response.xml new file mode 100644 index 000000000..965cd9b6a --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/response.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/soap.wsdl b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/soap.wsdl new file mode 100644 index 000000000..04c9c84be --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/soap.wsdl @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/wsdl_options.json b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/wsdl_options.json new file mode 100644 index 000000000..f7c3ab17d --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_preserves_leading_and_trailing_whitespace_when_preserveWhitespace_option_is_true/wsdl_options.json @@ -0,0 +1,3 @@ +{ + "preserveWhitespace": true +} diff --git a/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/request.json b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/request.json new file mode 100644 index 000000000..f42ad4b39 --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/request.json @@ -0,0 +1,3 @@ +{ + "message": "" +} diff --git a/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/request.xml b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/request.xml new file mode 100644 index 000000000..d51ae7512 --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/request.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/response.json b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/response.json new file mode 100644 index 000000000..6c20dcf4d --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/response.json @@ -0,0 +1,3 @@ +{ + "TestResult": "Hello World! & Hello Me!" +} diff --git a/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/response.xml b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/response.xml new file mode 100644 index 000000000..415eb5e90 --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/response.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/soap.wsdl b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/soap.wsdl new file mode 100644 index 000000000..04c9c84be --- /dev/null +++ b/test/request-response-samples/SendCDATA__cdata_removes_leading_and_trailing_whitespace_by_default/soap.wsdl @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/SetResource__should_correctly_set_element_if_complex-type_has_same_name/response.json b/test/request-response-samples/SetResource__should_correctly_set_element_if_complex-type_has_same_name/response.json index 42db3506a..2d1785889 100644 --- a/test/request-response-samples/SetResource__should_correctly_set_element_if_complex-type_has_same_name/response.json +++ b/test/request-response-samples/SetResource__should_correctly_set_element_if_complex-type_has_same_name/response.json @@ -1,5 +1,5 @@ { - "Result":{ + "Result": { "attributes": { "resultStatusFlag": "SUCCESS" } diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base/request.xml b/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base/request.xml index c52da69db..61a81f655 100644 --- a/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base/request.xml +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base/request.xml @@ -1 +1 @@ -100Another AddressMy Address123456 \ No newline at end of file +100Another AddressMy Address123456 \ No newline at end of file diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base/response.json b/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base/response.json index 8e70dca20..c15ebe460 100644 --- a/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base/response.json +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base/response.json @@ -1,5 +1,5 @@ { - "Result":{ + "Result": { "attributes": { "resultStatusFlag": "SUCCESS" }, @@ -14,4 +14,4 @@ ] } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base_ignorednamespaces/response.json b/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base_ignorednamespaces/response.json index 8e70dca20..c15ebe460 100644 --- a/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base_ignorednamespaces/response.json +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_for_elements_with_base_ignorednamespaces/response.json @@ -1,5 +1,5 @@ { - "Result":{ + "Result": { "attributes": { "resultStatusFlag": "SUCCESS" }, @@ -14,4 +14,4 @@ ] } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/request.json b/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/request.json index 3a3dbc540..ea38bc821 100644 --- a/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/request.json +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/request.json @@ -45,4 +45,4 @@ ] } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/request.xml b/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/request.xml index d1d7c8dfb..3b6cf6afd 100644 --- a/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/request.xml +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/request.xml @@ -1 +1 @@ -10012 \ No newline at end of file +10012 \ No newline at end of file diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/response.json b/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/response.json index 8e70dca20..c15ebe460 100644 --- a/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/response.json +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_in_sequence_with_imports/response.json @@ -1,5 +1,5 @@ { - "Result":{ + "Result": { "attributes": { "resultStatusFlag": "SUCCESS" }, @@ -14,4 +14,4 @@ ] } } -} \ No newline at end of file +} diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/Common.xsd b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/Common.xsd new file mode 100644 index 000000000..31979f117 --- /dev/null +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/Common.xsd @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/Name.xsd b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/Name.xsd new file mode 100644 index 000000000..a091e4a4f --- /dev/null +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/Name.xsd @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + Collection of NamePhone + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/request.json b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/request.json new file mode 100644 index 000000000..ea38bc821 --- /dev/null +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/request.json @@ -0,0 +1,48 @@ +{ + "Profile": { + "IDs": { + "UniqueID": [ + { + "attributes": { + "source": "TESTSOURCE" + }, + "$value": 100 + } + ] + }, + "Phones": { + "NamePhone": [ + { + "attributes": { + "primary": true + }, + "IDs": { + "UniqueID": [ + { + "attributes": { + "source": "TEST" + }, + "$value": 1 + } + ] + } + }, + { + "attributes": { + "primary": false + }, + "IDs": { + "UniqueID": [ + { + "attributes": { + "source": "TEST" + }, + "$value": 2 + } + ] + } + } + ] + } + } +} diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/request.xml b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/request.xml new file mode 100644 index 000000000..fad6e0c2d --- /dev/null +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/request.xml @@ -0,0 +1 @@ +10012 \ No newline at end of file diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/response.json b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/response.json new file mode 100644 index 000000000..9266b1d01 --- /dev/null +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/response.json @@ -0,0 +1,15 @@ +{ + "Result": { + "attributes": { + "resultStatusFlag": "SUCCESS" + }, + "IDs": { + "UniqueID": { + "attributes": { + "source": "TESTSOURCE" + }, + "$value": "100" + } + } + } +} diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/response.xml b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/response.xml new file mode 100644 index 000000000..223079d90 --- /dev/null +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/response.xml @@ -0,0 +1 @@ +100 \ No newline at end of file diff --git a/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/soap.wsdl b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/soap.wsdl new file mode 100644 index 000000000..2076cd354 --- /dev/null +++ b/test/request-response-samples/UpdateProfile__correct_namespaces_other_prefixes/soap.wsdl @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/request-response-samples/UpdateProfile__correct_ns_context/request.xml b/test/request-response-samples/UpdateProfile__correct_ns_context/request.xml index 12b5ba2e9..8176b6ccf 100644 --- a/test/request-response-samples/UpdateProfile__correct_ns_context/request.xml +++ b/test/request-response-samples/UpdateProfile__correct_ns_context/request.xml @@ -1 +1 @@ -100100100Another AddressMy Address123456 \ No newline at end of file +100100100Another AddressMy Address123456 \ No newline at end of file diff --git a/test/request-response-samples/UpdateProfile__correct_ns_context/response.json b/test/request-response-samples/UpdateProfile__correct_ns_context/response.json index 42db3506a..2d1785889 100644 --- a/test/request-response-samples/UpdateProfile__correct_ns_context/response.json +++ b/test/request-response-samples/UpdateProfile__correct_ns_context/response.json @@ -1,5 +1,5 @@ { - "Result":{ + "Result": { "attributes": { "resultStatusFlag": "SUCCESS" } diff --git a/test/request-response-samples/addList__complex_extension_namespace_for_arrays/request.json b/test/request-response-samples/addList__complex_extension_namespace_for_arrays/request.json index df14d1bce..f94d3f8f8 100644 --- a/test/request-response-samples/addList__complex_extension_namespace_for_arrays/request.json +++ b/test/request-response-samples/addList__complex_extension_namespace_for_arrays/request.json @@ -1,44 +1,44 @@ { - "record":[ - { - "firstName":"First-1400867779067", - "lastName":"Sullivan", - "phone":"800-555-2819", - "subsidiary":{ - "attributes":{ - "internalId":"1", - "xsi_type":{ - "type":"RecordRef", - "xmlns":"urn:core_2013_2.platform.webservices.netsuite.com" - } - } - }, - "attributes":{ - "xsi_type":{ - "type":"Contact", - "xmlns":"urn:relationships_2013_2.lists.webservices.netsuite.com" - } - } + "record": [ + { + "firstName": "First-1400867779067", + "lastName": "Sullivan", + "phone": "800-555-2819", + "subsidiary": { + "attributes": { + "internalId": "1", + "xsi_type": { + "type": "RecordRef", + "xmlns": "urn:core_2013_2.platform.webservices.netsuite.com" + } + } }, - { - "firstName":"aLFirst-1400867779067", - "lastName":"Sullivan", - "phone":"800-555-2819", - "subsidiary":{ - "attributes":{ - "internalId":"1", - "xsi_type":{ - "type":"RecordRef", - "xmlns":"urn:core_2013_2.platform.webservices.netsuite.com" - } - } - }, - "attributes":{ - "xsi_type":{ - "type":"Contact", - "xmlns":"urn:relationships_2013_2.lists.webservices.netsuite.com" - } - } + "attributes": { + "xsi_type": { + "type": "Contact", + "xmlns": "urn:relationships_2013_2.lists.webservices.netsuite.com" + } } - ] -} \ No newline at end of file + }, + { + "firstName": "aLFirst-1400867779067", + "lastName": "Sullivan", + "phone": "800-555-2819", + "subsidiary": { + "attributes": { + "internalId": "1", + "xsi_type": { + "type": "RecordRef", + "xmlns": "urn:core_2013_2.platform.webservices.netsuite.com" + } + } + }, + "attributes": { + "xsi_type": { + "type": "Contact", + "xmlns": "urn:relationships_2013_2.lists.webservices.netsuite.com" + } + } + } + ] +} diff --git a/test/request-response-samples/addList__complex_extension_namespace_for_arrays/response.json b/test/request-response-samples/addList__complex_extension_namespace_for_arrays/response.json index 5c1518016..3d23bc351 100644 --- a/test/request-response-samples/addList__complex_extension_namespace_for_arrays/response.json +++ b/test/request-response-samples/addList__complex_extension_namespace_for_arrays/response.json @@ -1,34 +1,34 @@ { - "writeResponseList":{ - "writeResponse":[ - { - "status":{ - "attributes":{ - "isSuccess":"true" - } - }, - "baseRef":{ - "attributes":{ - "xsi:type":"platformCore:RecordRef", - "type":"contact", - "internalId":"7080" - } - } + "writeResponseList": { + "writeResponse": [ + { + "status": { + "attributes": { + "isSuccess": "true" + } }, - { - "status":{ - "attributes":{ - "isSuccess":"true" - } - }, - "baseRef":{ - "attributes":{ - "xsi:type":"platformCore:RecordRef", - "type":"contact", - "internalId":"7081" - } - } + "baseRef": { + "attributes": { + "xsi:type": "platformCore:RecordRef", + "type": "contact", + "internalId": "7080" + } } - ] + }, + { + "status": { + "attributes": { + "isSuccess": "true" + } + }, + "baseRef": { + "attributes": { + "xsi:type": "platformCore:RecordRef", + "type": "contact", + "internalId": "7081" + } + } + } + ] } -} \ No newline at end of file +} diff --git a/test/request-response-samples/addPets__force_namespaces/request.json b/test/request-response-samples/addPets__force_namespaces/request.json index 9a8facb79..43a1cfbcd 100644 --- a/test/request-response-samples/addPets__force_namespaces/request.json +++ b/test/request-response-samples/addPets__force_namespaces/request.json @@ -1,7 +1,9 @@ { - "petList": [{ - "pet": { - "name": "Max" + "petList": [ + { + "pet": { + "name": "Max" + } } - }] + ] } diff --git a/test/request-response-samples/addPets__force_namespaces/response.json b/test/request-response-samples/addPets__force_namespaces/response.json index 12d1b5927..7eb906fd2 100644 --- a/test/request-response-samples/addPets__force_namespaces/response.json +++ b/test/request-response-samples/addPets__force_namespaces/response.json @@ -1 +1 @@ -{"status":"OK"} +{ "status": "OK" } diff --git a/test/request-response-samples/addPets__force_namespaces/soap.wsdl b/test/request-response-samples/addPets__force_namespaces/soap.wsdl index fc82a9e4f..88ac3d34a 100644 --- a/test/request-response-samples/addPets__force_namespaces/soap.wsdl +++ b/test/request-response-samples/addPets__force_namespaces/soap.wsdl @@ -9,7 +9,7 @@ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://tempuri.org/"> - + diff --git a/test/request-response-samples/addPets__force_namespaces/wsdl_options.json b/test/request-response-samples/addPets__force_namespaces/wsdl_options.json index 8a4e5a69b..9c4e35207 100644 --- a/test/request-response-samples/addPets__force_namespaces/wsdl_options.json +++ b/test/request-response-samples/addPets__force_namespaces/wsdl_options.json @@ -1,12 +1,15 @@ { "overrideRootElement": { "namespace": "xmlns:tns", - "xmlnsAttributes": [{ - "name": "xmlns:ns2", - "value": "http://tempuri.org/" - }, { - "name": "xmlns:ns3", - "value": "http://sillypets.com/xsd" - }] + "xmlnsAttributes": [ + { + "name": "xmlns:ns2", + "value": "http://tempuri.org/" + }, + { + "name": "xmlns:ns3", + "value": "http://sillypets.com/xsd" + } + ] } } diff --git a/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/request.json b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/request.json new file mode 100644 index 000000000..3e4ff7fa2 --- /dev/null +++ b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/request.json @@ -0,0 +1,3 @@ +{ + "TransType": "11124" +} diff --git a/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/request.xml b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/request.xml new file mode 100644 index 000000000..f2e1633ef --- /dev/null +++ b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/request.xml @@ -0,0 +1,8 @@ + + + + + 11124 + + + \ No newline at end of file diff --git a/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/response.json b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/response.json new file mode 100644 index 000000000..79138fd5d --- /dev/null +++ b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/response.json @@ -0,0 +1,4 @@ +{ + "ResultCode": "0", + "ResultDesc": "test dest" +} diff --git a/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/response.xml b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/response.xml new file mode 100644 index 000000000..245989fe6 --- /dev/null +++ b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/response.xml @@ -0,0 +1,11 @@ + + + + + 0 + test dest + + + \ No newline at end of file diff --git a/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/soap.wsdl b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/soap.wsdl new file mode 100644 index 000000000..74f2f4636 --- /dev/null +++ b/test/request-response-samples/addPrefix__should_add_namespace_on_output_message/soap.wsdl @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSDL File for SoapQueryService + + + + + diff --git a/test/request-response-samples/administrate__Complex_json_object_namespace_issue/request.json b/test/request-response-samples/administrate__Complex_json_object_namespace_issue/request.json index 97dd2b8e4..fc97f46cc 100755 --- a/test/request-response-samples/administrate__Complex_json_object_namespace_issue/request.json +++ b/test/request-response-samples/administrate__Complex_json_object_namespace_issue/request.json @@ -1,11 +1,11 @@ { - "AdminOperation": { - "CreateUser": { - "User": { - "Name": "name", - "Password": "password" - }, - "IgnoreDup":"" - } - } - } \ No newline at end of file + "AdminOperation": { + "CreateUser": { + "User": { + "Name": "name", + "Password": "password" + }, + "IgnoreDup": "" + } + } +} diff --git a/test/request-response-samples/attachments__should_send_binary_data/options.json b/test/request-response-samples/attachments__should_send_binary_data/options.json new file mode 100644 index 000000000..a448f861b --- /dev/null +++ b/test/request-response-samples/attachments__should_send_binary_data/options.json @@ -0,0 +1,10 @@ +{ + "attachments": [ + { + "mimetype": "plain/txt", + "contentId": "file_0", + "name": "data.txt", + "body": "some data" + } + ] +} diff --git a/test/request-response-samples/attachments__should_send_binary_data/request.json b/test/request-response-samples/attachments__should_send_binary_data/request.json new file mode 100644 index 000000000..8039f4231 --- /dev/null +++ b/test/request-response-samples/attachments__should_send_binary_data/request.json @@ -0,0 +1,7 @@ +{ + "field1": "field 1 value", + "field2": "another value", + "attachment": { + "$xml": "" + } +} diff --git a/test/request-response-samples/attachments__should_send_binary_data/response.json b/test/request-response-samples/attachments__should_send_binary_data/response.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/request-response-samples/attachments__should_send_binary_data/response.json @@ -0,0 +1 @@ +{} diff --git a/test/request-response-samples/attachments__should_send_binary_data/soap.wsdl b/test/request-response-samples/attachments__should_send_binary_data/soap.wsdl new file mode 100644 index 000000000..e94deee9b --- /dev/null +++ b/test/request-response-samples/attachments__should_send_binary_data/soap.wsdl @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/test/request-response-samples/createData__should_generate_complex_type_request/request.json b/test/request-response-samples/createData__should_generate_complex_type_request/request.json new file mode 100644 index 000000000..f76bff820 --- /dev/null +++ b/test/request-response-samples/createData__should_generate_complex_type_request/request.json @@ -0,0 +1,33 @@ +{ + "ModelCRUDRequest": { + "ModelCRUD": { + "serviceType": "CreateInterest", + "TableName": "WTC_EmployeeInterest", + "RecordID": 0, + "Filter": "", + "Action": "Create", + "DataRow": { + "field": [ + { + "attributes": { "column": "C_BPartner_ID" }, + "val": "1001047" + }, + { + "attributes": { "column": "Interest" }, + "val": "Cooking" + } + ] + } + }, + "ADLoginRequest": { + "user": "WTCAdmin", + "pass": "WTCAdmin", + "lang": "192", + "ClientID": 11, + "RoleID": 102, + "OrgID": 1000001, + "WarehouseID": 1000000, + "stage": 0 + } + } +} diff --git a/test/request-response-samples/createData__should_generate_complex_type_request/request.xml b/test/request-response-samples/createData__should_generate_complex_type_request/request.xml new file mode 100644 index 000000000..c16bd136a --- /dev/null +++ b/test/request-response-samples/createData__should_generate_complex_type_request/request.xml @@ -0,0 +1,34 @@ + + + + + + + CreateInterest + WTC_EmployeeInterest + 0 + + Create + + + 1001047 + + + Cooking + + + + + WTCAdmin + WTCAdmin + 192 + 11 + 102 + 1000001 + 1000000 + 0 + + + + + diff --git a/test/request-response-samples/createData__should_generate_complex_type_request/response.json b/test/request-response-samples/createData__should_generate_complex_type_request/response.json new file mode 100644 index 000000000..907c11075 --- /dev/null +++ b/test/request-response-samples/createData__should_generate_complex_type_request/response.json @@ -0,0 +1,5 @@ +{ + "StandardResponse": { + "attributes": { "RecordID": "1000027" } + } +} diff --git a/test/request-response-samples/createData__should_generate_complex_type_request/response.xml b/test/request-response-samples/createData__should_generate_complex_type_request/response.xml new file mode 100644 index 000000000..b26651a55 --- /dev/null +++ b/test/request-response-samples/createData__should_generate_complex_type_request/response.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/request-response-samples/createData__should_generate_complex_type_request/soap.wsdl b/test/request-response-samples/createData__should_generate_complex_type_request/soap.wsdl new file mode 100644 index 000000000..7c300225a --- /dev/null +++ b/test/request-response-samples/createData__should_generate_complex_type_request/soap.wsdl @@ -0,0 +1,159 @@ + +