pax_global_header00006660000000000000000000000064147277532100014522gustar00rootroot0000000000000052 comment=2dec7f81372f917b09b2c1da2fc89aaa573459cf strophejs-3.1.0/000077500000000000000000000000001472775321000135445ustar00rootroot00000000000000strophejs-3.1.0/.gitattributes000066400000000000000000000000171472775321000164350ustar00rootroot00000000000000*.min.js binarystrophejs-3.1.0/.github/000077500000000000000000000000001472775321000151045ustar00rootroot00000000000000strophejs-3.1.0/.github/dependabot.yml000066400000000000000000000001751472775321000177370ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: npm directory: "/" schedule: interval: daily open-pull-requests-limit: 10 strophejs-3.1.0/.github/workflows/000077500000000000000000000000001472775321000171415ustar00rootroot00000000000000strophejs-3.1.0/.github/workflows/karma-tests.yml000066400000000000000000000016471472775321000221270ustar00rootroot00000000000000# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions name: Strophe CI Tests on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest env: DISPLAY: :99.0 strategy: matrix: node-version: [19.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} cache: 'npm' - name: Run Karma tests uses: GabrielBB/xvfb-action@v1 with: run: make check ARGS=--single-run strophejs-3.1.0/.gitignore000066400000000000000000000002401472775321000155300ustar00rootroot00000000000000stamp-npm stamp-bower version.txt node_modules bower_components dist strophejs-*/ ndproj doc *.map .taperc *.tar.gz *.zip *~ .*.sw? doc-tmp tags.lock tags.temp strophejs-3.1.0/.nvmrc000066400000000000000000000000111472775321000146620ustar00rootroot00000000000000v20.18.0 strophejs-3.1.0/.prettierrc000066400000000000000000000001341472775321000157260ustar00rootroot00000000000000{ "printWidth": 120, "quoteProps": "preserve", "singleQuote": true, "tabWidth": 4 } strophejs-3.1.0/.travis.yml000066400000000000000000000001731472775321000156560ustar00rootroot00000000000000dist: bionic language: node_js addons: chrome: stable node_js: - "13" before_script: make serve_bg script: make check strophejs-3.1.0/CHANGELOG.md000066400000000000000000000326611472775321000153650ustar00rootroot00000000000000# Strophe.js Change Log ## Version 3.1.0 - (2024-12-16) - **Security Fix**: Escape values passed to the `stx` tagged template literal - Allow `Stanza` and `Builder` objects to be passed as values the `stx`. - Avoid inserting commas when nesting array values in `stx` templates. - Replace [xmldom](https://github.com/xmldom/xmldom) with [jsdom](https://github.com/jsdom/jsdom). - Remove deprecated `abab` package - Make sure `ConnectionOptions` type is exportable - fix: invert default and types exports ## Version 3.0.1 - (2024-08-15) * Bugfix: `Package path . is not exported from package` * #708 Properly set exports value in package.json * #710 Fix types minor errors * #711 Error with Builder.up depending on context * #712 fix: export node and default modules * #715 Fix the error when the attrs field is null Dependency updates: * Bump @rollup/plugin-commonjs from 24.1.0 to 26.0.1 * Bump @xmldom/xmldom from 0.8.8 to 0.8.10 * Bump prettier from 2.8.8 to 3.3.3 * Bump sinon from 15.0.4 to 18.0.0 ## Version 3.0.0 - (2024-05-07) * #704 Cannot use with NodeJS * #706 TypeError when receiving a `stream:error` IQ message Out of an abundance of caution, making a major version bump, since there was some internal refactoring of the Strophe files to remove circular dependencies. So certain deep imports used by integrators might no longer work. Instead of deep imports, everything should be imported from `strophe.js`. For example: ``` import { Strophe, $build, stx } from strophe.js; ``` ## Version 2.0.0 - (2024-02-21) * Type checking via TypeScript and JSDoc typing annotations * Types definitions are now generated and placed in `./dist/types/`. * Remove the deprecated `matchBare` option for `Strophe.Handler`. Use `matchBareFromJid` instead. * Add the ability to create stanzas via a tagged template literal (`stx`). * Bugfix: Ignore unknown SCRAM attributes instead of aborting the connection ## Version 1.6.2 - (2023-06-23) * #613 TypeError: XHTML.validTag is not a function * Re-add NodeJS support and add the ability to run tests on NodeJS to avoid regressions ## Version 1.6.1 - (2023-05-15) * #602 Websocket connection times out instead of being disconnected ## Version 1.6.0 - (2022-10-29) * #314 Support for SCRAM-SHA-256 and SCRAM-SHA-512 authentication ## Version 1.5.0 - (2022-04-28) * Add an automatic fallback handler for unhandled IQ "set" and "get" stanzas that returns an IQ error with `service-unavailable`. * Update various 3rd party dependencies * #390 Replace deprecated String.prototype.substr() * #418 BOSH fix: mark first request dead when second is done ## Version 1.4.4 - (2022-01-21) * #388 Properly import xmldom ## Version 1.4.3 - (2021-12-16) * Update xmldom to version 0.7.5 * Add disconnection_timeout setting: an optional timeout in milliseconds before `_doDisconnect` is called. * Update ws optional dependency to fix security issue https://github.com/websockets/ws/commit/00c425ec77993773d823f018f64a5c44e17023ff ## Version 1.4.2 - (2021-04-28) * Update optional NodeJS-specific dependency xmldom to version 0.5.0 which includes a security fix. * #369 Add `clientChallenge` SASL mechanism method to avoid having to monkey patch `onChallenge`, which prevents reconnection when using SCRAM-SHA1. ## Version 1.4.1 - (2020-12-02) * #201: NodeJS related fixes: `window` and `WebSocket` are `undefined` * New method `Strophe.Connection.prototype.setProtocol` which can be used to determine the protocol used after the connection has been constructed. ## Version 1.4.0 - (2020-09-10) * #347: Bugfix. Reconnection fails when SessionResultIQ arrives too late * #354: Strophe.js sends an authzid during PLAIN when not acting on behalf of another entity * #359: Bugfix: WebSocket connection failed: Data frame received after close * Add support for running a websocket connection inside a shared worker ## Version 1.3.6 - (2020-06-15) - #250 Bugfix: OAuth's SASL priority being higher causes problems - #352 Bugfix: Referencing undefined property ## Version 1.3.5 - (2020-04-29) * Remove support for obselete SASL DIGEST-MD5 auth * #329 Varous compatibility fixes to make Strophe.js work in NodeJS * #344 Properly set Strophe.VERSION ## Version 1.3.4 - (2019-08-08) * Replace webpack with rollup * `TypeError: this._changeConnectStatus is not a function` * Bugfix. Remove handlers on closed socket * Add new Strophe.Connection option `explicitResourceBinding`. If is set to true the XMPP client needs to explicitly call `Strophe.Connection.prototype.bind` once the XMPP server has advertised the "urn:ietf:params:xml:ns:xmpp-bind" feature. ## Version 1.3.3 - (2019-05-13) * The dist files are no longer included in the repo, but generated by NPM/Yarn * Moved some log statements from INFO to DEBUG level * Don't break when a falsy value is passed to `getResourceFromJid` ## Version 1.3.2 - (2019-03-21) * #320 Fix error on SCRAM-SHA-1 client nonce generation ## Version 1.3.1 - (2018-11-15) * #311 Expose `Strophe`, `$build`, `$msg` and `$iq` as globals ## Version 1.3.0 - (2018-10-21) * Use ES2015 modules * Drop support for Internet Explorer < 11 ## Version 1.2.16 - (2018-09-16) * #299 'no-auth-mech' error. Server did not offer a supported authentication mechanism * #306 Fix websocket close handler exception and reporting ## Version 1.2.15 - (2018-05-21) * #259 XML element should be sent to xmlOutput * #266 Support Browserify/CommonJS. `require('strophe.js/src/wrapper')` * #296 Remove error handler from old websocket before closing * #271 SASL X-OAUTH2 authentication mechanism implemented * #288 Strophe now logs fatal errors by default. * Run tests with headless Chromium instead of Phantomjs ## Version 1.2.14 - 2017-06-15 * #231 SASL OAuth Bearer authentication should not require a JID node, when a user identifer can be retreived from the bearer token. * #250 Show XHR error message * #254 Set connection status to CONNFAIL after max retries * #255 Set CONNFAIL error status when connection fails on Safari 10 ## Version 1.2.13 - 2017-02-25 * Use almond to create the build. This means that the build itself is an AMD module and can be loaded via `require`. * Remove Grunt as a build tool. ## Version 1.2.12 - 2017-01-15 * Reduce the priority of the SASL-EXTERNAL auth mechanism. OpenFire 4.1.1 advertises support for SASL-EXTERNAL and the vast majority of Strophe.js installs are not set up to support SASL-EXTERNAl, causing them to fail logging users in. ## Version 1.2.11 - 2016-12-13 * 189 Strophe never reaches DISCONNECTED status after .connect(..) and .disconnect(..) calls while offline. * Add `sendPresence` method, similar to `sendIQ`, i.e. for cases where you expect a responding presence (e.g. when leaving a MUC room). ## Version 1.2.10 - 2016-11-30 * #172 and #215: Strophe shouldn't require `from` attribute in iq response * #216 Get inactivity attribute from session creation response * Enable session restoration for anonymous logins ## Version 1.2.9 - 2016-10-24 * Allow SASL mechanisms to be supported to be passed in as option to `Strophe.Connection` constructor. * Add new matching option to `Strophe.Handler`, namely `ignoreNamespaceFragment`. * The `matchBare` matching option for `Strophe.Handler` has been renamed to `matchBareFromJid`. The old name will still work in this release but is deprecated and will be removed in a future release. * #114 Add an error handler for HTTP calls * #213 "XHR open failed." in BOSH in IE9 * #214 Add function to move Strophe.Builder pointer back to the root node * #172, #215 Don't compare `to` and `to` values of sent and received IQ stanzas to determine correctness (we rely on UUIDs for that). ## Version 1.2.8 - 2016-09-16 * #200 Fix for webpack * #203 Allow custom Content-Type header for requests * #206 XML stanza attributes: there is no 'quot' escape inside 'serialize' method * The files in `./src` are now also included in the NPM distribution. * Add support for SASL-EXTERNAL ## Version 1.2.7 - 2016-06-17 * #193 Move phantomjs dependencies to devDependencies ## Version 1.2.6 - 2016-06-06 * #178 Added new value (CONNTIMEOUT) to Strophe.Status * #180 bosh: check sessionStorage support before using it * #182 Adding SASL OAuth Bearer authentication * #190 Fix .c() to accept both text and numbers as text for the child element * #192 User requirejs instead of require for node compat ## Version 1.2.5 - 2016-02-09 * Add a new Strophe.Connection option to add cookies * Add new Strophe.Connection option "withCredentials" ## Version 1.2.4 - 2016-01-28 * #147 Support for UTF-16 encoded usernames (e.g. Chinese) * #162 allow empty expectedFrom according to W3C DOM 3 Specification * #171 Improve invalid BOSH URL handling ## Version 1.2.3 - 2015-09-01 * Bugfix. Check if JID is null when restoring a session. * #127 IE-Fix: error on setting null value with setAttributes * #138 New stub method nextValidRid * #144 Change ID generator to generate UUIDs ## Version 1.2.2 - 2015-06-20 * #109 Explicitly define AMD modules to prevent errors with AlmondJS and AngularJS. * #111 Fixed IE9 compatibility. * #113 Permit connecting with an alternative authcid. * #116 tree.attrs() now removes Elements when they are set to undefined * #119 Provide the 'keepalive' option to keep a BOSH session alive across page loads. * #121 Ensure that the node names of HTML elements copied into XHTML are lower case. * #124 Strophe's Builder will swallow elements if given a blank string as a 'text' parameter. ## Version 1.2.1 - 2015-02-22 * Rerelease of 1.2.0 but with a semver tag and proper formatting of bower.json for usage with Bower.io. ## Version 1.2.0 - 2015-02-21 * Add bower package manager support. * Add commandline testing support via qunit-phantomjs-runner * Add integrated testing via TravisCI. * Fix Websocket connections now use the current XMPP-over-WebSockets RFC * #25 Item-not-found-error caused by long term request. * #29 Add support for the Asynchronous Module Definition (AMD) and require.js * #30 Base64 encoding problem in some older browsers. * #45 Move xhlr plugin to strophejs-plugins repo. * #60 Fixed deletion of handlers in websocket connections * #62 Add `xmlunescape` method. * #67 Use correct Content-Type in BOSH * #70 `_onDisconnectTimeout` never tiggers because maxRetries is undefined. * #71 switched to case sensitive handling of XML elements * #73 `getElementsByTagName` problem with namespaced elements. * #76 respect "Invalid SID" message * #79 connect.pause work correctly again * #90 The queue data was not reset in .reset() method. * #104 Websocket connections with MongooseIM work now ## Version 1.1.3 - 2014-01-20 * Fix SCRAM-SHA1 auth now works for multiple connections at the same time * Fix Connecting to a different server with the same connection after disconnect * Add Gruntfile so StropheJS can now also be built using grunt * Fix change in sha1.js that broke the caps plugin * Fix all warnings from jshint. ## Version 1.1.2 - 2014-01-04 * Add option for synchronous BOSH connections * moved bower.json to other repository * Remove unused code in sha1 and md5 modules ## Version 1.1.1 - 2013-12-16 * Fix BOSH attach is working again ## Version 1.1.0 - 2013-12-11 * Add Support for XMPP-over-WebSocket * Authentication mechanisms are now modular and can be toggled * Transport protocols are now modular and will be chosen based on the connection URL. Currently supported protocols are BOSH and WebSocket * Add Strings to some disconnects that indicate the reason * Add option to strip tags before passing to xmlInput/xmlOutput * Fix Connection status staying at CONNFAIL or CONNECTING in certain error scenarios * Add package.json for use with npm * Add bower.json for use with bower * Fix handlers not being removed after disconnect * Fix legacy non-sasl authentication * Add better tests for BOSH bind * Fix use of deprecated functions in tests * Remove some dead code * Remove deprecated documentation * Fix Memory leak in IE9 * Add An options object can be passed to a Connection constructor now * Add "Route" Parameter for BOSH Connections * Add Maximum number of connection attempts before disconnecting * Add conflict condition for AUTHFAIL * Add XHTML message support * Fix parsing chat messages in IE * Add SCRAM-SHA-1 SASL mechanism * Fix escaping of messages ## Version 1.0.2 - 2011-06-19 * Fix security bug where DIGEST-MD5 client nonce was not properly randomized. * Fix double escaping in copyElement. * Fix IE errors related to importNode. * Add ability to pass text into Builder.c(). * Improve performance by skipping debugging callbacks when not overridden. * Wrap handler runs in try/catch so they don't affect or remove later handlers. * Add ' and " to escaped characters and other escaping fixes. * Fix _throttledRequestHandler to use proper window size. * Fix timed handler management. * Fix flXHR plugin to better deal with errors. * Fix bind() to be ECMAScript 5 compatible. * Use bosh.metajack.im in examples so they work out of the box. * Add simple XHR tests. * Update basic example to HTML5. * Move community plugins to their own repository. * Fix bug causing infinite retries. * Fix 5xx error handling. * Store stream:features for later use by plugins. * Fix to prevent passing stanzas during disconnect. * Fix handling of disconnect responses. * Fix getBareJidFromJid to return null on error. * Fix equality testing in matchers so that string literals and string objects both match. * Fix bare matching on missing from attributes. * Remove use of reserved word self. * Fix various documentation errors. ## Version 1.0.1 - 2010-01-27 * Fix handling of window, hold, and wait attributes. Bug #75. ## Version 1.0 - 2010-01-01 * First release. strophejs-3.1.0/LICENSE.txt000066400000000000000000000020471472775321000153720ustar00rootroot00000000000000Copyright (c) 2006-2009 Collecta, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. strophejs-3.1.0/Makefile000066400000000000000000000043541472775321000152120ustar00rootroot00000000000000DOC_DIR = doc DOC_TEMP = doc-temp HTTPSERVE ?= ./node_modules/http-server/bin/http-server HTTPSERVE_PORT ?= 8080 ESLINT ?= ./node_modules/eslint/bin/eslint.js NDPROJ_DIR = ndproj SED ?= sed SHELL ?= /usr/env/bin/bash SRC_DIR = src STROPHE = dist/strophe.umd.js all: doc $(STROPHE) .PHONY: help help: @echo "Please use \`make ' where is one of the following:" @echo "" @echo " all Update docs + build strophe" @echo " doc Update docs" @echo " dist Build strophe" @echo " check Build and run the tests" @echo " eslint Check code quality" @echo " release Prepare a new release of strophe. E.g. \`make release VERSION=1.2.14\`" @echo " serve Serve this directory via a webserver on port 8000." @echo " node_modules Install all dependencies" @echo "" @echo "If you are a Mac user:\n 1. Install \`gnu-sed\` (brew install gnu-sed) \n 2. Set \`SED\` to \`gsed\` in all commands. E.g. \`make release SED=gsed VERSION=1.2.14\`" node_modules: package.json npm install .PHONY: doc doc: @@echo "Building Strophe documentation..." npx jsdoc -p -d $(DOC_DIR) -c jsdoc.json src/ @@echo "Documentation built." @@echo .PHONY: release release: $(SED) -i 's/\"version\":\ \"[0-9]\+\.[0-9]\+\.[0-9]\+\"/\"version\":\ \"$(VERSION)\"/' package.json $(SED) -i 's/VERSION:\ \"[0-9]\+\.[0-9]\+\.[0-9]\+\"/VERSION:\ \"$(VERSION)\"/' src/index.js $(SED) -i "s/Unreleased/`date +%Y-%m-%d`/" CHANGELOG.md make dist .PHONY: watchjs watchjs: node_modules ./node_modules/.bin/npx webpack --mode=development --watch dist/types: src/* npm run types .PHONY: dist dist: $(STROPHE) dist/types $(STROPHE): src/* rollup.config.js node_modules Makefile npm run build .PHONY: eslint eslint: node_modules $(ESLINT) src/ .PHONY: prettier prettier: node_modules npm run prettier .PHONY: check check:: node_modules eslint dist npm ci && npm run test .PHONY: serve serve: node_modules $(HTTPSERVE) -p $(HTTPSERVE_PORT) .PHONY: serve_bg serve_bg: node_modules $(HTTPSERVE) -p $(HTTPSERVE_PORT) -c-1 -s & .PHONY: clean clean: @@rm -rf node_modules @@rm -f $(STROPHE) @@rm -f $(STROPHE_MIN) @@rm -f $(PLUGIN_FILES_MIN) @@rm -rf $(NDPROJ_DIR) $(DOC_DIR) $(DOC_TEMP) @@echo "Done." @@echo strophejs-3.1.0/README.md000066400000000000000000000040721472775321000150260ustar00rootroot00000000000000# Strophe.js ![Build Status](https://github.com/strophe/strophejs/actions/workflows/karma-tests.yml/badge.svg) Strophe.js is a JavaScript library for speaking XMPP via BOSH ([XEP 124](https://xmpp.org/extensions/xep-0124.html) and [XEP 206](https://xmpp.org/extensions/xep-0206.html)) and WebSockets ([RFC 7395](http://tools.ietf.org/html/rfc7395)). It runs in both NodeJS and in web browsers, and its purpose is to enable real-time XMPP applications. ## Quick Links * [Homepage](https://strophe.im/strophejs/) * [Documentation](https://strophe.im/strophejs/doc/2.0.0/files/strophe-umd-js.html) * [Mailing list](https://groups.google.com/g/strophe) * [Community Plugins](https://github.com/strophe/strophejs-plugins) ## Support in different environments ### Browsers Versions <= 1.2.16 have been tested on Firefox, Firefox for Android, IE, Safari, Mobile Safari, Chrome, Chrome for Android, Opera and the mobile Opera browser. Since version 1.3.0, support for IE < 11 has been dropped. ### React Native Since version 1.6.0 the [WebCrypto](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) API (included by default in Browsers and NodeJS) is used for crypto primitives such as hashing and signatures. Unfortunately this API is not available in React Native, and integrators will need to look for a 3rd party implementations of this API if they want to use Strophe there. ## Running tests You can run `npm run test`, or alternatively if you have [GNU Make](https://www.gnu.org/software/make/) available, you can run `make check`. ## License Strophe.js is licensed under the [MIT license](https://github.com/strophe/strophejs/raw/master/LICENSE.txt). ## Author & History Strophe.js was created by Jack Moffitt. It was originally developed for Chesspark, an online chess community based on XMPP technology. It has been cared for and improved over the years and is currently maintained by many people in the community. The book [Professional XMPP Programming with JavaScript and jQuery](http://professionalxmpp.com) covers Strophe in detail in the context of web applications. strophejs-3.1.0/RELEASE_CHECKLIST.md000066400000000000000000000015671472775321000165500ustar00rootroot00000000000000# Release Checklist ## Note: it's assumed that you have Strophe.js and Strophe.im checked out in sibling directories. 1. Make sure all tests pass (run 'make check') 2. Update CHANGELOG.md 3. Run `make release VERSION=3.0.1` (on Mac, prefix with "SED=gsed" so that GNU-sed is used). 4. Run `make doc` 5. Run `cp -r doc ../strophe.im/strophejs/doc/3.0.1` 5. Update links in `../strophe.im/strophejs/index.markdown` in Strophe.im 6. `cd ../strophe.im && git commit -am "Docs for Strophe.js 3.0.1" && git push` 7. Update link to documentation in README (of strophe.js) 8. `cd ../strophe.js && git commit -am "Release 3.0.1"` 9. `git tag -s v3.0.1 -m "Release 3.0.1"` 10. Run `git push && git push origin v3.0.1` 11. Publish on NPM: `npm publish` 12. Update the release notes on https://github.com/strophe/strophejs/releases 13. Run `npm pack` and upload the tgz file to the releases page. strophejs-3.1.0/babel.config.json000066400000000000000000000004201472775321000167440ustar00rootroot00000000000000{ "presets": [ ["@babel/preset-env", { "targets": { "browsers": [">1%", "not dead"] } }] ], "plugins": ["@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-nullish-coalescing-operator"] } strophejs-3.1.0/eslint.config.mjs000066400000000000000000000200461472775321000170230ustar00rootroot00000000000000import globals from "globals"; import babelParser from "@babel/eslint-parser"; import path from "node:path"; import { fileURLToPath } from "node:url"; import js from "@eslint/js"; import { FlatCompat } from "@eslint/eslintrc"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const compat = new FlatCompat({ baseDirectory: __dirname, recommendedConfig: js.configs.recommended, allConfig: js.configs.all }); export default [...compat.extends("eslint:recommended"), { languageOptions: { globals: { ...globals.browser, Uint8Array: true, Promise: true, define: true, require: true, sinon: true, window: true, }, parser: babelParser, ecmaVersion: 2017, sourceType: "module", parserOptions: { allowImportExportEverywhere: true, }, }, rules: { "accessor-pairs": "error", "array-bracket-spacing": "off", "array-callback-return": "error", "arrow-body-style": "off", "arrow-parens": "off", "arrow-spacing": "error", "block-scoped-var": "off", "block-spacing": "off", "brace-style": "off", "callback-return": "off", camelcase: "off", "capitalized-comments": "off", "class-methods-use-this": "error", "comma-dangle": "off", "comma-spacing": "off", "comma-style": "off", complexity: "off", "computed-property-spacing": ["error", "never"], "consistent-return": "off", "consistent-this": "off", curly: "off", "default-case": "off", "dot-location": ["error", "property"], "dot-notation": ["off", { allowKeywords: true, }], "eol-last": "error", eqeqeq: "off", "func-call-spacing": "off", "no-spaced-func": "off", "no-redeclare": "off", "func-name-matching": "error", "func-names": "off", "func-style": "off", "generator-star-spacing": "error", "global-require": "off", "guard-for-in": "error", "handle-callback-err": "error", "id-blacklist": "error", "id-length": "off", "id-match": "error", indent: "off", "init-declarations": "off", "jsx-quotes": "error", "key-spacing": "off", "keyword-spacing": "off", "line-comment-position": "off", "linebreak-style": ["error", "unix"], "lines-around-comment": "off", "lines-around-directive": "off", "max-depth": "off", "max-len": "off", "max-lines": "off", "max-nested-callbacks": "off", "max-params": "off", "max-statements": "off", "max-statements-per-line": "off", "multiline-ternary": "off", "new-parens": "error", "newline-after-var": "off", "newline-before-return": "off", "newline-per-chained-call": "off", "no-alert": "off", "no-array-constructor": "error", "no-await-in-loop": "off", "no-bitwise": "off", "no-caller": "error", "no-console": "off", "no-catch-shadow": "off", "no-cond-assign": ["off", "except-parens"], "no-confusing-arrow": "off", "no-continue": "off", "no-div-regex": "error", "no-duplicate-imports": "error", "no-else-return": "off", "no-empty-function": "off", "no-eq-null": "error", "no-eval": "error", "no-extend-native": "off", "no-extra-bind": "off", "no-extra-label": "error", "no-extra-parens": "off", "no-floating-decimal": "error", "no-implicit-globals": "off", "no-implied-eval": "error", "no-inline-comments": "off", "no-inner-declarations": ["error", "functions"], "no-invalid-this": "off", "no-iterator": "error", "no-label-var": "error", "no-labels": "error", "no-lone-blocks": "error", "no-lonely-if": "off", "no-loop-func": "error", "no-magic-numbers": "off", "no-mixed-operators": "off", "no-mixed-requires": "error", "no-multi-assign": "off", "no-multi-spaces": "off", "no-multi-str": "error", "no-multiple-empty-lines": "error", "no-native-reassign": "error", "no-negated-condition": "off", "no-negated-in-lhs": "error", "no-nested-ternary": "off", "no-new": "off", "no-new-func": "error", "no-new-object": "error", "no-new-require": "error", "no-new-wrappers": "error", "no-octal-escape": "error", "no-param-reassign": "off", "no-path-concat": "error", "no-plusplus": "off", "no-process-env": "off", "no-process-exit": "error", "no-proto": "error", "no-prototype-builtins": "error", "no-restricted-globals": "error", "no-restricted-imports": "error", "no-restricted-modules": "error", "no-restricted-properties": "error", "no-restricted-syntax": "error", "no-return-assign": "error", "no-return-await": "off", "no-script-url": "error", "no-self-compare": "error", "no-sequences": "error", "no-shadow": "off", "no-shadow-restricted-names": "error", "no-sync": "error", "no-tabs": "error", "no-template-curly-in-string": "error", "no-ternary": "off", "no-throw-literal": "error", "no-trailing-spaces": "off", "no-undef-init": "error", "no-undefined": "off", "no-underscore-dangle": "off", "no-unmodified-loop-condition": "error", "no-unneeded-ternary": "off", "no-unused-vars": "error", "no-unused-expressions": "off", "no-use-before-define": "off", "no-useless-call": "error", "no-useless-catch": "off", "no-useless-computed-key": "error", "no-useless-concat": "off", "no-useless-constructor": "error", "no-useless-escape": "off", "no-useless-rename": "error", "no-useless-return": "off", "no-var": "off", "no-void": "error", "no-warning-comments": "off", "no-whitespace-before-property": "error", "no-with": "error", "object-curly-newline": "off", "object-curly-spacing": "off", "object-property-newline": ["off", { allowMultiplePropertiesPerLine: true, }], "object-shorthand": "off", "one-var": "off", "one-var-declaration-per-line": "off", "operator-assignment": "off", "operator-linebreak": "off", "padded-blocks": "off", "prefer-arrow-callback": "off", "prefer-const": "error", "prefer-destructuring": ["error", { array: false, object: false, }], "prefer-numeric-literals": "error", "prefer-promise-reject-errors": "off", "prefer-reflect": "off", "prefer-rest-params": "off", "prefer-spread": "off", "prefer-template": "off", "quote-props": "off", quotes: "off", radix: ["error", "always"], "require-atomic-updates": "off", "require-await": "error", "require-jsdoc": "off", "rest-spread-spacing": "error", semi: "off", "semi-spacing": "off", "sort-imports": "off", "sort-keys": "off", "sort-vars": "off", "space-before-blocks": "off", "space-before-function-paren": "off", "space-in-parens": "off", "space-infix-ops": "off", "space-unary-ops": "off", "spaced-comment": "off", strict: "off", "symbol-description": "error", "template-curly-spacing": "off", "unicode-bom": ["error", "never"], "valid-jsdoc": "off", "vars-on-top": "off", "wrap-iife": ["error", "any"], "wrap-regex": "error", "yield-star-spacing": "error", yoda: "off", }, }];strophejs-3.1.0/examples/000077500000000000000000000000001472775321000153625ustar00rootroot00000000000000strophejs-3.1.0/examples/amd.html000066400000000000000000000011101472775321000170020ustar00rootroot00000000000000 Strophe.js AMD Example

strophejs-3.1.0/examples/attach/000077500000000000000000000000001472775321000166265ustar00rootroot00000000000000strophejs-3.1.0/examples/attach/README000066400000000000000000000023171472775321000175110ustar00rootroot00000000000000This is an example of Strophe attaching to a pre-existing BOSH session that is created externally. This example requires a bit more than HTML and JavaScript. Specifically it contains a very simple Web application written in Django which creates a BOSH session before rendering the page. Requirements: * Django 1.0 (http://www.djangoproject.com) * Twisted 8.1.x (http://twistedmatrix.com) * Punjab 0.3 (http://code.stanziq.com/punjab) Note that Twisted and Punjab are only used for small functions related to JID and BOSH parsing. How It Works: The Django app contains one view which is tied to the root URL. This view uses the BOSHClient class to start a BOSH session using the settings from settings.py. Once the connection is established, Django passes the JID, SID, and RID for the BOSH session into the template engine and renders the page. The template assigns the JID, SID, and RID to global vars like so: var BOSH_JID = {{ jid }}; var BOSH_SID = {{ sid }}; var BOSH_RID = {{ rid }}; The connection is attached to Strophe by calling Strophe.Connection.attach() with this data and a connection callback handler. To show that the session is attached and works, a disco info ping is done to jabber.org. strophejs-3.1.0/examples/attach/__init__.py000066400000000000000000000000001472775321000207250ustar00rootroot00000000000000strophejs-3.1.0/examples/attach/attacher/000077500000000000000000000000001472775321000204215ustar00rootroot00000000000000strophejs-3.1.0/examples/attach/attacher/__init__.py000066400000000000000000000000001472775321000225200ustar00rootroot00000000000000strophejs-3.1.0/examples/attach/attacher/views.py000066400000000000000000000007331472775321000221330ustar00rootroot00000000000000from django.http import HttpResponse from django.template import Context, loader from attach.settings import BOSH_SERVICE, JABBERID, PASSWORD from attach.boshclient import BOSHClient def index(request): bc = BOSHClient(JABBERID, PASSWORD, BOSH_SERVICE) bc.startSessionAndAuth() t = loader.get_template("attacher/index.html") c = Context({ 'jid': bc.jabberid.full(), 'sid': bc.sid, 'rid': bc.rid, }) return HttpResponse(t.render(c)) strophejs-3.1.0/examples/attach/boshclient.py000066400000000000000000000122661472775321000213410ustar00rootroot00000000000000import sys, os import httplib, urllib import random, binascii from urlparse import urlparse from punjab.httpb import HttpbParse from twisted.words.xish import domish from twisted.words.protocols.jabber import jid TLS_XMLNS = 'urn:ietf:params:xml:ns:xmpp-tls' SASL_XMLNS = 'urn:ietf:params:xml:ns:xmpp-sasl' BIND_XMLNS = 'urn:ietf:params:xml:ns:xmpp-bind' SESSION_XMLNS = 'urn:ietf:params:xml:ns:xmpp-session' class BOSHClient: def __init__(self, jabberid, password, bosh_service): self.rid = random.randint(0, 10000000) self.jabberid = jid.internJID(jabberid) self.password = password self.authid = None self.sid = None self.logged_in = False self.headers = {"Content-type": "text/xml", "Accept": "text/xml"} self.bosh_service = urlparse(bosh_service) def buildBody(self, child=None): """Build a BOSH body. """ body = domish.Element(("http://jabber.org/protocol/httpbind", "body")) body['content'] = 'text/xml; charset=utf-8' self.rid = self.rid + 1 body['rid'] = str(self.rid) body['sid'] = str(self.sid) body['xml:lang'] = 'en' if child is not None: body.addChild(child) return body def sendBody(self, body): """Send the body. """ parser = HttpbParse(True) # start new session conn = httplib.HTTPConnection(self.bosh_service.netloc) conn.request("POST", self.bosh_service.path, body.toXml(), self.headers) response = conn.getresponse() data = '' if response.status == 200: data = response.read() conn.close() return parser.parse(data) def startSessionAndAuth(self, hold='1', wait='70'): # Create a session # create body body = domish.Element(("http://jabber.org/protocol/httpbind", "body")) body['content'] = 'text/xml; charset=utf-8' body['hold'] = hold body['rid'] = str(self.rid) body['to'] = self.jabberid.host body['wait'] = wait body['window'] = '5' body['xml:lang'] = 'en' retb, elems = self.sendBody(body) if type(retb) != str and retb.hasAttribute('authid') and \ retb.hasAttribute('sid'): self.authid = retb['authid'] self.sid = retb['sid'] # go ahead and auth auth = domish.Element((SASL_XMLNS, 'auth')) auth['mechanism'] = 'PLAIN' # TODO: add authzid if auth['mechanism'] == 'PLAIN': auth_str = "" auth_str += "\000" auth_str += self.jabberid.user.encode('utf-8') auth_str += "\000" try: auth_str += self.password.encode('utf-8').strip() except UnicodeDecodeError: auth_str += self.password.decode('latin1') \ .encode('utf-8').strip() auth.addContent(binascii.b2a_base64(auth_str)) retb, elems = self.sendBody(self.buildBody(auth)) if len(elems) == 0: # poll for data retb, elems = self.sendBody(self.buildBody()) if len(elems) > 0: if elems[0].name == 'success': retb, elems = self.sendBody(self.buildBody()) has_bind = False for child in elems[0].children: if child.name == 'bind': has_bind = True break if has_bind: iq = domish.Element(('jabber:client', 'iq')) iq['type'] = 'set' iq.addUniqueId() iq.addElement('bind') iq.bind['xmlns'] = BIND_XMLNS if self.jabberid.resource: iq.bind.addElement('resource') iq.bind.resource.addContent( self.jabberid.resource) retb, elems = self.sendBody(self.buildBody(iq)) if type(retb) != str and retb.name == 'body': # send session iq = domish.Element(('jabber:client', 'iq')) iq['type'] = 'set' iq.addUniqueId() iq.addElement('session') iq.session['xmlns'] = SESSION_XMLNS retb, elems = self.sendBody(self.buildBody(iq)) # did not bind, TODO - add a retry? if type(retb) != str and retb.name == 'body': self.logged_in = True # bump up the rid, punjab already # received self.rid self.rid += 1 if __name__ == '__main__': USERNAME = sys.argv[1] PASSWORD = sys.argv[2] SERVICE = sys.argv[3] c = BOSHClient(USERNAME, PASSWORD, SERVICE) c.startSessionAndAuth() print c.logged_in strophejs-3.1.0/examples/attach/manage.py000077500000000000000000000010421472775321000204300ustar00rootroot00000000000000#!/usr/bin/env python from django.core.management import execute_manager try: import settings # Assumed to be in the same directory. except ImportError: import sys sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) sys.exit(1) if __name__ == "__main__": execute_manager(settings) strophejs-3.1.0/examples/attach/settings.py000066400000000000000000000055441472775321000210500ustar00rootroot00000000000000# Django settings for attach project. DEBUG = True TEMPLATE_DEBUG = DEBUG ADMINS = ( ('Some Body', 'romeo@example.com'), ) MANAGERS = ADMINS DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. DATABASE_NAME = '/path/to/attach.db' # Or path to database file if using sqlite3. DATABASE_USER = '' # Not used with sqlite3. DATABASE_PASSWORD = '' # Not used with sqlite3. DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # although not all choices may be available on all operating systems. # If running in a Windows environment this must be set to the same as your # system time zone. TIME_ZONE = 'America/Denver' # Language code for this installation. All choices can be found here: # http://www.i18nguy.com/unicode/language-identifiers.html LANGUAGE_CODE = 'en-us' SITE_ID = 1 # If you set this to False, Django will make some optimizations so as not # to load the internationalization machinery. USE_I18N = True # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" MEDIA_ROOT = '' # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash if there is a path component (optional in other cases). # Examples: "http://media.lawrence.com", "http://example.com/media/" MEDIA_URL = '' # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a # trailing slash. # Examples: "http://foo.com/media/", "/media/". ADMIN_MEDIA_PREFIX = '/media/' # Make this unique, and don't share it with anybody. SECRET_KEY = 'asdf' # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.load_template_source', 'django.template.loaders.app_directories.load_template_source', # 'django.template.loaders.eggs.load_template_source', ) MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', ) ROOT_URLCONF = 'attach.urls' TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. '/path/to/attach/templates', ) INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'attach.attacher', ) BOSH_SERVICE = 'http://example.com/xmpp-httpbind' JABBERID = 'romeo@example.com/bosh' PASSWORD = 'juliet.is.hawt' strophejs-3.1.0/examples/attach/templates/000077500000000000000000000000001472775321000206245ustar00rootroot00000000000000strophejs-3.1.0/examples/attach/templates/attacher/000077500000000000000000000000001472775321000224175ustar00rootroot00000000000000strophejs-3.1.0/examples/attach/templates/attacher/index.html000066400000000000000000000054421472775321000244210ustar00rootroot00000000000000 Strophe Attach Example

Strophe Attach Example

This example shows how to attach to an existing BOSH session with Strophe.

Log

strophejs-3.1.0/examples/attach/urls.py000066400000000000000000000011061472775321000201630ustar00rootroot00000000000000from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: # from django.contrib import admin # admin.autodiscover() urlpatterns = patterns('', # Example: # (r'^attach/', include('attach.foo.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: # (r'^admin/(.*)', admin.site.root), (r'^$', 'attach.attacher.views.index'), ) strophejs-3.1.0/examples/basic.html000066400000000000000000000014271472775321000173350ustar00rootroot00000000000000 Strophe.js Basic Example

strophejs-3.1.0/examples/basic.js000066400000000000000000000037521472775321000170100ustar00rootroot00000000000000var BOSH_SERVICE = 'http://bosh.metajack.im:5280/xmpp-httpbind'; var connection = null; function log(msg, data) { var tr = document.createElement('tr'); var th = document.createElement('th'); th.setAttribute('style', 'text-align: left; vertical-align: top;'); var td; th.appendChild(document.createTextNode(msg)); tr.appendChild(th); if (data) { td = document.createElement('td'); pre = document.createElement('code'); pre.setAttribute('style', 'white-space: pre-wrap;'); td.appendChild(pre); pre.appendChild(document.createTextNode(vkbeautify.xml(data))); tr.appendChild(td); } else { th.setAttribute('colspan', '2'); } $('#log').append(tr); } function rawInput(data) { log('RECV', data); } function rawOutput(data) { log('SENT', data); } function onConnect(status) { if (status == Strophe.Status.CONNECTING) { log('Strophe is connecting.'); } else if (status == Strophe.Status.CONNFAIL) { log('Strophe failed to connect.'); $('#connect').get(0).value = 'connect'; } else if (status == Strophe.Status.DISCONNECTING) { log('Strophe is disconnecting.'); } else if (status == Strophe.Status.DISCONNECTED) { log('Strophe is disconnected.'); $('#connect').get(0).value = 'connect'; } else if (status == Strophe.Status.CONNECTED) { log('Strophe is connected.'); connection.disconnect(); } } $(document).ready(function () { connection = new Strophe.Connection(BOSH_SERVICE); connection.rawInput = rawInput; connection.rawOutput = rawOutput; $('#connect').bind('click', function () { var button = $('#connect').get(0); if (button.value == 'connect') { button.value = 'disconnect'; connection.connect($('#jid').get(0).value, $('#pass').get(0).value, onConnect); } else { button.value = 'connect'; connection.disconnect(); } }); }); strophejs-3.1.0/examples/echobot.html000066400000000000000000000015531472775321000176770ustar00rootroot00000000000000 Strophe.js Echobot Example

strophejs-3.1.0/examples/echobot.js000066400000000000000000000051011472775321000173400ustar00rootroot00000000000000/* global Strophe, $, $pres, $msg */ const BOSH_SERVICE = '/xmpp-httpbind'; let connection = null; function log(msg) { const log = document.querySelector('#log'); const div = document.createElement('div'); log.appendChild(div); div.appendChild(document.createTextNode(msg)); } function onConnect(status) { if (status == Strophe.Status.CONNECTING) { log('Strophe is connecting.'); } else if (status == Strophe.Status.CONNFAIL) { log('Strophe failed to connect.'); $('#connect').get(0).value = 'connect'; } else if (status == Strophe.Status.DISCONNECTING) { log('Strophe is disconnecting.'); } else if (status == Strophe.Status.DISCONNECTED) { log('Strophe is disconnected.'); $('#connect').get(0).value = 'connect'; } else if (status == Strophe.Status.CONNECTED) { log('Strophe is connected.'); log('ECHOBOT: Send a message to ' + connection.jid + ' to talk to me.'); connection.addHandler(onMessage, null, 'message', null, null, null); connection.send($pres().tree()); } } function onMessage(msg) { const to = msg.getAttribute('to'); const from = msg.getAttribute('from'); const type = msg.getAttribute('type'); const elems = msg.getElementsByTagName('body'); if (type == 'chat' && elems.length > 0) { const body = elems[0]; log('ECHOBOT: I got a message from ' + from + ': ' + Strophe.getText(body)); const reply = $msg({ to: from, from: to, type: 'chat' }).cnode(Strophe.copyElement(body)); connection.send(reply.tree()); log('ECHOBOT: I sent ' + from + ': ' + Strophe.getText(body)); } // we must return true to keep the handler alive. // returning false would remove it after it finishes. return true; } $(document).ready(function () { connection = new Strophe.Connection(BOSH_SERVICE); // Uncomment the following lines to spy on the wire traffic. //connection.rawInput = function (data) { log('RECV: ' + data); }; //connection.rawOutput = function (data) { log('SEND: ' + data); }; // Uncomment the following line to see all the debug output. //Strophe.log = function (level, msg) { log('LOG: ' + msg); }; $('#connect').bind('click', function () { const button = $('#connect').get(0); if (button.value == 'connect') { button.value = 'disconnect'; connection.connect($('#jid').get(0).value, $('#pass').get(0).value, onConnect); } else { button.value = 'connect'; connection.disconnect(); } }); }); strophejs-3.1.0/examples/main.js000066400000000000000000000037141472775321000166510ustar00rootroot00000000000000config.baseUrl = '../'; require.config(config); if (typeof require === 'function') { require(['jquery', 'strophe'], function ($, wrapper) { Strophe = wrapper.Strophe; var BOSH_SERVICE = 'http://bosh.metajack.im:5280/xmpp-httpbind'; var connection = null; function log(msg) { $('#log').append('
').append(document.createTextNode(msg)); } function rawInput(data) { log('RECV: ' + data); } function rawOutput(data) { log('SENT: ' + data); } function onConnect(status) { if (status == Strophe.Status.CONNECTING) { log('Strophe is connecting.'); } else if (status == Strophe.Status.CONNFAIL) { log('Strophe failed to connect.'); $('#connect').get(0).value = 'connect'; } else if (status == Strophe.Status.DISCONNECTING) { log('Strophe is disconnecting.'); } else if (status == Strophe.Status.DISCONNECTED) { log('Strophe is disconnected.'); $('#connect').get(0).value = 'connect'; } else if (status == Strophe.Status.CONNECTED) { log('Strophe is connected.'); connection.disconnect(); } } $(document).ready(function () { connection = new Strophe.Connection(BOSH_SERVICE); connection.rawInput = rawInput; connection.rawOutput = rawOutput; $('#connect').bind('click', function () { var button = $('#connect').get(0); if (button.value == 'connect') { button.value = 'disconnect'; connection.connect($('#jid').get(0).value, $('#pass').get(0).value, onConnect); } else { button.value = 'connect'; connection.disconnect(); } }); }); }); } strophejs-3.1.0/examples/prebind.html000066400000000000000000000021121472775321000176670ustar00rootroot00000000000000 Strophe.js Pre-Bind Example

strophejs-3.1.0/examples/prebind.js000066400000000000000000000060131472775321000173430ustar00rootroot00000000000000// http-pre-bind example // This example works with mod_http_pre_bind found here: // http://github.com/thepug/Mod-Http-Pre-Bind // // It expects both /xmpp-httpbind to be proxied and /http-pre-bind // // If you want to test this out without setting it up, you can use Collecta's // at http://www.collecta.com/xmpp-httpbind and // http://www.collecta.com/http-pre-bind // Use a JID of 'guest.collecta.com' to test. var BOSH_SERVICE = '/xmpp-httpbind'; var PREBIND_SERVICE = '/http-pre-bind'; var connection = null; function log(msg) { $('#log').append('
').append(document.createTextNode(msg)); } function rawInput(data) { log('RECV: ' + data); } function rawOutput(data) { log('SENT: ' + data); } function onConnect(status) { if (status === Strophe.Status.CONNECTING) { log('Strophe is connecting.'); } else if (status === Strophe.Status.CONNFAIL) { log('Strophe failed to connect.'); $('#connect').get(0).value = 'connect'; } else if (status === Strophe.Status.DISCONNECTING) { log('Strophe is disconnecting.'); } else if (status === Strophe.Status.DISCONNECTED) { log('Strophe is disconnected.'); $('#connect').get(0).value = 'connect'; } else if (status === Strophe.Status.CONNECTED) { log('Strophe is connected.'); connection.disconnect(); } else if (status === Strophe.Status.ATTACHED) { log('Strophe is attached.'); connection.disconnect(); } } function normal_connect() { log('Prebind failed. Connecting normally...'); connection = new Strophe.Connection(BOSH_SERVICE); connection.rawInput = rawInput; connection.rawOutput = rawOutput; connection.connect($('#jid').val(), $('#pass').val(), onConnect); } function attach(data) { log('Prebind succeeded. Attaching...'); connection = new Strophe.Connection(BOSH_SERVICE); connection.rawInput = rawInput; connection.rawOutput = rawOutput; var $body = $(data.documentElement); connection.attach($body.find('jid').text(), $body.attr('sid'), parseInt($body.attr('rid'), 10) + 1, onConnect); } $(document).ready(function () { $('#connect').bind('click', function () { var button = $('#connect').get(0); if (button.value == 'connect') { button.value = 'disconnect'; // attempt prebind $.ajax({ type: 'POST', url: PREBIND_SERVICE, contentType: 'text/xml', processData: false, data: $build('body', { to: Strophe.getDomainFromJid($('#jid').val()), rid: '' + Math.floor(Math.random() * 4294967295), wait: '60', hold: '1', }).toString(), dataType: 'xml', error: normal_connect, success: attach, }); } else { button.value = 'connect'; if (connection) { connection.disconnect(); } } }); }); strophejs-3.1.0/examples/restore.html000066400000000000000000000012161472775321000177330ustar00rootroot00000000000000 Strophe.js Persistent Session Example

strophejs-3.1.0/examples/restore.js000066400000000000000000000046261472775321000174130ustar00rootroot00000000000000config.baseUrl = '../'; require.config(config); if (typeof require === 'function') { require(['jquery', 'strophe'], function ($, wrapper) { Strophe = wrapper.Strophe; var button = document.getElementById('connect'); button.addEventListener('click', function () { if (button.value == 'connect') { button.value = 'disconnect'; connection.connect($('#jid').get(0).value, $('#pass').get(0).value, onConnect); } else { button.value = 'connect'; connection.disconnect(); } }); $(button).hide(); var BOSH_SERVICE = 'https://conversejs.org/http-bind/'; var connection = null; function log(msg) { $('#log').append('
').append(document.createTextNode(msg)); } function rawInput(data) { log('RECV: ' + data); } function rawOutput(data) { log('SENT: ' + data); } function onConnect(status) { if (status == Strophe.Status.CONNECTING) { log('Strophe is connecting.'); } else if (status == Strophe.Status.CONNFAIL) { log('Strophe failed to connect.'); $('#connect').get(0).value = 'connect'; } else if (status == Strophe.Status.DISCONNECTING) { log('Strophe is disconnecting.'); } else if (status == Strophe.Status.DISCONNECTED) { log('Strophe is disconnected.'); $('#connect').get(0).value = 'connect'; } else if (status == Strophe.Status.CONNECTED) { log('Strophe is connected.'); } else if (status == Strophe.Status.ATTACHED) { log('Strophe is attached.'); var button = $('#connect').get(0); button.value = 'disconnect'; $(button).show(); } } $(document).ready(function () { connection = new Strophe.Connection(BOSH_SERVICE, { 'keepalive': true }); connection.rawInput = rawInput; connection.rawOutput = rawOutput; try { connection.restore(null, onConnect); } catch (e) { if (e.name !== 'StropheSessionError') { throw e; } $(button).show(); } }); }); } strophejs-3.1.0/jsdoc.json000066400000000000000000000000501472775321000155340ustar00rootroot00000000000000{ "plugins": ["plugins/markdown"] } strophejs-3.1.0/karma.conf.js000066400000000000000000000031751472775321000161270ustar00rootroot00000000000000/* global module */ module.exports = function (config) { config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['qunit'], // list of files / patterns to load in the browser files: [ 'node_modules/sinon/pkg/sinon.js', 'dist/strophe.umd.js', 'tests/tests.js', ], // list of files to exclude exclude: [], // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter reporters: ['progress'], client: {}, // web server port port: 9876, // enable / disable colors in the output (reporters and logs) colors: true, // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes autoWatch: true, // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher browsers: ['Chrome'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: true, // Concurrency level // how many browser should be started simultaneous concurrency: Infinity, }); }; strophejs-3.1.0/package-lock.json000066400000000000000000007473431472775321000170020ustar00rootroot00000000000000{ "name": "strophe.js", "version": "3.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "strophe.js", "version": "3.1.0", "license": "MIT", "devDependencies": { "@babel/core": "^7.18.5", "@babel/eslint-parser": "^7.19.1", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/preset-env": "^7.18.2", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.16.0", "@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-commonjs": "^28.0.1", "@rollup/plugin-node-resolve": "^15.0.1", "almond": "~0.3.0", "es6-promise": "^4.2.8", "eslint": "^9.16.0", "globals": "^15.13.0", "http-server": "^14.1.0", "jsdoc": "^4.0.2", "karma": "^6.3.17", "karma-chrome-launcher": "^3.1.1", "karma-qunit": "^4.1.2", "karma-rollup-preprocessor": "^7.0.8", "minimist": "^1.2.5", "prettier": "^3.3.3", "qunit": "2.23.1", "rollup": "^2.32.1", "rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-terser": "^7.0.2", "run-headless-chromium": "^0.1.1", "sinon": "19.0.2", "terser": "^5.10.0", "typescript": "^5.1.6", "xhr2": "^0.2.1" }, "optionalDependencies": { "@types/jsdom": "^21.1.7", "@types/ws": "^8.5.5", "jsdom": "^25.0.1", "ws": "^8.18.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.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.0", "@babel/generator": "^7.26.0", "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-module-transforms": "^7.26.0", "@babel/helpers": "^7.26.0", "@babel/parser": "^7.26.0", "@babel/template": "^7.25.9", "@babel/traverse": "^7.25.9", "@babel/types": "^7.26.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/eslint-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz", "integrity": "sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==", "dev": true, "license": "MIT", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", "semver": "^6.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || >=14.0.0" }, "peerDependencies": { "@babel/core": "^7.11.0", "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/@babel/generator": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.26.3", "@babel/types": "^7.26.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.9", "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/traverse": "^7.25.9", "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz", "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-wrap-function": "^7.25.9", "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-replace-supers": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-member-expression-to-functions": "^7.25.9", "@babel/helper-optimise-call-expression": "^7.25.9", "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", "@babel/types": "^7.26.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.26.3" }, "bin": { "parser": "bin/babel-parser.js" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.13.0" } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-optional-chaining": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-async-generator-functions": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-remap-async-to-generator": "^7.25.9", "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-async-to-generator": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-block-scoping": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-class-properties": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-class-static-block": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "node_modules/@babel/plugin-transform-classes": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9", "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-classes/node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-destructuring": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-export-namespace-from": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-json-strings": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-literals": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.26.0", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-numeric-separator": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-object-rest-spread": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/plugin-transform-parameters": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-optional-chaining": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-private-methods": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-private-property-in-object": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "regenerator-transform": "^0.15.2" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-spread": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/preset-env": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.26.0", "@babel/helper-compilation-targets": "^7.25.9", "@babel/helper-plugin-utils": "^7.25.9", "@babel/helper-validator-option": "^7.25.9", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-import-assertions": "^7.26.0", "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.25.9", "@babel/plugin-transform-async-generator-functions": "^7.25.9", "@babel/plugin-transform-async-to-generator": "^7.25.9", "@babel/plugin-transform-block-scoped-functions": "^7.25.9", "@babel/plugin-transform-block-scoping": "^7.25.9", "@babel/plugin-transform-class-properties": "^7.25.9", "@babel/plugin-transform-class-static-block": "^7.26.0", "@babel/plugin-transform-classes": "^7.25.9", "@babel/plugin-transform-computed-properties": "^7.25.9", "@babel/plugin-transform-destructuring": "^7.25.9", "@babel/plugin-transform-dotall-regex": "^7.25.9", "@babel/plugin-transform-duplicate-keys": "^7.25.9", "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-dynamic-import": "^7.25.9", "@babel/plugin-transform-exponentiation-operator": "^7.25.9", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-for-of": "^7.25.9", "@babel/plugin-transform-function-name": "^7.25.9", "@babel/plugin-transform-json-strings": "^7.25.9", "@babel/plugin-transform-literals": "^7.25.9", "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", "@babel/plugin-transform-member-expression-literals": "^7.25.9", "@babel/plugin-transform-modules-amd": "^7.25.9", "@babel/plugin-transform-modules-commonjs": "^7.25.9", "@babel/plugin-transform-modules-systemjs": "^7.25.9", "@babel/plugin-transform-modules-umd": "^7.25.9", "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", "@babel/plugin-transform-new-target": "^7.25.9", "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", "@babel/plugin-transform-numeric-separator": "^7.25.9", "@babel/plugin-transform-object-rest-spread": "^7.25.9", "@babel/plugin-transform-object-super": "^7.25.9", "@babel/plugin-transform-optional-catch-binding": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9", "@babel/plugin-transform-parameters": "^7.25.9", "@babel/plugin-transform-private-methods": "^7.25.9", "@babel/plugin-transform-private-property-in-object": "^7.25.9", "@babel/plugin-transform-property-literals": "^7.25.9", "@babel/plugin-transform-regenerator": "^7.25.9", "@babel/plugin-transform-regexp-modifiers": "^7.26.0", "@babel/plugin-transform-reserved-words": "^7.25.9", "@babel/plugin-transform-shorthand-properties": "^7.25.9", "@babel/plugin-transform-spread": "^7.25.9", "@babel/plugin-transform-sticky-regex": "^7.25.9", "@babel/plugin-transform-template-literals": "^7.25.9", "@babel/plugin-transform-typeof-symbol": "^7.25.9", "@babel/plugin-transform-unicode-escapes": "^7.25.9", "@babel/plugin-transform-unicode-property-regex": "^7.25.9", "@babel/plugin-transform-unicode-regex": "^7.25.9", "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/preset-modules": { "version": "0.1.6-no-external-plugins", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", "esutils": "^2.0.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/runtime": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "dev": true, "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.9", "@babel/parser": "^7.25.9", "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { "version": "7.26.4", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.3", "@babel/parser": "^7.26.3", "@babel/template": "^7.25.9", "@babel/types": "^7.26.3", "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse/node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/@babel/types": { "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, "license": "MIT", "engines": { "node": ">=0.1.90" } }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "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.19.1", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.5", "debug": "^4.3.1", "minimatch": "^3.1.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", "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.2.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "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/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/@eslint/js": { "version": "9.17.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/object-schema": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/plugin-kit": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", "dev": true, "license": "Apache-2.0", "dependencies": { "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "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.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" }, "funding": { "type": "github", "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "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/set-array": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@jsdoc/salty": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz", "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==", "dev": true, "license": "Apache-2.0", "dependencies": { "lodash": "^4.17.21" }, "engines": { "node": ">=v12.0.0" } }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", "dev": true, "license": "MIT", "dependencies": { "eslint-scope": "5.1.1" } }, "node_modules/@rollup/plugin-babel": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.0.4.tgz", "integrity": "sha512-YF7Y52kFdFT/xVSuVdjkV5ZdX/3YtmX0QulG+x0taQOtJdHYzVU61aSSkAgVJ7NOv6qPkIYiJSgSWWN/DM5sGw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.18.6", "@rollup/pluginutils": "^5.0.1" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0", "@types/babel__core": "^7.1.9", "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "@types/babel__core": { "optional": true }, "rollup": { "optional": true } } }, "node_modules/@rollup/plugin-commonjs": { "version": "28.0.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.2.tgz", "integrity": "sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", "fdir": "^6.2.0", "is-reference": "1.2.1", "magic-string": "^0.30.3", "picomatch": "^4.0.2" }, "engines": { "node": ">=16.0.0 || 14 >= 14.17" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { "optional": true } } }, "node_modules/@rollup/plugin-node-resolve": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", "integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==", "dev": true, "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { "optional": true } } }, "node_modules/@rollup/pluginutils": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { "optional": true } } }, "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, "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/@sinonjs/text-encoding": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", "dev": true, "license": "(Unlicense OR Apache-2.0)" }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true, "license": "MIT" }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", "dev": true, "license": "MIT" }, "node_modules/@types/cors": { "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, "license": "MIT" }, "node_modules/@types/jsdom": { "version": "21.1.7", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", "license": "MIT", "optional": true, "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", "parse5": "^7.0.0" } }, "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/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", "dev": true, "license": "MIT" }, "node_modules/@types/markdown-it": { "version": "14.1.2", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, "license": "MIT", "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "node_modules/@types/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "22.10.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" } }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true, "license": "MIT" }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", "license": "MIT", "optional": true }, "node_modules/@types/ws": { "version": "8.5.13", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" } }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" } }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "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/agent-base": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "license": "MIT", "optional": true, "engines": { "node": ">= 14" } }, "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/almond": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz", "integrity": "sha512-Eh5QhyxrKnTI0OuGpwTRvzRrnu1NF3F2kbQJRwpXj/uMy0uycwqw2/RhdDrD1cBTD1JFFHFrxGIU8HQztowR0g==", "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" } }, "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/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": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" }, "engines": { "node": ">= 8" } }, "node_modules/anymatch/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/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/async": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, "license": "MIT", "dependencies": { "lodash": "^4.17.14" } }, "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", "optional": true }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.12", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", "@babel/helper-define-polyfill-provider": "^0.6.3", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.10.6", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.2", "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.6.3" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "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/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true, "license": "MIT", "engines": { "node": "^4.5.0 || >= 5.9" } }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" }, "engines": { "node": ">= 0.8" } }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true, "license": "MIT" }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "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/browserslist": { "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "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.30001669", "electron-to-chromium": "^1.5.41", "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, "node_modules/buffer-es6": { "version": "4.9.3", "resolved": "https://registry.npmjs.org/buffer-es6/-/buffer-es6-4.9.3.tgz", "integrity": "sha512-Ibt+oXxhmeYJSsCkODPqNpPmyegefiD8rfutH1NYGhMZQhSp95Rz7haemgnJ6dxa6LT+JLLbtgOMORRluwKktw==", "dev": true, "license": "MIT" }, "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/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.1", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/call-bound": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.2.tgz", "integrity": "sha512-0lk0PHFe/uz0vl527fG9CgdE9WdafjDbCXvBbs+LUv000TVt2Jjhqbs4Jwm8gz070w8xXyEAxrPOMullsxXeGg==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "get-intrinsic": "^1.2.5" }, "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/caniuse-lite": { "version": "1.0.30001687", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001687.tgz", "integrity": "sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==", "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/catharsis": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", "dev": true, "license": "MIT", "dependencies": { "lodash": "^4.17.15" }, "engines": { "node": ">= 10" } }, "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/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "engines": { "node": ">= 8.10.0" }, "funding": { "url": "https://paulmillr.com/funding/" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "node_modules/chokidar/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/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "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/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/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", "optional": true, "dependencies": { "delayed-stream": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, "license": "MIT", "engines": { "node": ">= 10" } }, "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/connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", "parseurl": "~1.3.3", "utils-merge": "1.0.1" }, "engines": { "node": ">= 0.10.0" } }, "node_modules/connect/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, "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": "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/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/core-js-compat": { "version": "3.39.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.24.2" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" } }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" }, "engines": { "node": ">= 0.10" } }, "node_modules/corser": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4.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/cssstyle": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "license": "MIT", "optional": true, "dependencies": { "rrweb-cssom": "^0.7.1" }, "engines": { "node": ">=18" } }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true, "license": "MIT" }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "license": "MIT", "optional": true, "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" }, "engines": { "node": ">=18" } }, "node_modules/date-format": { "version": "4.0.14", "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, "license": "MIT", "engines": { "node": ">=4.0" } }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", "dev": true, "license": "MIT" }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "devOptional": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/decimal.js": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "license": "MIT", "optional": true }, "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/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "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/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", "optional": true, "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/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true, "license": "MIT" }, "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, "engines": { "node": ">=0.3.1" } }, "node_modules/dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "license": "MIT", "dependencies": { "custom-event": "~1.0.0", "ent": "~2.2.0", "extend": "^3.0.0", "void-elements": "^2.0.0" } }, "node_modules/dunder-proto": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.2.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.73", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.73.tgz", "integrity": "sha512-8wGNxG9tAG5KhGd3eeA0o6ixhiNdgr0DcHWm85XPCphwZgD1lIEoi6t3VERayWao7SF7AAZTw6oARGJeVjH8Kg==", "dev": true, "license": "ISC" }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/engine.io": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz", "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==", "dev": true, "license": "MIT", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", "ws": "~8.17.1" }, "engines": { "node": ">=10.2.0" } }, "node_modules/engine.io-parser": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/engine.io/node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/engine.io/node_modules/ws": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { "optional": true }, "utf-8-validate": { "optional": true } } }, "node_modules/ent": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.1.tgz", "integrity": "sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A==", "dev": true, "license": "MIT", "dependencies": { "punycode": "^1.4.1" }, "engines": { "node": ">= 0.4" } }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "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==", "dev": true, "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==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-object-atoms": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "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.17.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.9.0", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "9.17.0", "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "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.2.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.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": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" }, "engines": { "node": ">=8.0.0" } }, "node_modules/eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10" } }, "node_modules/eslint/node_modules/eslint-scope": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "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/node_modules/eslint-visitor-keys": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "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/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/espree": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/espree/node_modules/eslint-visitor-keys": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "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/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/esquery/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/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/esrecurse/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/estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, "license": "MIT" }, "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/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, "license": "MIT" }, "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-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/fdir": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz", "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==", "dev": true, "peerDependencies": { "picomatch": "^3 || ^4" }, "peerDependenciesMeta": { "picomatch": { "optional": true } } }, "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": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, "node_modules/finalhandler/node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, "engines": { "node": ">= 0.8" } }, "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-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.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "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==", "dev": true, "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], "license": "MIT", "engines": { "node": ">=4.0" }, "peerDependenciesMeta": { "debug": { "optional": true } } }, "node_modules/form-data": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "license": "MIT", "optional": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" }, "engines": { "node": ">= 6" } }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" }, "engines": { "node": ">=6 <7 || >=8" } }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "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==", "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.2.6", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "dunder-proto": "^1.0.0", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.0.0" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "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/globals": { "version": "15.13.0", "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", "dev": true, "license": "MIT", "engines": { "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalyzer": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", "dev": true, "license": "MIT" }, "node_modules/globrex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true, "license": "MIT" }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "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/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-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "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-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, "license": "MIT", "dependencies": { "whatwg-encoding": "^2.0.0" }, "engines": { "node": ">=12" } }, "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/http-errors/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/http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" }, "engines": { "node": ">=8.0.0" } }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "license": "MIT", "optional": true, "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" }, "engines": { "node": ">= 14" } }, "node_modules/http-server": { "version": "14.1.1", "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", "dev": true, "license": "MIT", "dependencies": { "basic-auth": "^2.0.1", "chalk": "^4.1.2", "corser": "^2.0.1", "he": "^1.2.0", "html-encoding-sniffer": "^3.0.0", "http-proxy": "^1.18.1", "mime": "^1.6.0", "minimist": "^1.2.6", "opener": "^1.5.1", "portfinder": "^1.0.28", "secure-compare": "3.0.1", "union": "~0.5.0", "url-join": "^4.0.1" }, "bin": { "http-server": "bin/http-server" }, "engines": { "node": ">=12" } }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "optional": true, "dependencies": { "agent-base": "^7.1.2", "debug": "4" }, "engines": { "node": ">= 14" } }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, "engines": { "node": ">=0.10.0" } }, "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.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "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/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/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==", "dev": true, "license": "ISC" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, "engines": { "node": ">=8" } }, "node_modules/is-core-module": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "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-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-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-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true, "license": "MIT" }, "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-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "license": "MIT", "optional": true }, "node_modules/is-reference": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/isbinaryfile": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "license": "MIT", "engines": { "node": ">= 8.0.0" }, "funding": { "url": "https://github.com/sponsors/gjtorikian/" } }, "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/jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^7.0.0" }, "engines": { "node": ">= 10.13.0" } }, "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/js2xmlparser": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", "dev": true, "license": "Apache-2.0", "dependencies": { "xmlcreate": "^2.0.4" } }, "node_modules/jsdoc": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz", "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==", "dev": true, "license": "Apache-2.0", "dependencies": { "@babel/parser": "^7.20.15", "@jsdoc/salty": "^0.2.1", "@types/markdown-it": "^14.1.1", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", "markdown-it": "^14.1.0", "markdown-it-anchor": "^8.6.7", "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "underscore": "~1.13.2" }, "bin": { "jsdoc": "jsdoc.js" }, "engines": { "node": ">=12.0.0" } }, "node_modules/jsdoc/node_modules/escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jsdom": { "version": "25.0.1", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "license": "MIT", "optional": true, "dependencies": { "cssstyle": "^4.1.0", "data-urls": "^5.0.0", "decimal.js": "^10.4.3", "form-data": "^4.0.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.5", "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.12", "parse5": "^7.1.2", "rrweb-cssom": "^0.7.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^5.0.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0", "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "engines": { "node": ">=18" }, "peerDependencies": { "canvas": "^2.11.2" }, "peerDependenciesMeta": { "canvas": { "optional": true } } }, "node_modules/jsdom/node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "license": "MIT", "optional": true, "dependencies": { "whatwg-encoding": "^3.1.1" }, "engines": { "node": ">=18" } }, "node_modules/jsdom/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==", "license": "MIT", "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" } }, "node_modules/jsdom/node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "0.6.3" }, "engines": { "node": ">=18" } }, "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/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "node_modules/just-extend": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", "dev": true, "license": "MIT" }, "node_modules/karma": { "version": "6.4.4", "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", "braces": "^3.0.2", "chokidar": "^3.5.1", "connect": "^3.7.0", "di": "^0.0.1", "dom-serialize": "^2.2.1", "glob": "^7.1.7", "graceful-fs": "^4.2.6", "http-proxy": "^1.18.1", "isbinaryfile": "^4.0.8", "lodash": "^4.17.21", "log4js": "^6.4.1", "mime": "^2.5.2", "minimatch": "^3.0.4", "mkdirp": "^0.5.5", "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", "socket.io": "^4.7.2", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", "yargs": "^16.1.1" }, "bin": { "karma": "bin/karma" }, "engines": { "node": ">= 10" } }, "node_modules/karma-chrome-launcher": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", "dev": true, "license": "MIT", "dependencies": { "which": "^1.2.1" } }, "node_modules/karma-chrome-launcher/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "bin/which" } }, "node_modules/karma-qunit": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/karma-qunit/-/karma-qunit-4.2.1.tgz", "integrity": "sha512-bd4TXH8L7i3hYelRo/5OTlyRiMrSyUpgI94pzkASaD/qjlc1j8liuZeroRS4aA5B7AmnCYQILEsKcSfuaQgcPA==", "dev": true, "license": "MIT", "peerDependencies": { "karma": "^4.0.0 || ^5.0.0 || ^6.0.0", "qunit": ">=2.1.1" } }, "node_modules/karma-rollup-preprocessor": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/karma-rollup-preprocessor/-/karma-rollup-preprocessor-7.0.8.tgz", "integrity": "sha512-WiuBCS9qsatJuR17dghiTARBZ7LF+ml+eb7qJXhw7IbsdY0lTWELDRQC/93J9i6636CsAXVBL3VJF4WtaFLZzA==", "dev": true, "license": "MIT", "dependencies": { "chokidar": "^3.3.1", "debounce": "^1.2.0" }, "engines": { "node": ">= 8.0.0" }, "peerDependencies": { "rollup": ">= 1.0.0" } }, "node_modules/karma/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/karma/node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, "license": "MIT", "bin": { "mime": "cli.js" }, "engines": { "node": ">=4.0.0" } }, "node_modules/karma/node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "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/klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.1.9" } }, "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==", "dev": true, "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "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==", "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/log4js": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, "license": "Apache-2.0", "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" }, "engines": { "node": ">=8.0" } }, "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/magic-string": { "version": "0.30.15", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.15.tgz", "integrity": "sha512-zXeaYRgZ6ldS1RJJUrMrYgNJ4fdwnyI6tVqoiIhyCyv5IVTK9BU8Ic2l253GGETQHxI4HNUwhJ3fjDhKqEoaAw==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "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-anchor": { "version": "8.6.7", "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", "dev": true, "license": "Unlicense", "peerDependencies": { "@types/markdown-it": "*", "markdown-it": "*" } }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true, "license": "MIT", "bin": { "marked": "bin/marked.js" }, "engines": { "node": ">= 12" } }, "node_modules/math-intrinsics": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz", "integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "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": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, "license": "MIT" }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "license": "MIT", "bin": { "mime": "cli.js" }, "engines": { "node": ">=4" } }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "devOptional": true, "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==", "devOptional": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" } }, "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/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, "engines": { "node": ">=10" } }, "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==", "devOptional": true, "license": "MIT" }, "node_modules/nan": { "version": "2.22.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", "dev": true, "license": "MIT", "optional": true }, "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": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/nise": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/nise/-/nise-6.1.1.tgz", "integrity": "sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", "@sinonjs/fake-timers": "^13.0.1", "@sinonjs/text-encoding": "^0.7.3", "just-extend": "^6.2.0", "path-to-regexp": "^8.1.0" } }, "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/node-watch": { "version": "0.7.3", "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==", "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/nwsapi": { "version": "2.2.16", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", "license": "MIT", "optional": true }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "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==", "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true, "license": "(WTFPL OR MIT)", "bin": { "opener": "bin/opener-bin.js" } }, "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/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/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/parse5": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "license": "MIT", "optional": true, "dependencies": { "entities": "^4.5.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" } }, "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-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, "license": "MIT" }, "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, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", "engines": { "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/portfinder": { "version": "1.0.32", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", "dev": true, "license": "MIT", "dependencies": { "async": "^2.6.4", "debug": "^3.2.7", "mkdirp": "^0.5.6" }, "engines": { "node": ">= 0.12.0" } }, "node_modules/portfinder/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/portfinder/node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "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.4.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, "engines": { "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/process-es6": { "version": "0.11.6", "resolved": "https://registry.npmjs.org/process-es6/-/process-es6-0.11.6.tgz", "integrity": "sha512-GYBRQtL4v3wgigq10Pv58jmTbFXlIiTbSfgnNqZLY0ldUPqy1rRxDI5fCjoCpnM6TqmHQI8ydzTBXW86OYc0gA==", "dev": true, "license": "MIT" }, "node_modules/punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true, "license": "MIT" }, "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/qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, "license": "MIT", "engines": { "node": ">=0.9" } }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/qunit": { "version": "2.23.1", "resolved": "https://registry.npmjs.org/qunit/-/qunit-2.23.1.tgz", "integrity": "sha512-CGrsGy7NhkQmfiyOixBpbexh2PT7ekIb35uWiBi/hBNdTJF1W98UonyACFJJs8UmcP96lH+YJlX99dYZi5rZkg==", "dev": true, "dependencies": { "commander": "7.2.0", "node-watch": "0.7.3", "tiny-glob": "0.2.9" }, "bin": { "qunit": "bin/qunit.js" }, "engines": { "node": ">=10" } }, "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": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "engines": { "node": ">= 0.8" } }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, "engines": { "node": ">=8.10.0" } }, "node_modules/readdirp/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/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true, "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, "engines": { "node": ">=4" } }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "dev": true, "license": "MIT" }, "node_modules/regenerator-transform": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regexpu-core": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "dev": true, "license": "MIT", "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", "regjsgen": "^0.8.0", "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, "engines": { "node": ">=4" } }, "node_modules/regjsgen": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", "dev": true, "license": "MIT" }, "node_modules/regjsparser": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, "node_modules/regjsparser/node_modules/jsesc": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { "node": ">=6" } }, "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/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true, "license": "MIT" }, "node_modules/requizzle": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", "dev": true, "license": "MIT", "dependencies": { "lodash": "^4.17.21" } }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "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/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true, "license": "MIT" }, "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/rollup": { "version": "2.79.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, "engines": { "node": ">=10.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-node-globals": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/rollup-plugin-node-globals/-/rollup-plugin-node-globals-1.4.0.tgz", "integrity": "sha512-xRkB+W/m1KLIzPUmG0ofvR+CPNcvuCuNdjVBVS7ALKSxr3EDhnzNceGkGi1m8MToSli13AzKFYH4ie9w3I5L3g==", "dev": true, "license": "MIT", "dependencies": { "acorn": "^5.7.3", "buffer-es6": "^4.9.3", "estree-walker": "^0.5.2", "magic-string": "^0.22.5", "process-es6": "^0.11.6", "rollup-pluginutils": "^2.3.1" } }, "node_modules/rollup-plugin-node-globals/node_modules/acorn": { "version": "5.7.4", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" }, "engines": { "node": ">=0.4.0" } }, "node_modules/rollup-plugin-node-globals/node_modules/estree-walker": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz", "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==", "dev": true, "license": "MIT" }, "node_modules/rollup-plugin-node-globals/node_modules/magic-string": { "version": "0.22.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "dev": true, "license": "MIT", "dependencies": { "vlq": "^0.2.2" } }, "node_modules/rollup-plugin-terser": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", "jest-worker": "^26.2.1", "serialize-javascript": "^4.0.0", "terser": "^5.0.0" }, "peerDependencies": { "rollup": "^2.0.0" } }, "node_modules/rollup-pluginutils": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", "dev": true, "license": "MIT", "dependencies": { "estree-walker": "^0.6.1" } }, "node_modules/rollup-pluginutils/node_modules/estree-walker": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", "dev": true, "license": "MIT" }, "node_modules/rrweb-cssom": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", "license": "MIT", "optional": true }, "node_modules/run-headless-chromium": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/run-headless-chromium/-/run-headless-chromium-0.1.1.tgz", "integrity": "sha512-ylyaNQvvevbxQ0nNI2usr/9vAN9Vd/NeNjMHf+mj5k1cc6PE5+fsYbg+yMkEw9OiD1fjlzpdri1uCJwxqntlAw==", "dev": true, "license": "MIT", "dependencies": { "rimraf": "2.2.8", "which": "1.0.5", "xvfb": "0.2.3" }, "bin": { "run-headless-chromium": "run-headless-chromium.js" } }, "node_modules/run-headless-chromium/node_modules/rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "MIT", "bin": { "rimraf": "bin.js" } }, "node_modules/run-headless-chromium/node_modules/which": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/which/-/which-1.0.5.tgz", "integrity": "sha512-p82w9e3628Y1sCI41PbzZb5Qbacst2Yt/gE4mtqrNXv65SmwNbAcQvS4VkehtqmclAcOh36tgQiwhg6fKvkyDA==", "dev": true, "bin": { "which": "bin/which" }, "engines": { "node": "*" } }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "devOptional": true, "license": "MIT" }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "license": "ISC", "optional": true, "dependencies": { "xmlchars": "^2.2.0" }, "engines": { "node": ">=v12.22.7" } }, "node_modules/secure-compare": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", "dev": true, "license": "MIT" }, "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/serialize-javascript": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } }, "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/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/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, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel-list": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel-map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "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" }, "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/sinon": { "version": "19.0.2", "resolved": "https://registry.npmjs.org/sinon/-/sinon-19.0.2.tgz", "integrity": "sha512-euuToqM+PjO4UgXeLETsfQiuoyPXlqFezr6YZDFwHR3t4qaX0fZUe1MfPMznTL5f8BWrVS89KduLdMUsxFCO6g==", "dev": true, "dependencies": { "@sinonjs/commons": "^3.0.1", "@sinonjs/fake-timers": "^13.0.2", "@sinonjs/samsam": "^8.0.1", "diff": "^7.0.0", "nise": "^6.1.1", "supports-color": "^7.2.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/sinon" } }, "node_modules/sleep": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sleep/-/sleep-3.0.1.tgz", "integrity": "sha512-dtegFdlKDk05SQzlA29LVj8gzf01bTvtSOHCt+JwYRXEmx3qp85OZ+MpB65IYwxTNylwSmq8mOcsa4MitU8PpQ==", "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, "dependencies": { "nan": ">=2.0.0" }, "engines": { "node": ">=0.4.0" } }, "node_modules/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, "engines": { "node": ">=10.2.0" } }, "node_modules/socket.io-adapter": { "version": "2.5.5", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", "dev": true, "license": "MIT", "dependencies": { "debug": "~4.3.4", "ws": "~8.17.1" } }, "node_modules/socket.io-adapter/node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/socket.io-adapter/node_modules/ws": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { "optional": true }, "utf-8-validate": { "optional": true } } }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" }, "engines": { "node": ">=10.0.0" } }, "node_modules/socket.io-parser/node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/socket.io/node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "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/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/streamroller": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, "license": "MIT", "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "fs-extra": "^8.1.0" }, "engines": { "node": ">=8.0" } }, "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/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": "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/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "license": "MIT", "optional": true }, "node_modules/terser": { "version": "5.37.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" }, "engines": { "node": ">=10" } }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, "license": "MIT" }, "node_modules/tiny-glob": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", "dev": true, "license": "MIT", "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, "node_modules/tldts": { "version": "6.1.67", "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.67.tgz", "integrity": "sha512-714VbegxoZ9WF5/IsVCy9rWXKUpPkJq87ebWLXQzNawce96l5oRrRf2eHzB4pT2g/4HQU1dYbu+sdXClYxlDKQ==", "license": "MIT", "optional": true, "dependencies": { "tldts-core": "^6.1.67" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { "version": "6.1.67", "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.67.tgz", "integrity": "sha512-12K5O4m3uUW6YM5v45Z7wc6NTSmAYj4Tq3de7eXghZkp879IlfPJrUWeWFwu1FS94U5t2vwETgJ1asu8UGNKVQ==", "license": "MIT", "optional": true }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, "license": "MIT", "engines": { "node": ">=14.14" } }, "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/tough-cookie": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", "license": "BSD-3-Clause", "optional": true, "dependencies": { "tldts": "^6.1.32" }, "engines": { "node": ">=16" } }, "node_modules/tr46": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "license": "MIT", "optional": true, "dependencies": { "punycode": "^2.3.1" }, "engines": { "node": ">=18" } }, "node_modules/tr46/node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", "optional": true, "engines": { "node": ">=6" } }, "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-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" }, "engines": { "node": ">= 0.6" } }, "node_modules/typescript": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { "node": ">=14.17" } }, "node_modules/ua-parser-js": { "version": "0.7.39", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.39.tgz", "integrity": "sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/ua-parser-js" }, { "type": "paypal", "url": "https://paypal.me/faisalman" }, { "type": "github", "url": "https://github.com/sponsors/faisalman" } ], "license": "MIT", "bin": { "ua-parser-js": "script/cli.js" }, "engines": { "node": "*" } }, "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/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/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "devOptional": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" }, "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/union": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", "dev": true, "dependencies": { "qs": "^6.4.0" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", "engines": { "node": ">= 4.0.0" } }, "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.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "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.0" }, "bin": { "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" } }, "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/uri-js/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/url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", "dev": true, "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4.0" } }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/vlq": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", "dev": true, "license": "MIT" }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "license": "MIT", "optional": true, "dependencies": { "xml-name-validator": "^5.0.0" }, "engines": { "node": ">=18" } }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "license": "BSD-2-Clause", "optional": true, "engines": { "node": ">=12" } }, "node_modules/whatwg-encoding": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, "license": "MIT", "dependencies": { "iconv-lite": "0.6.3" }, "engines": { "node": ">=12" } }, "node_modules/whatwg-encoding/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/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", "optional": true, "engines": { "node": ">=18" } }, "node_modules/whatwg-url": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "license": "MIT", "optional": true, "dependencies": { "tr46": "^5.0.0", "webidl-conversions": "^7.0.0" }, "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/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/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, "license": "ISC" }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "license": "MIT", "optional": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { "optional": true }, "utf-8-validate": { "optional": true } } }, "node_modules/xhr2": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.2.1.tgz", "integrity": "sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==", "dev": true, "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "license": "Apache-2.0", "optional": true, "engines": { "node": ">=18" } }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "license": "MIT", "optional": true }, "node_modules/xmlcreate": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true, "license": "Apache-2.0" }, "node_modules/xvfb": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/xvfb/-/xvfb-0.2.3.tgz", "integrity": "sha512-83mh/9xBiJZ6bc3E188hhOTw0vIJer9K/poGnrocCgPVinn42cvERKsXcKKVerkSBlzCBhC2n6ewf2VaRHsHwQ==", "dev": true, "license": "MIT", "optionalDependencies": { "sleep": "3.0.x" } }, "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/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" }, "engines": { "node": ">=10" } }, "node_modules/yargs-parser": { "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "license": "ISC", "engines": { "node": ">=10" } }, "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/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" } } } } strophejs-3.1.0/package.json000066400000000000000000000057141472775321000160410ustar00rootroot00000000000000{ "name": "strophe.js", "description": "Strophe.js is an XMPP library for JavaScript", "version": "3.1.0", "homepage": "http://strophe.im/strophejs", "repository": { "type": "git", "url": "git://github.com/strophe/strophejs.git" }, "keywords": [ "xmpp", "message", "bosh", "websocket", "browser" ], "files": [ "src/", "dist/", "CHANGELOG.txt", "LICENSE.txt", "README.txt" ], "author": "Jack Moffit (metajack)", "contributors": [ "Nathan Zorn (thepug)", "Andreas Guth (Gordin)", "Anton Stroganov (Aeon)", "Florian Zeitz (Florob)", "Christopher Zorn (twonds)", "dodo", "Lee Boynton (lboynton)", "Theo Cushion (theozaurus)", "Brendon Crawford (brendoncrawford)", "JC Brand (jcbrand)" ], "license": "MIT", "browserslist": ">1%, maintained node versions", "main": "src/index.js", "types": "src/types/index.d.ts", "browser": "dist/strophe.umd.js", "module": "dist/strophe.esm.js", "unpkg": "dist/strophe.umd.min.js", "exports": { "node": { "import": "./dist/strophe.esm.js", "require": "./dist/strophe.common.js" }, "types": "./src/types/index.d.ts", "default": "./src/index.js" }, "scripts": { "types": "tsc", "build": "rollup -c", "lint": "eslint src/*.js tests/tests.js", "clean": "make clean", "doc": "make doc", "debug-node": "NODE_OPTIONS='--inspect-wait' qunit -w --require ./tests/node tests/tests.js", "test-node": "qunit --require ./tests/node tests/tests.js", "test-browser": "karma start", "test": "npm run test-node && npm run test-browser && npm run lint", "prettier": "prettier --write src/*.js" }, "volo": { "url": "https://raw.githubusercontent.com/strophe/strophejs/release-{version}/strophe.js" }, "devDependencies": { "@babel/core": "^7.18.5", "@babel/eslint-parser": "^7.19.1", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/preset-env": "^7.18.2", "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.16.0", "@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-commonjs": "^28.0.1", "@rollup/plugin-node-resolve": "^15.0.1", "almond": "~0.3.0", "es6-promise": "^4.2.8", "eslint": "^9.16.0", "globals": "^15.13.0", "http-server": "^14.1.0", "jsdoc": "^4.0.2", "karma": "^6.3.17", "karma-chrome-launcher": "^3.1.1", "karma-qunit": "^4.1.2", "karma-rollup-preprocessor": "^7.0.8", "minimist": "^1.2.5", "prettier": "^3.3.3", "qunit": "2.23.1", "rollup": "^2.32.1", "rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-terser": "^7.0.2", "run-headless-chromium": "^0.1.1", "sinon": "19.0.2", "terser": "^5.10.0", "typescript": "^5.1.6", "xhr2": "^0.2.1" }, "optionalDependencies": { "@types/jsdom": "^21.1.7", "@types/ws": "^8.5.5", "jsdom": "^25.0.1", "ws": "^8.18.0" } } strophejs-3.1.0/rollup.config.js000066400000000000000000000023051472775321000166630ustar00rootroot00000000000000import babel from '@rollup/plugin-babel'; import commonjs from '@rollup/plugin-commonjs'; import globals from 'rollup-plugin-node-globals'; import pkg from './package.json'; import resolve from '@rollup/plugin-node-resolve'; import { terser } from 'rollup-plugin-terser'; import { babelConfig } from './babel.config.json'; export default [ // browser-friendly UMD build { input: 'src/index.js', output: { name: 'strophe', file: pkg.browser, format: 'umd', }, plugins: [babel(babelConfig), resolve(), commonjs(), globals()], }, // Minified UMD build { input: 'src/index.js', output: { name: 'strophe', file: 'dist/strophe.umd.min.js', format: 'umd', }, plugins: [babel(babelConfig), resolve(), commonjs(), globals(), terser()], }, // CommonJS (for Node) and ES module (for bundlers) build. { input: 'src/index.js', external: ['window'], output: [ { file: 'dist/strophe.common.js', format: 'cjs' }, { file: pkg.module, format: 'es' }, ], plugins: [babel(babelConfig), globals()], }, ]; strophejs-3.1.0/src/000077500000000000000000000000001472775321000143335ustar00rootroot00000000000000strophejs-3.1.0/src/bosh.js000066400000000000000000000724341472775321000156360ustar00rootroot00000000000000/** * A JavaScript library to enable BOSH in Strophejs. * * this library uses Bidirectional-streams Over Synchronous HTTP (BOSH) * to emulate a persistent, stateful, two-way connection to an XMPP server. * More information on BOSH can be found in XEP 124. */ /** * @typedef {import("./connection.js").default} Connection */ import log from './log.js'; import Builder, { $build } from './builder.js'; import Request from './request.js'; import { getBareJidFromJid, getDomainFromJid, getNodeFromJid } from './utils.js'; import { Status, NS } from './constants.js'; let timeoutMultiplier = 1.1; let secondaryTimeoutMultiplier = 0.1; /** * _Private_ helper class that handles BOSH Connections * The Bosh class is used internally by Connection * to encapsulate BOSH sessions. It is not meant to be used from user's code. */ class Bosh { /** * @param {Connection} connection - The Connection that will use BOSH. */ constructor(connection) { this._conn = connection; /* request id for body tags */ this.rid = Math.floor(Math.random() * 4294967295); /* The current session ID. */ this.sid = null; // default BOSH values this.hold = 1; this.wait = 60; this.window = 5; this.errors = 0; this.inactivity = null; /** * BOSH-Connections will have all stanzas wrapped in a tag when * passed to {@link Connection#xmlInput|xmlInput()} or {@link Connection#xmlOutput|xmlOutput()}. * To strip this tag, User code can set {@link Bosh#strip|strip} to `true`: * * > // You can set `strip` on the prototype * > Bosh.prototype.strip = true; * * > // Or you can set it on the Bosh instance (which is `._proto` on the connection instance. * > const conn = new Connection(); * > conn._proto.strip = true; * * This will enable stripping of the body tag in both * {@link Connection#xmlInput|xmlInput} and {@link Connection#xmlOutput|xmlOutput}. * * @property {boolean} [strip=false] */ this.strip = Bosh.prototype.strip ?? false; this.lastResponseHeaders = null; /** @type {Request[]} */ this._requests = []; } /** * @param {number} m */ static setTimeoutMultiplier(m) { timeoutMultiplier = m; } /** * @returns {number} */ static getTimeoutMultplier() { return timeoutMultiplier; } /** * @param {number} m */ static setSecondaryTimeoutMultiplier(m) { secondaryTimeoutMultiplier = m; } /** * @returns {number} */ static getSecondaryTimeoutMultplier() { return secondaryTimeoutMultiplier; } /** * _Private_ helper function to generate the wrapper for BOSH. * @private * @return {Builder} - A Builder with a element. */ _buildBody() { const bodyWrap = $build('body', { 'rid': this.rid++, 'xmlns': NS.HTTPBIND, }); if (this.sid !== null) { bodyWrap.attrs({ 'sid': this.sid }); } if (this._conn.options.keepalive && this._conn._sessionCachingSupported()) { this._cacheSession(); } return bodyWrap; } /** * Reset the connection. * This function is called by the reset function of the Connection */ _reset() { this.rid = Math.floor(Math.random() * 4294967295); this.sid = null; this.errors = 0; if (this._conn._sessionCachingSupported()) { sessionStorage.removeItem('strophe-bosh-session'); } this._conn.nextValidRid(this.rid); } /** * _Private_ function that initializes the BOSH connection. * Creates and sends the Request that initializes the BOSH connection. * @param {number} wait - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * Other settings will require tweaks to the Strophe.TIMEOUT value. * @param {number} hold - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {string} route */ _connect(wait, hold, route) { this.wait = wait || this.wait; this.hold = hold || this.hold; this.errors = 0; const body = this._buildBody().attrs({ 'to': this._conn.domain, 'xml:lang': 'en', 'wait': this.wait, 'hold': this.hold, 'content': 'text/xml; charset=utf-8', 'ver': '1.6', 'xmpp:version': '1.0', 'xmlns:xmpp': NS.BOSH, }); if (route) { body.attrs({ route }); } const _connect_cb = this._conn._connect_cb; this._requests.push( new Request( body.tree(), this._onRequestStateChange.bind(this, _connect_cb.bind(this._conn)), Number(body.tree().getAttribute('rid')) ) ); this._throttledRequestHandler(); } /** * Attach to an already created and authenticated BOSH session. * * This function is provided to allow Strophe to attach to BOSH * sessions which have been created externally, perhaps by a Web * application. This is often used to support auto-login type features * without putting user credentials into the page. * * @param {string} jid - The full JID that is bound by the session. * @param {string} sid - The SID of the BOSH session. * @param {number} rid - The current RID of the BOSH session. This RID * will be used by the next request. * @param {Function} callback The connect callback function. * @param {number} wait - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * Other settings will require tweaks to the Strophe.TIMEOUT value. * @param {number} hold - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {number} wind - The optional HTTBIND window value. This is the * allowed range of request ids that are valid. The default is 5. */ _attach(jid, sid, rid, callback, wait, hold, wind) { this._conn.jid = jid; this.sid = sid; this.rid = rid; this._conn.connect_callback = callback; this._conn.domain = getDomainFromJid(this._conn.jid); this._conn.authenticated = true; this._conn.connected = true; this.wait = wait || this.wait; this.hold = hold || this.hold; this.window = wind || this.window; this._conn._changeConnectStatus(Status.ATTACHED, null); } /** * Attempt to restore a cached BOSH session * * @param {string} jid - The full JID that is bound by the session. * This parameter is optional but recommended, specifically in cases * where prebinded BOSH sessions are used where it's important to know * that the right session is being restored. * @param {Function} callback The connect callback function. * @param {number} wait - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * Other settings will require tweaks to the Strophe.TIMEOUT value. * @param {number} hold - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {number} wind - The optional HTTBIND window value. This is the * allowed range of request ids that are valid. The default is 5. */ _restore(jid, callback, wait, hold, wind) { const session = JSON.parse(sessionStorage.getItem('strophe-bosh-session')); if ( typeof session !== 'undefined' && session !== null && session.rid && session.sid && session.jid && (typeof jid === 'undefined' || jid === null || getBareJidFromJid(session.jid) === getBareJidFromJid(jid) || // If authcid is null, then it's an anonymous login, so // we compare only the domains: (getNodeFromJid(jid) === null && getDomainFromJid(session.jid) === jid)) ) { this._conn.restored = true; this._attach(session.jid, session.sid, session.rid, callback, wait, hold, wind); } else { const error = new Error('_restore: no restoreable session.'); error.name = 'StropheSessionError'; throw error; } } /** * _Private_ handler for the beforeunload event. * This handler is used to process the Bosh-part of the initial request. * @private */ _cacheSession() { if (this._conn.authenticated) { if (this._conn.jid && this.rid && this.sid) { sessionStorage.setItem( 'strophe-bosh-session', JSON.stringify({ 'jid': this._conn.jid, 'rid': this.rid, 'sid': this.sid, }) ); } } else { sessionStorage.removeItem('strophe-bosh-session'); } } /** * _Private_ handler for initial connection request. * This handler is used to process the Bosh-part of the initial request. * @param {Element} bodyWrap - The received stanza. */ _connect_cb(bodyWrap) { const typ = bodyWrap.getAttribute('type'); if (typ !== null && typ === 'terminate') { // an error occurred let cond = bodyWrap.getAttribute('condition'); log.error('BOSH-Connection failed: ' + cond); const conflict = bodyWrap.getElementsByTagName('conflict'); if (cond !== null) { if (cond === 'remote-stream-error' && conflict.length > 0) { cond = 'conflict'; } this._conn._changeConnectStatus(Status.CONNFAIL, cond); } else { this._conn._changeConnectStatus(Status.CONNFAIL, 'unknown'); } this._conn._doDisconnect(cond); return Status.CONNFAIL; } // check to make sure we don't overwrite these if _connect_cb is // called multiple times in the case of missing stream:features if (!this.sid) { this.sid = bodyWrap.getAttribute('sid'); } const wind = bodyWrap.getAttribute('requests'); if (wind) { this.window = parseInt(wind, 10); } const hold = bodyWrap.getAttribute('hold'); if (hold) { this.hold = parseInt(hold, 10); } const wait = bodyWrap.getAttribute('wait'); if (wait) { this.wait = parseInt(wait, 10); } const inactivity = bodyWrap.getAttribute('inactivity'); if (inactivity) { this.inactivity = parseInt(inactivity, 10); } } /** * _Private_ part of Connection.disconnect for Bosh * @param {Element|Builder} pres - This stanza will be sent before disconnecting. */ _disconnect(pres) { this._sendTerminate(pres); } /** * _Private_ function to disconnect. * Resets the SID and RID. */ _doDisconnect() { this.sid = null; this.rid = Math.floor(Math.random() * 4294967295); if (this._conn._sessionCachingSupported()) { sessionStorage.removeItem('strophe-bosh-session'); } this._conn.nextValidRid(this.rid); } /** * _Private_ function to check if the Request queue is empty. * @return {boolean} - True, if there are no Requests queued, False otherwise. */ _emptyQueue() { return this._requests.length === 0; } /** * _Private_ function to call error handlers registered for HTTP errors. * @private * @param {Request} req - The request that is changing readyState. */ _callProtocolErrorHandlers(req) { const reqStatus = Bosh._getRequestStatus(req); const err_callback = this._conn.protocolErrorHandlers.HTTP[reqStatus]; if (err_callback) { err_callback.call(this, reqStatus); } } /** * _Private_ function to handle the error count. * * Requests are resent automatically until their error count reaches * 5. Each time an error is encountered, this function is called to * increment the count and disconnect if the count is too high. * @private * @param {number} reqStatus - The request status. */ _hitError(reqStatus) { this.errors++; log.warn('request errored, status: ' + reqStatus + ', number of errors: ' + this.errors); if (this.errors > 4) { this._conn._onDisconnectTimeout(); } } /** * @callback connectionCallback * @param {Connection} connection */ /** * Called on stream start/restart when no stream:features * has been received and sends a blank poll request. * @param {connectionCallback} callback */ _no_auth_received(callback) { log.warn('Server did not yet offer a supported authentication ' + 'mechanism. Sending a blank poll request.'); if (callback) { callback = callback.bind(this._conn); } else { callback = this._conn._connect_cb.bind(this._conn); } const body = this._buildBody(); this._requests.push( new Request( body.tree(), this._onRequestStateChange.bind(this, callback), Number(body.tree().getAttribute('rid')) ) ); this._throttledRequestHandler(); } /** * _Private_ timeout handler for handling non-graceful disconnection. * Cancels all remaining Requests and clears the queue. */ _onDisconnectTimeout() { this._abortAllRequests(); } /** * _Private_ helper function that makes sure all pending requests are aborted. */ _abortAllRequests() { while (this._requests.length > 0) { const req = this._requests.pop(); req.abort = true; req.xhr.abort(); req.xhr.onreadystatechange = function () {}; } } /** * _Private_ handler called by {@link Connection#_onIdle|Connection._onIdle()}. * Sends all queued Requests or polls with empty Request if there are none. */ _onIdle() { const data = this._conn._data; // if no requests are in progress, poll if (this._conn.authenticated && this._requests.length === 0 && data.length === 0 && !this._conn.disconnecting) { log.debug('no requests during idle cycle, sending blank request'); data.push(null); } if (this._conn.paused) { return; } if (this._requests.length < 2 && data.length > 0) { const body = this._buildBody(); for (let i = 0; i < data.length; i++) { if (data[i] !== null) { if (data[i] === 'restart') { body.attrs({ 'to': this._conn.domain, 'xml:lang': 'en', 'xmpp:restart': 'true', 'xmlns:xmpp': NS.BOSH, }); } else { body.cnode(/** @type {Element} */ (data[i])).up(); } } } delete this._conn._data; this._conn._data = []; this._requests.push( new Request( body.tree(), this._onRequestStateChange.bind(this, this._conn._dataRecv.bind(this._conn)), Number(body.tree().getAttribute('rid')) ) ); this._throttledRequestHandler(); } if (this._requests.length > 0) { const time_elapsed = this._requests[0].age(); if (this._requests[0].dead !== null) { if (this._requests[0].timeDead() > Math.floor(timeoutMultiplier * this.wait)) { this._throttledRequestHandler(); } } if (time_elapsed > Math.floor(timeoutMultiplier * this.wait)) { log.warn( 'Request ' + this._requests[0].id + ' timed out, over ' + Math.floor(timeoutMultiplier * this.wait) + ' seconds since last activity' ); this._throttledRequestHandler(); } } } /** * Returns the HTTP status code from a {@link Request} * @private * @param {Request} req - The {@link Request} instance. * @param {number} [def] - The default value that should be returned if no status value was found. */ static _getRequestStatus(req, def) { let reqStatus; if (req.xhr.readyState === 4) { try { reqStatus = req.xhr.status; } catch (e) { // ignore errors from undefined status attribute. Works // around a browser bug log.error( `Caught an error while retrieving a request's status, reqStatus: ${reqStatus}, message: ${e.message}` ); } } if (typeof reqStatus === 'undefined') { reqStatus = typeof def === 'number' ? def : 0; } return reqStatus; } /** * _Private_ handler for {@link Request} state changes. * * This function is called when the XMLHttpRequest readyState changes. * It contains a lot of error handling logic for the many ways that * requests can fail, and calls the request callback when requests * succeed. * @private * * @param {Function} func - The handler for the request. * @param {Request} req - The request that is changing readyState. */ _onRequestStateChange(func, req) { log.debug('request id ' + req.id + '.' + req.sends + ' state changed to ' + req.xhr.readyState); if (req.abort) { req.abort = false; return; } if (req.xhr.readyState !== 4) { // The request is not yet complete return; } const reqStatus = Bosh._getRequestStatus(req); this.lastResponseHeaders = req.xhr.getAllResponseHeaders(); if (this._conn.disconnecting && reqStatus >= 400) { this._hitError(reqStatus); this._callProtocolErrorHandlers(req); return; } const reqIs0 = this._requests[0] === req; const reqIs1 = this._requests[1] === req; const valid_request = reqStatus > 0 && reqStatus < 500; const too_many_retries = req.sends > this._conn.maxRetries; if (valid_request || too_many_retries) { // remove from internal queue this._removeRequest(req); log.debug('request id ' + req.id + ' should now be removed'); } if (reqStatus === 200) { // request succeeded // if request 1 finished, or request 0 finished and request // 1 is over _TIMEOUT seconds old, we need to // restart the other - both will be in the first spot, as the // completed request has been removed from the queue already if ( reqIs1 || (reqIs0 && this._requests.length > 0 && this._requests[0].age() > Math.floor(timeoutMultiplier * this.wait)) ) { this._restartRequest(0); } this._conn.nextValidRid(req.rid + 1); log.debug('request id ' + req.id + '.' + req.sends + ' got 200'); func(req); // call handler this.errors = 0; } else if (reqStatus === 0 || (reqStatus >= 400 && reqStatus < 600) || reqStatus >= 12000) { // request failed log.error('request id ' + req.id + '.' + req.sends + ' error ' + reqStatus + ' happened'); this._hitError(reqStatus); this._callProtocolErrorHandlers(req); if (reqStatus >= 400 && reqStatus < 500) { this._conn._changeConnectStatus(Status.DISCONNECTING, null); this._conn._doDisconnect(); } } else { log.error('request id ' + req.id + '.' + req.sends + ' error ' + reqStatus + ' happened'); } if (!valid_request && !too_many_retries) { this._throttledRequestHandler(); } else if (too_many_retries && !this._conn.connected) { this._conn._changeConnectStatus(Status.CONNFAIL, 'giving-up'); } } /** * _Private_ function to process a request in the queue. * * This function takes requests off the queue and sends them and * restarts dead requests. * @private * * @param {number} i - The index of the request in the queue. */ _processRequest(i) { let req = this._requests[i]; const reqStatus = Bosh._getRequestStatus(req, -1); // make sure we limit the number of retries if (req.sends > this._conn.maxRetries) { this._conn._onDisconnectTimeout(); return; } const time_elapsed = req.age(); const primary_timeout = !isNaN(time_elapsed) && time_elapsed > Math.floor(timeoutMultiplier * this.wait); const secondary_timeout = req.dead !== null && req.timeDead() > Math.floor(secondaryTimeoutMultiplier * this.wait); const server_error = req.xhr.readyState === 4 && (reqStatus < 1 || reqStatus >= 500); if (primary_timeout || secondary_timeout || server_error) { if (secondary_timeout) { log.error(`Request ${this._requests[i].id} timed out (secondary), restarting`); } req.abort = true; req.xhr.abort(); // setting to null fails on IE6, so set to empty function req.xhr.onreadystatechange = function () {}; this._requests[i] = new Request(req.xmlData, req.origFunc, req.rid, req.sends); req = this._requests[i]; } if (req.xhr.readyState === 0) { log.debug('request id ' + req.id + '.' + req.sends + ' posting'); try { const content_type = this._conn.options.contentType || 'text/xml; charset=utf-8'; req.xhr.open('POST', this._conn.service, this._conn.options.sync ? false : true); if (typeof req.xhr.setRequestHeader !== 'undefined') { // IE9 doesn't have setRequestHeader req.xhr.setRequestHeader('Content-Type', content_type); } if (this._conn.options.withCredentials) { req.xhr.withCredentials = true; } } catch (e2) { log.error('XHR open failed: ' + e2.toString()); if (!this._conn.connected) { this._conn._changeConnectStatus(Status.CONNFAIL, 'bad-service'); } this._conn.disconnect(); return; } // Fires the XHR request -- may be invoked immediately // or on a gradually expanding retry window for reconnects const sendFunc = () => { req.date = new Date().valueOf(); if (this._conn.options.customHeaders) { const headers = this._conn.options.customHeaders; for (const header in headers) { if (Object.prototype.hasOwnProperty.call(headers, header)) { req.xhr.setRequestHeader(header, headers[header]); } } } req.xhr.send(req.data); }; // Implement progressive backoff for reconnects -- // First retry (send === 1) should also be instantaneous if (req.sends > 1) { // Using a cube of the retry number creates a nicely // expanding retry window const backoff = Math.min(Math.floor(timeoutMultiplier * this.wait), Math.pow(req.sends, 3)) * 1000; setTimeout(function () { // XXX: setTimeout should be called only with function expressions (23974bc1) sendFunc(); }, backoff); } else { sendFunc(); } req.sends++; if (this.strip && req.xmlData.nodeName === 'body' && req.xmlData.childNodes.length) { this._conn.xmlOutput?.(req.xmlData.children[0]); } else { this._conn.xmlOutput?.(req.xmlData); } this._conn.rawOutput?.(req.data); } else { log.debug( '_processRequest: ' + (i === 0 ? 'first' : 'second') + ' request has readyState of ' + req.xhr.readyState ); } } /** * _Private_ function to remove a request from the queue. * @private * @param {Request} req - The request to remove. */ _removeRequest(req) { log.debug('removing request'); for (let i = this._requests.length - 1; i >= 0; i--) { if (req === this._requests[i]) { this._requests.splice(i, 1); } } // IE6 fails on setting to null, so set to empty function req.xhr.onreadystatechange = function () {}; this._throttledRequestHandler(); } /** * _Private_ function to restart a request that is presumed dead. * @private * * @param {number} i - The index of the request in the queue. */ _restartRequest(i) { const req = this._requests[i]; if (req.dead === null) { req.dead = new Date(); } this._processRequest(i); } /** * _Private_ function to get a stanza out of a request. * Tries to extract a stanza out of a Request Object. * When this fails the current connection will be disconnected. * * @param {Request} req - The Request. * @return {Element} - The stanza that was passed. */ _reqToData(req) { try { return req.getResponse(); } catch (e) { if (e.message !== 'parsererror') { throw e; } this._conn.disconnect('strophe-parsererror'); } } /** * _Private_ function to send initial disconnect sequence. * * This is the first step in a graceful disconnect. It sends * the BOSH server a terminate body and includes an unavailable * presence if authentication has completed. * @private * @param {Element|Builder} [pres] */ _sendTerminate(pres) { log.debug('_sendTerminate was called'); const body = this._buildBody().attrs({ type: 'terminate' }); const el = pres instanceof Builder ? pres.tree() : pres; if (pres) { body.cnode(el); } const req = new Request( body.tree(), this._onRequestStateChange.bind(this, this._conn._dataRecv.bind(this._conn)), Number(body.tree().getAttribute('rid')) ); this._requests.push(req); this._throttledRequestHandler(); } /** * _Private_ part of the Connection.send function for BOSH * Just triggers the RequestHandler to send the messages that are in the queue */ _send() { clearTimeout(this._conn._idleTimeout); this._throttledRequestHandler(); this._conn._idleTimeout = setTimeout(() => this._conn._onIdle(), 100); } /** * Send an xmpp:restart stanza. */ _sendRestart() { this._throttledRequestHandler(); clearTimeout(this._conn._idleTimeout); } /** * _Private_ function to throttle requests to the connection window. * * This function makes sure we don't send requests so fast that the * request ids overflow the connection window in the case that one * request died. * @private */ _throttledRequestHandler() { if (!this._requests) { log.debug('_throttledRequestHandler called with ' + 'undefined requests'); } else { log.debug('_throttledRequestHandler called with ' + this._requests.length + ' requests'); } if (!this._requests || this._requests.length === 0) { return; } if (this._requests.length > 0) { this._processRequest(0); } if (this._requests.length > 1 && Math.abs(this._requests[0].rid - this._requests[1].rid) < this.window) { this._processRequest(1); } } } export default Bosh; strophejs-3.1.0/src/builder.js000066400000000000000000000264271472775321000163320ustar00rootroot00000000000000import { ElementType, NS } from './constants.js'; import { copyElement, createHtml, toElement, xmlElement, xmlGenerator, xmlTextNode, xmlescape } from './utils.js'; /** * Create a {@link Strophe.Builder} * This is an alias for `new Strophe.Builder(name, attrs)`. * @param {string} name - The root element name. * @param {Object.} [attrs] - The attributes for the root element in object notation. * @return {Builder} A new Strophe.Builder object. */ export function $build(name, attrs) { return new Builder(name, attrs); } /** * Create a {@link Strophe.Builder} with a `` element as the root. * @param {Object.} [attrs] - The element attributes in object notation. * @return {Builder} A new Strophe.Builder object. */ export function $msg(attrs) { return new Builder('message', attrs); } /** * Create a {@link Strophe.Builder} with an `` element as the root. * @param {Object.} [attrs] - The element attributes in object notation. * @return {Builder} A new Strophe.Builder object. */ export function $iq(attrs) { return new Builder('iq', attrs); } /** * Create a {@link Strophe.Builder} with a `` element as the root. * @param {Object.} [attrs] - The element attributes in object notation. * @return {Builder} A new Strophe.Builder object. */ export function $pres(attrs) { return new Builder('presence', attrs); } /** * This class provides an interface similar to JQuery but for building * DOM elements easily and rapidly. All the functions except for `toString()` * and tree() return the object, so calls can be chained. * * The corresponding DOM manipulations to get a similar fragment would be * a lot more tedious and probably involve several helper variables. * * Since adding children makes new operations operate on the child, up() * is provided to traverse up the tree. To add two children, do * > builder.c('child1', ...).up().c('child2', ...) * * The next operation on the Builder will be relative to the second child. * * @example * // Here's an example using the $iq() builder helper. * $iq({to: 'you', from: 'me', type: 'get', id: '1'}) * .c('query', {xmlns: 'strophe:example'}) * .c('example') * .toString() * * // The above generates this XML fragment * // * // * // * // * // */ class Builder { /** * @typedef {Object.} StanzaAttrs * @property {string} [StanzaAttrs.xmlns] */ /** @type {Element} */ #nodeTree; /** @type {Element} */ #node; /** @type {string} */ #name; /** @type {StanzaAttrs} */ #attrs; /** * The attributes should be passed in object notation. * @param {string} name - The name of the root element. * @param {StanzaAttrs} [attrs] - The attributes for the root element in object notation. * @example const b = new Builder('message', {to: 'you', from: 'me'}); * @example const b = new Builder('messsage', {'xml:lang': 'en'}); */ constructor(name, attrs) { // Set correct namespace for jabber:client elements if (name === 'presence' || name === 'message' || name === 'iq') { if (attrs && !attrs.xmlns) { attrs.xmlns = NS.CLIENT; } else if (!attrs) { attrs = { xmlns: NS.CLIENT }; } } this.#name = name; this.#attrs = attrs; } /** * Creates a new Builder object from an XML string. * @param {string} str * @returns {Builder} * @example const stanza = Builder.fromString(''); */ static fromString(str) { const el = toElement(str, true); const b = new Builder(''); b.#nodeTree = el; return b; } buildTree() { return xmlElement(this.#name, this.#attrs); } /** @return {Element} */ get nodeTree() { if (!this.#nodeTree) { // Holds the tree being built. this.#nodeTree = this.buildTree(); } return this.#nodeTree; } /** @return {Element} */ get node() { if (!this.#node) { this.#node = this.tree(); } return this.#node; } /** @param {Element} el */ set node(el) { this.#node = el; } /** * Render a DOM element and all descendants to a String. * @param {Element|Builder} elem - A DOM element. * @return {string} - The serialized element tree as a String. */ static serialize(elem) { if (!elem) return null; const el = elem instanceof Builder ? elem.tree() : elem; const names = [...Array(el.attributes.length).keys()].map((i) => el.attributes[i].nodeName); names.sort(); let result = names.reduce( (a, n) => `${a} ${n}="${xmlescape(el.attributes.getNamedItem(n).value)}"`, `<${el.nodeName}` ); if (el.childNodes.length > 0) { result += '>'; for (let i = 0; i < el.childNodes.length; i++) { const child = el.childNodes[i]; switch (child.nodeType) { case ElementType.NORMAL: // normal element, so recurse result += Builder.serialize(/** @type {Element} */ (child)); break; case ElementType.TEXT: // text element to escape values result += xmlescape(child.nodeValue); break; case ElementType.CDATA: // cdata section so don't escape values result += ''; } } result += ''; } else { result += '/>'; } return result; } /** * Return the DOM tree. * * This function returns the current DOM tree as an element object. This * is suitable for passing to functions like Strophe.Connection.send(). * * @return {Element} The DOM tree as a element object. */ tree() { return this.nodeTree; } /** * Serialize the DOM tree to a String. * * This function returns a string serialization of the current DOM * tree. It is often used internally to pass data to a * Strophe.Request object. * * @return {string} The serialized DOM tree in a String. */ toString() { return Builder.serialize(this.tree()); } /** * Make the current parent element the new current element. * This function is often used after c() to traverse back up the tree. * * @example * // For example, to add two children to the same element * builder.c('child1', {}).up().c('child2', {}); * * @return {Builder} The Strophe.Builder object. */ up() { // Depending on context, parentElement is not always available this.node = this.node.parentElement ? this.node.parentElement : /** @type {Element} */ (this.node.parentNode); return this; } /** * Make the root element the new current element. * * When at a deeply nested element in the tree, this function can be used * to jump back to the root of the tree, instead of having to repeatedly * call up(). * * @return {Builder} The Strophe.Builder object. */ root() { this.node = this.tree(); return this; } /** * Add or modify attributes of the current element. * * The attributes should be passed in object notation. * This function does not move the current element pointer. * @param {Object.} moreattrs - The attributes to add/modify in object notation. * If an attribute is set to `null` or `undefined`, it will be removed. * @return {Builder} The Strophe.Builder object. */ attrs(moreattrs) { for (const k in moreattrs) { if (Object.prototype.hasOwnProperty.call(moreattrs, k)) { // eslint-disable-next-line no-eq-null if (moreattrs[k] != null) { this.node.setAttribute(k, moreattrs[k].toString()); } else { this.node.removeAttribute(k); } } } return this; } /** * Add a child to the current element and make it the new current * element. * * This function moves the current element pointer to the child, * unless text is provided. If you need to add another child, it * is necessary to use up() to go back to the parent in the tree. * * @param {string} name - The name of the child. * @param {Object.|string} [attrs] - The attributes of the child in object notation. * @param {string} [text] - The text to add to the child. * * @return {Builder} The Strophe.Builder object. */ c(name, attrs, text) { const child = xmlElement(name, attrs, text); this.node.appendChild(child); if (typeof text !== 'string' && typeof text !== 'number') { this.node = child; } return this; } /** * Add a child to the current element and make it the new current * element. * * This function is the same as c() except that instead of using a * name and an attributes object to create the child it uses an * existing DOM element object. * * @param {Element} elem - A DOM element. * @return {Builder} The Strophe.Builder object. */ cnode(elem) { let impNode; const xmlGen = xmlGenerator(); try { impNode = xmlGen.importNode !== undefined; // eslint-disable-next-line no-unused-vars } catch (e) { impNode = false; } const newElem = impNode ? xmlGen.importNode(elem, true) : copyElement(elem); this.node.appendChild(newElem); this.node = /** @type {Element} */ (newElem); return this; } /** * Add a child text element. * * This *does not* make the child the new current element since there * are no children of text elements. * * @param {string} text - The text data to append to the current element. * @return {Builder} The Strophe.Builder object. */ t(text) { const child = xmlTextNode(text); this.node.appendChild(child); return this; } /** * Replace current element contents with the HTML passed in. * * This *does not* make the child the new current element * * @param {string} html - The html to insert as contents of current element. * @return {Builder} The Strophe.Builder object. */ h(html) { const fragment = xmlGenerator().createElement('body'); // force the browser to try and fix any invalid HTML tags fragment.innerHTML = html; // copy cleaned html into an xml dom const xhtml = createHtml(fragment); while (xhtml.childNodes.length > 0) { this.node.appendChild(xhtml.childNodes[0]); } return this; } } export default Builder; strophejs-3.1.0/src/connection.js000066400000000000000000002134021472775321000170320ustar00rootroot00000000000000import Handler from './handler.js'; import TimedHandler from './timed-handler.js'; import Builder, { $build, $iq, $pres } from './builder.js'; import log from './log.js'; import { ErrorCondition, NS, Status } from './constants.js'; import SASLAnonymous from './sasl-anon.js'; import SASLExternal from './sasl-external.js'; import SASLOAuthBearer from './sasl-oauthbearer.js'; import SASLPlain from './sasl-plain.js'; import SASLSHA1 from './sasl-sha1.js'; import SASLSHA256 from './sasl-sha256.js'; import SASLSHA384 from './sasl-sha384.js'; import SASLSHA512 from './sasl-sha512.js'; import SASLXOAuth2 from './sasl-xoauth2.js'; import { addCookies, forEachChild, getBareJidFromJid, getDomainFromJid, getNodeFromJid, getResourceFromJid, getText, handleError, } from './utils.js'; import { SessionError } from './errors.js'; import Bosh from './bosh.js'; import WorkerWebsocket from './worker-websocket.js'; import Websocket from './websocket.js'; /** * @typedef {import("./sasl.js").default} SASLMechanism * @typedef {import("./request.js").default} Request * * @typedef {Object} ConnectionOptions * @property {Cookies} [cookies] * Allows you to pass in cookies that will be included in HTTP requests. * Relevant to both the BOSH and Websocket transports. * * The passed in value must be a map of cookie names and string values. * * > { "myCookie": { * > "value": "1234", * > "domain": ".example.org", * > "path": "/", * > "expires": expirationDate * > } * > } * * Note that cookies can't be set in this way for domains other than the one * that's hosting Strophe (i.e. cross-domain). * Those cookies need to be set under those domains, for example they can be * set server-side by making a XHR call to that domain to ask it to set any * necessary cookies. * @property {SASLMechanism[]} [mechanisms] * Allows you to specify the SASL authentication mechanisms that this * instance of Connection (and therefore your XMPP client) will support. * * The value must be an array of objects with {@link SASLMechanism} * prototypes. * * If nothing is specified, then the following mechanisms (and their * priorities) are registered: * * Mechanism Priority * ------------------------ * SCRAM-SHA-512 72 * SCRAM-SHA-384 71 * SCRAM-SHA-256 70 * SCRAM-SHA-1 60 * PLAIN 50 * OAUTHBEARER 40 * X-OAUTH2 30 * ANONYMOUS 20 * EXTERNAL 10 * * @property {boolean} [explicitResourceBinding] * If `explicitResourceBinding` is set to `true`, then the XMPP client * needs to explicitly call {@link Connection.bind} once the XMPP * server has advertised the `urn:ietf:propertys:xml:ns:xmpp-bind` feature. * * Making this step explicit allows client authors to first finish other * stream related tasks, such as setting up an XEP-0198 Stream Management * session, before binding the JID resource for this session. * * @property {'ws'|'wss'} [protocol] * _Note: This option is only relevant to Websocket connections, and not BOSH_ * * If you want to connect to the current host with a WebSocket connection you * can tell Strophe to use WebSockets through the "protocol" option. * Valid values are `ws` for WebSocket and `wss` for Secure WebSocket. * So to connect to "wss://CURRENT_HOSTNAME/xmpp-websocket" you would call * * const conn = new Strophe.Connection( * "/xmpp-websocket/", * {protocol: "wss"} * ); * * Note that relative URLs _NOT_ starting with a "/" will also include the path * of the current site. * * Also because downgrading security is not permitted by browsers, when using * relative URLs both BOSH and WebSocket connections will use their secure * variants if the current connection to the site is also secure (https). * * @property {string} [worker] * _Note: This option is only relevant to Websocket connections, and not BOSH_ * * Set this option to URL from where the shared worker script should be loaded. * * To run the websocket connection inside a shared worker. * This allows you to share a single websocket-based connection between * multiple Connection instances, for example one per browser tab. * * The script to use is the one in `src/shared-connection-worker.js`. * * @property {boolean} [sync] * Used to control whether BOSH HTTP requests will be made synchronously or not. * The default behaviour is asynchronous. If you want to make requests * synchronous, make "sync" evaluate to true. * * > const conn = new Strophe.Connection("/http-bind/", {sync: true}); * * You can also toggle this on an already established connection. * * > conn.options.sync = true; * * @property {string[]} [customHeaders] * Used to provide custom HTTP headers to be included in the BOSH HTTP requests. * * @property {boolean} [keepalive] * Used to instruct Strophe to maintain the current BOSH session across * interruptions such as webpage reloads. * * It will do this by caching the sessions tokens in sessionStorage, and when * "restore" is called it will check whether there are cached tokens with * which it can resume an existing session. * * @property {boolean} [withCredentials] * Used to indicate wether cookies should be included in HTTP requests (by default * they're not). * Set this value to `true` if you are connecting to a BOSH service * and for some reason need to send cookies to it. * In order for this to work cross-domain, the server must also enable * credentials by setting the `Access-Control-Allow-Credentials` response header * to "true". For most usecases however this setting should be false (which * is the default). * Additionally, when using `Access-Control-Allow-Credentials`, the * `Access-Control-Allow-Origin` header can't be set to the wildcard "*", but * instead must be restricted to actual domains. * * @property {string} [contentType] * Used to change the default Content-Type, which is "text/xml; charset=utf-8". * Can be useful to reduce the amount of CORS preflight requests that are sent * to the server. */ /** * _Private_ variable Used to store plugin names that need * initialization during Connection construction. * @type {Object.} */ const connectionPlugins = {}; /** * **XMPP Connection manager** * * This class is the main part of Strophe. It manages a BOSH or websocket * connection to an XMPP server and dispatches events to the user callbacks * as data arrives. * * It supports various authentication mechanisms (e.g. SASL PLAIN, SASL SCRAM), * and more can be added via * {@link Connection#registerSASLMechanisms|registerSASLMechanisms()}. * * After creating a Connection object, the user will typically * call {@link Connection#connect|connect()} with a user supplied callback * to handle connection level events like authentication failure, * disconnection, or connection complete. * * The user will also have several event handlers defined by using * {@link Connection#addHandler|addHandler()} and * {@link Connection#addTimedHandler|addTimedHandler()}. * These will allow the user code to respond to interesting stanzas or do * something periodically with the connection. These handlers will be active * once authentication is finished. * * To send data to the connection, use {@link Connection#send|send()}. * * @memberof Strophe */ class Connection { /** * @typedef {Object.} Cookie * @typedef {Cookie|Object.} Cookies */ /** * Create and initialize a {@link Connection} object. * * The transport-protocol for this connection will be chosen automatically * based on the given service parameter. URLs starting with "ws://" or * "wss://" will use WebSockets, URLs starting with "http://", "https://" * or without a protocol will use [BOSH](https://xmpp.org/extensions/xep-0124.html). * * To make Strophe connect to the current host you can leave out the protocol * and host part and just pass the path: * * const conn = new Strophe.Connection("/http-bind/"); * * @param {string} service - The BOSH or WebSocket service URL. * @param {ConnectionOptions} options - A object containing configuration options */ constructor(service, options = {}) { // The service URL this.service = service; // Configuration options this.options = options; this.setProtocol(); /* The connected JID. */ this.jid = ''; /* the JIDs domain */ this.domain = null; /* stream:features */ this.features = null; // SASL /** * @typedef {Object.} SASLData * @property {Object} [SASLData.keys] */ /** @type {SASLData} */ this._sasl_data = {}; this.do_bind = false; this.do_session = false; /** @type {Object.} */ this.mechanisms = {}; /** @type {TimedHandler[]} */ this.timedHandlers = []; /** @type {Handler[]} */ this.handlers = []; /** @type {TimedHandler[]} */ this.removeTimeds = []; /** @type {Handler[]} */ this.removeHandlers = []; /** @type {TimedHandler[]} */ this.addTimeds = []; /** @type {Handler[]} */ this.addHandlers = []; this.protocolErrorHandlers = { /** @type {Object.} */ 'HTTP': {}, /** @type {Object.} */ 'websocket': {}, }; this._idleTimeout = null; this._disconnectTimeout = null; this.authenticated = false; this.connected = false; this.disconnecting = false; this.do_authentication = true; this.paused = false; this.restored = false; /** @type {(Element|'restart')[]} */ this._data = []; this._uniqueId = 0; this._sasl_success_handler = null; this._sasl_failure_handler = null; this._sasl_challenge_handler = null; // Max retries before disconnecting this.maxRetries = 5; // Call onIdle callback every 1/10th of a second this._idleTimeout = setTimeout(() => this._onIdle(), 100); addCookies(this.options.cookies); this.registerSASLMechanisms(this.options.mechanisms); // A client must always respond to incoming IQ "set" and "get" stanzas. // See https://datatracker.ietf.org/doc/html/rfc6120#section-8.2.3 // // This is a fallback handler which gets called when no other handler // was called for a received IQ "set" or "get". this.iqFallbackHandler = new Handler( /** * @param {Element} iq */ (iq) => this.send( $iq({ type: 'error', id: iq.getAttribute('id') }) .c('error', { 'type': 'cancel' }) .c('service-unavailable', { 'xmlns': NS.STANZAS }) ), null, 'iq', ['get', 'set'] ); // initialize plugins for (const k in connectionPlugins) { if (Object.prototype.hasOwnProperty.call(connectionPlugins, k)) { const F = function () {}; F.prototype = connectionPlugins[k]; // @ts-ignore this[k] = new F(); // @ts-ignore this[k].init(this); } } } /** * Extends the Connection object with the given plugin. * @param {string} name - The name of the extension. * @param {Object} ptype - The plugin's prototype. */ static addConnectionPlugin(name, ptype) { connectionPlugins[name] = ptype; } /** * Select protocal based on this.options or this.service */ setProtocol() { const proto = this.options.protocol || ''; if (this.options.worker) { this._proto = new WorkerWebsocket(this); } else if ( this.service.indexOf('ws:') === 0 || this.service.indexOf('wss:') === 0 || proto.indexOf('ws') === 0 ) { this._proto = new Websocket(this); } else { this._proto = new Bosh(this); } } /** * Reset the connection. * * This function should be called after a connection is disconnected * before that connection is reused. */ reset() { this._proto._reset(); // SASL this.do_session = false; this.do_bind = false; // handler lists this.timedHandlers = []; this.handlers = []; this.removeTimeds = []; this.removeHandlers = []; this.addTimeds = []; this.addHandlers = []; this.authenticated = false; this.connected = false; this.disconnecting = false; this.restored = false; this._data = []; /** @type {Request[]} */ this._requests = []; this._uniqueId = 0; } /** * Pause the request manager. * * This will prevent Strophe from sending any more requests to the * server. This is very useful for temporarily pausing * BOSH-Connections while a lot of send() calls are happening quickly. * This causes Strophe to send the data in a single request, saving * many request trips. */ pause() { this.paused = true; } /** * Resume the request manager. * * This resumes after pause() has been called. */ resume() { this.paused = false; } /** * Generate a unique ID for use in elements. * * All stanzas are required to have unique id attributes. This * function makes creating these easy. Each connection instance has * a counter which starts from zero, and the value of this counter * plus a colon followed by the suffix becomes the unique id. If no * suffix is supplied, the counter is used as the unique id. * * Suffixes are used to make debugging easier when reading the stream * data, and their use is recommended. The counter resets to 0 for * every new connection for the same reason. For connections to the * same server that authenticate the same way, all the ids should be * the same, which makes it easy to see changes. This is useful for * automated testing as well. * * @param {string} suffix - A optional suffix to append to the id. * @returns {string} A unique string to be used for the id attribute. */ // eslint-disable-next-line class-methods-use-this getUniqueId(suffix) { const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = (Math.random() * 16) | 0, v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); if (typeof suffix === 'string' || typeof suffix === 'number') { return uuid + ':' + suffix; } else { return uuid + ''; } } /** * Register a handler function for when a protocol (websocker or HTTP) * error occurs. * * NOTE: Currently only HTTP errors for BOSH requests are handled. * Patches that handle websocket errors would be very welcome. * * @example * function onError(err_code){ * //do stuff * } * * const conn = Strophe.connect('http://example.com/http-bind'); * conn.addProtocolErrorHandler('HTTP', 500, onError); * // Triggers HTTP 500 error and onError handler will be called * conn.connect('user_jid@incorrect_jabber_host', 'secret', onConnect); * * @param {'HTTP'|'websocket'} protocol - 'HTTP' or 'websocket' * @param {number} status_code - Error status code (e.g 500, 400 or 404) * @param {Function} callback - Function that will fire on Http error */ addProtocolErrorHandler(protocol, status_code, callback) { this.protocolErrorHandlers[protocol][status_code] = callback; } /** * @typedef {Object} Password * @property {string} Password.name * @property {string} Password.ck * @property {string} Password.sk * @property {number} Password.iter * @property {string} Password.salt */ /** * Starts the connection process. * * As the connection process proceeds, the user supplied callback will * be triggered multiple times with status updates. The callback * should take two arguments - the status code and the error condition. * * The status code will be one of the values in the Strophe.Status * constants. The error condition will be one of the conditions * defined in RFC 3920 or the condition 'strophe-parsererror'. * * The Parameters _wait_, _hold_ and _route_ are optional and only relevant * for BOSH connections. Please see XEP 124 for a more detailed explanation * of the optional parameters. * * @param {string} jid - The user's JID. This may be a bare JID, * or a full JID. If a node is not supplied, SASL OAUTHBEARER or * SASL ANONYMOUS authentication will be attempted (OAUTHBEARER will * process the provided password value as an access token). * (String or Object) pass - The user's password, or an object containing * the users SCRAM client and server keys, in a fashion described as follows: * * { name: String, representing the hash used (eg. SHA-1), * salt: String, base64 encoded salt used to derive the client key, * iter: Int, the iteration count used to derive the client key, * ck: String, the base64 encoding of the SCRAM client key * sk: String, the base64 encoding of the SCRAM server key * } * @param {string|Password} pass - The user password * @param {Function} callback - The connect callback function. * @param {number} [wait] - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * @param {number} [hold] - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {string} [route] - The optional route value. * @param {string} [authcid] - The optional alternative authentication identity * (username) if intending to impersonate another user. * When using the SASL-EXTERNAL authentication mechanism, for example * with client certificates, then the authcid value is used to * determine whether an authorization JID (authzid) should be sent to * the server. The authzid should NOT be sent to the server if the * authzid and authcid are the same. So to prevent it from being sent * (for example when the JID is already contained in the client * certificate), set authcid to that same JID. See XEP-178 for more * details. * @param {number} [disconnection_timeout=3000] - The optional disconnection timeout * in milliseconds before _doDisconnect will be called. */ connect(jid, pass, callback, wait, hold, route, authcid, disconnection_timeout = 3000) { this.jid = jid; /** Authorization identity */ this.authzid = getBareJidFromJid(this.jid); /** Authentication identity (User name) */ this.authcid = authcid || getNodeFromJid(this.jid); /** Authentication identity (User password) */ this.pass = pass; /** * The SASL SCRAM client and server keys. This variable will be populated with a non-null * object of the above described form after a successful SCRAM connection */ this.scram_keys = null; this.connect_callback = callback; this.disconnecting = false; this.connected = false; this.authenticated = false; this.restored = false; this.disconnection_timeout = disconnection_timeout; // parse jid for domain this.domain = getDomainFromJid(this.jid); this._changeConnectStatus(Status.CONNECTING, null); this._proto._connect(wait, hold, route); } /** * Attach to an already created and authenticated BOSH session. * * This function is provided to allow Strophe to attach to BOSH * sessions which have been created externally, perhaps by a Web * application. This is often used to support auto-login type features * without putting user credentials into the page. * * @param {string|Function} jid - The full JID that is bound by the session. * @param {string} [sid] - The SID of the BOSH session. * @param {number} [rid] - The current RID of the BOSH session. This RID * will be used by the next request. * @param {Function} [callback] - The connect callback function. * @param {number} [wait] - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * Other settings will require tweaks to the Strophe.TIMEOUT value. * @param {number} [hold] - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {number} [wind] - The optional HTTBIND window value. This is the * allowed range of request ids that are valid. The default is 5. */ attach(jid, sid, rid, callback, wait, hold, wind) { if (this._proto instanceof Bosh && typeof jid === 'string') { return this._proto._attach(jid, sid, rid, callback, wait, hold, wind); } else if (this._proto instanceof WorkerWebsocket && typeof jid === 'function') { const callback = jid; return this._proto._attach(callback); } else { throw new SessionError('The "attach" method is not available for your connection protocol'); } } /** * Attempt to restore a cached BOSH session. * * This function is only useful in conjunction with providing the * "keepalive":true option when instantiating a new {@link Connection}. * * When "keepalive" is set to true, Strophe will cache the BOSH tokens * RID (Request ID) and SID (Session ID) and then when this function is * called, it will attempt to restore the session from those cached * tokens. * * This function must therefore be called instead of connect or attach. * * For an example on how to use it, please see examples/restore.js * * @param {string} jid - The user's JID. This may be a bare JID or a full JID. * @param {Function} callback - The connect callback function. * @param {number} [wait] - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * @param {number} [hold] - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {number} [wind] - The optional HTTBIND window value. This is the * allowed range of request ids that are valid. The default is 5. */ restore(jid, callback, wait, hold, wind) { if (!(this._proto instanceof Bosh) || !this._sessionCachingSupported()) { throw new SessionError('The "restore" method can only be used with a BOSH connection.'); } if (this._sessionCachingSupported()) { this._proto._restore(jid, callback, wait, hold, wind); } } /** * Checks whether sessionStorage and JSON are supported and whether we're * using BOSH. */ _sessionCachingSupported() { if (this._proto instanceof Bosh) { if (!JSON) { return false; } try { sessionStorage.setItem('_strophe_', '_strophe_'); sessionStorage.removeItem('_strophe_'); } catch (e) { // eslint-disable-line no-unused-vars return false; } return true; } return false; } /** * User overrideable function that receives XML data coming into the * connection. * * The default function does nothing. User code can override this with * > Connection.xmlInput = function (elem) { * > (user code) * > }; * * Due to limitations of current Browsers' XML-Parsers the opening and closing * tag for WebSocket-Connoctions will be passed as selfclosing here. * * BOSH-Connections will have all stanzas wrapped in a tag. See * if you want to strip this tag. * * @param {Node|MessageEvent} elem - The XML data received by the connection. */ // eslint-disable-next-line no-unused-vars, class-methods-use-this xmlInput(elem) { return; } /** * User overrideable function that receives XML data sent to the * connection. * * The default function does nothing. User code can override this with * > Connection.xmlOutput = function (elem) { * > (user code) * > }; * * Due to limitations of current Browsers' XML-Parsers the opening and closing * tag for WebSocket-Connoctions will be passed as selfclosing here. * * BOSH-Connections will have all stanzas wrapped in a tag. See * if you want to strip this tag. * * @param {Element} elem - The XMLdata sent by the connection. */ // eslint-disable-next-line no-unused-vars, class-methods-use-this xmlOutput(elem) { return; } /** * User overrideable function that receives raw data coming into the * connection. * * The default function does nothing. User code can override this with * > Connection.rawInput = function (data) { * > (user code) * > }; * * @param {string} data - The data received by the connection. */ // eslint-disable-next-line no-unused-vars, class-methods-use-this rawInput(data) { return; } /** * User overrideable function that receives raw data sent to the * connection. * * The default function does nothing. User code can override this with * > Connection.rawOutput = function (data) { * > (user code) * > }; * * @param {string} data - The data sent by the connection. */ // eslint-disable-next-line no-unused-vars, class-methods-use-this rawOutput(data) { return; } /** * User overrideable function that receives the new valid rid. * * The default function does nothing. User code can override this with * > Connection.nextValidRid = function (rid) { * > (user code) * > }; * * @param {number} rid - The next valid rid */ // eslint-disable-next-line no-unused-vars, class-methods-use-this nextValidRid(rid) { return; } /** * Send a stanza. * * This function is called to push data onto the send queue to * go out over the wire. Whenever a request is sent to the BOSH * server, all pending data is sent and the queue is flushed. * * @param {Element|Builder|Element[]|Builder[]} stanza - The stanza to send */ send(stanza) { if (stanza === null) return; if (Array.isArray(stanza)) { stanza.forEach((s) => this._queueData(s instanceof Builder ? s.tree() : s)); } else { const el = stanza instanceof Builder ? stanza.tree() : stanza; this._queueData(el); } this._proto._send(); } /** * Immediately send any pending outgoing data. * * Normally send() queues outgoing data until the next idle period * (100ms), which optimizes network use in the common cases when * several send()s are called in succession. flush() can be used to * immediately send all pending data. */ flush() { // cancel the pending idle period and run the idle function // immediately clearTimeout(this._idleTimeout); this._onIdle(); } /** * Helper function to send presence stanzas. The main benefit is for * sending presence stanzas for which you expect a responding presence * stanza with the same id (for example when leaving a chat room). * * @param {Element} stanza - The stanza to send. * @param {Function} [callback] - The callback function for a successful request. * @param {Function} [errback] - The callback function for a failed or timed * out request. On timeout, the stanza will be null. * @param {number} [timeout] - The time specified in milliseconds for a * timeout to occur. * @return {string} The id used to send the presence. */ sendPresence(stanza, callback, errback, timeout) { /** @type {TimedHandler} */ let timeoutHandler = null; const el = stanza instanceof Builder ? stanza.tree() : stanza; let id = el.getAttribute('id'); if (!id) { // inject id if not found id = this.getUniqueId('sendPresence'); el.setAttribute('id', id); } if (typeof callback === 'function' || typeof errback === 'function') { const handler = this.addHandler( /** @param {Element} stanza */ (stanza) => { // remove timeout handler if there is one if (timeoutHandler) this.deleteTimedHandler(timeoutHandler); if (stanza.getAttribute('type') === 'error') { errback?.(stanza); } else if (callback) { callback(stanza); } }, null, 'presence', null, id ); // if timeout specified, set up a timeout handler. if (timeout) { timeoutHandler = this.addTimedHandler(timeout, () => { // get rid of normal handler this.deleteHandler(handler); // call errback on timeout with null stanza errback?.(null); return false; }); } } this.send(el); return id; } /** * Helper function to send IQ stanzas. * * @param {Element|Builder} stanza - The stanza to send. * @param {Function} [callback] - The callback function for a successful request. * @param {Function} [errback] - The callback function for a failed or timed * out request. On timeout, the stanza will be null. * @param {number} [timeout] - The time specified in milliseconds for a * timeout to occur. * @return {string} The id used to send the IQ. */ sendIQ(stanza, callback, errback, timeout) { /** @type {TimedHandler} */ let timeoutHandler = null; const el = stanza instanceof Builder ? stanza.tree() : stanza; let id = el.getAttribute('id'); if (!id) { // inject id if not found id = this.getUniqueId('sendIQ'); el.setAttribute('id', id); } if (typeof callback === 'function' || typeof errback === 'function') { const handler = this.addHandler( /** @param {Element} stanza */ (stanza) => { // remove timeout handler if there is one if (timeoutHandler) this.deleteTimedHandler(timeoutHandler); const iqtype = stanza.getAttribute('type'); if (iqtype === 'result') { callback?.(stanza); } else if (iqtype === 'error') { errback?.(stanza); } else { const error = new Error(`Got bad IQ type of ${iqtype}`); error.name = 'StropheError'; throw error; } }, null, 'iq', ['error', 'result'], id ); // if timeout specified, set up a timeout handler. if (timeout) { timeoutHandler = this.addTimedHandler(timeout, () => { // get rid of normal handler this.deleteHandler(handler); // call errback on timeout with null stanza errback?.(null); return false; }); } } this.send(el); return id; } /** * Queue outgoing data for later sending. Also ensures that the data * is a DOMElement. * @private * @param {Element} element */ _queueData(element) { if (element === null || !element.tagName || !element.childNodes) { const error = new Error('Cannot queue non-DOMElement.'); error.name = 'StropheError'; throw error; } this._data.push(element); } /** * Send an xmpp:restart stanza. * @private */ _sendRestart() { this._data.push('restart'); this._proto._sendRestart(); this._idleTimeout = setTimeout(() => this._onIdle(), 100); } /** * Add a timed handler to the connection. * * This function adds a timed handler. The provided handler will * be called every period milliseconds until it returns false, * the connection is terminated, or the handler is removed. Handlers * that wish to continue being invoked should return true. * * Because of method binding it is necessary to save the result of * this function if you wish to remove a handler with * deleteTimedHandler(). * * Note that user handlers are not active until authentication is * successful. * * @param {number} period - The period of the handler. * @param {Function} handler - The callback function. * @return {TimedHandler} A reference to the handler that can be used to remove it. */ addTimedHandler(period, handler) { const thand = new TimedHandler(period, handler); this.addTimeds.push(thand); return thand; } /** * Delete a timed handler for a connection. * * This function removes a timed handler from the connection. The * handRef parameter is *not* the function passed to addTimedHandler(), * but is the reference returned from addTimedHandler(). * @param {TimedHandler} handRef - The handler reference. */ deleteTimedHandler(handRef) { // this must be done in the Idle loop so that we don't change // the handlers during iteration this.removeTimeds.push(handRef); } /** * @typedef {Object} HandlerOptions * @property {boolean} [HandlerOptions.matchBareFromJid] * @property {boolean} [HandlerOptions.ignoreNamespaceFragment] */ /** * Add a stanza handler for the connection. * * This function adds a stanza handler to the connection. The * handler callback will be called for any stanza that matches * the parameters. Note that if multiple parameters are supplied, * they must all match for the handler to be invoked. * * The handler will receive the stanza that triggered it as its argument. * *The handler should return true if it is to be invoked again; * returning false will remove the handler after it returns.* * * As a convenience, the ns parameters applies to the top level element * and also any of its immediate children. This is primarily to make * matching /iq/query elements easy. * * ### Options * * With the options argument, you can specify boolean flags that affect how * matches are being done. * * Currently two flags exist: * * * *matchBareFromJid*: * When set to true, the from parameter and the * from attribute on the stanza will be matched as bare JIDs instead * of full JIDs. To use this, pass {matchBareFromJid: true} as the * value of options. The default value for matchBareFromJid is false. * * * *ignoreNamespaceFragment*: * When set to true, a fragment specified on the stanza's namespace * URL will be ignored when it's matched with the one configured for * the handler. * * This means that if you register like this: * * > connection.addHandler( * > handler, * > 'http://jabber.org/protocol/muc', * > null, null, null, null, * > {'ignoreNamespaceFragment': true} * > ); * * Then a stanza with XML namespace of * 'http://jabber.org/protocol/muc#user' will also be matched. If * 'ignoreNamespaceFragment' is false, then only stanzas with * 'http://jabber.org/protocol/muc' will be matched. * * ### Deleting the handler * * The return value should be saved if you wish to remove the handler * with `deleteHandler()`. * * @param {Function} handler - The user callback. * @param {string} ns - The namespace to match. * @param {string} name - The stanza name to match. * @param {string|string[]} type - The stanza type (or types if an array) to match. * @param {string} [id] - The stanza id attribute to match. * @param {string} [from] - The stanza from attribute to match. * @param {HandlerOptions} [options] - The handler options * @return {Handler} A reference to the handler that can be used to remove it. */ addHandler(handler, ns, name, type, id, from, options) { const hand = new Handler(handler, ns, name, type, id, from, options); this.addHandlers.push(hand); return hand; } /** * Delete a stanza handler for a connection. * * This function removes a stanza handler from the connection. The * handRef parameter is *not* the function passed to addHandler(), * but is the reference returned from addHandler(). * * @param {Handler} handRef - The handler reference. */ deleteHandler(handRef) { // this must be done in the Idle loop so that we don't change // the handlers during iteration this.removeHandlers.push(handRef); // If a handler is being deleted while it is being added, // prevent it from getting added const i = this.addHandlers.indexOf(handRef); if (i >= 0) { this.addHandlers.splice(i, 1); } } /** * Register the SASL mechanisms which will be supported by this instance of * Connection (i.e. which this XMPP client will support). * @param {SASLMechanism[]} mechanisms - Array of objects with SASLMechanism prototypes */ registerSASLMechanisms(mechanisms) { this.mechanisms = {}; ( mechanisms || [ SASLAnonymous, SASLExternal, SASLOAuthBearer, SASLXOAuth2, SASLPlain, SASLSHA1, SASLSHA256, SASLSHA384, SASLSHA512, ] ).forEach((m) => this.registerSASLMechanism(m)); } /** * Register a single SASL mechanism, to be supported by this client. * @param {any} Mechanism - Object with a Strophe.SASLMechanism prototype */ registerSASLMechanism(Mechanism) { const mechanism = new Mechanism(); this.mechanisms[mechanism.mechname] = mechanism; } /** * Start the graceful disconnection process. * * This function starts the disconnection process. This process starts * by sending unavailable presence and sending BOSH body of type * terminate. A timeout handler makes sure that disconnection happens * even if the BOSH server does not respond. * If the Connection object isn't connected, at least tries to abort all pending requests * so the connection object won't generate successful requests (which were already opened). * * The user supplied connection callback will be notified of the * progress as this process happens. * * @param {string} [reason] - The reason the disconnect is occuring. */ disconnect(reason) { this._changeConnectStatus(Status.DISCONNECTING, reason); if (reason) { log.info('Disconnect was called because: ' + reason); } else { log.debug('Disconnect was called'); } if (this.connected) { let pres = null; this.disconnecting = true; if (this.authenticated) { pres = $pres({ 'xmlns': NS.CLIENT, 'type': 'unavailable', }); } // setup timeout handler this._disconnectTimeout = this._addSysTimedHandler( this.disconnection_timeout, this._onDisconnectTimeout.bind(this) ); this._proto._disconnect(pres); } else { log.debug('Disconnect was called before Strophe connected to the server'); this._proto._abortAllRequests(); this._doDisconnect(); } } /** * _Private_ helper function that makes sure plugins and the user's * callback are notified of connection status changes. * @param {number} status - the new connection status, one of the values * in Strophe.Status * @param {string|null} [condition] - the error condition * @param {Element} [elem] - The triggering stanza. */ _changeConnectStatus(status, condition, elem) { // notify all plugins listening for status changes for (const k in connectionPlugins) { if (Object.prototype.hasOwnProperty.call(connectionPlugins, k)) { // @ts-ignore const plugin = this[k]; if (plugin.statusChanged) { try { plugin.statusChanged(status, condition); } catch (err) { log.error(`${k} plugin caused an exception changing status: ${err}`); } } } } // notify the user's callback if (this.connect_callback) { try { this.connect_callback(status, condition, elem); } catch (e) { handleError(e); log.error(`User connection callback caused an exception: ${e}`); } } } /** * _Private_ function to disconnect. * * This is the last piece of the disconnection logic. This resets the * connection and alerts the user's connection callback. * @param {string|null} [condition] - the error condition */ _doDisconnect(condition) { if (typeof this._idleTimeout === 'number') { clearTimeout(this._idleTimeout); } // Cancel Disconnect Timeout if (this._disconnectTimeout !== null) { this.deleteTimedHandler(this._disconnectTimeout); this._disconnectTimeout = null; } log.debug('_doDisconnect was called'); this._proto._doDisconnect(); this.authenticated = false; this.disconnecting = false; this.restored = false; // delete handlers this.handlers = []; this.timedHandlers = []; this.removeTimeds = []; this.removeHandlers = []; this.addTimeds = []; this.addHandlers = []; // tell the parent we disconnected this._changeConnectStatus(Status.DISCONNECTED, condition); this.connected = false; } /** * _Private_ handler to processes incoming data from the the connection. * * Except for _connect_cb handling the initial connection request, * this function handles the incoming data for all requests. This * function also fires stanza handlers that match each incoming * stanza. * @param {Element | Request} req - The request that has data ready. * @param {string} [raw] - The stanza as raw string. */ _dataRecv(req, raw) { const elem = /** @type {Element} */ ( '_reqToData' in this._proto ? this._proto._reqToData(/** @type {Request} */ (req)) : req ); if (elem === null) { return; } if (this.xmlInput !== Connection.prototype.xmlInput) { if (elem.nodeName === this._proto.strip && elem.childNodes.length) { this.xmlInput(elem.childNodes[0]); } else { this.xmlInput(elem); } } if (this.rawInput !== Connection.prototype.rawInput) { if (raw) { this.rawInput(raw); } else { this.rawInput(Builder.serialize(elem)); } } // remove handlers scheduled for deletion while (this.removeHandlers.length > 0) { const hand = this.removeHandlers.pop(); const i = this.handlers.indexOf(hand); if (i >= 0) { this.handlers.splice(i, 1); } } // add handlers scheduled for addition while (this.addHandlers.length > 0) { this.handlers.push(this.addHandlers.pop()); } // handle graceful disconnect if (this.disconnecting && this._proto._emptyQueue()) { this._doDisconnect(); return; } const type = elem.getAttribute('type'); if (type !== null && type === 'terminate') { // Don't process stanzas that come in after disconnect if (this.disconnecting) { return; } // an error occurred let cond = elem.getAttribute('condition'); const conflict = elem.getElementsByTagName('conflict'); if (cond !== null) { if (cond === 'remote-stream-error' && conflict.length > 0) { cond = 'conflict'; } this._changeConnectStatus(Status.CONNFAIL, cond); } else { this._changeConnectStatus(Status.CONNFAIL, ErrorCondition.UNKNOWN_REASON); } this._doDisconnect(cond); return; } // send each incoming stanza through the handler chain forEachChild( elem, null, /** @param {Element} child */ (child) => { const matches = []; this.handlers = this.handlers.reduce((handlers, handler) => { try { if (handler.isMatch(child) && (this.authenticated || !handler.user)) { if (handler.run(child)) { handlers.push(handler); } matches.push(handler); } else { handlers.push(handler); } } catch (e) { // if the handler throws an exception, we consider it as false log.warn('Removing Strophe handlers due to uncaught exception: ' + e.message); } return handlers; }, []); // If no handler was fired for an incoming IQ with type="set", // then we return an IQ error stanza with service-unavailable. if (!matches.length && this.iqFallbackHandler.isMatch(child)) { this.iqFallbackHandler.run(child); } } ); } /** * @callback connectionCallback * @param {Connection} connection */ /** * _Private_ handler for initial connection request. * * This handler is used to process the initial connection request * response from the BOSH server. It is used to set up authentication * handlers and start the authentication process. * * SASL authentication will be attempted if available, otherwise * the code will fall back to legacy authentication. * * @param {Element | Request} req - The current request. * @param {connectionCallback} _callback - low level (xmpp) connect callback function. * Useful for plugins with their own xmpp connect callback (when they * want to do something special). * @param {string} [raw] - The stanza as raw string. */ _connect_cb(req, _callback, raw) { log.debug('_connect_cb was called'); this.connected = true; let bodyWrap; try { bodyWrap = /** @type {Element} */ ( '_reqToData' in this._proto ? this._proto._reqToData(/** @type {Request} */ (req)) : req ); } catch (e) { if (e.name !== ErrorCondition.BAD_FORMAT) { throw e; } this._changeConnectStatus(Status.CONNFAIL, ErrorCondition.BAD_FORMAT); this._doDisconnect(ErrorCondition.BAD_FORMAT); } if (!bodyWrap) { return; } if (this.xmlInput !== Connection.prototype.xmlInput) { if (bodyWrap.nodeName === this._proto.strip && bodyWrap.childNodes.length) { this.xmlInput(bodyWrap.childNodes[0]); } else { this.xmlInput(bodyWrap); } } if (this.rawInput !== Connection.prototype.rawInput) { if (raw) { this.rawInput(raw); } else { this.rawInput(Builder.serialize(bodyWrap)); } } const conncheck = this._proto._connect_cb(bodyWrap); if (conncheck === Status.CONNFAIL) { return; } // Check for the stream:features tag let hasFeatures; if (bodyWrap.getElementsByTagNameNS) { hasFeatures = bodyWrap.getElementsByTagNameNS(NS.STREAM, 'features').length > 0; } else { hasFeatures = bodyWrap.getElementsByTagName('stream:features').length > 0 || bodyWrap.getElementsByTagName('features').length > 0; } if (!hasFeatures) { this._proto._no_auth_received(_callback); return; } const matched = Array.from(bodyWrap.getElementsByTagName('mechanism')) .map((m) => this.mechanisms[m.textContent]) .filter((m) => m); if (matched.length === 0) { if (bodyWrap.getElementsByTagName('auth').length === 0) { // There are no matching SASL mechanisms and also no legacy // auth available. this._proto._no_auth_received(_callback); return; } } if (this.do_authentication !== false) { this.authenticate(matched); } } /** * Sorts an array of objects with prototype SASLMechanism according to * their priorities. * @param {SASLMechanism[]} mechanisms - Array of SASL mechanisms. */ // eslint-disable-next-line class-methods-use-this sortMechanismsByPriority(mechanisms) { // Sorting mechanisms according to priority. for (let i = 0; i < mechanisms.length - 1; ++i) { let higher = i; for (let j = i + 1; j < mechanisms.length; ++j) { if (mechanisms[j].priority > mechanisms[higher].priority) { higher = j; } } if (higher !== i) { const swap = mechanisms[i]; mechanisms[i] = mechanisms[higher]; mechanisms[higher] = swap; } } return mechanisms; } /** * Set up authentication * * Continues the initial connection request by setting up authentication * handlers and starting the authentication process. * * SASL authentication will be attempted if available, otherwise * the code will fall back to legacy authentication. * * @param {SASLMechanism[]} matched - Array of SASL mechanisms supported. */ authenticate(matched) { if (!this._attemptSASLAuth(matched)) { this._attemptLegacyAuth(); } } /** * Iterate through an array of SASL mechanisms and attempt authentication * with the highest priority (enabled) mechanism. * * @private * @param {SASLMechanism[]} mechanisms - Array of SASL mechanisms. * @return {Boolean} mechanism_found - true or false, depending on whether a * valid SASL mechanism was found with which authentication could be started. */ _attemptSASLAuth(mechanisms) { mechanisms = this.sortMechanismsByPriority(mechanisms || []); let mechanism_found = false; for (let i = 0; i < mechanisms.length; ++i) { if (!mechanisms[i].test(this)) { continue; } this._sasl_success_handler = this._addSysHandler( this._sasl_success_cb.bind(this), null, 'success', null, null ); this._sasl_failure_handler = this._addSysHandler( this._sasl_failure_cb.bind(this), null, 'failure', null, null ); this._sasl_challenge_handler = this._addSysHandler( this._sasl_challenge_cb.bind(this), null, 'challenge', null, null ); this._sasl_mechanism = mechanisms[i]; this._sasl_mechanism.onStart(this); const request_auth_exchange = $build('auth', { 'xmlns': NS.SASL, 'mechanism': this._sasl_mechanism.mechname, }); if (this._sasl_mechanism.isClientFirst) { const response = this._sasl_mechanism.clientChallenge(this); request_auth_exchange.t(btoa(/** @type {string} */ (response))); } this.send(request_auth_exchange.tree()); mechanism_found = true; break; } return mechanism_found; } /** * _Private_ handler for the SASL challenge * @private * @param {Element} elem */ async _sasl_challenge_cb(elem) { const challenge = atob(getText(elem)); const response = await this._sasl_mechanism.onChallenge(this, challenge); const stanza = $build('response', { 'xmlns': NS.SASL }); if (response) stanza.t(btoa(response)); this.send(stanza.tree()); return true; } /** * Attempt legacy (i.e. non-SASL) authentication. * @private */ _attemptLegacyAuth() { if (getNodeFromJid(this.jid) === null) { // we don't have a node, which is required for non-anonymous // client connections this._changeConnectStatus(Status.CONNFAIL, ErrorCondition.MISSING_JID_NODE); this.disconnect(ErrorCondition.MISSING_JID_NODE); } else { // Fall back to legacy authentication this._changeConnectStatus(Status.AUTHENTICATING, null); this._addSysHandler(this._onLegacyAuthIQResult.bind(this), null, null, null, '_auth_1'); this.send( $iq({ 'type': 'get', 'to': this.domain, 'id': '_auth_1', }) .c('query', { xmlns: NS.AUTH }) .c('username', {}) .t(getNodeFromJid(this.jid)) .tree() ); } } /** * _Private_ handler for legacy authentication. * * This handler is called in response to the initial * for legacy authentication. It builds an authentication and * sends it, creating a handler (calling back to _auth2_cb()) to * handle the result * @private * @return {false} `false` to remove the handler. */ _onLegacyAuthIQResult() { const pass = typeof this.pass === 'string' ? this.pass : ''; // build plaintext auth iq const iq = $iq({ type: 'set', id: '_auth_2' }) .c('query', { xmlns: NS.AUTH }) .c('username', {}) .t(getNodeFromJid(this.jid)) .up() .c('password') .t(pass); if (!getResourceFromJid(this.jid)) { // since the user has not supplied a resource, we pick // a default one here. unlike other auth methods, the server // cannot do this for us. this.jid = getBareJidFromJid(this.jid) + '/strophe'; } iq.up().c('resource', {}).t(getResourceFromJid(this.jid)); this._addSysHandler(this._auth2_cb.bind(this), null, null, null, '_auth_2'); this.send(iq.tree()); return false; } /** * _Private_ handler for succesful SASL authentication. * @private * @param {Element} elem - The matching stanza. * @return {false} `false` to remove the handler. */ _sasl_success_cb(elem) { if (this._sasl_data['server-signature']) { let serverSignature; const success = atob(getText(elem)); const attribMatch = /([a-z]+)=([^,]+)(,|$)/; const matches = success.match(attribMatch); if (matches[1] === 'v') { serverSignature = matches[2]; } if (serverSignature !== this._sasl_data['server-signature']) { // remove old handlers this.deleteHandler(this._sasl_failure_handler); this._sasl_failure_handler = null; if (this._sasl_challenge_handler) { this.deleteHandler(this._sasl_challenge_handler); this._sasl_challenge_handler = null; } this._sasl_data = {}; return this._sasl_failure_cb(null); } } log.info('SASL authentication succeeded.'); if (this._sasl_data.keys) { this.scram_keys = this._sasl_data.keys; } if (this._sasl_mechanism) { this._sasl_mechanism.onSuccess(); } // remove old handlers this.deleteHandler(this._sasl_failure_handler); this._sasl_failure_handler = null; if (this._sasl_challenge_handler) { this.deleteHandler(this._sasl_challenge_handler); this._sasl_challenge_handler = null; } /** @type {Handler[]} */ const streamfeature_handlers = []; /** * @param {Handler[]} handlers * @param {Element} elem */ const wrapper = (handlers, elem) => { while (handlers.length) { this.deleteHandler(handlers.pop()); } this._onStreamFeaturesAfterSASL(elem); return false; }; streamfeature_handlers.push( this._addSysHandler( /** @param {Element} elem */ (elem) => wrapper(streamfeature_handlers, elem), null, 'stream:features', null, null ) ); streamfeature_handlers.push( this._addSysHandler( /** @param {Element} elem */ (elem) => wrapper(streamfeature_handlers, elem), NS.STREAM, 'features', null, null ) ); // we must send an xmpp:restart now this._sendRestart(); return false; } /** * @private * @param {Element} elem - The matching stanza. * @return {false} `false` to remove the handler. */ _onStreamFeaturesAfterSASL(elem) { // save stream:features for future usage this.features = elem; for (let i = 0; i < elem.childNodes.length; i++) { const child = elem.childNodes[i]; if (child.nodeName === 'bind') { this.do_bind = true; } if (child.nodeName === 'session') { this.do_session = true; } } if (!this.do_bind) { this._changeConnectStatus(Status.AUTHFAIL, null); return false; } else if (!this.options.explicitResourceBinding) { this.bind(); } else { this._changeConnectStatus(Status.BINDREQUIRED, null); } return false; } /** * Sends an IQ to the XMPP server to bind a JID resource for this session. * * https://tools.ietf.org/html/rfc6120#section-7.5 * * If `explicitResourceBinding` was set to a truthy value in the options * passed to the Connection constructor, then this function needs * to be called explicitly by the client author. * * Otherwise it'll be called automatically as soon as the XMPP server * advertises the "urn:ietf:params:xml:ns:xmpp-bind" stream feature. */ bind() { if (!this.do_bind) { log.info(`Connection.prototype.bind called but "do_bind" is false`); return; } this._addSysHandler(this._onResourceBindResultIQ.bind(this), null, null, null, '_bind_auth_2'); const resource = getResourceFromJid(this.jid); if (resource) { this.send( $iq({ type: 'set', id: '_bind_auth_2' }) .c('bind', { xmlns: NS.BIND }) .c('resource', {}) .t(resource) .tree() ); } else { this.send($iq({ type: 'set', id: '_bind_auth_2' }).c('bind', { xmlns: NS.BIND }).tree()); } } /** * _Private_ handler for binding result and session start. * @private * @param {Element} elem - The matching stanza. * @return {false} `false` to remove the handler. */ _onResourceBindResultIQ(elem) { if (elem.getAttribute('type') === 'error') { log.warn('Resource binding failed.'); const conflict = elem.getElementsByTagName('conflict'); let condition; if (conflict.length > 0) { condition = ErrorCondition.CONFLICT; } this._changeConnectStatus(Status.AUTHFAIL, condition, elem); return false; } // TODO - need to grab errors const bind = elem.getElementsByTagName('bind'); if (bind.length > 0) { const jidNode = bind[0].getElementsByTagName('jid'); if (jidNode.length > 0) { this.authenticated = true; this.jid = getText(jidNode[0]); if (this.do_session) { this._establishSession(); } else { this._changeConnectStatus(Status.CONNECTED, null); } } } else { log.warn('Resource binding failed.'); this._changeConnectStatus(Status.AUTHFAIL, null, elem); return false; } } /** * Send IQ request to establish a session with the XMPP server. * * See https://xmpp.org/rfcs/rfc3921.html#session * * Note: The protocol for session establishment has been determined as * unnecessary and removed in RFC-6121. * @private */ _establishSession() { if (!this.do_session) { throw new Error( `Connection.prototype._establishSession ` + `called but apparently ${NS.SESSION} wasn't advertised by the server` ); } this._addSysHandler(this._onSessionResultIQ.bind(this), null, null, null, '_session_auth_2'); this.send($iq({ type: 'set', id: '_session_auth_2' }).c('session', { xmlns: NS.SESSION }).tree()); } /** * _Private_ handler for the server's IQ response to a client's session * request. * * This sets Connection.authenticated to true on success, which * starts the processing of user handlers. * * See https://xmpp.org/rfcs/rfc3921.html#session * * Note: The protocol for session establishment has been determined as * unnecessary and removed in RFC-6121. * @private * @param {Element} elem - The matching stanza. * @return {false} `false` to remove the handler. */ _onSessionResultIQ(elem) { if (elem.getAttribute('type') === 'result') { this.authenticated = true; this._changeConnectStatus(Status.CONNECTED, null); } else if (elem.getAttribute('type') === 'error') { this.authenticated = false; log.warn('Session creation failed.'); this._changeConnectStatus(Status.AUTHFAIL, null, elem); return false; } return false; } /** * _Private_ handler for SASL authentication failure. * @param {Element} [elem] - The matching stanza. * @return {false} `false` to remove the handler. */ _sasl_failure_cb(elem) { // delete unneeded handlers if (this._sasl_success_handler) { this.deleteHandler(this._sasl_success_handler); this._sasl_success_handler = null; } if (this._sasl_challenge_handler) { this.deleteHandler(this._sasl_challenge_handler); this._sasl_challenge_handler = null; } if (this._sasl_mechanism) this._sasl_mechanism.onFailure(); this._changeConnectStatus(Status.AUTHFAIL, null, elem); return false; } /** * _Private_ handler to finish legacy authentication. * * This handler is called when the result from the jabber:iq:auth * stanza is returned. * @private * @param {Element} elem - The stanza that triggered the callback. * @return {false} `false` to remove the handler. */ _auth2_cb(elem) { if (elem.getAttribute('type') === 'result') { this.authenticated = true; this._changeConnectStatus(Status.CONNECTED, null); } else if (elem.getAttribute('type') === 'error') { this._changeConnectStatus(Status.AUTHFAIL, null, elem); this.disconnect('authentication failed'); } return false; } /** * _Private_ function to add a system level timed handler. * * This function is used to add a TimedHandler for the * library code. System timed handlers are allowed to run before * authentication is complete. * @param {number} period - The period of the handler. * @param {Function} handler - The callback function. */ _addSysTimedHandler(period, handler) { const thand = new TimedHandler(period, handler); thand.user = false; this.addTimeds.push(thand); return thand; } /** * _Private_ function to add a system level stanza handler. * * This function is used to add a Handler for the * library code. System stanza handlers are allowed to run before * authentication is complete. * @param {Function} handler - The callback function. * @param {string} ns - The namespace to match. * @param {string} name - The stanza name to match. * @param {string} type - The stanza type attribute to match. * @param {string} id - The stanza id attribute to match. */ _addSysHandler(handler, ns, name, type, id) { const hand = new Handler(handler, ns, name, type, id); hand.user = false; this.addHandlers.push(hand); return hand; } /** * _Private_ timeout handler for handling non-graceful disconnection. * * If the graceful disconnect process does not complete within the * time allotted, this handler finishes the disconnect anyway. * @return {false} `false` to remove the handler. */ _onDisconnectTimeout() { log.debug('_onDisconnectTimeout was called'); this._changeConnectStatus(Status.CONNTIMEOUT, null); this._proto._onDisconnectTimeout(); // actually disconnect this._doDisconnect(); return false; } /** * _Private_ handler to process events during idle cycle. * * This handler is called every 100ms to fire timed handlers that * are ready and keep poll requests going. */ _onIdle() { // add timed handlers scheduled for addition // NOTE: we add before remove in the case a timed handler is // added and then deleted before the next _onIdle() call. while (this.addTimeds.length > 0) { this.timedHandlers.push(this.addTimeds.pop()); } // remove timed handlers that have been scheduled for deletion while (this.removeTimeds.length > 0) { const thand = this.removeTimeds.pop(); const i = this.timedHandlers.indexOf(thand); if (i >= 0) { this.timedHandlers.splice(i, 1); } } // call ready timed handlers const now = new Date().getTime(); const newList = []; for (let i = 0; i < this.timedHandlers.length; i++) { const thand = this.timedHandlers[i]; if (this.authenticated || !thand.user) { const since = thand.lastCalled + thand.period; if (since - now <= 0) { if (thand.run()) { newList.push(thand); } } else { newList.push(thand); } } } this.timedHandlers = newList; clearTimeout(this._idleTimeout); this._proto._onIdle(); // reactivate the timer only if connected if (this.connected) { this._idleTimeout = setTimeout(() => this._onIdle(), 100); } } } export default Connection; strophejs-3.1.0/src/constants.js000066400000000000000000000130511472775321000167050ustar00rootroot00000000000000/** * Common namespace constants from the XMPP RFCs and XEPs. * * @typedef { Object } NS * @property {string} NS.HTTPBIND - HTTP BIND namespace from XEP 124. * @property {string} NS.BOSH - BOSH namespace from XEP 206. * @property {string} NS.CLIENT - Main XMPP client namespace. * @property {string} NS.AUTH - Legacy authentication namespace. * @property {string} NS.ROSTER - Roster operations namespace. * @property {string} NS.PROFILE - Profile namespace. * @property {string} NS.DISCO_INFO - Service discovery info namespace from XEP 30. * @property {string} NS.DISCO_ITEMS - Service discovery items namespace from XEP 30. * @property {string} NS.MUC - Multi-User Chat namespace from XEP 45. * @property {string} NS.SASL - XMPP SASL namespace from RFC 3920. * @property {string} NS.STREAM - XMPP Streams namespace from RFC 3920. * @property {string} NS.BIND - XMPP Binding namespace from RFC 3920 and RFC 6120. * @property {string} NS.SESSION - XMPP Session namespace from RFC 3920. * @property {string} NS.XHTML_IM - XHTML-IM namespace from XEP 71. * @property {string} NS.XHTML - XHTML body namespace from XEP 71. * @property {string} NS.STANZAS * @property {string} NS.FRAMING */ export const NS = { HTTPBIND: 'http://jabber.org/protocol/httpbind', BOSH: 'urn:xmpp:xbosh', CLIENT: 'jabber:client', SERVER: 'jabber:server', AUTH: 'jabber:iq:auth', ROSTER: 'jabber:iq:roster', PROFILE: 'jabber:iq:profile', DISCO_INFO: 'http://jabber.org/protocol/disco#info', DISCO_ITEMS: 'http://jabber.org/protocol/disco#items', MUC: 'http://jabber.org/protocol/muc', SASL: 'urn:ietf:params:xml:ns:xmpp-sasl', STREAM: 'http://etherx.jabber.org/streams', FRAMING: 'urn:ietf:params:xml:ns:xmpp-framing', BIND: 'urn:ietf:params:xml:ns:xmpp-bind', SESSION: 'urn:ietf:params:xml:ns:xmpp-session', VERSION: 'jabber:iq:version', STANZAS: 'urn:ietf:params:xml:ns:xmpp-stanzas', XHTML_IM: 'http://jabber.org/protocol/xhtml-im', XHTML: 'http://www.w3.org/1999/xhtml', }; export const PARSE_ERROR_NS = 'http://www.w3.org/1999/xhtml'; /** * Contains allowed tags, tag attributes, and css properties. * Used in the {@link Strophe.createHtml} function to filter incoming html into the allowed XHTML-IM subset. * See [XEP-0071](http://xmpp.org/extensions/xep-0071.html#profile-summary) for the list of recommended * allowed tags and their attributes. */ export const XHTML = { tags: ['a', 'blockquote', 'br', 'cite', 'em', 'img', 'li', 'ol', 'p', 'span', 'strong', 'ul', 'body'], attributes: { 'a': ['href'], 'blockquote': ['style'], /** @type {never[]} */ 'br': [], 'cite': ['style'], /** @type {never[]} */ 'em': [], 'img': ['src', 'alt', 'style', 'height', 'width'], 'li': ['style'], 'ol': ['style'], 'p': ['style'], 'span': ['style'], /** @type {never[]} */ 'strong': [], 'ul': ['style'], /** @type {never[]} */ 'body': [], }, css: [ 'background-color', 'color', 'font-family', 'font-size', 'font-style', 'font-weight', 'margin-left', 'margin-right', 'text-align', 'text-decoration', ], }; /** @typedef {number} connstatus */ /** * Connection status constants for use by the connection handler * callback. * * @typedef {Object} Status * @property {connstatus} Status.ERROR - An error has occurred * @property {connstatus} Status.CONNECTING - The connection is currently being made * @property {connstatus} Status.CONNFAIL - The connection attempt failed * @property {connstatus} Status.AUTHENTICATING - The connection is authenticating * @property {connstatus} Status.AUTHFAIL - The authentication attempt failed * @property {connstatus} Status.CONNECTED - The connection has succeeded * @property {connstatus} Status.DISCONNECTED - The connection has been terminated * @property {connstatus} Status.DISCONNECTING - The connection is currently being terminated * @property {connstatus} Status.ATTACHED - The connection has been attached * @property {connstatus} Status.REDIRECT - The connection has been redirected * @property {connstatus} Status.CONNTIMEOUT - The connection has timed out * @property {connstatus} Status.BINDREQUIRED - The JID resource needs to be bound for this session * @property {connstatus} Status.ATTACHFAIL - Failed to attach to a pre-existing session * @property {connstatus} Status.RECONNECTING - Not used by Strophe, but added for integrators */ export const Status = { ERROR: 0, CONNECTING: 1, CONNFAIL: 2, AUTHENTICATING: 3, AUTHFAIL: 4, CONNECTED: 5, DISCONNECTED: 6, DISCONNECTING: 7, ATTACHED: 8, REDIRECT: 9, CONNTIMEOUT: 10, BINDREQUIRED: 11, ATTACHFAIL: 12, RECONNECTING: 13, }; export const ErrorCondition = { BAD_FORMAT: 'bad-format', CONFLICT: 'conflict', MISSING_JID_NODE: 'x-strophe-bad-non-anon-jid', NO_AUTH_MECH: 'no-auth-mech', UNKNOWN_REASON: 'unknown', }; /** * Logging level indicators. * @typedef {0|1|2|3|4} LogLevel * @typedef {'DEBUG'|'INFO'|'WARN'|'ERROR'|'FATAL'} LogLevelName * @typedef {Record} LogLevels */ export const LOG_LEVELS = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, FATAL: 4, }; /** * DOM element types. * * - ElementType.NORMAL - Normal element. * - ElementType.TEXT - Text data element. * - ElementType.FRAGMENT - XHTML fragment element. */ export const ElementType = { NORMAL: 1, TEXT: 3, CDATA: 4, FRAGMENT: 11, }; strophejs-3.1.0/src/errors.js000066400000000000000000000003221472775321000162020ustar00rootroot00000000000000class SessionError extends Error { /** * @param {string} message */ constructor(message) { super(message); this.name = 'StropheSessionError'; } } export { SessionError }; strophejs-3.1.0/src/handler.js000066400000000000000000000111011472775321000163000ustar00rootroot00000000000000import { getBareJidFromJid, handleError, isTagEqual } from './utils.js'; /** * _Private_ helper class for managing stanza handlers. * * A Handler encapsulates a user provided callback function to be * executed when matching stanzas are received by the connection. * Handlers can be either one-off or persistant depending on their * return value. Returning true will cause a Handler to remain active, and * returning false will remove the Handler. * * Users will not use Handler objects directly, but instead they * will use {@link Connection.addHandler} and * {@link Connection.deleteHandler}. */ class Handler { /** * @typedef {Object} HandlerOptions * @property {boolean} [HandlerOptions.matchBareFromJid] * @property {boolean} [HandlerOptions.ignoreNamespaceFragment] */ /** * Create and initialize a new Handler. * * @param {Function} handler - A function to be executed when the handler is run. * @param {string} ns - The namespace to match. * @param {string} name - The element name to match. * @param {string|string[]} type - The stanza type (or types if an array) to match. * @param {string} [id] - The element id attribute to match. * @param {string} [from] - The element from attribute to match. * @param {HandlerOptions} [options] - Handler options */ constructor(handler, ns, name, type, id, from, options) { this.handler = handler; this.ns = ns; this.name = name; this.type = type; this.id = id; this.options = options || { 'matchBareFromJid': false, 'ignoreNamespaceFragment': false }; if (this.options.matchBareFromJid) { this.from = from ? getBareJidFromJid(from) : null; } else { this.from = from; } // whether the handler is a user handler or a system handler this.user = true; } /** * Returns the XML namespace attribute on an element. * If `ignoreNamespaceFragment` was passed in for this handler, then the * URL fragment will be stripped. * @param {Element} elem - The XML element with the namespace. * @return {string} - The namespace, with optionally the fragment stripped. */ getNamespace(elem) { let elNamespace = elem.getAttribute('xmlns'); if (elNamespace && this.options.ignoreNamespaceFragment) { elNamespace = elNamespace.split('#')[0]; } return elNamespace; } /** * Tests if a stanza element (or any of its children) matches the * namespace set for this Handler. * @param {Element} elem - The XML element to test. * @return {boolean} - true if the stanza matches and false otherwise. */ namespaceMatch(elem) { if (!this.ns || this.getNamespace(elem) === this.ns) { return true; } for (const child of elem.children ?? []) { if (this.getNamespace(child) === this.ns) { return true; } else if (this.namespaceMatch(child)) { return true; } } return false; } /** * Tests if a stanza matches the Handler. * @param {Element} elem - The XML element to test. * @return {boolean} - true if the stanza matches and false otherwise. */ isMatch(elem) { let from = elem.getAttribute('from'); if (this.options.matchBareFromJid) { from = getBareJidFromJid(from); } const elem_type = elem.getAttribute('type'); if ( this.namespaceMatch(elem) && (!this.name || isTagEqual(elem, this.name)) && (!this.type || (Array.isArray(this.type) ? this.type.indexOf(elem_type) !== -1 : elem_type === this.type)) && (!this.id || elem.getAttribute('id') === this.id) && (!this.from || from === this.from) ) { return true; } return false; } /** * Run the callback on a matching stanza. * @param {Element} elem - The DOM element that triggered the Handler. * @return {boolean} - A boolean indicating if the handler should remain active. */ run(elem) { let result = null; try { result = this.handler(elem); } catch (e) { handleError(e); throw e; } return result; } /** * Get a String representation of the Handler object. * @return {string} */ toString() { return '{Handler: ' + this.handler + '(' + this.name + ',' + this.id + ',' + this.ns + ')}'; } } export default Handler; strophejs-3.1.0/src/index.js000066400000000000000000000137151472775321000160070ustar00rootroot00000000000000/*global globalThis*/ import * as shims from './shims.js'; import * as utils from './utils.js'; import Bosh from './bosh.js'; import Builder, { $build, $msg, $pres, $iq } from './builder.js'; import Connection from './connection.js'; import Handler from './handler.js'; import Request from './request.js'; import SASLAnonymous from './sasl-anon.js'; import SASLExternal from './sasl-external.js'; import SASLMechanism from './sasl.js'; import SASLOAuthBearer from './sasl-oauthbearer.js'; import SASLPlain from './sasl-plain.js'; import SASLSHA1 from './sasl-sha1.js'; import SASLSHA256 from './sasl-sha256.js'; import SASLSHA384 from './sasl-sha384.js'; import SASLSHA512 from './sasl-sha512.js'; import SASLXOAuth2 from './sasl-xoauth2.js'; import TimedHandler from './timed-handler.js'; import Websocket from './websocket.js'; import WorkerWebsocket from './worker-websocket.js'; import log from './log.js'; import { ElementType, ErrorCondition, LOG_LEVELS, NS, Status, XHTML } from './constants.js'; import { stx, Stanza } from './stanza.js'; /** * A container for all Strophe library functions. * * This object is a container for all the objects and constants * used in the library. It is not meant to be instantiated, but to * provide a namespace for library objects, constants, and functions. * * @namespace Strophe * @property {Handler} Handler * @property {Builder} Builder * @property {Request} Request Represents HTTP Requests made for a BOSH connection * @property {Bosh} Bosh Support for XMPP-over-HTTP via XEP-0124 (BOSH) * @property {Websocket} Websocket Support for XMPP over websocket * @property {WorkerWebsocket} WorkerWebsocket Support for XMPP over websocket in a shared worker * @property {number} TIMEOUT=1.1 Timeout multiplier. A waiting BOSH HTTP request * will be considered failed after Math.floor(TIMEOUT * wait) seconds have elapsed. * This defaults to 1.1, and with default wait, 66 seconds. * @property {number} SECONDARY_TIMEOUT=0.1 Secondary timeout multiplier. * In cases where Strophe can detect early failure, it will consider the request * failed if it doesn't return after `Math.floor(SECONDARY_TIMEOUT * wait)` * seconds have elapsed. This defaults to 0.1, and with default wait, 6 seconds. * @property {SASLAnonymous} SASLAnonymous SASL ANONYMOUS authentication. * @property {SASLPlain} SASLPlain SASL PLAIN authentication * @property {SASLSHA1} SASLSHA1 SASL SCRAM-SHA-1 authentication * @property {SASLSHA256} SASLSHA256 SASL SCRAM-SHA-256 authentication * @property {SASLSHA384} SASLSHA384 SASL SCRAM-SHA-384 authentication * @property {SASLSHA512} SASLSHA512 SASL SCRAM-SHA-512 authentication * @property {SASLOAuthBearer} SASLOAuthBearer SASL OAuth Bearer authentication * @property {SASLExternal} SASLExternal SASL EXTERNAL authentication * @property {SASLXOAuth2} SASLXOAuth2 SASL X-OAuth2 authentication * @property {Status} Status * @property {Object.} NS * @property {XHTML} XHTML */ const Strophe = { /** @constant: VERSION */ VERSION: '3.0.0', /** * @returns {number} */ get TIMEOUT() { return Bosh.getTimeoutMultplier(); }, /** * @param {number} n */ set TIMEOUT(n) { Bosh.setTimeoutMultiplier(n); }, /** * @returns {number} */ get SECONDARY_TIMEOUT() { return Bosh.getSecondaryTimeoutMultplier(); }, /** * @param {number} n */ set SECONDARY_TIMEOUT(n) { Bosh.setSecondaryTimeoutMultiplier(n); }, ...utils, ...log, shims, Request, // Transports Bosh, Websocket, WorkerWebsocket, Connection, Handler, // Available authentication mechanisms SASLAnonymous, SASLPlain, SASLSHA1, SASLSHA256, SASLSHA384, SASLSHA512, SASLOAuthBearer, SASLExternal, SASLXOAuth2, Stanza, Builder, ElementType, ErrorCondition, LogLevel: LOG_LEVELS, /** @type {Object.} */ NS, SASLMechanism, /** @type {Status} */ Status, TimedHandler, XHTML: { ...XHTML, validTag: utils.validTag, validCSS: utils.validCSS, validAttribute: utils.validAttribute, }, /** * Render a DOM element and all descendants to a String. * @method Strophe.serialize * @param {Element|Builder} elem - A DOM element. * @return {string} - The serialized element tree as a String. */ serialize(elem) { return Builder.serialize(elem); }, /** * @typedef {import('./constants').LogLevel} LogLevel * * Library consumers can use this function to set the log level of Strophe. * The default log level is Strophe.LogLevel.INFO. * @param {LogLevel} level * @example Strophe.setLogLevel(Strophe.LogLevel.DEBUG); */ setLogLevel(level) { log.setLogLevel(level); }, /** * This function is used to extend the current namespaces in * Strophe.NS. It takes a key and a value with the key being the * name of the new namespace, with its actual value. * @example: Strophe.addNamespace('PUBSUB', "http://jabber.org/protocol/pubsub"); * * @param {string} name - The name under which the namespace will be * referenced under Strophe.NS * @param {string} value - The actual namespace. */ addNamespace(name, value) { Strophe.NS[name] = value; }, /** * Extends the Strophe.Connection object with the given plugin. * @param {string} name - The name of the extension. * @param {Object} ptype - The plugin's prototype. */ addConnectionPlugin(name, ptype) { Connection.addConnectionPlugin(name, ptype); }, }; globalThis.$build = $build; globalThis.$iq = $iq; globalThis.$msg = $msg; globalThis.$pres = $pres; globalThis.Strophe = Strophe; globalThis.stx = stx; const toStanza = Stanza.toElement; globalThis.toStanza = Stanza.toElement; // Deprecated export { Builder, $build, $iq, $msg, $pres, Strophe, Stanza, stx, toStanza, Request }; strophejs-3.1.0/src/log.js000066400000000000000000000055431472775321000154610ustar00rootroot00000000000000/** * @typedef {import('./constants').LogLevel} LogLevel */ import { LOG_LEVELS } from './constants.js'; let logLevel = LOG_LEVELS.DEBUG; const log = { /** * Library consumers can use this function to set the log level of Strophe. * The default log level is Strophe.LogLevel.INFO. * @param {LogLevel} level * @example Strophe.setLogLevel(Strophe.LogLevel.DEBUG); */ setLogLevel(level) { if (level < LOG_LEVELS.DEBUG || level > LOG_LEVELS.FATAL) { throw new Error("Invalid log level supplied to setLogLevel"); } logLevel = level; }, /** * * Please note that data sent and received over the wire is logged * via {@link Strophe.Connection#rawInput|Strophe.Connection.rawInput()} * and {@link Strophe.Connection#rawOutput|Strophe.Connection.rawOutput()}. * * The different levels and their meanings are * * DEBUG - Messages useful for debugging purposes. * INFO - Informational messages. This is mostly information like * 'disconnect was called' or 'SASL auth succeeded'. * WARN - Warnings about potential problems. This is mostly used * to report transient connection errors like request timeouts. * ERROR - Some error occurred. * FATAL - A non-recoverable fatal error occurred. * * @param {number} level - The log level of the log message. * This will be one of the values in Strophe.LOG_LEVELS. * @param {string} msg - The log message. */ log(level, msg) { if (level < logLevel) { return; } if (level >= LOG_LEVELS.ERROR) { console?.error(msg); } else if (level === LOG_LEVELS.INFO) { console?.info(msg); } else if (level === LOG_LEVELS.WARN) { console?.warn(msg); } else if (level === LOG_LEVELS.DEBUG) { console?.debug(msg); } }, /** * Log a message at the Strophe.LOG_LEVELS.DEBUG level. * @param {string} msg - The log message. */ debug(msg) { this.log(LOG_LEVELS.DEBUG, msg); }, /** * Log a message at the Strophe.LOG_LEVELS.INFO level. * @param {string} msg - The log message. */ info(msg) { this.log(LOG_LEVELS.INFO, msg); }, /** * Log a message at the Strophe.LOG_LEVELS.WARN level. * @param {string} msg - The log message. */ warn(msg) { this.log(LOG_LEVELS.WARN, msg); }, /** * Log a message at the Strophe.LOG_LEVELS.ERROR level. * @param {string} msg - The log message. */ error(msg) { this.log(LOG_LEVELS.ERROR, msg); }, /** * Log a message at the Strophe.LOG_LEVELS.FATAL level. * @param {string} msg - The log message. */ fatal(msg) { this.log(LOG_LEVELS.FATAL, msg); }, }; export default log; strophejs-3.1.0/src/request.js000066400000000000000000000074551472775321000163740ustar00rootroot00000000000000import log from './log.js'; import Builder from './builder.js'; import { ErrorCondition } from './constants.js'; import { getParserError, xmlHtmlNode } from './utils.js'; /** * _Private_ variable that keeps track of the request ids for connections. */ let _requestId = 0; /** * Helper class that provides a cross implementation abstraction * for a BOSH related XMLHttpRequest. * * The Request class is used internally to encapsulate BOSH request * information. It is not meant to be used from user's code. * * @property {number} id * @property {number} sends * @property {XMLHttpRequest} xhr */ class Request { /** * Create and initialize a new Request object. * * @param {Element} elem - The XML data to be sent in the request. * @param {Function} func - The function that will be called when the * XMLHttpRequest readyState changes. * @param {number} rid - The BOSH rid attribute associated with this request. * @param {number} [sends=0] - The number of times this same request has been sent. */ constructor(elem, func, rid, sends = 0) { this.id = ++_requestId; this.xmlData = elem; this.data = Builder.serialize(elem); // save original function in case we need to make a new request // from this one. this.origFunc = func; this.func = func; this.rid = rid; this.date = NaN; this.sends = sends; this.abort = false; this.dead = null; this.age = () => (this.date ? (new Date().valueOf() - this.date.valueOf()) / 1000 : 0); this.timeDead = () => (this.dead ? (new Date().valueOf() - this.dead.valueOf()) / 1000 : 0); this.xhr = this._newXHR(); } /** * Get a response from the underlying XMLHttpRequest. * This function attempts to get a response from the request and checks * for errors. * @throws "parsererror" - A parser error occured. * @throws "bad-format" - The entity has sent XML that cannot be processed. * @return {Element} - The DOM element tree of the response. */ getResponse() { const node = this.xhr.responseXML?.documentElement; if (node) { if (node.tagName === 'parsererror') { log.error('invalid response received'); log.error('responseText: ' + this.xhr.responseText); log.error('responseXML: ' + Builder.serialize(node)); throw new Error('parsererror'); } } else if (this.xhr.responseText) { // In Node (with xhr2) or React Native, we may get responseText but no responseXML. // We can try to parse it manually. log.debug('Got responseText but no responseXML; attempting to parse it with DOMParser...'); const doc = xmlHtmlNode(this.xhr.responseText); const parserError = getParserError(doc); if (!doc || parserError) { if (parserError) { log.error('invalid response received: ' + parserError); log.error('responseText: ' + this.xhr.responseText); } const error = new Error(); error.name = ErrorCondition.BAD_FORMAT; throw error; } } return node; } /** * _Private_ helper function to create XMLHttpRequests. * This function creates XMLHttpRequests across all implementations. * @private * @return {XMLHttpRequest} */ _newXHR() { const xhr = new XMLHttpRequest(); if (xhr.overrideMimeType) { xhr.overrideMimeType('text/xml; charset=utf-8'); } // use Function.bind() to prepend ourselves as an argument xhr.onreadystatechange = this.func.bind(null, this); return xhr; } } export default Request; strophejs-3.1.0/src/sasl-anon.js000066400000000000000000000010551472775321000165650ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import SASLMechanism from './sasl.js'; class SASLAnonymous extends SASLMechanism { /** * SASL ANONYMOUS authentication. */ constructor(mechname = 'ANONYMOUS', isClientFirst = false, priority = 20) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this test(connection) { return connection.authcid === null; } } export default SASLAnonymous; strophejs-3.1.0/src/sasl-external.js000066400000000000000000000023361472775321000174570ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import SASLMechanism from './sasl.js'; class SASLExternal extends SASLMechanism { /** * SASL EXTERNAL authentication. * * The EXTERNAL mechanism allows a client to request the server to use * credentials established by means external to the mechanism to * authenticate the client. The external means may be, for instance, * TLS services. */ constructor(mechname = 'EXTERNAL', isClientFirst = true, priority = 10) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this onChallenge(connection) { /* According to XEP-178, an authzid SHOULD NOT be presented when the * authcid contained or implied in the client certificate is the JID (i.e. * authzid) with which the user wants to log in as. * * To NOT send the authzid, the user should therefore set the authcid equal * to the JID when instantiating a new Strophe.Connection object. */ return connection.authcid === connection.authzid ? '' : connection.authzid; } } export default SASLExternal; strophejs-3.1.0/src/sasl-oauthbearer.js000066400000000000000000000022211472775321000201270ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import SASLMechanism from './sasl.js'; import utils from './utils'; class SASLOAuthBearer extends SASLMechanism { /** * SASL OAuth Bearer authentication. */ constructor(mechname = 'OAUTHBEARER', isClientFirst = true, priority = 40) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this test(connection) { return connection.pass !== null; } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this onChallenge(connection) { let auth_str = 'n,'; if (connection.authcid !== null) { auth_str = auth_str + 'a=' + connection.authzid; } auth_str = auth_str + ','; auth_str = auth_str + '\u0001'; auth_str = auth_str + 'auth=Bearer '; auth_str = auth_str + connection.pass; auth_str = auth_str + '\u0001'; auth_str = auth_str + '\u0001'; return utils.utf16to8(auth_str); } } export default SASLOAuthBearer; strophejs-3.1.0/src/sasl-plain.js000066400000000000000000000024051472775321000167350ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import SASLMechanism from './sasl.js'; import utils from './utils'; class SASLPlain extends SASLMechanism { /** * SASL PLAIN authentication. */ constructor(mechname = 'PLAIN', isClientFirst = true, priority = 50) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this test(connection) { return connection.authcid !== null; } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this onChallenge(connection) { const { authcid, authzid, domain, pass } = connection; if (!domain) { throw new Error('SASLPlain onChallenge: domain is not defined!'); } // Only include authzid if it differs from authcid. // See: https://tools.ietf.org/html/rfc6120#section-6.3.8 let auth_str = authzid !== `${authcid}@${domain}` ? authzid : ''; auth_str = auth_str + '\u0000'; auth_str = auth_str + authcid; auth_str = auth_str + '\u0000'; auth_str = auth_str + pass; return utils.utf16to8(auth_str); } } export default SASLPlain; strophejs-3.1.0/src/sasl-sha1.js000066400000000000000000000022351472775321000164670ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import SASLMechanism from './sasl.js'; import scram from './scram.js'; class SASLSHA1 extends SASLMechanism { /** * SASL SCRAM SHA 1 authentication. */ constructor(mechname = 'SCRAM-SHA-1', isClientFirst = true, priority = 60) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this test(connection) { return connection.authcid !== null; } /** * @param {Connection} connection * @param {string} [challenge] * @return {Promise} Mechanism response. */ // eslint-disable-next-line class-methods-use-this async onChallenge(connection, challenge) { return await scram.scramResponse(connection, challenge, 'SHA-1', 160); } /** * @param {Connection} connection * @param {string} [test_cnonce] */ // eslint-disable-next-line class-methods-use-this clientChallenge(connection, test_cnonce) { return scram.clientChallenge(connection, test_cnonce); } } export default SASLSHA1; strophejs-3.1.0/src/sasl-sha256.js000066400000000000000000000021541472775321000166430ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import SASLMechanism from './sasl.js'; import scram from './scram.js'; class SASLSHA256 extends SASLMechanism { /** * SASL SCRAM SHA 256 authentication. */ constructor(mechname = 'SCRAM-SHA-256', isClientFirst = true, priority = 70) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this test(connection) { return connection.authcid !== null; } /** * @param {Connection} connection * @param {string} [challenge] */ // eslint-disable-next-line class-methods-use-this async onChallenge(connection, challenge) { return await scram.scramResponse(connection, challenge, 'SHA-256', 256); } /** * @param {Connection} connection * @param {string} [test_cnonce] */ // eslint-disable-next-line class-methods-use-this clientChallenge(connection, test_cnonce) { return scram.clientChallenge(connection, test_cnonce); } } export default SASLSHA256; strophejs-3.1.0/src/sasl-sha384.js000066400000000000000000000021541472775321000166450ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import SASLMechanism from './sasl.js'; import scram from './scram.js'; class SASLSHA384 extends SASLMechanism { /** * SASL SCRAM SHA 384 authentication. */ constructor(mechname = 'SCRAM-SHA-384', isClientFirst = true, priority = 71) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this test(connection) { return connection.authcid !== null; } /** * @param {Connection} connection * @param {string} [challenge] */ // eslint-disable-next-line class-methods-use-this async onChallenge(connection, challenge) { return await scram.scramResponse(connection, challenge, 'SHA-384', 384); } /** * @param {Connection} connection * @param {string} [test_cnonce] */ // eslint-disable-next-line class-methods-use-this clientChallenge(connection, test_cnonce) { return scram.clientChallenge(connection, test_cnonce); } } export default SASLSHA384; strophejs-3.1.0/src/sasl-sha512.js000066400000000000000000000021541472775321000166360ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import SASLMechanism from './sasl.js'; import scram from './scram.js'; class SASLSHA512 extends SASLMechanism { /** * SASL SCRAM SHA 512 authentication. */ constructor(mechname = 'SCRAM-SHA-512', isClientFirst = true, priority = 72) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this test(connection) { return connection.authcid !== null; } /** * @param {Connection} connection * @param {string} [challenge] */ // eslint-disable-next-line class-methods-use-this async onChallenge(connection, challenge) { return await scram.scramResponse(connection, challenge, 'SHA-512', 512); } /** * @param {Connection} connection * @param {string} [test_cnonce] */ // eslint-disable-next-line class-methods-use-this clientChallenge(connection, test_cnonce) { return scram.clientChallenge(connection, test_cnonce); } } export default SASLSHA512; strophejs-3.1.0/src/sasl-xoauth2.js000066400000000000000000000017371472775321000172330ustar00rootroot00000000000000import SASLMechanism from './sasl.js'; import utils from './utils'; /** * @typedef {import("./connection.js").default} Connection */ class SASLXOAuth2 extends SASLMechanism { /** * SASL X-OAuth2 authentication. */ constructor(mechname = 'X-OAUTH2', isClientFirst = true, priority = 30) { super(mechname, isClientFirst, priority); } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this test(connection) { return connection.pass !== null; } /** * @param {Connection} connection */ // eslint-disable-next-line class-methods-use-this onChallenge(connection) { let auth_str = '\u0000'; if (connection.authcid !== null) { auth_str = auth_str + connection.authzid; } auth_str = auth_str + '\u0000'; auth_str = auth_str + connection.pass; return utils.utf16to8(auth_str); } } export default SASLXOAuth2; strophejs-3.1.0/src/sasl.js000066400000000000000000000077631472775321000156500ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ /** * Encapsulates an SASL authentication mechanism. * * User code may override the priority for each mechanism or disable it completely. * See for information about changing priority and for informatian on * how to disable a mechanism. * * By default, all mechanisms are enabled and t_he priorities are * * SCRAM-SHA-512 - 72 * SCRAM-SHA-384 - 71 * SCRAM-SHA-256 - 70 * SCRAM-SHA-1 - 60 * PLAIN - 50 * OAUTHBEARER - 40 * X-OAUTH2 - 30 * ANONYMOUS - 20 * EXTERNAL - 10 * * See: {@link Strophe.Connection#registerSASLMechanisms} */ class SASLMechanism { /** * PrivateConstructor: Strophe.SASLMechanism * SASL auth mechanism abstraction. * @param {String} [name] - SASL Mechanism name. * @param {Boolean} [isClientFirst] - If client should send response first without challenge. * @param {Number} [priority] - Priority. */ constructor(name, isClientFirst, priority) { /** Mechanism name. */ this.mechname = name; /** * If client sends response without initial server challenge. */ this.isClientFirst = isClientFirst; /** * Determines which {@link SASLMechanism} is chosen for authentication (Higher is better). * Users may override this to prioritize mechanisms differently. * * Example: (This will cause Strophe to choose the mechanism that the server sent first) * * > Strophe.SASLPlain.priority = Strophe.SASLSHA1.priority; * * See for a list of available mechanisms. */ this.priority = priority; } /** * Checks if mechanism able to run. * To disable a mechanism, make this return false; * * To disable plain authentication run * > Strophe.SASLPlain.test = function() { * > return false; * > } * * See for a list of available mechanisms. * @param {Connection} connection - Target Connection. * @return {boolean} If mechanism was able to run. */ // eslint-disable-next-line class-methods-use-this, no-unused-vars test(connection) { return true; } /** * Called before starting mechanism on some connection. * @param {Connection} connection - Target Connection. */ onStart(connection) { this._connection = connection; } /** * Called by protocol implementation on incoming challenge. * * By deafult, if the client is expected to send data first (isClientFirst === true), * this method is called with `challenge` as null on the first call, * unless `clientChallenge` is overridden in the relevant subclass. * @param {Connection} connection - Target Connection. * @param {string} [challenge] - current challenge to handle. * @return {string|Promise} Mechanism response. */ // eslint-disable-next-line no-unused-vars, class-methods-use-this onChallenge(connection, challenge) { throw new Error('You should implement challenge handling!'); } /** * Called by the protocol implementation if the client is expected to send * data first in the authentication exchange (i.e. isClientFirst === true). * @param {Connection} connection - Target Connection. * @return {string|Promise} Mechanism response. */ clientChallenge(connection) { if (!this.isClientFirst) { throw new Error('clientChallenge should not be called if isClientFirst is false!'); } return this.onChallenge(connection); } /** * Protocol informs mechanism implementation about SASL failure. */ onFailure() { this._connection = null; } /** * Protocol informs mechanism implementation about SASL success. */ onSuccess() { this._connection = null; } } export default SASLMechanism; strophejs-3.1.0/src/scram.js000066400000000000000000000172751472775321000160120ustar00rootroot00000000000000/** * @typedef {import("./connection.js").default} Connection */ import utils from './utils'; import log from './log.js'; /** * @param {string} authMessage * @param {ArrayBufferLike} clientKey * @param {string} hashName */ async function scramClientProof(authMessage, clientKey, hashName) { const storedKey = await crypto.subtle.importKey( 'raw', await crypto.subtle.digest(hashName, clientKey), { 'name': 'HMAC', 'hash': hashName }, false, ['sign'] ); const clientSignature = await crypto.subtle.sign('HMAC', storedKey, utils.stringToArrayBuf(authMessage)); return utils.xorArrayBuffers(clientKey, clientSignature); } /** * This function parses the information in a SASL SCRAM challenge response, * into an object of the form * { nonce: String, * salt: ArrayBuffer, * iter: Int * } * Returns undefined on failure. * @param {string} challenge */ function scramParseChallenge(challenge) { let nonce, salt, iter; const attribMatch = /([a-z]+)=([^,]+)(,|$)/; while (challenge.match(attribMatch)) { const matches = challenge.match(attribMatch); challenge = challenge.replace(matches[0], ''); switch (matches[1]) { case 'r': nonce = matches[2]; break; case 's': salt = utils.base64ToArrayBuf(matches[2]); break; case 'i': iter = parseInt(matches[2], 10); break; case 'm': // Mandatory but unknown extension, per RFC 5802 we should abort return undefined; default: // Non-mandatory extension, per RFC 5802 we should ignore it break; } } // Consider iteration counts less than 4096 insecure, as reccommended by // RFC 5802 if (isNaN(iter) || iter < 4096) { log.warn('Failing SCRAM authentication because server supplied iteration count < 4096.'); return undefined; } if (!salt) { log.warn('Failing SCRAM authentication because server supplied incorrect salt.'); return undefined; } return { 'nonce': nonce, 'salt': salt, 'iter': iter }; } /** * Derive the client and server keys given a string password, * a hash name, and a bit length. * Returns an object of the following form: * { ck: ArrayBuffer, the client key * sk: ArrayBuffer, the server key * } * @param {string} password * @param {BufferSource} salt * @param {number} iter * @param {string} hashName * @param {number} hashBits */ async function scramDeriveKeys(password, salt, iter, hashName, hashBits) { const saltedPasswordBits = await crypto.subtle.deriveBits( { 'name': 'PBKDF2', 'salt': salt, 'iterations': iter, 'hash': { 'name': hashName } }, await crypto.subtle.importKey('raw', utils.stringToArrayBuf(password), 'PBKDF2', false, ['deriveBits']), hashBits ); const saltedPassword = await crypto.subtle.importKey( 'raw', saltedPasswordBits, { 'name': 'HMAC', 'hash': hashName }, false, ['sign'] ); return { 'ck': await crypto.subtle.sign('HMAC', saltedPassword, utils.stringToArrayBuf('Client Key')), 'sk': await crypto.subtle.sign('HMAC', saltedPassword, utils.stringToArrayBuf('Server Key')), }; } /** * @param {string} authMessage * @param {BufferSource} sk * @param {string} hashName */ async function scramServerSign(authMessage, sk, hashName) { const serverKey = await crypto.subtle.importKey('raw', sk, { 'name': 'HMAC', 'hash': hashName }, false, ['sign']); return crypto.subtle.sign('HMAC', serverKey, utils.stringToArrayBuf(authMessage)); } /** * Generate an ASCII nonce (not containing the ',' character) * @return {string} */ function generate_cnonce() { // generate 16 random bytes of nonce, base64 encoded const bytes = new Uint8Array(16); return utils.arrayBufToBase64(crypto.getRandomValues(bytes).buffer); } /** * @typedef {Object} Password * @property {string} Password.name * @property {string} Password.ck * @property {string} Password.sk * @property {number} Password.iter * @property {string} salt */ const scram = { /** * On success, sets * connection_sasl_data["server-signature"] * and * connection._sasl_data.keys * * The server signature should be verified after this function completes.. * * On failure, returns connection._sasl_failure_cb(); * @param {Connection} connection * @param {string} challenge * @param {string} hashName * @param {number} hashBits */ async scramResponse(connection, challenge, hashName, hashBits) { const cnonce = connection._sasl_data.cnonce; const challengeData = scramParseChallenge(challenge); // The RFC requires that we verify the (server) nonce has the client // nonce as an initial substring. if (!challengeData && challengeData?.nonce.slice(0, cnonce.length) !== cnonce) { log.warn('Failing SCRAM authentication because server supplied incorrect nonce.'); connection._sasl_data = {}; return connection._sasl_failure_cb(); } let clientKey, serverKey; const { pass } = connection; if (typeof connection.pass === 'string' || connection.pass instanceof String) { const keys = await scramDeriveKeys( /** @type {string} */ (pass), challengeData.salt, challengeData.iter, hashName, hashBits ); clientKey = keys.ck; serverKey = keys.sk; } else if ( // Either restore the client key and server key passed in, or derive new ones /** @type {Password} */ (pass)?.name === hashName && /** @type {Password} */ (pass)?.salt === utils.arrayBufToBase64(challengeData.salt) && /** @type {Password} */ (pass)?.iter === challengeData.iter ) { const { ck, sk } = /** @type {Password} */ (pass); clientKey = utils.base64ToArrayBuf(ck); serverKey = utils.base64ToArrayBuf(sk); } else { return connection._sasl_failure_cb(); } const clientFirstMessageBare = connection._sasl_data['client-first-message-bare']; const serverFirstMessage = challenge; const clientFinalMessageBare = `c=biws,r=${challengeData.nonce}`; const authMessage = `${clientFirstMessageBare},${serverFirstMessage},${clientFinalMessageBare}`; const clientProof = await scramClientProof(authMessage, clientKey, hashName); const serverSignature = await scramServerSign(authMessage, serverKey, hashName); connection._sasl_data['server-signature'] = utils.arrayBufToBase64(serverSignature); connection._sasl_data.keys = { 'name': hashName, 'iter': challengeData.iter, 'salt': utils.arrayBufToBase64(challengeData.salt), 'ck': utils.arrayBufToBase64(clientKey), 'sk': utils.arrayBufToBase64(serverKey), }; return `${clientFinalMessageBare},p=${utils.arrayBufToBase64(clientProof)}`; }, /** * Returns a string containing the client first message * @param {Connection} connection * @param {string} test_cnonce */ clientChallenge(connection, test_cnonce) { const cnonce = test_cnonce || generate_cnonce(); const client_first_message_bare = `n=${connection.authcid},r=${cnonce}`; connection._sasl_data.cnonce = cnonce; connection._sasl_data['client-first-message-bare'] = client_first_message_bare; return `n,,${client_first_message_bare}`; }, }; export { scram as default }; strophejs-3.1.0/src/shared-connection-worker.js000066400000000000000000000063771472775321000216200ustar00rootroot00000000000000/** @type {ConnectionManager} */ let manager; const Status = { ERROR: 0, CONNECTING: 1, CONNFAIL: 2, AUTHENTICATING: 3, AUTHFAIL: 4, CONNECTED: 5, DISCONNECTED: 6, DISCONNECTING: 7, ATTACHED: 8, REDIRECT: 9, CONNTIMEOUT: 10, BINDREQUIRED: 11, ATTACHFAIL: 12, }; /** Class: ConnectionManager * * Manages the shared websocket connection as well as the ports of the * connected tabs. */ class ConnectionManager { constructor() { /** @type {MessagePort[]} */ this.ports = []; } /** @param {MessagePort} port */ addPort(port) { this.ports.push(port); port.addEventListener('message', (e) => { const method = e.data[0]; try { this[/** @type {'send'|'_closeSocket'}*/ (method)](e.data.splice(1)); } catch (e) { console?.error(e); } }); port.start(); } /** * @param {[string, string]} data */ _connect(data) { this.jid = data[1]; this._closeSocket(); this.socket = new WebSocket(data[0], 'xmpp'); this.socket.onopen = () => this._onOpen(); this.socket.onerror = (e) => this._onError(e); this.socket.onclose = (e) => this._onClose(e); this.socket.onmessage = (message) => this._onMessage(message); } _attach() { if (this.socket && this.socket.readyState !== WebSocket.CLOSED) { this.ports.forEach((p) => p.postMessage(['_attachCallback', Status.ATTACHED, this.jid])); } else { this.ports.forEach((p) => p.postMessage(['_attachCallback', Status.ATTACHFAIL])); } } /** @param {string} str */ send(str) { this.socket.send(str); } /** @param {string} str */ close(str) { if (this.socket && this.socket.readyState !== WebSocket.CLOSED) { try { this.socket.send(str); } catch (e) { this.ports.forEach((p) => p.postMessage(['log', 'error', e])); this.ports.forEach((p) => p.postMessage(['log', 'error', "Couldn't send tag."])); } } } _onOpen() { this.ports.forEach((p) => p.postMessage(['_onOpen'])); } /** @param {CloseEvent} e */ _onClose(e) { this.ports.forEach((p) => p.postMessage(['_onClose', e.reason])); } /** @param {MessageEvent} message */ _onMessage(message) { const o = { 'data': message.data }; this.ports.forEach((p) => p.postMessage(['_onMessage', o])); } /** @param {Event} error */ _onError(error) { this.ports.forEach((p) => p.postMessage(['_onError', error])); } _closeSocket() { if (this.socket) { try { this.socket.onclose = null; this.socket.onerror = null; this.socket.onmessage = null; this.socket.close(); } catch (e) { this.ports.forEach((p) => p.postMessage(['log', 'error', e])); } } this.socket = null; } } addEventListener( 'connect', /** @param {MessageEvent} e */ (e) => { manager = manager || new ConnectionManager(); manager.addPort(e.ports[0]); } ); strophejs-3.1.0/src/shims.js000066400000000000000000000072731472775321000160250ustar00rootroot00000000000000/** * This module provides uniform * Shims APIs and globals that are not present in all JS environments, * the most common example for Strophe being browser APIs like WebSocket * and DOM that don't exist under nodejs. * * Usually these will be supplied in nodejs by conditionally requiring a * NPM module that provides a compatible implementation. */ /* global globalThis */ /** * WHATWG WebSockets API * https://www.w3.org/TR/websockets/ * * Interface to use the web socket protocol * * Used implementations: * - supported browsers: built-in in WebSocket global * https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Browser_compatibility * - nodejs: use standard-compliant 'ws' module * https://www.npmjs.com/package/ws */ function getWebSocketImplementation() { if (typeof globalThis.WebSocket === 'undefined') { try { return require('ws'); // eslint-disable-next-line no-unused-vars } catch (e) { throw new Error('You must install the "ws" package to use Strophe in nodejs.'); } } return globalThis.WebSocket; } export const WebSocket = getWebSocketImplementation(); /** * Retrieves the XMLSerializer implementation for the current environment. * * In browser environments, it uses the built-in XMLSerializer. * In Node.js environments, it attempts to load the 'jsdom' package * to create a compatible XMLSerializer. */ function getXMLSerializerImplementation() { if (typeof globalThis.XMLSerializer === 'undefined') { let JSDOM; try { JSDOM = require('jsdom').JSDOM; // eslint-disable-next-line no-unused-vars } catch (e) { throw new Error('You must install the "ws" package to use Strophe in nodejs.'); } const dom = new JSDOM(''); return dom.window.XMLSerializer; } return globalThis.XMLSerializer; } export const XMLSerializer = getXMLSerializerImplementation(); /** * DOMParser * https://w3c.github.io/DOM-Parsing/#the-domparser-interface * * Interface to parse XML strings into Document objects * * Used implementations: * - supported browsers: built-in in DOMParser global * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility * - nodejs: use 'jsdom' https://www.npmjs.com/package/jsdom */ function getDOMParserImplementation() { const DOMParserImplementation = globalThis.DOMParser; if (typeof DOMParserImplementation === 'undefined') { // NodeJS let JSDOM; try { JSDOM = require('jsdom').JSDOM; // eslint-disable-next-line no-unused-vars } catch (e) { throw new Error('You must install the "jsdom" package to use Strophe in nodejs.'); } const dom = new JSDOM(''); return dom.window.DOMParser; } return DOMParserImplementation; } export const DOMParser = getDOMParserImplementation(); /** * Creates a dummy XML DOM document to serve as an element and text node generator. * * Used implementations: * - browser: use document's createDocument * - nodejs: use 'jsdom' https://www.npmjs.com/package/jsdom */ export function getDummyXMLDOMDocument() { if (typeof document === 'undefined') { // NodeJS let JSDOM; try { JSDOM = require('jsdom').JSDOM; // eslint-disable-next-line no-unused-vars } catch (e) { throw new Error('You must install the "jsdom" package to use Strophe in nodejs.'); } const dom = new JSDOM(''); return dom.window.document.implementation.createDocument('jabber:client', 'strophe', null); } return document.implementation.createDocument('jabber:client', 'strophe', null); } strophejs-3.1.0/src/stanza.js000066400000000000000000000100221472775321000161640ustar00rootroot00000000000000import Builder from './builder.js'; import log from './log.js'; import { getFirstElementChild, getParserError, xmlHtmlNode, xmlescape } from './utils.js'; /** * A Stanza represents a XML element used in XMPP (commonly referred to as stanzas). */ export class Stanza extends Builder { /** @type {string} */ #string; /** @type {Array} */ #strings; /** * @typedef {Array} StanzaValue * @type {StanzaValue|Array} */ #values; /** * @param {string[]} strings * @param {any[]} values */ constructor(strings, values) { super('stanza'); this.#strings = strings; this.#values = values; } /** * A directive which can be used to pass a string of XML as a value to the * stx tagged template literal. * * It's considered "unsafe" because it can pose a security risk if used with * untrusted input. * * @param {string} string * @returns {Builder} * @example * const status = 'I am busy!'; * const pres = stx` * * dnd * ${unsafeXML(status)} * `; * connection.send(pres); */ static unsafeXML(string) { return Builder.fromString(string); } /** * Turns the passed-in string into an XML Element. * @param {string} string * @param {boolean} [throwErrorIfInvalidNS] * @returns {Element} */ static toElement(string, throwErrorIfInvalidNS) { const doc = xmlHtmlNode(string); const parserError = getParserError(doc); if (parserError) { throw new Error(`Parser Error: ${parserError}`); } const node = getFirstElementChild(doc); if ( ['message', 'iq', 'presence'].includes(node.nodeName.toLowerCase()) && node.namespaceURI !== 'jabber:client' && node.namespaceURI !== 'jabber:server' ) { const err_msg = `Invalid namespaceURI ${node.namespaceURI}`; if (throwErrorIfInvalidNS) { throw new Error(err_msg); } else { log.error(err_msg); } } return node; } buildTree() { return Stanza.toElement(this.toString(), true); } /** * @return {string} */ toString() { this.#string = this.#string || this.#strings .reduce((acc, str) => { const idx = this.#strings.indexOf(str); const value = this.#values.length > idx ? this.#values[idx] : ''; return ( acc + str + (Array.isArray(value) ? value .map((v) => v instanceof Stanza || v instanceof Builder ? v : xmlescape(v.toString()) ) .join('') : value instanceof Stanza || value instanceof Builder ? value : xmlescape(value.toString())) ); }, '') .trim(); return this.#string; } } /** * Tagged template literal function which generates {@link Stanza} objects * * @example * const pres = stx`${show}` * * connection.send(msg); * * @example * const msg = stx` * Hello world * `; * * connection.send(msg); * * @param {string[]} strings * @param {...any} values * @returns {Stanza} */ export function stx(strings, ...values) { return new Stanza(strings, values); } strophejs-3.1.0/src/timed-handler.js000066400000000000000000000034461472775321000174150ustar00rootroot00000000000000/** * _Private_ helper class for managing timed handlers. * * A Strophe.TimedHandler encapsulates a user provided callback that * should be called after a certain period of time or at regular * intervals. The return value of the callback determines whether the * Strophe.TimedHandler will continue to fire. * * Users will not use Strophe.TimedHandler objects directly, but instead * they will use {@link Strophe.Connection#addTimedHandler|addTimedHandler()} and * {@link Strophe.Connection#deleteTimedHandler|deleteTimedHandler()}. * * @memberof Strophe */ class TimedHandler { /** * Create and initialize a new Strophe.TimedHandler object. * @param {number} period - The number of milliseconds to wait before the * handler is called. * @param {Function} handler - The callback to run when the handler fires. This * function should take no arguments. */ constructor(period, handler) { this.period = period; this.handler = handler; this.lastCalled = new Date().getTime(); this.user = true; } /** * Run the callback for the Strophe.TimedHandler. * * @return {boolean} Returns the result of running the handler, * which is `true` if the Strophe.TimedHandler should be called again, * and `false` otherwise. */ run() { this.lastCalled = new Date().getTime(); return this.handler(); } /** * Reset the last called time for the Strophe.TimedHandler. */ reset() { this.lastCalled = new Date().getTime(); } /** * Get a string representation of the Strophe.TimedHandler object. * @return {string} */ toString() { return '{TimedHandler: ' + this.handler + '(' + this.period + ')}'; } } export default TimedHandler; strophejs-3.1.0/src/types/000077500000000000000000000000001472775321000154775ustar00rootroot00000000000000strophejs-3.1.0/src/types/bosh.d.ts000066400000000000000000000251071472775321000172310ustar00rootroot00000000000000export default Bosh; export type Connection = import("./connection.js").default; /** * _Private_ helper class that handles BOSH Connections * The Bosh class is used internally by Connection * to encapsulate BOSH sessions. It is not meant to be used from user's code. */ declare class Bosh { /** * @param {number} m */ static setTimeoutMultiplier(m: number): void; /** * @returns {number} */ static getTimeoutMultplier(): number; /** * @param {number} m */ static setSecondaryTimeoutMultiplier(m: number): void; /** * @returns {number} */ static getSecondaryTimeoutMultplier(): number; /** * Returns the HTTP status code from a {@link Request} * @private * @param {Request} req - The {@link Request} instance. * @param {number} [def] - The default value that should be returned if no status value was found. */ private static _getRequestStatus; /** * @param {Connection} connection - The Connection that will use BOSH. */ constructor(connection: Connection); _conn: import("./connection.js").default; rid: number; sid: string; hold: number; wait: number; window: number; errors: number; inactivity: number; /** * BOSH-Connections will have all stanzas wrapped in a tag when * passed to {@link Connection#xmlInput|xmlInput()} or {@link Connection#xmlOutput|xmlOutput()}. * To strip this tag, User code can set {@link Bosh#strip|strip} to `true`: * * > // You can set `strip` on the prototype * > Bosh.prototype.strip = true; * * > // Or you can set it on the Bosh instance (which is `._proto` on the connection instance. * > const conn = new Connection(); * > conn._proto.strip = true; * * This will enable stripping of the body tag in both * {@link Connection#xmlInput|xmlInput} and {@link Connection#xmlOutput|xmlOutput}. * * @property {boolean} [strip=false] */ strip: boolean; lastResponseHeaders: string; /** @type {Request[]} */ _requests: Request[]; /** * _Private_ helper function to generate the wrapper for BOSH. * @private * @return {Builder} - A Builder with a element. */ private _buildBody; /** * Reset the connection. * This function is called by the reset function of the Connection */ _reset(): void; /** * _Private_ function that initializes the BOSH connection. * Creates and sends the Request that initializes the BOSH connection. * @param {number} wait - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * Other settings will require tweaks to the Strophe.TIMEOUT value. * @param {number} hold - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {string} route */ _connect(wait: number, hold: number, route: string): void; /** * Attach to an already created and authenticated BOSH session. * * This function is provided to allow Strophe to attach to BOSH * sessions which have been created externally, perhaps by a Web * application. This is often used to support auto-login type features * without putting user credentials into the page. * * @param {string} jid - The full JID that is bound by the session. * @param {string} sid - The SID of the BOSH session. * @param {number} rid - The current RID of the BOSH session. This RID * will be used by the next request. * @param {Function} callback The connect callback function. * @param {number} wait - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * Other settings will require tweaks to the Strophe.TIMEOUT value. * @param {number} hold - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {number} wind - The optional HTTBIND window value. This is the * allowed range of request ids that are valid. The default is 5. */ _attach(jid: string, sid: string, rid: number, callback: Function, wait: number, hold: number, wind: number): void; /** * Attempt to restore a cached BOSH session * * @param {string} jid - The full JID that is bound by the session. * This parameter is optional but recommended, specifically in cases * where prebinded BOSH sessions are used where it's important to know * that the right session is being restored. * @param {Function} callback The connect callback function. * @param {number} wait - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * Other settings will require tweaks to the Strophe.TIMEOUT value. * @param {number} hold - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {number} wind - The optional HTTBIND window value. This is the * allowed range of request ids that are valid. The default is 5. */ _restore(jid: string, callback: Function, wait: number, hold: number, wind: number): void; /** * _Private_ handler for the beforeunload event. * This handler is used to process the Bosh-part of the initial request. * @private */ private _cacheSession; /** * _Private_ handler for initial connection request. * This handler is used to process the Bosh-part of the initial request. * @param {Element} bodyWrap - The received stanza. */ _connect_cb(bodyWrap: Element): number; /** * _Private_ part of Connection.disconnect for Bosh * @param {Element|Builder} pres - This stanza will be sent before disconnecting. */ _disconnect(pres: Element | Builder): void; /** * _Private_ function to disconnect. * Resets the SID and RID. */ _doDisconnect(): void; /** * _Private_ function to check if the Request queue is empty. * @return {boolean} - True, if there are no Requests queued, False otherwise. */ _emptyQueue(): boolean; /** * _Private_ function to call error handlers registered for HTTP errors. * @private * @param {Request} req - The request that is changing readyState. */ private _callProtocolErrorHandlers; /** * _Private_ function to handle the error count. * * Requests are resent automatically until their error count reaches * 5. Each time an error is encountered, this function is called to * increment the count and disconnect if the count is too high. * @private * @param {number} reqStatus - The request status. */ private _hitError; /** * @callback connectionCallback * @param {Connection} connection */ /** * Called on stream start/restart when no stream:features * has been received and sends a blank poll request. * @param {connectionCallback} callback */ _no_auth_received(callback: (connection: Connection) => any): void; /** * _Private_ timeout handler for handling non-graceful disconnection. * Cancels all remaining Requests and clears the queue. */ _onDisconnectTimeout(): void; /** * _Private_ helper function that makes sure all pending requests are aborted. */ _abortAllRequests(): void; /** * _Private_ handler called by {@link Connection#_onIdle|Connection._onIdle()}. * Sends all queued Requests or polls with empty Request if there are none. */ _onIdle(): void; /** * _Private_ handler for {@link Request} state changes. * * This function is called when the XMLHttpRequest readyState changes. * It contains a lot of error handling logic for the many ways that * requests can fail, and calls the request callback when requests * succeed. * @private * * @param {Function} func - The handler for the request. * @param {Request} req - The request that is changing readyState. */ private _onRequestStateChange; /** * _Private_ function to process a request in the queue. * * This function takes requests off the queue and sends them and * restarts dead requests. * @private * * @param {number} i - The index of the request in the queue. */ private _processRequest; /** * _Private_ function to remove a request from the queue. * @private * @param {Request} req - The request to remove. */ private _removeRequest; /** * _Private_ function to restart a request that is presumed dead. * @private * * @param {number} i - The index of the request in the queue. */ private _restartRequest; /** * _Private_ function to get a stanza out of a request. * Tries to extract a stanza out of a Request Object. * When this fails the current connection will be disconnected. * * @param {Request} req - The Request. * @return {Element} - The stanza that was passed. */ _reqToData(req: Request): Element; /** * _Private_ function to send initial disconnect sequence. * * This is the first step in a graceful disconnect. It sends * the BOSH server a terminate body and includes an unavailable * presence if authentication has completed. * @private * @param {Element|Builder} [pres] */ private _sendTerminate; /** * _Private_ part of the Connection.send function for BOSH * Just triggers the RequestHandler to send the messages that are in the queue */ _send(): void; /** * Send an xmpp:restart stanza. */ _sendRestart(): void; /** * _Private_ function to throttle requests to the connection window. * * This function makes sure we don't send requests so fast that the * request ids overflow the connection window in the case that one * request died. * @private */ private _throttledRequestHandler; } import Request from './request.js'; import Builder from './builder.js'; //# sourceMappingURL=bosh.d.ts.mapstrophejs-3.1.0/src/types/builder.d.ts000066400000000000000000000161571472775321000177310ustar00rootroot00000000000000/** * Create a {@link Strophe.Builder} * This is an alias for `new Strophe.Builder(name, attrs)`. * @param {string} name - The root element name. * @param {Object.} [attrs] - The attributes for the root element in object notation. * @return {Builder} A new Strophe.Builder object. */ export function $build(name: string, attrs?: { [x: string]: string | number; }): Builder; /** * Create a {@link Strophe.Builder} with a `` element as the root. * @param {Object.} [attrs] - The element attributes in object notation. * @return {Builder} A new Strophe.Builder object. */ export function $msg(attrs?: { [x: string]: string; }): Builder; /** * Create a {@link Strophe.Builder} with an `` element as the root. * @param {Object.} [attrs] - The element attributes in object notation. * @return {Builder} A new Strophe.Builder object. */ export function $iq(attrs?: { [x: string]: string; }): Builder; /** * Create a {@link Strophe.Builder} with a `` element as the root. * @param {Object.} [attrs] - The element attributes in object notation. * @return {Builder} A new Strophe.Builder object. */ export function $pres(attrs?: { [x: string]: string; }): Builder; export default Builder; /** * This class provides an interface similar to JQuery but for building * DOM elements easily and rapidly. All the functions except for `toString()` * and tree() return the object, so calls can be chained. * * The corresponding DOM manipulations to get a similar fragment would be * a lot more tedious and probably involve several helper variables. * * Since adding children makes new operations operate on the child, up() * is provided to traverse up the tree. To add two children, do * > builder.c('child1', ...).up().c('child2', ...) * * The next operation on the Builder will be relative to the second child. * * @example * // Here's an example using the $iq() builder helper. * $iq({to: 'you', from: 'me', type: 'get', id: '1'}) * .c('query', {xmlns: 'strophe:example'}) * .c('example') * .toString() * * // The above generates this XML fragment * // * // * // * // * // */ declare class Builder { /** * Creates a new Builder object from an XML string. * @param {string} str * @returns {Builder} * @example const stanza = Builder.fromString(''); */ static fromString(str: string): Builder; /** * Render a DOM element and all descendants to a String. * @param {Element|Builder} elem - A DOM element. * @return {string} - The serialized element tree as a String. */ static serialize(elem: Element | Builder): string; /** * The attributes should be passed in object notation. * @param {string} name - The name of the root element. * @param {StanzaAttrs} [attrs] - The attributes for the root element in object notation. * @example const b = new Builder('message', {to: 'you', from: 'me'}); * @example const b = new Builder('messsage', {'xml:lang': 'en'}); */ constructor(name: string, attrs?: { [x: string]: string | number; }); buildTree(): Element; /** @return {Element} */ get nodeTree(): Element; /** @param {Element} el */ set node(el: Element); /** @return {Element} */ get node(): Element; /** * Return the DOM tree. * * This function returns the current DOM tree as an element object. This * is suitable for passing to functions like Strophe.Connection.send(). * * @return {Element} The DOM tree as a element object. */ tree(): Element; /** * Serialize the DOM tree to a String. * * This function returns a string serialization of the current DOM * tree. It is often used internally to pass data to a * Strophe.Request object. * * @return {string} The serialized DOM tree in a String. */ toString(): string; /** * Make the current parent element the new current element. * This function is often used after c() to traverse back up the tree. * * @example * // For example, to add two children to the same element * builder.c('child1', {}).up().c('child2', {}); * * @return {Builder} The Strophe.Builder object. */ up(): Builder; /** * Make the root element the new current element. * * When at a deeply nested element in the tree, this function can be used * to jump back to the root of the tree, instead of having to repeatedly * call up(). * * @return {Builder} The Strophe.Builder object. */ root(): Builder; /** * Add or modify attributes of the current element. * * The attributes should be passed in object notation. * This function does not move the current element pointer. * @param {Object.} moreattrs - The attributes to add/modify in object notation. * If an attribute is set to `null` or `undefined`, it will be removed. * @return {Builder} The Strophe.Builder object. */ attrs(moreattrs: { [x: string]: string | number; }): Builder; /** * Add a child to the current element and make it the new current * element. * * This function moves the current element pointer to the child, * unless text is provided. If you need to add another child, it * is necessary to use up() to go back to the parent in the tree. * * @param {string} name - The name of the child. * @param {Object.|string} [attrs] - The attributes of the child in object notation. * @param {string} [text] - The text to add to the child. * * @return {Builder} The Strophe.Builder object. */ c(name: string, attrs?: { [x: string]: string; } | string, text?: string): Builder; /** * Add a child to the current element and make it the new current * element. * * This function is the same as c() except that instead of using a * name and an attributes object to create the child it uses an * existing DOM element object. * * @param {Element} elem - A DOM element. * @return {Builder} The Strophe.Builder object. */ cnode(elem: Element): Builder; /** * Add a child text element. * * This *does not* make the child the new current element since there * are no children of text elements. * * @param {string} text - The text data to append to the current element. * @return {Builder} The Strophe.Builder object. */ t(text: string): Builder; /** * Replace current element contents with the HTML passed in. * * This *does not* make the child the new current element * * @param {string} html - The html to insert as contents of current element. * @return {Builder} The Strophe.Builder object. */ h(html: string): Builder; #private; } //# sourceMappingURL=builder.d.ts.mapstrophejs-3.1.0/src/types/connection.d.ts000066400000000000000000001150261472775321000204350ustar00rootroot00000000000000export default Connection; export type SASLMechanism = import("./sasl.js").default; export type Request = import("./request.js").default; export type ConnectionOptions = { /** * Allows you to pass in cookies that will be included in HTTP requests. * Relevant to both the BOSH and Websocket transports. * * The passed in value must be a map of cookie names and string values. * * > { "myCookie": { * > "value": "1234", * > "domain": ".example.org", * > "path": "/", * > "expires": expirationDate * > } * > } * * Note that cookies can't be set in this way for domains other than the one * that's hosting Strophe (i.e. cross-domain). * Those cookies need to be set under those domains, for example they can be * set server-side by making a XHR call to that domain to ask it to set any * necessary cookies. */ cookies?: { [x: string]: string; } | { [x: string]: { [x: string]: string; }; }; /** * Allows you to specify the SASL authentication mechanisms that this * instance of Connection (and therefore your XMPP client) will support. * * The value must be an array of objects with {@link SASLMechanism}prototypes. * * If nothing is specified, then the following mechanisms (and their * priorities) are registered: * * Mechanism Priority * ------------------------ * SCRAM-SHA-512 72 * SCRAM-SHA-384 71 * SCRAM-SHA-256 70 * SCRAM-SHA-1 60 * PLAIN 50 * OAUTHBEARER 40 * X-OAUTH2 30 * ANONYMOUS 20 * EXTERNAL 10 */ mechanisms?: SASLMechanism[]; /** * If `explicitResourceBinding` is set to `true`, then the XMPP client * needs to explicitly call {@link Connection.bind} once the XMPP * server has advertised the `urn:ietf:propertys:xml:ns:xmpp-bind` feature. * * Making this step explicit allows client authors to first finish other * stream related tasks, such as setting up an XEP-0198 Stream Management * session, before binding the JID resource for this session. */ explicitResourceBinding?: boolean; /** * _Note: This option is only relevant to Websocket connections, and not BOSH_ * * If you want to connect to the current host with a WebSocket connection you * can tell Strophe to use WebSockets through the "protocol" option. * Valid values are `ws` for WebSocket and `wss` for Secure WebSocket. * So to connect to "wss://CURRENT_HOSTNAME/xmpp-websocket" you would call * * const conn = new Strophe.Connection( * "/xmpp-websocket/", * {protocol: "wss"} * ); * * Note that relative URLs _NOT_ starting with a "/" will also include the path * of the current site. * * Also because downgrading security is not permitted by browsers, when using * relative URLs both BOSH and WebSocket connections will use their secure * variants if the current connection to the site is also secure (https). */ protocol?: "ws" | "wss"; /** * _Note: This option is only relevant to Websocket connections, and not BOSH_ * * Set this option to URL from where the shared worker script should be loaded. * * To run the websocket connection inside a shared worker. * This allows you to share a single websocket-based connection between * multiple Connection instances, for example one per browser tab. * * The script to use is the one in `src/shared-connection-worker.js`. */ worker?: string; /** * Used to control whether BOSH HTTP requests will be made synchronously or not. * The default behaviour is asynchronous. If you want to make requests * synchronous, make "sync" evaluate to true. * * > const conn = new Strophe.Connection("/http-bind/", {sync: true}); * * You can also toggle this on an already established connection. * * > conn.options.sync = true; */ sync?: boolean; /** * Used to provide custom HTTP headers to be included in the BOSH HTTP requests. */ customHeaders?: string[]; /** * Used to instruct Strophe to maintain the current BOSH session across * interruptions such as webpage reloads. * * It will do this by caching the sessions tokens in sessionStorage, and when * "restore" is called it will check whether there are cached tokens with * which it can resume an existing session. */ keepalive?: boolean; /** * Used to indicate wether cookies should be included in HTTP requests (by default * they're not). * Set this value to `true` if you are connecting to a BOSH service * and for some reason need to send cookies to it. * In order for this to work cross-domain, the server must also enable * credentials by setting the `Access-Control-Allow-Credentials` response header * to "true". For most usecases however this setting should be false (which * is the default). * Additionally, when using `Access-Control-Allow-Credentials`, the * `Access-Control-Allow-Origin` header can't be set to the wildcard "*", but * instead must be restricted to actual domains. */ withCredentials?: boolean; /** * Used to change the default Content-Type, which is "text/xml; charset=utf-8". * Can be useful to reduce the amount of CORS preflight requests that are sent * to the server. */ contentType?: string; }; /** * **XMPP Connection manager** * * This class is the main part of Strophe. It manages a BOSH or websocket * connection to an XMPP server and dispatches events to the user callbacks * as data arrives. * * It supports various authentication mechanisms (e.g. SASL PLAIN, SASL SCRAM), * and more can be added via * {@link Connection#registerSASLMechanisms|registerSASLMechanisms()}. * * After creating a Connection object, the user will typically * call {@link Connection#connect|connect()} with a user supplied callback * to handle connection level events like authentication failure, * disconnection, or connection complete. * * The user will also have several event handlers defined by using * {@link Connection#addHandler|addHandler()} and * {@link Connection#addTimedHandler|addTimedHandler()}. * These will allow the user code to respond to interesting stanzas or do * something periodically with the connection. These handlers will be active * once authentication is finished. * * To send data to the connection, use {@link Connection#send|send()}. * * @memberof Strophe */ declare class Connection { /** * Extends the Connection object with the given plugin. * @param {string} name - The name of the extension. * @param {Object} ptype - The plugin's prototype. */ static addConnectionPlugin(name: string, ptype: Object): void; /** * @typedef {Object.} Cookie * @typedef {Cookie|Object.} Cookies */ /** * Create and initialize a {@link Connection} object. * * The transport-protocol for this connection will be chosen automatically * based on the given service parameter. URLs starting with "ws://" or * "wss://" will use WebSockets, URLs starting with "http://", "https://" * or without a protocol will use [BOSH](https://xmpp.org/extensions/xep-0124.html). * * To make Strophe connect to the current host you can leave out the protocol * and host part and just pass the path: * * const conn = new Strophe.Connection("/http-bind/"); * * @param {string} service - The BOSH or WebSocket service URL. * @param {ConnectionOptions} options - A object containing configuration options */ constructor(service: string, options?: ConnectionOptions); service: string; options: ConnectionOptions; jid: string; domain: string; features: Element; /** * @typedef {Object.} SASLData * @property {Object} [SASLData.keys] */ /** @type {SASLData} */ _sasl_data: { [x: string]: any; }; do_bind: boolean; do_session: boolean; /** @type {Object.} */ mechanisms: { [x: string]: import("./sasl.js").default; }; /** @type {TimedHandler[]} */ timedHandlers: TimedHandler[]; /** @type {Handler[]} */ handlers: Handler[]; /** @type {TimedHandler[]} */ removeTimeds: TimedHandler[]; /** @type {Handler[]} */ removeHandlers: Handler[]; /** @type {TimedHandler[]} */ addTimeds: TimedHandler[]; /** @type {Handler[]} */ addHandlers: Handler[]; protocolErrorHandlers: { /** @type {Object.} */ HTTP: { [x: number]: Function; }; /** @type {Object.} */ websocket: { [x: number]: Function; }; }; _idleTimeout: NodeJS.Timeout; _disconnectTimeout: TimedHandler; authenticated: boolean; connected: boolean; disconnecting: boolean; do_authentication: boolean; paused: boolean; restored: boolean; /** @type {(Element|'restart')[]} */ _data: (Element | "restart")[]; _uniqueId: number; _sasl_success_handler: Handler; _sasl_failure_handler: Handler; _sasl_challenge_handler: Handler; maxRetries: number; iqFallbackHandler: Handler; /** * Select protocal based on this.options or this.service */ setProtocol(): void; _proto: Bosh | Websocket | WorkerWebsocket; /** * Reset the connection. * * This function should be called after a connection is disconnected * before that connection is reused. */ reset(): void; /** @type {Request[]} */ _requests: Request[]; /** * Pause the request manager. * * This will prevent Strophe from sending any more requests to the * server. This is very useful for temporarily pausing * BOSH-Connections while a lot of send() calls are happening quickly. * This causes Strophe to send the data in a single request, saving * many request trips. */ pause(): void; /** * Resume the request manager. * * This resumes after pause() has been called. */ resume(): void; /** * Generate a unique ID for use in elements. * * All stanzas are required to have unique id attributes. This * function makes creating these easy. Each connection instance has * a counter which starts from zero, and the value of this counter * plus a colon followed by the suffix becomes the unique id. If no * suffix is supplied, the counter is used as the unique id. * * Suffixes are used to make debugging easier when reading the stream * data, and their use is recommended. The counter resets to 0 for * every new connection for the same reason. For connections to the * same server that authenticate the same way, all the ids should be * the same, which makes it easy to see changes. This is useful for * automated testing as well. * * @param {string} suffix - A optional suffix to append to the id. * @returns {string} A unique string to be used for the id attribute. */ getUniqueId(suffix: string): string; /** * Register a handler function for when a protocol (websocker or HTTP) * error occurs. * * NOTE: Currently only HTTP errors for BOSH requests are handled. * Patches that handle websocket errors would be very welcome. * * @example * function onError(err_code){ * //do stuff * } * * const conn = Strophe.connect('http://example.com/http-bind'); * conn.addProtocolErrorHandler('HTTP', 500, onError); * // Triggers HTTP 500 error and onError handler will be called * conn.connect('user_jid@incorrect_jabber_host', 'secret', onConnect); * * @param {'HTTP'|'websocket'} protocol - 'HTTP' or 'websocket' * @param {number} status_code - Error status code (e.g 500, 400 or 404) * @param {Function} callback - Function that will fire on Http error */ addProtocolErrorHandler(protocol: "HTTP" | "websocket", status_code: number, callback: Function): void; /** * @typedef {Object} Password * @property {string} Password.name * @property {string} Password.ck * @property {string} Password.sk * @property {number} Password.iter * @property {string} Password.salt */ /** * Starts the connection process. * * As the connection process proceeds, the user supplied callback will * be triggered multiple times with status updates. The callback * should take two arguments - the status code and the error condition. * * The status code will be one of the values in the Strophe.Status * constants. The error condition will be one of the conditions * defined in RFC 3920 or the condition 'strophe-parsererror'. * * The Parameters _wait_, _hold_ and _route_ are optional and only relevant * for BOSH connections. Please see XEP 124 for a more detailed explanation * of the optional parameters. * * @param {string} jid - The user's JID. This may be a bare JID, * or a full JID. If a node is not supplied, SASL OAUTHBEARER or * SASL ANONYMOUS authentication will be attempted (OAUTHBEARER will * process the provided password value as an access token). * (String or Object) pass - The user's password, or an object containing * the users SCRAM client and server keys, in a fashion described as follows: * * { name: String, representing the hash used (eg. SHA-1), * salt: String, base64 encoded salt used to derive the client key, * iter: Int, the iteration count used to derive the client key, * ck: String, the base64 encoding of the SCRAM client key * sk: String, the base64 encoding of the SCRAM server key * } * @param {string|Password} pass - The user password * @param {Function} callback - The connect callback function. * @param {number} [wait] - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * @param {number} [hold] - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {string} [route] - The optional route value. * @param {string} [authcid] - The optional alternative authentication identity * (username) if intending to impersonate another user. * When using the SASL-EXTERNAL authentication mechanism, for example * with client certificates, then the authcid value is used to * determine whether an authorization JID (authzid) should be sent to * the server. The authzid should NOT be sent to the server if the * authzid and authcid are the same. So to prevent it from being sent * (for example when the JID is already contained in the client * certificate), set authcid to that same JID. See XEP-178 for more * details. * @param {number} [disconnection_timeout=3000] - The optional disconnection timeout * in milliseconds before _doDisconnect will be called. */ connect(jid: string, pass: string | { name: string; ck: string; sk: string; iter: number; salt: string; }, callback: Function, wait?: number, hold?: number, route?: string, authcid?: string, disconnection_timeout?: number): void; /** Authorization identity */ authzid: string; /** Authentication identity (User name) */ authcid: string; /** Authentication identity (User password) */ pass: string | { name: string; ck: string; sk: string; iter: number; salt: string; }; /** * The SASL SCRAM client and server keys. This variable will be populated with a non-null * object of the above described form after a successful SCRAM connection */ scram_keys: any; connect_callback: Function; disconnection_timeout: number; /** * Attach to an already created and authenticated BOSH session. * * This function is provided to allow Strophe to attach to BOSH * sessions which have been created externally, perhaps by a Web * application. This is often used to support auto-login type features * without putting user credentials into the page. * * @param {string|Function} jid - The full JID that is bound by the session. * @param {string} [sid] - The SID of the BOSH session. * @param {number} [rid] - The current RID of the BOSH session. This RID * will be used by the next request. * @param {Function} [callback] - The connect callback function. * @param {number} [wait] - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * Other settings will require tweaks to the Strophe.TIMEOUT value. * @param {number} [hold] - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {number} [wind] - The optional HTTBIND window value. This is the * allowed range of request ids that are valid. The default is 5. */ attach(jid: string | Function, sid?: string, rid?: number, callback?: Function, wait?: number, hold?: number, wind?: number): void; /** * Attempt to restore a cached BOSH session. * * This function is only useful in conjunction with providing the * "keepalive":true option when instantiating a new {@link Connection}. * * When "keepalive" is set to true, Strophe will cache the BOSH tokens * RID (Request ID) and SID (Session ID) and then when this function is * called, it will attempt to restore the session from those cached * tokens. * * This function must therefore be called instead of connect or attach. * * For an example on how to use it, please see examples/restore.js * * @param {string} jid - The user's JID. This may be a bare JID or a full JID. * @param {Function} callback - The connect callback function. * @param {number} [wait] - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. * @param {number} [hold] - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). * @param {number} [wind] - The optional HTTBIND window value. This is the * allowed range of request ids that are valid. The default is 5. */ restore(jid: string, callback: Function, wait?: number, hold?: number, wind?: number): void; /** * Checks whether sessionStorage and JSON are supported and whether we're * using BOSH. */ _sessionCachingSupported(): boolean; /** * User overrideable function that receives XML data coming into the * connection. * * The default function does nothing. User code can override this with * > Connection.xmlInput = function (elem) { * > (user code) * > }; * * Due to limitations of current Browsers' XML-Parsers the opening and closing * tag for WebSocket-Connoctions will be passed as selfclosing here. * * BOSH-Connections will have all stanzas wrapped in a tag. See * if you want to strip this tag. * * @param {Node|MessageEvent} elem - The XML data received by the connection. */ xmlInput(elem: Node | MessageEvent): void; /** * User overrideable function that receives XML data sent to the * connection. * * The default function does nothing. User code can override this with * > Connection.xmlOutput = function (elem) { * > (user code) * > }; * * Due to limitations of current Browsers' XML-Parsers the opening and closing * tag for WebSocket-Connoctions will be passed as selfclosing here. * * BOSH-Connections will have all stanzas wrapped in a tag. See * if you want to strip this tag. * * @param {Element} elem - The XMLdata sent by the connection. */ xmlOutput(elem: Element): void; /** * User overrideable function that receives raw data coming into the * connection. * * The default function does nothing. User code can override this with * > Connection.rawInput = function (data) { * > (user code) * > }; * * @param {string} data - The data received by the connection. */ rawInput(data: string): void; /** * User overrideable function that receives raw data sent to the * connection. * * The default function does nothing. User code can override this with * > Connection.rawOutput = function (data) { * > (user code) * > }; * * @param {string} data - The data sent by the connection. */ rawOutput(data: string): void; /** * User overrideable function that receives the new valid rid. * * The default function does nothing. User code can override this with * > Connection.nextValidRid = function (rid) { * > (user code) * > }; * * @param {number} rid - The next valid rid */ nextValidRid(rid: number): void; /** * Send a stanza. * * This function is called to push data onto the send queue to * go out over the wire. Whenever a request is sent to the BOSH * server, all pending data is sent and the queue is flushed. * * @param {Element|Builder|Element[]|Builder[]} stanza - The stanza to send */ send(stanza: Element | Builder | Element[] | Builder[]): void; /** * Immediately send any pending outgoing data. * * Normally send() queues outgoing data until the next idle period * (100ms), which optimizes network use in the common cases when * several send()s are called in succession. flush() can be used to * immediately send all pending data. */ flush(): void; /** * Helper function to send presence stanzas. The main benefit is for * sending presence stanzas for which you expect a responding presence * stanza with the same id (for example when leaving a chat room). * * @param {Element} stanza - The stanza to send. * @param {Function} [callback] - The callback function for a successful request. * @param {Function} [errback] - The callback function for a failed or timed * out request. On timeout, the stanza will be null. * @param {number} [timeout] - The time specified in milliseconds for a * timeout to occur. * @return {string} The id used to send the presence. */ sendPresence(stanza: Element, callback?: Function, errback?: Function, timeout?: number): string; /** * Helper function to send IQ stanzas. * * @param {Element|Builder} stanza - The stanza to send. * @param {Function} [callback] - The callback function for a successful request. * @param {Function} [errback] - The callback function for a failed or timed * out request. On timeout, the stanza will be null. * @param {number} [timeout] - The time specified in milliseconds for a * timeout to occur. * @return {string} The id used to send the IQ. */ sendIQ(stanza: Element | Builder, callback?: Function, errback?: Function, timeout?: number): string; /** * Queue outgoing data for later sending. Also ensures that the data * is a DOMElement. * @private * @param {Element} element */ private _queueData; /** * Send an xmpp:restart stanza. * @private */ private _sendRestart; /** * Add a timed handler to the connection. * * This function adds a timed handler. The provided handler will * be called every period milliseconds until it returns false, * the connection is terminated, or the handler is removed. Handlers * that wish to continue being invoked should return true. * * Because of method binding it is necessary to save the result of * this function if you wish to remove a handler with * deleteTimedHandler(). * * Note that user handlers are not active until authentication is * successful. * * @param {number} period - The period of the handler. * @param {Function} handler - The callback function. * @return {TimedHandler} A reference to the handler that can be used to remove it. */ addTimedHandler(period: number, handler: Function): TimedHandler; /** * Delete a timed handler for a connection. * * This function removes a timed handler from the connection. The * handRef parameter is *not* the function passed to addTimedHandler(), * but is the reference returned from addTimedHandler(). * @param {TimedHandler} handRef - The handler reference. */ deleteTimedHandler(handRef: TimedHandler): void; /** * @typedef {Object} HandlerOptions * @property {boolean} [HandlerOptions.matchBareFromJid] * @property {boolean} [HandlerOptions.ignoreNamespaceFragment] */ /** * Add a stanza handler for the connection. * * This function adds a stanza handler to the connection. The * handler callback will be called for any stanza that matches * the parameters. Note that if multiple parameters are supplied, * they must all match for the handler to be invoked. * * The handler will receive the stanza that triggered it as its argument. * *The handler should return true if it is to be invoked again; * returning false will remove the handler after it returns.* * * As a convenience, the ns parameters applies to the top level element * and also any of its immediate children. This is primarily to make * matching /iq/query elements easy. * * ### Options * * With the options argument, you can specify boolean flags that affect how * matches are being done. * * Currently two flags exist: * * * *matchBareFromJid*: * When set to true, the from parameter and the * from attribute on the stanza will be matched as bare JIDs instead * of full JIDs. To use this, pass {matchBareFromJid: true} as the * value of options. The default value for matchBareFromJid is false. * * * *ignoreNamespaceFragment*: * When set to true, a fragment specified on the stanza's namespace * URL will be ignored when it's matched with the one configured for * the handler. * * This means that if you register like this: * * > connection.addHandler( * > handler, * > 'http://jabber.org/protocol/muc', * > null, null, null, null, * > {'ignoreNamespaceFragment': true} * > ); * * Then a stanza with XML namespace of * 'http://jabber.org/protocol/muc#user' will also be matched. If * 'ignoreNamespaceFragment' is false, then only stanzas with * 'http://jabber.org/protocol/muc' will be matched. * * ### Deleting the handler * * The return value should be saved if you wish to remove the handler * with `deleteHandler()`. * * @param {Function} handler - The user callback. * @param {string} ns - The namespace to match. * @param {string} name - The stanza name to match. * @param {string|string[]} type - The stanza type (or types if an array) to match. * @param {string} [id] - The stanza id attribute to match. * @param {string} [from] - The stanza from attribute to match. * @param {HandlerOptions} [options] - The handler options * @return {Handler} A reference to the handler that can be used to remove it. */ addHandler(handler: Function, ns: string, name: string, type: string | string[], id?: string, from?: string, options?: { matchBareFromJid?: boolean; ignoreNamespaceFragment?: boolean; }): Handler; /** * Delete a stanza handler for a connection. * * This function removes a stanza handler from the connection. The * handRef parameter is *not* the function passed to addHandler(), * but is the reference returned from addHandler(). * * @param {Handler} handRef - The handler reference. */ deleteHandler(handRef: Handler): void; /** * Register the SASL mechanisms which will be supported by this instance of * Connection (i.e. which this XMPP client will support). * @param {SASLMechanism[]} mechanisms - Array of objects with SASLMechanism prototypes */ registerSASLMechanisms(mechanisms: SASLMechanism[]): void; /** * Register a single SASL mechanism, to be supported by this client. * @param {any} Mechanism - Object with a Strophe.SASLMechanism prototype */ registerSASLMechanism(Mechanism: any): void; /** * Start the graceful disconnection process. * * This function starts the disconnection process. This process starts * by sending unavailable presence and sending BOSH body of type * terminate. A timeout handler makes sure that disconnection happens * even if the BOSH server does not respond. * If the Connection object isn't connected, at least tries to abort all pending requests * so the connection object won't generate successful requests (which were already opened). * * The user supplied connection callback will be notified of the * progress as this process happens. * * @param {string} [reason] - The reason the disconnect is occuring. */ disconnect(reason?: string): void; /** * _Private_ helper function that makes sure plugins and the user's * callback are notified of connection status changes. * @param {number} status - the new connection status, one of the values * in Strophe.Status * @param {string|null} [condition] - the error condition * @param {Element} [elem] - The triggering stanza. */ _changeConnectStatus(status: number, condition?: string | null, elem?: Element): void; /** * _Private_ function to disconnect. * * This is the last piece of the disconnection logic. This resets the * connection and alerts the user's connection callback. * @param {string|null} [condition] - the error condition */ _doDisconnect(condition?: string | null): void; /** * _Private_ handler to processes incoming data from the the connection. * * Except for _connect_cb handling the initial connection request, * this function handles the incoming data for all requests. This * function also fires stanza handlers that match each incoming * stanza. * @param {Element | Request} req - The request that has data ready. * @param {string} [raw] - The stanza as raw string. */ _dataRecv(req: Element | Request, raw?: string): void; /** * @callback connectionCallback * @param {Connection} connection */ /** * _Private_ handler for initial connection request. * * This handler is used to process the initial connection request * response from the BOSH server. It is used to set up authentication * handlers and start the authentication process. * * SASL authentication will be attempted if available, otherwise * the code will fall back to legacy authentication. * * @param {Element | Request} req - The current request. * @param {connectionCallback} _callback - low level (xmpp) connect callback function. * Useful for plugins with their own xmpp connect callback (when they * want to do something special). * @param {string} [raw] - The stanza as raw string. */ _connect_cb(req: Element | Request, _callback: (connection: Connection) => any, raw?: string): void; /** * Sorts an array of objects with prototype SASLMechanism according to * their priorities. * @param {SASLMechanism[]} mechanisms - Array of SASL mechanisms. */ sortMechanismsByPriority(mechanisms: SASLMechanism[]): import("./sasl.js").default[]; /** * Set up authentication * * Continues the initial connection request by setting up authentication * handlers and starting the authentication process. * * SASL authentication will be attempted if available, otherwise * the code will fall back to legacy authentication. * * @param {SASLMechanism[]} matched - Array of SASL mechanisms supported. */ authenticate(matched: SASLMechanism[]): void; /** * Iterate through an array of SASL mechanisms and attempt authentication * with the highest priority (enabled) mechanism. * * @private * @param {SASLMechanism[]} mechanisms - Array of SASL mechanisms. * @return {Boolean} mechanism_found - true or false, depending on whether a * valid SASL mechanism was found with which authentication could be started. */ private _attemptSASLAuth; _sasl_mechanism: import("./sasl.js").default; /** * _Private_ handler for the SASL challenge * @private * @param {Element} elem */ private _sasl_challenge_cb; /** * Attempt legacy (i.e. non-SASL) authentication. * @private */ private _attemptLegacyAuth; /** * _Private_ handler for legacy authentication. * * This handler is called in response to the initial * for legacy authentication. It builds an authentication and * sends it, creating a handler (calling back to _auth2_cb()) to * handle the result * @private * @return {false} `false` to remove the handler. */ private _onLegacyAuthIQResult; /** * _Private_ handler for succesful SASL authentication. * @private * @param {Element} elem - The matching stanza. * @return {false} `false` to remove the handler. */ private _sasl_success_cb; /** * @private * @param {Element} elem - The matching stanza. * @return {false} `false` to remove the handler. */ private _onStreamFeaturesAfterSASL; /** * Sends an IQ to the XMPP server to bind a JID resource for this session. * * https://tools.ietf.org/html/rfc6120#section-7.5 * * If `explicitResourceBinding` was set to a truthy value in the options * passed to the Connection constructor, then this function needs * to be called explicitly by the client author. * * Otherwise it'll be called automatically as soon as the XMPP server * advertises the "urn:ietf:params:xml:ns:xmpp-bind" stream feature. */ bind(): void; /** * _Private_ handler for binding result and session start. * @private * @param {Element} elem - The matching stanza. * @return {false} `false` to remove the handler. */ private _onResourceBindResultIQ; /** * Send IQ request to establish a session with the XMPP server. * * See https://xmpp.org/rfcs/rfc3921.html#session * * Note: The protocol for session establishment has been determined as * unnecessary and removed in RFC-6121. * @private */ private _establishSession; /** * _Private_ handler for the server's IQ response to a client's session * request. * * This sets Connection.authenticated to true on success, which * starts the processing of user handlers. * * See https://xmpp.org/rfcs/rfc3921.html#session * * Note: The protocol for session establishment has been determined as * unnecessary and removed in RFC-6121. * @private * @param {Element} elem - The matching stanza. * @return {false} `false` to remove the handler. */ private _onSessionResultIQ; /** * _Private_ handler for SASL authentication failure. * @param {Element} [elem] - The matching stanza. * @return {false} `false` to remove the handler. */ _sasl_failure_cb(elem?: Element): false; /** * _Private_ handler to finish legacy authentication. * * This handler is called when the result from the jabber:iq:auth * stanza is returned. * @private * @param {Element} elem - The stanza that triggered the callback. * @return {false} `false` to remove the handler. */ private _auth2_cb; /** * _Private_ function to add a system level timed handler. * * This function is used to add a TimedHandler for the * library code. System timed handlers are allowed to run before * authentication is complete. * @param {number} period - The period of the handler. * @param {Function} handler - The callback function. */ _addSysTimedHandler(period: number, handler: Function): TimedHandler; /** * _Private_ function to add a system level stanza handler. * * This function is used to add a Handler for the * library code. System stanza handlers are allowed to run before * authentication is complete. * @param {Function} handler - The callback function. * @param {string} ns - The namespace to match. * @param {string} name - The stanza name to match. * @param {string} type - The stanza type attribute to match. * @param {string} id - The stanza id attribute to match. */ _addSysHandler(handler: Function, ns: string, name: string, type: string, id: string): Handler; /** * _Private_ timeout handler for handling non-graceful disconnection. * * If the graceful disconnect process does not complete within the * time allotted, this handler finishes the disconnect anyway. * @return {false} `false` to remove the handler. */ _onDisconnectTimeout(): false; /** * _Private_ handler to process events during idle cycle. * * This handler is called every 100ms to fire timed handlers that * are ready and keep poll requests going. */ _onIdle(): void; } import TimedHandler from './timed-handler.js'; import Handler from './handler.js'; import Bosh from './bosh.js'; import Websocket from './websocket.js'; import WorkerWebsocket from './worker-websocket.js'; import Builder from './builder.js'; //# sourceMappingURL=connection.d.ts.mapstrophejs-3.1.0/src/types/constants.d.ts000066400000000000000000000116131472775321000203070ustar00rootroot00000000000000/** * Common namespace constants from the XMPP RFCs and XEPs. */ export type NS = { /** * - HTTP BIND namespace from XEP 124. */ HTTPBIND: string; /** * - BOSH namespace from XEP 206. */ BOSH: string; /** * - Main XMPP client namespace. */ CLIENT: string; /** * - Legacy authentication namespace. */ AUTH: string; /** * - Roster operations namespace. */ ROSTER: string; /** * - Profile namespace. */ PROFILE: string; /** * - Service discovery info namespace from XEP 30. */ DISCO_INFO: string; /** * - Service discovery items namespace from XEP 30. */ DISCO_ITEMS: string; /** * - Multi-User Chat namespace from XEP 45. */ MUC: string; /** * - XMPP SASL namespace from RFC 3920. */ SASL: string; /** * - XMPP Streams namespace from RFC 3920. */ STREAM: string; /** * - XMPP Binding namespace from RFC 3920 and RFC 6120. */ BIND: string; /** * - XMPP Session namespace from RFC 3920. */ SESSION: string; /** * - XHTML-IM namespace from XEP 71. */ XHTML_IM: string; /** * - XHTML body namespace from XEP 71. */ XHTML: string; STANZAS: string; FRAMING: string; }; export namespace NS { let HTTPBIND: string; let BOSH: string; let CLIENT: string; let SERVER: string; let AUTH: string; let ROSTER: string; let PROFILE: string; let DISCO_INFO: string; let DISCO_ITEMS: string; let MUC: string; let SASL: string; let STREAM: string; let FRAMING: string; let BIND: string; let SESSION: string; let VERSION: string; let STANZAS: string; let XHTML_IM: string; let XHTML: string; } export const PARSE_ERROR_NS: "http://www.w3.org/1999/xhtml"; export namespace XHTML { let tags: string[]; namespace attributes { let a: string[]; let blockquote: string[]; let br: never[]; let cite: string[]; let em: never[]; let img: string[]; let li: string[]; let ol: string[]; let p: string[]; let span: string[]; let strong: never[]; let ul: string[]; let body: never[]; } let css: string[]; } /** * Connection status constants for use by the connection handler * callback. */ export type Status = { /** * - An error has occurred */ ERROR: connstatus; /** * - The connection is currently being made */ CONNECTING: connstatus; /** * - The connection attempt failed */ CONNFAIL: connstatus; /** * - The connection is authenticating */ AUTHENTICATING: connstatus; /** * - The authentication attempt failed */ AUTHFAIL: connstatus; /** * - The connection has succeeded */ CONNECTED: connstatus; /** * - The connection has been terminated */ DISCONNECTED: connstatus; /** * - The connection is currently being terminated */ DISCONNECTING: connstatus; /** * - The connection has been attached */ ATTACHED: connstatus; /** * - The connection has been redirected */ REDIRECT: connstatus; /** * - The connection has timed out */ CONNTIMEOUT: connstatus; /** * - The JID resource needs to be bound for this session */ BINDREQUIRED: connstatus; /** * - Failed to attach to a pre-existing session */ ATTACHFAIL: connstatus; /** * - Not used by Strophe, but added for integrators */ RECONNECTING: connstatus; }; export namespace Status { let ERROR: number; let CONNECTING: number; let CONNFAIL: number; let AUTHENTICATING: number; let AUTHFAIL: number; let CONNECTED: number; let DISCONNECTED: number; let DISCONNECTING: number; let ATTACHED: number; let REDIRECT: number; let CONNTIMEOUT: number; let BINDREQUIRED: number; let ATTACHFAIL: number; let RECONNECTING: number; } export namespace ErrorCondition { let BAD_FORMAT: string; let CONFLICT: string; let MISSING_JID_NODE: string; let NO_AUTH_MECH: string; let UNKNOWN_REASON: string; } export namespace LOG_LEVELS { export let DEBUG: number; export let INFO: number; export let WARN: number; let ERROR_1: number; export { ERROR_1 as ERROR }; export let FATAL: number; } export namespace ElementType { let NORMAL: number; let TEXT: number; let CDATA: number; let FRAGMENT: number; } export type connstatus = number; /** * Logging level indicators. */ export type LogLevel = 0 | 1 | 2 | 3 | 4; /** * Logging level indicators. */ export type LogLevelName = "DEBUG" | "INFO" | "WARN" | "ERROR" | "FATAL"; /** * Logging level indicators. */ export type LogLevels = Record; //# sourceMappingURL=constants.d.ts.mapstrophejs-3.1.0/src/types/core.d.ts000066400000000000000000000045701472775321000172270ustar00rootroot00000000000000export default Strophe; declare namespace Strophe { export let VERSION: string; export let TIMEOUT: number; export let SECONDARY_TIMEOUT: number; export { shims }; export { SASLAnonymous }; export { SASLPlain }; export { SASLSHA1 }; export { SASLSHA256 }; export { SASLSHA384 }; export { SASLSHA512 }; export { SASLOAuthBearer }; export { SASLExternal }; export { SASLXOAuth2 }; export { Builder }; export { ElementType }; export { ErrorCondition }; export { LOG_LEVELS as LogLevel }; export let setLogLevel: (level: import("./constants.js").LogLevel) => void; export { NS }; export { SASLMechanism }; export { Status }; export { TimedHandler }; /** * This function is used to extend the current namespaces in * Strophe.NS. It takes a key and a value with the key being the * name of the new namespace, with its actual value. * @example: Strophe.addNamespace('PUBSUB', "http://jabber.org/protocol/pubsub"); * * @param {string} name - The name under which the namespace will be * referenced under Strophe.NS * @param {string} value - The actual namespace. */ export function addNamespace(name: string, value: string): void; export let _connectionPlugins: { [x: string]: Object; }; /** * Extends the Strophe.Connection object with the given plugin. * @param {string} name - The name of the extension. * @param {Object} ptype - The plugin's prototype. */ export function addConnectionPlugin(name: string, ptype: Object): void; } import * as shims from './shims.js'; import SASLAnonymous from './sasl-anon.js'; import SASLPlain from './sasl-plain.js'; import SASLSHA1 from './sasl-sha1.js'; import SASLSHA256 from './sasl-sha256.js'; import SASLSHA384 from './sasl-sha384.js'; import SASLSHA512 from './sasl-sha512.js'; import SASLOAuthBearer from './sasl-oauthbearer.js'; import SASLExternal from './sasl-external.js'; import SASLXOAuth2 from './sasl-xoauth2.js'; import Builder from './builder.js'; import { ElementType } from './constants.js'; import { ErrorCondition } from './constants.js'; import { LOG_LEVELS } from './constants.js'; import { NS } from './constants.js'; import SASLMechanism from './sasl.js'; import { Status } from './constants.js'; import TimedHandler from './timed-handler.js'; //# sourceMappingURL=core.d.ts.mapstrophejs-3.1.0/src/types/errors.d.ts000066400000000000000000000002411472775321000176020ustar00rootroot00000000000000export class SessionError extends Error { /** * @param {string} message */ constructor(message: string); } //# sourceMappingURL=errors.d.ts.mapstrophejs-3.1.0/src/types/handler.d.ts000066400000000000000000000060201472775321000177040ustar00rootroot00000000000000export default Handler; /** * _Private_ helper class for managing stanza handlers. * * A Handler encapsulates a user provided callback function to be * executed when matching stanzas are received by the connection. * Handlers can be either one-off or persistant depending on their * return value. Returning true will cause a Handler to remain active, and * returning false will remove the Handler. * * Users will not use Handler objects directly, but instead they * will use {@link Connection.addHandler} and * {@link Connection.deleteHandler}. */ declare class Handler { /** * @typedef {Object} HandlerOptions * @property {boolean} [HandlerOptions.matchBareFromJid] * @property {boolean} [HandlerOptions.ignoreNamespaceFragment] */ /** * Create and initialize a new Handler. * * @param {Function} handler - A function to be executed when the handler is run. * @param {string} ns - The namespace to match. * @param {string} name - The element name to match. * @param {string|string[]} type - The stanza type (or types if an array) to match. * @param {string} [id] - The element id attribute to match. * @param {string} [from] - The element from attribute to match. * @param {HandlerOptions} [options] - Handler options */ constructor(handler: Function, ns: string, name: string, type: string | string[], id?: string, from?: string, options?: { matchBareFromJid?: boolean; ignoreNamespaceFragment?: boolean; }); handler: Function; ns: string; name: string; type: string | string[]; id: string; options: { matchBareFromJid?: boolean; ignoreNamespaceFragment?: boolean; }; from: string; user: boolean; /** * Returns the XML namespace attribute on an element. * If `ignoreNamespaceFragment` was passed in for this handler, then the * URL fragment will be stripped. * @param {Element} elem - The XML element with the namespace. * @return {string} - The namespace, with optionally the fragment stripped. */ getNamespace(elem: Element): string; /** * Tests if a stanza element (or any of its children) matches the * namespace set for this Handler. * @param {Element} elem - The XML element to test. * @return {boolean} - true if the stanza matches and false otherwise. */ namespaceMatch(elem: Element): boolean; /** * Tests if a stanza matches the Handler. * @param {Element} elem - The XML element to test. * @return {boolean} - true if the stanza matches and false otherwise. */ isMatch(elem: Element): boolean; /** * Run the callback on a matching stanza. * @param {Element} elem - The DOM element that triggered the Handler. * @return {boolean} - A boolean indicating if the handler should remain active. */ run(elem: Element): boolean; /** * Get a String representation of the Handler object. * @return {string} */ toString(): string; } //# sourceMappingURL=handler.d.ts.mapstrophejs-3.1.0/src/types/index.d.ts000066400000000000000000000211271472775321000174030ustar00rootroot00000000000000import Builder from './builder.js'; import { $build } from './builder.js'; import { $iq } from './builder.js'; import { $msg } from './builder.js'; import { $pres } from './builder.js'; /** * A container for all Strophe library functions. * * This object is a container for all the objects and constants * used in the library. It is not meant to be instantiated, but to * provide a namespace for library objects, constants, and functions. * * @namespace Strophe * @property {Handler} Handler * @property {Builder} Builder * @property {Request} Request Represents HTTP Requests made for a BOSH connection * @property {Bosh} Bosh Support for XMPP-over-HTTP via XEP-0124 (BOSH) * @property {Websocket} Websocket Support for XMPP over websocket * @property {WorkerWebsocket} WorkerWebsocket Support for XMPP over websocket in a shared worker * @property {number} TIMEOUT=1.1 Timeout multiplier. A waiting BOSH HTTP request * will be considered failed after Math.floor(TIMEOUT * wait) seconds have elapsed. * This defaults to 1.1, and with default wait, 66 seconds. * @property {number} SECONDARY_TIMEOUT=0.1 Secondary timeout multiplier. * In cases where Strophe can detect early failure, it will consider the request * failed if it doesn't return after `Math.floor(SECONDARY_TIMEOUT * wait)` * seconds have elapsed. This defaults to 0.1, and with default wait, 6 seconds. * @property {SASLAnonymous} SASLAnonymous SASL ANONYMOUS authentication. * @property {SASLPlain} SASLPlain SASL PLAIN authentication * @property {SASLSHA1} SASLSHA1 SASL SCRAM-SHA-1 authentication * @property {SASLSHA256} SASLSHA256 SASL SCRAM-SHA-256 authentication * @property {SASLSHA384} SASLSHA384 SASL SCRAM-SHA-384 authentication * @property {SASLSHA512} SASLSHA512 SASL SCRAM-SHA-512 authentication * @property {SASLOAuthBearer} SASLOAuthBearer SASL OAuth Bearer authentication * @property {SASLExternal} SASLExternal SASL EXTERNAL authentication * @property {SASLXOAuth2} SASLXOAuth2 SASL X-OAuth2 authentication * @property {Status} Status * @property {Object.} NS * @property {XHTML} XHTML */ export const Strophe: { shims: typeof shims; Request: typeof Request; Bosh: typeof Bosh; Websocket: typeof Websocket; WorkerWebsocket: typeof WorkerWebsocket; Connection: typeof Connection; Handler: typeof Handler; SASLAnonymous: typeof SASLAnonymous; SASLPlain: typeof SASLPlain; SASLSHA1: typeof SASLSHA1; SASLSHA256: typeof SASLSHA256; SASLSHA384: typeof SASLSHA384; SASLSHA512: typeof SASLSHA512; SASLOAuthBearer: typeof SASLOAuthBearer; SASLExternal: typeof SASLExternal; SASLXOAuth2: typeof SASLXOAuth2; Stanza: typeof Stanza; Builder: typeof Builder; ElementType: { NORMAL: number; TEXT: number; CDATA: number; FRAGMENT: number; }; ErrorCondition: { BAD_FORMAT: string; CONFLICT: string; MISSING_JID_NODE: string; NO_AUTH_MECH: string; UNKNOWN_REASON: string; }; LogLevel: { DEBUG: number; INFO: number; WARN: number; ERROR: number; FATAL: number; }; /** @type {Object.} */ NS: { [x: string]: string; }; SASLMechanism: typeof SASLMechanism; /** @type {Status} */ Status: Status; TimedHandler: typeof TimedHandler; XHTML: { validTag: typeof utils.validTag; validCSS: typeof utils.validCSS; validAttribute: typeof utils.validAttribute; tags: string[]; attributes: { a: string[]; blockquote: string[]; br: never[]; cite: string[]; em: never[]; img: string[]; li: string[]; ol: string[]; p: string[]; span: string[]; strong: never[]; ul: string[]; body: never[]; }; css: string[]; }; /** * Render a DOM element and all descendants to a String. * @method Strophe.serialize * @param {Element|Builder} elem - A DOM element. * @return {string} - The serialized element tree as a String. */ serialize(elem: Element | Builder): string; /** * @typedef {import('./constants').LogLevel} LogLevel * * Library consumers can use this function to set the log level of Strophe. * The default log level is Strophe.LogLevel.INFO. * @param {LogLevel} level * @example Strophe.setLogLevel(Strophe.LogLevel.DEBUG); */ setLogLevel(level: import("./constants.js").LogLevel): void; /** * This function is used to extend the current namespaces in * Strophe.NS. It takes a key and a value with the key being the * name of the new namespace, with its actual value. * @example: Strophe.addNamespace('PUBSUB', "http://jabber.org/protocol/pubsub"); * * @param {string} name - The name under which the namespace will be * referenced under Strophe.NS * @param {string} value - The actual namespace. */ addNamespace(name: string, value: string): void; /** * Extends the Strophe.Connection object with the given plugin. * @param {string} name - The name of the extension. * @param {Object} ptype - The plugin's prototype. */ addConnectionPlugin(name: string, ptype: Object): void; log(level: number, msg: string): void; debug(msg: string): void; info(msg: string): void; warn(msg: string): void; error(msg: string): void; fatal(msg: string): void; toElement(string: string, throwErrorIfInvalidNS?: boolean): Element; handleError(e: Error): void; utf16to8(str: string): string; xorArrayBuffers(x: ArrayBufferLike, y: ArrayBufferLike): ArrayBuffer; arrayBufToBase64(buffer: ArrayBufferLike): string; base64ToArrayBuf(str: string): ArrayBufferLike; stringToArrayBuf(str: string): ArrayBufferLike; addCookies(cookies: { [x: string]: string; } | { [x: string]: { [x: string]: string; }; }): void; xmlGenerator(): Document; xmlTextNode(text: string): Text; xmlHtmlNode(text: string): XMLDocument; getParserError(doc: XMLDocument): string | null; getFirstElementChild(el: XMLDocument): Element; xmlElement(name: string, attrs?: Array> | { [x: string]: string | number; } | string | number, text?: string | number): Element; validTag(tag: string): boolean; validAttribute(tag: string, attribute: string): boolean; validCSS(style: string): boolean; createHtml(node: Node): Node; copyElement(node: Node): Element | Text; xmlescape(text: string): string; xmlunescape(text: string): string; forEachChild(elem: Element, elemName: string, func: Function): void; isTagEqual(el: Element, name: string): boolean; getText(elem: Element): string; escapeNode(node: string): string; unescapeNode(node: string): string; getNodeFromJid(jid: string): string; getDomainFromJid(jid: string): string; getResourceFromJid(jid: string): string; getBareJidFromJid(jid: string): string; default: { utf16to8: typeof utils.utf16to8; xorArrayBuffers: typeof utils.xorArrayBuffers; arrayBufToBase64: typeof utils.arrayBufToBase64; base64ToArrayBuf: typeof utils.base64ToArrayBuf; stringToArrayBuf: typeof utils.stringToArrayBuf; addCookies: typeof utils.addCookies; }; /** @constant: VERSION */ VERSION: string; /** * @returns {number} */ TIMEOUT: number; /** * @returns {number} */ SECONDARY_TIMEOUT: number; }; import { Stanza } from './stanza.js'; import { stx } from './stanza.js'; export const toStanza: typeof Stanza.toElement; import Request from './request.js'; import * as shims from './shims.js'; import Bosh from './bosh.js'; import Websocket from './websocket.js'; import WorkerWebsocket from './worker-websocket.js'; import Connection from './connection.js'; import Handler from './handler.js'; import SASLAnonymous from './sasl-anon.js'; import SASLPlain from './sasl-plain.js'; import SASLSHA1 from './sasl-sha1.js'; import SASLSHA256 from './sasl-sha256.js'; import SASLSHA384 from './sasl-sha384.js'; import SASLSHA512 from './sasl-sha512.js'; import SASLOAuthBearer from './sasl-oauthbearer.js'; import SASLExternal from './sasl-external.js'; import SASLXOAuth2 from './sasl-xoauth2.js'; import SASLMechanism from './sasl.js'; import { Status } from './constants.js'; import TimedHandler from './timed-handler.js'; import * as utils from './utils.js'; export { Builder, $build, $iq, $msg, $pres, Stanza, stx, Request }; //# sourceMappingURL=index.d.ts.mapstrophejs-3.1.0/src/types/log.d.ts000066400000000000000000000042401472775321000170520ustar00rootroot00000000000000export default log; export type LogLevel = import("./constants").LogLevel; declare namespace log { /** * Library consumers can use this function to set the log level of Strophe. * The default log level is Strophe.LogLevel.INFO. * @param {LogLevel} level * @example Strophe.setLogLevel(Strophe.LogLevel.DEBUG); */ function setLogLevel(level: LogLevel): void; /** * * Please note that data sent and received over the wire is logged * via {@link Strophe.Connection#rawInput|Strophe.Connection.rawInput()} * and {@link Strophe.Connection#rawOutput|Strophe.Connection.rawOutput()}. * * The different levels and their meanings are * * DEBUG - Messages useful for debugging purposes. * INFO - Informational messages. This is mostly information like * 'disconnect was called' or 'SASL auth succeeded'. * WARN - Warnings about potential problems. This is mostly used * to report transient connection errors like request timeouts. * ERROR - Some error occurred. * FATAL - A non-recoverable fatal error occurred. * * @param {number} level - The log level of the log message. * This will be one of the values in Strophe.LOG_LEVELS. * @param {string} msg - The log message. */ function log(level: number, msg: string): void; /** * Log a message at the Strophe.LOG_LEVELS.DEBUG level. * @param {string} msg - The log message. */ function debug(msg: string): void; /** * Log a message at the Strophe.LOG_LEVELS.INFO level. * @param {string} msg - The log message. */ function info(msg: string): void; /** * Log a message at the Strophe.LOG_LEVELS.WARN level. * @param {string} msg - The log message. */ function warn(msg: string): void; /** * Log a message at the Strophe.LOG_LEVELS.ERROR level. * @param {string} msg - The log message. */ function error(msg: string): void; /** * Log a message at the Strophe.LOG_LEVELS.FATAL level. * @param {string} msg - The log message. */ function fatal(msg: string): void; } //# sourceMappingURL=log.d.ts.mapstrophejs-3.1.0/src/types/request.d.ts000066400000000000000000000034251472775321000177650ustar00rootroot00000000000000export default Request; /** * Helper class that provides a cross implementation abstraction * for a BOSH related XMLHttpRequest. * * The Request class is used internally to encapsulate BOSH request * information. It is not meant to be used from user's code. * * @property {number} id * @property {number} sends * @property {XMLHttpRequest} xhr */ declare class Request { /** * Create and initialize a new Request object. * * @param {Element} elem - The XML data to be sent in the request. * @param {Function} func - The function that will be called when the * XMLHttpRequest readyState changes. * @param {number} rid - The BOSH rid attribute associated with this request. * @param {number} [sends=0] - The number of times this same request has been sent. */ constructor(elem: Element, func: Function, rid: number, sends?: number); id: number; xmlData: Element; data: string; origFunc: Function; func: Function; rid: number; date: number; sends: number; abort: boolean; dead: any; age: () => number; timeDead: () => number; xhr: XMLHttpRequest; /** * Get a response from the underlying XMLHttpRequest. * This function attempts to get a response from the request and checks * for errors. * @throws "parsererror" - A parser error occured. * @throws "bad-format" - The entity has sent XML that cannot be processed. * @return {Element} - The DOM element tree of the response. */ getResponse(): Element; /** * _Private_ helper function to create XMLHttpRequests. * This function creates XMLHttpRequests across all implementations. * @private * @return {XMLHttpRequest} */ private _newXHR; } //# sourceMappingURL=request.d.ts.mapstrophejs-3.1.0/src/types/sasl-anon.d.ts000066400000000000000000000003361472775321000201660ustar00rootroot00000000000000export default SASLAnonymous; export type Connection = import("./connection.js").default; declare class SASLAnonymous extends SASLMechanism { } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-anon.d.ts.mapstrophejs-3.1.0/src/types/sasl-external.d.ts000066400000000000000000000005071472775321000210550ustar00rootroot00000000000000export default SASLExternal; export type Connection = import("./connection.js").default; declare class SASLExternal extends SASLMechanism { /** * @param {Connection} connection */ onChallenge(connection: Connection): string; } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-external.d.ts.mapstrophejs-3.1.0/src/types/sasl-oauthbearer.d.ts000066400000000000000000000005201472775321000215270ustar00rootroot00000000000000export default SASLOAuthBearer; export type Connection = import("./connection.js").default; declare class SASLOAuthBearer extends SASLMechanism { /** * @param {Connection} connection */ onChallenge(connection: Connection): string; } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-oauthbearer.d.ts.mapstrophejs-3.1.0/src/types/sasl-plain.d.ts000066400000000000000000000004761472775321000203430ustar00rootroot00000000000000export default SASLPlain; export type Connection = import("./connection.js").default; declare class SASLPlain extends SASLMechanism { /** * @param {Connection} connection */ onChallenge(connection: Connection): string; } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-plain.d.ts.mapstrophejs-3.1.0/src/types/sasl-sha1.d.ts000066400000000000000000000011441472775321000200650ustar00rootroot00000000000000export default SASLSHA1; export type Connection = import("./connection.js").default; declare class SASLSHA1 extends SASLMechanism { /** * @param {Connection} connection * @param {string} [challenge] * @return {Promise} Mechanism response. */ onChallenge(connection: Connection, challenge?: string): Promise; /** * @param {Connection} connection * @param {string} [test_cnonce] */ clientChallenge(connection: Connection, test_cnonce?: string): string; } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-sha1.d.ts.mapstrophejs-3.1.0/src/types/sasl-sha256.d.ts000066400000000000000000000010571472775321000202440ustar00rootroot00000000000000export default SASLSHA256; export type Connection = import("./connection.js").default; declare class SASLSHA256 extends SASLMechanism { /** * @param {Connection} connection * @param {string} [challenge] */ onChallenge(connection: Connection, challenge?: string): Promise; /** * @param {Connection} connection * @param {string} [test_cnonce] */ clientChallenge(connection: Connection, test_cnonce?: string): string; } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-sha256.d.ts.mapstrophejs-3.1.0/src/types/sasl-sha384.d.ts000066400000000000000000000010571472775321000202460ustar00rootroot00000000000000export default SASLSHA384; export type Connection = import("./connection.js").default; declare class SASLSHA384 extends SASLMechanism { /** * @param {Connection} connection * @param {string} [challenge] */ onChallenge(connection: Connection, challenge?: string): Promise; /** * @param {Connection} connection * @param {string} [test_cnonce] */ clientChallenge(connection: Connection, test_cnonce?: string): string; } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-sha384.d.ts.mapstrophejs-3.1.0/src/types/sasl-sha512.d.ts000066400000000000000000000010571472775321000202370ustar00rootroot00000000000000export default SASLSHA512; export type Connection = import("./connection.js").default; declare class SASLSHA512 extends SASLMechanism { /** * @param {Connection} connection * @param {string} [challenge] */ onChallenge(connection: Connection, challenge?: string): Promise; /** * @param {Connection} connection * @param {string} [test_cnonce] */ clientChallenge(connection: Connection, test_cnonce?: string): string; } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-sha512.d.ts.mapstrophejs-3.1.0/src/types/sasl-xoauth2.d.ts000066400000000000000000000006071472775321000206260ustar00rootroot00000000000000export default SASLXOAuth2; export type Connection = import("./connection.js").default; /** * @typedef {import("./connection.js").default} Connection */ declare class SASLXOAuth2 extends SASLMechanism { /** * @param {Connection} connection */ onChallenge(connection: Connection): string; } import SASLMechanism from './sasl.js'; //# sourceMappingURL=sasl-xoauth2.d.ts.mapstrophejs-3.1.0/src/types/sasl.d.ts000066400000000000000000000072371472775321000172440ustar00rootroot00000000000000export default SASLMechanism; export type Connection = import("./connection.js").default; /** * @typedef {import("./connection.js").default} Connection */ /** * Encapsulates an SASL authentication mechanism. * * User code may override the priority for each mechanism or disable it completely. * See for information about changing priority and for informatian on * how to disable a mechanism. * * By default, all mechanisms are enabled and t_he priorities are * * SCRAM-SHA-512 - 72 * SCRAM-SHA-384 - 71 * SCRAM-SHA-256 - 70 * SCRAM-SHA-1 - 60 * PLAIN - 50 * OAUTHBEARER - 40 * X-OAUTH2 - 30 * ANONYMOUS - 20 * EXTERNAL - 10 * * See: {@link Strophe.Connection#registerSASLMechanisms} */ declare class SASLMechanism { /** * PrivateConstructor: Strophe.SASLMechanism * SASL auth mechanism abstraction. * @param {String} [name] - SASL Mechanism name. * @param {Boolean} [isClientFirst] - If client should send response first without challenge. * @param {Number} [priority] - Priority. */ constructor(name?: string, isClientFirst?: boolean, priority?: number); /** Mechanism name. */ mechname: string; /** * If client sends response without initial server challenge. */ isClientFirst: boolean; /** * Determines which {@link SASLMechanism} is chosen for authentication (Higher is better). * Users may override this to prioritize mechanisms differently. * * Example: (This will cause Strophe to choose the mechanism that the server sent first) * * > Strophe.SASLPlain.priority = Strophe.SASLSHA1.priority; * * See for a list of available mechanisms. */ priority: number; /** * Checks if mechanism able to run. * To disable a mechanism, make this return false; * * To disable plain authentication run * > Strophe.SASLPlain.test = function() { * > return false; * > } * * See for a list of available mechanisms. * @param {Connection} connection - Target Connection. * @return {boolean} If mechanism was able to run. */ test(connection: Connection): boolean; /** * Called before starting mechanism on some connection. * @param {Connection} connection - Target Connection. */ onStart(connection: Connection): void; _connection: import("./connection.js").default; /** * Called by protocol implementation on incoming challenge. * * By deafult, if the client is expected to send data first (isClientFirst === true), * this method is called with `challenge` as null on the first call, * unless `clientChallenge` is overridden in the relevant subclass. * @param {Connection} connection - Target Connection. * @param {string} [challenge] - current challenge to handle. * @return {string|Promise} Mechanism response. */ onChallenge(connection: Connection, challenge?: string): string | Promise; /** * Called by the protocol implementation if the client is expected to send * data first in the authentication exchange (i.e. isClientFirst === true). * @param {Connection} connection - Target Connection. * @return {string|Promise} Mechanism response. */ clientChallenge(connection: Connection): string | Promise; /** * Protocol informs mechanism implementation about SASL failure. */ onFailure(): void; /** * Protocol informs mechanism implementation about SASL success. */ onSuccess(): void; } //# sourceMappingURL=sasl.d.ts.mapstrophejs-3.1.0/src/types/scram.d.ts000066400000000000000000000020311472775321000173720ustar00rootroot00000000000000export { scram as default }; export type Connection = import("./connection.js").default; export type Password = { name: string; ck: string; sk: string; iter: number; salt: string; }; declare namespace scram { /** * On success, sets * connection_sasl_data["server-signature"] * and * connection._sasl_data.keys * * The server signature should be verified after this function completes.. * * On failure, returns connection._sasl_failure_cb(); * @param {Connection} connection * @param {string} challenge * @param {string} hashName * @param {number} hashBits */ function scramResponse(connection: Connection, challenge: string, hashName: string, hashBits: number): Promise; /** * Returns a string containing the client first message * @param {Connection} connection * @param {string} test_cnonce */ function clientChallenge(connection: Connection, test_cnonce: string): string; } //# sourceMappingURL=scram.d.ts.mapstrophejs-3.1.0/src/types/shared-connection-worker.d.ts000066400000000000000000000025211472775321000232030ustar00rootroot00000000000000/** @type {ConnectionManager} */ declare let manager: ConnectionManager; declare namespace Status { let ERROR: number; let CONNECTING: number; let CONNFAIL: number; let AUTHENTICATING: number; let AUTHFAIL: number; let CONNECTED: number; let DISCONNECTED: number; let DISCONNECTING: number; let ATTACHED: number; let REDIRECT: number; let CONNTIMEOUT: number; let BINDREQUIRED: number; let ATTACHFAIL: number; } /** Class: ConnectionManager * * Manages the shared websocket connection as well as the ports of the * connected tabs. */ declare class ConnectionManager { /** @type {MessagePort[]} */ ports: MessagePort[]; /** @param {MessagePort} port */ addPort(port: MessagePort): void; /** * @param {[string, string]} data */ _connect(data: [string, string]): void; jid: string; socket: WebSocket; _attach(): void; /** @param {string} str */ send(str: string): void; /** @param {string} str */ close(str: string): void; _onOpen(): void; /** @param {CloseEvent} e */ _onClose(e: CloseEvent): void; /** @param {MessageEvent} message */ _onMessage(message: MessageEvent): void; /** @param {Event} error */ _onError(error: Event): void; _closeSocket(): void; } //# sourceMappingURL=shared-connection-worker.d.ts.mapstrophejs-3.1.0/src/types/shims.d.ts000066400000000000000000000013331472775321000174140ustar00rootroot00000000000000/** * Creates a dummy XML DOM document to serve as an element and text node generator. * * Used implementations: * - browser: use document's createDocument * - nodejs: use 'jsdom' https://www.npmjs.com/package/jsdom */ export function getDummyXMLDOMDocument(): XMLDocument; export const WebSocket: { new (url: string | URL, protocols?: string | string[]): WebSocket; prototype: WebSocket; readonly CONNECTING: 0; readonly OPEN: 1; readonly CLOSING: 2; readonly CLOSED: 3; } | typeof import("ws"); export const XMLSerializer: { new (): XMLSerializer; prototype: XMLSerializer; }; export const DOMParser: { new (): DOMParser; prototype: DOMParser; }; //# sourceMappingURL=shims.d.ts.mapstrophejs-3.1.0/src/types/stanza.d.ts000066400000000000000000000035611472775321000175760ustar00rootroot00000000000000/** * Tagged template literal function which generates {@link Stanza} objects * * @example * const pres = stx`${show}` * * connection.send(msg); * * @example * const msg = stx` * Hello world * `; * * connection.send(msg); * * @param {string[]} strings * @param {...any} values * @returns {Stanza} */ export function stx(strings: string[], ...values: any[]): Stanza; /** * A Stanza represents a XML element used in XMPP (commonly referred to as stanzas). */ export class Stanza extends Builder { /** * A directive which can be used to pass a string of XML as a value to the * stx tagged template literal. * * It's considered "unsafe" because it can pose a security risk if used with * untrusted input. * * @param {string} string * @returns {Builder} * @example * const status = 'I am busy!'; * const pres = stx` * * dnd * ${unsafeXML(status)} * `; * connection.send(pres); */ static unsafeXML(string: string): Builder; /** * Turns the passed-in string into an XML Element. * @param {string} string * @param {boolean} [throwErrorIfInvalidNS] * @returns {Element} */ static toElement(string: string, throwErrorIfInvalidNS?: boolean): Element; /** * @param {string[]} strings * @param {any[]} values */ constructor(strings: string[], values: any[]); #private; } import Builder from './builder.js'; //# sourceMappingURL=stanza.d.ts.mapstrophejs-3.1.0/src/types/timed-handler.d.ts000066400000000000000000000031451472775321000210110ustar00rootroot00000000000000export default TimedHandler; /** * _Private_ helper class for managing timed handlers. * * A Strophe.TimedHandler encapsulates a user provided callback that * should be called after a certain period of time or at regular * intervals. The return value of the callback determines whether the * Strophe.TimedHandler will continue to fire. * * Users will not use Strophe.TimedHandler objects directly, but instead * they will use {@link Strophe.Connection#addTimedHandler|addTimedHandler()} and * {@link Strophe.Connection#deleteTimedHandler|deleteTimedHandler()}. * * @memberof Strophe */ declare class TimedHandler { /** * Create and initialize a new Strophe.TimedHandler object. * @param {number} period - The number of milliseconds to wait before the * handler is called. * @param {Function} handler - The callback to run when the handler fires. This * function should take no arguments. */ constructor(period: number, handler: Function); period: number; handler: Function; lastCalled: number; user: boolean; /** * Run the callback for the Strophe.TimedHandler. * * @return {boolean} Returns the result of running the handler, * which is `true` if the Strophe.TimedHandler should be called again, * and `false` otherwise. */ run(): boolean; /** * Reset the last called time for the Strophe.TimedHandler. */ reset(): void; /** * Get a string representation of the Strophe.TimedHandler object. * @return {string} */ toString(): string; } //# sourceMappingURL=timed-handler.d.ts.mapstrophejs-3.1.0/src/types/utils.d.ts000066400000000000000000000173451472775321000174430ustar00rootroot00000000000000/** * Takes a string and turns it into an XML Element. * @param {string} string * @param {boolean} [throwErrorIfInvalidNS] * @returns {Element} */ export function toElement(string: string, throwErrorIfInvalidNS?: boolean): Element; /** * Properly logs an error to the console * @param {Error} e */ export function handleError(e: Error): void; /** * @param {string} str * @return {string} */ export function utf16to8(str: string): string; /** * @param {ArrayBufferLike} x * @param {ArrayBufferLike} y */ export function xorArrayBuffers(x: ArrayBufferLike, y: ArrayBufferLike): ArrayBuffer; /** * @param {ArrayBufferLike} buffer * @return {string} */ export function arrayBufToBase64(buffer: ArrayBufferLike): string; /** * @param {string} str * @return {ArrayBufferLike} */ export function base64ToArrayBuf(str: string): ArrayBufferLike; /** * @param {string} str * @return {ArrayBufferLike} */ export function stringToArrayBuf(str: string): ArrayBufferLike; /** * @param {Cookies} cookies */ export function addCookies(cookies: { [x: string]: string; } | { [x: string]: { [x: string]: string; }; }): void; /** * Get the DOM document to generate elements. * @return {Document} - The currently used DOM document. */ export function xmlGenerator(): Document; /** * Creates an XML DOM text node. * Provides a cross implementation version of document.createTextNode. * @param {string} text - The content of the text node. * @return {Text} - A new XML DOM text node. */ export function xmlTextNode(text: string): Text; /** * Creates an XML DOM node. * @param {string} text - The contents of the XML element. * @return {XMLDocument} */ export function xmlHtmlNode(text: string): XMLDocument; /** * @param {XMLDocument} doc * @returns {string|null} */ export function getParserError(doc: XMLDocument): string | null; /** * @param {XMLDocument} el * @returns {Element} */ export function getFirstElementChild(el: XMLDocument): Element; /** * Create an XML DOM element. * * This function creates an XML DOM element correctly across all * implementations. Note that these are not HTML DOM elements, which * aren't appropriate for XMPP stanzas. * * @param {string} name - The name for the element. * @param {Array>|Object.|string|number} [attrs] * An optional array or object containing * key/value pairs to use as element attributes. * The object should be in the format `{'key': 'value'}`. * The array should have the format `[['key1', 'value1'], ['key2', 'value2']]`. * @param {string|number} [text] - The text child data for the element. * * @return {Element} A new XML DOM element. */ export function xmlElement(name: string, attrs?: Array> | { [x: string]: string | number; } | string | number, text?: string | number): Element; /** * Utility method to determine whether a tag is allowed * in the XHTML_IM namespace. * * XHTML tag names are case sensitive and must be lower case. * @method Strophe.XHTML.validTag * @param {string} tag */ export function validTag(tag: string): boolean; /** * @typedef {'a'|'blockquote'|'br'|'cite'|'em'|'img'|'li'|'ol'|'p'|'span'|'strong'|'ul'|'body'} XHTMLAttrs */ /** * Utility method to determine whether an attribute is allowed * as recommended per XEP-0071 * * XHTML attribute names are case sensitive and must be lower case. * @method Strophe.XHTML.validAttribute * @param {string} tag * @param {string} attribute */ export function validAttribute(tag: string, attribute: string): boolean; /** * @method Strophe.XHTML.validCSS * @param {string} style */ export function validCSS(style: string): boolean; /** * Copy an HTML DOM Node into an XML DOM. * This function copies a DOM element and all its descendants and returns * the new copy. * @method Strophe.createHtml * @param {Node} node - A DOM element. * @return {Node} - A new, copied DOM element tree. */ export function createHtml(node: Node): Node; /** * Copy an XML DOM element. * * This function copies a DOM element and all its descendants and returns * the new copy. * @method Strophe.copyElement * @param {Node} node - A DOM element. * @return {Element|Text} - A new, copied DOM element tree. */ export function copyElement(node: Node): Element | Text; /** * Excapes invalid xml characters. * @method Strophe.xmlescape * @param {string} text - text to escape. * @return {string} - Escaped text. */ export function xmlescape(text: string): string; /** * Unexcapes invalid xml characters. * @method Strophe.xmlunescape * @param {string} text - text to unescape. * @return {string} - Unescaped text. */ export function xmlunescape(text: string): string; /** * Map a function over some or all child elements of a given element. * * This is a small convenience function for mapping a function over * some or all of the children of an element. If elemName is null, all * children will be passed to the function, otherwise only children * whose tag names match elemName will be passed. * * @method Strophe.forEachChild * @param {Element} elem - The element to operate on. * @param {string} elemName - The child element tag name filter. * @param {Function} func - The function to apply to each child. This * function should take a single argument, a DOM element. */ export function forEachChild(elem: Element, elemName: string, func: Function): void; /** * Compare an element's tag name with a string. * This function is case sensitive. * @method Strophe.isTagEqual * @param {Element} el - A DOM element. * @param {string} name - The element name. * @return {boolean} * true if the element's tag name matches _el_, and false * otherwise. */ export function isTagEqual(el: Element, name: string): boolean; /** * Get the concatenation of all text children of an element. * @method Strophe.getText * @param {Element} elem - A DOM element. * @return {string} - A String with the concatenated text of all text element children. */ export function getText(elem: Element): string; /** * Escape the node part (also called local part) of a JID. * @method Strophe.escapeNode * @param {string} node - A node (or local part). * @return {string} An escaped node (or local part). */ export function escapeNode(node: string): string; /** * Unescape a node part (also called local part) of a JID. * @method Strophe.unescapeNode * @param {string} node - A node (or local part). * @return {string} An unescaped node (or local part). */ export function unescapeNode(node: string): string; /** * Get the node portion of a JID String. * @method Strophe.getNodeFromJid * @param {string} jid - A JID. * @return {string} - A String containing the node. */ export function getNodeFromJid(jid: string): string; /** * Get the domain portion of a JID String. * @method Strophe.getDomainFromJid * @param {string} jid - A JID. * @return {string} - A String containing the domain. */ export function getDomainFromJid(jid: string): string; /** * Get the resource portion of a JID String. * @method Strophe.getResourceFromJid * @param {string} jid - A JID. * @return {string} - A String containing the resource. */ export function getResourceFromJid(jid: string): string; /** * Get the bare JID from a JID String. * @method Strophe.getBareJidFromJid * @param {string} jid - A JID. * @return {string} - A String containing the bare JID. */ export function getBareJidFromJid(jid: string): string; export { utils as default }; export type XHTMLAttrs = "a" | "blockquote" | "br" | "cite" | "em" | "img" | "li" | "ol" | "p" | "span" | "strong" | "ul" | "body"; declare namespace utils { export { utf16to8 }; export { xorArrayBuffers }; export { arrayBufToBase64 }; export { base64ToArrayBuf }; export { stringToArrayBuf }; export { addCookies }; } //# sourceMappingURL=utils.d.ts.mapstrophejs-3.1.0/src/types/websocket.d.ts000066400000000000000000000155641472775321000202720ustar00rootroot00000000000000export default Websocket; export type Connection = import("./connection.js").default; /** * Helper class that handles WebSocket Connections * * The WebSocket class is used internally by Connection * to encapsulate WebSocket sessions. It is not meant to be used from user's code. */ declare class Websocket { /** * Create and initialize a WebSocket object. * Currently only sets the connection Object. * @param {Connection} connection - The Connection that will use WebSockets. */ constructor(connection: Connection); _conn: import("./connection.js").default; strip: string; /** * _Private_ helper function to generate the start tag for WebSockets * @private * @return {Builder} - A Builder with a element. */ private _buildStream; /** * _Private_ checks a message for stream:error * @private * @param {Element} bodyWrap - The received stanza. * @param {number} connectstatus - The ConnectStatus that will be set on error. * @return {boolean} - true if there was a streamerror, false otherwise. */ private _checkStreamError; /** * Reset the connection. * * This function is called by the reset function of the Strophe Connection. * Is not needed by WebSockets. */ _reset(): void; /** * _Private_ function called by Connection.connect * * Creates a WebSocket for a connection and assigns Callbacks to it. * Does nothing if there already is a WebSocket. */ _connect(): void; /** * @typedef {Object} WebsocketLike * @property {(str: string) => void} WebsocketLike.send * @property {function(): void} WebsocketLike.close * @property {function(): void} WebsocketLike.onopen * @property {(e: ErrorEvent) => void} WebsocketLike.onerror * @property {(e: CloseEvent) => void} WebsocketLike.onclose * @property {(message: MessageEvent) => void} WebsocketLike.onmessage * @property {string} WebsocketLike.readyState */ /** @type {import('ws')|WebSocket|WebsocketLike} */ socket: import("ws") | WebSocket | { send: (str: string) => void; close: () => void; onopen: () => void; onerror: (e: ErrorEvent) => void; onclose: (e: CloseEvent) => void; onmessage: (message: MessageEvent) => void; readyState: string; }; /** * _Private_ function called by Connection._connect_cb * checks for stream:error * @param {Element} bodyWrap - The received stanza. */ _connect_cb(bodyWrap: Element): number; /** * _Private_ function that checks the opening tag for errors. * * Disconnects if there is an error and returns false, true otherwise. * @private * @param {Element} message - Stanza containing the tag. */ private _handleStreamStart; /** * _Private_ function that handles the first connection messages. * * On receiving an opening stream tag this callback replaces itself with the real * message handler. On receiving a stream error the connection is terminated. * @param {MessageEvent} message */ _onInitialMessage(message: MessageEvent): void; /** * Called by _onInitialMessage in order to replace itself with the general message handler. * This method is overridden by WorkerWebsocket, which manages a * websocket connection via a service worker and doesn't have direct access * to the socket. */ _replaceMessageHandler(): void; /** * _Private_ function called by Connection.disconnect * Disconnects and sends a last stanza if one is given * @param {Element|Builder} [pres] - This stanza will be sent before disconnecting. */ _disconnect(pres?: Element | Builder): void; /** * _Private_ function to disconnect. * Just closes the Socket for WebSockets */ _doDisconnect(): void; /** * PrivateFunction _streamWrap * _Private_ helper function to wrap a stanza in a tag. * This is used so Strophe can process stanzas from WebSockets like BOSH * @param {string} stanza */ _streamWrap(stanza: string): string; /** * _Private_ function to close the WebSocket. * * Closes the socket if it is still open and deletes it */ _closeSocket(): void; /** * _Private_ function to check if the message queue is empty. * @return {true} - True, because WebSocket messages are send immediately after queueing. */ _emptyQueue(): true; /** * _Private_ function to handle websockets closing. * @param {CloseEvent} [e] */ _onClose(e?: CloseEvent): void; /** * @callback connectionCallback * @param {Connection} connection */ /** * Called on stream start/restart when no stream:features * has been received. * @param {connectionCallback} callback */ _no_auth_received(callback: (connection: Connection) => any): void; /** * _Private_ timeout handler for handling non-graceful disconnection. * * This does nothing for WebSockets */ _onDisconnectTimeout(): void; /** * _Private_ helper function that makes sure all pending requests are aborted. */ _abortAllRequests(): void; /** * _Private_ function to handle websockets errors. * @param {Object} error - The websocket error. */ _onError(error: Object): void; /** * _Private_ function called by Connection._onIdle * sends all queued stanzas */ _onIdle(): void; /** * _Private_ function to handle websockets messages. * * This function parses each of the messages as if they are full documents. * [TODO : We may actually want to use a SAX Push parser]. * * Since all XMPP traffic starts with * * * The first stanza will always fail to be parsed. * * Additionally, the seconds stanza will always be with * the stream NS defined in the previous stanza, so we need to 'force' * the inclusion of the NS in this stanza. * * @param {MessageEvent} message - The websocket message event */ _onMessage(message: MessageEvent): void; /** * _Private_ function to handle websockets connection setup. * The opening stream tag is sent here. * @private */ private _onOpen; /** * _Private_ part of the Connection.send function for WebSocket * Just flushes the messages that are in the queue */ _send(): void; /** * Send an xmpp:restart stanza. */ _sendRestart(): void; } import Builder from './builder.js'; //# sourceMappingURL=websocket.d.ts.mapstrophejs-3.1.0/src/types/worker-websocket.d.ts000066400000000000000000000020321472775321000215630ustar00rootroot00000000000000export default WorkerWebsocket; /** * Helper class that handles a websocket connection inside a shared worker. */ declare class WorkerWebsocket extends Websocket { worker: SharedWorker; /** * @private */ private _setSocket; /** @param {MessageEvent} m */ _messageHandler: ((m: MessageEvent) => void) | ((m: MessageEvent) => void) | ((m: MessageEvent) => void); /** * @param {Function} callback */ _attach(callback: Function): void; /** * @param {number} status * @param {string} jid */ _attachCallback(status: number, jid: string): void; /** * @param {Element|Builder} pres - This stanza will be sent before disconnecting. */ _disconnect(pres: Element | Builder): void; /** * function that handles messages received from the service worker * @private * @param {MessageEvent} ev */ private _onWorkerMessage; } import Websocket from './websocket.js'; import Builder from './builder.js'; //# sourceMappingURL=worker-websocket.d.ts.mapstrophejs-3.1.0/src/utils.js000066400000000000000000000455701472775321000160440ustar00rootroot00000000000000/* global btoa */ import log from './log.js'; import * as shims from './shims.js'; import { ElementType, PARSE_ERROR_NS, XHTML } from './constants.js'; /** * Takes a string and turns it into an XML Element. * @param {string} string * @param {boolean} [throwErrorIfInvalidNS] * @returns {Element} */ export function toElement(string, throwErrorIfInvalidNS) { const doc = xmlHtmlNode(string); const parserError = getParserError(doc); if (parserError) { throw new Error(`Parser Error: ${parserError}`); } const node = getFirstElementChild(doc); if ( ['message', 'iq', 'presence'].includes(node.nodeName.toLowerCase()) && node.namespaceURI !== 'jabber:client' && node.namespaceURI !== 'jabber:server' ) { const err_msg = `Invalid namespaceURI ${node.namespaceURI}`; if (throwErrorIfInvalidNS) { throw new Error(err_msg); } else { log.error(err_msg); } } return node; } /** * Properly logs an error to the console * @param {Error} e */ export function handleError(e) { if (typeof e.stack !== 'undefined') { log.fatal(e.stack); } log.fatal('error: ' + e.message); } /** * @param {string} str * @return {string} */ export function utf16to8(str) { let out = ''; const len = str.length; for (let i = 0; i < len; i++) { const c = str.charCodeAt(i); if (c >= 0x0000 && c <= 0x007f) { out += str.charAt(i); } else if (c > 0x07ff) { out += String.fromCharCode(0xe0 | ((c >> 12) & 0x0f)); out += String.fromCharCode(0x80 | ((c >> 6) & 0x3f)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3f)); } else { out += String.fromCharCode(0xc0 | ((c >> 6) & 0x1f)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3f)); } } return out; } /** * @param {ArrayBufferLike} x * @param {ArrayBufferLike} y */ export function xorArrayBuffers(x, y) { const xIntArray = new Uint8Array(x); const yIntArray = new Uint8Array(y); const zIntArray = new Uint8Array(x.byteLength); for (let i = 0; i < x.byteLength; i++) { zIntArray[i] = xIntArray[i] ^ yIntArray[i]; } return zIntArray.buffer; } /** * @param {ArrayBufferLike} buffer * @return {string} */ export function arrayBufToBase64(buffer) { // This function is due to mobz (https://stackoverflow.com/users/1234628/mobz) // and Emmanuel (https://stackoverflow.com/users/288564/emmanuel) let binary = ''; const bytes = new Uint8Array(buffer); const len = bytes.byteLength; for (let i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return btoa(binary); } /** * @param {string} str * @return {ArrayBufferLike} */ export function base64ToArrayBuf(str) { return Uint8Array.from(atob(str), (c) => c.charCodeAt(0))?.buffer; } /** * @param {string} str * @return {ArrayBufferLike} */ export function stringToArrayBuf(str) { const bytes = new TextEncoder().encode(str); return bytes.buffer; } /** * @param {Cookies} cookies */ export function addCookies(cookies) { if (typeof document === 'undefined') { log.error(`addCookies: not adding any cookies, since there's no document object`); } /** * @typedef {Object.} Cookie * * A map of cookie names to string values or to maps of cookie values. * @typedef {Cookie|Object.} Cookies * * For example: * { "myCookie": "1234" } * * or: * { "myCookie": { * "value": "1234", * "domain": ".example.org", * "path": "/", * "expires": expirationDate * } * } * * These values get passed to {@link Strophe.Connection} via options.cookies */ cookies = cookies || {}; for (const cookieName in cookies) { if (Object.prototype.hasOwnProperty.call(cookies, cookieName)) { let expires = ''; let domain = ''; let path = ''; const cookieObj = cookies[cookieName]; const isObj = typeof cookieObj === 'object'; const cookieValue = escape(unescape(isObj ? cookieObj.value : cookieObj)); if (isObj) { expires = cookieObj.expires ? ';expires=' + cookieObj.expires : ''; domain = cookieObj.domain ? ';domain=' + cookieObj.domain : ''; path = cookieObj.path ? ';path=' + cookieObj.path : ''; } document.cookie = cookieName + '=' + cookieValue + expires + domain + path; } } } /** @type {Document} */ let _xmlGenerator = null; /** * Get the DOM document to generate elements. * @return {Document} - The currently used DOM document. */ export function xmlGenerator() { if (!_xmlGenerator) { _xmlGenerator = shims.getDummyXMLDOMDocument(); } return _xmlGenerator; } /** * Creates an XML DOM text node. * Provides a cross implementation version of document.createTextNode. * @param {string} text - The content of the text node. * @return {Text} - A new XML DOM text node. */ export function xmlTextNode(text) { return xmlGenerator().createTextNode(text); } /** * Creates an XML DOM node. * @param {string} text - The contents of the XML element. * @return {XMLDocument} */ export function xmlHtmlNode(text) { const parser = new shims.DOMParser(); return parser.parseFromString(text, 'text/xml'); } /** * @param {XMLDocument} doc * @returns {string|null} */ export function getParserError(doc) { const el = doc.firstElementChild?.nodeName === 'parsererror' ? doc.firstElementChild : doc.getElementsByTagNameNS(PARSE_ERROR_NS, 'parsererror')[0]; return el?.nodeName === 'parsererror' ? el?.textContent : null; } /** * @param {XMLDocument} el * @returns {Element} */ export function getFirstElementChild(el) { if (el.firstElementChild) return el.firstElementChild; let node, i = 0; const nodes = el.childNodes; while ((node = nodes[i++])) { if (node.nodeType === 1) return /** @type {Element} */ (node); } return null; } /** * Create an XML DOM element. * * This function creates an XML DOM element correctly across all * implementations. Note that these are not HTML DOM elements, which * aren't appropriate for XMPP stanzas. * * @param {string} name - The name for the element. * @param {Array>|Object.|string|number} [attrs] * An optional array or object containing * key/value pairs to use as element attributes. * The object should be in the format `{'key': 'value'}`. * The array should have the format `[['key1', 'value1'], ['key2', 'value2']]`. * @param {string|number} [text] - The text child data for the element. * * @return {Element} A new XML DOM element. */ export function xmlElement(name, attrs, text) { if (!name) return null; const node = xmlGenerator().createElement(name); if (text && (typeof text === 'string' || typeof text === 'number')) { node.appendChild(xmlTextNode(text.toString())); } else if (typeof attrs === 'string' || typeof attrs === 'number') { node.appendChild(xmlTextNode(/** @type {number|string} */ (attrs).toString())); return node; } if (!attrs) { return node; } else if (Array.isArray(attrs)) { for (const attr of attrs) { if (Array.isArray(attr)) { // eslint-disable-next-line no-eq-null if (attr[0] != null && attr[1] != null) { node.setAttribute(attr[0], attr[1]); } } } } else if (typeof attrs === 'object') { for (const k of Object.keys(attrs)) { // eslint-disable-next-line no-eq-null if (k && attrs[k] != null) { node.setAttribute(k, attrs[k].toString()); } } } return node; } /** * Utility method to determine whether a tag is allowed * in the XHTML_IM namespace. * * XHTML tag names are case sensitive and must be lower case. * @method Strophe.XHTML.validTag * @param {string} tag */ export function validTag(tag) { for (let i = 0; i < XHTML.tags.length; i++) { if (tag === XHTML.tags[i]) { return true; } } return false; } /** * @typedef {'a'|'blockquote'|'br'|'cite'|'em'|'img'|'li'|'ol'|'p'|'span'|'strong'|'ul'|'body'} XHTMLAttrs */ /** * Utility method to determine whether an attribute is allowed * as recommended per XEP-0071 * * XHTML attribute names are case sensitive and must be lower case. * @method Strophe.XHTML.validAttribute * @param {string} tag * @param {string} attribute */ export function validAttribute(tag, attribute) { const attrs = XHTML.attributes[/** @type {XHTMLAttrs} */ (tag)]; if (attrs?.length > 0) { for (let i = 0; i < attrs.length; i++) { if (attribute === attrs[i]) { return true; } } } return false; } /** * @method Strophe.XHTML.validCSS * @param {string} style */ export function validCSS(style) { for (let i = 0; i < XHTML.css.length; i++) { if (style === XHTML.css[i]) { return true; } } return false; } /** * Copy an HTML DOM Element into an XML DOM. * This function copies a DOM element and all its descendants and returns * the new copy. * @param {HTMLElement} elem - A DOM element. * @return {Node} - A new, copied DOM element tree. */ function createFromHtmlElement(elem) { let el; const tag = elem.nodeName.toLowerCase(); // XHTML tags must be lower case. if (validTag(tag)) { try { el = xmlElement(tag); if (tag in XHTML.attributes) { const attrs = XHTML.attributes[/** @type {XHTMLAttrs} */ (tag)]; for (let i = 0; i < attrs.length; i++) { const attribute = attrs[i]; let value = elem.getAttribute(attribute); if (typeof value === 'undefined' || value === null || value === '') { continue; } if (attribute === 'style' && typeof value === 'object') { value = /** @type {Object.<'csstext',string>} */ (value).cssText ?? value; // we're dealing with IE, need to get CSS out } // filter out invalid css styles if (attribute === 'style') { const css = []; const cssAttrs = value.split(';'); for (let j = 0; j < cssAttrs.length; j++) { const attr = cssAttrs[j].split(':'); const cssName = attr[0].replace(/^\s*/, '').replace(/\s*$/, '').toLowerCase(); if (validCSS(cssName)) { const cssValue = attr[1].replace(/^\s*/, '').replace(/\s*$/, ''); css.push(cssName + ': ' + cssValue); } } if (css.length > 0) { value = css.join('; '); el.setAttribute(attribute, value); } } else { el.setAttribute(attribute, value); } } for (let i = 0; i < elem.childNodes.length; i++) { el.appendChild(createHtml(elem.childNodes[i])); } } } catch (e) { // eslint-disable-line no-unused-vars // invalid elements el = xmlTextNode(''); } } else { el = xmlGenerator().createDocumentFragment(); for (let i = 0; i < elem.childNodes.length; i++) { el.appendChild(createHtml(elem.childNodes[i])); } } return el; } /** * Copy an HTML DOM Node into an XML DOM. * This function copies a DOM element and all its descendants and returns * the new copy. * @method Strophe.createHtml * @param {Node} node - A DOM element. * @return {Node} - A new, copied DOM element tree. */ export function createHtml(node) { if (node.nodeType === ElementType.NORMAL) { return createFromHtmlElement(/** @type {HTMLElement} */ (node)); } else if (node.nodeType === ElementType.FRAGMENT) { const el = xmlGenerator().createDocumentFragment(); for (let i = 0; i < node.childNodes.length; i++) { el.appendChild(createHtml(node.childNodes[i])); } return el; } else if (node.nodeType === ElementType.TEXT) { return xmlTextNode(node.nodeValue); } } /** * Copy an XML DOM element. * * This function copies a DOM element and all its descendants and returns * the new copy. * @method Strophe.copyElement * @param {Node} node - A DOM element. * @return {Element|Text} - A new, copied DOM element tree. */ export function copyElement(node) { let out; if (node.nodeType === ElementType.NORMAL) { const el = /** @type {Element} */ (node); out = xmlElement(el.tagName); for (let i = 0; i < el.attributes.length; i++) { out.setAttribute(el.attributes[i].nodeName, el.attributes[i].value); } for (let i = 0; i < el.childNodes.length; i++) { out.appendChild(copyElement(el.childNodes[i])); } } else if (node.nodeType === ElementType.TEXT) { out = xmlGenerator().createTextNode(node.nodeValue); } return out; } /** * Excapes invalid xml characters. * @method Strophe.xmlescape * @param {string} text - text to escape. * @return {string} - Escaped text. */ export function xmlescape(text) { text = text.replace(/\&/g, '&'); text = text.replace(//g, '>'); text = text.replace(/'/g, '''); text = text.replace(/"/g, '"'); return text; } /** * Unexcapes invalid xml characters. * @method Strophe.xmlunescape * @param {string} text - text to unescape. * @return {string} - Unescaped text. */ export function xmlunescape(text) { text = text.replace(/\&/g, '&'); text = text.replace(/</g, '<'); text = text.replace(/>/g, '>'); text = text.replace(/'/g, "'"); text = text.replace(/"/g, '"'); return text; } /** * Map a function over some or all child elements of a given element. * * This is a small convenience function for mapping a function over * some or all of the children of an element. If elemName is null, all * children will be passed to the function, otherwise only children * whose tag names match elemName will be passed. * * @method Strophe.forEachChild * @param {Element} elem - The element to operate on. * @param {string} elemName - The child element tag name filter. * @param {Function} func - The function to apply to each child. This * function should take a single argument, a DOM element. */ export function forEachChild(elem, elemName, func) { for (let i = 0; i < elem.childNodes.length; i++) { const childNode = elem.childNodes[i]; if (childNode.nodeType === ElementType.NORMAL && (!elemName || this.isTagEqual(childNode, elemName))) { func(childNode); } } } /** * Compare an element's tag name with a string. * This function is case sensitive. * @method Strophe.isTagEqual * @param {Element} el - A DOM element. * @param {string} name - The element name. * @return {boolean} * true if the element's tag name matches _el_, and false * otherwise. */ export function isTagEqual(el, name) { return el.tagName === name; } /** * Get the concatenation of all text children of an element. * @method Strophe.getText * @param {Element} elem - A DOM element. * @return {string} - A String with the concatenated text of all text element children. */ export function getText(elem) { if (!elem) return null; let str = ''; if (!elem.childNodes.length && elem.nodeType === ElementType.TEXT) { str += elem.nodeValue; } for (const child of elem.childNodes) { if (child.nodeType === ElementType.TEXT) { str += child.nodeValue; } } return xmlescape(str); } /** * Escape the node part (also called local part) of a JID. * @method Strophe.escapeNode * @param {string} node - A node (or local part). * @return {string} An escaped node (or local part). */ export function escapeNode(node) { if (typeof node !== 'string') { return node; } return node .replace(/^\s+|\s+$/g, '') .replace(/\\/g, '\\5c') .replace(/ /g, '\\20') .replace(/\"/g, '\\22') .replace(/\&/g, '\\26') .replace(/\'/g, '\\27') .replace(/\//g, '\\2f') .replace(/:/g, '\\3a') .replace(//g, '\\3e') .replace(/@/g, '\\40'); } /** * Unescape a node part (also called local part) of a JID. * @method Strophe.unescapeNode * @param {string} node - A node (or local part). * @return {string} An unescaped node (or local part). */ export function unescapeNode(node) { if (typeof node !== 'string') { return node; } return node .replace(/\\20/g, ' ') .replace(/\\22/g, '"') .replace(/\\26/g, '&') .replace(/\\27/g, "'") .replace(/\\2f/g, '/') .replace(/\\3a/g, ':') .replace(/\\3c/g, '<') .replace(/\\3e/g, '>') .replace(/\\40/g, '@') .replace(/\\5c/g, '\\'); } /** * Get the node portion of a JID String. * @method Strophe.getNodeFromJid * @param {string} jid - A JID. * @return {string} - A String containing the node. */ export function getNodeFromJid(jid) { if (jid.indexOf('@') < 0) { return null; } return jid.split('@')[0]; } /** * Get the domain portion of a JID String. * @method Strophe.getDomainFromJid * @param {string} jid - A JID. * @return {string} - A String containing the domain. */ export function getDomainFromJid(jid) { const bare = getBareJidFromJid(jid); if (bare.indexOf('@') < 0) { return bare; } else { const parts = bare.split('@'); parts.splice(0, 1); return parts.join('@'); } } /** * Get the resource portion of a JID String. * @method Strophe.getResourceFromJid * @param {string} jid - A JID. * @return {string} - A String containing the resource. */ export function getResourceFromJid(jid) { if (!jid) { return null; } const s = jid.split('/'); if (s.length < 2) { return null; } s.splice(0, 1); return s.join('/'); } /** * Get the bare JID from a JID String. * @method Strophe.getBareJidFromJid * @param {string} jid - A JID. * @return {string} - A String containing the bare JID. */ export function getBareJidFromJid(jid) { return jid ? jid.split('/')[0] : null; } const utils = { utf16to8, xorArrayBuffers, arrayBufToBase64, base64ToArrayBuf, stringToArrayBuf, addCookies, }; export { utils as default }; strophejs-3.1.0/src/websocket.js000066400000000000000000000450511472775321000166640ustar00rootroot00000000000000/** * A JavaScript library to enable XMPP over Websocket in Strophejs. * * This file implements XMPP over WebSockets for Strophejs. * If a Connection is established with a Websocket url (ws://...) * Strophe will use WebSockets. * For more information on XMPP-over-WebSocket see RFC 7395: * http://tools.ietf.org/html/rfc7395 * * WebSocket support implemented by Andreas Guth (andreas.guth@rwth-aachen.de) */ /* global clearTimeout, location */ /** * @typedef {import("./connection.js").default} Connection */ import { DOMParser, WebSocket } from './shims'; import Builder, { $build } from './builder.js'; import log from './log.js'; import { NS, ErrorCondition, Status } from './constants.js'; /** * Helper class that handles WebSocket Connections * * The WebSocket class is used internally by Connection * to encapsulate WebSocket sessions. It is not meant to be used from user's code. */ class Websocket { /** * Create and initialize a WebSocket object. * Currently only sets the connection Object. * @param {Connection} connection - The Connection that will use WebSockets. */ constructor(connection) { this._conn = connection; this.strip = 'wrapper'; const service = connection.service; if (service.indexOf('ws:') !== 0 && service.indexOf('wss:') !== 0) { // If the service is not an absolute URL, assume it is a path and put the absolute // URL together from options, current URL and the path. let new_service = ''; if (connection.options.protocol === 'ws' && location.protocol !== 'https:') { new_service += 'ws'; } else { new_service += 'wss'; } new_service += '://' + location.host; if (service.indexOf('/') !== 0) { new_service += location.pathname + service; } else { new_service += service; } connection.service = new_service; } } /** * _Private_ helper function to generate the start tag for WebSockets * @private * @return {Builder} - A Builder with a element. */ _buildStream() { return $build('open', { 'xmlns': NS.FRAMING, 'to': this._conn.domain, 'version': '1.0', }); } /** * _Private_ checks a message for stream:error * @private * @param {Element} bodyWrap - The received stanza. * @param {number} connectstatus - The ConnectStatus that will be set on error. * @return {boolean} - true if there was a streamerror, false otherwise. */ _checkStreamError(bodyWrap, connectstatus) { let errors; if (bodyWrap.getElementsByTagNameNS) { errors = bodyWrap.getElementsByTagNameNS(NS.STREAM, 'error'); } else { errors = bodyWrap.getElementsByTagName('stream:error'); } if (errors.length === 0) { return false; } const error = errors[0]; let condition = ''; let text = ''; const ns = 'urn:ietf:params:xml:ns:xmpp-streams'; for (let i = 0; i < error.childNodes.length; i++) { const e = error.childNodes[i]; if (e.nodeType === e.ELEMENT_NODE) { /** @type {Element} */ const el = /** @type {any} */ (e); if (el.getAttribute('xmlns') !== ns) { break; } } if (e.nodeName === 'text') { text = e.textContent; } else { condition = e.nodeName; } } let errorString = 'WebSocket stream error: '; if (condition) { errorString += condition; } else { errorString += 'unknown'; } if (text) { errorString += ' - ' + text; } log.error(errorString); // close the connection on stream_error this._conn._changeConnectStatus(connectstatus, condition); this._conn._doDisconnect(); return true; } /** * Reset the connection. * * This function is called by the reset function of the Strophe Connection. * Is not needed by WebSockets. */ // eslint-disable-next-line class-methods-use-this _reset() { return; } /** * _Private_ function called by Connection.connect * * Creates a WebSocket for a connection and assigns Callbacks to it. * Does nothing if there already is a WebSocket. */ _connect() { // Ensure that there is no open WebSocket from a previous Connection. this._closeSocket(); /** * @typedef {Object} WebsocketLike * @property {(str: string) => void} WebsocketLike.send * @property {function(): void} WebsocketLike.close * @property {function(): void} WebsocketLike.onopen * @property {(e: ErrorEvent) => void} WebsocketLike.onerror * @property {(e: CloseEvent) => void} WebsocketLike.onclose * @property {(message: MessageEvent) => void} WebsocketLike.onmessage * @property {string} WebsocketLike.readyState */ /** @type {import('ws')|WebSocket|WebsocketLike} */ this.socket = new WebSocket(this._conn.service, 'xmpp'); this.socket.onopen = () => this._onOpen(); /** @param {ErrorEvent} e */ this.socket.onerror = (e) => this._onError(e); /** @param {CloseEvent} e */ this.socket.onclose = (e) => this._onClose(e); /** * Gets replaced with this._onMessage once _onInitialMessage is called * @param {MessageEvent} message */ this.socket.onmessage = (message) => this._onInitialMessage(message); } /** * _Private_ function called by Connection._connect_cb * checks for stream:error * @param {Element} bodyWrap - The received stanza. */ _connect_cb(bodyWrap) { const error = this._checkStreamError(bodyWrap, Status.CONNFAIL); if (error) { return Status.CONNFAIL; } } /** * _Private_ function that checks the opening tag for errors. * * Disconnects if there is an error and returns false, true otherwise. * @private * @param {Element} message - Stanza containing the tag. */ _handleStreamStart(message) { let error = null; // Check for errors in the tag const ns = message.getAttribute('xmlns'); if (typeof ns !== 'string') { error = 'Missing xmlns in '; } else if (ns !== NS.FRAMING) { error = 'Wrong xmlns in : ' + ns; } const ver = message.getAttribute('version'); if (typeof ver !== 'string') { error = 'Missing version in '; } else if (ver !== '1.0') { error = 'Wrong version in : ' + ver; } if (error) { this._conn._changeConnectStatus(Status.CONNFAIL, error); this._conn._doDisconnect(); return false; } return true; } /** * _Private_ function that handles the first connection messages. * * On receiving an opening stream tag this callback replaces itself with the real * message handler. On receiving a stream error the connection is terminated. * @param {MessageEvent} message */ _onInitialMessage(message) { if (message.data.indexOf('\s*)*/, ''); if (data === '') return; const streamStart = new DOMParser().parseFromString(data, 'text/xml').documentElement; this._conn.xmlInput(streamStart); this._conn.rawInput(message.data); //_handleStreamSteart will check for XML errors and disconnect on error if (this._handleStreamStart(streamStart)) { //_connect_cb will check for stream:error and disconnect on error this._connect_cb(streamStart); } } else if (message.data.indexOf(' this._conn._doDisconnect(), 0); } /** * _Private_ function to disconnect. * Just closes the Socket for WebSockets */ _doDisconnect() { log.debug('WebSockets _doDisconnect was called'); this._closeSocket(); } /** * PrivateFunction _streamWrap * _Private_ helper function to wrap a stanza in a tag. * This is used so Strophe can process stanzas from WebSockets like BOSH * @param {string} stanza */ // eslint-disable-next-line class-methods-use-this _streamWrap(stanza) { return '' + stanza + ''; } /** * _Private_ function to close the WebSocket. * * Closes the socket if it is still open and deletes it */ _closeSocket() { if (this.socket) { try { this.socket.onclose = null; this.socket.onerror = null; this.socket.onmessage = null; this.socket.close(); } catch (e) { log.debug(e.message); } } this.socket = null; } /** * _Private_ function to check if the message queue is empty. * @return {true} - True, because WebSocket messages are send immediately after queueing. */ // eslint-disable-next-line class-methods-use-this _emptyQueue() { return true; } /** * _Private_ function to handle websockets closing. * @param {CloseEvent} [e] */ _onClose(e) { if (this._conn.connected && !this._conn.disconnecting) { log.error('Websocket closed unexpectedly'); this._conn._doDisconnect(); } else if (e && e.code === 1006 && !this._conn.connected && this.socket) { // in case the onError callback was not called (Safari 10 does not // call onerror when the initial connection fails) we need to // dispatch a CONNFAIL status update to be consistent with the // behavior on other browsers. log.error('Websocket closed unexcectedly'); this._conn._changeConnectStatus( Status.CONNFAIL, 'The WebSocket connection could not be established or was disconnected.' ); this._conn._doDisconnect(); } else { log.debug('Websocket closed'); } } /** * @callback connectionCallback * @param {Connection} connection */ /** * Called on stream start/restart when no stream:features * has been received. * @param {connectionCallback} callback */ _no_auth_received(callback) { log.error('Server did not offer a supported authentication mechanism'); this._conn._changeConnectStatus(Status.CONNFAIL, ErrorCondition.NO_AUTH_MECH); callback?.call(this._conn); this._conn._doDisconnect(); } /** * _Private_ timeout handler for handling non-graceful disconnection. * * This does nothing for WebSockets */ _onDisconnectTimeout() {} // eslint-disable-line class-methods-use-this /** * _Private_ helper function that makes sure all pending requests are aborted. */ _abortAllRequests() {} // eslint-disable-line class-methods-use-this /** * _Private_ function to handle websockets errors. * @param {Object} error - The websocket error. */ _onError(error) { log.error('Websocket error ' + JSON.stringify(error)); this._conn._changeConnectStatus( Status.CONNFAIL, 'The WebSocket connection could not be established or was disconnected.' ); this._disconnect(); } /** * _Private_ function called by Connection._onIdle * sends all queued stanzas */ _onIdle() { const data = this._conn._data; if (data.length > 0 && !this._conn.paused) { for (let i = 0; i < data.length; i++) { if (data[i] !== null) { const stanza = data[i] === 'restart' ? this._buildStream().tree() : data[i]; if (stanza === 'restart') throw new Error('Wrong type for stanza'); // Shut up tsc const rawStanza = Builder.serialize(stanza); this._conn.xmlOutput(stanza); this._conn.rawOutput(rawStanza); this.socket.send(rawStanza); } } this._conn._data = []; } } /** * _Private_ function to handle websockets messages. * * This function parses each of the messages as if they are full documents. * [TODO : We may actually want to use a SAX Push parser]. * * Since all XMPP traffic starts with * * * The first stanza will always fail to be parsed. * * Additionally, the seconds stanza will always be with * the stream NS defined in the previous stanza, so we need to 'force' * the inclusion of the NS in this stanza. * * @param {MessageEvent} message - The websocket message event */ _onMessage(message) { let elem; // check for closing stream const close = ''; if (message.data === close) { this._conn.rawInput(close); this._conn.xmlInput(message); if (!this._conn.disconnecting) { this._conn._doDisconnect(); } return; } else if (message.data.search(' tag before we close the connection return; } this._conn._dataRecv(elem, message.data); } /** * _Private_ function to handle websockets connection setup. * The opening stream tag is sent here. * @private */ _onOpen() { log.debug('Websocket open'); const start = this._buildStream(); this._conn.xmlOutput(start.tree()); const startString = Builder.serialize(start); this._conn.rawOutput(startString); this.socket.send(startString); } /** * _Private_ part of the Connection.send function for WebSocket * Just flushes the messages that are in the queue */ _send() { this._conn.flush(); } /** * Send an xmpp:restart stanza. */ _sendRestart() { clearTimeout(this._conn._idleTimeout); this._conn._onIdle.bind(this._conn)(); } } export default Websocket; strophejs-3.1.0/src/worker-websocket.js000066400000000000000000000116141472775321000201710ustar00rootroot00000000000000/** * @license MIT * @copyright JC Brand */ import Websocket from './websocket.js'; import log from './log.js'; import Builder, { $build } from './builder.js'; import { LOG_LEVELS, NS, Status } from './constants.js'; /** * Helper class that handles a websocket connection inside a shared worker. */ class WorkerWebsocket extends Websocket { /** * @typedef {import("./connection.js").default} Connection */ /** * Create and initialize a WorkerWebsocket object. * @param {Connection} connection - The Connection */ constructor(connection) { super(connection); this._conn = connection; this.worker = new SharedWorker(this._conn.options.worker, 'Strophe XMPP Connection'); this.worker.onerror = (e) => { console?.error(e); log.error(`Shared Worker Error: ${e}`); }; } /** * @private */ _setSocket() { this.socket = { /** @param {string} str */ send: (str) => this.worker.port.postMessage(['send', str]), close: () => this.worker.port.postMessage(['_closeSocket']), onopen: () => {}, /** @param {ErrorEvent} e */ onerror: (e) => this._onError(e), /** @param {CloseEvent} e */ onclose: (e) => this._onClose(e), onmessage: () => {}, readyState: null, }; } _connect() { this._setSocket(); /** @param {MessageEvent} m */ this._messageHandler = (m) => this._onInitialMessage(m); this.worker.port.start(); this.worker.port.onmessage = (ev) => this._onWorkerMessage(ev); this.worker.port.postMessage(['_connect', this._conn.service, this._conn.jid]); } /** * @param {Function} callback */ _attach(callback) { this._setSocket(); /** @param {MessageEvent} m */ this._messageHandler = (m) => this._onMessage(m); this._conn.connect_callback = callback; this.worker.port.start(); this.worker.port.onmessage = (ev) => this._onWorkerMessage(ev); this.worker.port.postMessage(['_attach', this._conn.service]); } /** * @param {number} status * @param {string} jid */ _attachCallback(status, jid) { if (status === Status.ATTACHED) { this._conn.jid = jid; this._conn.authenticated = true; this._conn.connected = true; this._conn.restored = true; this._conn._changeConnectStatus(Status.ATTACHED); } else if (status === Status.ATTACHFAIL) { this._conn.authenticated = false; this._conn.connected = false; this._conn.restored = false; this._conn._changeConnectStatus(Status.ATTACHFAIL); } } /** * @param {Element|Builder} pres - This stanza will be sent before disconnecting. */ _disconnect(pres) { pres && this._conn.send(pres); const close = $build('close', { 'xmlns': NS.FRAMING }); this._conn.xmlOutput(close.tree()); const closeString = Builder.serialize(close); this._conn.rawOutput(closeString); this.worker.port.postMessage(['send', closeString]); this._conn._doDisconnect(); } _closeSocket() { this.socket.close(); } /** * Called by _onInitialMessage in order to replace itself with the general message handler. * This method is overridden by WorkerWebsocket, which manages a * websocket connection via a service worker and doesn't have direct access * to the socket. */ _replaceMessageHandler() { /** @param {MessageEvent} m */ this._messageHandler = (m) => this._onMessage(m); } /** * function that handles messages received from the service worker * @private * @param {MessageEvent} ev */ _onWorkerMessage(ev) { const { data } = ev; const method_name = data[0]; if (method_name === '_onMessage') { this._messageHandler(data[1]); } else if (method_name in this) { try { this[ /** @type {'_attachCallback'|'_onOpen'|'_onClose'|'_onError'} */ (method_name) ].apply(this, ev.data.slice(1)); } catch (e) { log.error(e); } } else if (method_name === 'log') { /** @type {Object.} */ const lmap = { debug: LOG_LEVELS.DEBUG, info: LOG_LEVELS.INFO, warn: LOG_LEVELS.WARN, error: LOG_LEVELS.ERROR, fatal: LOG_LEVELS.FATAL, }; const level = data[1]; const msg = data[2]; log.log(lmap[level], msg); } else { log.error(`Found unhandled service worker message: ${data}`); } } } export default WorkerWebsocket; strophejs-3.1.0/tests/000077500000000000000000000000001472775321000147065ustar00rootroot00000000000000strophejs-3.1.0/tests/node.js000066400000000000000000000004451472775321000161740ustar00rootroot00000000000000/* eslint-env node */ const { Strophe, $iq, $msg, $build, $pres } = require('../dist/strophe.common.js'); global.sinon = require('sinon'); global.XMLHttpRequest = require('xhr2'); global.Strophe = Strophe; global.$iq = $iq; global.$msg = $msg; global.$build = $build; global.$pres = $pres; strophejs-3.1.0/tests/tests.js000066400000000000000000001564301472775321000164170ustar00rootroot00000000000000/*global globalThis, Strophe, $iq, $msg, $build, $pres, QUnit, stx */ const serializer = new Strophe.shims.XMLSerializer(); const { test } = QUnit; QUnit.module('Utility Methods'); test('xvalidTag', (assert) => { /** * Utility method to determine whether a tag is allowed * in the XHTML_IM namespace. * * Used in the createHtml function to filter incoming HTML * into the allowed XHTML-IM subset. * See http://xmpp.org/extensions/xep-0071.html#profile-summary * for the list of recommended */ // Tags must always be lower case (as per XHMTL) assert.equal(Strophe.XHTML.validTag('BODY'), false); assert.equal(Strophe.XHTML.validTag('A'), false); assert.equal(Strophe.XHTML.validTag('Img'), false); assert.equal(Strophe.XHTML.validTag('IMg'), false); // Check all tags mentioned in XEP-0071 assert.equal(Strophe.XHTML.validTag('a'), true); assert.equal(Strophe.XHTML.validTag('blockquote'), true); assert.equal(Strophe.XHTML.validTag('body'), true); assert.equal(Strophe.XHTML.validTag('br'), true); assert.equal(Strophe.XHTML.validTag('cite'), true); assert.equal(Strophe.XHTML.validTag('em'), true); assert.equal(Strophe.XHTML.validTag('img'), true); assert.equal(Strophe.XHTML.validTag('li'), true); assert.equal(Strophe.XHTML.validTag('ol'), true); assert.equal(Strophe.XHTML.validTag('p'), true); assert.equal(Strophe.XHTML.validTag('span'), true); assert.equal(Strophe.XHTML.validTag('strong'), true); assert.equal(Strophe.XHTML.validTag('ul'), true); // Check tags not mentioned in XEP-0071 assert.equal(Strophe.XHTML.validTag('script'), false); assert.equal(Strophe.XHTML.validTag('blink'), false); assert.equal(Strophe.XHTML.validTag('article'), false); }); test('_getRequestStatus', (assert) => { const req = new Strophe.Request('', function () {}); req.xhr = new XHR(200, 4); assert.equal(Strophe.Bosh._getRequestStatus(req), 200, 'Returns the status'); req.xhr = new XHR(500, 4); assert.equal(Strophe.Bosh._getRequestStatus(req), 500, 'Returns the default if the request is not finished yet'); req.xhr = new XHR(200, 3); assert.equal(Strophe.Bosh._getRequestStatus(req), 0, 'Returns the default if the request is not finished yet'); req.xhr = new XHR(undefined, 4); assert.equal( Strophe.Bosh._getRequestStatus(req, -1), -1, "Returns the default if the request doesn't have a status" ); assert.equal(Strophe.Bosh._getRequestStatus(req, 0), 0, "Returns the default if the request doesn't have a status"); }); QUnit.module('JIDs'); test('Normal JID', (assert) => { const jid = 'darcy@pemberley.lit/library'; assert.equal(Strophe.getNodeFromJid(jid), 'darcy', "Node should be 'darcy'"); assert.equal(Strophe.getDomainFromJid(jid), 'pemberley.lit', "Domain should be 'pemberley.lit'"); assert.equal(Strophe.getResourceFromJid(jid), 'library', "Node should be 'library'"); assert.equal(Strophe.getBareJidFromJid(jid), 'darcy@pemberley.lit', "Bare JID should be 'darcy@pemberley.lit'"); }); test('Weird node (unescaped)', (assert) => { const jid = 'darcy@netherfield.lit@pemberley.lit/library'; assert.equal(Strophe.getNodeFromJid(jid), 'darcy', "Node should be 'darcy'"); assert.equal( Strophe.getDomainFromJid(jid), 'netherfield.lit@pemberley.lit', "Domain should be 'netherfield.lit@pemberley.lit'" ); assert.equal(Strophe.getResourceFromJid(jid), 'library', "Resource should be 'library'"); assert.equal( Strophe.getBareJidFromJid(jid), 'darcy@netherfield.lit@pemberley.lit', "Bare JID should be 'darcy@netherfield.lit@pemberley.lit'" ); }); test('Weird node (escaped)', (assert) => { const escapedNode = Strophe.escapeNode('darcy@netherfield.lit'); const jid = escapedNode + '@pemberley.lit/library'; assert.equal(Strophe.getNodeFromJid(jid), 'darcy\\40netherfield.lit', "Node should be 'darcy\\40netherfield.lit'"); assert.equal(Strophe.getDomainFromJid(jid), 'pemberley.lit', "Domain should be 'pemberley.lit'"); assert.equal(Strophe.getResourceFromJid(jid), 'library', "Resource should be 'library'"); assert.equal( Strophe.getBareJidFromJid(jid), 'darcy\\40netherfield.lit@pemberley.lit', "Bare JID should be 'darcy\\40netherfield.lit@pemberley.lit'" ); }); test('Weird resource', (assert) => { const jid = 'books@chat.pemberley.lit/darcy@pemberley.lit/library'; assert.equal(Strophe.getNodeFromJid(jid), 'books', "Node should be 'books'"); assert.equal(Strophe.getDomainFromJid(jid), 'chat.pemberley.lit', "Domain should be 'chat.pemberley.lit'"); assert.equal( Strophe.getResourceFromJid(jid), 'darcy@pemberley.lit/library', "Resource should be 'darcy@pemberley.lit/library'" ); assert.equal( Strophe.getBareJidFromJid(jid), 'books@chat.pemberley.lit', "Bare JID should be 'books@chat.pemberley.lit'" ); }); QUnit.module('Builder'); test('The root() method', (assert) => { const builder = new Strophe.Builder('root'); const el = builder.c('child').c('grandchild').c('greatgrandchild').root(); assert.equal(el.node.nodeName, 'root', 'root() jump back to the root of the tree'); }); test('Correct namespace (#32)', (assert) => { const stanzas = [new Strophe.Builder('message', { foo: 'asdf' }).tree(), $build('iq', {}).tree(), $pres().tree()]; stanzas.forEach((s) => assert.equal(s.getAttribute('xmlns'), Strophe.NS.CLIENT, `Namespace should be '${Strophe.NS.CLIENT}'`) ); }); test('Strophe.Connection.prototype.send() accepts Builders (#27)', (assert) => { const stanza = $pres(); const conn = new Strophe.Connection(''); const sendStub = sinon.stub(XMLHttpRequest.prototype, 'send'); const timeoutStub = sinon.stub(globalThis, 'setTimeout').callsFake(function (func) { // Stub setTimeout to immediately call functions, otherwise our // assertions fail due to async execution. func.apply(arguments); }); conn.send(stanza); assert.equal(sendStub.called, true, 'XMLHttpRequest.send was called'); sendStub.restore(); timeoutStub.restore(); }); test('The fromString static method', (assert) => { const stanza = Strophe.Builder.fromString( '' ); assert.equal(isEqualNode(stanza, $pres({ from: 'juliet@example.com/chamber' })), true); }); QUnit.module('Strophe.Connection options'); test('withCredentials can be set on the XMLHttpRequest object', (assert) => { const stanza = $pres(); // Stub XMLHttpRequest.protototype.send so that it doesn't // actually try to send out the request. const sendStub = sinon.stub(XMLHttpRequest.prototype, 'send'); // Stub setTimeout to immediately call functions, otherwise our // assertions fail due to async execution. const timeoutStub = sinon.stub(globalThis, 'setTimeout').callsFake(function (func) { func.apply(arguments); }); let conn = new Strophe.Connection('example.org'); conn.send(stanza); assert.equal(sendStub.called, true); assert.equal(!!sendStub.getCalls()[0].thisValue.withCredentials, false); conn = new Strophe.Connection('example.org', { 'withCredentials': true }); conn.send(stanza); assert.equal(sendStub.called, true); assert.equal(sendStub.getCalls()[1].thisValue.withCredentials, true); sendStub.restore(); timeoutStub.restore(); }); test('content type can be set on the XMLHttpRequest object', (assert) => { const stanza = $pres(); // Stub XMLHttpRequest.protototype.send so that it doesn't // actually try to send out the request. const sendStub = sinon.stub(XMLHttpRequest.prototype, 'send'); // Stub setTimeout to immediately call functions, otherwise our // assertions fail due to async execution. const timeoutStub = sinon.stub(globalThis, 'setTimeout').callsFake(function (func) { func.apply(arguments); }); const setRetRequestHeaderStub = sinon.stub(XMLHttpRequest.prototype, 'setRequestHeader'); let conn = new Strophe.Connection('example.org'); conn.send(stanza); assert.equal(setRetRequestHeaderStub.getCalls()[0].args[0], 'Content-Type'); assert.equal(setRetRequestHeaderStub.getCalls()[0].args[1], 'text/xml; charset=utf-8'); conn = new Strophe.Connection('example.org', { contentType: 'text/plain; charset=utf-8' }); conn.send(stanza); assert.equal(setRetRequestHeaderStub.getCalls()[1].args[0], 'Content-Type'); assert.equal(setRetRequestHeaderStub.getCalls()[1].args[1], 'text/plain; charset=utf-8'); sendStub.restore(); timeoutStub.restore(); setRetRequestHeaderStub.restore(); }); test('Cookies can be added to the document passing them as options to Strophe.Connection', (assert) => { if (typeof document === 'undefined') { console.warn("Skipping test since there's no 'document' object"); assert.equal(true, true); return; } const stanza = $pres(); let conn = new Strophe.Connection('http://localhost', { 'cookies': { '_xxx': { 'value': '1234', 'path': '/', }, }, }); assert.notEqual(document.cookie.indexOf('_xxx'), -1); let start = document.cookie.indexOf('_xxx'); let end = document.cookie.indexOf(';', start); end = end == -1 ? document.cookie.length : end; assert.equal(document.cookie.substring(start, end), '_xxx=1234'); // Also test when passing only a string conn = new Strophe.Connection('http://localhost', { 'cookies': { '_yyy': '4321' }, 'withCredentials': true }); assert.notEqual(document.cookie.indexOf('_yyy'), -1); start = document.cookie.indexOf('_yyy'); end = document.cookie.indexOf(';', start); end = end == -1 ? document.cookie.length : end; assert.equal(document.cookie.substring(start, end), '_yyy=4321'); // Stub XMLHttpRequest.protototype.send so that it doesn't // actually try to send out the request. const sendStub = sinon.stub(XMLHttpRequest.prototype, 'send'); // Stub setTimeout to immediately call functions, otherwise our // assertions fail due to async execution. const timeoutStub = sinon.stub(globalThis, 'setTimeout').callsFake(function (func) { func.apply(arguments); }); conn.send(stanza); // Unfortunately there's no way to test the headers set in the // request (only in the response). They can however be checked with // the browser's developer tools. assert.equal(sendStub.called, true); sendStub.restore(); timeoutStub.restore(); }); test('send() does not accept strings', (assert) => { const stanza = ''; const conn = new Strophe.Connection(''); // fake connection callback to avoid errors conn.connect_callback = () => {}; try { conn.send(stanza); } catch (e) { assert.equal(e.name, 'StropheError', 'send() should throw exception'); } }); test('Builder with XML attribute escaping test', (assert) => { let text = ''; let expected = ''; let pres = $pres({ to: text }); assert.equal(pres.toString(), expected, '< should be escaped'); text = 'foo&bar'; expected = ''; pres = $pres({ to: text }); assert.equal(pres.toString(), expected, '& should be escaped'); }); test('c() accepts text and passes it to xmlElement', (assert) => { const pres = $pres({ from: 'darcy@pemberley.lit', to: 'books@chat.pemberley.lit' }).c( 'nick', { xmlns: 'http://jabber.org/protocol/nick' }, 'Darcy' ); const expected = '' + 'Darcy' + ''; assert.equal(pres.toString(), expected, "'Darcy' should be a child of "); }); test('c() return the child element if it is a text node.', (assert) => { // See this issue: https://github.com/strophe/strophejs/issues/124 let pres = $pres({ from: 'darcy@pemberley.lit', to: 'books@chat.pemberley.lit' }) .c('show', {}, 'dnd') .c('status', {}, 'In a meeting'); let expected = '' + 'dndIn a meeting' + ''; assert.equal(pres.toString(), expected, ''); pres = $pres({ from: 'darcy@pemberley.lit', to: 'books@chat.pemberley.lit' }).c('show', {}, '').c('status', {}, ''); expected = '' + '' + ''; assert.equal(pres.toString(), expected, ''); }); QUnit.module('XML'); test('XML escaping test', (assert) => { const text = 's & p'; const textNode = Strophe.xmlTextNode(text); assert.equal(Strophe.getText(textNode), 's & p', 'should be escaped'); const text0 = 's < & > p'; const textNode0 = Strophe.xmlTextNode(text0); assert.equal(Strophe.getText(textNode0), 's < & > p', 'should be escaped'); const text1 = 's\'s or "p"'; const textNode1 = Strophe.xmlTextNode(text1); assert.equal(Strophe.getText(textNode1), 's's or "p"', 'should be escaped'); const text2 = ']]>'; const textNode2 = Strophe.xmlTextNode(text2); assert.equal(Strophe.getText(textNode2), '<![CDATA[<foo>]]>', 'should be escaped'); const text3 = ']]>'; const textNode3 = Strophe.xmlTextNode(text3); assert.equal(Strophe.getText(textNode3), '<![CDATA[]]]]><![CDATA[>]]>', 'should be escaped'); const text4 = '<foo>]]>'; const textNode4 = Strophe.xmlTextNode(text4); assert.equal(Strophe.getText(textNode4), '&lt;foo&gt;<![CDATA[<foo>]]>', 'should be escaped'); }); test('XML element creation', (assert) => { let el = Strophe.xmlElement('message'); assert.equal(el.tagName, 'message', 'Element name should be the same'); el = Strophe.xmlElement('message', 'Some text'); assert.equal(el.textContent, 'Some text'); el = Strophe.xmlElement('message', {}, 'Some text'); assert.equal(el.textContent, 'Some text'); el = Strophe.xmlElement('message', { foo: 'bar' }, 'Some text'); assert.equal(el.textContent, 'Some text'); assert.equal(el.getAttribute('foo'), 'bar'); el = Strophe.xmlElement('message', [['foo', 'bar']], 'Some text'); assert.equal(el.textContent, 'Some text'); assert.equal(el.getAttribute('foo'), 'bar'); }); test('copyElement() double escape bug', function (assert) { const cloned = Strophe.copyElement(Strophe.xmlGenerator().createTextNode('<><>')); assert.equal(cloned.nodeValue, '<><>'); }); test('XML serializing', function (assert) { const parser = new Strophe.shims.DOMParser(); // Attributes const element1 = parser.parseFromString("bar", 'text/xml').documentElement; assert.equal(Strophe.serialize(element1), 'bar', 'should be serialized'); const element2 = parser.parseFromString('bar', 'text/xml').documentElement; assert.equal(Strophe.serialize(element2), 'bar', 'should be serialized'); // Escaping values const element3 = parser.parseFromString( 'a > 'b' & "b" < c', 'text/xml' ).documentElement; assert.equal( Strophe.serialize(element3), 'a > 'b' & "b" < c', 'should be serialized' ); // Escaping attributes const element4 = parser.parseFromString("bar", 'text/xml').documentElement; assert.equal(Strophe.serialize(element4), 'bar', 'should be serialized'); const element5 = parser.parseFromString('bar', 'text/xml').documentElement; assert.equal(Strophe.serialize(element5), 'bar', 'should be serialized'); // Empty elements const element6 = parser.parseFromString('', 'text/xml').documentElement; assert.equal(Strophe.serialize(element6), '', 'should be serialized'); // Children const element7 = parser.parseFromString( 'ab', 'text/xml' ).documentElement; assert.equal( Strophe.serialize(element7), 'ab', 'should be serialized' ); const element8 = parser.parseFromString( 'abcd', 'text/xml' ).documentElement; assert.equal( Strophe.serialize(element8), 'abcd', 'should be serialized' ); // CDATA const element9 = parser.parseFromString(']]>', 'text/xml').documentElement; assert.equal(Strophe.serialize(element9), ']]>', 'should be serialized'); const element10 = parser.parseFromString(']]>', 'text/xml').documentElement; if (globalThis.DOMParser) { assert.equal(Strophe.serialize(element10), ']]>', 'should be serialized'); } else { assert.equal(Strophe.serialize(element10), ']]>', 'should be serialized'); } const element11 = parser.parseFromString('<foo>]]>', 'text/xml').documentElement; assert.equal(Strophe.serialize(element11), '<foo>]]>', 'should be serialized'); }); QUnit.module('Handler'); test('HTTP errors', (assert) => { const spy500 = sinon.spy(); const spy401 = sinon.spy(); const conn = new Strophe.Connection('http://fake'); conn.addProtocolErrorHandler('HTTP', 500, spy500); conn.addProtocolErrorHandler('HTTP', 401, spy401); const req = new Strophe.Request('', () => {}); req.xhr = new XHR(200, 4); conn._proto._onRequestStateChange(() => {}, req); assert.equal(spy500.called, false, 'Error handler does not get called when no HTTP error'); assert.equal(spy401.called, false, 'Error handler does not get called when no HTTP error'); req.xhr = new XHR(401, 4); conn._proto._onRequestStateChange(() => {}, req); assert.equal(spy500.called, false, 'Error handler does not get called when no HTTP 500 error'); assert.equal(spy401.called, true, 'Error handler does get called when HTTP 401 error'); req.xhr = new XHR(500, 4); conn._proto._onRequestStateChange(() => {}, req); assert.equal(spy500.called, true, 'Error handler gets called on HTTP 500 error'); }); test('IQ fallback handler', (assert) => { // Strophe returns an IQ error stanza to unhandled incoming IQ get and set stanzas const conn = new Strophe.Connection('http://fake'); conn.authenticated = true; const spy = sinon.spy(conn, 'send'); conn._dataRecv(makeRequest($iq({ 'type': 'get', 'id': '1' }).tree())); assert.equal(spy.calledOnce, true, 'send was called only once'); assert.equal( Strophe.serialize(spy.args[0][0].nodeTree), '' + '' + '' ); conn._dataRecv(makeRequest($iq({ 'type': 'get', 'id': '2' }).tree())); assert.equal(spy.calledTwice, true, 'send was called twice'); assert.equal( Strophe.serialize(spy.args[1][0].nodeTree), '' + '' + '' ); // When there is a handler, then the fallback handler isn't called. const handlerStub = sinon.stub(); handlerStub.returns(true); conn.addHandler(handlerStub, null, 'iq'); conn._dataRecv(makeRequest($iq({ 'type': 'set' }).tree())); assert.equal(spy.calledTwice, true, 'send was called twice'); conn._dataRecv(makeRequest($iq({ 'type': 'get' }).tree())); assert.equal(spy.calledTwice, true, 'send was called twice'); assert.equal(handlerStub.calledTwice, true, 'The manually registered IQ handler was called twice'); }); test('Full JID matching', (assert) => { const elem = $msg({ from: 'darcy@pemberley.lit/library' }).tree(); let hand = new Strophe.Handler(null, null, null, null, null, 'darcy@pemberley.lit/library'); assert.equal(hand.isMatch(elem), true, 'Full JID should match'); hand = new Strophe.Handler(null, null, null, null, null, 'darcy@pemberley.lit'); assert.equal(hand.isMatch(elem), false, "Bare JID shouldn't match"); }); test('Bare JID matching', (assert) => { const elem = $msg({ from: 'darcy@pemberley.lit/library' }).tree(); let hand = new Strophe.Handler(null, null, null, null, null, 'darcy@pemberley.lit/library', { matchBareFromJid: true, }); assert.equal(hand.isMatch(elem), true, 'Full JID should match'); hand = new Strophe.Handler(null, null, null, null, null, 'darcy@pemberley.lit', { matchBareFromJid: true }); assert.equal(hand.isMatch(elem), true, 'Bare JID should match'); }); test('Namespace matching', (assert) => { const elemNoFrag = $msg({ xmlns: 'http://jabber.org/protocol/muc' }).tree(); const elemWithFrag = $msg({ xmlns: 'http://jabber.org/protocol/muc#user' }).tree(); let hand = new Strophe.Handler(null, 'http://jabber.org/protocol/muc', null, null, null, null); assert.equal(hand.isMatch(elemNoFrag), true, 'The handler should match on stanza namespace'); assert.equal(hand.isMatch(elemWithFrag), false, 'The handler should not match on stanza namespace with fragment'); const elemNested = stx` `.tree(); hand = new Strophe.Handler(null, 'urn:ietf:params:xml:ns:xmpp-stanzas'); assert.equal(hand.isMatch(elemNested), true, 'The handler should match on a nested namespace'); assert.equal(hand.isMatch(elemNoFrag), false, 'The handler should not match on a non-existing namespace'); hand = new Strophe.Handler(null, 'http://jabber.org/protocol/muc', null, null, null, null, { 'ignoreNamespaceFragment': true, }); assert.equal(hand.isMatch(elemNoFrag), true, 'The handler should match on stanza namespace'); assert.equal(hand.isMatch(elemWithFrag), true, 'The handler should match on stanza namespace, even with fragment'); }); test('Stanza name matching', (assert) => { const elem = $iq().tree(); let hand = new Strophe.Handler(null, null, 'iq'); assert.equal(hand.isMatch(elem), true, 'The handler should match on stanza name'); hand = new Strophe.Handler(null, null, 'message'); assert.notEqual(hand.isMatch(elem), true, 'The handler should not match wrong stanza name'); }); test('Stanza type matching', (assert) => { const elem = $iq({ type: 'error' }).tree(); let hand = new Strophe.Handler(null, null, 'iq', 'error'); assert.equal(hand.isMatch(elem), true, 'The handler should match on stanza type'); hand = new Strophe.Handler(null, null, 'iq', 'result'); assert.notEqual(hand.isMatch(elem), true, 'The handler should not match wrong stanza type'); hand = new Strophe.Handler(null, null, 'iq', ['error', 'result']); assert.equal(hand.isMatch(elem), true, 'The handler should match if stanza type is in array of types'); }); QUnit.module('Misc'); test('Function binding', (assert) => { const spy = sinon.spy(); const obj = {}; const arg1 = 'foo'; const arg2 = 'bar'; const arg3 = 'baz'; const f = spy.bind(obj, arg1, arg2); f(arg3); assert.equal(spy.called, true, 'bound function should be called'); assert.equal(spy.calledOn(obj), true, 'bound function should have correct context'); assert.equal(spy.alwaysCalledWithExactly(arg1, arg2, arg3), true, 'bound function should get all arguments'); }); test('Connfail for invalid XML', (assert) => { const req = new Strophe.Request('', function () {}); req.xhr = new XHR(undefined, undefined, 'text'); const conn = new Strophe.Connection('http://fake'); conn.connect_callback = function (status, condition) { if (status === Strophe.Status.CONNFAIL) { assert.equal(condition, 'bad-format', 'connection should fail with condition bad-format'); } }; conn._connect_cb(req); }); QUnit.module('XHR error handling'); // Note that these tests are pretty dependent on the actual code. test('Aborted requests do nothing', (assert) => { Strophe.Connection.prototype._onIdle = () => {}; const conn = new Strophe.Connection('http://fake'); // simulate a finished but aborted request const req = { id: 43, sends: 1, xhr: new XHR(undefined, 4), abort: true }; conn._requests = [req]; const spy = sinon.spy(); conn._proto._onRequestStateChange(spy, req); assert.equal(req.abort, false, 'abort flag should be toggled'); assert.equal(conn._requests.length, 1, '_requests should be same length'); assert.equal(spy.called, false, 'callback should not be called'); }); test('Incomplete requests do nothing', (assert) => { Strophe.Connection.prototype._onIdle = () => {}; const conn = new Strophe.Connection('http://fake'); // simulate a finished but aborted request const req = { id: 44, sends: 1, xhr: new XHR(undefined, 3) }; conn._requests = [req]; const spy = sinon.spy(); conn._proto._onRequestStateChange(spy, req); assert.equal(conn._requests.length, 1, '_requests should be same length'); assert.equal(spy.called, false, 'callback should not be called'); }); QUnit.module('SASL Mechanisms'); test('Default mechanisms will be registered if none are provided', (assert) => { const conn = new Strophe.Connection('http://localhost'); assert.equal(Object.keys(conn.mechanisms).length, 9, 'Ten by default registered SASL mechanisms'); assert.equal('ANONYMOUS' in conn.mechanisms, true, 'ANONYMOUS is registered'); assert.equal('EXTERNAL' in conn.mechanisms, true, 'EXTERNAL is registered'); assert.equal('OAUTHBEARER' in conn.mechanisms, true, 'OAUTHBEARER is registered'); assert.equal('PLAIN' in conn.mechanisms, true, 'PLAIN is registered'); assert.equal('SCRAM-SHA-1' in conn.mechanisms, true, 'SCRAM-SHA-1 is registered'); assert.equal('SCRAM-SHA-256' in conn.mechanisms, true, 'SCRAM-SHA-256 is registered'); assert.equal('SCRAM-SHA-384' in conn.mechanisms, true, 'SCRAM-SHA-384 is registered'); assert.equal('SCRAM-SHA-512' in conn.mechanisms, true, 'SCRAM-SHA-512 is registered'); assert.equal('X-OAUTH2' in conn.mechanisms, true, 'X-OAUTH2 is registered'); }); test('Custom mechanisms be specified when instantiating Strophe.Connection', (assert) => { let conn = new Strophe.Connection('http://localhost', { 'mechanisms': [SASLFoo] }); assert.equal(Object.keys(conn.mechanisms).length, 1, 'Only one registered SASL mechanism'); assert.equal('FOO' in conn.mechanisms, true, 'FOO is registered'); assert.notEqual('PLAIN' in conn.mechanisms, true, 'PLAIN is not registered'); conn = new Strophe.Connection('http://localhost', { 'mechanisms': [SASLFoo, Strophe.SASLPlain] }); assert.equal(Object.keys(conn.mechanisms).length, 2, 'Only two registered SASL mechanisms'); assert.equal('FOO' in conn.mechanisms, true, 'FOO is registered'); assert.equal('PLAIN' in conn.mechanisms, true, 'PLAIN is registered'); }); test('The supported mechanism with the highest priority will be used', (assert) => { Strophe.SASLExternal.prototype.priority = 10; Strophe.SASLSHA1.prototype.priority = 20; const conn = new Strophe.Connection('http://localhost', { 'mechanisms': [Strophe.SASLSHA1, Strophe.SASLExternal] }); const authSpy = sinon.spy(conn, '_attemptSASLAuth'); assert.equal(authSpy.called, false); conn.connect('dummy@localhost', 'secret'); const mechanisms = Object.values(conn.mechanisms); conn.authenticate(mechanisms); assert.equal(authSpy.called, true); assert.equal(authSpy.returnValues.length, 1); assert.equal(authSpy.returnValues[0], true); assert.equal(conn._sasl_mechanism.mechname, 'SCRAM-SHA-1'); mechanisms[0].priority = 20; mechanisms[1].priority = 30; conn.connect('dummy@localhost', 'secret'); conn.authenticate(Object.values(mechanisms)); assert.equal(conn._sasl_mechanism.mechname, 'EXTERNAL'); }); test('SASL PLAIN Auth', async (assert) => { const conn = { pass: 'password', authcid: 'user', authzid: 'user@xmpp.org', domain: 'xmpp.org' }; const saslplain = new Strophe.SASLPlain(); saslplain.onStart(conn); assert.ok(saslplain.test(conn), 'PLAIN is enabled by default.'); const response = await saslplain.onChallenge(conn); assert.equal(response, ['', conn.authcid, conn.pass].join('\u0000'), 'checking plain auth challenge'); saslplain.onSuccess(); }); test('SASL PLAIN Auth with authzid', async (assert) => { const conn = { pass: 'password', authcid: 'user', authzid: 'admin@xmpp.org', domain: 'xmpp.org' }; const saslplain = new Strophe.SASLPlain(); saslplain.onStart(conn); assert.ok(saslplain.test(conn), 'PLAIN is enabled by default.'); const response = await saslplain.onChallenge(conn, null); assert.equal(response, [conn.authzid, conn.authcid, conn.pass].join('\u0000'), 'checking plain auth challenge'); saslplain.onSuccess(); }); test('SASL SCRAM-SHA-1 Auth', async (assert) => { /* This is a simple example of a SCRAM-SHA-1 authentication exchange * when the client doesn't support channel bindings (username 'user' and * password 'pencil' are used): * * C: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL * S: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92, * i=4096 * C: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j, * p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts= * S: v=rmF9pqV8S7suAoZWja4dJRkFsKQ= * */ const conn = { pass: 'pencil', authcid: 'user', authzid: 'user@xmpp.org', _sasl_data: [], }; const saslsha1 = new Strophe.SASLSHA1(); saslsha1.onStart(conn); assert.ok(saslsha1.test(conn), 'SHA-1 is enabled by default.'); // test taken from example section on: // URL: http://tools.ietf.org/html/rfc5802#section-5 let response = await saslsha1.clientChallenge(conn, 'fyko+d2lbbFgONRv9qkxdawL'); assert.equal(response, 'n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL', 'checking first auth challenge'); response = await saslsha1.onChallenge( conn, 'r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096' ); assert.equal( response, 'c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=', 'checking second auth challenge' ); saslsha1.onSuccess(); }); test('SASL SCRAM-SHA-256 Auth', async (assert) => { /* This is a simple example of a SCRAM-SHA-256 authentication exchange * when the client doesn't support channel bindings (username 'user' and * password 'pencil' are used): * * C: n,,n=user,r=rOprNGfwEbeRWgbNEkqO * S: r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0, * s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096 * C: c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0, * p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ= * S: v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4= * */ const conn = { pass: 'pencil', authcid: 'user', authzid: 'user@xmpp.org', _sasl_data: [], }; const saslsha256 = new Strophe.SASLSHA256(); saslsha256.onStart(conn); assert.ok(saslsha256.test(conn), 'SHA-256 is enabled by default.'); // test taken from example section on: // URL: https://datatracker.ietf.org/doc/html/rfc7677#section-3 let response = await saslsha256.clientChallenge(conn, 'rOprNGfwEbeRWgbNEkqO'); assert.equal(response, 'n,,n=user,r=rOprNGfwEbeRWgbNEkqO', 'checking first auth challenge'); response = await saslsha256.onChallenge( conn, 'r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096' ); assert.equal( response, 'c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=', 'checking second auth challenge' ); saslsha256.onSuccess(); }); test('SASL EXTERNAL Auth', async (assert) => { let conn = { pass: 'password', authcid: 'user', authzid: 'user@xmpp.org' }; let sasl_external = new Strophe.SASLExternal(); assert.ok(sasl_external.test(conn), 'EXTERNAL is enabled by default.'); sasl_external.onStart(conn); let response = await sasl_external.clientChallenge(conn); assert.equal( response, conn.authzid, 'Response to EXTERNAL auth challenge should be authzid if different authcid was passed in.' ); sasl_external.onSuccess(); conn = { pass: 'password', authcid: 'user', authzid: 'user@xmpp.org' }; sasl_external = new Strophe.SASLExternal(); assert.ok(sasl_external.test(conn), 'EXTERNAL is enabled by default.'); sasl_external.onStart(conn); response = await sasl_external.onChallenge(conn, null); assert.equal( response, conn.authzid, 'Response to EXTERNAL auth challenge should be empty string if authcid = authzid' ); sasl_external.onSuccess(); }); QUnit.module('BOSH Session resumption'); test('When passing in {keepalive: true} to Strophe.Connection, then the session tokens get cached automatically', (assert) => { const conn = new Strophe.Connection('', { 'keepalive': true }); conn.jid = 'dummy@localhost'; conn._proto.sid = '5332346'; const cacheSpy = sinon.spy(conn._proto, '_cacheSession'); assert.equal(cacheSpy.called, false); conn._proto._buildBody(); assert.equal(cacheSpy.called, true); assert.equal(sessionStorage.getItem('strophe-bosh-session'), null); conn.authenticated = true; conn._proto._buildBody(); assert.ok(sessionStorage.getItem('strophe-bosh-session')); assert.equal(cacheSpy.called, true); conn.authenticated = false; conn._proto._buildBody(); assert.equal(sessionStorage.getItem('strophe-bosh-session'), null); assert.equal(cacheSpy.called, true); }); test('the request ID (RID) has the proper value whenever a session is restored', (assert) => { sessionStorage.removeItem('strophe-bosh-session'); const conn = new Strophe.Connection('', { 'keepalive': true }); conn.authenticated = true; conn.jid = 'dummy@localhost'; conn._proto.rid = '123456'; conn._proto.sid = '987654321'; conn._proto._cacheSession(); delete conn._proto.rid; conn.restore(); let body = conn._proto._buildBody(); assert.equal(body.tree().getAttribute('rid'), '123456'); body = conn._proto._buildBody(); assert.equal(body.tree().getAttribute('rid'), '123457'); body = conn._proto._buildBody(); assert.equal(body.tree().getAttribute('rid'), '123458'); delete conn._proto.rid; conn.restore(); body = conn._proto._buildBody(); assert.equal(body.tree().getAttribute('rid'), '123459'); }); test('restore can only be called with BOSH and when {keepalive: true} is passed to Strophe.Connection', (assert) => { let conn = new Strophe.Connection(''); const boshSpy = sinon.spy(conn._proto, '_restore'); const checkSpy = sinon.spy(conn, '_sessionCachingSupported'); assert.equal(conn.restored, false); try { conn.restore(); } catch (e) { assert.equal( e.name, 'StropheSessionError', 'conn.restore() should throw an exception when keepalive is false.' ); assert.equal( e.message, '_restore: no restoreable session.', 'conn.restore() should throw an exception when keepalive is false' ); } assert.equal(boshSpy.called, true); assert.equal(checkSpy.called, true); conn = new Strophe.Connection('ws:localhost'); try { conn.restore(); } catch (e) { assert.equal( e.name, 'StropheSessionError', 'conn.restore() should throw an exception when keepalive is false.' ); assert.equal( e.message, 'The "restore" method can only be used with a BOSH connection.', 'The conn.restore method can only be used with a BOSH connection.' ); } assert.equal(conn.restored, false); }); test('the _cacheSession method caches the BOSH session tokens', (assert) => { sessionStorage.removeItem('strophe-bosh-session'); const conn = new Strophe.Connection('http://fake', { 'keepalive': true }); // Nothing gets cached if there aren't tokens to cache conn._proto._cacheSession(); assert.equal(sessionStorage.getItem('strophe-bosh-session'), null); // Let's create some tokens to cache conn.authenticated = true; conn.jid = 'dummy@localhost'; conn._proto.rid = '123456'; conn._proto.sid = '987654321'; assert.equal(sessionStorage.getItem('strophe-bosh-session'), null); conn._proto._cacheSession(); assert.notEqual(sessionStorage.getItem('strophe-bosh-session'), null); }); test('when calling "restore" without a restorable session, an exception is raised', (assert) => { sessionStorage.removeItem('strophe-bosh-session'); const conn = new Strophe.Connection('', { 'keepalive': true }); const boshSpy = sinon.spy(conn._proto, '_restore'); const checkSpy = sinon.spy(conn, '_sessionCachingSupported'); assert.equal(conn.restored, false); try { conn.restore(); } catch (e) { assert.equal(e.name, 'StropheSessionError'); assert.equal(e.message, '_restore: no restoreable session.'); } assert.equal(conn.restored, false); assert.equal(boshSpy.called, true); assert.equal(checkSpy.called, true); }); test('"restore" takes an optional JID argument for more precise session verification', (assert) => { sessionStorage.removeItem('strophe-bosh-session'); const conn = new Strophe.Connection('', { 'keepalive': true }); const boshSpy = sinon.spy(conn._proto, '_restore'); const checkSpy = sinon.spy(conn, '_sessionCachingSupported'); // Let's create some tokens to cache conn.authenticated = true; conn.jid = 'dummy@localhost'; conn._proto.rid = '1234567'; conn._proto.sid = '9876543210'; conn._proto._cacheSession(); // Check that giving a different jid causes an exception to be // raised. try { conn.restore('differentdummy@localhost'); } catch (e) { assert.equal(e.name, 'StropheSessionError'); assert.equal(e.message, '_restore: no restoreable session.'); } assert.equal(conn.restored, false); assert.equal(boshSpy.called, true); assert.equal(checkSpy.called, true); // Check that passing in the right jid but with a resource is not a problem. conn.restore('dummy@localhost/with_resource'); assert.equal(conn.jid, 'dummy@localhost'); assert.equal(conn._proto.rid, '1234567'); assert.equal(conn._proto.sid, '9876543210'); assert.equal(conn.restored, true); }); test('when calling "restore" with a restorable session, bosh._attach is called with the session tokens', (assert) => { sessionStorage.removeItem('strophe-bosh-session'); const conn = new Strophe.Connection('', { 'keepalive': true }); conn.authenticated = true; conn.jid = 'dummy@localhost'; conn._proto.rid = '123456'; conn._proto.sid = '987654321'; conn._proto._cacheSession(); delete conn._proto.rid; delete conn._proto.sid; delete conn._proto.jid; assert.equal(conn.restored, false); const boshSpy = sinon.spy(conn._proto, '_restore'); const checkSpy = sinon.spy(conn, '_sessionCachingSupported'); const attachSpsy = sinon.spy(conn._proto, '_attach'); conn.restore(); assert.equal(conn.jid, 'dummy@localhost'); assert.equal(conn._proto.rid, '123456'); assert.equal(conn._proto.sid, '987654321'); assert.equal(conn.restored, true); assert.equal(boshSpy.called, true); assert.equal(checkSpy.called, true); assert.equal(attachSpsy.called, true); }); QUnit.module('BOSH next valid request id'); test('nextValidRid is called after successful request', (assert) => { Strophe.Connection.prototype._onIdle = () => {}; const conn = new Strophe.Connection('http://fake'); const spy = sinon.spy(conn, 'nextValidRid'); const req = { id: 43, sends: 1, xhr: new XHR(200, 4), rid: 42 }; conn._requests = [req]; conn._proto._onRequestStateChange(function () {}, req); assert.equal(spy.calledOnce, true, 'nextValidRid was called only once'); assert.equal(spy.calledWith(43), true, 'The RID was valid'); }); test('nextValidRid is not called after failed request', (assert) => { Strophe.Connection.prototype._onIdle = () => {}; const conn = new Strophe.Connection('http://fake'); const spy = sinon.spy(conn, 'nextValidRid'); const req = { id: 43, sends: 1, xhr: new XHR(0, 4), rid: 42 }; conn._requests = [req]; conn._proto._onRequestStateChange(function () {}, req); assert.equal(spy.called, false, 'nextValidRid was not called'); }); test('nextValidRid is called after failed request with disconnection', (assert) => { sinon.stub(Math, 'random').callsFake(() => 1); Strophe.Connection.prototype._onIdle = () => {}; const conn = new Strophe.Connection('http://fake'); const spy = sinon.spy(conn, 'nextValidRid'); const req = { id: 43, sends: 1, xhr: new XHR(404, 4), rid: 42 }; conn._requests = [req]; conn._proto._onRequestStateChange(function () {}, req); assert.equal(spy.calledOnce, true, 'nextValidRid was called only once'); assert.equal(spy.calledWith(4294967295), true, 'The RID was valid'); Math.random.restore(); }); test('nextValidRid is called after connection reset', (assert) => { sinon.stub(Math, 'random').callsFake(() => 1); Strophe.Connection.prototype._onIdle = () => {}; const conn = new Strophe.Connection('http://fake'); const spy = sinon.spy(conn, 'nextValidRid'); conn.reset(); assert.equal(spy.calledOnce, true, 'nextValidRid was called only once'); assert.equal(spy.calledWith(4294967295), true, 'The RID was valid'); Math.random.restore(); }); QUnit.module('The stx tagged template literal'); test('can be used to create Stanza objects that are equivalent to Builder objects', (assert) => { let templateStanza = stx` JC JC `; // prettier-ignore let builderStanza = $iq({ type: "result", to: "juliet@capulet.lit/balcony", id: "retrieve1" }) .c("pubsub", { xmlns: "http://jabber.org/protocol/pubsub" }) .c("items", { node: "urn:xmpp:bookmarks:1" }) .c("item", { id: "theplay@conference.shakespeare.lit" }) .c("conference", { xmlns: "urn:xmpp:bookmarks:1", name: "The Play's the Thing", autojoin: "true" }) .c("nick").t("JC").up() .up() .up() .c("item", { id: "orchard@conference.shakespeare.lit" }) .c("conference", { xmlns: "urn:xmpp:bookmarks:1", name: "The Orcard", autojoin: "1" }) .c("nick").t("JC").up() .c("extensions") .c("state", { xmlns: "http://myclient.example/bookmark/state", minimized: "true" }) .up() .up() .up() .up() .up(); assert.equal(isEqualNode(templateStanza, builderStanza), true); templateStanza = stx` Thrice the brinded cat hath mew'd. `; // prettier-ignore builderStanza = $msg({ from: 'coven@chat.shakespeare.lit/firstwitch', id: '162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2', to: 'hecate@shakespeare.lit/broom', type: 'groupchat', }).c('body').t("Thrice the brinded cat hath mew'd.").up() .c('delay', { xmlns: 'urn:xmpp:delay', from: 'coven@chat.shakespeare.lit', stamp: '2002-10-13T23:58:37Z' }); assert.equal(isEqualNode(templateStanza, builderStanza), true); templateStanza = stx` `; // prettier-ignore builderStanza = $pres({ from: 'hag66@shakespeare.lit/pda', id: 'n13mt3l', to: 'coven@chat.shakespeare.lit/thirdwitch', }).c('x', { xmlns: 'http://jabber.org/protocol/muc' }) .c('history', { maxchars: '65000' }); assert.equal(isEqualNode(templateStanza, builderStanza), true); }); test('can be nested recursively', (assert) => { const templateStanza = stx` ${[ stx` JC `, stx` JC `, ]} `; // prettier-ignore const builderStanza = $iq({ type: "result", to: "juliet@capulet.lit/balcony", id: "retrieve1" }) .c("pubsub", { xmlns: "http://jabber.org/protocol/pubsub" }) .c("items", { node: "urn:xmpp:bookmarks:1" }) .c("item", { id: "theplay@conference.shakespeare.lit" }) .c("conference", { xmlns: "urn:xmpp:bookmarks:1", name: "The Play's the Thing", autojoin: "true" }) .c("nick").t("JC").up() .up() .up() .c("item", { id: "orchard@conference.shakespeare.lit" }) .c("conference", { xmlns: "urn:xmpp:bookmarks:1", name: "The Orcard", autojoin: "1" }) .c("nick").t("JC").up() .c("extensions") .c("state", { xmlns: "http://myclient.example/bookmark/state", minimized: "true" }) .up() .up() .up() .up() .up(); assert.equal(isEqualNode(templateStanza, builderStanza), true); }); test('can have nested Builder objects', (assert) => { // prettier-ignore const templateStanza = stx` ${[ new Strophe.Builder('item', { id: "theplay@conference.shakespeare.lit" }) .c("conference", { xmlns: "urn:xmpp:bookmarks:1", name: "The Play's the Thing", autojoin: "true" }) .c("nick").t("JC"), new Strophe.Builder('item', { id: "orchard@conference.shakespeare.lit" }) .c("conference", { xmlns: "urn:xmpp:bookmarks:1", name: "The Orcard", autojoin: "1" }) .c("nick").t("JC").up() .c("extensions") .c("state", { xmlns: "http://myclient.example/bookmark/state", minimized: "true" }), ]} `; // prettier-ignore const builderStanza = $iq({ type: "result", to: "juliet@capulet.lit/balcony", id: "retrieve1" }) .c("pubsub", { xmlns: "http://jabber.org/protocol/pubsub" }) .c("items", { node: "urn:xmpp:bookmarks:1" }) .c("item", { id: "theplay@conference.shakespeare.lit" }) .c("conference", { xmlns: "urn:xmpp:bookmarks:1", name: "The Play's the Thing", autojoin: "true" }) .c("nick").t("JC").up() .up() .up() .c("item", { id: "orchard@conference.shakespeare.lit" }) .c("conference", { xmlns: "urn:xmpp:bookmarks:1", name: "The Orcard", autojoin: "1" }) .c("nick").t("JC").up() .c("extensions") .c("state", { xmlns: "http://myclient.example/bookmark/state", minimized: "true" }) .up() .up() .up() .up() .up(); assert.equal(isEqualNode(templateStanza, builderStanza), true); }); test('escape the values passed in to them', (assert) => { const status = ''; const templateStanza = stx` ${status} `; assert.equal( templateStanza.tree().querySelector('status').innerHTML, '<script>alert("p0wned")</script>' ); }); test('The unsafeXML directive', (assert) => { const templateStanza = stx` ${Strophe.Stanza.unsafeXML(`I'm busy!`)} `; assert.equal( isEqualNode(templateStanza, $pres({ from: 'juliet@example.com/chamber' }).c('status').t("I'm busy!")), true ); }); const TEXT_NODE = 3; const ELEMENT_NODE = 1; function stripEmptyTextNodes(element) { const childNodes = Array.from(element.childNodes ?? []); childNodes.forEach((node) => { if (node.nodeType === TEXT_NODE && !node.nodeValue.trim()) { element.removeChild(node); } else if (node.nodeType === ELEMENT_NODE) { stripEmptyTextNodes(node); // Recursively call for child elements } }); return element; } /** * Given two XML or HTML elements, determine if they're equal * @param {Strophe.Stanza|Strophe.Builder} actual * @param {Strophe.Stanza|Strophe.Builder} expected * @returns {Boolean} */ function isEqualNode(actual, expected) { actual = stripEmptyTextNodes(actual.tree()); expected = stripEmptyTextNodes(expected.tree()); let isEqual = actual.isEqualNode(expected); if (!isEqual) { // XXX: This is a hack. // When creating two XML elements, one via DOMParser, and one via // createElementNS (or createElement), then "isEqualNode" doesn't match. // // For example, in the following code `isEqual` is false: // ------------------------------------------------------ // const a = document.createElementNS('foo', 'div'); // a.setAttribute('xmlns', 'foo'); // // const b = (new DOMParser()).parseFromString('
', 'text/xml').firstElementChild; // const isEqual = a.isEqualNode(div); // false // // The workaround here is to serialize both elements to string and then use // DOMParser again for both (via xmlHtmlNode). // // This is not efficient, but currently this is only being used in tests. // const { xmlHtmlNode } = Strophe; const actual_string = serializer.serializeToString(actual); const expected_string = serializer.serializeToString(expected); isEqual = actual_string === expected_string || xmlHtmlNode(actual_string).isEqualNode(xmlHtmlNode(expected_string)); } return isEqual; } /** * Mock xhr, provides getAllResponseHeaders function. * @param status * @param readyState * @param responseText */ function XHR(status, readyState, responseText) { this.status = status; this.readyState = readyState; this.responseText = responseText; this.getAllResponseHeaders = () => null; } class SASLFoo extends Strophe.SASLMechanism { constructor() { super('FOO', false, 10); } static get name() { return 'FOO'; } } function makeRequest(stanza) { const req = new Strophe.Request(stanza, () => {}); req.getResponse = function () { const env = new Strophe.Builder('env', { type: 'mock' }).tree(); env.appendChild(stanza); return env; }; return req; } const _sessionStorage = {}; if (!globalThis.sessionStorage) { Object.defineProperty(globalThis, 'sessionStorage', { value: { setItem: (key, value) => (_sessionStorage[key] = value), getItem: (key) => _sessionStorage[key] ?? null, removeItem: (key) => delete _sessionStorage[key], }, }); } strophejs-3.1.0/tsconfig.json000066400000000000000000000010701472775321000162510ustar00rootroot00000000000000{ "include": [ "src/**/*" ], "compilerOptions": { "target": "es2016", "module": "esnext", "allowJs": true, "checkJs": true, // Generate d.ts files "declaration": true, "emitDeclarationOnly": true, "declarationMap": true, "rootDir": "./src", "outDir": "./src/types/", "baseUrl": "./src/", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": false, "noImplicitAny": true, "skipLibCheck": true, "moduleResolution": "node", "resolveJsonModule": true } }